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