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