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