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