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
50static int
51dt_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*/
63static int
64dt_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
86static void
87dt_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*/
110static int
111dt_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*/
125static int
126dt_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*/
141static int
142dt_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
162static int
163dt_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*/
188static int
189dt_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*/
205static int
206dt_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*/
213static int
214dt_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*/
230static int
231dt_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*/
241static int
242dt_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*/
254static int
255dt_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*/
263static int
264dt_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__
284static int
285dt_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*/
306static int
307dt_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*/
325static int
326dt_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*/
346static int
347dt_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*/
363static int
364dt_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*/
380static int
381dt_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*/
401static int
402dt_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
413static int
414dt_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*/
470static int
471dt_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*/
494static int
495dt_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*/
513static int
514dt_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*/
526static int
527dt_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*/
539static int
540dt_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*/
556static int
557dt_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
570static int
571dt_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
580static int
581dt_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*/
595static int
596dt_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
612static int
613dt_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
657out:
658	dtp->dt_options[option] = val;
659	return (0);
660}
661
662static int
663dt_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
703static int
704dt_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
715static int
716dt_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 */
779static int
780dt_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
813static 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*/
824static int
825dt_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
848static 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*/
858static int
859dt_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
882int
883dt_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
948typedef 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 */
957static 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 */
1010static 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 */
1035static 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
1052int
1053dtrace_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
1081int
1082dtrace_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