xref: /freebsd/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c (revision 7aa383846770374466b1dcb2cefd71bde9acf463)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/resource.h>
30 #include <sys/mman.h>
31 #include <sys/types.h>
32 
33 #include <strings.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <limits.h>
38 #if defined(sun)
39 #include <alloca.h>
40 #endif
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 /*ARGSUSED*/
372 static int
373 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
374 {
375 	if (arg == NULL)
376 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
377 
378 	if (dtp->dt_pcb != NULL)
379 		return (dt_set_errno(dtp, EDT_BADOPTCTX));
380 
381 	if (strcmp(arg, "a") == 0)
382 		dtp->dt_stdcmode = DT_STDC_XA;
383 	else if (strcmp(arg, "c") == 0)
384 		dtp->dt_stdcmode = DT_STDC_XC;
385 	else if (strcmp(arg, "s") == 0)
386 		dtp->dt_stdcmode = DT_STDC_XS;
387 	else if (strcmp(arg, "t") == 0)
388 		dtp->dt_stdcmode = DT_STDC_XT;
389 	else
390 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
391 
392 	return (0);
393 }
394 
395 /*ARGSUSED*/
396 static int
397 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
398 {
399 	dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
400 	char *path;
401 
402 	if (arg == NULL)
403 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
404 
405 	if ((path = strdup(arg)) == NULL)
406 		return (dt_set_errno(dtp, EDT_NOMEM));
407 
408 	free(dp->dir_path);
409 	dp->dir_path = path;
410 
411 	return (0);
412 }
413 
414 
415 /*ARGSUSED*/
416 static int
417 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
418 {
419 	int m;
420 
421 	if (arg == NULL || (m = atoi(arg)) <= 0)
422 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
423 
424 	dtp->dt_treedump = m;
425 	return (0);
426 }
427 
428 /*ARGSUSED*/
429 static int
430 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
431 {
432 	int n;
433 
434 	if (arg == NULL || (n = atoi(arg)) <= 0)
435 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
436 
437 	dtp->dt_conf.dtc_diftupregs = n;
438 	return (0);
439 }
440 
441 /*ARGSUSED*/
442 static int
443 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
444 {
445 	if (arg == NULL)
446 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
447 
448 	if (strcmp(arg, "dynamic") == 0)
449 		dtp->dt_xlatemode = DT_XL_DYNAMIC;
450 	else if (strcmp(arg, "static") == 0)
451 		dtp->dt_xlatemode = DT_XL_STATIC;
452 	else
453 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
454 
455 	return (0);
456 }
457 
458 /*ARGSUSED*/
459 static int
460 dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
461 {
462 	if (arg != NULL)
463 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
464 
465 	if (dtp->dt_pcb != NULL)
466 		dtp->dt_pcb->pcb_cflags |= option;
467 	else
468 		dtp->dt_cflags |= option;
469 
470 	return (0);
471 }
472 
473 static int
474 dt_opt_dflags(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 	dtp->dt_dflags |= option;
480 	return (0);
481 }
482 
483 static int
484 dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
485 {
486 	if (arg != NULL)
487 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
488 
489 	if (dtp->dt_pcb != NULL)
490 		dtp->dt_pcb->pcb_cflags &= ~option;
491 	else
492 		dtp->dt_cflags &= ~option;
493 
494 	return (0);
495 }
496 
497 /*ARGSUSED*/
498 static int
499 dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
500 {
501 	dt_version_t v;
502 
503 	if (arg == NULL)
504 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
505 
506 	if (dt_version_str2num(arg, &v) == -1)
507 		return (dt_set_errno(dtp, EDT_VERSINVAL));
508 
509 	if (!dt_version_defined(v))
510 		return (dt_set_errno(dtp, EDT_VERSUNDEF));
511 
512 	return (dt_reduce(dtp, v));
513 }
514 
515 static int
516 dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
517 {
518 	char *end;
519 	dtrace_optval_t val = 0;
520 	int i;
521 
522 	const struct {
523 		char *positive;
524 		char *negative;
525 	} couples[] = {
526 		{ "yes",	"no" },
527 		{ "enable",	"disable" },
528 		{ "enabled",	"disabled" },
529 		{ "true",	"false" },
530 		{ "on",		"off" },
531 		{ "set",	"unset" },
532 		{ NULL }
533 	};
534 
535 	if (arg != NULL) {
536 		if (arg[0] == '\0') {
537 			val = DTRACEOPT_UNSET;
538 			goto out;
539 		}
540 
541 		for (i = 0; couples[i].positive != NULL; i++) {
542 			if (strcasecmp(couples[i].positive, arg) == 0) {
543 				val = 1;
544 				goto out;
545 			}
546 
547 			if (strcasecmp(couples[i].negative, arg) == 0) {
548 				val = DTRACEOPT_UNSET;
549 				goto out;
550 			}
551 		}
552 
553 		errno = 0;
554 		val = strtoull(arg, &end, 0);
555 
556 		if (*end != '\0' || errno != 0 || val < 0)
557 			return (dt_set_errno(dtp, EDT_BADOPTVAL));
558 	}
559 
560 out:
561 	dtp->dt_options[option] = val;
562 	return (0);
563 }
564 
565 static int
566 dt_optval_parse(const char *arg, dtrace_optval_t *rval)
567 {
568 	dtrace_optval_t mul = 1;
569 	size_t len;
570 	char *end;
571 
572 	len = strlen(arg);
573 	errno = 0;
574 
575 	switch (arg[len - 1]) {
576 	case 't':
577 	case 'T':
578 		mul *= 1024;
579 		/*FALLTHRU*/
580 	case 'g':
581 	case 'G':
582 		mul *= 1024;
583 		/*FALLTHRU*/
584 	case 'm':
585 	case 'M':
586 		mul *= 1024;
587 		/*FALLTHRU*/
588 	case 'k':
589 	case 'K':
590 		mul *= 1024;
591 		/*FALLTHRU*/
592 	default:
593 		break;
594 	}
595 
596 	errno = 0;
597 	*rval = strtoull(arg, &end, 0) * mul;
598 
599 	if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
600 	    *rval < 0 || errno != 0)
601 		return (-1);
602 
603 	return (0);
604 }
605 
606 static int
607 dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
608 {
609 	dtrace_optval_t val = 0;
610 
611 	if (arg != NULL && dt_optval_parse(arg, &val) != 0)
612 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
613 
614 	dtp->dt_options[option] = val;
615 	return (0);
616 }
617 
618 static int
619 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
620 {
621 	char *end;
622 	int i;
623 	dtrace_optval_t mul = 1, val = 0;
624 
625 	const struct {
626 		char *name;
627 		hrtime_t mul;
628 	} suffix[] = {
629 		{ "ns", 	NANOSEC / NANOSEC },
630 		{ "nsec",	NANOSEC / NANOSEC },
631 		{ "us",		NANOSEC / MICROSEC },
632 		{ "usec",	NANOSEC / MICROSEC },
633 		{ "ms",		NANOSEC / MILLISEC },
634 		{ "msec",	NANOSEC / MILLISEC },
635 		{ "s",		NANOSEC / SEC },
636 		{ "sec",	NANOSEC / SEC },
637 		{ "m",		NANOSEC * (hrtime_t)60 },
638 		{ "min",	NANOSEC * (hrtime_t)60 },
639 		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
640 		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
641 		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
642 		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
643 		{ "hz",		0 },
644 		{ NULL }
645 	};
646 
647 	if (arg != NULL) {
648 		errno = 0;
649 		val = strtoull(arg, &end, 0);
650 
651 		for (i = 0; suffix[i].name != NULL; i++) {
652 			if (strcasecmp(suffix[i].name, end) == 0) {
653 				mul = suffix[i].mul;
654 				break;
655 			}
656 		}
657 
658 		if (suffix[i].name == NULL && *end != '\0' || val < 0)
659 			return (dt_set_errno(dtp, EDT_BADOPTVAL));
660 
661 		if (mul == 0) {
662 			/*
663 			 * The rate has been specified in frequency-per-second.
664 			 */
665 			if (val != 0)
666 				val = NANOSEC / val;
667 		} else {
668 			val *= mul;
669 		}
670 	}
671 
672 	dtp->dt_options[option] = val;
673 	return (0);
674 }
675 
676 /*
677  * When setting the strsize option, set the option in the dt_options array
678  * using dt_opt_size() as usual, and then update the definition of the CTF
679  * type for the D intrinsic "string" to be an array of the corresponding size.
680  * If any errors occur, reset dt_options[option] to its previous value.
681  */
682 static int
683 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
684 {
685 	dtrace_optval_t val = dtp->dt_options[option];
686 	ctf_file_t *fp = DT_STR_CTFP(dtp);
687 	ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
688 	ctf_arinfo_t r;
689 
690 	if (dt_opt_size(dtp, arg, option) != 0)
691 		return (-1); /* dt_errno is set for us */
692 
693 	if (dtp->dt_options[option] > UINT_MAX) {
694 		dtp->dt_options[option] = val;
695 		return (dt_set_errno(dtp, EOVERFLOW));
696 	}
697 
698 	if (ctf_array_info(fp, type, &r) == CTF_ERR) {
699 		dtp->dt_options[option] = val;
700 		dtp->dt_ctferr = ctf_errno(fp);
701 		return (dt_set_errno(dtp, EDT_CTF));
702 	}
703 
704 	r.ctr_nelems = (uint_t)dtp->dt_options[option];
705 
706 	if (ctf_set_array(fp, type, &r) == CTF_ERR ||
707 	    ctf_update(fp) == CTF_ERR) {
708 		dtp->dt_options[option] = val;
709 		dtp->dt_ctferr = ctf_errno(fp);
710 		return (dt_set_errno(dtp, EDT_CTF));
711 	}
712 
713 	return (0);
714 }
715 
716 static const struct {
717 	const char *dtbp_name;
718 	int dtbp_policy;
719 } _dtrace_bufpolicies[] = {
720 	{ "ring", DTRACEOPT_BUFPOLICY_RING },
721 	{ "fill", DTRACEOPT_BUFPOLICY_FILL },
722 	{ "switch", DTRACEOPT_BUFPOLICY_SWITCH },
723 	{ NULL, 0 }
724 };
725 
726 /*ARGSUSED*/
727 static int
728 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
729 {
730 	dtrace_optval_t policy = DTRACEOPT_UNSET;
731 	int i;
732 
733 	if (arg == NULL)
734 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
735 
736 	for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
737 		if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
738 			policy = _dtrace_bufpolicies[i].dtbp_policy;
739 			break;
740 		}
741 	}
742 
743 	if (policy == DTRACEOPT_UNSET)
744 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
745 
746 	dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
747 
748 	return (0);
749 }
750 
751 static const struct {
752 	const char *dtbr_name;
753 	int dtbr_policy;
754 } _dtrace_bufresize[] = {
755 	{ "auto", DTRACEOPT_BUFRESIZE_AUTO },
756 	{ "manual", DTRACEOPT_BUFRESIZE_MANUAL },
757 	{ NULL, 0 }
758 };
759 
760 /*ARGSUSED*/
761 static int
762 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
763 {
764 	dtrace_optval_t policy = DTRACEOPT_UNSET;
765 	int i;
766 
767 	if (arg == NULL)
768 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
769 
770 	for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
771 		if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
772 			policy = _dtrace_bufresize[i].dtbr_policy;
773 			break;
774 		}
775 	}
776 
777 	if (policy == DTRACEOPT_UNSET)
778 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
779 
780 	dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
781 
782 	return (0);
783 }
784 
785 int
786 dt_options_load(dtrace_hdl_t *dtp)
787 {
788 	dof_hdr_t hdr, *dof;
789 	dof_sec_t *sec;
790 	size_t offs;
791 	int i;
792 
793 	/*
794 	 * To load the option values, we need to ask the kernel to provide its
795 	 * DOF, which we'll sift through to look for OPTDESC sections.
796 	 */
797 	bzero(&hdr, sizeof (dof_hdr_t));
798 	hdr.dofh_loadsz = sizeof (dof_hdr_t);
799 
800 #if defined(sun)
801 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
802 #else
803 	dof = &hdr;
804 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
805 #endif
806 		return (dt_set_errno(dtp, errno));
807 
808 	if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
809 		return (dt_set_errno(dtp, EINVAL));
810 
811 	dof = alloca(hdr.dofh_loadsz);
812 	bzero(dof, sizeof (dof_hdr_t));
813 	dof->dofh_loadsz = hdr.dofh_loadsz;
814 
815 	for (i = 0; i < DTRACEOPT_MAX; i++)
816 		dtp->dt_options[i] = DTRACEOPT_UNSET;
817 
818 #if defined(sun)
819 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
820 #else
821 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
822 #endif
823 		return (dt_set_errno(dtp, errno));
824 
825 	for (i = 0; i < dof->dofh_secnum; i++) {
826 		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
827 		    dof->dofh_secoff + i * dof->dofh_secsize);
828 
829 		if (sec->dofs_type != DOF_SECT_OPTDESC)
830 			continue;
831 
832 		break;
833 	}
834 
835 	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
836 		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
837 		    ((uintptr_t)dof + sec->dofs_offset + offs);
838 
839 		if (opt->dofo_strtab != DOF_SECIDX_NONE)
840 			continue;
841 
842 		if (opt->dofo_option >= DTRACEOPT_MAX)
843 			continue;
844 
845 		dtp->dt_options[opt->dofo_option] = opt->dofo_value;
846 	}
847 
848 	return (0);
849 }
850 
851 /*ARGSUSED*/
852 static int
853 dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
854 {
855 	dtrace_optval_t size;
856 	void *p;
857 
858 	if (arg == NULL || dt_optval_parse(arg, &size) != 0)
859 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
860 
861 	if (size > SIZE_MAX)
862 		size = SIZE_MAX;
863 
864 	if ((p = dt_zalloc(dtp, size)) == NULL) {
865 		do {
866 			size /= 2;
867 		} while ((p = dt_zalloc(dtp, size)) == NULL);
868 	}
869 
870 	dt_free(dtp, p);
871 
872 	return (0);
873 }
874 
875 typedef struct dt_option {
876 	const char *o_name;
877 	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
878 	uintptr_t o_option;
879 } dt_option_t;
880 
881 /*
882  * Compile-time options.
883  */
884 static const dt_option_t _dtrace_ctoptions[] = {
885 	{ "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
886 	{ "amin", dt_opt_amin },
887 	{ "argref", dt_opt_cflags, DTRACE_C_ARGREF },
888 	{ "core", dt_opt_core },
889 	{ "cpp", dt_opt_cflags, DTRACE_C_CPP },
890 	{ "cpphdrs", dt_opt_cpp_hdrs },
891 	{ "cpppath", dt_opt_cpp_path },
892 	{ "ctypes", dt_opt_ctypes },
893 	{ "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
894 	{ "dtypes", dt_opt_dtypes },
895 	{ "debug", dt_opt_debug },
896 	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
897 	{ "droptags", dt_opt_droptags },
898 	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
899 	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
900 	{ "evaltime", dt_opt_evaltime },
901 	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
902 	{ "iregs", dt_opt_iregs },
903 	{ "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
904 	{ "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
905 	{ "late", dt_opt_xlate },
906 	{ "lazyload", dt_opt_lazyload },
907 	{ "ldpath", dt_opt_ld_path },
908 	{ "libdir", dt_opt_libdir },
909 	{ "linkmode", dt_opt_linkmode },
910 	{ "linktype", dt_opt_linktype },
911 	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
912 	{ "pgmax", dt_opt_pgmax },
913 	{ "preallocate", dt_opt_preallocate },
914 	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
915 	{ "stdc", dt_opt_stdc },
916 	{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
917 	{ "syslibdir", dt_opt_syslibdir },
918 	{ "tree", dt_opt_tree },
919 	{ "tregs", dt_opt_tregs },
920 	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
921 	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
922 	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
923 	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
924 	{ "version", dt_opt_version },
925 	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
926 	{ NULL, NULL, 0 }
927 };
928 
929 /*
930  * Run-time options.
931  */
932 static const dt_option_t _dtrace_rtoptions[] = {
933 	{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
934 	{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
935 	{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
936 	{ "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
937 	{ "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
938 	{ "cpu", dt_opt_runtime, DTRACEOPT_CPU },
939 	{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
940 	{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
941 	{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
942 	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
943 	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
944 	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
945 	{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
946 	{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
947 	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
948 	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
949 	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
950 	{ NULL, NULL, 0 }
951 };
952 
953 /*
954  * Dynamic run-time options.
955  */
956 static const dt_option_t _dtrace_drtoptions[] = {
957 	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
958 	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
959 	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
960 	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
961 	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
962 	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
963 	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
964 	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
965 	{ "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
966 	{ "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
967 	{ NULL, NULL, 0 }
968 };
969 
970 int
971 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
972 {
973 	const dt_option_t *op;
974 
975 	if (opt == NULL)
976 		return (dt_set_errno(dtp, EINVAL));
977 
978 	/*
979 	 * We only need to search the run-time options -- it's not legal
980 	 * to get the values of compile-time options.
981 	 */
982 	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
983 		if (strcmp(op->o_name, opt) == 0) {
984 			*val = dtp->dt_options[op->o_option];
985 			return (0);
986 		}
987 	}
988 
989 	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
990 		if (strcmp(op->o_name, opt) == 0) {
991 			*val = dtp->dt_options[op->o_option];
992 			return (0);
993 		}
994 	}
995 
996 	return (dt_set_errno(dtp, EDT_BADOPTNAME));
997 }
998 
999 int
1000 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1001 {
1002 	const dt_option_t *op;
1003 
1004 	if (opt == NULL)
1005 		return (dt_set_errno(dtp, EINVAL));
1006 
1007 	for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1008 		if (strcmp(op->o_name, opt) == 0)
1009 			return (op->o_func(dtp, val, op->o_option));
1010 	}
1011 
1012 	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1013 		if (strcmp(op->o_name, opt) == 0)
1014 			return (op->o_func(dtp, val, op->o_option));
1015 	}
1016 
1017 	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1018 		if (strcmp(op->o_name, opt) == 0) {
1019 			/*
1020 			 * Only dynamic run-time options may be set while
1021 			 * tracing is active.
1022 			 */
1023 			if (dtp->dt_active)
1024 				return (dt_set_errno(dtp, EDT_ACTIVE));
1025 
1026 			return (op->o_func(dtp, val, op->o_option));
1027 		}
1028 	}
1029 
1030 	return (dt_set_errno(dtp, EDT_BADOPTNAME));
1031 }
1032