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