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_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
201 {
202 	dtp->dt_droptags = 1;
203 	return (0);
204 }
205 
206 /*ARGSUSED*/
207 static int
208 dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
209 {
210 	int fd;
211 
212 	if (arg == NULL)
213 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
214 
215 	if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
216 		return (dt_set_errno(dtp, errno));
217 
218 	(void) close(dtp->dt_ddefs_fd);
219 	dtp->dt_ddefs_fd = fd;
220 	return (0);
221 }
222 
223 /*ARGSUSED*/
224 static int
225 dt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
226 {
227 	if (arg != NULL)
228 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
229 
230 	_dtrace_debug = 1;
231 	return (0);
232 }
233 
234 /*ARGSUSED*/
235 static int
236 dt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
237 {
238 	int n;
239 
240 	if (arg == NULL || (n = atoi(arg)) <= 0)
241 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
242 
243 	dtp->dt_conf.dtc_difintregs = n;
244 	return (0);
245 }
246 
247 /*ARGSUSED*/
248 static int
249 dt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
250 {
251 	dtp->dt_lazyload = 1;
252 
253 	return (0);
254 }
255 
256 /*ARGSUSED*/
257 static int
258 dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
259 {
260 	char *ld;
261 
262 	if (arg == NULL)
263 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
264 
265 	if (dtp->dt_pcb != NULL)
266 		return (dt_set_errno(dtp, EDT_BADOPTCTX));
267 
268 	if ((ld = strdup(arg)) == NULL)
269 		return (dt_set_errno(dtp, EDT_NOMEM));
270 
271 	free(dtp->dt_ld_path);
272 	dtp->dt_ld_path = ld;
273 
274 	return (0);
275 }
276 
277 /*ARGSUSED*/
278 static int
279 dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
280 {
281 	dt_dirpath_t *dp;
282 
283 	if (arg == NULL)
284 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
285 
286 	if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
287 	    (dp->dir_path = strdup(arg)) == NULL) {
288 		free(dp);
289 		return (dt_set_errno(dtp, EDT_NOMEM));
290 	}
291 
292 	dt_list_append(&dtp->dt_lib_path, dp);
293 	return (0);
294 }
295 
296 /*ARGSUSED*/
297 static int
298 dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
299 {
300 	if (arg == NULL)
301 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
302 
303 	if (strcmp(arg, "kernel") == 0)
304 		dtp->dt_linkmode = DT_LINK_KERNEL;
305 	else if (strcmp(arg, "primary") == 0)
306 		dtp->dt_linkmode = DT_LINK_PRIMARY;
307 	else if (strcmp(arg, "dynamic") == 0)
308 		dtp->dt_linkmode = DT_LINK_DYNAMIC;
309 	else if (strcmp(arg, "static") == 0)
310 		dtp->dt_linkmode = DT_LINK_STATIC;
311 	else
312 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
313 
314 	return (0);
315 }
316 
317 /*ARGSUSED*/
318 static int
319 dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
320 {
321 	if (arg == NULL)
322 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
323 
324 	if (strcasecmp(arg, "elf") == 0)
325 		dtp->dt_linktype = DT_LTYP_ELF;
326 	else if (strcasecmp(arg, "dof") == 0)
327 		dtp->dt_linktype = DT_LTYP_DOF;
328 	else
329 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
330 
331 	return (0);
332 }
333 
334 /*ARGSUSED*/
335 static int
336 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
337 {
338 	if (arg == NULL)
339 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
340 
341 	if (strcmp(arg, "exec") == 0)
342 		dtp->dt_prcmode = DT_PROC_STOP_CREATE;
343 	else if (strcmp(arg, "preinit") == 0)
344 		dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
345 	else if (strcmp(arg, "postinit") == 0)
346 		dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
347 	else if (strcmp(arg, "main") == 0)
348 		dtp->dt_prcmode = DT_PROC_STOP_MAIN;
349 	else
350 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
351 
352 	return (0);
353 }
354 
355 /*ARGSUSED*/
356 static int
357 dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
358 {
359 	int n;
360 
361 	if (arg == NULL || (n = atoi(arg)) < 0)
362 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
363 
364 	dtp->dt_procs->dph_lrulim = n;
365 	return (0);
366 }
367 
368 /*ARGSUSED*/
369 static int
370 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
371 {
372 	if (arg == NULL)
373 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
374 
375 	if (dtp->dt_pcb != NULL)
376 		return (dt_set_errno(dtp, EDT_BADOPTCTX));
377 
378 	if (strcmp(arg, "a") == 0)
379 		dtp->dt_stdcmode = DT_STDC_XA;
380 	else if (strcmp(arg, "c") == 0)
381 		dtp->dt_stdcmode = DT_STDC_XC;
382 	else if (strcmp(arg, "s") == 0)
383 		dtp->dt_stdcmode = DT_STDC_XS;
384 	else if (strcmp(arg, "t") == 0)
385 		dtp->dt_stdcmode = DT_STDC_XT;
386 	else
387 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
388 
389 	return (0);
390 }
391 
392 /*ARGSUSED*/
393 static int
394 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
395 {
396 	dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
397 	char *path;
398 
399 	if (arg == NULL)
400 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
401 
402 	if ((path = strdup(arg)) == NULL)
403 		return (dt_set_errno(dtp, EDT_NOMEM));
404 
405 	free(dp->dir_path);
406 	dp->dir_path = path;
407 
408 	return (0);
409 }
410 
411 
412 /*ARGSUSED*/
413 static int
414 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
415 {
416 	int m;
417 
418 	if (arg == NULL || (m = atoi(arg)) <= 0)
419 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
420 
421 	dtp->dt_treedump = m;
422 	return (0);
423 }
424 
425 /*ARGSUSED*/
426 static int
427 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
428 {
429 	int n;
430 
431 	if (arg == NULL || (n = atoi(arg)) <= 0)
432 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
433 
434 	dtp->dt_conf.dtc_diftupregs = n;
435 	return (0);
436 }
437 
438 /*ARGSUSED*/
439 static int
440 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
441 {
442 	if (arg == NULL)
443 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
444 
445 	if (strcmp(arg, "dynamic") == 0)
446 		dtp->dt_xlatemode = DT_XL_DYNAMIC;
447 	else if (strcmp(arg, "static") == 0)
448 		dtp->dt_xlatemode = DT_XL_STATIC;
449 	else
450 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
451 
452 	return (0);
453 }
454 
455 /*ARGSUSED*/
456 
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_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
565 {
566 	char *end;
567 	int len;
568 	dtrace_optval_t mul = 1, val = 0;
569 
570 	if (arg != NULL) {
571 		len = strlen(arg);
572 		errno = 0;
573 
574 		switch (arg[len - 1]) {
575 		case 't':
576 		case 'T':
577 			mul *= 1024;
578 			/*FALLTHRU*/
579 		case 'g':
580 		case 'G':
581 			mul *= 1024;
582 			/*FALLTHRU*/
583 		case 'm':
584 		case 'M':
585 			mul *= 1024;
586 			/*FALLTHRU*/
587 		case 'k':
588 		case 'K':
589 			mul *= 1024;
590 			/*FALLTHRU*/
591 		default:
592 			break;
593 		}
594 
595 		val = strtoull(arg, &end, 0) * mul;
596 
597 		if ((mul > 1 && end != &arg[len - 1]) ||
598 		    (mul == 1 && *end != '\0') || val < 0 ||
599 		    errno != 0 || val == DTRACEOPT_UNSET)
600 			return (dt_set_errno(dtp, EDT_BADOPTVAL));
601 	}
602 
603 	dtp->dt_options[option] = val;
604 	return (0);
605 }
606 
607 static int
608 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
609 {
610 	char *end;
611 	int i;
612 	dtrace_optval_t mul = 1, val = 0;
613 
614 	const struct {
615 		char *name;
616 		hrtime_t mul;
617 	} suffix[] = {
618 		{ "ns", 	NANOSEC / NANOSEC },
619 		{ "nsec",	NANOSEC / NANOSEC },
620 		{ "us",		NANOSEC / MICROSEC },
621 		{ "usec",	NANOSEC / MICROSEC },
622 		{ "ms",		NANOSEC / MILLISEC },
623 		{ "msec",	NANOSEC / MILLISEC },
624 		{ "s",		NANOSEC / SEC },
625 		{ "sec",	NANOSEC / SEC },
626 		{ "m",		NANOSEC * (hrtime_t)60 },
627 		{ "min",	NANOSEC * (hrtime_t)60 },
628 		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
629 		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
630 		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
631 		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
632 		{ "hz",		0 },
633 		{ NULL }
634 	};
635 
636 	if (arg != NULL) {
637 		errno = 0;
638 		val = strtoull(arg, &end, 0);
639 
640 		for (i = 0; suffix[i].name != NULL; i++) {
641 			if (strcasecmp(suffix[i].name, end) == 0) {
642 				mul = suffix[i].mul;
643 				break;
644 			}
645 		}
646 
647 		if (suffix[i].name == NULL && *end != '\0' || val < 0)
648 			return (dt_set_errno(dtp, EDT_BADOPTVAL));
649 
650 		if (mul == 0) {
651 			/*
652 			 * The rate has been specified in frequency-per-second.
653 			 */
654 			if (val != 0)
655 				val = NANOSEC / val;
656 		} else {
657 			val *= mul;
658 		}
659 	}
660 
661 	dtp->dt_options[option] = val;
662 	return (0);
663 }
664 
665 /*
666  * When setting the strsize option, set the option in the dt_options array
667  * using dt_opt_size() as usual, and then update the definition of the CTF
668  * type for the D intrinsic "string" to be an array of the corresponding size.
669  * If any errors occur, reset dt_options[option] to its previous value.
670  */
671 static int
672 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
673 {
674 	dtrace_optval_t val = dtp->dt_options[option];
675 	ctf_file_t *fp = DT_STR_CTFP(dtp);
676 	ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
677 	ctf_arinfo_t r;
678 
679 	if (dt_opt_size(dtp, arg, option) != 0)
680 		return (-1); /* dt_errno is set for us */
681 
682 	if (dtp->dt_options[option] > UINT_MAX) {
683 		dtp->dt_options[option] = val;
684 		return (dt_set_errno(dtp, EOVERFLOW));
685 	}
686 
687 	if (ctf_array_info(fp, type, &r) == CTF_ERR) {
688 		dtp->dt_options[option] = val;
689 		dtp->dt_ctferr = ctf_errno(fp);
690 		return (dt_set_errno(dtp, EDT_CTF));
691 	}
692 
693 	r.ctr_nelems = (uint_t)dtp->dt_options[option];
694 
695 	if (ctf_set_array(fp, type, &r) == CTF_ERR ||
696 	    ctf_update(fp) == 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 	return (0);
703 }
704 
705 static const struct {
706 	const char *dtbp_name;
707 	int dtbp_policy;
708 } _dtrace_bufpolicies[] = {
709 	{ "ring", DTRACEOPT_BUFPOLICY_RING },
710 	{ "fill", DTRACEOPT_BUFPOLICY_FILL },
711 	{ "switch", DTRACEOPT_BUFPOLICY_SWITCH },
712 	{ NULL, 0 }
713 };
714 
715 /*ARGSUSED*/
716 static int
717 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
718 {
719 	dtrace_optval_t policy = DTRACEOPT_UNSET;
720 	int i;
721 
722 	if (arg == NULL)
723 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
724 
725 	for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
726 		if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
727 			policy = _dtrace_bufpolicies[i].dtbp_policy;
728 			break;
729 		}
730 	}
731 
732 	if (policy == DTRACEOPT_UNSET)
733 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
734 
735 	dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
736 
737 	return (0);
738 }
739 
740 static const struct {
741 	const char *dtbr_name;
742 	int dtbr_policy;
743 } _dtrace_bufresize[] = {
744 	{ "auto", DTRACEOPT_BUFRESIZE_AUTO },
745 	{ "manual", DTRACEOPT_BUFRESIZE_MANUAL },
746 	{ NULL, 0 }
747 };
748 
749 /*ARGSUSED*/
750 static int
751 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
752 {
753 	dtrace_optval_t policy = DTRACEOPT_UNSET;
754 	int i;
755 
756 	if (arg == NULL)
757 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
758 
759 	for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
760 		if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
761 			policy = _dtrace_bufresize[i].dtbr_policy;
762 			break;
763 		}
764 	}
765 
766 	if (policy == DTRACEOPT_UNSET)
767 		return (dt_set_errno(dtp, EDT_BADOPTVAL));
768 
769 	dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
770 
771 	return (0);
772 }
773 
774 int
775 dt_options_load(dtrace_hdl_t *dtp)
776 {
777 	dof_hdr_t hdr, *dof;
778 	dof_sec_t *sec;
779 	size_t offs;
780 	int i;
781 
782 	/*
783 	 * To load the option values, we need to ask the kernel to provide its
784 	 * DOF, which we'll sift through to look for OPTDESC sections.
785 	 */
786 	bzero(&hdr, sizeof (dof_hdr_t));
787 	hdr.dofh_loadsz = sizeof (dof_hdr_t);
788 
789 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
790 		return (dt_set_errno(dtp, errno));
791 
792 	if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
793 		return (dt_set_errno(dtp, EINVAL));
794 
795 	dof = alloca(hdr.dofh_loadsz);
796 	bzero(dof, sizeof (dof_hdr_t));
797 	dof->dofh_loadsz = hdr.dofh_loadsz;
798 
799 	for (i = 0; i < DTRACEOPT_MAX; i++)
800 		dtp->dt_options[i] = DTRACEOPT_UNSET;
801 
802 	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
803 		return (dt_set_errno(dtp, errno));
804 
805 	for (i = 0; i < dof->dofh_secnum; i++) {
806 		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
807 		    dof->dofh_secoff + i * dof->dofh_secsize);
808 
809 		if (sec->dofs_type != DOF_SECT_OPTDESC)
810 			continue;
811 
812 		break;
813 	}
814 
815 	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
816 		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
817 		    ((uintptr_t)dof + sec->dofs_offset + offs);
818 
819 		if (opt->dofo_strtab != DOF_SECIDX_NONE)
820 			continue;
821 
822 		if (opt->dofo_option >= DTRACEOPT_MAX)
823 			continue;
824 
825 		dtp->dt_options[opt->dofo_option] = opt->dofo_value;
826 	}
827 
828 	return (0);
829 }
830 
831 typedef struct dt_option {
832 	const char *o_name;
833 	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
834 	uintptr_t o_option;
835 } dt_option_t;
836 
837 /*
838  * Compile-time options.
839  */
840 static const dt_option_t _dtrace_ctoptions[] = {
841 	{ "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
842 	{ "amin", dt_opt_amin },
843 	{ "argref", dt_opt_cflags, DTRACE_C_ARGREF },
844 	{ "core", dt_opt_core },
845 	{ "cpp", dt_opt_cflags, DTRACE_C_CPP },
846 	{ "cpphdrs", dt_opt_cpp_hdrs },
847 	{ "cpppath", dt_opt_cpp_path },
848 	{ "ctypes", dt_opt_ctypes },
849 	{ "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
850 	{ "dtypes", dt_opt_dtypes },
851 	{ "debug", dt_opt_debug },
852 	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
853 	{ "droptags", dt_opt_droptags },
854 	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
855 	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
856 	{ "evaltime", dt_opt_evaltime },
857 	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
858 	{ "iregs", dt_opt_iregs },
859 	{ "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
860 	{ "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
861 	{ "late", dt_opt_xlate },
862 	{ "lazyload", dt_opt_lazyload },
863 	{ "ldpath", dt_opt_ld_path },
864 	{ "libdir", dt_opt_libdir },
865 	{ "linkmode", dt_opt_linkmode },
866 	{ "linktype", dt_opt_linktype },
867 	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
868 	{ "pgmax", dt_opt_pgmax },
869 	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
870 	{ "stdc", dt_opt_stdc },
871 	{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
872 	{ "syslibdir", dt_opt_syslibdir },
873 	{ "tree", dt_opt_tree },
874 	{ "tregs", dt_opt_tregs },
875 	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
876 	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
877 	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
878 	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
879 	{ "version", dt_opt_version },
880 	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
881 	{ NULL }
882 };
883 
884 /*
885  * Run-time options.
886  */
887 static const dt_option_t _dtrace_rtoptions[] = {
888 	{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
889 	{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
890 	{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
891 	{ "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
892 	{ "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
893 	{ "cpu", dt_opt_runtime, DTRACEOPT_CPU },
894 	{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
895 	{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
896 	{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
897 	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
898 	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
899 	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
900 	{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
901 	{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
902 	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
903 	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
904 	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
905 	{ NULL }
906 };
907 
908 /*
909  * Dynamic run-time options.
910  */
911 static const dt_option_t _dtrace_drtoptions[] = {
912 	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
913 	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
914 	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
915 	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
916 	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
917 	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
918 	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
919 	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
920 	{ "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
921 	{ "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
922 	{ NULL }
923 };
924 
925 int
926 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
927 {
928 	const dt_option_t *op;
929 
930 	if (opt == NULL)
931 		return (dt_set_errno(dtp, EINVAL));
932 
933 	/*
934 	 * We only need to search the run-time options -- it's not legal
935 	 * to get the values of compile-time options.
936 	 */
937 	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
938 		if (strcmp(op->o_name, opt) == 0) {
939 			*val = dtp->dt_options[op->o_option];
940 			return (0);
941 		}
942 	}
943 
944 	for (op = _dtrace_drtoptions; 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 	return (dt_set_errno(dtp, EDT_BADOPTNAME));
952 }
953 
954 int
955 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
956 {
957 	const dt_option_t *op;
958 
959 	if (opt == NULL)
960 		return (dt_set_errno(dtp, EINVAL));
961 
962 	for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
963 		if (strcmp(op->o_name, opt) == 0)
964 			return (op->o_func(dtp, val, op->o_option));
965 	}
966 
967 	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
968 		if (strcmp(op->o_name, opt) == 0)
969 			return (op->o_func(dtp, val, op->o_option));
970 	}
971 
972 	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
973 		if (strcmp(op->o_name, opt) == 0) {
974 			/*
975 			 * Only dynamic run-time options may be set while
976 			 * tracing is active.
977 			 */
978 			if (dtp->dt_active)
979 				return (dt_set_errno(dtp, EDT_ACTIVE));
980 
981 			return (op->o_func(dtp, val, op->o_option));
982 		}
983 	}
984 
985 	return (dt_set_errno(dtp, EDT_BADOPTNAME));
986 }
987