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