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 = alloca(hdr.dofh_loadsz); 879 bzero(dof, sizeof (dof_hdr_t)); 880 dof->dofh_loadsz = hdr.dofh_loadsz; 881 882 for (i = 0; i < DTRACEOPT_MAX; i++) 883 dtp->dt_options[i] = DTRACEOPT_UNSET; 884 885 if (dt_ioctl(dtp, DTRACEIOC_DOFGET, dof) == -1) 886 return (dt_set_errno(dtp, errno)); 887 888 for (i = 0; i < dof->dofh_secnum; i++) { 889 sec = (dof_sec_t *)(uintptr_t)((uintptr_t)dof + 890 dof->dofh_secoff + i * dof->dofh_secsize); 891 892 if (sec->dofs_type != DOF_SECT_OPTDESC) 893 continue; 894 895 break; 896 } 897 898 for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { 899 dof_optdesc_t *opt = (dof_optdesc_t *)(uintptr_t) 900 ((uintptr_t)dof + sec->dofs_offset + offs); 901 902 if (opt->dofo_strtab != DOF_SECIDX_NONE) 903 continue; 904 905 if (opt->dofo_option >= DTRACEOPT_MAX) 906 continue; 907 908 dtp->dt_options[opt->dofo_option] = opt->dofo_value; 909 } 910 911 return (0); 912 } 913 914 typedef struct dt_option { 915 const char *o_name; 916 int (*o_func)(dtrace_hdl_t *, const char *, uintptr_t); 917 uintptr_t o_option; 918 } dt_option_t; 919 920 /* 921 * Compile-time options. 922 */ 923 static const dt_option_t _dtrace_ctoptions[] = { 924 { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU }, 925 { "amin", dt_opt_amin }, 926 { "argref", dt_opt_cflags, DTRACE_C_ARGREF }, 927 { "core", dt_opt_core }, 928 { "cpp", dt_opt_cflags, DTRACE_C_CPP }, 929 { "cpphdrs", dt_opt_cpp_hdrs }, 930 { "cpppath", dt_opt_cpp_path }, 931 { "ctypes", dt_opt_ctypes }, 932 { "defaultargs", dt_opt_cflags, DTRACE_C_DEFARG }, 933 { "dtypes", dt_opt_dtypes }, 934 { "debug", dt_opt_debug }, 935 { "define", dt_opt_cpp_opts, (uintptr_t)"-D" }, 936 { "droptags", dt_opt_droptags }, 937 { "empty", dt_opt_cflags, DTRACE_C_EMPTY }, 938 { "encoding", dt_opt_encoding }, 939 { "errtags", dt_opt_cflags, DTRACE_C_ETAGS }, 940 { "evaltime", dt_opt_evaltime }, 941 { "incdir", dt_opt_cpp_opts, (uintptr_t)"-I" }, 942 { "iregs", dt_opt_iregs }, 943 { "kdefs", dt_opt_invcflags, DTRACE_C_KNODEF }, 944 { "knodefs", dt_opt_cflags, DTRACE_C_KNODEF }, 945 { "late", dt_opt_xlate }, 946 { "lazyload", dt_opt_lazyload }, 947 { "ldpath", dt_opt_ld_path }, 948 { "libdir", dt_opt_libdir }, 949 { "linkmode", dt_opt_linkmode }, 950 { "linktype", dt_opt_linktype }, 951 { "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS }, 952 { "pgmax", dt_opt_pgmax }, 953 { "pspec", dt_opt_cflags, DTRACE_C_PSPEC }, 954 { "setenv", dt_opt_setenv, 1 }, 955 { "stdc", dt_opt_stdc }, 956 { "strip", dt_opt_dflags, DTRACE_D_STRIP }, 957 { "syslibdir", dt_opt_syslibdir }, 958 { "tree", dt_opt_tree }, 959 { "tregs", dt_opt_tregs }, 960 { "udefs", dt_opt_invcflags, DTRACE_C_UNODEF }, 961 { "undef", dt_opt_cpp_opts, (uintptr_t)"-U" }, 962 { "unodefs", dt_opt_cflags, DTRACE_C_UNODEF }, 963 { "unsetenv", dt_opt_setenv, 0 }, 964 { "verbose", dt_opt_cflags, DTRACE_C_DIFV }, 965 { "version", dt_opt_version }, 966 { "zdefs", dt_opt_cflags, DTRACE_C_ZDEFS }, 967 { NULL } 968 }; 969 970 /* 971 * Run-time options. 972 */ 973 static const dt_option_t _dtrace_rtoptions[] = { 974 { "aggsize", dt_opt_size, DTRACEOPT_AGGSIZE }, 975 { "bufsize", dt_opt_size, DTRACEOPT_BUFSIZE }, 976 { "bufpolicy", dt_opt_bufpolicy, DTRACEOPT_BUFPOLICY }, 977 { "bufresize", dt_opt_bufresize, DTRACEOPT_BUFRESIZE }, 978 { "cleanrate", dt_opt_rate, DTRACEOPT_CLEANRATE }, 979 { "cpu", dt_opt_runtime, DTRACEOPT_CPU }, 980 { "destructive", dt_opt_runtime, DTRACEOPT_DESTRUCTIVE }, 981 { "dynvarsize", dt_opt_size, DTRACEOPT_DYNVARSIZE }, 982 { "grabanon", dt_opt_runtime, DTRACEOPT_GRABANON }, 983 { "jstackframes", dt_opt_runtime, DTRACEOPT_JSTACKFRAMES }, 984 { "jstackstrsize", dt_opt_size, DTRACEOPT_JSTACKSTRSIZE }, 985 { "nspec", dt_opt_runtime, DTRACEOPT_NSPEC }, 986 { "specsize", dt_opt_size, DTRACEOPT_SPECSIZE }, 987 { "stackframes", dt_opt_runtime, DTRACEOPT_STACKFRAMES }, 988 { "statusrate", dt_opt_rate, DTRACEOPT_STATUSRATE }, 989 { "strsize", dt_opt_strsize, DTRACEOPT_STRSIZE }, 990 { "ustackframes", dt_opt_runtime, DTRACEOPT_USTACKFRAMES }, 991 { "temporal", dt_opt_runtime, DTRACEOPT_TEMPORAL }, 992 { NULL } 993 }; 994 995 /* 996 * Dynamic run-time options. 997 */ 998 static const dt_option_t _dtrace_drtoptions[] = { 999 { "agghist", dt_opt_runtime, DTRACEOPT_AGGHIST }, 1000 { "aggpack", dt_opt_runtime, DTRACEOPT_AGGPACK }, 1001 { "aggrate", dt_opt_rate, DTRACEOPT_AGGRATE }, 1002 { "aggsortkey", dt_opt_runtime, DTRACEOPT_AGGSORTKEY }, 1003 { "aggsortkeypos", dt_opt_runtime, DTRACEOPT_AGGSORTKEYPOS }, 1004 { "aggsortpos", dt_opt_runtime, DTRACEOPT_AGGSORTPOS }, 1005 { "aggsortrev", dt_opt_runtime, DTRACEOPT_AGGSORTREV }, 1006 { "aggzoom", dt_opt_runtime, DTRACEOPT_AGGZOOM }, 1007 { "flowindent", dt_opt_runtime, DTRACEOPT_FLOWINDENT }, 1008 { "quiet", dt_opt_runtime, DTRACEOPT_QUIET }, 1009 { "rawbytes", dt_opt_runtime, DTRACEOPT_RAWBYTES }, 1010 { "stackindent", dt_opt_runtime, DTRACEOPT_STACKINDENT }, 1011 { "switchrate", dt_opt_rate, DTRACEOPT_SWITCHRATE }, 1012 { NULL } 1013 }; 1014 1015 int 1016 dtrace_getopt(dtrace_hdl_t *dtp, const char *opt, dtrace_optval_t *val) 1017 { 1018 const dt_option_t *op; 1019 1020 if (opt == NULL) 1021 return (dt_set_errno(dtp, EINVAL)); 1022 1023 /* 1024 * We only need to search the run-time options -- it's not legal 1025 * to get the values of compile-time options. 1026 */ 1027 for (op = _dtrace_rtoptions; op->o_name != NULL; op++) { 1028 if (strcmp(op->o_name, opt) == 0) { 1029 *val = dtp->dt_options[op->o_option]; 1030 return (0); 1031 } 1032 } 1033 1034 for (op = _dtrace_drtoptions; op->o_name != NULL; op++) { 1035 if (strcmp(op->o_name, opt) == 0) { 1036 *val = dtp->dt_options[op->o_option]; 1037 return (0); 1038 } 1039 } 1040 1041 return (dt_set_errno(dtp, EDT_BADOPTNAME)); 1042 } 1043 1044 int 1045 dtrace_setopt(dtrace_hdl_t *dtp, const char *opt, const char *val) 1046 { 1047 const dt_option_t *op; 1048 1049 if (opt == NULL) 1050 return (dt_set_errno(dtp, EINVAL)); 1051 1052 for (op = _dtrace_ctoptions; op->o_name != NULL; op++) { 1053 if (strcmp(op->o_name, opt) == 0) 1054 return (op->o_func(dtp, val, op->o_option)); 1055 } 1056 1057 for (op = _dtrace_drtoptions; 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_rtoptions; op->o_name != NULL; op++) { 1063 if (strcmp(op->o_name, opt) == 0) { 1064 /* 1065 * Only dynamic run-time options may be set while 1066 * tracing is active. 1067 */ 1068 if (dtp->dt_active) 1069 return (dt_set_errno(dtp, EDT_ACTIVE)); 1070 1071 return (op->o_func(dtp, val, op->o_option)); 1072 } 1073 } 1074 1075 return (dt_set_errno(dtp, EDT_BADOPTNAME)); 1076 } 1077