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