dt_options.c revision 266667
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
49static int
50dt_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*/
62static int
63dt_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
85static void
86dt_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*/
109static int
110dt_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*/
124static int
125dt_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*/
140static int
141dt_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
161static int
162dt_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*/
187static int
188dt_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*/
204static int
205dt_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*/
212static int
213dt_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*/
229static int
230dt_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*/
240static int
241dt_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*/
253static int
254dt_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*/
262static int
263dt_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*/
283static int
284dt_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*/
302static int
303dt_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*/
323static int
324dt_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*/
340static int
341dt_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*/
361static int
362dt_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
373static int
374dt_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*/
429static int
430dt_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*/
453static int
454dt_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*/
472static int
473dt_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*/
485static int
486dt_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*/
498static int
499dt_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*/
515static int
516dt_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
529static int
530dt_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
539static int
540dt_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*/
554static int
555dt_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
571static int
572dt_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
616out:
617	dtp->dt_options[option] = val;
618	return (0);
619}
620
621static int
622dt_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
662static int
663dt_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
674static int
675dt_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 */
738static int
739dt_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
772static 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*/
783static int
784dt_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
807static 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*/
817static int
818dt_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
841int
842dt_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
907typedef 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 */
916static 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 */
965static 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 */
990static 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
1004int
1005dtrace_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
1033int
1034dtrace_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