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 #include <zone.h>
45 #include <libzonecfg.h>
46
47 #include <dt_impl.h>
48 #include <dt_string.h>
49
50 static int
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
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
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
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
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
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
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
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
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
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
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
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
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
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 /*ARGSUSED*/
284 static int
285 dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
286 {
287 dt_dirpath_t *dp;
288
289 if (arg == NULL)
290 return (dt_set_errno(dtp, EDT_BADOPTVAL));
291
292 if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
293 (dp->dir_path = strdup(arg)) == NULL) {
294 free(dp);
295 return (dt_set_errno(dtp, EDT_NOMEM));
296 }
297
298 dt_list_append(&dtp->dt_lib_path, dp);
299 return (0);
300 }
301
302 /*ARGSUSED*/
303 static int
304 dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
305 {
306 if (arg == NULL)
307 return (dt_set_errno(dtp, EDT_BADOPTVAL));
308
309 if (strcmp(arg, "kernel") == 0)
310 dtp->dt_linkmode = DT_LINK_KERNEL;
311 else if (strcmp(arg, "primary") == 0)
312 dtp->dt_linkmode = DT_LINK_PRIMARY;
313 else if (strcmp(arg, "dynamic") == 0)
314 dtp->dt_linkmode = DT_LINK_DYNAMIC;
315 else if (strcmp(arg, "static") == 0)
316 dtp->dt_linkmode = DT_LINK_STATIC;
317 else
318 return (dt_set_errno(dtp, EDT_BADOPTVAL));
319
320 return (0);
321 }
322
323 /*ARGSUSED*/
324 static int
325 dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
326 {
327 if (arg == NULL)
328 return (dt_set_errno(dtp, EDT_BADOPTVAL));
329
330 if (strcasecmp(arg, "elf") == 0)
331 dtp->dt_linktype = DT_LTYP_ELF;
332 else if (strcasecmp(arg, "dof") == 0)
333 dtp->dt_linktype = DT_LTYP_DOF;
334 else
335 return (dt_set_errno(dtp, EDT_BADOPTVAL));
336
337 return (0);
338 }
339
340 /*ARGSUSED*/
341 static int
342 dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
343 {
344 if (arg == NULL)
345 return (dt_set_errno(dtp, EDT_BADOPTVAL));
346
347 if (strcmp(arg, "ascii") == 0)
348 dtp->dt_encoding = DT_ENCODING_ASCII;
349 else if (strcmp(arg, "utf8") == 0)
350 dtp->dt_encoding = DT_ENCODING_UTF8;
351 else
352 return (dt_set_errno(dtp, EDT_BADOPTVAL));
353
354 return (0);
355 }
356
357 /*ARGSUSED*/
358 static int
359 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
360 {
361 if (arg == NULL)
362 return (dt_set_errno(dtp, EDT_BADOPTVAL));
363
364 if (strcmp(arg, "exec") == 0)
365 dtp->dt_prcmode = DT_PROC_STOP_CREATE;
366 else if (strcmp(arg, "preinit") == 0)
367 dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
368 else if (strcmp(arg, "postinit") == 0)
369 dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
370 else if (strcmp(arg, "main") == 0)
371 dtp->dt_prcmode = DT_PROC_STOP_MAIN;
372 else
373 return (dt_set_errno(dtp, EDT_BADOPTVAL));
374
375 return (0);
376 }
377
378 /*ARGSUSED*/
379 static int
380 dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
381 {
382 int n;
383
384 if (arg == NULL || (n = atoi(arg)) < 0)
385 return (dt_set_errno(dtp, EDT_BADOPTVAL));
386
387 dtp->dt_procs->dph_lrulim = n;
388 return (0);
389 }
390
391 static int
392 dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
393 {
394 char **p;
395 char *var;
396 int i;
397
398 /*
399 * We can't effectively set environment variables from #pragma lines
400 * since the processes have already been spawned.
401 */
402 if (dtp->dt_pcb != NULL)
403 return (dt_set_errno(dtp, EDT_BADOPTCTX));
404
405 if (arg == NULL)
406 return (dt_set_errno(dtp, EDT_BADOPTVAL));
407
408 if (!option && strchr(arg, '=') != NULL)
409 return (dt_set_errno(dtp, EDT_BADOPTVAL));
410
411 for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
412 continue;
413
414 for (p = dtp->dt_proc_env; *p != NULL; p++) {
415 var = strchr(*p, '=');
416 if (var == NULL)
417 var = *p + strlen(*p);
418 if (strncmp(*p, arg, var - *p) == 0) {
419 dt_free(dtp, *p);
420 *p = dtp->dt_proc_env[i - 1];
421 dtp->dt_proc_env[i - 1] = NULL;
422 i--;
423 }
424 }
425
426 if (option) {
427 if ((var = strdup(arg)) == NULL)
428 return (dt_set_errno(dtp, EDT_NOMEM));
429
430 if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
431 dt_free(dtp, var);
432 return (dt_set_errno(dtp, EDT_NOMEM));
433 }
434
435 bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
436 dt_free(dtp, dtp->dt_proc_env);
437 dtp->dt_proc_env = p;
438
439 dtp->dt_proc_env[i - 1] = var;
440 dtp->dt_proc_env[i] = NULL;
441 }
442
443 return (0);
444 }
445
446 /*ARGSUSED*/
447 static int
448 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
449 {
450 if (arg == NULL)
451 return (dt_set_errno(dtp, EDT_BADOPTVAL));
452
453 if (dtp->dt_pcb != NULL)
454 return (dt_set_errno(dtp, EDT_BADOPTCTX));
455
456 if (strcmp(arg, "a") == 0)
457 dtp->dt_stdcmode = DT_STDC_XA;
458 else if (strcmp(arg, "c") == 0)
459 dtp->dt_stdcmode = DT_STDC_XC;
460 else if (strcmp(arg, "s") == 0)
461 dtp->dt_stdcmode = DT_STDC_XS;
462 else if (strcmp(arg, "t") == 0)
463 dtp->dt_stdcmode = DT_STDC_XT;
464 else
465 return (dt_set_errno(dtp, EDT_BADOPTVAL));
466
467 return (0);
468 }
469
470 /*ARGSUSED*/
471 static int
472 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
473 {
474 dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
475 char *path;
476
477 if (arg == NULL)
478 return (dt_set_errno(dtp, EDT_BADOPTVAL));
479
480 if ((path = strdup(arg)) == NULL)
481 return (dt_set_errno(dtp, EDT_NOMEM));
482
483 free(dp->dir_path);
484 dp->dir_path = path;
485
486 return (0);
487 }
488
489 /*ARGSUSED*/
490 static int
491 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
492 {
493 int m;
494
495 if (arg == NULL || (m = atoi(arg)) <= 0)
496 return (dt_set_errno(dtp, EDT_BADOPTVAL));
497
498 dtp->dt_treedump = m;
499 return (0);
500 }
501
502 /*ARGSUSED*/
503 static int
504 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
505 {
506 int n;
507
508 if (arg == NULL || (n = atoi(arg)) <= 0)
509 return (dt_set_errno(dtp, EDT_BADOPTVAL));
510
511 dtp->dt_conf.dtc_diftupregs = n;
512 return (0);
513 }
514
515 /*ARGSUSED*/
516 static int
517 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
518 {
519 if (arg == NULL)
520 return (dt_set_errno(dtp, EDT_BADOPTVAL));
521
522 if (strcmp(arg, "dynamic") == 0)
523 dtp->dt_xlatemode = DT_XL_DYNAMIC;
524 else if (strcmp(arg, "static") == 0)
525 dtp->dt_xlatemode = DT_XL_STATIC;
526 else
527 return (dt_set_errno(dtp, EDT_BADOPTVAL));
528
529 return (0);
530 }
531
532 /*ARGSUSED*/
533 static int
534 dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
535 {
536 if (arg != NULL)
537 return (dt_set_errno(dtp, EDT_BADOPTVAL));
538
539 if (dtp->dt_pcb != NULL)
540 dtp->dt_pcb->pcb_cflags |= option;
541 else
542 dtp->dt_cflags |= option;
543
544 return (0);
545 }
546
547 static int
548 dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
549 {
550 if (arg != NULL)
551 return (dt_set_errno(dtp, EDT_BADOPTVAL));
552
553 dtp->dt_dflags |= option;
554 return (0);
555 }
556
557 static int
558 dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
559 {
560 if (arg != NULL)
561 return (dt_set_errno(dtp, EDT_BADOPTVAL));
562
563 if (dtp->dt_pcb != NULL)
564 dtp->dt_pcb->pcb_cflags &= ~option;
565 else
566 dtp->dt_cflags &= ~option;
567
568 return (0);
569 }
570
571 /*ARGSUSED*/
572 static int
573 dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
574 {
575 dt_version_t v;
576
577 if (arg == NULL)
578 return (dt_set_errno(dtp, EDT_BADOPTVAL));
579
580 if (dt_version_str2num(arg, &v) == -1)
581 return (dt_set_errno(dtp, EDT_VERSINVAL));
582
583 if (!dt_version_defined(v))
584 return (dt_set_errno(dtp, EDT_VERSUNDEF));
585
586 return (dt_reduce(dtp, v));
587 }
588
589 static int
590 dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
591 {
592 char *end;
593 dtrace_optval_t val = 0;
594 int i;
595
596 const struct {
597 char *positive;
598 char *negative;
599 } couples[] = {
600 { "yes", "no" },
601 { "enable", "disable" },
602 { "enabled", "disabled" },
603 { "true", "false" },
604 { "on", "off" },
605 { "set", "unset" },
606 { NULL }
607 };
608
609 if (arg != NULL) {
610 if (arg[0] == '\0') {
611 val = DTRACEOPT_UNSET;
612 goto out;
613 }
614
615 for (i = 0; couples[i].positive != NULL; i++) {
616 if (strcasecmp(couples[i].positive, arg) == 0) {
617 val = 1;
618 goto out;
619 }
620
621 if (strcasecmp(couples[i].negative, arg) == 0) {
622 val = DTRACEOPT_UNSET;
623 goto out;
624 }
625 }
626
627 errno = 0;
628 val = strtoull(arg, &end, 0);
629
630 if (*end != '\0' || errno != 0 || val < 0)
631 return (dt_set_errno(dtp, EDT_BADOPTVAL));
632 }
633
634 out:
635 dtp->dt_options[option] = val;
636 return (0);
637 }
638
639 static int
640 dt_optval_parse(const char *arg, dtrace_optval_t *rval)
641 {
642 dtrace_optval_t mul = 1;
643 size_t len;
644 char *end;
645
646 len = strlen(arg);
647 errno = 0;
648
649 switch (arg[len - 1]) {
650 case 't':
651 case 'T':
652 mul *= 1024;
653 /*FALLTHRU*/
654 case 'g':
655 case 'G':
656 mul *= 1024;
657 /*FALLTHRU*/
658 case 'm':
659 case 'M':
660 mul *= 1024;
661 /*FALLTHRU*/
662 case 'k':
663 case 'K':
664 mul *= 1024;
665 /*FALLTHRU*/
666 default:
667 break;
668 }
669
670 errno = 0;
671 *rval = strtoull(arg, &end, 0) * mul;
672
673 if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
674 *rval < 0 || errno != 0)
675 return (-1);
676
677 return (0);
678 }
679
680 static int
681 dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
682 {
683 dtrace_optval_t val = 0;
684
685 if (arg != NULL && dt_optval_parse(arg, &val) != 0)
686 return (dt_set_errno(dtp, EDT_BADOPTVAL));
687
688 dtp->dt_options[option] = val;
689 return (0);
690 }
691
692 static int
693 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
694 {
695 char *end;
696 int i;
697 dtrace_optval_t mul = 1, val = 0;
698
699 const struct {
700 char *name;
701 hrtime_t mul;
702 } suffix[] = {
703 { "ns", NANOSEC / NANOSEC },
704 { "nsec", NANOSEC / NANOSEC },
705 { "us", NANOSEC / MICROSEC },
706 { "usec", NANOSEC / MICROSEC },
707 { "ms", NANOSEC / MILLISEC },
708 { "msec", NANOSEC / MILLISEC },
709 { "s", NANOSEC / SEC },
710 { "sec", NANOSEC / SEC },
711 { "m", NANOSEC * (hrtime_t)60 },
712 { "min", NANOSEC * (hrtime_t)60 },
713 { "h", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
714 { "hour", NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
715 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
716 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
717 { "hz", 0 },
718 { NULL }
719 };
720
721 if (arg != NULL) {
722 errno = 0;
723 val = strtoull(arg, &end, 0);
724
725 for (i = 0; suffix[i].name != NULL; i++) {
726 if (strcasecmp(suffix[i].name, end) == 0) {
727 mul = suffix[i].mul;
728 break;
729 }
730 }
731
732 if (suffix[i].name == NULL && *end != '\0' || val < 0)
733 return (dt_set_errno(dtp, EDT_BADOPTVAL));
734
735 if (mul == 0) {
736 /*
737 * The rate has been specified in frequency-per-second.
738 */
739 if (val != 0)
740 val = NANOSEC / val;
741 } else {
742 val *= mul;
743 }
744 }
745
746 dtp->dt_options[option] = val;
747 return (0);
748 }
749
750 /*
751 * When setting the strsize option, set the option in the dt_options array
752 * using dt_opt_size() as usual, and then update the definition of the CTF
753 * type for the D intrinsic "string" to be an array of the corresponding size.
754 * If any errors occur, reset dt_options[option] to its previous value.
755 */
756 static int
757 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
758 {
759 dtrace_optval_t val = dtp->dt_options[option];
760 ctf_file_t *fp = DT_STR_CTFP(dtp);
761 ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
762 ctf_arinfo_t r;
763
764 if (dt_opt_size(dtp, arg, option) != 0)
765 return (-1); /* dt_errno is set for us */
766
767 if (dtp->dt_options[option] > UINT_MAX) {
768 dtp->dt_options[option] = val;
769 return (dt_set_errno(dtp, EOVERFLOW));
770 }
771
772 if (ctf_array_info(fp, type, &r) == CTF_ERR) {
773 dtp->dt_options[option] = val;
774 dtp->dt_ctferr = ctf_errno(fp);
775 return (dt_set_errno(dtp, EDT_CTF));
776 }
777
778 r.ctr_nelems = (uint_t)dtp->dt_options[option];
779
780 if (ctf_set_array(fp, type, &r) == CTF_ERR ||
781 ctf_update(fp) == CTF_ERR) {
782 dtp->dt_options[option] = val;
783 dtp->dt_ctferr = ctf_errno(fp);
784 return (dt_set_errno(dtp, EDT_CTF));
785 }
786
787 return (0);
788 }
789
790 static const struct {
791 const char *dtbp_name;
792 int dtbp_policy;
793 } _dtrace_bufpolicies[] = {
794 { "ring", DTRACEOPT_BUFPOLICY_RING },
795 { "fill", DTRACEOPT_BUFPOLICY_FILL },
796 { "switch", DTRACEOPT_BUFPOLICY_SWITCH },
797 { NULL, 0 }
798 };
799
800 /*ARGSUSED*/
801 static int
802 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
803 {
804 dtrace_optval_t policy = DTRACEOPT_UNSET;
805 int i;
806
807 if (arg == NULL)
808 return (dt_set_errno(dtp, EDT_BADOPTVAL));
809
810 for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
811 if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
812 policy = _dtrace_bufpolicies[i].dtbp_policy;
813 break;
814 }
815 }
816
817 if (policy == DTRACEOPT_UNSET)
818 return (dt_set_errno(dtp, EDT_BADOPTVAL));
819
820 dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
821
822 return (0);
823 }
824
825 static const struct {
826 const char *dtbr_name;
827 int dtbr_policy;
828 } _dtrace_bufresize[] = {
829 { "auto", DTRACEOPT_BUFRESIZE_AUTO },
830 { "manual", DTRACEOPT_BUFRESIZE_MANUAL },
831 { NULL, 0 }
832 };
833
834 /*ARGSUSED*/
835 static int
836 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
837 {
838 dtrace_optval_t policy = DTRACEOPT_UNSET;
839 int i;
840
841 if (arg == NULL)
842 return (dt_set_errno(dtp, EDT_BADOPTVAL));
843
844 for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
845 if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
846 policy = _dtrace_bufresize[i].dtbr_policy;
847 break;
848 }
849 }
850
851 if (policy == DTRACEOPT_UNSET)
852 return (dt_set_errno(dtp, EDT_BADOPTVAL));
853
854 dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
855
856 return (0);
857 }
858
859 /*ARGSUSED*/
860 static int
861 dt_opt_zone(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
862 {
863 zoneid_t z, did;
864
865 if (arg == NULL)
866 return (dt_set_errno(dtp, EDT_BADOPTVAL));
867
868 /*
869 * If the specified zone is currently running, we'll query the kernel
870 * for its debugger ID. If it doesn't appear to be running, we'll look
871 * for it for among all installed zones (thereby allowing a zdefs
872 * enabling against a halted zone).
873 */
874 if ((z = getzoneidbyname(arg)) != -1) {
875 if (zone_getattr(z, ZONE_ATTR_DID, &did, sizeof (did)) < 0)
876 return (dt_set_errno(dtp, EDT_BADOPTVAL));
877 } else {
878 zone_dochandle_t handle;
879
880 if ((handle = zonecfg_init_handle()) == NULL)
881 return (dt_set_errno(dtp, errno));
882
883 if (zonecfg_get_handle(arg, handle) != Z_OK) {
884 zonecfg_fini_handle(handle);
885 return (dt_set_errno(dtp, EDT_BADOPTVAL));
886 }
887
888 did = zonecfg_get_did(handle);
889 zonecfg_fini_handle(handle);
890 }
891
892 dtp->dt_options[DTRACEOPT_ZONE] = did;
893
894 return (0);
895 }
896
897 int
898 dt_options_load(dtrace_hdl_t *dtp)
899 {
900 dof_hdr_t hdr, *dof;
901 dof_sec_t *sec;
902 size_t offs;
903 int i;
904
905 /*
906 * To load the option values, we need to ask the kernel to provide its
907 * DOF, which we'll sift through to look for OPTDESC sections.
908 */
909 bzero(&hdr, sizeof (dof_hdr_t));
910 hdr.dofh_loadsz = sizeof (dof_hdr_t);
911
912 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
913 return (dt_set_errno(dtp, errno));
914
915 if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
916 return (dt_set_errno(dtp, EINVAL));
917
918 dof = calloc(1, hdr.dofh_loadsz);
919 if (dof == NULL)
920 return (dt_set_errno(dtp, errno));
921
922 dof->dofh_loadsz = hdr.dofh_loadsz;
923
924 for (i = 0; i < DTRACEOPT_MAX; i++)
925 dtp->dt_options[i] = DTRACEOPT_UNSET;
926
927 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) {
928 free(dof);
929 return (dt_set_errno(dtp, errno));
930 }
931
932 for (i = 0; i < dof->dofh_secnum; i++) {
933 sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
934 dof->dofh_secoff + i * dof->dofh_secsize);
935
936 if (sec->dofs_type != DOF_SECT_OPTDESC)
937 continue;
938
939 break;
940 }
941
942 for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
943 dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
944 ((uintptr_t)dof + sec->dofs_offset + offs);
945
946 if (opt->dofo_strtab != DOF_SECIDX_NONE)
947 continue;
948
949 if (opt->dofo_option >= DTRACEOPT_MAX)
950 continue;
951
952 dtp->dt_options[opt->dofo_option] = opt->dofo_value;
953 }
954
955 free(dof);
956 return (0);
957 }
958
959 typedef struct dt_option {
960 const char *o_name;
961 int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
962 uintptr_t o_option;
963 } dt_option_t;
964
965 /*
966 * Compile-time options.
967 */
968 static const dt_option_t _dtrace_ctoptions[] = {
969 { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
970 { "amin", dt_opt_amin },
971 { "argref", dt_opt_cflags, DTRACE_C_ARGREF },
972 { "core", dt_opt_core },
973 { "cpp", dt_opt_cflags, DTRACE_C_CPP },
974 { "cpphdrs", dt_opt_cpp_hdrs },
975 { "cpppath", dt_opt_cpp_path },
976 { "ctypes", dt_opt_ctypes },
977 { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
978 { "dtypes", dt_opt_dtypes },
979 { "debug", dt_opt_debug },
980 { "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
981 { "droptags", dt_opt_droptags },
982 { "empty", dt_opt_cflags, DTRACE_C_EMPTY },
983 { "encoding", dt_opt_encoding },
984 { "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
985 { "evaltime", dt_opt_evaltime },
986 { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
987 { "iregs", dt_opt_iregs },
988 { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
989 { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
990 { "late", dt_opt_xlate },
991 { "lazyload", dt_opt_lazyload },
992 { "ldpath", dt_opt_ld_path },
993 { "libdir", dt_opt_libdir },
994 { "linkmode", dt_opt_linkmode },
995 { "linktype", dt_opt_linktype },
996 { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
997 { "pgmax", dt_opt_pgmax },
998 { "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
999 { "setenv", dt_opt_setenv, 1 },
1000 { "stdc", dt_opt_stdc },
1001 { "strip", dt_opt_dflags, DTRACE_D_STRIP },
1002 { "syslibdir", dt_opt_syslibdir },
1003 { "tree", dt_opt_tree },
1004 { "tregs", dt_opt_tregs },
1005 { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
1006 { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
1007 { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
1008 { "unsetenv", dt_opt_setenv, 0 },
1009 { "verbose", dt_opt_cflags, DTRACE_C_DIFV },
1010 { "version", dt_opt_version },
1011 { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
1012 { NULL }
1013 };
1014
1015 /*
1016 * Run-time options.
1017 */
1018 static const dt_option_t _dtrace_rtoptions[] = {
1019 { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
1020 { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
1021 { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
1022 { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
1023 { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
1024 { "cpu", dt_opt_runtime, DTRACEOPT_CPU },
1025 { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
1026 { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
1027 { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
1028 { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
1029 { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
1030 { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
1031 { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
1032 { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
1033 { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
1034 { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
1035 { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
1036 { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
1037 { "zone", dt_opt_zone, DTRACEOPT_ZONE },
1038 { NULL }
1039 };
1040
1041 /*
1042 * Dynamic run-time options.
1043 */
1044 static const dt_option_t _dtrace_drtoptions[] = {
1045 { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
1046 { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
1047 { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
1048 { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
1049 { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
1050 { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
1051 { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
1052 { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
1053 { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
1054 { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
1055 { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
1056 { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
1057 { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
1058 { NULL }
1059 };
1060
1061 int
1062 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
1063 {
1064 const dt_option_t *op;
1065
1066 if (opt == NULL)
1067 return (dt_set_errno(dtp, EINVAL));
1068
1069 /*
1070 * We only need to search the run-time options -- it's not legal
1071 * to get the values of compile-time options.
1072 */
1073 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1074 if (strcmp(op->o_name, opt) == 0) {
1075 *val = dtp->dt_options[op->o_option];
1076 return (0);
1077 }
1078 }
1079
1080 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1081 if (strcmp(op->o_name, opt) == 0) {
1082 *val = dtp->dt_options[op->o_option];
1083 return (0);
1084 }
1085 }
1086
1087 return (dt_set_errno(dtp, EDT_BADOPTNAME));
1088 }
1089
1090 int
1091 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1092 {
1093 const dt_option_t *op;
1094
1095 if (opt == NULL)
1096 return (dt_set_errno(dtp, EINVAL));
1097
1098 for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1099 if (strcmp(op->o_name, opt) == 0)
1100 return (op->o_func(dtp, val, op->o_option));
1101 }
1102
1103 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1104 if (strcmp(op->o_name, opt) == 0)
1105 return (op->o_func(dtp, val, op->o_option));
1106 }
1107
1108 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1109 if (strcmp(op->o_name, opt) == 0) {
1110 /*
1111 * Only dynamic run-time options may be set while
1112 * tracing is active.
1113 */
1114 if (dtp->dt_active)
1115 return (dt_set_errno(dtp, EDT_ACTIVE));
1116
1117 return (op->o_func(dtp, val, op->o_option));
1118 }
1119 }
1120
1121 return (dt_set_errno(dtp, EDT_BADOPTNAME));
1122 }