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