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