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