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