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