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