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 } 1082