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