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