/* * 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. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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 = NULL; size_t len; const char *opt = (const char *)option; int ret; if (opt == NULL || arg == NULL) { ret = dt_set_errno(dtp, EDT_BADOPTVAL); goto out; } if (dtp->dt_pcb != NULL) { ret = dt_set_errno(dtp, EDT_BADOPTCTX); goto out; } len = strlen(opt) + strlen(arg) + 1; if ((buf = dt_alloc(dtp, len)) == NULL) { ret = dt_set_errno(dtp, EDT_NOMEM); goto out; } (void) strcpy(buf, opt); (void) strcat(buf, arg); if (dt_cpp_add_arg(dtp, buf) == NULL) { ret = dt_set_errno(dtp, EDT_NOMEM); goto out; } ret = 0; out: if (buf != NULL) dt_free(dtp, buf); return (ret); } /*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); } #ifdef __FreeBSD__ static int dt_opt_objcopy_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { char *objcopy; if (arg == NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if (dtp->dt_pcb != NULL) return (dt_set_errno(dtp, EDT_BADOPTCTX)); if ((objcopy = strdup(arg)) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); free(dtp->dt_objcopy_path); dtp->dt_objcopy_path = objcopy; return (0); } #endif /*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_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { if (arg == NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if (strcmp(arg, "ascii") == 0) dtp->dt_encoding = DT_ENCODING_ASCII; else if (strcmp(arg, "utf8") == 0) dtp->dt_encoding = DT_ENCODING_UTF8; 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); } static int dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { char **p; char *var; int nvars; /* * We can't effectively set environment variables from #pragma lines * since the processes have already been spawned. */ if (dtp->dt_pcb != NULL) return (dt_set_errno(dtp, EDT_BADOPTCTX)); if (arg == NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if (!option && strchr(arg, '=') != NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); for (nvars = 0, p = dtp->dt_proc_env; *p != NULL; nvars++, p++) continue; for (p = dtp->dt_proc_env; *p != NULL; p++) { var = strchr(*p, '='); if (var == NULL) var = *p + strlen(*p); if (strncmp(*p, arg, var - *p) == 0) { dt_free(dtp, *p); *p = dtp->dt_proc_env[nvars - 1]; dtp->dt_proc_env[nvars - 1] = NULL; nvars--; } } if (option) { if ((var = strdup(arg)) == NULL) return (dt_set_errno(dtp, EDT_NOMEM)); nvars++; if ((p = dt_alloc(dtp, sizeof(char *) * (nvars + 1))) == NULL) { dt_free(dtp, var); return (dt_set_errno(dtp, EDT_NOMEM)); } bcopy(dtp->dt_proc_env, p, sizeof(char *) * nvars); dt_free(dtp, dtp->dt_proc_env); dtp->dt_proc_env = p; dtp->dt_proc_env[nvars - 1] = var; dtp->dt_proc_env[nvars] = NULL; } 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_oformat(dtrace_hdl_t *dtp, const char *arg, uintptr_t option __unused) { if (arg == NULL) return (dt_set_errno(dtp, EDT_BADOPTVAL)); if (xo_set_options(NULL, arg) < 0) return (dt_set_errno(dtp, EDT_BADOPTVAL)); return (dtrace_oformat_configure(dtp)); } 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, ret; /* * 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. */ dof = &hdr; bzero(&hdr, sizeof (dof_hdr_t)); hdr.dofh_loadsz = sizeof (dof_hdr_t); #ifdef illumos if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) #else if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1) #endif { ret = dt_set_errno(dtp, errno); goto out; } if (hdr.dofh_loadsz < sizeof (dof_hdr_t)) { ret = dt_set_errno(dtp, EINVAL); goto out; } if ((dof = dt_alloc(dtp, hdr.dofh_loadsz)) == NULL) { ret = dt_set_errno(dtp, EDT_NOMEM); goto out; } 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; #ifdef illumos if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) #else if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &dof) == -1) #endif { ret = dt_set_errno(dtp, errno); goto out; } 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; } ret = 0; out: if (dof != NULL && dof != &hdr) dt_free(dtp, dof); return (ret); } 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 }, { "encoding", dt_opt_encoding }, { "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 }, #ifdef __FreeBSD__ { "objcopypath", dt_opt_objcopy_path }, #endif { "pgmax", dt_opt_pgmax }, { "pspec", dt_opt_cflags, DTRACE_C_PSPEC }, { "setenv", dt_opt_setenv, 1 }, { "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 }, { "unsetenv", dt_opt_setenv, 0 }, { "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 }, { "oformat", dt_opt_oformat, 0 }, { "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 }, { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL }, { NULL, NULL, 0 } }; /* * Dynamic run-time options. */ static const dt_option_t _dtrace_drtoptions[] = { { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST }, { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK }, { "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 }, { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM }, { "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)); }