1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 * Copyright (c) 2012 by Delphix. All rights reserved.
30 */
31
32 #include <sys/resource.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35
36 #include <strings.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <limits.h>
41 #ifdef illumos
42 #include <alloca.h>
43 #endif
44 #include <errno.h>
45 #include <fcntl.h>
46
47 #include <dt_impl.h>
48 #include <dt_string.h>
49
50 static int
dt_opt_agg(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)51 dt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
52 {
53 dt_aggregate_t *agp = &dtp->dt_aggregate;
54
55 if (arg != NULL)
56 return (dt_set_errno(dtp, EDT_BADOPTVAL));
57
58 agp->dtat_flags |= option;
59 return (0);
60 }
61
62 /*ARGSUSED*/
63 static int
dt_opt_amin(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)64 dt_opt_amin(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
65 {
66 char str[DTRACE_ATTR2STR_MAX];
67 dtrace_attribute_t attr;
68
69 if (arg == NULL || dtrace_str2attr(arg, &attr) == -1)
70 return (dt_set_errno(dtp, EDT_BADOPTVAL));
71
72 dt_dprintf("set compiler attribute minimum to %s\n",
73 dtrace_attr2str(attr, str, sizeof (str)));
74
75 if (dtp->dt_pcb != NULL) {
76 dtp->dt_pcb->pcb_cflags |= DTRACE_C_EATTR;
77 dtp->dt_pcb->pcb_amin = attr;
78 } else {
79 dtp->dt_cflags |= DTRACE_C_EATTR;
80 dtp->dt_amin = attr;
81 }
82
83 return (0);
84 }
85
86 static void
dt_coredump(void)87 dt_coredump(void)
88 {
89 const char msg[] = "libdtrace DEBUG: [ forcing coredump ]\n";
90
91 struct sigaction act;
92 struct rlimit lim;
93
94 (void) write(STDERR_FILENO, msg, sizeof (msg) - 1);
95
96 act.sa_handler = SIG_DFL;
97 act.sa_flags = 0;
98
99 (void) sigemptyset(&act.sa_mask);
100 (void) sigaction(SIGABRT, &act, NULL);
101
102 lim.rlim_cur = RLIM_INFINITY;
103 lim.rlim_max = RLIM_INFINITY;
104
105 (void) setrlimit(RLIMIT_CORE, &lim);
106 abort();
107 }
108
109 /*ARGSUSED*/
110 static int
dt_opt_core(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)111 dt_opt_core(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
112 {
113 static int enabled = 0;
114
115 if (arg != NULL)
116 return (dt_set_errno(dtp, EDT_BADOPTVAL));
117
118 if (enabled++ || atexit(dt_coredump) == 0)
119 return (0);
120
121 return (dt_set_errno(dtp, errno));
122 }
123
124 /*ARGSUSED*/
125 static int
dt_opt_cpp_hdrs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)126 dt_opt_cpp_hdrs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
127 {
128 if (arg != NULL)
129 return (dt_set_errno(dtp, EDT_BADOPTVAL));
130
131 if (dtp->dt_pcb != NULL)
132 return (dt_set_errno(dtp, EDT_BADOPTCTX));
133
134 if (dt_cpp_add_arg(dtp, "-H") == NULL)
135 return (dt_set_errno(dtp, EDT_NOMEM));
136
137 return (0);
138 }
139
140 /*ARGSUSED*/
141 static int
dt_opt_cpp_path(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)142 dt_opt_cpp_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
143 {
144 char *cpp;
145
146 if (arg == NULL)
147 return (dt_set_errno(dtp, EDT_BADOPTVAL));
148
149 if (dtp->dt_pcb != NULL)
150 return (dt_set_errno(dtp, EDT_BADOPTCTX));
151
152 if ((cpp = strdup(arg)) == NULL)
153 return (dt_set_errno(dtp, EDT_NOMEM));
154
155 dtp->dt_cpp_argv[0] = (char *)strbasename(cpp);
156 free(dtp->dt_cpp_path);
157 dtp->dt_cpp_path = cpp;
158
159 return (0);
160 }
161
162 static int
dt_opt_cpp_opts(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)163 dt_opt_cpp_opts(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
164 {
165 char *buf;
166 size_t len;
167 const char *opt = (const char *)option;
168
169 if (opt == NULL || arg == NULL)
170 return (dt_set_errno(dtp, EDT_BADOPTVAL));
171
172 if (dtp->dt_pcb != NULL)
173 return (dt_set_errno(dtp, EDT_BADOPTCTX));
174
175 len = strlen(opt) + strlen(arg) + 1;
176 buf = alloca(len);
177
178 (void) strcpy(buf, opt);
179 (void) strcat(buf, arg);
180
181 if (dt_cpp_add_arg(dtp, buf) == NULL)
182 return (dt_set_errno(dtp, EDT_NOMEM));
183
184 return (0);
185 }
186
187 /*ARGSUSED*/
188 static int
dt_opt_ctypes(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)189 dt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
190 {
191 int fd;
192
193 if (arg == NULL)
194 return (dt_set_errno(dtp, EDT_BADOPTVAL));
195
196 if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
197 return (dt_set_errno(dtp, errno));
198
199 (void) close(dtp->dt_cdefs_fd);
200 dtp->dt_cdefs_fd = fd;
201 return (0);
202 }
203
204 /*ARGSUSED*/
205 static int
dt_opt_droptags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)206 dt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
207 {
208 dtp->dt_droptags = 1;
209 return (0);
210 }
211
212 /*ARGSUSED*/
213 static int
dt_opt_dtypes(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)214 dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
215 {
216 int fd;
217
218 if (arg == NULL)
219 return (dt_set_errno(dtp, EDT_BADOPTVAL));
220
221 if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
222 return (dt_set_errno(dtp, errno));
223
224 (void) close(dtp->dt_ddefs_fd);
225 dtp->dt_ddefs_fd = fd;
226 return (0);
227 }
228
229 /*ARGSUSED*/
230 static int
dt_opt_debug(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)231 dt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
232 {
233 if (arg != NULL)
234 return (dt_set_errno(dtp, EDT_BADOPTVAL));
235
236 _dtrace_debug = 1;
237 return (0);
238 }
239
240 /*ARGSUSED*/
241 static int
dt_opt_iregs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)242 dt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
243 {
244 int n;
245
246 if (arg == NULL || (n = atoi(arg)) <= 0)
247 return (dt_set_errno(dtp, EDT_BADOPTVAL));
248
249 dtp->dt_conf.dtc_difintregs = n;
250 return (0);
251 }
252
253 /*ARGSUSED*/
254 static int
dt_opt_lazyload(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)255 dt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
256 {
257 dtp->dt_lazyload = 1;
258
259 return (0);
260 }
261
262 /*ARGSUSED*/
263 static int
dt_opt_ld_path(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)264 dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
265 {
266 char *ld;
267
268 if (arg == NULL)
269 return (dt_set_errno(dtp, EDT_BADOPTVAL));
270
271 if (dtp->dt_pcb != NULL)
272 return (dt_set_errno(dtp, EDT_BADOPTCTX));
273
274 if ((ld = strdup(arg)) == NULL)
275 return (dt_set_errno(dtp, EDT_NOMEM));
276
277 free(dtp->dt_ld_path);
278 dtp->dt_ld_path = ld;
279
280 return (0);
281 }
282
283 #if defined(__FreeBSD__) || defined(__NetBSD__)
284 static int
dt_opt_objcopy_path(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)285 dt_opt_objcopy_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
286 {
287 char *objcopy;
288
289 if (arg == NULL)
290 return (dt_set_errno(dtp, EDT_BADOPTVAL));
291
292 if (dtp->dt_pcb != NULL)
293 return (dt_set_errno(dtp, EDT_BADOPTCTX));
294
295 if ((objcopy = strdup(arg)) == NULL)
296 return (dt_set_errno(dtp, EDT_NOMEM));
297
298 free(dtp->dt_objcopy_path);
299 dtp->dt_objcopy_path = objcopy;
300
301 return (0);
302 }
303 #endif
304
305 /*ARGSUSED*/
306 static int
dt_opt_libdir(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)307 dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
308 {
309 dt_dirpath_t *dp;
310
311 if (arg == NULL)
312 return (dt_set_errno(dtp, EDT_BADOPTVAL));
313
314 if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
315 (dp->dir_path = strdup(arg)) == NULL) {
316 free(dp);
317 return (dt_set_errno(dtp, EDT_NOMEM));
318 }
319
320 dt_list_append(&dtp->dt_lib_path, dp);
321 return (0);
322 }
323
324 /*ARGSUSED*/
325 static int
dt_opt_linkmode(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)326 dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
327 {
328 if (arg == NULL)
329 return (dt_set_errno(dtp, EDT_BADOPTVAL));
330
331 if (strcmp(arg, "kernel") == 0)
332 dtp->dt_linkmode = DT_LINK_KERNEL;
333 else if (strcmp(arg, "primary") == 0)
334 dtp->dt_linkmode = DT_LINK_PRIMARY;
335 else if (strcmp(arg, "dynamic") == 0)
336 dtp->dt_linkmode = DT_LINK_DYNAMIC;
337 else if (strcmp(arg, "static") == 0)
338 dtp->dt_linkmode = DT_LINK_STATIC;
339 else
340 return (dt_set_errno(dtp, EDT_BADOPTVAL));
341
342 return (0);
343 }
344
345 /*ARGSUSED*/
346 static int
dt_opt_linktype(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)347 dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
348 {
349 if (arg == NULL)
350 return (dt_set_errno(dtp, EDT_BADOPTVAL));
351
352 if (strcasecmp(arg, "elf") == 0)
353 dtp->dt_linktype = DT_LTYP_ELF;
354 else if (strcasecmp(arg, "dof") == 0)
355 dtp->dt_linktype = DT_LTYP_DOF;
356 else
357 return (dt_set_errno(dtp, EDT_BADOPTVAL));
358
359 return (0);
360 }
361
362 /*ARGSUSED*/
363 static int
dt_opt_encoding(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)364 dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
365 {
366 if (arg == NULL)
367 return (dt_set_errno(dtp, EDT_BADOPTVAL));
368
369 if (strcmp(arg, "ascii") == 0)
370 dtp->dt_encoding = DT_ENCODING_ASCII;
371 else if (strcmp(arg, "utf8") == 0)
372 dtp->dt_encoding = DT_ENCODING_UTF8;
373 else
374 return (dt_set_errno(dtp, EDT_BADOPTVAL));
375
376 return (0);
377 }
378
379 /*ARGSUSED*/
380 static int
dt_opt_evaltime(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)381 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
382 {
383 if (arg == NULL)
384 return (dt_set_errno(dtp, EDT_BADOPTVAL));
385
386 if (strcmp(arg, "exec") == 0)
387 dtp->dt_prcmode = DT_PROC_STOP_CREATE;
388 else if (strcmp(arg, "preinit") == 0)
389 dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
390 else if (strcmp(arg, "postinit") == 0)
391 dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
392 else if (strcmp(arg, "main") == 0)
393 dtp->dt_prcmode = DT_PROC_STOP_MAIN;
394 else
395 return (dt_set_errno(dtp, EDT_BADOPTVAL));
396
397 return (0);
398 }
399
400 /*ARGSUSED*/
401 static int
dt_opt_pgmax(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)402 dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
403 {
404 int n;
405
406 if (arg == NULL || (n = atoi(arg)) < 0)
407 return (dt_set_errno(dtp, EDT_BADOPTVAL));
408
409 dtp->dt_procs->dph_lrulim = n;
410 return (0);
411 }
412
413 static int
dt_opt_setenv(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)414 dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
415 {
416 char **p;
417 char *var;
418 int i;
419
420 /*
421 * We can't effectively set environment variables from #pragma lines
422 * since the processes have already been spawned.
423 */
424 if (dtp->dt_pcb != NULL)
425 return (dt_set_errno(dtp, EDT_BADOPTCTX));
426
427 if (arg == NULL)
428 return (dt_set_errno(dtp, EDT_BADOPTVAL));
429
430 if (!option && strchr(arg, '=') != NULL)
431 return (dt_set_errno(dtp, EDT_BADOPTVAL));
432
433 for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
434 continue;
435
436 for (p = dtp->dt_proc_env; *p != NULL; p++) {
437 var = strchr(*p, '=');
438 if (var == NULL)
439 var = *p + strlen(*p);
440 if (strncmp(*p, arg, var - *p) == 0) {
441 dt_free(dtp, *p);
442 *p = dtp->dt_proc_env[i - 1];
443 dtp->dt_proc_env[i - 1] = NULL;
444 i--;
445 }
446 }
447
448 if (option) {
449 if ((var = strdup(arg)) == NULL)
450 return (dt_set_errno(dtp, EDT_NOMEM));
451
452 if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
453 dt_free(dtp, var);
454 return (dt_set_errno(dtp, EDT_NOMEM));
455 }
456
457 bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
458 dt_free(dtp, dtp->dt_proc_env);
459 dtp->dt_proc_env = p;
460
461 dtp->dt_proc_env[i - 1] = var;
462 dtp->dt_proc_env[i] = NULL;
463 }
464
465 return (0);
466 }
467
468 /*ARGSUSED*/
469 static int
dt_opt_stdc(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)470 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
471 {
472 if (arg == NULL)
473 return (dt_set_errno(dtp, EDT_BADOPTVAL));
474
475 if (dtp->dt_pcb != NULL)
476 return (dt_set_errno(dtp, EDT_BADOPTCTX));
477
478 if (strcmp(arg, "a") == 0)
479 dtp->dt_stdcmode = DT_STDC_XA;
480 else if (strcmp(arg, "c") == 0)
481 dtp->dt_stdcmode = DT_STDC_XC;
482 else if (strcmp(arg, "s") == 0)
483 dtp->dt_stdcmode = DT_STDC_XS;
484 else if (strcmp(arg, "t") == 0)
485 dtp->dt_stdcmode = DT_STDC_XT;
486 else
487 return (dt_set_errno(dtp, EDT_BADOPTVAL));
488
489 return (0);
490 }
491
492 /*ARGSUSED*/
493 static int
dt_opt_syslibdir(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)494 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
495 {
496 dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
497 char *path;
498
499 if (arg == NULL)
500 return (dt_set_errno(dtp, EDT_BADOPTVAL));
501
502 if ((path = strdup(arg)) == NULL)
503 return (dt_set_errno(dtp, EDT_NOMEM));
504
505 free(dp->dir_path);
506 dp->dir_path = path;
507
508 return (0);
509 }
510
511 /*ARGSUSED*/
512 static int
dt_opt_tree(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)513 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
514 {
515 int m;
516
517 if (arg == NULL || (m = atoi(arg)) <= 0)
518 return (dt_set_errno(dtp, EDT_BADOPTVAL));
519
520 dtp->dt_treedump = m;
521 return (0);
522 }
523
524 /*ARGSUSED*/
525 static int
dt_opt_tregs(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)526 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
527 {
528 int n;
529
530 if (arg == NULL || (n = atoi(arg)) <= 0)
531 return (dt_set_errno(dtp, EDT_BADOPTVAL));
532
533 dtp->dt_conf.dtc_diftupregs = n;
534 return (0);
535 }
536
537 /*ARGSUSED*/
538 static int
dt_opt_xlate(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)539 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
540 {
541 if (arg == NULL)
542 return (dt_set_errno(dtp, EDT_BADOPTVAL));
543
544 if (strcmp(arg, "dynamic") == 0)
545 dtp->dt_xlatemode = DT_XL_DYNAMIC;
546 else if (strcmp(arg, "static") == 0)
547 dtp->dt_xlatemode = DT_XL_STATIC;
548 else
549 return (dt_set_errno(dtp, EDT_BADOPTVAL));
550
551 return (0);
552 }
553
554 /*ARGSUSED*/
555 static int
dt_opt_cflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)556 dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
557 {
558 if (arg != NULL)
559 return (dt_set_errno(dtp, EDT_BADOPTVAL));
560
561 if (dtp->dt_pcb != NULL)
562 dtp->dt_pcb->pcb_cflags |= option;
563 else
564 dtp->dt_cflags |= option;
565
566 return (0);
567 }
568
569 static int
dt_opt_dflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)570 dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
571 {
572 if (arg != NULL)
573 return (dt_set_errno(dtp, EDT_BADOPTVAL));
574
575 dtp->dt_dflags |= option;
576 return (0);
577 }
578
579 static int
dt_opt_invcflags(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)580 dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
581 {
582 if (arg != NULL)
583 return (dt_set_errno(dtp, EDT_BADOPTVAL));
584
585 if (dtp->dt_pcb != NULL)
586 dtp->dt_pcb->pcb_cflags &= ~option;
587 else
588 dtp->dt_cflags &= ~option;
589
590 return (0);
591 }
592
593 /*ARGSUSED*/
594 static int
dt_opt_version(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)595 dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
596 {
597 dt_version_t v;
598
599 if (arg == NULL)
600 return (dt_set_errno(dtp, EDT_BADOPTVAL));
601
602 if (dt_version_str2num(arg, &v) == -1)
603 return (dt_set_errno(dtp, EDT_VERSINVAL));
604
605 if (!dt_version_defined(v))
606 return (dt_set_errno(dtp, EDT_VERSUNDEF));
607
608 return (dt_reduce(dtp, v));
609 }
610
611 static int
dt_opt_runtime(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)612 dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
613 {
614 char *end;
615 dtrace_optval_t val = 0;
616 int i;
617
618 const struct {
619 char *positive;
620 char *negative;
621 } couples[] = {
622 { "yes", "no" },
623 { "enable", "disable" },
624 { "enabled", "disabled" },
625 { "true", "false" },
626 { "on", "off" },
627 { "set", "unset" },
628 { NULL }
629 };
630
631 if (arg != NULL) {
632 if (arg[0] == '\0') {
633 val = DTRACEOPT_UNSET;
634 goto out;
635 }
636
637 for (i = 0; couples[i].positive != NULL; i++) {
638 if (strcasecmp(couples[i].positive, arg) == 0) {
639 val = 1;
640 goto out;
641 }
642
643 if (strcasecmp(couples[i].negative, arg) == 0) {
644 val = DTRACEOPT_UNSET;
645 goto out;
646 }
647 }
648
649 errno = 0;
650 val = strtoull(arg, &end, 0);
651
652 if (*end != '\0' || errno != 0 || val < 0)
653 return (dt_set_errno(dtp, EDT_BADOPTVAL));
654 }
655
656 out:
657 dtp->dt_options[option] = val;
658 return (0);
659 }
660
661 static int
dt_optval_parse(const char * arg,dtrace_optval_t * rval)662 dt_optval_parse(const char *arg, dtrace_optval_t *rval)
663 {
664 dtrace_optval_t mul = 1;
665 size_t len;
666 char *end;
667
668 len = strlen(arg);
669 errno = 0;
670
671 switch (arg[len - 1]) {
672 case 't':
673 case 'T':
674 mul *= 1024;
675 /*FALLTHRU*/
676 case 'g':
677 case 'G':
678 mul *= 1024;
679 /*FALLTHRU*/
680 case 'm':
681 case 'M':
682 mul *= 1024;
683 /*FALLTHRU*/
684 case 'k':
685 case 'K':
686 mul *= 1024;
687 /*FALLTHRU*/
688 default:
689 break;
690 }
691
692 errno = 0;
693 *rval = strtoull(arg, &end, 0) * mul;
694
695 if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
696 *rval < 0 || errno != 0)
697 return (-1);
698
699 return (0);
700 }
701
702 static int
dt_opt_size(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)703 dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
704 {
705 dtrace_optval_t val = 0;
706
707 if (arg != NULL && dt_optval_parse(arg, &val) != 0)
708 return (dt_set_errno(dtp, EDT_BADOPTVAL));
709
710 dtp->dt_options[option] = val;
711 return (0);
712 }
713
714 static int
dt_opt_rate(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)715 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
716 {
717 char *end;
718 int i;
719 dtrace_optval_t mul = 1, val = 0;
720
721 const struct {
722 char *name;
723 hrtime_t mul;
724 } suffix[] = {
725 { "ns", NANOSEC / NANOSEC },
726 { "nsec", NANOSEC / NANOSEC },
727 { "us", NANOSEC / MICROSEC },
728 { "usec", NANOSEC / MICROSEC },
729 { "ms", NANOSEC / MILLISEC },
730 { "msec", NANOSEC / MILLISEC },
731 { "s", NANOSEC / SEC },
732 { "sec", NANOSEC / SEC },
733 { "m", NANOSEC * (hrtime_t)60 },
734 { "min", NANOSEC * (hrtime_t)60 },
735 { "h", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
736 { "hour", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
737 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
738 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
739 { "hz", 0 },
740 { NULL }
741 };
742
743 if (arg != NULL) {
744 errno = 0;
745 val = strtoull(arg, &end, 0);
746
747 for (i = 0; suffix[i].name != NULL; i++) {
748 if (strcasecmp(suffix[i].name, end) == 0) {
749 mul = suffix[i].mul;
750 break;
751 }
752 }
753
754 if (suffix[i].name == NULL && *end != '\0' || val < 0)
755 return (dt_set_errno(dtp, EDT_BADOPTVAL));
756
757 if (mul == 0) {
758 /*
759 * The rate has been specified in frequency-per-second.
760 */
761 if (val != 0)
762 val = NANOSEC / val;
763 } else {
764 val *= mul;
765 }
766 }
767
768 dtp->dt_options[option] = val;
769 return (0);
770 }
771
772 /*
773 * When setting the strsize option, set the option in the dt_options array
774 * using dt_opt_size() as usual, and then update the definition of the CTF
775 * type for the D intrinsic "string" to be an array of the corresponding size.
776 * If any errors occur, reset dt_options[option] to its previous value.
777 */
778 static int
dt_opt_strsize(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)779 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
780 {
781 dtrace_optval_t val = dtp->dt_options[option];
782 ctf_file_t *fp = DT_STR_CTFP(dtp);
783 ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
784 ctf_arinfo_t r;
785
786 if (dt_opt_size(dtp, arg, option) != 0)
787 return (-1); /* dt_errno is set for us */
788
789 if (dtp->dt_options[option] > UINT_MAX) {
790 dtp->dt_options[option] = val;
791 return (dt_set_errno(dtp, EOVERFLOW));
792 }
793
794 if (ctf_array_info(fp, type, &r) == CTF_ERR) {
795 dtp->dt_options[option] = val;
796 dtp->dt_ctferr = ctf_errno(fp);
797 return (dt_set_errno(dtp, EDT_CTF));
798 }
799
800 r.ctr_nelems = (uint_t)dtp->dt_options[option];
801
802 if (ctf_set_array(fp, type, &r) == CTF_ERR ||
803 ctf_update(fp) == CTF_ERR) {
804 dtp->dt_options[option] = val;
805 dtp->dt_ctferr = ctf_errno(fp);
806 return (dt_set_errno(dtp, EDT_CTF));
807 }
808
809 return (0);
810 }
811
812 static const struct {
813 const char *dtbp_name;
814 int dtbp_policy;
815 } _dtrace_bufpolicies[] = {
816 { "ring", DTRACEOPT_BUFPOLICY_RING },
817 { "fill", DTRACEOPT_BUFPOLICY_FILL },
818 { "switch", DTRACEOPT_BUFPOLICY_SWITCH },
819 { NULL, 0 }
820 };
821
822 /*ARGSUSED*/
823 static int
dt_opt_bufpolicy(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)824 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
825 {
826 dtrace_optval_t policy = DTRACEOPT_UNSET;
827 int i;
828
829 if (arg == NULL)
830 return (dt_set_errno(dtp, EDT_BADOPTVAL));
831
832 for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
833 if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
834 policy = _dtrace_bufpolicies[i].dtbp_policy;
835 break;
836 }
837 }
838
839 if (policy == DTRACEOPT_UNSET)
840 return (dt_set_errno(dtp, EDT_BADOPTVAL));
841
842 dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
843
844 return (0);
845 }
846
847 static const struct {
848 const char *dtbr_name;
849 int dtbr_policy;
850 } _dtrace_bufresize[] = {
851 { "auto", DTRACEOPT_BUFRESIZE_AUTO },
852 { "manual", DTRACEOPT_BUFRESIZE_MANUAL },
853 { NULL, 0 }
854 };
855
856 /*ARGSUSED*/
857 static int
dt_opt_bufresize(dtrace_hdl_t * dtp,const char * arg,uintptr_t option)858 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
859 {
860 dtrace_optval_t policy = DTRACEOPT_UNSET;
861 int i;
862
863 if (arg == NULL)
864 return (dt_set_errno(dtp, EDT_BADOPTVAL));
865
866 for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
867 if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
868 policy = _dtrace_bufresize[i].dtbr_policy;
869 break;
870 }
871 }
872
873 if (policy == DTRACEOPT_UNSET)
874 return (dt_set_errno(dtp, EDT_BADOPTVAL));
875
876 dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
877
878 return (0);
879 }
880
881 int
dt_options_load(dtrace_hdl_t * dtp)882 dt_options_load(dtrace_hdl_t *dtp)
883 {
884 dof_hdr_t hdr, *dof;
885 dof_sec_t *sec = NULL; // XXX: gcc
886 size_t offs;
887 int i;
888
889 /*
890 * To load the option values, we need to ask the kernel to provide its
891 * DOF, which we'll sift through to look for OPTDESC sections.
892 */
893 bzero(&hdr, sizeof (dof_hdr_t));
894 hdr.dofh_loadsz = sizeof (dof_hdr_t);
895
896 #ifdef illumos
897 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
898 #else
899 dof = &hdr;
900 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
901 #endif
902 return (dt_set_errno(dtp, errno));
903
904 if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
905 return (dt_set_errno(dtp, EINVAL));
906
907 dof = calloc(hdr.dofh_loadsz, 1);
908 if (dof == NULL)
909 return (dt_set_errno(dtp, errno));
910 dof->dofh_loadsz = hdr.dofh_loadsz;
911
912 for (i = 0; i < DTRACEOPT_MAX; i++)
913 dtp->dt_options[i] = DTRACEOPT_UNSET;
914
915 #ifdef illumos
916 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
917 #else
918 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
919 #endif
920 {
921 free(dof);
922 return (dt_set_errno(dtp, errno));
923 }
924
925 for (i = 0; i < dof->dofh_secnum; i++) {
926 sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
927 dof->dofh_secoff + i * dof->dofh_secsize);
928
929 if (sec->dofs_type != DOF_SECT_OPTDESC)
930 continue;
931
932 break;
933 }
934
935 for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
936 dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
937 ((uintptr_t)dof + sec->dofs_offset + offs);
938
939 if (opt->dofo_strtab != DOF_SECIDX_NONE)
940 continue;
941
942 if (opt->dofo_option >= DTRACEOPT_MAX)
943 continue;
944
945 dtp->dt_options[opt->dofo_option] = opt->dofo_value;
946 }
947 free(dof);
948 return (0);
949 }
950
951 typedef struct dt_option {
952 const char *o_name;
953 int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
954 uintptr_t o_option;
955 } dt_option_t;
956
957 /*
958 * Compile-time options.
959 */
960 static const dt_option_t _dtrace_ctoptions[] = {
961 { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
962 { "amin", dt_opt_amin },
963 { "argref", dt_opt_cflags, DTRACE_C_ARGREF },
964 { "core", dt_opt_core },
965 { "cpp", dt_opt_cflags, DTRACE_C_CPP },
966 { "cpphdrs", dt_opt_cpp_hdrs },
967 { "cpppath", dt_opt_cpp_path },
968 { "ctypes", dt_opt_ctypes },
969 { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
970 { "dtypes", dt_opt_dtypes },
971 { "debug", dt_opt_debug },
972 { "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
973 { "droptags", dt_opt_droptags },
974 { "empty", dt_opt_cflags, DTRACE_C_EMPTY },
975 { "encoding", dt_opt_encoding },
976 { "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
977 { "evaltime", dt_opt_evaltime },
978 { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
979 { "iregs", dt_opt_iregs },
980 { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
981 { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
982 { "late", dt_opt_xlate },
983 { "lazyload", dt_opt_lazyload },
984 { "ldpath", dt_opt_ld_path },
985 { "libdir", dt_opt_libdir },
986 { "linkmode", dt_opt_linkmode },
987 { "linktype", dt_opt_linktype },
988 { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
989 #if defined(__FreeBSD__) || defined(__NetBSD__)
990 { "objcopypath", dt_opt_objcopy_path },
991 #endif
992 { "pgmax", dt_opt_pgmax },
993 { "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
994 { "setenv", dt_opt_setenv, 1 },
995 { "stdc", dt_opt_stdc },
996 { "strip", dt_opt_dflags, DTRACE_D_STRIP },
997 { "syslibdir", dt_opt_syslibdir },
998 { "tree", dt_opt_tree },
999 { "tregs", dt_opt_tregs },
1000 { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
1001 { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
1002 { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
1003 { "unsetenv", dt_opt_setenv, 0 },
1004 { "verbose", dt_opt_cflags, DTRACE_C_DIFV },
1005 { "version", dt_opt_version },
1006 { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
1007 { NULL, NULL, 0 }
1008 };
1009
1010 /*
1011 * Run-time options.
1012 */
1013 static const dt_option_t _dtrace_rtoptions[] = {
1014 { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
1015 { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
1016 { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
1017 { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
1018 { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
1019 { "cpu", dt_opt_runtime, DTRACEOPT_CPU },
1020 { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
1021 { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
1022 { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
1023 { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
1024 { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
1025 { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
1026 { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
1027 { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
1028 { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
1029 { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
1030 { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
1031 { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
1032 { NULL, NULL, 0 }
1033 };
1034
1035 /*
1036 * Dynamic run-time options.
1037 */
1038 static const dt_option_t _dtrace_drtoptions[] = {
1039 { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
1040 { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
1041 { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
1042 { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
1043 { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
1044 { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
1045 { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
1046 { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
1047 { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
1048 { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
1049 { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
1050 { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
1051 { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
1052 { NULL, NULL, 0 }
1053 };
1054
1055 int
dtrace_getopt(dtrace_hdl_t * dtp,const char * opt,dtrace_optval_t * val)1056 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
1057 {
1058 const dt_option_t *op;
1059
1060 if (opt == NULL)
1061 return (dt_set_errno(dtp, EINVAL));
1062
1063 /*
1064 * We only need to search the run-time options -- it's not legal
1065 * to get the values of compile-time options.
1066 */
1067 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1068 if (strcmp(op->o_name, opt) == 0) {
1069 *val = dtp->dt_options[op->o_option];
1070 return (0);
1071 }
1072 }
1073
1074 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1075 if (strcmp(op->o_name, opt) == 0) {
1076 *val = dtp->dt_options[op->o_option];
1077 return (0);
1078 }
1079 }
1080
1081 return (dt_set_errno(dtp, EDT_BADOPTNAME));
1082 }
1083
1084 int
dtrace_setopt(dtrace_hdl_t * dtp,const char * opt,const char * val)1085 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1086 {
1087 const dt_option_t *op;
1088
1089 if (opt == NULL)
1090 return (dt_set_errno(dtp, EINVAL));
1091
1092 for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1093 if (strcmp(op->o_name, opt) == 0)
1094 return (op->o_func(dtp, val, op->o_option));
1095 }
1096
1097 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1098 if (strcmp(op->o_name, opt) == 0)
1099 return (op->o_func(dtp, val, op->o_option));
1100 }
1101
1102 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1103 if (strcmp(op->o_name, opt) == 0) {
1104 /*
1105 * Only dynamic run-time options may be set while
1106 * tracing is active.
1107 */
1108 if (dtp->dt_active)
1109 return (dt_set_errno(dtp, EDT_ACTIVE));
1110
1111 return (op->o_func(dtp, val, op->o_option));
1112 }
1113 }
1114
1115 return (dt_set_errno(dtp, EDT_BADOPTNAME));
1116 }
1117