158582Skris/*
265674Skris * CDDL HEADER START
365674Skris *
465674Skris * The contents of this file are subject to the terms of the
565674Skris * Common Development and Distribution License (the "License").
665674Skris * You may not use this file except in compliance with the License.
765674Skris *
865674Skris * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
965674Skris * or http://www.opensolaris.org/os/licensing.
1065674Skris * See the License for the specific language governing permissions
1165674Skris * and limitations under the License.
1292559Sdes *
1358582Skris * When distributing Covered Code, include this CDDL HEADER in each
1458582Skris * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1558582Skris * If applicable, add the following below this CDDL HEADER, with the
1658582Skris * fields enclosed by brackets "[]" replaced with your own identifying
1758582Skris * information: Portions Copyright [yyyy] [name of copyright owner]
1858582Skris *
1958582Skris * CDDL HEADER END
2058582Skris */
2158582Skris
2258582Skris/*
2358582Skris * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2458582Skris * Use is subject to license terms.
2558582Skris */
2658582Skris
2758582Skris/*
2858582Skris * Copyright (c) 2013, Joyent, Inc. All rights reserved.
2958582Skris * Copyright (c) 2012 by Delphix. All rights reserved.
3058582Skris */
3158582Skris
3258582Skris#include <sys/resource.h>
3358582Skris#include <sys/mman.h>
3476262Sgreen#include <sys/types.h>
35137019Sdes
3658582Skris#include <strings.h>
3758592Skris#include <signal.h>
3876262Sgreen#include <stdlib.h>
3958582Skris#include <unistd.h>
4058582Skris#include <limits.h>
4176262Sgreen#ifdef illumos
4260576Skris#include <alloca.h>
4376262Sgreen#endif
4476262Sgreen#include <errno.h>
4576262Sgreen#include <fcntl.h>
4658582Skris
4758582Skris#include <dt_impl.h>
4858582Skris#include <dt_string.h>
4958582Skris
5058582Skrisstatic int
5158582Skrisdt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
5258582Skris{
5358582Skris	dt_aggregate_t *agp = &dtp->dt_aggregate;
5458582Skris
5592559Sdes	if (arg != NULL)
5660576Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
5760576Skris
5858582Skris	agp->dtat_flags |= option;
5976262Sgreen	return (0);
6058582Skris}
6192559Sdes
6292559Sdes/*ARGSUSED*/
6392559Sdesstatic int
6492559Sdesdt_opt_amin(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
6592559Sdes{
6692559Sdes	char str[DTRACE_ATTR2STR_MAX];
6758582Skris	dtrace_attribute_t attr;
6858582Skris
6958582Skris	if (arg == NULL || dtrace_str2attr(arg, &attr) == -1)
7092559Sdes		return (dt_set_errno(dtp, EDT_BADOPTVAL));
7192559Sdes
7292559Sdes	dt_dprintf("set compiler attribute minimum to %s\n",
7392559Sdes	    dtrace_attr2str(attr, str, sizeof (str)));
7492559Sdes
7592559Sdes	if (dtp->dt_pcb != NULL) {
7692559Sdes		dtp->dt_pcb->pcb_cflags |= DTRACE_C_EATTR;
7792559Sdes		dtp->dt_pcb->pcb_amin = attr;
7892559Sdes	} else {
7992559Sdes		dtp->dt_cflags |= DTRACE_C_EATTR;
8058582Skris		dtp->dt_amin = attr;
8158582Skris	}
8276262Sgreen
8358582Skris	return (0);
8458582Skris}
8558582Skris
8658582Skrisstatic void
8758582Skrisdt_coredump(void)
8858582Skris{
8958582Skris	const char msg[] = "libdtrace DEBUG: [ forcing coredump ]\n";
9099063Sdes
9176262Sgreen	struct sigaction act;
9276262Sgreen	struct rlimit lim;
9376262Sgreen
9476262Sgreen	(void) write(STDERR_FILENO, msg, sizeof (msg) - 1);
9576262Sgreen
9676262Sgreen	act.sa_handler = SIG_DFL;
9776262Sgreen	act.sa_flags = 0;
9892559Sdes
9992559Sdes	(void) sigemptyset(&act.sa_mask);
10092559Sdes	(void) sigaction(SIGABRT, &act, NULL);
10192559Sdes
10292559Sdes	lim.rlim_cur = RLIM_INFINITY;
10392559Sdes	lim.rlim_max = RLIM_INFINITY;
10492559Sdes
10592559Sdes	(void) setrlimit(RLIMIT_CORE, &lim);
10692559Sdes	abort();
10792559Sdes}
10892559Sdes
10992559Sdes/*ARGSUSED*/
11076262Sgreenstatic int
11176262Sgreendt_opt_core(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
11292559Sdes{
11392559Sdes	static int enabled = 0;
11476262Sgreen
11576262Sgreen	if (arg != NULL)
11676262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
11776262Sgreen
11876262Sgreen	if (enabled++ || atexit(dt_coredump) == 0)
11976262Sgreen		return (0);
12076262Sgreen
12176262Sgreen	return (dt_set_errno(dtp, errno));
12299063Sdes}
12358582Skris
12458582Skris/*ARGSUSED*/
12558582Skrisstatic int
12658582Skrisdt_opt_cpp_hdrs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
12776262Sgreen{
12858582Skris	if (arg != NULL)
12958582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
13058582Skris
13158582Skris	if (dtp->dt_pcb != NULL)
13258582Skris		return (dt_set_errno(dtp, EDT_BADOPTCTX));
13358582Skris
13458582Skris	if (dt_cpp_add_arg(dtp, "-H") == NULL)
13558582Skris		return (dt_set_errno(dtp, EDT_NOMEM));
13658582Skris
13758582Skris	return (0);
13876262Sgreen}
13976262Sgreen
14058582Skris/*ARGSUSED*/
14158582Skrisstatic int
14258582Skrisdt_opt_cpp_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
14358582Skris{
14458582Skris	char *cpp;
14558582Skris
146126277Sdes	if (arg == NULL)
14758582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
148126277Sdes
14958582Skris	if (dtp->dt_pcb != NULL)
15058582Skris		return (dt_set_errno(dtp, EDT_BADOPTCTX));
15158582Skris
15258582Skris	if ((cpp = strdup(arg)) == NULL)
15376262Sgreen		return (dt_set_errno(dtp, EDT_NOMEM));
15458582Skris
15558582Skris	dtp->dt_cpp_argv[0] = (char *)strbasename(cpp);
15658582Skris	free(dtp->dt_cpp_path);
15758582Skris	dtp->dt_cpp_path = cpp;
15858582Skris
15958582Skris	return (0);
16058582Skris}
16158582Skris
16258582Skrisstatic int
16358582Skrisdt_opt_cpp_opts(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
16458582Skris{
16558582Skris	char *buf;
16658582Skris	size_t len;
16760576Skris	const char *opt = (const char *)option;
16858582Skris
16958582Skris	if (opt == NULL || arg == NULL)
17058582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
17158582Skris
17258582Skris	if (dtp->dt_pcb != NULL)
173124211Sdes		return (dt_set_errno(dtp, EDT_BADOPTCTX));
174126277Sdes
175126277Sdes	len = strlen(opt) + strlen(arg) + 1;
17658582Skris	buf = alloca(len);
17792559Sdes
17876262Sgreen	(void) strcpy(buf, opt);
17976262Sgreen	(void) strcat(buf, arg);
18076262Sgreen
18192559Sdes	if (dt_cpp_add_arg(dtp, buf) == NULL)
18260576Skris		return (dt_set_errno(dtp, EDT_NOMEM));
18358582Skris
18476262Sgreen	return (0);
18576262Sgreen}
18676262Sgreen
18776262Sgreen/*ARGSUSED*/
18876262Sgreenstatic int
18976262Sgreendt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
19076262Sgreen{
19176262Sgreen	int fd;
19276262Sgreen
19376262Sgreen	if (arg == NULL)
19476262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
19576262Sgreen
19676262Sgreen	if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
19758582Skris		return (dt_set_errno(dtp, errno));
19876262Sgreen
19958582Skris	(void) close(dtp->dt_cdefs_fd);
20058582Skris	dtp->dt_cdefs_fd = fd;
20158582Skris	return (0);
20260576Skris}
20360576Skris
20460576Skris/*ARGSUSED*/
20558582Skrisstatic int
20658582Skrisdt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
20776262Sgreen{
20876262Sgreen	dtp->dt_droptags = 1;
20958582Skris	return (0);
21076262Sgreen}
21176262Sgreen
21276262Sgreen/*ARGSUSED*/
21358582Skrisstatic int
21476262Sgreendt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
21558582Skris{
21658582Skris	int fd;
21760576Skris
21876262Sgreen	if (arg == NULL)
21965674Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
22065674Skris
22192559Sdes	if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1)
22260576Skris		return (dt_set_errno(dtp, errno));
22360576Skris
22476262Sgreen	(void) close(dtp->dt_ddefs_fd);
22576262Sgreen	dtp->dt_ddefs_fd = fd;
22658582Skris	return (0);
22758582Skris}
22858582Skris
22958582Skris/*ARGSUSED*/
230106130Sdesstatic int
231106130Sdesdt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
23276262Sgreen{
23376262Sgreen	if (arg != NULL)
23476262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
23576262Sgreen
23676262Sgreen	_dtrace_debug = 1;
23776262Sgreen	return (0);
23892559Sdes}
23976262Sgreen
24076262Sgreen/*ARGSUSED*/
241124211Sdesstatic int
24276262Sgreendt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
243124211Sdes{
244124211Sdes	int n;
24576262Sgreen
24676262Sgreen	if (arg == NULL || (n = atoi(arg)) <= 0)
24776262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
24876262Sgreen
249106130Sdes	dtp->dt_conf.dtc_difintregs = n;
250106130Sdes	return (0);
25176262Sgreen}
25276262Sgreen
25376262Sgreen/*ARGSUSED*/
25476262Sgreenstatic int
25576262Sgreendt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
25676262Sgreen{
25776262Sgreen	dtp->dt_lazyload = 1;
25876262Sgreen
25976262Sgreen	return (0);
26076262Sgreen}
26176262Sgreen
26276262Sgreen/*ARGSUSED*/
26376262Sgreenstatic int
26476262Sgreendt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
26576262Sgreen{
26676262Sgreen	char *ld;
26776262Sgreen
26876262Sgreen	if (arg == NULL)
26976262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
27076262Sgreen
27176262Sgreen	if (dtp->dt_pcb != NULL)
27276262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTCTX));
27376262Sgreen
27476262Sgreen	if ((ld = strdup(arg)) == NULL)
27576262Sgreen		return (dt_set_errno(dtp, EDT_NOMEM));
27676262Sgreen
27776262Sgreen	free(dtp->dt_ld_path);
27876262Sgreen	dtp->dt_ld_path = ld;
27976262Sgreen
28076262Sgreen	return (0);
28176262Sgreen}
28276262Sgreen
28376262Sgreen/*ARGSUSED*/
28476262Sgreenstatic int
28576262Sgreendt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
28676262Sgreen{
28776262Sgreen	dt_dirpath_t *dp;
28876262Sgreen
28976262Sgreen	if (arg == NULL)
29076262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
29176262Sgreen
29276262Sgreen	if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
29376262Sgreen	    (dp->dir_path = strdup(arg)) == NULL) {
29476262Sgreen		free(dp);
29576262Sgreen		return (dt_set_errno(dtp, EDT_NOMEM));
296106130Sdes	}
297126277Sdes
29876262Sgreen	dt_list_append(&dtp->dt_lib_path, dp);
29976262Sgreen	return (0);
30076262Sgreen}
30192559Sdes
30292559Sdes/*ARGSUSED*/
30376262Sgreenstatic int
30476262Sgreendt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
30576262Sgreen{
30692559Sdes	if (arg == NULL)
30776262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
30876262Sgreen
30976262Sgreen	if (strcmp(arg, "kernel") == 0)
31076262Sgreen		dtp->dt_linkmode = DT_LINK_KERNEL;
31176262Sgreen	else if (strcmp(arg, "primary") == 0)
31276262Sgreen		dtp->dt_linkmode = DT_LINK_PRIMARY;
31376262Sgreen	else if (strcmp(arg, "dynamic") == 0)
31476262Sgreen		dtp->dt_linkmode = DT_LINK_DYNAMIC;
31576262Sgreen	else if (strcmp(arg, "static") == 0)
31676262Sgreen		dtp->dt_linkmode = DT_LINK_STATIC;
31776262Sgreen	else
31876262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
31976262Sgreen
32076262Sgreen	return (0);
32176262Sgreen}
32276262Sgreen
32358582Skris/*ARGSUSED*/
32458582Skrisstatic int
32558582Skrisdt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
32658582Skris{
32758582Skris	if (arg == NULL)
32858582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
32958582Skris
33092559Sdes	if (strcasecmp(arg, "elf") == 0)
33158582Skris		dtp->dt_linktype = DT_LTYP_ELF;
33258582Skris	else if (strcasecmp(arg, "dof") == 0)
33358582Skris		dtp->dt_linktype = DT_LTYP_DOF;
33458582Skris	else
33558582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
33658582Skris
33758582Skris	return (0);
33858582Skris}
33958582Skris
34058582Skris/*ARGSUSED*/
34158582Skrisstatic int
34258582Skrisdt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
34358582Skris{
34458582Skris	if (arg == NULL)
34558582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
34658582Skris
34758582Skris	if (strcmp(arg, "ascii") == 0)
34858582Skris		dtp->dt_encoding = DT_ENCODING_ASCII;
34958582Skris	else if (strcmp(arg, "utf8") == 0)
35058582Skris		dtp->dt_encoding = DT_ENCODING_UTF8;
35158582Skris	else
35258582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
35358582Skris
35458582Skris	return (0);
35558582Skris}
35658582Skris
35758582Skris/*ARGSUSED*/
35858582Skrisstatic int
35958582Skrisdt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
36058582Skris{
36158582Skris	if (arg == NULL)
36258582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
36358582Skris
36458582Skris	if (strcmp(arg, "exec") == 0)
36558582Skris		dtp->dt_prcmode = DT_PROC_STOP_CREATE;
36699063Sdes	else if (strcmp(arg, "preinit") == 0)
36792559Sdes		dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
36858582Skris	else if (strcmp(arg, "postinit") == 0)
36958582Skris		dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
37058582Skris	else if (strcmp(arg, "main") == 0)
37158582Skris		dtp->dt_prcmode = DT_PROC_STOP_MAIN;
37258582Skris	else
37358582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
37458582Skris
37558582Skris	return (0);
37692559Sdes}
37758582Skris
37858582Skris/*ARGSUSED*/
37976262Sgreenstatic int
38092559Sdesdt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
38176262Sgreen{
38260576Skris	int n;
38358582Skris
38460576Skris	if (arg == NULL || (n = atoi(arg)) < 0)
38576262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
38676262Sgreen
38776262Sgreen	dtp->dt_procs->dph_lrulim = n;
38876262Sgreen	return (0);
38976262Sgreen}
39060576Skris
39160576Skrisstatic int
39260576Skrisdt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
39392559Sdes{
39476262Sgreen	char **p;
39560576Skris	char *var;
39660576Skris	int i;
39776262Sgreen
39860576Skris	/*
39960576Skris	 * We can't effectively set environment variables from #pragma lines
40058582Skris	 * since the processes have already been spawned.
40176262Sgreen	 */
40260576Skris	if (dtp->dt_pcb != NULL)
40358582Skris		return (dt_set_errno(dtp, EDT_BADOPTCTX));
40458582Skris
40576262Sgreen	if (arg == NULL)
40658582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
40776262Sgreen
40876262Sgreen	if (!option && strchr(arg, '=') != NULL)
40958582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
41076262Sgreen
41176262Sgreen	for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
41258582Skris		continue;
41376262Sgreen
41476262Sgreen	for (p = dtp->dt_proc_env; *p != NULL; p++) {
415113911Sdes		var = strchr(*p, '=');
41676262Sgreen		if (var == NULL)
41776262Sgreen			var = *p + strlen(*p);
41876262Sgreen		if (strncmp(*p, arg, var - *p) == 0) {
41976262Sgreen			dt_free(dtp, *p);
42076262Sgreen			*p = dtp->dt_proc_env[i - 1];
42176262Sgreen			dtp->dt_proc_env[i - 1] = NULL;
422113911Sdes			i--;
42376262Sgreen		}
42476262Sgreen	}
42576262Sgreen
42676262Sgreen	if (option) {
42776262Sgreen		if ((var = strdup(arg)) == NULL)
42876262Sgreen			return (dt_set_errno(dtp, EDT_NOMEM));
42976262Sgreen
43076262Sgreen		if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
43176262Sgreen			dt_free(dtp, var);
43276262Sgreen			return (dt_set_errno(dtp, EDT_NOMEM));
43376262Sgreen		}
43476262Sgreen
43592559Sdes		bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
43676262Sgreen		dt_free(dtp, dtp->dt_proc_env);
43760576Skris		dtp->dt_proc_env = p;
43860576Skris
43960576Skris		dtp->dt_proc_env[i - 1] = var;
44060576Skris		dtp->dt_proc_env[i] = NULL;
44161203Skris	}
44292559Sdes
44376262Sgreen	return (0);
44460576Skris}
445124211Sdes
44692559Sdes/*ARGSUSED*/
44761203Skrisstatic int
44876262Sgreendt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
44976262Sgreen{
45061203Skris	if (arg == NULL)
45176262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
45276262Sgreen
45376262Sgreen	if (dtp->dt_pcb != NULL)
45476262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTCTX));
45576262Sgreen
45676262Sgreen	if (strcmp(arg, "a") == 0)
45776262Sgreen		dtp->dt_stdcmode = DT_STDC_XA;
45876262Sgreen	else if (strcmp(arg, "c") == 0)
45976262Sgreen		dtp->dt_stdcmode = DT_STDC_XC;
46076262Sgreen	else if (strcmp(arg, "s") == 0)
46176262Sgreen		dtp->dt_stdcmode = DT_STDC_XS;
46276262Sgreen	else if (strcmp(arg, "t") == 0)
46376262Sgreen		dtp->dt_stdcmode = DT_STDC_XT;
46476262Sgreen	else
46576262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
46676262Sgreen
46776262Sgreen	return (0);
46876262Sgreen}
46976262Sgreen
47076262Sgreen/*ARGSUSED*/
47176262Sgreenstatic int
47276262Sgreendt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
47376262Sgreen{
47476262Sgreen	dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
47576262Sgreen	char *path;
47676262Sgreen
47792559Sdes	if (arg == NULL)
47876262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
47976262Sgreen
48061203Skris	if ((path = strdup(arg)) == NULL)
48161203Skris		return (dt_set_errno(dtp, EDT_NOMEM));
48261203Skris
48361203Skris	free(dp->dir_path);
48461203Skris	dp->dir_path = path;
48561203Skris
48658582Skris	return (0);
48758582Skris}
48860576Skris
48958582Skris/*ARGSUSED*/
49058582Skrisstatic int
49176262Sgreendt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
49258582Skris{
49399063Sdes	int m;
49458582Skris
495126277Sdes	if (arg == NULL || (m = atoi(arg)) <= 0)
49658582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
49792559Sdes
49892559Sdes	dtp->dt_treedump = m;
499106130Sdes	return (0);
500106130Sdes}
50158582Skris
50276262Sgreen/*ARGSUSED*/
50358582Skrisstatic int
50458582Skrisdt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
50558582Skris{
50658582Skris	int n;
50758582Skris
50858582Skris	if (arg == NULL || (n = atoi(arg)) <= 0)
50958582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
51058582Skris
51158582Skris	dtp->dt_conf.dtc_diftupregs = n;
51276262Sgreen	return (0);
51376262Sgreen}
51476262Sgreen
51560576Skris/*ARGSUSED*/
51660576Skrisstatic int
51760576Skrisdt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
51876262Sgreen{
51958582Skris	if (arg == NULL)
52058582Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
52160576Skris
52260576Skris	if (strcmp(arg, "dynamic") == 0)
52358582Skris		dtp->dt_xlatemode = DT_XL_DYNAMIC;
52458582Skris	else if (strcmp(arg, "static") == 0)
52558582Skris		dtp->dt_xlatemode = DT_XL_STATIC;
52699063Sdes	else
527126277Sdes		return (dt_set_errno(dtp, EDT_BADOPTVAL));
528126277Sdes
52960576Skris	return (0);
53060576Skris}
53176262Sgreen
53276262Sgreen/*ARGSUSED*/
53376262Sgreenstatic int
53460576Skrisdt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
53560576Skris{
53660576Skris	if (arg != NULL)
53760576Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
53860576Skris
53960576Skris	if (dtp->dt_pcb != NULL)
54060576Skris		dtp->dt_pcb->pcb_cflags |= option;
54160576Skris	else
54260576Skris		dtp->dt_cflags |= option;
54399063Sdes
544126277Sdes	return (0);
545126277Sdes}
54676262Sgreen
54776262Sgreenstatic int
54876262Sgreendt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
54976262Sgreen{
55076262Sgreen	if (arg != NULL)
55176262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
55276262Sgreen
55376262Sgreen	dtp->dt_dflags |= option;
55476262Sgreen	return (0);
55576262Sgreen}
55676262Sgreen
55799063Sdesstatic int
55876262Sgreendt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
559126277Sdes{
56092559Sdes	if (arg != NULL)
56165674Skris		return (dt_set_errno(dtp, EDT_BADOPTVAL));
56276262Sgreen
56365674Skris	if (dtp->dt_pcb != NULL)
56465674Skris		dtp->dt_pcb->pcb_cflags &= ~option;
56565674Skris	else
56665674Skris		dtp->dt_cflags &= ~option;
56765674Skris
56865674Skris	return (0);
56965674Skris}
57065674Skris
57165674Skris/*ARGSUSED*/
57276262Sgreenstatic int
57392559Sdesdt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
57476262Sgreen{
57576262Sgreen	dt_version_t v;
57676262Sgreen
57776262Sgreen	if (arg == NULL)
57876262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
57976262Sgreen
58076262Sgreen	if (dt_version_str2num(arg, &v) == -1)
58176262Sgreen		return (dt_set_errno(dtp, EDT_VERSINVAL));
58276262Sgreen
58392559Sdes	if (!dt_version_defined(v))
58476262Sgreen		return (dt_set_errno(dtp, EDT_VERSUNDEF));
58576262Sgreen
58676262Sgreen	return (dt_reduce(dtp, v));
58776262Sgreen}
58876262Sgreen
58976262Sgreenstatic int
59076262Sgreendt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
59176262Sgreen{
59276262Sgreen	char *end;
59376262Sgreen	dtrace_optval_t val = 0;
59476262Sgreen	int i;
59576262Sgreen
59676262Sgreen	const struct {
59776262Sgreen		char *positive;
59876262Sgreen		char *negative;
59976262Sgreen	} couples[] = {
60076262Sgreen		{ "yes",	"no" },
60176262Sgreen		{ "enable",	"disable" },
60276262Sgreen		{ "enabled",	"disabled" },
60376262Sgreen		{ "true",	"false" },
60476262Sgreen		{ "on",		"off" },
60576262Sgreen		{ "set",	"unset" },
60676262Sgreen		{ NULL }
60776262Sgreen	};
60876262Sgreen
60976262Sgreen	if (arg != NULL) {
61076262Sgreen		if (arg[0] == '\0') {
61176262Sgreen			val = DTRACEOPT_UNSET;
61276262Sgreen			goto out;
61376262Sgreen		}
61476262Sgreen
61576262Sgreen		for (i = 0; couples[i].positive != NULL; i++) {
616126277Sdes			if (strcasecmp(couples[i].positive, arg) == 0) {
61776262Sgreen				val = 1;
61876262Sgreen				goto out;
61976262Sgreen			}
62076262Sgreen
62176262Sgreen			if (strcasecmp(couples[i].negative, arg) == 0) {
62276262Sgreen				val = DTRACEOPT_UNSET;
62376262Sgreen				goto out;
62476262Sgreen			}
62576262Sgreen		}
62676262Sgreen
62776262Sgreen		errno = 0;
62876262Sgreen		val = strtoull(arg, &end, 0);
62976262Sgreen
63076262Sgreen		if (*end != '\0' || errno != 0 || val < 0)
63176262Sgreen			return (dt_set_errno(dtp, EDT_BADOPTVAL));
63276262Sgreen	}
63376262Sgreen
63476262Sgreenout:
63576262Sgreen	dtp->dt_options[option] = val;
63676262Sgreen	return (0);
63776262Sgreen}
63876262Sgreen
63976262Sgreenstatic int
64076262Sgreendt_optval_parse(const char *arg, dtrace_optval_t *rval)
64176262Sgreen{
64276262Sgreen	dtrace_optval_t mul = 1;
64392559Sdes	size_t len;
64476262Sgreen	char *end;
64592559Sdes
64676262Sgreen	len = strlen(arg);
64792559Sdes	errno = 0;
64876262Sgreen
64992559Sdes	switch (arg[len - 1]) {
65076262Sgreen	case 't':
65192559Sdes	case 'T':
65276262Sgreen		mul *= 1024;
65376262Sgreen		/*FALLTHRU*/
65476262Sgreen	case 'g':
65576262Sgreen	case 'G':
65676262Sgreen		mul *= 1024;
65776262Sgreen		/*FALLTHRU*/
65876262Sgreen	case 'm':
65976262Sgreen	case 'M':
66076262Sgreen		mul *= 1024;
66176262Sgreen		/*FALLTHRU*/
66276262Sgreen	case 'k':
66376262Sgreen	case 'K':
66476262Sgreen		mul *= 1024;
66576262Sgreen		/*FALLTHRU*/
66676262Sgreen	default:
66792559Sdes		break;
66876262Sgreen	}
66976262Sgreen
67076262Sgreen	errno = 0;
67176262Sgreen	*rval = strtoull(arg, &end, 0) * mul;
67276262Sgreen
67376262Sgreen	if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
67476262Sgreen	    *rval < 0 || errno != 0)
67576262Sgreen		return (-1);
67676262Sgreen
67776262Sgreen	return (0);
67876262Sgreen}
67976262Sgreen
68076262Sgreenstatic int
681126277Sdesdt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
68276262Sgreen{
68376262Sgreen	dtrace_optval_t val = 0;
68476262Sgreen
68576262Sgreen	if (arg != NULL && dt_optval_parse(arg, &val) != 0)
68676262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
68776262Sgreen
68876262Sgreen	dtp->dt_options[option] = val;
68976262Sgreen	return (0);
69076262Sgreen}
69176262Sgreen
69276262Sgreenstatic int
69376262Sgreendt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
69476262Sgreen{
69576262Sgreen	char *end;
69692559Sdes	int i;
69776262Sgreen	dtrace_optval_t mul = 1, val = 0;
69876262Sgreen
69976262Sgreen	const struct {
70076262Sgreen		char *name;
70176262Sgreen		hrtime_t mul;
70276262Sgreen	} suffix[] = {
70376262Sgreen		{ "ns", 	NANOSEC / NANOSEC },
70476262Sgreen		{ "nsec",	NANOSEC / NANOSEC },
70576262Sgreen		{ "us",		NANOSEC / MICROSEC },
70676262Sgreen		{ "usec",	NANOSEC / MICROSEC },
70776262Sgreen		{ "ms",		NANOSEC / MILLISEC },
70876262Sgreen		{ "msec",	NANOSEC / MILLISEC },
70976262Sgreen		{ "s",		NANOSEC / SEC },
71076262Sgreen		{ "sec",	NANOSEC / SEC },
71176262Sgreen		{ "m",		NANOSEC * (hrtime_t)60 },
71276262Sgreen		{ "min",	NANOSEC * (hrtime_t)60 },
71376262Sgreen		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
71476262Sgreen		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
71576262Sgreen		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
71676262Sgreen		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
71776262Sgreen		{ "hz",		0 },
71876262Sgreen		{ NULL }
71976262Sgreen	};
72076262Sgreen
72176262Sgreen	if (arg != NULL) {
72276262Sgreen		errno = 0;
72376262Sgreen		val = strtoull(arg, &end, 0);
72476262Sgreen
72576262Sgreen		for (i = 0; suffix[i].name != NULL; i++) {
72676262Sgreen			if (strcasecmp(suffix[i].name, end) == 0) {
72776262Sgreen				mul = suffix[i].mul;
72876262Sgreen				break;
72976262Sgreen			}
73076262Sgreen		}
731126277Sdes
73276262Sgreen		if (suffix[i].name == NULL && *end != '\0' || val < 0)
73376262Sgreen			return (dt_set_errno(dtp, EDT_BADOPTVAL));
73476262Sgreen
73576262Sgreen		if (mul == 0) {
73676262Sgreen			/*
73776262Sgreen			 * The rate has been specified in frequency-per-second.
73876262Sgreen			 */
73976262Sgreen			if (val != 0)
74076262Sgreen				val = NANOSEC / val;
74192559Sdes		} else {
74276262Sgreen			val *= mul;
74376262Sgreen		}
74476262Sgreen	}
74576262Sgreen
74676262Sgreen	dtp->dt_options[option] = val;
74776262Sgreen	return (0);
74876262Sgreen}
74976262Sgreen
75076262Sgreen/*
75176262Sgreen * When setting the strsize option, set the option in the dt_options array
75276262Sgreen * using dt_opt_size() as usual, and then update the definition of the CTF
75376262Sgreen * type for the D intrinsic "string" to be an array of the corresponding size.
75476262Sgreen * If any errors occur, reset dt_options[option] to its previous value.
75592559Sdes */
75692559Sdesstatic int
75792559Sdesdt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
75876262Sgreen{
75976262Sgreen	dtrace_optval_t val = dtp->dt_options[option];
760106130Sdes	ctf_file_t *fp = DT_STR_CTFP(dtp);
761106130Sdes	ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
762106130Sdes	ctf_arinfo_t r;
763106130Sdes
764106130Sdes	if (dt_opt_size(dtp, arg, option) != 0)
765106130Sdes		return (-1); /* dt_errno is set for us */
76676262Sgreen
76776262Sgreen	if (dtp->dt_options[option] > UINT_MAX) {
76876262Sgreen		dtp->dt_options[option] = val;
76976262Sgreen		return (dt_set_errno(dtp, EOVERFLOW));
77076262Sgreen	}
77176262Sgreen
77276262Sgreen	if (ctf_array_info(fp, type, &r) == CTF_ERR) {
773126277Sdes		dtp->dt_options[option] = val;
77492559Sdes		dtp->dt_ctferr = ctf_errno(fp);
775126277Sdes		return (dt_set_errno(dtp, EDT_CTF));
77676262Sgreen	}
77792559Sdes
77876262Sgreen	r.ctr_nelems = (uint_t)dtp->dt_options[option];
77976262Sgreen
78076262Sgreen	if (ctf_set_array(fp, type, &r) == CTF_ERR ||
78176262Sgreen	    ctf_update(fp) == CTF_ERR) {
78276262Sgreen		dtp->dt_options[option] = val;
78376262Sgreen		dtp->dt_ctferr = ctf_errno(fp);
78476262Sgreen		return (dt_set_errno(dtp, EDT_CTF));
785137019Sdes	}
78676262Sgreen
78776262Sgreen	return (0);
78876262Sgreen}
78976262Sgreen
79076262Sgreenstatic const struct {
79198684Sdes	const char *dtbp_name;
79298684Sdes	int dtbp_policy;
79398684Sdes} _dtrace_bufpolicies[] = {
79498684Sdes	{ "ring", DTRACEOPT_BUFPOLICY_RING },
79576262Sgreen	{ "fill", DTRACEOPT_BUFPOLICY_FILL },
79676262Sgreen	{ "switch", DTRACEOPT_BUFPOLICY_SWITCH },
797126277Sdes	{ NULL, 0 }
798126277Sdes};
799126277Sdes
80076262Sgreen/*ARGSUSED*/
80192559Sdesstatic int
80292559Sdesdt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
80392559Sdes{
80492559Sdes	dtrace_optval_t policy = DTRACEOPT_UNSET;
80576262Sgreen	int i;
80676262Sgreen
80776262Sgreen	if (arg == NULL)
80876262Sgreen		return (dt_set_errno(dtp, EDT_BADOPTVAL));
80976262Sgreen
81076262Sgreen	for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
81176262Sgreen		if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
812137019Sdes			policy = _dtrace_bufpolicies[i].dtbp_policy;
81376262Sgreen			break;
81476262Sgreen		}
81576262Sgreen	}
81676262Sgreen
81798684Sdes	if (policy == DTRACEOPT_UNSET)
81898684Sdes		return (dt_set_errno(dtp, EDT_BADOPTVAL));
81998684Sdes
820126277Sdes	dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
82198684Sdes
82298684Sdes	return (0);
82398684Sdes}
82498684Sdes
82598684Sdesstatic const struct {
82698684Sdes	const char *dtbr_name;
82798684Sdes	int dtbr_policy;
82898684Sdes} _dtrace_bufresize[] = {
82998684Sdes	{ "auto", DTRACEOPT_BUFRESIZE_AUTO },
83098684Sdes	{ "manual", DTRACEOPT_BUFRESIZE_MANUAL },
83198684Sdes	{ NULL, 0 }
83298684Sdes};
83398684Sdes
83498684Sdes/*ARGSUSED*/
83598684Sdesstatic int
83698684Sdesdt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
83798684Sdes{
83898684Sdes	dtrace_optval_t policy = DTRACEOPT_UNSET;
83998684Sdes	int i;
84098684Sdes
84198684Sdes	if (arg == NULL)
84298684Sdes		return (dt_set_errno(dtp, EDT_BADOPTVAL));
84398684Sdes
84498684Sdes	for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
84598684Sdes		if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
84698684Sdes			policy = _dtrace_bufresize[i].dtbr_policy;
84798684Sdes			break;
84898684Sdes		}
84998684Sdes	}
85098684Sdes
85198684Sdes	if (policy == DTRACEOPT_UNSET)
85298684Sdes		return (dt_set_errno(dtp, EDT_BADOPTVAL));
85398684Sdes
85498684Sdes	dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
85598684Sdes
85698684Sdes	return (0);
85798684Sdes}
85898684Sdes
859int
860dt_options_load(dtrace_hdl_t *dtp)
861{
862	dof_hdr_t hdr, *dof;
863	dof_sec_t *sec;
864	size_t offs;
865	int i;
866
867	/*
868	 * To load the option values, we need to ask the kernel to provide its
869	 * DOF, which we'll sift through to look for OPTDESC sections.
870	 */
871	bzero(&hdr, sizeof (dof_hdr_t));
872	hdr.dofh_loadsz = sizeof (dof_hdr_t);
873
874#ifdef illumos
875	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
876#else
877	dof = &hdr;
878	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
879#endif
880		return (dt_set_errno(dtp, errno));
881
882	if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
883		return (dt_set_errno(dtp, EINVAL));
884
885	dof = alloca(hdr.dofh_loadsz);
886	bzero(dof, sizeof (dof_hdr_t));
887	dof->dofh_loadsz = hdr.dofh_loadsz;
888
889	for (i = 0; i < DTRACEOPT_MAX; i++)
890		dtp->dt_options[i] = DTRACEOPT_UNSET;
891
892#ifdef illumos
893	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1)
894#else
895	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1)
896#endif
897		return (dt_set_errno(dtp, errno));
898
899	for (i = 0; i < dof->dofh_secnum; i++) {
900		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
901		    dof->dofh_secoff + i * dof->dofh_secsize);
902
903		if (sec->dofs_type != DOF_SECT_OPTDESC)
904			continue;
905
906		break;
907	}
908
909	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
910		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
911		    ((uintptr_t)dof + sec->dofs_offset + offs);
912
913		if (opt->dofo_strtab != DOF_SECIDX_NONE)
914			continue;
915
916		if (opt->dofo_option >= DTRACEOPT_MAX)
917			continue;
918
919		dtp->dt_options[opt->dofo_option] = opt->dofo_value;
920	}
921
922	return (0);
923}
924
925typedef struct dt_option {
926	const char *o_name;
927	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
928	uintptr_t o_option;
929} dt_option_t;
930
931/*
932 * Compile-time options.
933 */
934static const dt_option_t _dtrace_ctoptions[] = {
935	{ "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
936	{ "amin", dt_opt_amin },
937	{ "argref", dt_opt_cflags, DTRACE_C_ARGREF },
938	{ "core", dt_opt_core },
939	{ "cpp", dt_opt_cflags, DTRACE_C_CPP },
940	{ "cpphdrs", dt_opt_cpp_hdrs },
941	{ "cpppath", dt_opt_cpp_path },
942	{ "ctypes", dt_opt_ctypes },
943	{ "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
944	{ "dtypes", dt_opt_dtypes },
945	{ "debug", dt_opt_debug },
946	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
947	{ "droptags", dt_opt_droptags },
948	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY },
949	{ "encoding", dt_opt_encoding },
950	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
951	{ "evaltime", dt_opt_evaltime },
952	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
953	{ "iregs", dt_opt_iregs },
954	{ "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
955	{ "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
956	{ "late", dt_opt_xlate },
957	{ "lazyload", dt_opt_lazyload },
958	{ "ldpath", dt_opt_ld_path },
959	{ "libdir", dt_opt_libdir },
960	{ "linkmode", dt_opt_linkmode },
961	{ "linktype", dt_opt_linktype },
962	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
963	{ "pgmax", dt_opt_pgmax },
964	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
965	{ "setenv", dt_opt_setenv, 1 },
966	{ "stdc", dt_opt_stdc },
967	{ "strip", dt_opt_dflags, DTRACE_D_STRIP },
968	{ "syslibdir", dt_opt_syslibdir },
969	{ "tree", dt_opt_tree },
970	{ "tregs", dt_opt_tregs },
971	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
972	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
973	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
974	{ "unsetenv", dt_opt_setenv, 0 },
975	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV },
976	{ "version", dt_opt_version },
977	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
978	{ NULL, NULL, 0 }
979};
980
981/*
982 * Run-time options.
983 */
984static const dt_option_t _dtrace_rtoptions[] = {
985	{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
986	{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
987	{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
988	{ "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
989	{ "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
990	{ "cpu", dt_opt_runtime, DTRACEOPT_CPU },
991	{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
992	{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
993	{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
994	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
995	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
996	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
997	{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
998	{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
999	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
1000	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
1001	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
1002	{ "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
1003	{ NULL, NULL, 0 }
1004};
1005
1006/*
1007 * Dynamic run-time options.
1008 */
1009static const dt_option_t _dtrace_drtoptions[] = {
1010	{ "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
1011	{ "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
1012	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
1013	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
1014	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
1015	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
1016	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
1017	{ "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
1018	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
1019	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
1020	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
1021	{ "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
1022	{ "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
1023	{ NULL, NULL, 0 }
1024};
1025
1026int
1027dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
1028{
1029	const dt_option_t *op;
1030
1031	if (opt == NULL)
1032		return (dt_set_errno(dtp, EINVAL));
1033
1034	/*
1035	 * We only need to search the run-time options -- it's not legal
1036	 * to get the values of compile-time options.
1037	 */
1038	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1039		if (strcmp(op->o_name, opt) == 0) {
1040			*val = dtp->dt_options[op->o_option];
1041			return (0);
1042		}
1043	}
1044
1045	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1046		if (strcmp(op->o_name, opt) == 0) {
1047			*val = dtp->dt_options[op->o_option];
1048			return (0);
1049		}
1050	}
1051
1052	return (dt_set_errno(dtp, EDT_BADOPTNAME));
1053}
1054
1055int
1056dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1057{
1058	const dt_option_t *op;
1059
1060	if (opt == NULL)
1061		return (dt_set_errno(dtp, EINVAL));
1062
1063	for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1064		if (strcmp(op->o_name, opt) == 0)
1065			return (op->o_func(dtp, val, op->o_option));
1066	}
1067
1068	for (op = _dtrace_drtoptions; 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_rtoptions; op->o_name != NULL; op++) {
1074		if (strcmp(op->o_name, opt) == 0) {
1075			/*
1076			 * Only dynamic run-time options may be set while
1077			 * tracing is active.
1078			 */
1079			if (dtp->dt_active)
1080				return (dt_set_errno(dtp, EDT_ACTIVE));
1081
1082			return (op->o_func(dtp, val, op->o_option));
1083		}
1084	}
1085
1086	return (dt_set_errno(dtp, EDT_BADOPTNAME));
1087}
1088