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