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