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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright (c) 2012 by Delphix. All rights reserved. 28 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/wait.h> 34 35 #include <dtrace.h> 36 #include <stdlib.h> 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <strings.h> 41 #include <unistd.h> 42 #include <limits.h> 43 #include <fcntl.h> 44 #include <errno.h> 45 #include <signal.h> 46 #ifdef illumos 47 #include <alloca.h> 48 #endif 49 #include <libgen.h> 50 #ifdef illumos 51 #include <libproc.h> 52 #endif 53 54 typedef struct dtrace_cmd { 55 void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */ 56 dtrace_probespec_t dc_spec; /* probe specifier context */ 57 char *dc_arg; /* argument from main argv */ 58 const char *dc_name; /* name for error messages */ 59 const char *dc_desc; /* desc for error messages */ 60 dtrace_prog_t *dc_prog; /* program compiled from arg */ 61 char dc_ofile[PATH_MAX]; /* derived output file name */ 62 } dtrace_cmd_t; 63 64 #define DMODE_VERS 0 /* display version information and exit (-V) */ 65 #define DMODE_EXEC 1 /* compile program for enabling (-a/e/E) */ 66 #define DMODE_ANON 2 /* compile program for anonymous tracing (-A) */ 67 #define DMODE_LINK 3 /* compile program for linking with ELF (-G) */ 68 #define DMODE_LIST 4 /* compile program and list probes (-l) */ 69 #define DMODE_HEADER 5 /* compile program for headergen (-h) */ 70 71 #define E_SUCCESS 0 72 #define E_ERROR 1 73 #define E_USAGE 2 74 75 static const char DTRACE_OPTSTR[] = 76 "3:6:aAb:Bc:CD:ef:FGhHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z"; 77 78 static char **g_argv; 79 static int g_argc; 80 static char **g_objv; 81 static int g_objc; 82 static dtrace_cmd_t *g_cmdv; 83 static int g_cmdc; 84 static struct ps_prochandle **g_psv; 85 static int g_psc; 86 static int g_pslive; 87 static char *g_pname; 88 static int g_quiet; 89 static int g_flowindent; 90 static int g_intr; 91 static int g_impatient; 92 static int g_newline; 93 static int g_total; 94 static int g_cflags; 95 static int g_oflags; 96 static int g_verbose; 97 static int g_exec = 1; 98 static int g_mode = DMODE_EXEC; 99 static int g_status = E_SUCCESS; 100 static int g_grabanon = 0; 101 static const char *g_ofile = NULL; 102 static FILE *g_ofp; 103 static dtrace_hdl_t *g_dtp; 104 #ifdef illumos 105 static char *g_etcfile = "/etc/system"; 106 static const char *g_etcbegin = "* vvvv Added by DTrace"; 107 static const char *g_etcend = "* ^^^^ Added by DTrace"; 108 109 static const char *g_etc[] = { 110 "*", 111 "* The following forceload directives were added by dtrace(1M) to allow for", 112 "* tracing during boot. If these directives are removed, the system will", 113 "* continue to function, but tracing will not occur during boot as desired.", 114 "* To remove these directives (and this block comment) automatically, run", 115 "* \"dtrace -A\" without additional arguments. See the \"Anonymous Tracing\"", 116 "* chapter of the Solaris Dynamic Tracing Guide for details.", 117 "*", 118 NULL }; 119 #endif 120 121 static int 122 usage(FILE *fp) 123 { 124 static const char predact[] = "[[ predicate ] action ]"; 125 126 (void) fprintf(fp, "Usage: %s [-32|-64] [-aACeFGhHlqSvVwZ] " 127 "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " 128 "[-o output] [-p pid] [-s script] [-U name]\n\t" 129 "[-x opt[=val]] [-X a|c|s|t]\n\n" 130 "\t[-P provider %s]\n" 131 "\t[-m [ provider: ] module %s]\n" 132 "\t[-f [[ provider: ] module: ] func %s]\n" 133 "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" 134 "\t[-i probe-id %s] [ args ... ]\n\n", g_pname, 135 predact, predact, predact, predact, predact); 136 137 (void) fprintf(fp, "\tpredicate -> '/' D-expression '/'\n"); 138 (void) fprintf(fp, "\t action -> '{' D-statements '}'\n"); 139 140 (void) fprintf(fp, "\n" 141 "\t-32 generate 32-bit D programs and ELF files\n" 142 "\t-64 generate 64-bit D programs and ELF files\n\n" 143 "\t-a claim anonymous tracing state\n" 144 "\t-A generate driver.conf(4) directives for anonymous tracing\n" 145 "\t-b set trace buffer size\n" 146 "\t-c run specified command and exit upon its completion\n" 147 "\t-C run cpp(1) preprocessor on script files\n" 148 "\t-D define symbol when invoking preprocessor\n" 149 "\t-e exit after compiling request but prior to enabling probes\n" 150 "\t-f enable or list probes matching the specified function name\n" 151 "\t-F coalesce trace output by function\n" 152 "\t-G generate an ELF file containing embedded dtrace program\n" 153 "\t-h generate a header file with definitions for static probes\n" 154 "\t-H print included files when invoking preprocessor\n" 155 "\t-i enable or list probes matching the specified probe id\n" 156 "\t-I add include directory to preprocessor search path\n" 157 "\t-l list probes matching specified criteria\n" 158 "\t-L add library directory to library search path\n" 159 "\t-m enable or list probes matching the specified module name\n" 160 "\t-n enable or list probes matching the specified probe name\n" 161 "\t-o set output file\n" 162 "\t-p grab specified process-ID and cache its symbol tables\n" 163 "\t-P enable or list probes matching the specified provider name\n" 164 "\t-q set quiet mode (only output explicitly traced data)\n" 165 "\t-s enable or list probes according to the specified D script\n" 166 "\t-S print D compiler intermediate code\n" 167 "\t-U undefine symbol when invoking preprocessor\n" 168 "\t-v set verbose mode (report stability attributes, arguments)\n" 169 "\t-V report DTrace API version\n" 170 "\t-w permit destructive actions\n" 171 "\t-x enable or modify compiler and tracing options\n" 172 "\t-X specify ISO C conformance settings for preprocessor\n" 173 "\t-Z permit probe descriptions that match zero probes\n"); 174 175 return (E_USAGE); 176 } 177 178 static void 179 verror(const char *fmt, va_list ap) 180 { 181 int error = errno; 182 183 (void) fprintf(stderr, "%s: ", g_pname); 184 (void) vfprintf(stderr, fmt, ap); 185 186 if (fmt[strlen(fmt) - 1] != '\n') 187 (void) fprintf(stderr, ": %s\n", strerror(error)); 188 } 189 190 /*PRINTFLIKE1*/ 191 static void 192 fatal(const char *fmt, ...) 193 { 194 va_list ap; 195 196 va_start(ap, fmt); 197 verror(fmt, ap); 198 va_end(ap); 199 200 /* 201 * Close the DTrace handle to ensure that any controlled processes are 202 * correctly restored and continued. 203 */ 204 if (g_dtp) 205 dtrace_close(g_dtp); 206 207 exit(E_ERROR); 208 } 209 210 /*PRINTFLIKE1*/ 211 static void 212 dfatal(const char *fmt, ...) 213 { 214 #if !defined(illumos) && defined(NEED_ERRLOC) 215 char *p_errfile = NULL; 216 int errline = 0; 217 #endif 218 va_list ap; 219 220 va_start(ap, fmt); 221 222 (void) fprintf(stderr, "%s: ", g_pname); 223 if (fmt != NULL) 224 (void) vfprintf(stderr, fmt, ap); 225 226 va_end(ap); 227 228 if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { 229 (void) fprintf(stderr, ": %s\n", 230 dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 231 } else if (fmt == NULL) { 232 (void) fprintf(stderr, "%s\n", 233 dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 234 } 235 #if !defined(illumos) && defined(NEED_ERRLOC) 236 dt_get_errloc(g_dtp, &p_errfile, &errline); 237 if (p_errfile != NULL) 238 printf("File '%s', line %d\n", p_errfile, errline); 239 #endif 240 241 /* 242 * Close the DTrace handle to ensure that any controlled processes are 243 * correctly restored and continued. 244 */ 245 dtrace_close(g_dtp); 246 247 exit(E_ERROR); 248 } 249 250 /*PRINTFLIKE1*/ 251 static void 252 error(const char *fmt, ...) 253 { 254 va_list ap; 255 256 va_start(ap, fmt); 257 verror(fmt, ap); 258 va_end(ap); 259 } 260 261 /*PRINTFLIKE1*/ 262 static void 263 notice(const char *fmt, ...) 264 { 265 va_list ap; 266 267 if (g_quiet) 268 return; /* -q or quiet pragma suppresses notice()s */ 269 270 va_start(ap, fmt); 271 verror(fmt, ap); 272 va_end(ap); 273 } 274 275 /*PRINTFLIKE1*/ 276 static void 277 oprintf(const char *fmt, ...) 278 { 279 va_list ap; 280 int n; 281 282 if (g_ofp == NULL) 283 return; 284 285 va_start(ap, fmt); 286 n = vfprintf(g_ofp, fmt, ap); 287 va_end(ap); 288 289 if (n < 0) { 290 if (errno != EINTR) { 291 fatal("failed to write to %s", 292 g_ofile ? g_ofile : "<stdout>"); 293 } 294 clearerr(g_ofp); 295 } 296 } 297 298 static char ** 299 make_argv(char *s) 300 { 301 const char *ws = "\f\n\r\t\v "; 302 char **argv = malloc(sizeof (char *) * (strlen(s) / 2 + 1)); 303 int argc = 0; 304 char *p = s; 305 306 if (argv == NULL) 307 return (NULL); 308 309 for (p = strtok(s, ws); p != NULL; p = strtok(NULL, ws)) 310 argv[argc++] = p; 311 312 if (argc == 0) 313 argv[argc++] = s; 314 315 argv[argc] = NULL; 316 return (argv); 317 } 318 319 static void 320 dof_prune(const char *fname) 321 { 322 struct stat sbuf; 323 size_t sz, i, j, mark, len; 324 char *buf; 325 int msg = 0, fd; 326 327 if ((fd = open(fname, O_RDONLY)) == -1) { 328 /* 329 * This is okay only if the file doesn't exist at all. 330 */ 331 if (errno != ENOENT) 332 fatal("failed to open %s", fname); 333 return; 334 } 335 336 if (fstat(fd, &sbuf) == -1) 337 fatal("failed to fstat %s", fname); 338 339 if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) 340 fatal("failed to allocate memory for %s", fname); 341 342 if (read(fd, buf, sz) != sz) 343 fatal("failed to read %s", fname); 344 345 buf[sz] = '\0'; 346 (void) close(fd); 347 348 if ((fd = open(fname, O_WRONLY | O_TRUNC)) == -1) 349 fatal("failed to open %s for writing", fname); 350 351 len = strlen("dof-data-"); 352 353 for (mark = 0, i = 0; i < sz; i++) { 354 if (strncmp(&buf[i], "dof-data-", len) != 0) 355 continue; 356 357 /* 358 * This is only a match if it's in the 0th column. 359 */ 360 if (i != 0 && buf[i - 1] != '\n') 361 continue; 362 363 if (msg++ == 0) { 364 error("cleaned up old anonymous " 365 "enabling in %s\n", fname); 366 } 367 368 /* 369 * We have a match. First write out our data up until now. 370 */ 371 if (i != mark) { 372 if (write(fd, &buf[mark], i - mark) != i - mark) 373 fatal("failed to write to %s", fname); 374 } 375 376 /* 377 * Now scan forward until we scan past a newline. 378 */ 379 for (j = i; j < sz && buf[j] != '\n'; j++) 380 continue; 381 382 /* 383 * Reset our mark. 384 */ 385 if ((mark = j + 1) >= sz) 386 break; 387 388 i = j; 389 } 390 391 if (mark < sz) { 392 if (write(fd, &buf[mark], sz - mark) != sz - mark) 393 fatal("failed to write to %s", fname); 394 } 395 396 (void) close(fd); 397 free(buf); 398 } 399 400 #ifdef illumos 401 static void 402 etcsystem_prune(void) 403 { 404 struct stat sbuf; 405 size_t sz; 406 char *buf, *start, *end; 407 int fd; 408 char *fname = g_etcfile, *tmpname; 409 410 if ((fd = open(fname, O_RDONLY)) == -1) 411 fatal("failed to open %s", fname); 412 413 if (fstat(fd, &sbuf) == -1) 414 fatal("failed to fstat %s", fname); 415 416 if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) 417 fatal("failed to allocate memory for %s", fname); 418 419 if (read(fd, buf, sz) != sz) 420 fatal("failed to read %s", fname); 421 422 buf[sz] = '\0'; 423 (void) close(fd); 424 425 if ((start = strstr(buf, g_etcbegin)) == NULL) 426 goto out; 427 428 if (strlen(buf) != sz) { 429 fatal("embedded nul byte in %s; manual repair of %s " 430 "required\n", fname, fname); 431 } 432 433 if (strstr(start + 1, g_etcbegin) != NULL) { 434 fatal("multiple start sentinels in %s; manual repair of %s " 435 "required\n", fname, fname); 436 } 437 438 if ((end = strstr(buf, g_etcend)) == NULL) { 439 fatal("missing end sentinel in %s; manual repair of %s " 440 "required\n", fname, fname); 441 } 442 443 if (start > end) { 444 fatal("end sentinel preceeds start sentinel in %s; manual " 445 "repair of %s required\n", fname, fname); 446 } 447 448 end += strlen(g_etcend) + 1; 449 bcopy(end, start, strlen(end) + 1); 450 451 tmpname = alloca(sz = strlen(fname) + 80); 452 (void) snprintf(tmpname, sz, "%s.dtrace.%d", fname, getpid()); 453 454 if ((fd = open(tmpname, 455 O_WRONLY | O_CREAT | O_EXCL, sbuf.st_mode)) == -1) 456 fatal("failed to create %s", tmpname); 457 458 if (write(fd, buf, strlen(buf)) < strlen(buf)) { 459 (void) unlink(tmpname); 460 fatal("failed to write to %s", tmpname); 461 } 462 463 (void) close(fd); 464 465 if (chown(tmpname, sbuf.st_uid, sbuf.st_gid) != 0) { 466 (void) unlink(tmpname); 467 fatal("failed to chown(2) %s to uid %d, gid %d", tmpname, 468 (int)sbuf.st_uid, (int)sbuf.st_gid); 469 } 470 471 if (rename(tmpname, fname) == -1) 472 fatal("rename of %s to %s failed", tmpname, fname); 473 474 error("cleaned up forceload directives in %s\n", fname); 475 out: 476 free(buf); 477 } 478 479 static void 480 etcsystem_add(void) 481 { 482 const char *mods[20]; 483 int nmods, line; 484 485 if ((g_ofp = fopen(g_ofile = g_etcfile, "a")) == NULL) 486 fatal("failed to open output file '%s'", g_ofile); 487 488 oprintf("%s\n", g_etcbegin); 489 490 for (line = 0; g_etc[line] != NULL; line++) 491 oprintf("%s\n", g_etc[line]); 492 493 nmods = dtrace_provider_modules(g_dtp, mods, 494 sizeof (mods) / sizeof (char *) - 1); 495 496 if (nmods >= sizeof (mods) / sizeof (char *)) 497 fatal("unexpectedly large number of modules!"); 498 499 mods[nmods++] = "dtrace"; 500 501 for (line = 0; line < nmods; line++) 502 oprintf("forceload: drv/%s\n", mods[line]); 503 504 oprintf("%s\n", g_etcend); 505 506 if (fclose(g_ofp) == EOF) 507 fatal("failed to close output file '%s'", g_ofile); 508 509 error("added forceload directives to %s\n", g_ofile); 510 } 511 #endif /* illumos */ 512 513 static void 514 print_probe_info(const dtrace_probeinfo_t *p) 515 { 516 char buf[BUFSIZ]; 517 char *user; 518 int i; 519 520 oprintf("\n\tProbe Description Attributes\n"); 521 522 oprintf("\t\tIdentifier Names: %s\n", 523 dtrace_stability_name(p->dtp_attr.dtat_name)); 524 oprintf("\t\tData Semantics: %s\n", 525 dtrace_stability_name(p->dtp_attr.dtat_data)); 526 oprintf("\t\tDependency Class: %s\n", 527 dtrace_class_name(p->dtp_attr.dtat_class)); 528 529 oprintf("\n\tArgument Attributes\n"); 530 531 oprintf("\t\tIdentifier Names: %s\n", 532 dtrace_stability_name(p->dtp_arga.dtat_name)); 533 oprintf("\t\tData Semantics: %s\n", 534 dtrace_stability_name(p->dtp_arga.dtat_data)); 535 oprintf("\t\tDependency Class: %s\n", 536 dtrace_class_name(p->dtp_arga.dtat_class)); 537 538 oprintf("\n\tArgument Types\n"); 539 540 for (i = 0; i < p->dtp_argc; i++) { 541 if (p->dtp_argv[i].dtt_flags & DTT_FL_USER) 542 user = "userland "; 543 else 544 user = ""; 545 if (ctf_type_name(p->dtp_argv[i].dtt_ctfp, 546 p->dtp_argv[i].dtt_type, buf, sizeof (buf)) == NULL) 547 (void) strlcpy(buf, "(unknown)", sizeof (buf)); 548 oprintf("\t\targs[%d]: %s%s\n", i, user, buf); 549 } 550 551 if (p->dtp_argc == 0) 552 oprintf("\t\tNone\n"); 553 554 oprintf("\n"); 555 } 556 557 /*ARGSUSED*/ 558 static int 559 info_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 560 dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) 561 { 562 dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 563 dtrace_probedesc_t *pdp = &edp->dted_probe; 564 dtrace_probeinfo_t p; 565 566 if (edp == *last) 567 return (0); 568 569 oprintf("\n%s:%s:%s:%s\n", 570 pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); 571 572 if (dtrace_probe_info(dtp, pdp, &p) == 0) 573 print_probe_info(&p); 574 575 *last = edp; 576 return (0); 577 } 578 579 /* 580 * Execute the specified program by enabling the corresponding instrumentation. 581 * If -e has been specified, we get the program info but do not enable it. If 582 * -v has been specified, we print a stability report for the program. 583 */ 584 static void 585 exec_prog(const dtrace_cmd_t *dcp) 586 { 587 dtrace_ecbdesc_t *last = NULL; 588 dtrace_proginfo_t dpi; 589 590 if (!g_exec) { 591 dtrace_program_info(g_dtp, dcp->dc_prog, &dpi); 592 } else if (dtrace_program_exec(g_dtp, dcp->dc_prog, &dpi) == -1) { 593 dfatal("failed to enable '%s'", dcp->dc_name); 594 } else { 595 notice("%s '%s' matched %u probe%s\n", 596 dcp->dc_desc, dcp->dc_name, 597 dpi.dpi_matches, dpi.dpi_matches == 1 ? "" : "s"); 598 } 599 600 if (g_verbose) { 601 oprintf("\nStability attributes for %s %s:\n", 602 dcp->dc_desc, dcp->dc_name); 603 604 oprintf("\n\tMinimum Probe Description Attributes\n"); 605 oprintf("\t\tIdentifier Names: %s\n", 606 dtrace_stability_name(dpi.dpi_descattr.dtat_name)); 607 oprintf("\t\tData Semantics: %s\n", 608 dtrace_stability_name(dpi.dpi_descattr.dtat_data)); 609 oprintf("\t\tDependency Class: %s\n", 610 dtrace_class_name(dpi.dpi_descattr.dtat_class)); 611 612 oprintf("\n\tMinimum Statement Attributes\n"); 613 614 oprintf("\t\tIdentifier Names: %s\n", 615 dtrace_stability_name(dpi.dpi_stmtattr.dtat_name)); 616 oprintf("\t\tData Semantics: %s\n", 617 dtrace_stability_name(dpi.dpi_stmtattr.dtat_data)); 618 oprintf("\t\tDependency Class: %s\n", 619 dtrace_class_name(dpi.dpi_stmtattr.dtat_class)); 620 621 if (!g_exec) { 622 (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, 623 (dtrace_stmt_f *)info_stmt, &last); 624 } else 625 oprintf("\n"); 626 } 627 628 g_total += dpi.dpi_matches; 629 } 630 631 /* 632 * Print out the specified DOF buffer as a set of ASCII bytes appropriate for 633 * storing in a driver.conf(4) file associated with the dtrace driver. 634 */ 635 static void 636 anon_prog(const dtrace_cmd_t *dcp, dof_hdr_t *dof, int n) 637 { 638 const uchar_t *p, *q; 639 640 if (dof == NULL) 641 dfatal("failed to create DOF image for '%s'", dcp->dc_name); 642 643 p = (uchar_t *)dof; 644 q = p + dof->dofh_loadsz; 645 646 #ifdef illumos 647 oprintf("dof-data-%d=0x%x", n, *p++); 648 649 while (p < q) 650 oprintf(",0x%x", *p++); 651 652 oprintf(";\n"); 653 #else 654 /* 655 * On FreeBSD, the DOF data is handled as a kernel environment (kenv) 656 * string. We use two hex characters per DOF byte. 657 */ 658 oprintf("dof-data-%d=%02x", n, *p++); 659 660 while (p < q) 661 oprintf("%02x", *p++); 662 663 oprintf("\n"); 664 #endif 665 666 dtrace_dof_destroy(g_dtp, dof); 667 } 668 669 /* 670 * Link the specified D program in DOF form into an ELF file for use in either 671 * helpers, userland provider definitions, or both. If -o was specified, that 672 * path is used as the output file name. If -o wasn't specified and the input 673 * program is from a script whose name is %.d, use basename(%.o) as the output 674 * file name. Otherwise we use "d.out" as the default output file name. 675 */ 676 static void 677 link_prog(dtrace_cmd_t *dcp) 678 { 679 char *p; 680 681 if (g_cmdc == 1 && g_ofile != NULL) { 682 (void) strlcpy(dcp->dc_ofile, g_ofile, sizeof (dcp->dc_ofile)); 683 } else if ((p = strrchr(dcp->dc_arg, '.')) != NULL && 684 strcmp(p, ".d") == 0) { 685 p[0] = '\0'; /* strip .d suffix */ 686 (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 687 "%s.o", basename(dcp->dc_arg)); 688 } else if (g_cmdc > 1) { 689 (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 690 "d.out.%td", dcp - g_cmdv); 691 } else { 692 (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 693 "d.out"); 694 } 695 696 if (dtrace_program_link(g_dtp, dcp->dc_prog, DTRACE_D_PROBES, 697 dcp->dc_ofile, g_objc, g_objv) != 0) 698 dfatal("failed to link %s %s", dcp->dc_desc, dcp->dc_name); 699 } 700 701 /*ARGSUSED*/ 702 static int 703 list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) 704 { 705 dtrace_probeinfo_t p; 706 707 oprintf("%5d %10s %17s %33s %s\n", pdp->dtpd_id, 708 pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); 709 710 if (g_verbose && dtrace_probe_info(dtp, pdp, &p) == 0) 711 print_probe_info(&p); 712 713 if (g_intr != 0) 714 return (1); 715 716 return (0); 717 } 718 719 /*ARGSUSED*/ 720 static int 721 list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 722 dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) 723 { 724 dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 725 726 if (edp == *last) 727 return (0); 728 729 if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) { 730 error("failed to match %s:%s:%s:%s: %s\n", 731 edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, 732 edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name, 733 dtrace_errmsg(dtp, dtrace_errno(dtp))); 734 } 735 736 *last = edp; 737 return (0); 738 } 739 740 /* 741 * List the probes corresponding to the specified program by iterating over 742 * each statement and then matching probes to the statement probe descriptions. 743 */ 744 static void 745 list_prog(const dtrace_cmd_t *dcp) 746 { 747 dtrace_ecbdesc_t *last = NULL; 748 749 (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, 750 (dtrace_stmt_f *)list_stmt, &last); 751 } 752 753 static void 754 compile_file(dtrace_cmd_t *dcp) 755 { 756 char *arg0; 757 FILE *fp; 758 759 if ((fp = fopen(dcp->dc_arg, "r")) == NULL) 760 fatal("failed to open %s", dcp->dc_arg); 761 762 arg0 = g_argv[0]; 763 g_argv[0] = dcp->dc_arg; 764 765 if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp, 766 g_cflags, g_argc, g_argv)) == NULL) 767 dfatal("failed to compile script %s", dcp->dc_arg); 768 769 g_argv[0] = arg0; 770 (void) fclose(fp); 771 772 dcp->dc_desc = "script"; 773 dcp->dc_name = dcp->dc_arg; 774 } 775 776 static void 777 compile_str(dtrace_cmd_t *dcp) 778 { 779 char *p; 780 781 if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg, 782 dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL) 783 dfatal("invalid probe specifier %s", dcp->dc_arg); 784 785 if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL) 786 *p = '\0'; /* crop name for reporting */ 787 788 dcp->dc_desc = "description"; 789 dcp->dc_name = dcp->dc_arg; 790 } 791 792 /*ARGSUSED*/ 793 static void 794 prochandler(struct ps_prochandle *P, const char *msg, void *arg) 795 { 796 #ifdef illumos 797 const psinfo_t *prp = Ppsinfo(P); 798 int pid = Pstatus(P)->pr_pid; 799 char name[SIG2STR_MAX]; 800 #else 801 int wstatus = proc_getwstat(P); 802 int pid = proc_getpid(P); 803 #endif 804 805 if (msg != NULL) { 806 notice("pid %d: %s\n", pid, msg); 807 return; 808 } 809 810 #ifdef illumos 811 switch (Pstate(P)) { 812 #else 813 switch (proc_state(P)) { 814 #endif 815 case PS_UNDEAD: 816 #ifdef illumos 817 /* 818 * Ideally we would like to always report pr_wstat here, but it 819 * isn't possible given current /proc semantics. If we grabbed 820 * the process, Ppsinfo() will either fail or return a zeroed 821 * psinfo_t depending on how far the parent is in reaping it. 822 * When /proc provides a stable pr_wstat in the status file, 823 * this code can be improved by examining this new pr_wstat. 824 */ 825 if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 826 notice("pid %d terminated by %s\n", pid, 827 proc_signame(WTERMSIG(prp->pr_wstat), 828 name, sizeof (name))); 829 #else 830 if (WIFSIGNALED(wstatus)) { 831 notice("pid %d terminated by %d\n", pid, 832 WTERMSIG(wstatus)); 833 #endif 834 #ifdef illumos 835 } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { 836 notice("pid %d exited with status %d\n", 837 pid, WEXITSTATUS(prp->pr_wstat)); 838 #else 839 } else if (WEXITSTATUS(wstatus) != 0) { 840 notice("pid %d exited with status %d\n", 841 pid, WEXITSTATUS(wstatus)); 842 #endif 843 } else { 844 notice("pid %d has exited\n", pid); 845 } 846 g_pslive--; 847 break; 848 849 case PS_LOST: 850 notice("pid %d exec'd a set-id or unobservable program\n", pid); 851 g_pslive--; 852 break; 853 } 854 } 855 856 /*ARGSUSED*/ 857 static int 858 errhandler(const dtrace_errdata_t *data, void *arg) 859 { 860 error(data->dteda_msg); 861 return (DTRACE_HANDLE_OK); 862 } 863 864 /*ARGSUSED*/ 865 static int 866 drophandler(const dtrace_dropdata_t *data, void *arg) 867 { 868 error(data->dtdda_msg); 869 return (DTRACE_HANDLE_OK); 870 } 871 872 /*ARGSUSED*/ 873 static int 874 setopthandler(const dtrace_setoptdata_t *data, void *arg) 875 { 876 if (strcmp(data->dtsda_option, "quiet") == 0) 877 g_quiet = data->dtsda_newval != DTRACEOPT_UNSET; 878 879 if (strcmp(data->dtsda_option, "flowindent") == 0) 880 g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET; 881 882 return (DTRACE_HANDLE_OK); 883 } 884 885 #define BUFDUMPHDR(hdr) \ 886 (void) printf("%s: %s%s\n", g_pname, hdr, strlen(hdr) > 0 ? ":" : ""); 887 888 #define BUFDUMPSTR(ptr, field) \ 889 (void) printf("%s: %20s => ", g_pname, #field); \ 890 if ((ptr)->field != NULL) { \ 891 const char *c = (ptr)->field; \ 892 (void) printf("\""); \ 893 do { \ 894 if (*c == '\n') { \ 895 (void) printf("\\n"); \ 896 continue; \ 897 } \ 898 \ 899 (void) printf("%c", *c); \ 900 } while (*c++ != '\0'); \ 901 (void) printf("\"\n"); \ 902 } else { \ 903 (void) printf("<NULL>\n"); \ 904 } 905 906 #define BUFDUMPASSTR(ptr, field, str) \ 907 (void) printf("%s: %20s => %s\n", g_pname, #field, str); 908 909 #define BUFDUMP(ptr, field) \ 910 (void) printf("%s: %20s => %lld\n", g_pname, #field, \ 911 (long long)(ptr)->field); 912 913 #define BUFDUMPPTR(ptr, field) \ 914 (void) printf("%s: %20s => %s\n", g_pname, #field, \ 915 (ptr)->field != NULL ? "<non-NULL>" : "<NULL>"); 916 917 /*ARGSUSED*/ 918 static int 919 bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 920 { 921 const dtrace_aggdata_t *agg = bufdata->dtbda_aggdata; 922 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 923 const dtrace_probedesc_t *pd; 924 uint32_t flags = bufdata->dtbda_flags; 925 char buf[512], *c = buf, *end = c + sizeof (buf); 926 int i, printed; 927 928 struct { 929 const char *name; 930 uint32_t value; 931 } flagnames[] = { 932 { "AGGVAL", DTRACE_BUFDATA_AGGVAL }, 933 { "AGGKEY", DTRACE_BUFDATA_AGGKEY }, 934 { "AGGFORMAT", DTRACE_BUFDATA_AGGFORMAT }, 935 { "AGGLAST", DTRACE_BUFDATA_AGGLAST }, 936 { "???", UINT32_MAX }, 937 { NULL } 938 }; 939 940 if (bufdata->dtbda_probe != NULL) { 941 pd = bufdata->dtbda_probe->dtpda_pdesc; 942 } else if (agg != NULL) { 943 pd = agg->dtada_pdesc; 944 } else { 945 pd = NULL; 946 } 947 948 BUFDUMPHDR(">>> Called buffer handler"); 949 BUFDUMPHDR(""); 950 951 BUFDUMPHDR(" dtrace_bufdata"); 952 BUFDUMPSTR(bufdata, dtbda_buffered); 953 BUFDUMPPTR(bufdata, dtbda_probe); 954 BUFDUMPPTR(bufdata, dtbda_aggdata); 955 BUFDUMPPTR(bufdata, dtbda_recdesc); 956 957 (void) snprintf(c, end - c, "0x%x ", bufdata->dtbda_flags); 958 c += strlen(c); 959 960 for (i = 0, printed = 0; flagnames[i].name != NULL; i++) { 961 if (!(flags & flagnames[i].value)) 962 continue; 963 964 (void) snprintf(c, end - c, 965 "%s%s", printed++ ? " | " : "(", flagnames[i].name); 966 c += strlen(c); 967 flags &= ~flagnames[i].value; 968 } 969 970 if (printed) 971 (void) snprintf(c, end - c, ")"); 972 973 BUFDUMPASSTR(bufdata, dtbda_flags, buf); 974 BUFDUMPHDR(""); 975 976 if (pd != NULL) { 977 BUFDUMPHDR(" dtrace_probedesc"); 978 BUFDUMPSTR(pd, dtpd_provider); 979 BUFDUMPSTR(pd, dtpd_mod); 980 BUFDUMPSTR(pd, dtpd_func); 981 BUFDUMPSTR(pd, dtpd_name); 982 BUFDUMPHDR(""); 983 } 984 985 if (rec != NULL) { 986 BUFDUMPHDR(" dtrace_recdesc"); 987 BUFDUMP(rec, dtrd_action); 988 BUFDUMP(rec, dtrd_size); 989 990 if (agg != NULL) { 991 uint8_t *data; 992 int lim = rec->dtrd_size; 993 994 (void) sprintf(buf, "%d (data: ", rec->dtrd_offset); 995 c = buf + strlen(buf); 996 997 if (lim > sizeof (uint64_t)) 998 lim = sizeof (uint64_t); 999 1000 data = (uint8_t *)agg->dtada_data + rec->dtrd_offset; 1001 1002 for (i = 0; i < lim; i++) { 1003 (void) snprintf(c, end - c, "%s%02x", 1004 i == 0 ? "" : " ", *data++); 1005 c += strlen(c); 1006 } 1007 1008 (void) snprintf(c, end - c, 1009 "%s)", lim < rec->dtrd_size ? " ..." : ""); 1010 BUFDUMPASSTR(rec, dtrd_offset, buf); 1011 } else { 1012 BUFDUMP(rec, dtrd_offset); 1013 } 1014 1015 BUFDUMPHDR(""); 1016 } 1017 1018 if (agg != NULL) { 1019 dtrace_aggdesc_t *desc = agg->dtada_desc; 1020 1021 BUFDUMPHDR(" dtrace_aggdesc"); 1022 BUFDUMPSTR(desc, dtagd_name); 1023 BUFDUMP(desc, dtagd_varid); 1024 BUFDUMP(desc, dtagd_id); 1025 BUFDUMP(desc, dtagd_nrecs); 1026 BUFDUMPHDR(""); 1027 } 1028 1029 return (DTRACE_HANDLE_OK); 1030 } 1031 1032 /*ARGSUSED*/ 1033 static int 1034 chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) 1035 { 1036 dtrace_actkind_t act; 1037 uintptr_t addr; 1038 1039 if (rec == NULL) { 1040 /* 1041 * We have processed the final record; output the newline if 1042 * we're not in quiet mode. 1043 */ 1044 if (!g_quiet) 1045 oprintf("\n"); 1046 1047 return (DTRACE_CONSUME_NEXT); 1048 } 1049 1050 act = rec->dtrd_action; 1051 addr = (uintptr_t)data->dtpda_data; 1052 1053 if (act == DTRACEACT_EXIT) { 1054 g_status = *((uint32_t *)addr); 1055 return (DTRACE_CONSUME_NEXT); 1056 } 1057 1058 return (DTRACE_CONSUME_THIS); 1059 } 1060 1061 /*ARGSUSED*/ 1062 static int 1063 chew(const dtrace_probedata_t *data, void *arg) 1064 { 1065 dtrace_probedesc_t *pd = data->dtpda_pdesc; 1066 processorid_t cpu = data->dtpda_cpu; 1067 static int heading; 1068 1069 if (g_impatient) { 1070 g_newline = 0; 1071 return (DTRACE_CONSUME_ABORT); 1072 } 1073 1074 if (heading == 0) { 1075 if (!g_flowindent) { 1076 if (!g_quiet) { 1077 oprintf("%3s %6s %32s\n", 1078 "CPU", "ID", "FUNCTION:NAME"); 1079 } 1080 } else { 1081 oprintf("%3s %-41s\n", "CPU", "FUNCTION"); 1082 } 1083 heading = 1; 1084 } 1085 1086 if (!g_flowindent) { 1087 if (!g_quiet) { 1088 char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; 1089 1090 (void) snprintf(name, sizeof (name), "%s:%s", 1091 pd->dtpd_func, pd->dtpd_name); 1092 1093 oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name); 1094 } 1095 } else { 1096 int indent = data->dtpda_indent; 1097 char *name; 1098 size_t len; 1099 1100 if (data->dtpda_flow == DTRACEFLOW_NONE) { 1101 len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5; 1102 name = alloca(len); 1103 (void) snprintf(name, len, "%*s%s%s:%s", indent, "", 1104 data->dtpda_prefix, pd->dtpd_func, 1105 pd->dtpd_name); 1106 } else { 1107 len = indent + DTRACE_FUNCNAMELEN + 5; 1108 name = alloca(len); 1109 (void) snprintf(name, len, "%*s%s%s", indent, "", 1110 data->dtpda_prefix, pd->dtpd_func); 1111 } 1112 1113 oprintf("%3d %-41s ", cpu, name); 1114 } 1115 1116 return (DTRACE_CONSUME_THIS); 1117 } 1118 1119 static void 1120 go(void) 1121 { 1122 int i; 1123 1124 struct { 1125 char *name; 1126 char *optname; 1127 dtrace_optval_t val; 1128 } bufs[] = { 1129 { "buffer size", "bufsize" }, 1130 { "aggregation size", "aggsize" }, 1131 { "speculation size", "specsize" }, 1132 { "dynamic variable size", "dynvarsize" }, 1133 { NULL } 1134 }, rates[] = { 1135 { "cleaning rate", "cleanrate" }, 1136 { "status rate", "statusrate" }, 1137 { NULL } 1138 }; 1139 1140 for (i = 0; bufs[i].name != NULL; i++) { 1141 if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1) 1142 fatal("couldn't get option %s", bufs[i].optname); 1143 } 1144 1145 for (i = 0; rates[i].name != NULL; i++) { 1146 if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1) 1147 fatal("couldn't get option %s", rates[i].optname); 1148 } 1149 1150 if (dtrace_go(g_dtp) == -1) 1151 dfatal("could not enable tracing"); 1152 1153 for (i = 0; bufs[i].name != NULL; i++) { 1154 dtrace_optval_t j = 0, mul = 10; 1155 dtrace_optval_t nsize; 1156 1157 if (bufs[i].val == DTRACEOPT_UNSET) 1158 continue; 1159 1160 (void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize); 1161 1162 if (nsize == DTRACEOPT_UNSET || nsize == 0) 1163 continue; 1164 1165 if (nsize >= bufs[i].val - sizeof (uint64_t)) 1166 continue; 1167 1168 for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10) 1169 continue; 1170 1171 if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) { 1172 error("%s lowered to %lld%c\n", bufs[i].name, 1173 (long long)nsize >> (mul - 10), " kmgtpe"[j]); 1174 } else { 1175 error("%s lowered to %lld bytes\n", bufs[i].name, 1176 (long long)nsize); 1177 } 1178 } 1179 1180 for (i = 0; rates[i].name != NULL; i++) { 1181 dtrace_optval_t nval; 1182 char *dir; 1183 1184 if (rates[i].val == DTRACEOPT_UNSET) 1185 continue; 1186 1187 (void) dtrace_getopt(g_dtp, rates[i].optname, &nval); 1188 1189 if (nval == DTRACEOPT_UNSET || nval == 0) 1190 continue; 1191 1192 if (rates[i].val == nval) 1193 continue; 1194 1195 dir = nval > rates[i].val ? "reduced" : "increased"; 1196 1197 if (nval <= NANOSEC && (NANOSEC % nval) == 0) { 1198 error("%s %s to %lld hz\n", rates[i].name, dir, 1199 (long long)NANOSEC / (long long)nval); 1200 continue; 1201 } 1202 1203 if ((nval % NANOSEC) == 0) { 1204 error("%s %s to once every %lld seconds\n", 1205 rates[i].name, dir, 1206 (long long)nval / (long long)NANOSEC); 1207 continue; 1208 } 1209 1210 error("%s %s to once every %lld nanoseconds\n", 1211 rates[i].name, dir, (long long)nval); 1212 } 1213 } 1214 1215 /*ARGSUSED*/ 1216 static void 1217 intr(int signo) 1218 { 1219 if (!g_intr) 1220 g_newline = 1; 1221 1222 if (g_intr++) 1223 g_impatient = 1; 1224 } 1225 1226 static void 1227 installsighands(void) 1228 { 1229 struct sigaction act, oact; 1230 1231 (void) sigemptyset(&act.sa_mask); 1232 act.sa_flags = 0; 1233 act.sa_handler = intr; 1234 1235 if (sigaction(SIGINT, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1236 (void) sigaction(SIGINT, &act, NULL); 1237 1238 if (sigaction(SIGTERM, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1239 (void) sigaction(SIGTERM, &act, NULL); 1240 1241 #ifndef illumos 1242 if (sigaction(SIGPIPE, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1243 (void) sigaction(SIGPIPE, &act, NULL); 1244 1245 if (sigaction(SIGUSR1, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1246 (void) sigaction(SIGUSR1, &act, NULL); 1247 #endif 1248 } 1249 1250 int 1251 main(int argc, char *argv[]) 1252 { 1253 dtrace_bufdesc_t buf; 1254 dtrace_status_t status[2]; 1255 dtrace_optval_t opt; 1256 dtrace_cmd_t *dcp; 1257 1258 g_ofp = stdout; 1259 int done = 0, mode = 0; 1260 int err, i, c; 1261 char *p, **v; 1262 struct ps_prochandle *P; 1263 pid_t pid; 1264 1265 g_pname = basename(argv[0]); 1266 1267 if (argc == 1) 1268 return (usage(stderr)); 1269 1270 if ((g_argv = malloc(sizeof (char *) * argc)) == NULL || 1271 (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL || 1272 (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL) 1273 fatal("failed to allocate memory for arguments"); 1274 1275 g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */ 1276 argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ 1277 1278 bzero(status, sizeof (status)); 1279 bzero(&buf, sizeof (buf)); 1280 1281 /* 1282 * Make an initial pass through argv[] processing any arguments that 1283 * affect our behavior mode (g_mode) and flags used for dtrace_open(). 1284 * We also accumulate arguments that are not affiliated with getopt 1285 * options into g_argv[], and abort if any invalid options are found. 1286 */ 1287 for (optind = 1; optind < argc; optind++) { 1288 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1289 switch (c) { 1290 case '3': 1291 if (strcmp(optarg, "2") != 0) { 1292 (void) fprintf(stderr, 1293 "%s: illegal option -- 3%s\n", 1294 argv[0], optarg); 1295 return (usage(stderr)); 1296 } 1297 g_oflags &= ~DTRACE_O_LP64; 1298 g_oflags |= DTRACE_O_ILP32; 1299 break; 1300 1301 case '6': 1302 if (strcmp(optarg, "4") != 0) { 1303 (void) fprintf(stderr, 1304 "%s: illegal option -- 6%s\n", 1305 argv[0], optarg); 1306 return (usage(stderr)); 1307 } 1308 g_oflags &= ~DTRACE_O_ILP32; 1309 g_oflags |= DTRACE_O_LP64; 1310 break; 1311 1312 case 'a': 1313 g_grabanon++; /* also checked in pass 2 below */ 1314 break; 1315 1316 case 'A': 1317 g_mode = DMODE_ANON; 1318 g_exec = 0; 1319 mode++; 1320 break; 1321 1322 case 'e': 1323 g_exec = 0; 1324 done = 1; 1325 break; 1326 1327 case 'h': 1328 g_mode = DMODE_HEADER; 1329 g_oflags |= DTRACE_O_NODEV; 1330 g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */ 1331 g_exec = 0; 1332 mode++; 1333 break; 1334 1335 case 'G': 1336 g_mode = DMODE_LINK; 1337 g_oflags |= DTRACE_O_NODEV; 1338 g_cflags |= DTRACE_C_ZDEFS; /* -G implies -Z */ 1339 g_exec = 0; 1340 mode++; 1341 break; 1342 1343 case 'l': 1344 g_mode = DMODE_LIST; 1345 g_cflags |= DTRACE_C_ZDEFS; /* -l implies -Z */ 1346 mode++; 1347 break; 1348 1349 case 'V': 1350 g_mode = DMODE_VERS; 1351 mode++; 1352 break; 1353 1354 default: 1355 if (strchr(DTRACE_OPTSTR, c) == NULL) 1356 return (usage(stderr)); 1357 } 1358 } 1359 1360 if (optind < argc) 1361 g_argv[g_argc++] = argv[optind]; 1362 } 1363 1364 if (mode > 1) { 1365 (void) fprintf(stderr, "%s: only one of the [-AGhlV] options " 1366 "can be specified at a time\n", g_pname); 1367 return (E_USAGE); 1368 } 1369 1370 if (g_mode == DMODE_VERS) 1371 return (printf("%s: %s\n", g_pname, _dtrace_version) <= 0); 1372 1373 /* 1374 * If we're in linker mode and the data model hasn't been specified, 1375 * we try to guess the appropriate setting by examining the object 1376 * files. We ignore certain errors since we'll catch them later when 1377 * we actually process the object files. 1378 */ 1379 if (g_mode == DMODE_LINK && 1380 (g_oflags & (DTRACE_O_ILP32 | DTRACE_O_LP64)) == 0 && 1381 elf_version(EV_CURRENT) != EV_NONE) { 1382 int fd; 1383 Elf *elf; 1384 GElf_Ehdr ehdr; 1385 1386 for (i = 1; i < g_argc; i++) { 1387 if ((fd = open64(g_argv[i], O_RDONLY)) == -1) 1388 break; 1389 1390 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 1391 (void) close(fd); 1392 break; 1393 } 1394 1395 if (elf_kind(elf) != ELF_K_ELF || 1396 gelf_getehdr(elf, &ehdr) == NULL) { 1397 (void) close(fd); 1398 (void) elf_end(elf); 1399 break; 1400 } 1401 1402 (void) close(fd); 1403 (void) elf_end(elf); 1404 1405 if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 1406 if (g_oflags & DTRACE_O_ILP32) { 1407 fatal("can't mix 32-bit and 64-bit " 1408 "object files\n"); 1409 } 1410 g_oflags |= DTRACE_O_LP64; 1411 } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1412 if (g_oflags & DTRACE_O_LP64) { 1413 fatal("can't mix 32-bit and 64-bit " 1414 "object files\n"); 1415 } 1416 g_oflags |= DTRACE_O_ILP32; 1417 } else { 1418 break; 1419 } 1420 } 1421 } 1422 1423 /* 1424 * Open libdtrace. If we are not actually going to be enabling any 1425 * instrumentation attempt to reopen libdtrace using DTRACE_O_NODEV. 1426 */ 1427 while ((g_dtp = dtrace_open(DTRACE_VERSION, g_oflags, &err)) == NULL) { 1428 if (!(g_oflags & DTRACE_O_NODEV) && !g_exec && !g_grabanon) { 1429 g_oflags |= DTRACE_O_NODEV; 1430 continue; 1431 } 1432 1433 fatal("failed to initialize dtrace: %s\n", 1434 dtrace_errmsg(NULL, err)); 1435 } 1436 1437 #if defined(__i386__) 1438 /* XXX The 32-bit seems to need more buffer space by default -sson */ 1439 (void) dtrace_setopt(g_dtp, "bufsize", "12m"); 1440 (void) dtrace_setopt(g_dtp, "aggsize", "12m"); 1441 #else 1442 (void) dtrace_setopt(g_dtp, "bufsize", "4m"); 1443 (void) dtrace_setopt(g_dtp, "aggsize", "4m"); 1444 #endif 1445 (void) dtrace_setopt(g_dtp, "temporal", "yes"); 1446 1447 /* 1448 * If -G is specified, enable -xlink=dynamic and -xunodefs to permit 1449 * references to undefined symbols to remain as unresolved relocations. 1450 * If -A is specified, enable -xlink=primary to permit static linking 1451 * only to kernel symbols that are defined in a primary kernel module. 1452 */ 1453 if (g_mode == DMODE_LINK) { 1454 (void) dtrace_setopt(g_dtp, "linkmode", "dynamic"); 1455 (void) dtrace_setopt(g_dtp, "unodefs", NULL); 1456 1457 /* 1458 * Use the remaining arguments as the list of object files 1459 * when in linker mode. 1460 */ 1461 g_objc = g_argc - 1; 1462 g_objv = g_argv + 1; 1463 1464 /* 1465 * We still use g_argv[0], the name of the executable. 1466 */ 1467 g_argc = 1; 1468 } else if (g_mode == DMODE_ANON) 1469 (void) dtrace_setopt(g_dtp, "linkmode", "primary"); 1470 1471 /* 1472 * Now that we have libdtrace open, make a second pass through argv[] 1473 * to perform any dtrace_setopt() calls and change any compiler flags. 1474 * We also accumulate any program specifications into our g_cmdv[] at 1475 * this time; these will compiled as part of the fourth processing pass. 1476 */ 1477 for (optind = 1; optind < argc; optind++) { 1478 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1479 switch (c) { 1480 case 'a': 1481 if (dtrace_setopt(g_dtp, "grabanon", 0) != 0) 1482 dfatal("failed to set -a"); 1483 break; 1484 1485 case 'b': 1486 if (dtrace_setopt(g_dtp, 1487 "bufsize", optarg) != 0) 1488 dfatal("failed to set -b %s", optarg); 1489 break; 1490 1491 case 'B': 1492 g_ofp = NULL; 1493 break; 1494 1495 case 'C': 1496 g_cflags |= DTRACE_C_CPP; 1497 break; 1498 1499 case 'D': 1500 if (dtrace_setopt(g_dtp, "define", optarg) != 0) 1501 dfatal("failed to set -D %s", optarg); 1502 break; 1503 1504 case 'f': 1505 dcp = &g_cmdv[g_cmdc++]; 1506 dcp->dc_func = compile_str; 1507 dcp->dc_spec = DTRACE_PROBESPEC_FUNC; 1508 dcp->dc_arg = optarg; 1509 break; 1510 1511 case 'F': 1512 if (dtrace_setopt(g_dtp, "flowindent", 0) != 0) 1513 dfatal("failed to set -F"); 1514 break; 1515 1516 case 'H': 1517 if (dtrace_setopt(g_dtp, "cpphdrs", 0) != 0) 1518 dfatal("failed to set -H"); 1519 break; 1520 1521 case 'i': 1522 dcp = &g_cmdv[g_cmdc++]; 1523 dcp->dc_func = compile_str; 1524 dcp->dc_spec = DTRACE_PROBESPEC_NAME; 1525 dcp->dc_arg = optarg; 1526 break; 1527 1528 case 'I': 1529 if (dtrace_setopt(g_dtp, "incdir", optarg) != 0) 1530 dfatal("failed to set -I %s", optarg); 1531 break; 1532 1533 case 'L': 1534 if (dtrace_setopt(g_dtp, "libdir", optarg) != 0) 1535 dfatal("failed to set -L %s", optarg); 1536 break; 1537 1538 case 'm': 1539 dcp = &g_cmdv[g_cmdc++]; 1540 dcp->dc_func = compile_str; 1541 dcp->dc_spec = DTRACE_PROBESPEC_MOD; 1542 dcp->dc_arg = optarg; 1543 break; 1544 1545 case 'n': 1546 dcp = &g_cmdv[g_cmdc++]; 1547 dcp->dc_func = compile_str; 1548 dcp->dc_spec = DTRACE_PROBESPEC_NAME; 1549 dcp->dc_arg = optarg; 1550 break; 1551 1552 case 'P': 1553 dcp = &g_cmdv[g_cmdc++]; 1554 dcp->dc_func = compile_str; 1555 dcp->dc_spec = DTRACE_PROBESPEC_PROVIDER; 1556 dcp->dc_arg = optarg; 1557 break; 1558 1559 case 'q': 1560 if (dtrace_setopt(g_dtp, "quiet", 0) != 0) 1561 dfatal("failed to set -q"); 1562 break; 1563 1564 case 'o': 1565 g_ofile = optarg; 1566 break; 1567 1568 case 's': 1569 dcp = &g_cmdv[g_cmdc++]; 1570 dcp->dc_func = compile_file; 1571 dcp->dc_spec = DTRACE_PROBESPEC_NONE; 1572 dcp->dc_arg = optarg; 1573 break; 1574 1575 case 'S': 1576 g_cflags |= DTRACE_C_DIFV; 1577 break; 1578 1579 case 'U': 1580 if (dtrace_setopt(g_dtp, "undef", optarg) != 0) 1581 dfatal("failed to set -U %s", optarg); 1582 break; 1583 1584 case 'v': 1585 g_verbose++; 1586 break; 1587 1588 case 'w': 1589 if (dtrace_setopt(g_dtp, "destructive", 0) != 0) 1590 dfatal("failed to set -w"); 1591 break; 1592 1593 case 'x': 1594 if ((p = strchr(optarg, '=')) != NULL) 1595 *p++ = '\0'; 1596 1597 if (dtrace_setopt(g_dtp, optarg, p) != 0) 1598 dfatal("failed to set -x %s", optarg); 1599 break; 1600 1601 case 'X': 1602 if (dtrace_setopt(g_dtp, "stdc", optarg) != 0) 1603 dfatal("failed to set -X %s", optarg); 1604 break; 1605 1606 case 'Z': 1607 g_cflags |= DTRACE_C_ZDEFS; 1608 break; 1609 1610 default: 1611 if (strchr(DTRACE_OPTSTR, c) == NULL) 1612 return (usage(stderr)); 1613 } 1614 } 1615 } 1616 1617 if (g_ofp == NULL && g_mode != DMODE_EXEC) { 1618 (void) fprintf(stderr, "%s: -B not valid in combination" 1619 " with [-AGl] options\n", g_pname); 1620 return (E_USAGE); 1621 } 1622 1623 if (g_ofp == NULL && g_ofile != NULL) { 1624 (void) fprintf(stderr, "%s: -B not valid in combination" 1625 " with -o option\n", g_pname); 1626 return (E_USAGE); 1627 } 1628 1629 /* 1630 * In our third pass we handle any command-line options related to 1631 * grabbing or creating victim processes. The behavior of these calls 1632 * may been affected by any library options set by the second pass. 1633 */ 1634 for (optind = 1; optind < argc; optind++) { 1635 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1636 switch (c) { 1637 case 'c': 1638 if ((v = make_argv(optarg)) == NULL) 1639 fatal("failed to allocate memory"); 1640 1641 P = dtrace_proc_create(g_dtp, v[0], v, NULL, NULL); 1642 if (P == NULL) 1643 dfatal(NULL); /* dtrace_errmsg() only */ 1644 1645 g_psv[g_psc++] = P; 1646 free(v); 1647 break; 1648 1649 case 'p': 1650 errno = 0; 1651 pid = strtol(optarg, &p, 10); 1652 1653 if (errno != 0 || p == optarg || p[0] != '\0') 1654 fatal("invalid pid: %s\n", optarg); 1655 1656 P = dtrace_proc_grab(g_dtp, pid, 0); 1657 if (P == NULL) 1658 dfatal(NULL); /* dtrace_errmsg() only */ 1659 1660 g_psv[g_psc++] = P; 1661 break; 1662 } 1663 } 1664 } 1665 1666 /* 1667 * In our fourth pass we finish g_cmdv[] by calling dc_func to convert 1668 * each string or file specification into a compiled program structure. 1669 */ 1670 for (i = 0; i < g_cmdc; i++) 1671 g_cmdv[i].dc_func(&g_cmdv[i]); 1672 1673 if (g_mode != DMODE_LIST) { 1674 if (dtrace_handle_err(g_dtp, &errhandler, NULL) == -1) 1675 dfatal("failed to establish error handler"); 1676 1677 if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1) 1678 dfatal("failed to establish drop handler"); 1679 1680 if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1) 1681 dfatal("failed to establish proc handler"); 1682 1683 if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1) 1684 dfatal("failed to establish setopt handler"); 1685 1686 if (g_ofp == NULL && 1687 dtrace_handle_buffered(g_dtp, &bufhandler, NULL) == -1) 1688 dfatal("failed to establish buffered handler"); 1689 } 1690 1691 (void) dtrace_getopt(g_dtp, "flowindent", &opt); 1692 g_flowindent = opt != DTRACEOPT_UNSET; 1693 1694 (void) dtrace_getopt(g_dtp, "grabanon", &opt); 1695 g_grabanon = opt != DTRACEOPT_UNSET; 1696 1697 (void) dtrace_getopt(g_dtp, "quiet", &opt); 1698 g_quiet = opt != DTRACEOPT_UNSET; 1699 1700 /* 1701 * Now make a fifth and final pass over the options that have been 1702 * turned into programs and saved in g_cmdv[], performing any mode- 1703 * specific processing. If g_mode is DMODE_EXEC, we will break out 1704 * of the switch() and continue on to the data processing loop. For 1705 * other modes, we will exit dtrace once mode-specific work is done. 1706 */ 1707 switch (g_mode) { 1708 case DMODE_EXEC: 1709 if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 1710 fatal("failed to open output file '%s'", g_ofile); 1711 1712 for (i = 0; i < g_cmdc; i++) 1713 exec_prog(&g_cmdv[i]); 1714 1715 if (done && !g_grabanon) { 1716 dtrace_close(g_dtp); 1717 return (g_status); 1718 } 1719 break; 1720 1721 case DMODE_ANON: 1722 if (g_ofile == NULL) 1723 #ifdef illumos 1724 g_ofile = "/kernel/drv/dtrace.conf"; 1725 #else 1726 /* 1727 * On FreeBSD, anonymous DOF data is written to 1728 * the DTrace DOF file that the boot loader will 1729 * read if booting with the DTrace option. 1730 */ 1731 g_ofile = "/boot/dtrace.dof"; 1732 #endif 1733 1734 dof_prune(g_ofile); /* strip out any old DOF directives */ 1735 #ifdef illumos 1736 etcsystem_prune(); /* string out any forceload directives */ 1737 #endif 1738 1739 if (g_cmdc == 0) { 1740 dtrace_close(g_dtp); 1741 return (g_status); 1742 } 1743 1744 if ((g_ofp = fopen(g_ofile, "a")) == NULL) 1745 fatal("failed to open output file '%s'", g_ofile); 1746 1747 for (i = 0; i < g_cmdc; i++) { 1748 anon_prog(&g_cmdv[i], 1749 dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i); 1750 } 1751 1752 /* 1753 * Dump out the DOF corresponding to the error handler and the 1754 * current options as the final DOF property in the .conf file. 1755 */ 1756 anon_prog(NULL, dtrace_geterr_dof(g_dtp), i++); 1757 anon_prog(NULL, dtrace_getopt_dof(g_dtp), i++); 1758 1759 if (fclose(g_ofp) == EOF) 1760 fatal("failed to close output file '%s'", g_ofile); 1761 1762 /* 1763 * These messages would use notice() rather than error(), but 1764 * we don't want them suppressed when -A is run on a D program 1765 * that itself contains a #pragma D option quiet. 1766 */ 1767 error("saved anonymous enabling in %s\n", g_ofile); 1768 #ifdef illumos 1769 etcsystem_add(); 1770 error("run update_drv(1M) or reboot to enable changes\n"); 1771 #endif 1772 1773 dtrace_close(g_dtp); 1774 return (g_status); 1775 1776 case DMODE_LINK: 1777 if (g_cmdc == 0) { 1778 (void) fprintf(stderr, "%s: -G requires one or more " 1779 "scripts or enabling options\n", g_pname); 1780 dtrace_close(g_dtp); 1781 return (E_USAGE); 1782 } 1783 1784 for (i = 0; i < g_cmdc; i++) 1785 link_prog(&g_cmdv[i]); 1786 1787 if (g_cmdc > 1 && g_ofile != NULL) { 1788 char **objv = alloca(g_cmdc * sizeof (char *)); 1789 1790 for (i = 0; i < g_cmdc; i++) 1791 objv[i] = g_cmdv[i].dc_ofile; 1792 1793 if (dtrace_program_link(g_dtp, NULL, DTRACE_D_PROBES, 1794 g_ofile, g_cmdc, objv) != 0) 1795 dfatal(NULL); /* dtrace_errmsg() only */ 1796 } 1797 1798 dtrace_close(g_dtp); 1799 return (g_status); 1800 1801 case DMODE_LIST: 1802 if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 1803 fatal("failed to open output file '%s'", g_ofile); 1804 1805 installsighands(); 1806 1807 oprintf("%5s %10s %17s %33s %s\n", 1808 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME"); 1809 1810 for (i = 0; i < g_cmdc; i++) 1811 list_prog(&g_cmdv[i]); 1812 1813 if (g_cmdc == 0) 1814 (void) dtrace_probe_iter(g_dtp, NULL, list_probe, NULL); 1815 1816 dtrace_close(g_dtp); 1817 return (g_status); 1818 1819 case DMODE_HEADER: 1820 if (g_cmdc == 0) { 1821 (void) fprintf(stderr, "%s: -h requires one or more " 1822 "scripts or enabling options\n", g_pname); 1823 dtrace_close(g_dtp); 1824 return (E_USAGE); 1825 } 1826 1827 if (g_ofile == NULL) { 1828 char *p; 1829 1830 if (g_cmdc > 1) { 1831 (void) fprintf(stderr, "%s: -h requires an " 1832 "output file if multiple scripts are " 1833 "specified\n", g_pname); 1834 dtrace_close(g_dtp); 1835 return (E_USAGE); 1836 } 1837 1838 if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL || 1839 strcmp(p, ".d") != 0) { 1840 (void) fprintf(stderr, "%s: -h requires an " 1841 "output file if no scripts are " 1842 "specified\n", g_pname); 1843 dtrace_close(g_dtp); 1844 return (E_USAGE); 1845 } 1846 1847 p[0] = '\0'; /* strip .d suffix */ 1848 g_ofile = p = g_cmdv[0].dc_ofile; 1849 (void) snprintf(p, sizeof (g_cmdv[0].dc_ofile), 1850 "%s.h", basename(g_cmdv[0].dc_arg)); 1851 } 1852 1853 if ((g_ofp = fopen(g_ofile, "w")) == NULL) 1854 fatal("failed to open header file '%s'", g_ofile); 1855 1856 oprintf("/*\n * Generated by dtrace(1M).\n */\n\n"); 1857 1858 if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 || 1859 fclose(g_ofp) == EOF) 1860 dfatal("failed to create header file %s", g_ofile); 1861 1862 dtrace_close(g_dtp); 1863 return (g_status); 1864 } 1865 1866 /* 1867 * If -a and -Z were not specified and no probes have been matched, no 1868 * probe criteria was specified on the command line and we abort. 1869 */ 1870 if (g_total == 0 && !g_grabanon && !(g_cflags & DTRACE_C_ZDEFS)) 1871 dfatal("no probes %s\n", g_cmdc ? "matched" : "specified"); 1872 1873 /* 1874 * Start tracing. Once we dtrace_go(), reload any options that affect 1875 * our globals in case consuming anonymous state has changed them. 1876 */ 1877 go(); 1878 1879 (void) dtrace_getopt(g_dtp, "flowindent", &opt); 1880 g_flowindent = opt != DTRACEOPT_UNSET; 1881 1882 (void) dtrace_getopt(g_dtp, "grabanon", &opt); 1883 g_grabanon = opt != DTRACEOPT_UNSET; 1884 1885 (void) dtrace_getopt(g_dtp, "quiet", &opt); 1886 g_quiet = opt != DTRACEOPT_UNSET; 1887 1888 (void) dtrace_getopt(g_dtp, "destructive", &opt); 1889 if (opt != DTRACEOPT_UNSET) 1890 notice("allowing destructive actions\n"); 1891 1892 installsighands(); 1893 1894 /* 1895 * Now that tracing is active and we are ready to consume trace data, 1896 * continue any grabbed or created processes, setting them running 1897 * using the /proc control mechanism inside of libdtrace. 1898 */ 1899 for (i = 0; i < g_psc; i++) 1900 dtrace_proc_continue(g_dtp, g_psv[i]); 1901 1902 g_pslive = g_psc; /* count for prochandler() */ 1903 1904 do { 1905 if (!g_intr && !done) 1906 dtrace_sleep(g_dtp); 1907 1908 if (g_newline) { 1909 /* 1910 * Output a newline just to make the output look 1911 * slightly cleaner. Note that we do this even in 1912 * "quiet" mode... 1913 */ 1914 oprintf("\n"); 1915 g_newline = 0; 1916 } 1917 1918 if (done || g_intr || (g_psc != 0 && g_pslive == 0)) { 1919 done = 1; 1920 if (dtrace_stop(g_dtp) == -1) 1921 dfatal("couldn't stop tracing"); 1922 } 1923 1924 switch (dtrace_work(g_dtp, g_ofp, chew, chewrec, NULL)) { 1925 case DTRACE_WORKSTATUS_DONE: 1926 done = 1; 1927 break; 1928 case DTRACE_WORKSTATUS_OKAY: 1929 break; 1930 default: 1931 if (!g_impatient && dtrace_errno(g_dtp) != EINTR) 1932 dfatal("processing aborted"); 1933 } 1934 1935 if (g_ofp != NULL && fflush(g_ofp) == EOF) 1936 clearerr(g_ofp); 1937 } while (!done); 1938 1939 oprintf("\n"); 1940 1941 if (!g_impatient) { 1942 if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 && 1943 dtrace_errno(g_dtp) != EINTR) 1944 dfatal("failed to print aggregations"); 1945 } 1946 1947 dtrace_close(g_dtp); 1948 return (g_status); 1949 } 1950