diff options
| author | John Birrell <jb@FreeBSD.org> | 2008-04-25 09:04:09 +0000 | 
|---|---|---|
| committer | John Birrell <jb@FreeBSD.org> | 2008-04-25 09:04:09 +0000 | 
| commit | c53d354ffe3b3f603cf36c67c489eeeb881403b2 (patch) | |
| tree | c9428b1eda7cd726730c2a51001d1afaee07c0e6 /lib/libdtrace/common/dt_options.c | |
| parent | 12456ea875a4e2a468753b9890e6864519aeb931 (diff) | |
Notes
Diffstat (limited to 'lib/libdtrace/common/dt_options.c')
| -rw-r--r-- | lib/libdtrace/common/dt_options.c | 1031 | 
1 files changed, 1031 insertions, 0 deletions
| diff --git a/lib/libdtrace/common/dt_options.c b/lib/libdtrace/common/dt_options.c new file mode 100644 index 000000000000..fa1407f83c12 --- /dev/null +++ b/lib/libdtrace/common/dt_options.c @@ -0,0 +1,1031 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2007 Sun Microsystems, Inc.  All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident	"%Z%%M%	%I%	%E% SMI" + +#include <sys/resource.h> +#include <sys/mman.h> +#include <sys/types.h> + +#include <strings.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#if defined(sun) +#include <alloca.h> +#endif +#include <errno.h> +#include <fcntl.h> + +#include <dt_impl.h> +#include <dt_string.h> + +static int +dt_opt_agg(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dt_aggregate_t *agp = &dtp->dt_aggregate; + +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	agp->dtat_flags |= option; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_amin(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char str[DTRACE_ATTR2STR_MAX]; +	dtrace_attribute_t attr; + +	if (arg == NULL || dtrace_str2attr(arg, &attr) == -1) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dt_dprintf("set compiler attribute minimum to %s\n", +	    dtrace_attr2str(attr, str, sizeof (str))); + +	if (dtp->dt_pcb != NULL) { +		dtp->dt_pcb->pcb_cflags |= DTRACE_C_EATTR; +		dtp->dt_pcb->pcb_amin = attr; +	} else { +		dtp->dt_cflags |= DTRACE_C_EATTR; +		dtp->dt_amin = attr; +	} + +	return (0); +} + +static void +dt_coredump(void) +{ +	const char msg[] = "libdtrace DEBUG: [ forcing coredump ]\n"; + +	struct sigaction act; +	struct rlimit lim; + +	(void) write(STDERR_FILENO, msg, sizeof (msg) - 1); + +	act.sa_handler = SIG_DFL; +	act.sa_flags = 0; + +	(void) sigemptyset(&act.sa_mask); +	(void) sigaction(SIGABRT, &act, NULL); + +	lim.rlim_cur = RLIM_INFINITY; +	lim.rlim_max = RLIM_INFINITY; + +	(void) setrlimit(RLIMIT_CORE, &lim); +	abort(); +} + +/*ARGSUSED*/ +static int +dt_opt_core(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	static int enabled = 0; + +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (enabled++ || atexit(dt_coredump) == 0) +		return (0); + +	return (dt_set_errno(dtp, errno)); +} + +/*ARGSUSED*/ +static int +dt_opt_cpp_hdrs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTCTX)); + +	if (dt_cpp_add_arg(dtp, "-H") == NULL) +		return (dt_set_errno(dtp, EDT_NOMEM)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_cpp_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char *cpp; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTCTX)); + +	if ((cpp = strdup(arg)) == NULL) +		return (dt_set_errno(dtp, EDT_NOMEM)); + +	dtp->dt_cpp_argv[0] = (char *)strbasename(cpp); +	free(dtp->dt_cpp_path); +	dtp->dt_cpp_path = cpp; + +	return (0); +} + +static int +dt_opt_cpp_opts(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char *buf; +	size_t len; +	const char *opt = (const char *)option; + +	if (opt == NULL || arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTCTX)); + +	len = strlen(opt) + strlen(arg) + 1; +	buf = alloca(len); + +	(void) strcpy(buf, opt); +	(void) strcat(buf, arg); + +	if (dt_cpp_add_arg(dtp, buf) == NULL) +		return (dt_set_errno(dtp, EDT_NOMEM)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_ctypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int fd; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1) +		return (dt_set_errno(dtp, errno)); + +	(void) close(dtp->dt_cdefs_fd); +	dtp->dt_cdefs_fd = fd; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_droptags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtp->dt_droptags = 1; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_dtypes(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int fd; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if ((fd = open64(arg, O_CREAT | O_WRONLY, 0666)) == -1) +		return (dt_set_errno(dtp, errno)); + +	(void) close(dtp->dt_ddefs_fd); +	dtp->dt_ddefs_fd = fd; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_debug(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	_dtrace_debug = 1; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_iregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int n; + +	if (arg == NULL || (n = atoi(arg)) <= 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_conf.dtc_difintregs = n; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_lazyload(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtp->dt_lazyload = 1; + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char *ld; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTCTX)); + +	if ((ld = strdup(arg)) == NULL) +		return (dt_set_errno(dtp, EDT_NOMEM)); + +	free(dtp->dt_ld_path); +	dtp->dt_ld_path = ld; + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dt_dirpath_t *dp; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL || +	    (dp->dir_path = strdup(arg)) == NULL) { +		free(dp); +		return (dt_set_errno(dtp, EDT_NOMEM)); +	} + +	dt_list_append(&dtp->dt_lib_path, dp); +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (strcmp(arg, "kernel") == 0) +		dtp->dt_linkmode = DT_LINK_KERNEL; +	else if (strcmp(arg, "primary") == 0) +		dtp->dt_linkmode = DT_LINK_PRIMARY; +	else if (strcmp(arg, "dynamic") == 0) +		dtp->dt_linkmode = DT_LINK_DYNAMIC; +	else if (strcmp(arg, "static") == 0) +		dtp->dt_linkmode = DT_LINK_STATIC; +	else +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (strcasecmp(arg, "elf") == 0) +		dtp->dt_linktype = DT_LTYP_ELF; +	else if (strcasecmp(arg, "dof") == 0) +		dtp->dt_linktype = DT_LTYP_DOF; +	else +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (strcmp(arg, "exec") == 0) +		dtp->dt_prcmode = DT_PROC_STOP_CREATE; +	else if (strcmp(arg, "preinit") == 0) +		dtp->dt_prcmode = DT_PROC_STOP_PREINIT; +	else if (strcmp(arg, "postinit") == 0) +		dtp->dt_prcmode = DT_PROC_STOP_POSTINIT; +	else if (strcmp(arg, "main") == 0) +		dtp->dt_prcmode = DT_PROC_STOP_MAIN; +	else +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int n; + +	if (arg == NULL || (n = atoi(arg)) < 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_procs->dph_lrulim = n; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTCTX)); + +	if (strcmp(arg, "a") == 0) +		dtp->dt_stdcmode = DT_STDC_XA; +	else if (strcmp(arg, "c") == 0) +		dtp->dt_stdcmode = DT_STDC_XC; +	else if (strcmp(arg, "s") == 0) +		dtp->dt_stdcmode = DT_STDC_XS; +	else if (strcmp(arg, "t") == 0) +		dtp->dt_stdcmode = DT_STDC_XT; +	else +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path); +	char *path; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if ((path = strdup(arg)) == NULL) +		return (dt_set_errno(dtp, EDT_NOMEM)); + +	free(dp->dir_path); +	dp->dir_path = path; + +	return (0); +} + + +/*ARGSUSED*/ +static int +dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int m; + +	if (arg == NULL || (m = atoi(arg)) <= 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_treedump = m; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	int n; + +	if (arg == NULL || (n = atoi(arg)) <= 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_conf.dtc_diftupregs = n; +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (strcmp(arg, "dynamic") == 0) +		dtp->dt_xlatemode = DT_XL_DYNAMIC; +	else if (strcmp(arg, "static") == 0) +		dtp->dt_xlatemode = DT_XL_STATIC; +	else +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		dtp->dt_pcb->pcb_cflags |= option; +	else +		dtp->dt_cflags |= option; + +	return (0); +} + +static int +dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_dflags |= option; +	return (0); +} + +static int +dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	if (arg != NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dtp->dt_pcb != NULL) +		dtp->dt_pcb->pcb_cflags &= ~option; +	else +		dtp->dt_cflags &= ~option; + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dt_version_t v; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (dt_version_str2num(arg, &v) == -1) +		return (dt_set_errno(dtp, EDT_VERSINVAL)); + +	if (!dt_version_defined(v)) +		return (dt_set_errno(dtp, EDT_VERSUNDEF)); + +	return (dt_reduce(dtp, v)); +} + +static int +dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char *end; +	dtrace_optval_t val = 0; +	int i; + +	const struct { +		char *positive; +		char *negative; +	} couples[] = { +		{ "yes",	"no" }, +		{ "enable",	"disable" }, +		{ "enabled",	"disabled" }, +		{ "true",	"false" }, +		{ "on",		"off" }, +		{ "set",	"unset" }, +		{ NULL } +	}; + +	if (arg != NULL) { +		if (arg[0] == '\0') { +			val = DTRACEOPT_UNSET; +			goto out; +		} + +		for (i = 0; couples[i].positive != NULL; i++) { +			if (strcasecmp(couples[i].positive, arg) == 0) { +				val = 1; +				goto out; +			} + +			if (strcasecmp(couples[i].negative, arg) == 0) { +				val = DTRACEOPT_UNSET; +				goto out; +			} +		} + +		errno = 0; +		val = strtoull(arg, &end, 0); + +		if (*end != '\0' || errno != 0 || val < 0) +			return (dt_set_errno(dtp, EDT_BADOPTVAL)); +	} + +out: +	dtp->dt_options[option] = val; +	return (0); +} + +static int +dt_optval_parse(const char *arg, dtrace_optval_t *rval) +{ +	dtrace_optval_t mul = 1; +	size_t len; +	char *end; + +	len = strlen(arg); +	errno = 0; + +	switch (arg[len - 1]) { +	case 't': +	case 'T': +		mul *= 1024; +		/*FALLTHRU*/ +	case 'g': +	case 'G': +		mul *= 1024; +		/*FALLTHRU*/ +	case 'm': +	case 'M': +		mul *= 1024; +		/*FALLTHRU*/ +	case 'k': +	case 'K': +		mul *= 1024; +		/*FALLTHRU*/ +	default: +		break; +	} + +	errno = 0; +	*rval = strtoull(arg, &end, 0) * mul; + +	if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') || +	    *rval < 0 || errno != 0) +		return (-1); + +	return (0); +} + +static int +dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtrace_optval_t val = 0; + +	if (arg != NULL && dt_optval_parse(arg, &val) != 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_options[option] = val; +	return (0); +} + +static int +dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	char *end; +	int i; +	dtrace_optval_t mul = 1, val = 0; + +	const struct { +		char *name; +		hrtime_t mul; +	} suffix[] = { +		{ "ns", 	NANOSEC / NANOSEC }, +		{ "nsec",	NANOSEC / NANOSEC }, +		{ "us",		NANOSEC / MICROSEC }, +		{ "usec",	NANOSEC / MICROSEC }, +		{ "ms",		NANOSEC / MILLISEC }, +		{ "msec",	NANOSEC / MILLISEC }, +		{ "s",		NANOSEC / SEC }, +		{ "sec",	NANOSEC / SEC }, +		{ "m",		NANOSEC * (hrtime_t)60 }, +		{ "min",	NANOSEC * (hrtime_t)60 }, +		{ "h",		NANOSEC * (hrtime_t)60 * (hrtime_t)60 }, +		{ "hour",	NANOSEC * (hrtime_t)60 * (hrtime_t)60 }, +		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) }, +		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) }, +		{ "hz",		0 }, +		{ NULL } +	}; + +	if (arg != NULL) { +		errno = 0; +		val = strtoull(arg, &end, 0); + +		for (i = 0; suffix[i].name != NULL; i++) { +			if (strcasecmp(suffix[i].name, end) == 0) { +				mul = suffix[i].mul; +				break; +			} +		} + +		if (suffix[i].name == NULL && *end != '\0' || val < 0) +			return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +		if (mul == 0) { +			/* +			 * The rate has been specified in frequency-per-second. +			 */ +			if (val != 0) +				val = NANOSEC / val; +		} else { +			val *= mul; +		} +	} + +	dtp->dt_options[option] = val; +	return (0); +} + +/* + * When setting the strsize option, set the option in the dt_options array + * using dt_opt_size() as usual, and then update the definition of the CTF + * type for the D intrinsic "string" to be an array of the corresponding size. + * If any errors occur, reset dt_options[option] to its previous value. + */ +static int +dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtrace_optval_t val = dtp->dt_options[option]; +	ctf_file_t *fp = DT_STR_CTFP(dtp); +	ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp)); +	ctf_arinfo_t r; + +	if (dt_opt_size(dtp, arg, option) != 0) +		return (-1); /* dt_errno is set for us */ + +	if (dtp->dt_options[option] > UINT_MAX) { +		dtp->dt_options[option] = val; +		return (dt_set_errno(dtp, EOVERFLOW)); +	} + +	if (ctf_array_info(fp, type, &r) == CTF_ERR) { +		dtp->dt_options[option] = val; +		dtp->dt_ctferr = ctf_errno(fp); +		return (dt_set_errno(dtp, EDT_CTF)); +	} + +	r.ctr_nelems = (uint_t)dtp->dt_options[option]; + +	if (ctf_set_array(fp, type, &r) == CTF_ERR || +	    ctf_update(fp) == CTF_ERR) { +		dtp->dt_options[option] = val; +		dtp->dt_ctferr = ctf_errno(fp); +		return (dt_set_errno(dtp, EDT_CTF)); +	} + +	return (0); +} + +static const struct { +	const char *dtbp_name; +	int dtbp_policy; +} _dtrace_bufpolicies[] = { +	{ "ring", DTRACEOPT_BUFPOLICY_RING }, +	{ "fill", DTRACEOPT_BUFPOLICY_FILL }, +	{ "switch", DTRACEOPT_BUFPOLICY_SWITCH }, +	{ NULL, 0 } +}; + +/*ARGSUSED*/ +static int +dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtrace_optval_t policy = DTRACEOPT_UNSET; +	int i; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) { +		if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) { +			policy = _dtrace_bufpolicies[i].dtbp_policy; +			break; +		} +	} + +	if (policy == DTRACEOPT_UNSET) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy; + +	return (0); +} + +static const struct { +	const char *dtbr_name; +	int dtbr_policy; +} _dtrace_bufresize[] = { +	{ "auto", DTRACEOPT_BUFRESIZE_AUTO }, +	{ "manual", DTRACEOPT_BUFRESIZE_MANUAL }, +	{ NULL, 0 } +}; + +/*ARGSUSED*/ +static int +dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtrace_optval_t policy = DTRACEOPT_UNSET; +	int i; + +	if (arg == NULL) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) { +		if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) { +			policy = _dtrace_bufresize[i].dtbr_policy; +			break; +		} +	} + +	if (policy == DTRACEOPT_UNSET) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy; + +	return (0); +} + +int +dt_options_load(dtrace_hdl_t *dtp) +{ +	dof_hdr_t hdr, *dof; +	dof_sec_t *sec; +	size_t offs; +	int i; + +	/* +	 * To load the option values, we need to ask the kernel to provide its +	 * DOF, which we'll sift through to look for OPTDESC sections. +	 */ +	bzero(&hdr, sizeof (dof_hdr_t)); +	hdr.dofh_loadsz = sizeof (dof_hdr_t); + +#if defined(sun) +	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1) +#else +	dof = &hdr; +	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1) +#endif +		return (dt_set_errno(dtp, errno)); + +	if (hdr.dofh_loadsz < sizeof (dof_hdr_t)) +		return (dt_set_errno(dtp, EINVAL)); + +	dof = alloca(hdr.dofh_loadsz); +	bzero(dof, sizeof (dof_hdr_t)); +	dof->dofh_loadsz = hdr.dofh_loadsz; + +	for (i = 0; i < DTRACEOPT_MAX; i++) +		dtp->dt_options[i] = DTRACEOPT_UNSET; + +#if defined(sun) +	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) +#else +	if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1) +#endif +		return (dt_set_errno(dtp, errno)); + +	for (i = 0; i < dof->dofh_secnum; i++) { +		sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof + +		    dof->dofh_secoff + i * dof->dofh_secsize); + +		if (sec->dofs_type != DOF_SECT_OPTDESC) +			continue; + +		break; +	} + +	for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { +		dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t) +		    ((uintptr_t)dof + sec->dofs_offset + offs); + +		if (opt->dofo_strtab != DOF_SECIDX_NONE) +			continue; + +		if (opt->dofo_option >= DTRACEOPT_MAX) +			continue; + +		dtp->dt_options[opt->dofo_option] = opt->dofo_value; +	} + +	return (0); +} + +/*ARGSUSED*/ +static int +dt_opt_preallocate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ +	dtrace_optval_t size; +	void *p; + +	if (arg == NULL || dt_optval_parse(arg, &size) != 0) +		return (dt_set_errno(dtp, EDT_BADOPTVAL)); + +	if (size > SIZE_MAX) +		size = SIZE_MAX; + +	if ((p = dt_zalloc(dtp, size)) == NULL) { +		do { +			size /= 2; +		} while ((p = dt_zalloc(dtp, size)) == NULL); +	} + +	dt_free(dtp, p); + +	return (0); +} + +typedef struct dt_option { +	const char *o_name; +	int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t); +	uintptr_t o_option; +} dt_option_t; + +/* + * Compile-time options. + */ +static const dt_option_t _dtrace_ctoptions[] = { +	{ "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU }, +	{ "amin", dt_opt_amin }, +	{ "argref", dt_opt_cflags, DTRACE_C_ARGREF }, +	{ "core", dt_opt_core }, +	{ "cpp", dt_opt_cflags, DTRACE_C_CPP }, +	{ "cpphdrs", dt_opt_cpp_hdrs }, +	{ "cpppath", dt_opt_cpp_path }, +	{ "ctypes", dt_opt_ctypes }, +	{ "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG }, +	{ "dtypes", dt_opt_dtypes }, +	{ "debug", dt_opt_debug }, +	{ "define", dt_opt_cpp_opts, (uintptr_t)"-D" }, +	{ "droptags", dt_opt_droptags }, +	{ "empty", dt_opt_cflags, DTRACE_C_EMPTY }, +	{ "errtags", dt_opt_cflags, DTRACE_C_ETAGS }, +	{ "evaltime", dt_opt_evaltime }, +	{ "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" }, +	{ "iregs", dt_opt_iregs }, +	{ "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF }, +	{ "knodefs", dt_opt_cflags, DTRACE_C_KNODEF }, +	{ "late", dt_opt_xlate }, +	{ "lazyload", dt_opt_lazyload }, +	{ "ldpath", dt_opt_ld_path }, +	{ "libdir", dt_opt_libdir }, +	{ "linkmode", dt_opt_linkmode }, +	{ "linktype", dt_opt_linktype }, +	{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS }, +	{ "pgmax", dt_opt_pgmax }, +	{ "preallocate", dt_opt_preallocate }, +	{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC }, +	{ "stdc", dt_opt_stdc }, +	{ "strip", dt_opt_dflags, DTRACE_D_STRIP }, +	{ "syslibdir", dt_opt_syslibdir }, +	{ "tree", dt_opt_tree }, +	{ "tregs", dt_opt_tregs }, +	{ "udefs", dt_opt_invcflags, DTRACE_C_UNODEF }, +	{ "undef", dt_opt_cpp_opts, (uintptr_t)"-U" }, +	{ "unodefs", dt_opt_cflags, DTRACE_C_UNODEF }, +	{ "verbose", dt_opt_cflags, DTRACE_C_DIFV }, +	{ "version", dt_opt_version }, +	{ "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS }, +	{ NULL, NULL, 0 } +}; + +/* + * Run-time options. + */ +static const dt_option_t _dtrace_rtoptions[] = { +	{ "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE }, +	{ "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE }, +	{ "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY }, +	{ "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE }, +	{ "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE }, +	{ "cpu", dt_opt_runtime, DTRACEOPT_CPU }, +	{ "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE }, +	{ "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE }, +	{ "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON }, +	{ "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES }, +	{ "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE }, +	{ "nspec", dt_opt_runtime, DTRACEOPT_NSPEC }, +	{ "specsize", dt_opt_size, DTRACEOPT_SPECSIZE }, +	{ "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES }, +	{ "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE }, +	{ "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE }, +	{ "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES }, +	{ NULL, NULL, 0 } +}; + +/* + * Dynamic run-time options. + */ +static const dt_option_t _dtrace_drtoptions[] = { +	{ "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE }, +	{ "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY }, +	{ "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS }, +	{ "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS }, +	{ "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV }, +	{ "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT }, +	{ "quiet", dt_opt_runtime, DTRACEOPT_QUIET }, +	{ "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES }, +	{ "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT }, +	{ "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE }, +	{ NULL, NULL, 0 } +}; + +int +dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val) +{ +	const dt_option_t *op; + +	if (opt == NULL) +		return (dt_set_errno(dtp, EINVAL)); + +	/* +	 * We only need to search the run-time options -- it's not legal +	 * to get the values of compile-time options. +	 */ +	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) { +		if (strcmp(op->o_name, opt) == 0) { +			*val = dtp->dt_options[op->o_option]; +			return (0); +		} +	} + +	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) { +		if (strcmp(op->o_name, opt) == 0) { +			*val = dtp->dt_options[op->o_option]; +			return (0); +		} +	} + +	return (dt_set_errno(dtp, EDT_BADOPTNAME)); +} + +int +dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val) +{ +	const dt_option_t *op; + +	if (opt == NULL) +		return (dt_set_errno(dtp, EINVAL)); + +	for (op = _dtrace_ctoptions; op->o_name != NULL; op++) { +		if (strcmp(op->o_name, opt) == 0) +			return (op->o_func(dtp, val, op->o_option)); +	} + +	for (op = _dtrace_drtoptions; op->o_name != NULL; op++) { +		if (strcmp(op->o_name, opt) == 0) +			return (op->o_func(dtp, val, op->o_option)); +	} + +	for (op = _dtrace_rtoptions; op->o_name != NULL; op++) { +		if (strcmp(op->o_name, opt) == 0) { +			/* +			 * Only dynamic run-time options may be set while +			 * tracing is active. +			 */ +			if (dtp->dt_active) +				return (dt_set_errno(dtp, EDT_ACTIVE)); + +			return (op->o_func(dtp, val, op->o_option)); +		} +	} + +	return (dt_set_errno(dtp, EDT_BADOPTNAME)); +} | 
