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