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