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 #include <alloca.h>
  42 #include <errno.h>
  43 #include <fcntl.h>
  44 #include <zone.h>
  45 #include <libzonecfg.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 /*ARGSUSED*/
 284 static int
 285 dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 286 {
 287         dt_dirpath_t *dp;
 288 
 289         if (arg == NULL)
 290                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 291 
 292         if ((dp = malloc(sizeof (dt_dirpath_t))) == NULL ||
 293             (dp->dir_path = strdup(arg)) == NULL) {
 294                 free(dp);
 295                 return (dt_set_errno(dtp, EDT_NOMEM));
 296         }
 297 
 298         dt_list_append(&dtp->dt_lib_path, dp);
 299         return (0);
 300 }
 301 
 302 /*ARGSUSED*/
 303 static int
 304 dt_opt_linkmode(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 305 {
 306         if (arg == NULL)
 307                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 308 
 309         if (strcmp(arg, "kernel") == 0)
 310                 dtp->dt_linkmode = DT_LINK_KERNEL;
 311         else if (strcmp(arg, "primary") == 0)
 312                 dtp->dt_linkmode = DT_LINK_PRIMARY;
 313         else if (strcmp(arg, "dynamic") == 0)
 314                 dtp->dt_linkmode = DT_LINK_DYNAMIC;
 315         else if (strcmp(arg, "static") == 0)
 316                 dtp->dt_linkmode = DT_LINK_STATIC;
 317         else
 318                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 319 
 320         return (0);
 321 }
 322 
 323 /*ARGSUSED*/
 324 static int
 325 dt_opt_linktype(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 326 {
 327         if (arg == NULL)
 328                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 329 
 330         if (strcasecmp(arg, "elf") == 0)
 331                 dtp->dt_linktype = DT_LTYP_ELF;
 332         else if (strcasecmp(arg, "dof") == 0)
 333                 dtp->dt_linktype = DT_LTYP_DOF;
 334         else
 335                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 336 
 337         return (0);
 338 }
 339 
 340 /*ARGSUSED*/
 341 static int
 342 dt_opt_encoding(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 343 {
 344         if (arg == NULL)
 345                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 346 
 347         if (strcmp(arg, "ascii") == 0)
 348                 dtp->dt_encoding = DT_ENCODING_ASCII;
 349         else if (strcmp(arg, "utf8") == 0)
 350                 dtp->dt_encoding = DT_ENCODING_UTF8;
 351         else
 352                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 353 
 354         return (0);
 355 }
 356 
 357 /*ARGSUSED*/
 358 static int
 359 dt_opt_evaltime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 360 {
 361         if (arg == NULL)
 362                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 363 
 364         if (strcmp(arg, "exec") == 0)
 365                 dtp->dt_prcmode = DT_PROC_STOP_CREATE;
 366         else if (strcmp(arg, "preinit") == 0)
 367                 dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
 368         else if (strcmp(arg, "postinit") == 0)
 369                 dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
 370         else if (strcmp(arg, "main") == 0)
 371                 dtp->dt_prcmode = DT_PROC_STOP_MAIN;
 372         else
 373                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 374 
 375         return (0);
 376 }
 377 
 378 /*ARGSUSED*/
 379 static int
 380 dt_opt_pgmax(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 381 {
 382         int n;
 383 
 384         if (arg == NULL || (n = atoi(arg)) < 0)
 385                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 386 
 387         dtp->dt_procs->dph_lrulim = n;
 388         return (0);
 389 }
 390 
 391 static int
 392 dt_opt_setenv(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 393 {
 394         char **p;
 395         char *var;
 396         int i;
 397 
 398         /*
 399          * We can't effectively set environment variables from #pragma lines
 400          * since the processes have already been spawned.
 401          */
 402         if (dtp->dt_pcb != NULL)
 403                 return (dt_set_errno(dtp, EDT_BADOPTCTX));
 404 
 405         if (arg == NULL)
 406                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 407 
 408         if (!option && strchr(arg, '=') != NULL)
 409                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 410 
 411         for (i = 1, p = dtp->dt_proc_env; *p != NULL; i++, p++)
 412                 continue;
 413 
 414         for (p = dtp->dt_proc_env; *p != NULL; p++) {
 415                 var = strchr(*p, '=');
 416                 if (var == NULL)
 417                         var = *p + strlen(*p);
 418                 if (strncmp(*p, arg, var - *p) == 0) {
 419                         dt_free(dtp, *p);
 420                         *p = dtp->dt_proc_env[i - 1];
 421                         dtp->dt_proc_env[i - 1] = NULL;
 422                         i--;
 423                 }
 424         }
 425 
 426         if (option) {
 427                 if ((var = strdup(arg)) == NULL)
 428                         return (dt_set_errno(dtp, EDT_NOMEM));
 429 
 430                 if ((p = dt_alloc(dtp, sizeof (char *) * (i + 1))) == NULL) {
 431                         dt_free(dtp, var);
 432                         return (dt_set_errno(dtp, EDT_NOMEM));
 433                 }
 434 
 435                 bcopy(dtp->dt_proc_env, p, sizeof (char *) * i);
 436                 dt_free(dtp, dtp->dt_proc_env);
 437                 dtp->dt_proc_env = p;
 438 
 439                 dtp->dt_proc_env[i - 1] = var;
 440                 dtp->dt_proc_env[i] = NULL;
 441         }
 442 
 443         return (0);
 444 }
 445 
 446 /*ARGSUSED*/
 447 static int
 448 dt_opt_stdc(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 449 {
 450         if (arg == NULL)
 451                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 452 
 453         if (dtp->dt_pcb != NULL)
 454                 return (dt_set_errno(dtp, EDT_BADOPTCTX));
 455 
 456         if (strcmp(arg, "a") == 0)
 457                 dtp->dt_stdcmode = DT_STDC_XA;
 458         else if (strcmp(arg, "c") == 0)
 459                 dtp->dt_stdcmode = DT_STDC_XC;
 460         else if (strcmp(arg, "s") == 0)
 461                 dtp->dt_stdcmode = DT_STDC_XS;
 462         else if (strcmp(arg, "t") == 0)
 463                 dtp->dt_stdcmode = DT_STDC_XT;
 464         else
 465                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 466 
 467         return (0);
 468 }
 469 
 470 /*ARGSUSED*/
 471 static int
 472 dt_opt_syslibdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 473 {
 474         dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
 475         char *path;
 476 
 477         if (arg == NULL)
 478                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 479 
 480         if ((path = strdup(arg)) == NULL)
 481                 return (dt_set_errno(dtp, EDT_NOMEM));
 482 
 483         free(dp->dir_path);
 484         dp->dir_path = path;
 485 
 486         return (0);
 487 }
 488 
 489 /*ARGSUSED*/
 490 static int
 491 dt_opt_tree(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 492 {
 493         int m;
 494 
 495         if (arg == NULL || (m = atoi(arg)) <= 0)
 496                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 497 
 498         dtp->dt_treedump = m;
 499         return (0);
 500 }
 501 
 502 /*ARGSUSED*/
 503 static int
 504 dt_opt_tregs(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 505 {
 506         int n;
 507 
 508         if (arg == NULL || (n = atoi(arg)) <= 0)
 509                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 510 
 511         dtp->dt_conf.dtc_diftupregs = n;
 512         return (0);
 513 }
 514 
 515 /*ARGSUSED*/
 516 static int
 517 dt_opt_xlate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 518 {
 519         if (arg == NULL)
 520                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 521 
 522         if (strcmp(arg, "dynamic") == 0)
 523                 dtp->dt_xlatemode = DT_XL_DYNAMIC;
 524         else if (strcmp(arg, "static") == 0)
 525                 dtp->dt_xlatemode = DT_XL_STATIC;
 526         else
 527                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 528 
 529         return (0);
 530 }
 531 
 532 /*ARGSUSED*/
 533 static int
 534 dt_opt_cflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 535 {
 536         if (arg != NULL)
 537                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 538 
 539         if (dtp->dt_pcb != NULL)
 540                 dtp->dt_pcb->pcb_cflags |= option;
 541         else
 542                 dtp->dt_cflags |= option;
 543 
 544         return (0);
 545 }
 546 
 547 static int
 548 dt_opt_dflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 549 {
 550         if (arg != NULL)
 551                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 552 
 553         dtp->dt_dflags |= option;
 554         return (0);
 555 }
 556 
 557 static int
 558 dt_opt_invcflags(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 559 {
 560         if (arg != NULL)
 561                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 562 
 563         if (dtp->dt_pcb != NULL)
 564                 dtp->dt_pcb->pcb_cflags &= ~option;
 565         else
 566                 dtp->dt_cflags &= ~option;
 567 
 568         return (0);
 569 }
 570 
 571 /*ARGSUSED*/
 572 static int
 573 dt_opt_version(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 574 {
 575         dt_version_t v;
 576 
 577         if (arg == NULL)
 578                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 579 
 580         if (dt_version_str2num(arg, &v) == -1)
 581                 return (dt_set_errno(dtp, EDT_VERSINVAL));
 582 
 583         if (!dt_version_defined(v))
 584                 return (dt_set_errno(dtp, EDT_VERSUNDEF));
 585 
 586         return (dt_reduce(dtp, v));
 587 }
 588 
 589 static int
 590 dt_opt_runtime(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 591 {
 592         char *end;
 593         dtrace_optval_t val = 0;
 594         int i;
 595 
 596         const struct {
 597                 char *positive;
 598                 char *negative;
 599         } couples[] = {
 600                 { "yes",        "no" },
 601                 { "enable",     "disable" },
 602                 { "enabled",    "disabled" },
 603                 { "true",       "false" },
 604                 { "on",         "off" },
 605                 { "set",        "unset" },
 606                 { NULL }
 607         };
 608 
 609         if (arg != NULL) {
 610                 if (arg[0] == '\0') {
 611                         val = DTRACEOPT_UNSET;
 612                         goto out;
 613                 }
 614 
 615                 for (i = 0; couples[i].positive != NULL; i++) {
 616                         if (strcasecmp(couples[i].positive, arg) == 0) {
 617                                 val = 1;
 618                                 goto out;
 619                         }
 620 
 621                         if (strcasecmp(couples[i].negative, arg) == 0) {
 622                                 val = DTRACEOPT_UNSET;
 623                                 goto out;
 624                         }
 625                 }
 626 
 627                 errno = 0;
 628                 val = strtoull(arg, &end, 0);
 629 
 630                 if (*end != '\0' || errno != 0 || val < 0)
 631                         return (dt_set_errno(dtp, EDT_BADOPTVAL));
 632         }
 633 
 634 out:
 635         dtp->dt_options[option] = val;
 636         return (0);
 637 }
 638 
 639 static int
 640 dt_optval_parse(const char *arg, dtrace_optval_t *rval)
 641 {
 642         dtrace_optval_t mul = 1;
 643         size_t len;
 644         char *end;
 645 
 646         len = strlen(arg);
 647         errno = 0;
 648 
 649         switch (arg[len - 1]) {
 650         case 't':
 651         case 'T':
 652                 mul *= 1024;
 653                 /*FALLTHRU*/
 654         case 'g':
 655         case 'G':
 656                 mul *= 1024;
 657                 /*FALLTHRU*/
 658         case 'm':
 659         case 'M':
 660                 mul *= 1024;
 661                 /*FALLTHRU*/
 662         case 'k':
 663         case 'K':
 664                 mul *= 1024;
 665                 /*FALLTHRU*/
 666         default:
 667                 break;
 668         }
 669 
 670         errno = 0;
 671         *rval = strtoull(arg, &end, 0) * mul;
 672 
 673         if ((mul > 1 && end != &arg[len - 1]) || (mul == 1 && *end != '\0') ||
 674             *rval < 0 || errno != 0)
 675                 return (-1);
 676 
 677         return (0);
 678 }
 679 
 680 static int
 681 dt_opt_size(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 682 {
 683         dtrace_optval_t val = 0;
 684 
 685         if (arg != NULL && dt_optval_parse(arg, &val) != 0)
 686                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 687 
 688         dtp->dt_options[option] = val;
 689         return (0);
 690 }
 691 
 692 static int
 693 dt_opt_rate(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 694 {
 695         char *end;
 696         int i;
 697         dtrace_optval_t mul = 1, val = 0;
 698 
 699         const struct {
 700                 char *name;
 701                 hrtime_t mul;
 702         } suffix[] = {
 703                 { "ns",         NANOSEC / NANOSEC },
 704                 { "nsec",       NANOSEC / NANOSEC },
 705                 { "us",         NANOSEC / MICROSEC },
 706                 { "usec",       NANOSEC / MICROSEC },
 707                 { "ms",         NANOSEC / MILLISEC },
 708                 { "msec",       NANOSEC / MILLISEC },
 709                 { "s",          NANOSEC / SEC },
 710                 { "sec",        NANOSEC / SEC },
 711                 { "m",          NANOSEC * (hrtime_t)60 },
 712                 { "min",        NANOSEC * (hrtime_t)60 },
 713                 { "h",          NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
 714                 { "hour",       NANOSEC * (hrtime_t)60 * (hrtime_t)60 },
 715                 { "d",          NANOSEC * (hrtime_t)(24 * 60 * 60) },
 716                 { "day",        NANOSEC * (hrtime_t)(24 * 60 * 60) },
 717                 { "hz",         0 },
 718                 { NULL }
 719         };
 720 
 721         if (arg != NULL) {
 722                 errno = 0;
 723                 val = strtoull(arg, &end, 0);
 724 
 725                 for (i = 0; suffix[i].name != NULL; i++) {
 726                         if (strcasecmp(suffix[i].name, end) == 0) {
 727                                 mul = suffix[i].mul;
 728                                 break;
 729                         }
 730                 }
 731 
 732                 if (suffix[i].name == NULL && *end != '\0' || val < 0)
 733                         return (dt_set_errno(dtp, EDT_BADOPTVAL));
 734 
 735                 if (mul == 0) {
 736                         /*
 737                          * The rate has been specified in frequency-per-second.
 738                          */
 739                         if (val != 0)
 740                                 val = NANOSEC / val;
 741                 } else {
 742                         val *= mul;
 743                 }
 744         }
 745 
 746         dtp->dt_options[option] = val;
 747         return (0);
 748 }
 749 
 750 /*
 751  * When setting the strsize option, set the option in the dt_options array
 752  * using dt_opt_size() as usual, and then update the definition of the CTF
 753  * type for the D intrinsic "string" to be an array of the corresponding size.
 754  * If any errors occur, reset dt_options[option] to its previous value.
 755  */
 756 static int
 757 dt_opt_strsize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 758 {
 759         dtrace_optval_t val = dtp->dt_options[option];
 760         ctf_file_t *fp = DT_STR_CTFP(dtp);
 761         ctf_id_t type = ctf_type_resolve(fp, DT_STR_TYPE(dtp));
 762         ctf_arinfo_t r;
 763 
 764         if (dt_opt_size(dtp, arg, option) != 0)
 765                 return (-1); /* dt_errno is set for us */
 766 
 767         if (dtp->dt_options[option] > UINT_MAX) {
 768                 dtp->dt_options[option] = val;
 769                 return (dt_set_errno(dtp, EOVERFLOW));
 770         }
 771 
 772         if (ctf_array_info(fp, type, &r) == CTF_ERR) {
 773                 dtp->dt_options[option] = val;
 774                 dtp->dt_ctferr = ctf_errno(fp);
 775                 return (dt_set_errno(dtp, EDT_CTF));
 776         }
 777 
 778         r.ctr_nelems = (uint_t)dtp->dt_options[option];
 779 
 780         if (ctf_set_array(fp, type, &r) == CTF_ERR ||
 781             ctf_update(fp) == CTF_ERR) {
 782                 dtp->dt_options[option] = val;
 783                 dtp->dt_ctferr = ctf_errno(fp);
 784                 return (dt_set_errno(dtp, EDT_CTF));
 785         }
 786 
 787         return (0);
 788 }
 789 
 790 static const struct {
 791         const char *dtbp_name;
 792         int dtbp_policy;
 793 } _dtrace_bufpolicies[] = {
 794         { "ring", DTRACEOPT_BUFPOLICY_RING },
 795         { "fill", DTRACEOPT_BUFPOLICY_FILL },
 796         { "switch", DTRACEOPT_BUFPOLICY_SWITCH },
 797         { NULL, 0 }
 798 };
 799 
 800 /*ARGSUSED*/
 801 static int
 802 dt_opt_bufpolicy(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 803 {
 804         dtrace_optval_t policy = DTRACEOPT_UNSET;
 805         int i;
 806 
 807         if (arg == NULL)
 808                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 809 
 810         for (i = 0; _dtrace_bufpolicies[i].dtbp_name != NULL; i++) {
 811                 if (strcmp(_dtrace_bufpolicies[i].dtbp_name, arg) == 0) {
 812                         policy = _dtrace_bufpolicies[i].dtbp_policy;
 813                         break;
 814                 }
 815         }
 816 
 817         if (policy == DTRACEOPT_UNSET)
 818                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 819 
 820         dtp->dt_options[DTRACEOPT_BUFPOLICY] = policy;
 821 
 822         return (0);
 823 }
 824 
 825 static const struct {
 826         const char *dtbr_name;
 827         int dtbr_policy;
 828 } _dtrace_bufresize[] = {
 829         { "auto", DTRACEOPT_BUFRESIZE_AUTO },
 830         { "manual", DTRACEOPT_BUFRESIZE_MANUAL },
 831         { NULL, 0 }
 832 };
 833 
 834 /*ARGSUSED*/
 835 static int
 836 dt_opt_bufresize(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 837 {
 838         dtrace_optval_t policy = DTRACEOPT_UNSET;
 839         int i;
 840 
 841         if (arg == NULL)
 842                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 843 
 844         for (i = 0; _dtrace_bufresize[i].dtbr_name != NULL; i++) {
 845                 if (strcmp(_dtrace_bufresize[i].dtbr_name, arg) == 0) {
 846                         policy = _dtrace_bufresize[i].dtbr_policy;
 847                         break;
 848                 }
 849         }
 850 
 851         if (policy == DTRACEOPT_UNSET)
 852                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 853 
 854         dtp->dt_options[DTRACEOPT_BUFRESIZE] = policy;
 855 
 856         return (0);
 857 }
 858 
 859 /*ARGSUSED*/
 860 static int
 861 dt_opt_zone(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 862 {
 863         zoneid_t z, did;
 864 
 865         if (arg == NULL)
 866                 return (dt_set_errno(dtp, EDT_BADOPTVAL));
 867 
 868         /*
 869          * If the specified zone is currently running, we'll query the kernel
 870          * for its debugger ID.  If it doesn't appear to be running, we'll look
 871          * for it for among all installed zones (thereby allowing a zdefs
 872          * enabling against a halted zone).
 873          */
 874         if ((z = getzoneidbyname(arg)) != -1) {
 875                 if (zone_getattr(z, ZONE_ATTR_DID, &did, sizeof (did)) < 0)
 876                         return (dt_set_errno(dtp, EDT_BADOPTVAL));
 877         } else {
 878                 zone_dochandle_t handle;
 879 
 880                 if ((handle = zonecfg_init_handle()) == NULL)
 881                         return (dt_set_errno(dtp, errno));
 882 
 883                 if (zonecfg_get_handle(arg, handle) != Z_OK) {
 884                         zonecfg_fini_handle(handle);
 885                         return (dt_set_errno(dtp, EDT_BADOPTVAL));
 886                 }
 887 
 888                 did = zonecfg_get_did(handle);
 889                 zonecfg_fini_handle(handle);
 890         }
 891 
 892         dtp->dt_options[DTRACEOPT_ZONE] = did;
 893 
 894         return (0);
 895 }
 896 
 897 int
 898 dt_options_load(dtrace_hdl_t *dtp)
 899 {
 900         dof_hdr_t hdr, *dof;
 901         dof_sec_t *sec;
 902         size_t offs;
 903         int i;
 904 
 905         /*
 906          * To load the option values, we need to ask the kernel to provide its
 907          * DOF, which we'll sift through to look for OPTDESC sections.
 908          */
 909         bzero(&hdr, sizeof (dof_hdr_t));
 910         hdr.dofh_loadsz = sizeof (dof_hdr_t);
 911 
 912         if (dt_ioctl(dtp, DTRACEIOC_DOFGET, &hdr) == -1)
 913                 return (dt_set_errno(dtp, errno));
 914 
 915         if (hdr.dofh_loadsz < sizeof (dof_hdr_t))
 916                 return (dt_set_errno(dtp, EINVAL));
 917 
 918         dof = calloc(1, hdr.dofh_loadsz);
 919         if (dof == NULL)
 920                 return (dt_set_errno(dtp, errno));
 921 
 922         dof->dofh_loadsz = hdr.dofh_loadsz;
 923 
 924         for (i = 0; i < DTRACEOPT_MAX; i++)
 925                 dtp->dt_options[i] = DTRACEOPT_UNSET;
 926 
 927         if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) {
 928                 free(dof);
 929                 return (dt_set_errno(dtp, errno));
 930         }
 931 
 932         for (i = 0; i < dof->dofh_secnum; i++) {
 933                 sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof +
 934                     dof->dofh_secoff + i * dof->dofh_secsize);
 935 
 936                 if (sec->dofs_type != DOF_SECT_OPTDESC)
 937                         continue;
 938 
 939                 break;
 940         }
 941 
 942         for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) {
 943                 dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t)
 944                     ((uintptr_t)dof + sec->dofs_offset + offs);
 945 
 946                 if (opt->dofo_strtab != DOF_SECIDX_NONE)
 947                         continue;
 948 
 949                 if (opt->dofo_option >= DTRACEOPT_MAX)
 950                         continue;
 951 
 952                 dtp->dt_options[opt->dofo_option] = opt->dofo_value;
 953         }
 954 
 955         free(dof);
 956         return (0);
 957 }
 958 
 959 typedef struct dt_option {
 960         const char *o_name;
 961         int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t);
 962         uintptr_t o_option;
 963 } dt_option_t;
 964 
 965 /*
 966  * Compile-time options.
 967  */
 968 static const dt_option_t _dtrace_ctoptions[] = {
 969         { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU },
 970         { "amin", dt_opt_amin },
 971         { "argref", dt_opt_cflags, DTRACE_C_ARGREF },
 972         { "core", dt_opt_core },
 973         { "cpp", dt_opt_cflags, DTRACE_C_CPP },
 974         { "cpphdrs", dt_opt_cpp_hdrs },
 975         { "cpppath", dt_opt_cpp_path },
 976         { "ctypes", dt_opt_ctypes },
 977         { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG },
 978         { "dtypes", dt_opt_dtypes },
 979         { "debug", dt_opt_debug },
 980         { "define", dt_opt_cpp_opts, (uintptr_t)"-D" },
 981         { "droptags", dt_opt_droptags },
 982         { "empty", dt_opt_cflags, DTRACE_C_EMPTY },
 983         { "encoding", dt_opt_encoding },
 984         { "errtags", dt_opt_cflags, DTRACE_C_ETAGS },
 985         { "evaltime", dt_opt_evaltime },
 986         { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" },
 987         { "iregs", dt_opt_iregs },
 988         { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF },
 989         { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF },
 990         { "late", dt_opt_xlate },
 991         { "lazyload", dt_opt_lazyload },
 992         { "ldpath", dt_opt_ld_path },
 993         { "libdir", dt_opt_libdir },
 994         { "linkmode", dt_opt_linkmode },
 995         { "linktype", dt_opt_linktype },
 996         { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
 997         { "pgmax", dt_opt_pgmax },
 998         { "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
 999         { "setenv", dt_opt_setenv, 1 },
1000         { "stdc", dt_opt_stdc },
1001         { "strip", dt_opt_dflags, DTRACE_D_STRIP },
1002         { "syslibdir", dt_opt_syslibdir },
1003         { "tree", dt_opt_tree },
1004         { "tregs", dt_opt_tregs },
1005         { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF },
1006         { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" },
1007         { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF },
1008         { "unsetenv", dt_opt_setenv, 0 },
1009         { "verbose", dt_opt_cflags, DTRACE_C_DIFV },
1010         { "version", dt_opt_version },
1011         { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS },
1012         { NULL }
1013 };
1014 
1015 /*
1016  * Run-time options.
1017  */
1018 static const dt_option_t _dtrace_rtoptions[] = {
1019         { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE },
1020         { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE },
1021         { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY },
1022         { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE },
1023         { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE },
1024         { "cpu", dt_opt_runtime, DTRACEOPT_CPU },
1025         { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE },
1026         { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE },
1027         { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON },
1028         { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES },
1029         { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE },
1030         { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC },
1031         { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE },
1032         { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES },
1033         { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE },
1034         { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE },
1035         { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES },
1036         { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL },
1037         { "zone", dt_opt_zone, DTRACEOPT_ZONE },
1038         { NULL }
1039 };
1040 
1041 /*
1042  * Dynamic run-time options.
1043  */
1044 static const dt_option_t _dtrace_drtoptions[] = {
1045         { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST },
1046         { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK },
1047         { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE },
1048         { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY },
1049         { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS },
1050         { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS },
1051         { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV },
1052         { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM },
1053         { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT },
1054         { "quiet", dt_opt_runtime, DTRACEOPT_QUIET },
1055         { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES },
1056         { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT },
1057         { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE },
1058         { NULL }
1059 };
1060 
1061 int
1062 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val)
1063 {
1064         const dt_option_t *op;
1065 
1066         if (opt == NULL)
1067                 return (dt_set_errno(dtp, EINVAL));
1068 
1069         /*
1070          * We only need to search the run-time options -- it's not legal
1071          * to get the values of compile-time options.
1072          */
1073         for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1074                 if (strcmp(op->o_name, opt) == 0) {
1075                         *val = dtp->dt_options[op->o_option];
1076                         return (0);
1077                 }
1078         }
1079 
1080         for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1081                 if (strcmp(op->o_name, opt) == 0) {
1082                         *val = dtp->dt_options[op->o_option];
1083                         return (0);
1084                 }
1085         }
1086 
1087         return (dt_set_errno(dtp, EDT_BADOPTNAME));
1088 }
1089 
1090 int
1091 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val)
1092 {
1093         const dt_option_t *op;
1094 
1095         if (opt == NULL)
1096                 return (dt_set_errno(dtp, EINVAL));
1097 
1098         for (op = _dtrace_ctoptions; op->o_name != NULL; op++) {
1099                 if (strcmp(op->o_name, opt) == 0)
1100                         return (op->o_func(dtp, val, op->o_option));
1101         }
1102 
1103         for (op = _dtrace_drtoptions; op->o_name != NULL; op++) {
1104                 if (strcmp(op->o_name, opt) == 0)
1105                         return (op->o_func(dtp, val, op->o_option));
1106         }
1107 
1108         for (op = _dtrace_rtoptions; op->o_name != NULL; op++) {
1109                 if (strcmp(op->o_name, opt) == 0) {
1110                         /*
1111                          * Only dynamic run-time options may be set while
1112                          * tracing is active.
1113                          */
1114                         if (dtp->dt_active)
1115                                 return (dt_set_errno(dtp, EDT_ACTIVE));
1116 
1117                         return (op->o_func(dtp, val, op->o_option));
1118                 }
1119         }
1120 
1121         return (dt_set_errno(dtp, EDT_BADOPTNAME));
1122 }