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