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