dt_options.c revision 297077
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/*ARGSUSED*/
284static int
285dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
286{
287	dt_dirpath_t *dp;
288
289	if (arg == NULL)
290		return (dt_set_errno(dtp, EDT_BADOPTVAL));
291
292	if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
293	    (dp->dir_path = strdup(arg)) == NULL) {
294		free(dp);
295		return (dt_set_errno(dtp, EDT_NOMEM));
296	}
297
298	dt_list_append(&dtp->dt_lib_path, dp);
299	return (0);
300}
301
302/*ARGSUSED*/
303static int
304dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
305{
306	if (arg == NULL)
307		return (dt_set_errno(dtp, EDT_BADOPTVAL));
308
309	if (strcmp(arg, "kernel") == 0)
310		dtp->dt_linkmode = DT_LINK_KERNEL;
311	else if (strcmp(arg, "primary") == 0)
312		dtp->dt_linkmode = DT_LINK_PRIMARY;
313	else if (strcmp(arg, "dynamic") == 0)
314		dtp->dt_linkmode = DT_LINK_DYNAMIC;
315	else if (strcmp(arg, "static") == 0)
316		dtp->dt_linkmode = DT_LINK_STATIC;
317	else
318		return (dt_set_errno(dtp, EDT_BADOPTVAL));
319
320	return (0);
321}
322
323/*ARGSUSED*/
324static int
325dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
326{
327	if (arg == NULL)
328		return (dt_set_errno(dtp, EDT_BADOPTVAL));
329
330	if (strcasecmp(arg, "elf") == 0)
331		dtp->dt_linktype = DT_LTYP_ELF;
332	else if (strcasecmp(arg, "dof") == 0)
333		dtp->dt_linktype = DT_LTYP_DOF;
334	else
335		return (dt_set_errno(dtp, EDT_BADOPTVAL));
336
337	return (0);
338}
339
340/*ARGSUSED*/
341static int
342dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
343{
344	if (arg == NULL)
345		return (dt_set_errno(dtp, EDT_BADOPTVAL));
346
347	if (strcmp(arg, "ascii") == 0)
348		dtp->dt_encoding = DT_ENCODING_ASCII;
349	else if (strcmp(arg, "utf8") == 0)
350		dtp->dt_encoding = DT_ENCODING_UTF8;
351	else
352		return (dt_set_errno(dtp, EDT_BADOPTVAL));
353
354	return (0);
355}
356
357/*ARGSUSED*/
358static int
359dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
360{
361	if (arg == NULL)
362		return (dt_set_errno(dtp, EDT_BADOPTVAL));
363
364	if (strcmp(arg, "exec") == 0)
365		dtp->dt_prcmode = DT_PROC_STOP_CREATE;
366	else if (strcmp(arg, "preinit") == 0)
367		dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
368	else if (strcmp(arg, "postinit") == 0)
369		dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
370	else if (strcmp(arg, "main") == 0)
371		dtp->dt_prcmode = DT_PROC_STOP_MAIN;
372	else
373		return (dt_set_errno(dtp, EDT_BADOPTVAL));
374
375	return (0);
376}
377
378/*ARGSUSED*/
379static int
380dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
381{
382	int n;
383
384	if (arg == NULL || (n = atoi(arg)) < 0)
385		return (dt_set_errno(dtp, EDT_BADOPTVAL));
386
387	dtp->dt_procs->dph_lrulim = n;
388	return (0);
389}
390
391static int
392dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
393{
394	char **p;
395	char *var;
396	int i;
397
398	/*
399	 * We can't effectively set environment variables from #pragma lines
400	 * since the processes have already been spawned.
401	 */
402	if (dtp->dt_pcb != NULL)
403		return (dt_set_errno(dtp, EDT_BADOPTCTX));
404
405	if (arg == NULL)
406		return (dt_set_errno(dtp, EDT_BADOPTVAL));
407
408	if (!option && strchr(arg, '=') != NULL)
409		return (dt_set_errno(dtp, EDT_BADOPTVAL));
410
411	for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
412		continue;
413
414	for (p = dtp->dt_proc_env; *p != NULL; p++) {
415		var = strchr(*p, '=');
416		if (var == NULL)
417			var = *p + strlen(*p);
418		if (strncmp(*p, arg, var - *p) == 0) {
419			dt_free(dtp, *p);
420			*p = dtp->dt_proc_env[i - 1];
421			dtp->dt_proc_env[i - 1] = NULL;
422			i--;
423		}
424	}
425
426	if (option) {
427		if ((var = strdup(arg)) == NULL)
428			return (dt_set_errno(dtp, EDT_NOMEM));
429
430		if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
431			dt_free(dtp, var);
432			return (dt_set_errno(dtp, EDT_NOMEM));
433		}
434
435		bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
436		dt_free(dtp, dtp->dt_proc_env);
437		dtp->dt_proc_env = p;
438
439		dtp->dt_proc_env[i - 1] = var;
440		dtp->dt_proc_env[i] = NULL;
441	}
442
443	return (0);
444}
445
446/*ARGSUSED*/
447static int
448dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
449{
450	if (arg == NULL)
451		return (dt_set_errno(dtp, EDT_BADOPTVAL));
452
453	if (dtp->dt_pcb != NULL)
454		return (dt_set_errno(dtp, EDT_BADOPTCTX));
455
456	if (strcmp(arg, "a") == 0)
457		dtp->dt_stdcmode = DT_STDC_XA;
458	else if (strcmp(arg, "c") == 0)
459		dtp->dt_stdcmode = DT_STDC_XC;
460	else if (strcmp(arg, "s") == 0)
461		dtp->dt_stdcmode = DT_STDC_XS;
462	else if (strcmp(arg, "t") == 0)
463		dtp->dt_stdcmode = DT_STDC_XT;
464	else
465		return (dt_set_errno(dtp, EDT_BADOPTVAL));
466
467	return (0);
468}
469
470/*ARGSUSED*/
471static int
472dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
473{
474	dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
475	char *path;
476
477	if (arg == NULL)
478		return (dt_set_errno(dtp, EDT_BADOPTVAL));
479
480	if ((path = strdup(arg)) == NULL)
481		return (dt_set_errno(dtp, EDT_NOMEM));
482
483	free(dp->dir_path);
484	dp->dir_path = path;
485
486	return (0);
487}
488
489/*ARGSUSED*/
490static int
491dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
492{
493	int m;
494
495	if (arg == NULL || (m = atoi(arg)) <= 0)
496		return (dt_set_errno(dtp, EDT_BADOPTVAL));
497
498	dtp->dt_treedump = m;
499	return (0);
500}
501
502/*ARGSUSED*/
503static int
504dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
505{
506	int n;
507
508	if (arg == NULL || (n = atoi(arg)) <= 0)
509		return (dt_set_errno(dtp, EDT_BADOPTVAL));
510
511	dtp->dt_conf.dtc_diftupregs = n;
512	return (0);
513}
514
515/*ARGSUSED*/
516static int
517dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
518{
519	if (arg == NULL)
520		return (dt_set_errno(dtp, EDT_BADOPTVAL));
521
522	if (strcmp(arg, "dynamic") == 0)
523		dtp->dt_xlatemode = DT_XL_DYNAMIC;
524	else if (strcmp(arg, "static") == 0)
525		dtp->dt_xlatemode = DT_XL_STATIC;
526	else
527		return (dt_set_errno(dtp, EDT_BADOPTVAL));
528
529	return (0);
530}
531
532/*ARGSUSED*/
533static int
534dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
535{
536	if (arg != NULL)
537		return (dt_set_errno(dtp, EDT_BADOPTVAL));
538
539	if (dtp->dt_pcb != NULL)
540		dtp->dt_pcb->pcb_cflags |= option;
541	else
542		dtp->dt_cflags |= option;
543
544	return (0);
545}
546
547static int
548dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
549{
550	if (arg != NULL)
551		return (dt_set_errno(dtp, EDT_BADOPTVAL));
552
553	dtp->dt_dflags |= option;
554	return (0);
555}
556
557static int
558dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
559{
560	if (arg != NULL)
561		return (dt_set_errno(dtp, EDT_BADOPTVAL));
562
563	if (dtp->dt_pcb != NULL)
564		dtp->dt_pcb->pcb_cflags &= ~option;
565	else
566		dtp->dt_cflags &= ~option;
567
568	return (0);
569}
570
571/*ARGSUSED*/
572static int
573dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
574{
575	dt_version_t v;
576
577	if (arg == NULL)
578		return (dt_set_errno(dtp, EDT_BADOPTVAL));
579
580	if (dt_version_str2num(arg, &v) == -1)
581		return (dt_set_errno(dtp, EDT_VERSINVAL));
582
583	if (!dt_version_defined(v))
584		return (dt_set_errno(dtp, EDT_VERSUNDEF));
585
586	return (dt_reduce(dtp, v));
587}
588
589static int
590dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
591{
592	char *end;
593	dtrace_optval_t val = 0;
594	int i;
595
596	const struct {
597		char *positive;
598		char *negative;
599	} couples[] = {
600		{ "yes",	"no" },
601		{ "enable",	"disable" },
602		{ "enabled",	"disabled" },
603		{ "true",	"false" },
604		{ "on",		"off" },
605		{ "set",	"unset" },
606		{ NULL }
607	};
608
609	if (arg != NULL) {
610		if (arg[0] == '\0') {
611			val = DTRACEOPT_UNSET;
612			goto out;
613		}
614
615		for (i = 0; couples[i].positive != NULL; i++) {
616			if (strcasecmp(couples[i].positive, arg) == 0) {
617				val = 1;
618				goto out;
619			}
620
621			if (strcasecmp(couples[i].negative, arg) == 0) {
622				val = DTRACEOPT_UNSET;
623				goto out;
624			}
625		}
626
627		errno = 0;
628		val = strtoull(arg, &end, 0);
629
630		if (*end != '\0' || errno != 0 || val < 0)
631			return (dt_set_errno(dtp, EDT_BADOPTVAL));
632	}
633
634out:
635	dtp->dt_options[option] = val;
636	return (0);
637}
638
639static int
640dt_optval_parse(const char *arg, dtrace_optval_t *rval)
641{
642	dtrace_optval_t mul = 1;
643	size_t len;
644	char *end;
645
646	len = strlen(arg);
647	errno = 0;
648
649	switch (arg[len - 1]) {
650	case 't':
651	case 'T':
652		mul *= 1024;
653		/*FALLTHRU*/
654	case 'g':
655	case 'G':
656		mul *= 1024;
657		/*FALLTHRU*/
658	case 'm':
659	case 'M':
660		mul *= 1024;
661		/*FALLTHRU*/
662	case 'k':
663	case 'K':
664		mul *= 1024;
665		/*FALLTHRU*/
666	default:
667		break;
668	}
669
670	errno = 0;
671	*rval = strtoull(arg, &end, 0) * mul;
672
673	if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
674	    *rval < 0 || errno != 0)
675		return (-1);
676
677	return (0);
678}
679
680static int
681dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
682{
683	dtrace_optval_t val = 0;
684
685	if (arg != NULL && dt_optval_parse(arg, &val) != 0)
686		return (dt_set_errno(dtp, EDT_BADOPTVAL));
687
688	dtp->dt_options[option] = val;
689	return (0);
690}
691
692static int
693dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
694{
695	char *end;
696	int i;
697	dtrace_optval_t mul = 1, val = 0;
698
699	const struct {
700		char *name;
701		hrtime_t mul;
702	} suffix[] = {
703		{ "ns", 	NANOSEC / NANOSEC },
704		{ "nsec",	NANOSEC / NANOSEC },
705		{ "us",		NANOSEC / MICROSEC },
706		{ "usec",	NANOSEC / MICROSEC },
707		{ "ms",		NANOSEC / MILLISEC },
708		{ "msec",	NANOSEC / MILLISEC },
709		{ "s",		NANOSEC / SEC },
710		{ "sec",	NANOSEC / SEC },
711		{ "m",		NANOSEC * (hrtime_t)60 },
712		{ "min",	NANOSEC * (hrtime_t)60 },
713		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
714		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
715		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
716		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
717		{ "hz",		0 },
718		{ NULL }
719	};
720
721	if (arg != NULL) {
722		errno = 0;
723		val = strtoull(arg, &end, 0);
724
725		for (i = 0; suffix[i].name != NULL; i++) {
726			if (strcasecmp(suffix[i].name, end) == 0) {
727				mul = suffix[i].mul;
728				break;
729			}
730		}
731
732		if (suffix[i].name == NULL && *end != '\0' || val < 0)
733			return (dt_set_errno(dtp, EDT_BADOPTVAL));
734
735		if (mul == 0) {
736			/*
737			 * The rate has been specified in frequency-per-second.
738			 */
739			if (val != 0)
740				val = NANOSEC / val;
741		} else {
742			val *= mul;
743		}
744	}
745
746	dtp->dt_options[option] = val;
747	return (0);
748}
749
750/*
751 * When setting the strsize option, set the option in the dt_options array
752 * using dt_opt_size() as usual, and then update the definition of the CTF
753 * type for the D intrinsic "string" to be an array of the corresponding size.
754 * If any errors occur, reset dt_options[option] to its previous value.
755 */
756static int
757dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
758{
759	dtrace_optval_t val = dtp->dt_options[option];
760	ctf_file_t *fp = DT_STR_CTFP(dtp);
761	ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
762	ctf_arinfo_t r;
763
764	if (dt_opt_size(dtp, arg, option) != 0)
765		return (-1); /* dt_errno is set for us */
766
767	if (dtp->dt_options[option] > UINT_MAX) {
768		dtp->dt_options[option] = val;
769		return (dt_set_errno(dtp, EOVERFLOW));
770	}
771
772	if (ctf_array_info(fp, type, &r) == CTF_ERR) {
773		dtp->dt_options[option] = val;
774		dtp->dt_ctferr = ctf_errno(fp);
775		return (dt_set_errno(dtp, EDT_CTF));
776	}
777
778	r.ctr_nelems = (uint_t)dtp->dt_options[option];
779
780	if (ctf_set_array(fp, type, &r) == CTF_ERR ||
781	    ctf_update(fp) == CTF_ERR) {
782		dtp->dt_options[option] = val;
783		dtp->dt_ctferr = ctf_errno(fp);
784		return (dt_set_errno(dtp, EDT_CTF));
785	}
786
787	return (0);
788}
789
790static const struct {
791	const char *dtbp_name;
792	int dtbp_policy;
793} _dtrace_bufpolicies[] = {
794	{ "ring", DTRACEOPT_BUFPOLICY_RING },
795	{ "fill", DTRACEOPT_BUFPOLICY_FILL },
796	{ "switch", DTRACEOPT_BUFPOLICY_SWITCH },
797	{ NULL, 0 }
798};
799
800/*ARGSUSED*/
801static int
802dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
803{
804	dtrace_optval_t policy = DTRACEOPT_UNSET;
805	int i;
806
807	if (arg == NULL)
808		return (dt_set_errno(dtp, EDT_BADOPTVAL));
809
810	for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
811		if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
812			policy = _dtrace_bufpolicies[i].dtbp_policy;
813			break;
814		}
815	}
816
817	if (policy == DTRACEOPT_UNSET)
818		return (dt_set_errno(dtp, EDT_BADOPTVAL));
819
820	dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
821
822	return (0);
823}
824
825static const struct {
826	const char *dtbr_name;
827	int dtbr_policy;
828} _dtrace_bufresize[] = {
829	{ "auto", DTRACEOPT_BUFRESIZE_AUTO },
830	{ "manual", DTRACEOPT_BUFRESIZE_MANUAL },
831	{ NULL, 0 }
832};
833
834/*ARGSUSED*/
835static int
836dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
837{
838	dtrace_optval_t policy = DTRACEOPT_UNSET;
839	int i;
840
841	if (arg == NULL)
842		return (dt_set_errno(dtp, EDT_BADOPTVAL));
843
844	for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
845		if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
846			policy = _dtrace_bufresize[i].dtbr_policy;
847			break;
848		}
849	}
850
851	if (policy == DTRACEOPT_UNSET)
852		return (dt_set_errno(dtp, EDT_BADOPTVAL));
853
854	dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
855
856	return (0);
857}
858
859int
860dt_options_load(dtrace_hdl_t *dtp)
861{
862	dof_hdr_t hdr, *dof;
863	dof_sec_t *sec;
864	size_t offs;
865	int i;
866
867	/*
868	 * To load the option values, we need to ask the kernel to provide its
869	 * DOF, which we'll sift through to look for OPTDESC sections.
870	 */
871	bzero(&hdr, sizeof (dof_hdr_t));
872	hdr.dofh_loadsz = sizeof (dof_hdr_t);
873
874#ifdef illumos
875	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
876#else
877	dof = &hdr;
878	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
879#endif
880		return (dt_set_errno(dtp, errno));
881
882	if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
883		return (dt_set_errno(dtp, EINVAL));
884
885	dof = alloca(hdr.dofh_loadsz);
886	bzero(dof, sizeof (dof_hdr_t));
887	dof->dofh_loadsz = hdr.dofh_loadsz;
888
889	for (i = 0; i < DTRACEOPT_MAX; i++)
890		dtp->dt_options[i] = DTRACEOPT_UNSET;
891
892#ifdef illumos
893	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
894#else
895	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
896#endif
897		return (dt_set_errno(dtp, errno));
898
899	for (i = 0; i < dof->dofh_secnum; i++) {
900		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
901		    dof->dofh_secoff + i * dof->dofh_secsize);
902
903		if (sec->dofs_type != DOF_SECT_OPTDESC)
904			continue;
905
906		break;
907	}
908
909	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
910		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
911		    ((uintptr_t)dof + sec->dofs_offset + offs);
912
913		if (opt->dofo_strtab != DOF_SECIDX_NONE)
914			continue;
915
916		if (opt->dofo_option >= DTRACEOPT_MAX)
917			continue;
918
919		dtp->dt_options[opt->dofo_option] = opt->dofo_value;
920	}
921
922	return (0);
923}
924
925typedef struct dt_option {
926	const char *o_name;
927	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
928	uintptr_t o_option;
929} dt_option_t;
930
931/*
932 * Compile-time options.
933 */
934static const dt_option_t _dtrace_ctoptions[] = {
935	{ "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
936	{ "amin", dt_opt_amin },
937	{ "argref", dt_opt_cflags, DTRACE_C_ARGREF },
938	{ "core", dt_opt_core },
939	{ "cpp", dt_opt_cflags, DTRACE_C_CPP },
940	{ "cpphdrs", dt_opt_cpp_hdrs },
941	{ "cpppath", dt_opt_cpp_path },
942	{ "ctypes", dt_opt_ctypes },
943	{ "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
944	{ "dtypes", dt_opt_dtypes },
945	{ "debug", dt_opt_debug },
946	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
947	{ "droptags", dt_opt_droptags },
948	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
949	{ "encoding", dt_opt_encoding },
950	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
951	{ "evaltime", dt_opt_evaltime },
952	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
953	{ "iregs", dt_opt_iregs },
954	{ "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
955	{ "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
956	{ "late", dt_opt_xlate },
957	{ "lazyload", dt_opt_lazyload },
958	{ "ldpath", dt_opt_ld_path },
959	{ "libdir", dt_opt_libdir },
960	{ "linkmode", dt_opt_linkmode },
961	{ "linktype", dt_opt_linktype },
962	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
963	{ "pgmax", dt_opt_pgmax },
964	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
965	{ "setenv", dt_opt_setenv, 1 },
966	{ "stdc", dt_opt_stdc },
967	{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
968	{ "syslibdir", dt_opt_syslibdir },
969	{ "tree", dt_opt_tree },
970	{ "tregs", dt_opt_tregs },
971	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
972	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
973	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
974	{ "unsetenv", dt_opt_setenv, 0 },
975	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
976	{ "version", dt_opt_version },
977	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
978	{ NULL, NULL, 0 }
979};
980
981/*
982 * Run-time options.
983 */
984static const dt_option_t _dtrace_rtoptions[] = {
985	{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
986	{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
987	{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
988	{ "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
989	{ "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
990	{ "cpu", dt_opt_runtime, DTRACEOPT_CPU },
991	{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
992	{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
993	{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
994	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
995	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
996	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
997	{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
998	{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
999	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
1000	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
1001	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
1002	{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
1003	{ NULL, NULL, 0 }
1004};
1005
1006/*
1007 * Dynamic run-time options.
1008 */
1009static const dt_option_t _dtrace_drtoptions[] = {
1010	{ "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
1011	{ "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
1012	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
1013	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
1014	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
1015	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
1016	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
1017	{ "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
1018	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
1019	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
1020	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
1021	{ "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
1022	{ "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
1023	{ NULL, NULL, 0 }
1024};
1025
1026int
1027dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
1028{
1029	const dt_option_t *op;
1030
1031	if (opt == NULL)
1032		return (dt_set_errno(dtp, EINVAL));
1033
1034	/*
1035	 * We only need to search the run-time options -- it's not legal
1036	 * to get the values of compile-time options.
1037	 */
1038	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1039		if (strcmp(op->o_name, opt) == 0) {
1040			*val = dtp->dt_options[op->o_option];
1041			return (0);
1042		}
1043	}
1044
1045	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1046		if (strcmp(op->o_name, opt) == 0) {
1047			*val = dtp->dt_options[op->o_option];
1048			return (0);
1049		}
1050	}
1051
1052	return (dt_set_errno(dtp, EDT_BADOPTNAME));
1053}
1054
1055int
1056dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1057{
1058	const dt_option_t *op;
1059
1060	if (opt == NULL)
1061		return (dt_set_errno(dtp, EINVAL));
1062
1063	for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1064		if (strcmp(op->o_name, opt) == 0)
1065			return (op->o_func(dtp, val, op->o_option));
1066	}
1067
1068	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1069		if (strcmp(op->o_name, opt) == 0)
1070			return (op->o_func(dtp, val, op->o_option));
1071	}
1072
1073	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1074		if (strcmp(op->o_name, opt) == 0) {
1075			/*
1076			 * Only dynamic run-time options may be set while
1077			 * tracing is active.
1078			 */
1079			if (dtp->dt_active)
1080				return (dt_set_errno(dtp, EDT_ACTIVE));
1081
1082			return (op->o_func(dtp, val, op->o_option));
1083		}
1084	}
1085
1086	return (dt_set_errno(dtp, EDT_BADOPTNAME));
1087}
1088