dtrace.c revision 268578
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#if defined(sun) 47#include <alloca.h> 48#endif 49#include <libgen.h> 50#if defined(sun) 51#include <libproc.h> 52#endif 53 54typedef 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 75static 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 78static char **g_argv; 79static int g_argc; 80static char **g_objv; 81static int g_objc; 82static dtrace_cmd_t *g_cmdv; 83static int g_cmdc; 84static struct ps_prochandle **g_psv; 85static int g_psc; 86static int g_pslive; 87static char *g_pname; 88static int g_quiet; 89static int g_flowindent; 90static int g_intr; 91static int g_impatient; 92static int g_newline; 93static int g_total; 94static int g_cflags; 95static int g_oflags; 96static int g_verbose; 97static int g_exec = 1; 98static int g_mode = DMODE_EXEC; 99static int g_status = E_SUCCESS; 100static int g_grabanon = 0; 101static const char *g_ofile = NULL; 102static FILE *g_ofp; 103static dtrace_hdl_t *g_dtp; 104#if defined(sun) 105static char *g_etcfile = "/etc/system"; 106static const char *g_etcbegin = "* vvvv Added by DTrace"; 107static const char *g_etcend = "* ^^^^ Added by DTrace"; 108 109static 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"*", 118NULL }; 119#endif 120 121static int 122usage(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 178static void 179verror(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*/ 191static void 192fatal(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*/ 211static void 212dfatal(const char *fmt, ...) 213{ 214#if !defined(sun) && 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(sun) && 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*/ 251static void 252error(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*/ 262static void 263notice(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*/ 276static void 277oprintf(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 298static char ** 299make_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 319static void 320dof_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#if defined(sun) 401static void 402etcsystem_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); 475out: 476 free(buf); 477} 478 479static void 480etcsystem_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 512 513static void 514print_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*/ 558static int 559info_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 */ 584static void 585exec_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 */ 635static void 636anon_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#if defined(sun) 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 */ 676static void 677link_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*/ 702static int 703list_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 return (0); 714} 715 716/*ARGSUSED*/ 717static int 718list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 719 dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) 720{ 721 dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 722 723 if (edp == *last) 724 return (0); 725 726 if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) { 727 error("failed to match %s:%s:%s:%s: %s\n", 728 edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, 729 edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name, 730 dtrace_errmsg(dtp, dtrace_errno(dtp))); 731 } 732 733 *last = edp; 734 return (0); 735} 736 737/* 738 * List the probes corresponding to the specified program by iterating over 739 * each statement and then matching probes to the statement probe descriptions. 740 */ 741static void 742list_prog(const dtrace_cmd_t *dcp) 743{ 744 dtrace_ecbdesc_t *last = NULL; 745 746 (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, 747 (dtrace_stmt_f *)list_stmt, &last); 748} 749 750static void 751compile_file(dtrace_cmd_t *dcp) 752{ 753 char *arg0; 754 FILE *fp; 755 756 if ((fp = fopen(dcp->dc_arg, "r")) == NULL) 757 fatal("failed to open %s", dcp->dc_arg); 758 759 arg0 = g_argv[0]; 760 g_argv[0] = dcp->dc_arg; 761 762 if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp, 763 g_cflags, g_argc, g_argv)) == NULL) 764 dfatal("failed to compile script %s", dcp->dc_arg); 765 766 g_argv[0] = arg0; 767 (void) fclose(fp); 768 769 dcp->dc_desc = "script"; 770 dcp->dc_name = dcp->dc_arg; 771} 772 773static void 774compile_str(dtrace_cmd_t *dcp) 775{ 776 char *p; 777 778 if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg, 779 dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL) 780 dfatal("invalid probe specifier %s", dcp->dc_arg); 781 782 if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL) 783 *p = '\0'; /* crop name for reporting */ 784 785 dcp->dc_desc = "description"; 786 dcp->dc_name = dcp->dc_arg; 787} 788 789/*ARGSUSED*/ 790static void 791prochandler(struct ps_prochandle *P, const char *msg, void *arg) 792{ 793#if defined(sun) 794 const psinfo_t *prp = Ppsinfo(P); 795 int pid = Pstatus(P)->pr_pid; 796 char name[SIG2STR_MAX]; 797#else 798 int wstatus = proc_getwstat(P); 799 int pid = proc_getpid(P); 800#endif 801 802 if (msg != NULL) { 803 notice("pid %d: %s\n", pid, msg); 804 return; 805 } 806 807#if defined(sun) 808 switch (Pstate(P)) { 809#else 810 switch (proc_state(P)) { 811#endif 812 case PS_UNDEAD: 813#if defined(sun) 814 /* 815 * Ideally we would like to always report pr_wstat here, but it 816 * isn't possible given current /proc semantics. If we grabbed 817 * the process, Ppsinfo() will either fail or return a zeroed 818 * psinfo_t depending on how far the parent is in reaping it. 819 * When /proc provides a stable pr_wstat in the status file, 820 * this code can be improved by examining this new pr_wstat. 821 */ 822 if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 823 notice("pid %d terminated by %s\n", pid, 824 proc_signame(WTERMSIG(prp->pr_wstat), 825 name, sizeof (name))); 826#else 827 if (WIFSIGNALED(wstatus)) { 828 notice("pid %d terminated by %d\n", pid, 829 WTERMSIG(wstatus)); 830#endif 831#if defined(sun) 832 } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { 833 notice("pid %d exited with status %d\n", 834 pid, WEXITSTATUS(prp->pr_wstat)); 835#else 836 } else if (WEXITSTATUS(wstatus) != 0) { 837 notice("pid %d exited with status %d\n", 838 pid, WEXITSTATUS(wstatus)); 839#endif 840 } else { 841 notice("pid %d has exited\n", pid); 842 } 843 g_pslive--; 844 break; 845 846 case PS_LOST: 847 notice("pid %d exec'd a set-id or unobservable program\n", pid); 848 g_pslive--; 849 break; 850 } 851} 852 853/*ARGSUSED*/ 854static int 855errhandler(const dtrace_errdata_t *data, void *arg) 856{ 857 error(data->dteda_msg); 858 return (DTRACE_HANDLE_OK); 859} 860 861/*ARGSUSED*/ 862static int 863drophandler(const dtrace_dropdata_t *data, void *arg) 864{ 865 error(data->dtdda_msg); 866 return (DTRACE_HANDLE_OK); 867} 868 869/*ARGSUSED*/ 870static int 871setopthandler(const dtrace_setoptdata_t *data, void *arg) 872{ 873 if (strcmp(data->dtsda_option, "quiet") == 0) 874 g_quiet = data->dtsda_newval != DTRACEOPT_UNSET; 875 876 if (strcmp(data->dtsda_option, "flowindent") == 0) 877 g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET; 878 879 return (DTRACE_HANDLE_OK); 880} 881 882#define BUFDUMPHDR(hdr) \ 883 (void) printf("%s: %s%s\n", g_pname, hdr, strlen(hdr) > 0 ? ":" : ""); 884 885#define BUFDUMPSTR(ptr, field) \ 886 (void) printf("%s: %20s => ", g_pname, #field); \ 887 if ((ptr)->field != NULL) { \ 888 const char *c = (ptr)->field; \ 889 (void) printf("\""); \ 890 do { \ 891 if (*c == '\n') { \ 892 (void) printf("\\n"); \ 893 continue; \ 894 } \ 895 \ 896 (void) printf("%c", *c); \ 897 } while (*c++ != '\0'); \ 898 (void) printf("\"\n"); \ 899 } else { \ 900 (void) printf("<NULL>\n"); \ 901 } 902 903#define BUFDUMPASSTR(ptr, field, str) \ 904 (void) printf("%s: %20s => %s\n", g_pname, #field, str); 905 906#define BUFDUMP(ptr, field) \ 907 (void) printf("%s: %20s => %lld\n", g_pname, #field, \ 908 (long long)(ptr)->field); 909 910#define BUFDUMPPTR(ptr, field) \ 911 (void) printf("%s: %20s => %s\n", g_pname, #field, \ 912 (ptr)->field != NULL ? "<non-NULL>" : "<NULL>"); 913 914/*ARGSUSED*/ 915static int 916bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 917{ 918 const dtrace_aggdata_t *agg = bufdata->dtbda_aggdata; 919 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 920 const dtrace_probedesc_t *pd; 921 uint32_t flags = bufdata->dtbda_flags; 922 char buf[512], *c = buf, *end = c + sizeof (buf); 923 int i, printed; 924 925 struct { 926 const char *name; 927 uint32_t value; 928 } flagnames[] = { 929 { "AGGVAL", DTRACE_BUFDATA_AGGVAL }, 930 { "AGGKEY", DTRACE_BUFDATA_AGGKEY }, 931 { "AGGFORMAT", DTRACE_BUFDATA_AGGFORMAT }, 932 { "AGGLAST", DTRACE_BUFDATA_AGGLAST }, 933 { "???", UINT32_MAX }, 934 { NULL } 935 }; 936 937 if (bufdata->dtbda_probe != NULL) { 938 pd = bufdata->dtbda_probe->dtpda_pdesc; 939 } else if (agg != NULL) { 940 pd = agg->dtada_pdesc; 941 } else { 942 pd = NULL; 943 } 944 945 BUFDUMPHDR(">>> Called buffer handler"); 946 BUFDUMPHDR(""); 947 948 BUFDUMPHDR(" dtrace_bufdata"); 949 BUFDUMPSTR(bufdata, dtbda_buffered); 950 BUFDUMPPTR(bufdata, dtbda_probe); 951 BUFDUMPPTR(bufdata, dtbda_aggdata); 952 BUFDUMPPTR(bufdata, dtbda_recdesc); 953 954 (void) snprintf(c, end - c, "0x%x ", bufdata->dtbda_flags); 955 c += strlen(c); 956 957 for (i = 0, printed = 0; flagnames[i].name != NULL; i++) { 958 if (!(flags & flagnames[i].value)) 959 continue; 960 961 (void) snprintf(c, end - c, 962 "%s%s", printed++ ? " | " : "(", flagnames[i].name); 963 c += strlen(c); 964 flags &= ~flagnames[i].value; 965 } 966 967 if (printed) 968 (void) snprintf(c, end - c, ")"); 969 970 BUFDUMPASSTR(bufdata, dtbda_flags, buf); 971 BUFDUMPHDR(""); 972 973 if (pd != NULL) { 974 BUFDUMPHDR(" dtrace_probedesc"); 975 BUFDUMPSTR(pd, dtpd_provider); 976 BUFDUMPSTR(pd, dtpd_mod); 977 BUFDUMPSTR(pd, dtpd_func); 978 BUFDUMPSTR(pd, dtpd_name); 979 BUFDUMPHDR(""); 980 } 981 982 if (rec != NULL) { 983 BUFDUMPHDR(" dtrace_recdesc"); 984 BUFDUMP(rec, dtrd_action); 985 BUFDUMP(rec, dtrd_size); 986 987 if (agg != NULL) { 988 uint8_t *data; 989 int lim = rec->dtrd_size; 990 991 (void) sprintf(buf, "%d (data: ", rec->dtrd_offset); 992 c = buf + strlen(buf); 993 994 if (lim > sizeof (uint64_t)) 995 lim = sizeof (uint64_t); 996 997 data = (uint8_t *)agg->dtada_data + rec->dtrd_offset; 998 999 for (i = 0; i < lim; i++) { 1000 (void) snprintf(c, end - c, "%s%02x", 1001 i == 0 ? "" : " ", *data++); 1002 c += strlen(c); 1003 } 1004 1005 (void) snprintf(c, end - c, 1006 "%s)", lim < rec->dtrd_size ? " ..." : ""); 1007 BUFDUMPASSTR(rec, dtrd_offset, buf); 1008 } else { 1009 BUFDUMP(rec, dtrd_offset); 1010 } 1011 1012 BUFDUMPHDR(""); 1013 } 1014 1015 if (agg != NULL) { 1016 dtrace_aggdesc_t *desc = agg->dtada_desc; 1017 1018 BUFDUMPHDR(" dtrace_aggdesc"); 1019 BUFDUMPSTR(desc, dtagd_name); 1020 BUFDUMP(desc, dtagd_varid); 1021 BUFDUMP(desc, dtagd_id); 1022 BUFDUMP(desc, dtagd_nrecs); 1023 BUFDUMPHDR(""); 1024 } 1025 1026 return (DTRACE_HANDLE_OK); 1027} 1028 1029/*ARGSUSED*/ 1030static int 1031chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) 1032{ 1033 dtrace_actkind_t act; 1034 uintptr_t addr; 1035 1036 if (rec == NULL) { 1037 /* 1038 * We have processed the final record; output the newline if 1039 * we're not in quiet mode. 1040 */ 1041 if (!g_quiet) 1042 oprintf("\n"); 1043 1044 return (DTRACE_CONSUME_NEXT); 1045 } 1046 1047 act = rec->dtrd_action; 1048 addr = (uintptr_t)data->dtpda_data; 1049 1050 if (act == DTRACEACT_EXIT) { 1051 g_status = *((uint32_t *)addr); 1052 return (DTRACE_CONSUME_NEXT); 1053 } 1054 1055 return (DTRACE_CONSUME_THIS); 1056} 1057 1058/*ARGSUSED*/ 1059static int 1060chew(const dtrace_probedata_t *data, void *arg) 1061{ 1062 dtrace_probedesc_t *pd = data->dtpda_pdesc; 1063 processorid_t cpu = data->dtpda_cpu; 1064 static int heading; 1065 1066 if (g_impatient) { 1067 g_newline = 0; 1068 return (DTRACE_CONSUME_ABORT); 1069 } 1070 1071 if (heading == 0) { 1072 if (!g_flowindent) { 1073 if (!g_quiet) { 1074 oprintf("%3s %6s %32s\n", 1075 "CPU", "ID", "FUNCTION:NAME"); 1076 } 1077 } else { 1078 oprintf("%3s %-41s\n", "CPU", "FUNCTION"); 1079 } 1080 heading = 1; 1081 } 1082 1083 if (!g_flowindent) { 1084 if (!g_quiet) { 1085 char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; 1086 1087 (void) snprintf(name, sizeof (name), "%s:%s", 1088 pd->dtpd_func, pd->dtpd_name); 1089 1090 oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name); 1091 } 1092 } else { 1093 int indent = data->dtpda_indent; 1094 char *name; 1095 size_t len; 1096 1097 if (data->dtpda_flow == DTRACEFLOW_NONE) { 1098 len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5; 1099 name = alloca(len); 1100 (void) snprintf(name, len, "%*s%s%s:%s", indent, "", 1101 data->dtpda_prefix, pd->dtpd_func, 1102 pd->dtpd_name); 1103 } else { 1104 len = indent + DTRACE_FUNCNAMELEN + 5; 1105 name = alloca(len); 1106 (void) snprintf(name, len, "%*s%s%s", indent, "", 1107 data->dtpda_prefix, pd->dtpd_func); 1108 } 1109 1110 oprintf("%3d %-41s ", cpu, name); 1111 } 1112 1113 return (DTRACE_CONSUME_THIS); 1114} 1115 1116static void 1117go(void) 1118{ 1119 int i; 1120 1121 struct { 1122 char *name; 1123 char *optname; 1124 dtrace_optval_t val; 1125 } bufs[] = { 1126 { "buffer size", "bufsize" }, 1127 { "aggregation size", "aggsize" }, 1128 { "speculation size", "specsize" }, 1129 { "dynamic variable size", "dynvarsize" }, 1130 { NULL } 1131 }, rates[] = { 1132 { "cleaning rate", "cleanrate" }, 1133 { "status rate", "statusrate" }, 1134 { NULL } 1135 }; 1136 1137 for (i = 0; bufs[i].name != NULL; i++) { 1138 if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1) 1139 fatal("couldn't get option %s", bufs[i].optname); 1140 } 1141 1142 for (i = 0; rates[i].name != NULL; i++) { 1143 if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1) 1144 fatal("couldn't get option %s", rates[i].optname); 1145 } 1146 1147 if (dtrace_go(g_dtp) == -1) 1148 dfatal("could not enable tracing"); 1149 1150 for (i = 0; bufs[i].name != NULL; i++) { 1151 dtrace_optval_t j = 0, mul = 10; 1152 dtrace_optval_t nsize; 1153 1154 if (bufs[i].val == DTRACEOPT_UNSET) 1155 continue; 1156 1157 (void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize); 1158 1159 if (nsize == DTRACEOPT_UNSET || nsize == 0) 1160 continue; 1161 1162 if (nsize >= bufs[i].val - sizeof (uint64_t)) 1163 continue; 1164 1165 for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10) 1166 continue; 1167 1168 if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) { 1169 error("%s lowered to %lld%c\n", bufs[i].name, 1170 (long long)nsize >> (mul - 10), " kmgtpe"[j]); 1171 } else { 1172 error("%s lowered to %lld bytes\n", bufs[i].name, 1173 (long long)nsize); 1174 } 1175 } 1176 1177 for (i = 0; rates[i].name != NULL; i++) { 1178 dtrace_optval_t nval; 1179 char *dir; 1180 1181 if (rates[i].val == DTRACEOPT_UNSET) 1182 continue; 1183 1184 (void) dtrace_getopt(g_dtp, rates[i].optname, &nval); 1185 1186 if (nval == DTRACEOPT_UNSET || nval == 0) 1187 continue; 1188 1189 if (rates[i].val == nval) 1190 continue; 1191 1192 dir = nval > rates[i].val ? "reduced" : "increased"; 1193 1194 if (nval <= NANOSEC && (NANOSEC % nval) == 0) { 1195 error("%s %s to %lld hz\n", rates[i].name, dir, 1196 (long long)NANOSEC / (long long)nval); 1197 continue; 1198 } 1199 1200 if ((nval % NANOSEC) == 0) { 1201 error("%s %s to once every %lld seconds\n", 1202 rates[i].name, dir, 1203 (long long)nval / (long long)NANOSEC); 1204 continue; 1205 } 1206 1207 error("%s %s to once every %lld nanoseconds\n", 1208 rates[i].name, dir, (long long)nval); 1209 } 1210} 1211 1212/*ARGSUSED*/ 1213static void 1214intr(int signo) 1215{ 1216 if (!g_intr) 1217 g_newline = 1; 1218 1219 if (g_intr++) 1220 g_impatient = 1; 1221} 1222 1223int 1224main(int argc, char *argv[]) 1225{ 1226 dtrace_bufdesc_t buf; 1227 struct sigaction act, oact; 1228 dtrace_status_t status[2]; 1229 dtrace_optval_t opt; 1230 dtrace_cmd_t *dcp; 1231 1232 g_ofp = stdout; 1233 int done = 0, mode = 0; 1234 int err, i, c; 1235 char *p, **v; 1236 struct ps_prochandle *P; 1237 pid_t pid; 1238 1239 g_pname = basename(argv[0]); 1240 1241 if (argc == 1) 1242 return (usage(stderr)); 1243 1244 if ((g_argv = malloc(sizeof (char *) * argc)) == NULL || 1245 (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL || 1246 (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL) 1247 fatal("failed to allocate memory for arguments"); 1248 1249 g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */ 1250 argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ 1251 1252 bzero(status, sizeof (status)); 1253 bzero(&buf, sizeof (buf)); 1254 1255 /* 1256 * Make an initial pass through argv[] processing any arguments that 1257 * affect our behavior mode (g_mode) and flags used for dtrace_open(). 1258 * We also accumulate arguments that are not affiliated with getopt 1259 * options into g_argv[], and abort if any invalid options are found. 1260 */ 1261 for (optind = 1; optind < argc; optind++) { 1262 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1263 switch (c) { 1264 case '3': 1265 if (strcmp(optarg, "2") != 0) { 1266 (void) fprintf(stderr, 1267 "%s: illegal option -- 3%s\n", 1268 argv[0], optarg); 1269 return (usage(stderr)); 1270 } 1271 g_oflags &= ~DTRACE_O_LP64; 1272 g_oflags |= DTRACE_O_ILP32; 1273 break; 1274 1275 case '6': 1276 if (strcmp(optarg, "4") != 0) { 1277 (void) fprintf(stderr, 1278 "%s: illegal option -- 6%s\n", 1279 argv[0], optarg); 1280 return (usage(stderr)); 1281 } 1282 g_oflags &= ~DTRACE_O_ILP32; 1283 g_oflags |= DTRACE_O_LP64; 1284 break; 1285 1286 case 'a': 1287 g_grabanon++; /* also checked in pass 2 below */ 1288 break; 1289 1290 case 'A': 1291 g_mode = DMODE_ANON; 1292 g_exec = 0; 1293 mode++; 1294 break; 1295 1296 case 'e': 1297 g_exec = 0; 1298 done = 1; 1299 break; 1300 1301 case 'h': 1302 g_mode = DMODE_HEADER; 1303 g_oflags |= DTRACE_O_NODEV; 1304 g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */ 1305 g_exec = 0; 1306 mode++; 1307 break; 1308 1309 case 'G': 1310 g_mode = DMODE_LINK; 1311 g_oflags |= DTRACE_O_NODEV; 1312 g_cflags |= DTRACE_C_ZDEFS; /* -G implies -Z */ 1313 g_exec = 0; 1314 mode++; 1315 break; 1316 1317 case 'l': 1318 g_mode = DMODE_LIST; 1319 g_cflags |= DTRACE_C_ZDEFS; /* -l implies -Z */ 1320 mode++; 1321 break; 1322 1323 case 'V': 1324 g_mode = DMODE_VERS; 1325 mode++; 1326 break; 1327 1328 default: 1329 if (strchr(DTRACE_OPTSTR, c) == NULL) 1330 return (usage(stderr)); 1331 } 1332 } 1333 1334 if (optind < argc) 1335 g_argv[g_argc++] = argv[optind]; 1336 } 1337 1338 if (mode > 1) { 1339 (void) fprintf(stderr, "%s: only one of the [-AGhlV] options " 1340 "can be specified at a time\n", g_pname); 1341 return (E_USAGE); 1342 } 1343 1344 if (g_mode == DMODE_VERS) 1345 return (printf("%s: %s\n", g_pname, _dtrace_version) <= 0); 1346 1347 /* 1348 * If we're in linker mode and the data model hasn't been specified, 1349 * we try to guess the appropriate setting by examining the object 1350 * files. We ignore certain errors since we'll catch them later when 1351 * we actually process the object files. 1352 */ 1353 if (g_mode == DMODE_LINK && 1354 (g_oflags & (DTRACE_O_ILP32 | DTRACE_O_LP64)) == 0 && 1355 elf_version(EV_CURRENT) != EV_NONE) { 1356 int fd; 1357 Elf *elf; 1358 GElf_Ehdr ehdr; 1359 1360 for (i = 1; i < g_argc; i++) { 1361 if ((fd = open64(g_argv[i], O_RDONLY)) == -1) 1362 break; 1363 1364 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 1365 (void) close(fd); 1366 break; 1367 } 1368 1369 if (elf_kind(elf) != ELF_K_ELF || 1370 gelf_getehdr(elf, &ehdr) == NULL) { 1371 (void) close(fd); 1372 (void) elf_end(elf); 1373 break; 1374 } 1375 1376 (void) close(fd); 1377 (void) elf_end(elf); 1378 1379 if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 1380 if (g_oflags & DTRACE_O_ILP32) { 1381 fatal("can't mix 32-bit and 64-bit " 1382 "object files\n"); 1383 } 1384 g_oflags |= DTRACE_O_LP64; 1385 } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1386 if (g_oflags & DTRACE_O_LP64) { 1387 fatal("can't mix 32-bit and 64-bit " 1388 "object files\n"); 1389 } 1390 g_oflags |= DTRACE_O_ILP32; 1391 } else { 1392 break; 1393 } 1394 } 1395 } 1396 1397 /* 1398 * Open libdtrace. If we are not actually going to be enabling any 1399 * instrumentation attempt to reopen libdtrace using DTRACE_O_NODEV. 1400 */ 1401 while ((g_dtp = dtrace_open(DTRACE_VERSION, g_oflags, &err)) == NULL) { 1402 if (!(g_oflags & DTRACE_O_NODEV) && !g_exec && !g_grabanon) { 1403 g_oflags |= DTRACE_O_NODEV; 1404 continue; 1405 } 1406 1407 fatal("failed to initialize dtrace: %s\n", 1408 dtrace_errmsg(NULL, err)); 1409 } 1410 1411#if defined(__i386__) 1412 /* XXX The 32-bit seems to need more buffer space by default -sson */ 1413 (void) dtrace_setopt(g_dtp, "bufsize", "12m"); 1414 (void) dtrace_setopt(g_dtp, "aggsize", "12m"); 1415#else 1416 (void) dtrace_setopt(g_dtp, "bufsize", "4m"); 1417 (void) dtrace_setopt(g_dtp, "aggsize", "4m"); 1418#endif 1419 (void) dtrace_setopt(g_dtp, "temporal", "yes"); 1420 1421 /* 1422 * If -G is specified, enable -xlink=dynamic and -xunodefs to permit 1423 * references to undefined symbols to remain as unresolved relocations. 1424 * If -A is specified, enable -xlink=primary to permit static linking 1425 * only to kernel symbols that are defined in a primary kernel module. 1426 */ 1427 if (g_mode == DMODE_LINK) { 1428 (void) dtrace_setopt(g_dtp, "linkmode", "dynamic"); 1429 (void) dtrace_setopt(g_dtp, "unodefs", NULL); 1430 1431 /* 1432 * Use the remaining arguments as the list of object files 1433 * when in linker mode. 1434 */ 1435 g_objc = g_argc - 1; 1436 g_objv = g_argv + 1; 1437 1438 /* 1439 * We still use g_argv[0], the name of the executable. 1440 */ 1441 g_argc = 1; 1442 } else if (g_mode == DMODE_ANON) 1443 (void) dtrace_setopt(g_dtp, "linkmode", "primary"); 1444 1445 /* 1446 * Now that we have libdtrace open, make a second pass through argv[] 1447 * to perform any dtrace_setopt() calls and change any compiler flags. 1448 * We also accumulate any program specifications into our g_cmdv[] at 1449 * this time; these will compiled as part of the fourth processing pass. 1450 */ 1451 for (optind = 1; optind < argc; optind++) { 1452 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1453 switch (c) { 1454 case 'a': 1455 if (dtrace_setopt(g_dtp, "grabanon", 0) != 0) 1456 dfatal("failed to set -a"); 1457 break; 1458 1459 case 'b': 1460 if (dtrace_setopt(g_dtp, 1461 "bufsize", optarg) != 0) 1462 dfatal("failed to set -b %s", optarg); 1463 break; 1464 1465 case 'B': 1466 g_ofp = NULL; 1467 break; 1468 1469 case 'C': 1470 g_cflags |= DTRACE_C_CPP; 1471 break; 1472 1473 case 'D': 1474 if (dtrace_setopt(g_dtp, "define", optarg) != 0) 1475 dfatal("failed to set -D %s", optarg); 1476 break; 1477 1478 case 'f': 1479 dcp = &g_cmdv[g_cmdc++]; 1480 dcp->dc_func = compile_str; 1481 dcp->dc_spec = DTRACE_PROBESPEC_FUNC; 1482 dcp->dc_arg = optarg; 1483 break; 1484 1485 case 'F': 1486 if (dtrace_setopt(g_dtp, "flowindent", 0) != 0) 1487 dfatal("failed to set -F"); 1488 break; 1489 1490 case 'H': 1491 if (dtrace_setopt(g_dtp, "cpphdrs", 0) != 0) 1492 dfatal("failed to set -H"); 1493 break; 1494 1495 case 'i': 1496 dcp = &g_cmdv[g_cmdc++]; 1497 dcp->dc_func = compile_str; 1498 dcp->dc_spec = DTRACE_PROBESPEC_NAME; 1499 dcp->dc_arg = optarg; 1500 break; 1501 1502 case 'I': 1503 if (dtrace_setopt(g_dtp, "incdir", optarg) != 0) 1504 dfatal("failed to set -I %s", optarg); 1505 break; 1506 1507 case 'L': 1508 if (dtrace_setopt(g_dtp, "libdir", optarg) != 0) 1509 dfatal("failed to set -L %s", optarg); 1510 break; 1511 1512 case 'm': 1513 dcp = &g_cmdv[g_cmdc++]; 1514 dcp->dc_func = compile_str; 1515 dcp->dc_spec = DTRACE_PROBESPEC_MOD; 1516 dcp->dc_arg = optarg; 1517 break; 1518 1519 case 'n': 1520 dcp = &g_cmdv[g_cmdc++]; 1521 dcp->dc_func = compile_str; 1522 dcp->dc_spec = DTRACE_PROBESPEC_NAME; 1523 dcp->dc_arg = optarg; 1524 break; 1525 1526 case 'P': 1527 dcp = &g_cmdv[g_cmdc++]; 1528 dcp->dc_func = compile_str; 1529 dcp->dc_spec = DTRACE_PROBESPEC_PROVIDER; 1530 dcp->dc_arg = optarg; 1531 break; 1532 1533 case 'q': 1534 if (dtrace_setopt(g_dtp, "quiet", 0) != 0) 1535 dfatal("failed to set -q"); 1536 break; 1537 1538 case 'o': 1539 g_ofile = optarg; 1540 break; 1541 1542 case 's': 1543 dcp = &g_cmdv[g_cmdc++]; 1544 dcp->dc_func = compile_file; 1545 dcp->dc_spec = DTRACE_PROBESPEC_NONE; 1546 dcp->dc_arg = optarg; 1547 break; 1548 1549 case 'S': 1550 g_cflags |= DTRACE_C_DIFV; 1551 break; 1552 1553 case 'U': 1554 if (dtrace_setopt(g_dtp, "undef", optarg) != 0) 1555 dfatal("failed to set -U %s", optarg); 1556 break; 1557 1558 case 'v': 1559 g_verbose++; 1560 break; 1561 1562 case 'w': 1563 if (dtrace_setopt(g_dtp, "destructive", 0) != 0) 1564 dfatal("failed to set -w"); 1565 break; 1566 1567 case 'x': 1568 if ((p = strchr(optarg, '=')) != NULL) 1569 *p++ = '\0'; 1570 1571 if (dtrace_setopt(g_dtp, optarg, p) != 0) 1572 dfatal("failed to set -x %s", optarg); 1573 break; 1574 1575 case 'X': 1576 if (dtrace_setopt(g_dtp, "stdc", optarg) != 0) 1577 dfatal("failed to set -X %s", optarg); 1578 break; 1579 1580 case 'Z': 1581 g_cflags |= DTRACE_C_ZDEFS; 1582 break; 1583 1584 default: 1585 if (strchr(DTRACE_OPTSTR, c) == NULL) 1586 return (usage(stderr)); 1587 } 1588 } 1589 } 1590 1591 if (g_ofp == NULL && g_mode != DMODE_EXEC) { 1592 (void) fprintf(stderr, "%s: -B not valid in combination" 1593 " with [-AGl] options\n", g_pname); 1594 return (E_USAGE); 1595 } 1596 1597 if (g_ofp == NULL && g_ofile != NULL) { 1598 (void) fprintf(stderr, "%s: -B not valid in combination" 1599 " with -o option\n", g_pname); 1600 return (E_USAGE); 1601 } 1602 1603 /* 1604 * In our third pass we handle any command-line options related to 1605 * grabbing or creating victim processes. The behavior of these calls 1606 * may been affected by any library options set by the second pass. 1607 */ 1608 for (optind = 1; optind < argc; optind++) { 1609 while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 1610 switch (c) { 1611 case 'c': 1612 if ((v = make_argv(optarg)) == NULL) 1613 fatal("failed to allocate memory"); 1614 1615 P = dtrace_proc_create(g_dtp, v[0], v, NULL, NULL); 1616 if (P == NULL) 1617 dfatal(NULL); /* dtrace_errmsg() only */ 1618 1619 g_psv[g_psc++] = P; 1620 free(v); 1621 break; 1622 1623 case 'p': 1624 errno = 0; 1625 pid = strtol(optarg, &p, 10); 1626 1627 if (errno != 0 || p == optarg || p[0] != '\0') 1628 fatal("invalid pid: %s\n", optarg); 1629 1630 P = dtrace_proc_grab(g_dtp, pid, 0); 1631 if (P == NULL) 1632 dfatal(NULL); /* dtrace_errmsg() only */ 1633 1634 g_psv[g_psc++] = P; 1635 break; 1636 } 1637 } 1638 } 1639 1640 /* 1641 * In our fourth pass we finish g_cmdv[] by calling dc_func to convert 1642 * each string or file specification into a compiled program structure. 1643 */ 1644 for (i = 0; i < g_cmdc; i++) 1645 g_cmdv[i].dc_func(&g_cmdv[i]); 1646 1647 if (g_mode != DMODE_LIST) { 1648 if (dtrace_handle_err(g_dtp, &errhandler, NULL) == -1) 1649 dfatal("failed to establish error handler"); 1650 1651 if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1) 1652 dfatal("failed to establish drop handler"); 1653 1654 if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1) 1655 dfatal("failed to establish proc handler"); 1656 1657 if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1) 1658 dfatal("failed to establish setopt handler"); 1659 1660 if (g_ofp == NULL && 1661 dtrace_handle_buffered(g_dtp, &bufhandler, NULL) == -1) 1662 dfatal("failed to establish buffered handler"); 1663 } 1664 1665 (void) dtrace_getopt(g_dtp, "flowindent", &opt); 1666 g_flowindent = opt != DTRACEOPT_UNSET; 1667 1668 (void) dtrace_getopt(g_dtp, "grabanon", &opt); 1669 g_grabanon = opt != DTRACEOPT_UNSET; 1670 1671 (void) dtrace_getopt(g_dtp, "quiet", &opt); 1672 g_quiet = opt != DTRACEOPT_UNSET; 1673 1674 /* 1675 * Now make a fifth and final pass over the options that have been 1676 * turned into programs and saved in g_cmdv[], performing any mode- 1677 * specific processing. If g_mode is DMODE_EXEC, we will break out 1678 * of the switch() and continue on to the data processing loop. For 1679 * other modes, we will exit dtrace once mode-specific work is done. 1680 */ 1681 switch (g_mode) { 1682 case DMODE_EXEC: 1683 if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 1684 fatal("failed to open output file '%s'", g_ofile); 1685 1686 for (i = 0; i < g_cmdc; i++) 1687 exec_prog(&g_cmdv[i]); 1688 1689 if (done && !g_grabanon) { 1690 dtrace_close(g_dtp); 1691 return (g_status); 1692 } 1693 break; 1694 1695 case DMODE_ANON: 1696 if (g_ofile == NULL) 1697#if defined(sun) 1698 g_ofile = "/kernel/drv/dtrace.conf"; 1699#else 1700 /* 1701 * On FreeBSD, anonymous DOF data is written to 1702 * the DTrace DOF file that the boot loader will 1703 * read if booting with the DTrace option. 1704 */ 1705 g_ofile = "/boot/dtrace.dof"; 1706#endif 1707 1708 dof_prune(g_ofile); /* strip out any old DOF directives */ 1709#if defined(sun) 1710 etcsystem_prune(); /* string out any forceload directives */ 1711#endif 1712 1713 if (g_cmdc == 0) { 1714 dtrace_close(g_dtp); 1715 return (g_status); 1716 } 1717 1718 if ((g_ofp = fopen(g_ofile, "a")) == NULL) 1719 fatal("failed to open output file '%s'", g_ofile); 1720 1721 for (i = 0; i < g_cmdc; i++) { 1722 anon_prog(&g_cmdv[i], 1723 dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i); 1724 } 1725 1726 /* 1727 * Dump out the DOF corresponding to the error handler and the 1728 * current options as the final DOF property in the .conf file. 1729 */ 1730 anon_prog(NULL, dtrace_geterr_dof(g_dtp), i++); 1731 anon_prog(NULL, dtrace_getopt_dof(g_dtp), i++); 1732 1733 if (fclose(g_ofp) == EOF) 1734 fatal("failed to close output file '%s'", g_ofile); 1735 1736 /* 1737 * These messages would use notice() rather than error(), but 1738 * we don't want them suppressed when -A is run on a D program 1739 * that itself contains a #pragma D option quiet. 1740 */ 1741 error("saved anonymous enabling in %s\n", g_ofile); 1742#if defined(sun) 1743 etcsystem_add(); 1744 error("run update_drv(1M) or reboot to enable changes\n"); 1745#endif 1746 1747 dtrace_close(g_dtp); 1748 return (g_status); 1749 1750 case DMODE_LINK: 1751 if (g_cmdc == 0) { 1752 (void) fprintf(stderr, "%s: -G requires one or more " 1753 "scripts or enabling options\n", g_pname); 1754 dtrace_close(g_dtp); 1755 return (E_USAGE); 1756 } 1757 1758 for (i = 0; i < g_cmdc; i++) 1759 link_prog(&g_cmdv[i]); 1760 1761 if (g_cmdc > 1 && g_ofile != NULL) { 1762 char **objv = alloca(g_cmdc * sizeof (char *)); 1763 1764 for (i = 0; i < g_cmdc; i++) 1765 objv[i] = g_cmdv[i].dc_ofile; 1766 1767 if (dtrace_program_link(g_dtp, NULL, DTRACE_D_PROBES, 1768 g_ofile, g_cmdc, objv) != 0) 1769 dfatal(NULL); /* dtrace_errmsg() only */ 1770 } 1771 1772 dtrace_close(g_dtp); 1773 return (g_status); 1774 1775 case DMODE_LIST: 1776 if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 1777 fatal("failed to open output file '%s'", g_ofile); 1778 1779 oprintf("%5s %10s %17s %33s %s\n", 1780 "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME"); 1781 1782 for (i = 0; i < g_cmdc; i++) 1783 list_prog(&g_cmdv[i]); 1784 1785 if (g_cmdc == 0) 1786 (void) dtrace_probe_iter(g_dtp, NULL, list_probe, NULL); 1787 1788 dtrace_close(g_dtp); 1789 return (g_status); 1790 1791 case DMODE_HEADER: 1792 if (g_cmdc == 0) { 1793 (void) fprintf(stderr, "%s: -h requires one or more " 1794 "scripts or enabling options\n", g_pname); 1795 dtrace_close(g_dtp); 1796 return (E_USAGE); 1797 } 1798 1799 if (g_ofile == NULL) { 1800 char *p; 1801 1802 if (g_cmdc > 1) { 1803 (void) fprintf(stderr, "%s: -h requires an " 1804 "output file if multiple scripts are " 1805 "specified\n", g_pname); 1806 dtrace_close(g_dtp); 1807 return (E_USAGE); 1808 } 1809 1810 if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL || 1811 strcmp(p, ".d") != 0) { 1812 (void) fprintf(stderr, "%s: -h requires an " 1813 "output file if no scripts are " 1814 "specified\n", g_pname); 1815 dtrace_close(g_dtp); 1816 return (E_USAGE); 1817 } 1818 1819 p[0] = '\0'; /* strip .d suffix */ 1820 g_ofile = p = g_cmdv[0].dc_ofile; 1821 (void) snprintf(p, sizeof (g_cmdv[0].dc_ofile), 1822 "%s.h", basename(g_cmdv[0].dc_arg)); 1823 } 1824 1825 if ((g_ofp = fopen(g_ofile, "w")) == NULL) 1826 fatal("failed to open header file '%s'", g_ofile); 1827 1828 oprintf("/*\n * Generated by dtrace(1M).\n */\n\n"); 1829 1830 if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 || 1831 fclose(g_ofp) == EOF) 1832 dfatal("failed to create header file %s", g_ofile); 1833 1834 dtrace_close(g_dtp); 1835 return (g_status); 1836 } 1837 1838 /* 1839 * If -a and -Z were not specified and no probes have been matched, no 1840 * probe criteria was specified on the command line and we abort. 1841 */ 1842 if (g_total == 0 && !g_grabanon && !(g_cflags & DTRACE_C_ZDEFS)) 1843 dfatal("no probes %s\n", g_cmdc ? "matched" : "specified"); 1844 1845 /* 1846 * Start tracing. Once we dtrace_go(), reload any options that affect 1847 * our globals in case consuming anonymous state has changed them. 1848 */ 1849 go(); 1850 1851 (void) dtrace_getopt(g_dtp, "flowindent", &opt); 1852 g_flowindent = opt != DTRACEOPT_UNSET; 1853 1854 (void) dtrace_getopt(g_dtp, "grabanon", &opt); 1855 g_grabanon = opt != DTRACEOPT_UNSET; 1856 1857 (void) dtrace_getopt(g_dtp, "quiet", &opt); 1858 g_quiet = opt != DTRACEOPT_UNSET; 1859 1860 (void) dtrace_getopt(g_dtp, "destructive", &opt); 1861 if (opt != DTRACEOPT_UNSET) 1862 notice("allowing destructive actions\n"); 1863 1864 (void) sigemptyset(&act.sa_mask); 1865 act.sa_flags = 0; 1866 act.sa_handler = intr; 1867 1868 if (sigaction(SIGINT, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1869 (void) sigaction(SIGINT, &act, NULL); 1870 1871 if (sigaction(SIGTERM, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1872 (void) sigaction(SIGTERM, &act, NULL); 1873 1874#if !defined(sun) 1875 if (sigaction(SIGUSR1, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1876 (void) sigaction(SIGUSR1, &act, NULL); 1877#endif 1878 1879 /* 1880 * Now that tracing is active and we are ready to consume trace data, 1881 * continue any grabbed or created processes, setting them running 1882 * using the /proc control mechanism inside of libdtrace. 1883 */ 1884 for (i = 0; i < g_psc; i++) 1885 dtrace_proc_continue(g_dtp, g_psv[i]); 1886 1887 g_pslive = g_psc; /* count for prochandler() */ 1888 1889 do { 1890 if (!g_intr && !done) 1891 dtrace_sleep(g_dtp); 1892 1893 if (g_newline) { 1894 /* 1895 * Output a newline just to make the output look 1896 * slightly cleaner. Note that we do this even in 1897 * "quiet" mode... 1898 */ 1899 oprintf("\n"); 1900 g_newline = 0; 1901 } 1902 1903 if (done || g_intr || (g_psc != 0 && g_pslive == 0)) { 1904 done = 1; 1905 if (dtrace_stop(g_dtp) == -1) 1906 dfatal("couldn't stop tracing"); 1907 } 1908 1909 switch (dtrace_work(g_dtp, g_ofp, chew, chewrec, NULL)) { 1910 case DTRACE_WORKSTATUS_DONE: 1911 done = 1; 1912 break; 1913 case DTRACE_WORKSTATUS_OKAY: 1914 break; 1915 default: 1916 if (!g_impatient && dtrace_errno(g_dtp) != EINTR) 1917 dfatal("processing aborted"); 1918 } 1919 1920 if (g_ofp != NULL && fflush(g_ofp) == EOF) 1921 clearerr(g_ofp); 1922 } while (!done); 1923 1924 oprintf("\n"); 1925 1926 if (!g_impatient) { 1927 if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 && 1928 dtrace_errno(g_dtp) != EINTR) 1929 dfatal("failed to print aggregations"); 1930 } 1931 1932 dtrace_close(g_dtp); 1933 return (g_status); 1934} 1935