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