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