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