📄 dtrace.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dtrace.c 1.15 04/12/18 SMI"#include <sys/types.h>#include <sys/stat.h>#include <sys/wait.h>#include <dtrace.h>#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <strings.h>#include <unistd.h>#include <limits.h>#include <fcntl.h>#include <errno.h>#include <signal.h>#include <alloca.h>#include <libgen.h>#include <libproc.h>typedef struct dtrace_cmd { void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */ dtrace_probespec_t dc_spec; /* probe specifier context */ char *dc_arg; /* argument from main argv */ const char *dc_name; /* name for error messages */ const char *dc_desc; /* desc for error messages */ dtrace_prog_t *dc_prog; /* program compiled from arg */} dtrace_cmd_t;#define DMODE_VERS 0 /* display version information and exit (-V) */#define DMODE_EXEC 1 /* compile program for enabling (-a/e/E) */#define DMODE_ANON 2 /* compile program for anonymous tracing (-A) */#define DMODE_LINK 3 /* compile program for linking with ELF (-G) */#define DMODE_LIST 4 /* compile program and list probes (-l) */#define E_SUCCESS 0#define E_ERROR 1#define E_USAGE 2static const char DTRACE_OPTSTR[] = "3:6:aAb:c:CD:ef:FGHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z";static int g_fd;static char **g_argv;static int g_argc;static char **g_objv;static int g_objc;static dtrace_cmd_t *g_cmdv;static int g_cmdc;static struct ps_prochandle **g_psv;static int g_psc;static int g_pslive;static char *g_pname;static int g_quiet;static int g_flowindent;static int g_intr;static int g_impatient;static int g_newline;static int g_total;static int g_cflags;static int g_oflags;static int g_verbose;static int g_exec = 1;static int g_mode = DMODE_EXEC;static int g_status = E_SUCCESS;static int g_grabanon = 0;static const char *g_ofile = NULL;static FILE *g_ofp = stdout;static dtrace_hdl_t *g_dtp;static char *g_etcfile = "/etc/system";static const char *g_etcbegin = "* vvvv Added by DTrace";static const char *g_etcend = "* ^^^^ Added by DTrace";static const char *g_etc[] = {"*","* The following forceload directives were added by dtrace(1M) to allow for","* tracing during boot. If these directives are removed, the system will","* continue to function, but tracing will not occur during boot as desired.","* To remove these directives (and this block comment) automatically, run","* \"dtrace -A\" without additional arguments. See the \"Anonymous Tracing\"","* chapter of the Solaris Dynamic Tracing Guide for details.","*",NULL };static intusage(FILE *fp){ static const char predact[] = "[[ predicate ] action ]"; (void) fprintf(fp, "Usage: %s [-32|-64] [-aACeFGHlqSvVwZ] " "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " "[-o output] [-p pid] [-s script] [-U name]\n\t" "[-x opt[=val]] [-X a|c|s|t]\n\n" "\t[-P provider %s]\n" "\t[-m [ provider: ] module %s]\n" "\t[-f [[ provider: ] module: ] func %s]\n" "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" "\t[-i probe-id %s] [ args ... ]\n\n", g_pname, predact, predact, predact, predact, predact); (void) fprintf(fp, "\tpredicate -> '/' D-expression '/'\n"); (void) fprintf(fp, "\t action -> '{' D-statements '}'\n"); (void) fprintf(fp, "\n" "\t-32 generate 32-bit D programs and ELF files\n" "\t-64 generate 64-bit D programs and ELF files\n\n" "\t-a claim anonymous tracing state\n" "\t-A generate driver.conf(4) directives for anonymous tracing\n" "\t-b set trace buffer size\n" "\t-c run specified command and exit upon its completion\n" "\t-C run cpp(1) preprocessor on script files\n" "\t-D define symbol when invoking preprocessor\n" "\t-e exit after compiling request but prior to enabling probes\n" "\t-f enable or list probes matching the specified function name\n" "\t-F coalesce trace output by function\n" "\t-G generate an ELF file containing embedded dtrace program\n" "\t-H print included files when invoking preprocessor\n" "\t-i enable or list probes matching the specified probe id\n" "\t-I add include directory to preprocessor search path\n" "\t-l list probes matching specified criteria\n" "\t-L add library directory to library search path\n" "\t-m enable or list probes matching the specified module name\n" "\t-n enable or list probes matching the specified probe name\n" "\t-o set output file\n" "\t-p grab specified process-ID and cache its symbol tables\n" "\t-P enable or list probes matching the specified provider name\n" "\t-q set quiet mode (only output explicitly traced data)\n" "\t-s enable or list probes according to the specified D script\n" "\t-S print D compiler intermediate code\n" "\t-U undefine symbol when invoking preprocessor\n" "\t-v set verbose mode (report program stability attributes)\n" "\t-V report DTrace API version\n" "\t-w permit destructive actions\n" "\t-x enable or modify compiler and tracing options\n" "\t-X specify ISO C conformance settings for preprocessor\n" "\t-Z permit probe descriptions that match zero probes\n"); return (E_USAGE);}static voidverror(const char *fmt, va_list ap){ int error = errno; (void) fprintf(stderr, "%s: ", g_pname); (void) vfprintf(stderr, fmt, ap); if (fmt[strlen(fmt) - 1] != '\n') (void) fprintf(stderr, ": %s\n", strerror(error));}/*PRINTFLIKE1*/static voidfatal(const char *fmt, ...){ va_list ap; va_start(ap, fmt); verror(fmt, ap); va_end(ap); exit(E_ERROR);}/*PRINTFLIKE1*/static voiddfatal(const char *fmt, ...){ va_list ap; va_start(ap, fmt); (void) fprintf(stderr, "%s: ", g_pname); if (fmt != NULL) (void) vfprintf(stderr, fmt, ap); va_end(ap); if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { (void) fprintf(stderr, ": %s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } else if (fmt == NULL) { (void) fprintf(stderr, "%s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } exit(E_ERROR);}/*PRINTFLIKE1*/static voiderror(const char *fmt, ...){ va_list ap; va_start(ap, fmt); verror(fmt, ap); va_end(ap);}/*PRINTFLIKE1*/static voidnotice(const char *fmt, ...){ va_list ap; if (g_quiet) return; /* -q or quiet pragma suppresses notice()s */ va_start(ap, fmt); verror(fmt, ap); va_end(ap);}/*PRINTFLIKE1*/static voidoprintf(const char *fmt, ...){ va_list ap; int n; va_start(ap, fmt); n = vfprintf(g_ofp, fmt, ap); va_end(ap); if (n < 0) { if (errno != EINTR) { fatal("failed to write to %s", g_ofile ? g_ofile : "<stdout>"); } clearerr(g_ofp); }}static char **make_argv(char *s){ const char *ws = "\f\n\r\t\v "; char **argv = malloc(sizeof (char *) * (strlen(s) / 2 + 1)); int argc = 0; char *p = s; if (argv == NULL) return (NULL); for (p = strtok(s, ws); p != NULL; p = strtok(NULL, ws)) argv[argc++] = p; if (argc == 0) argv[argc++] = s; argv[argc] = NULL; return (argv);}static voidlist_probes(void){ dtrace_probedesc_t probe; bzero(&probe, sizeof (probe)); while (ioctl(g_fd, DTRACEIOC_PROBES, &probe) != -1) { oprintf("%5d %10s %17s %33s %s\n", probe.dtpd_id, probe.dtpd_provider, probe.dtpd_mod, probe.dtpd_func, probe.dtpd_name); probe.dtpd_id++; }}static voiddof_prune(const char *fname){ struct stat sbuf; size_t sz, i, j, mark, len; char *buf; int msg = 0, fd; if ((fd = open(fname, O_RDONLY)) == -1) { /* * This is okay only if the file doesn't exist at all. */ if (errno != ENOENT) fatal("failed to open %s", fname); return; } if (fstat(fd, &sbuf) == -1) fatal("failed to fstat %s", fname); if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) fatal("failed to allocate memory for %s", fname); if (read(fd, buf, sz) != sz) fatal("failed to read %s", fname); buf[sz] = '\0'; (void) close(fd); if ((fd = open(fname, O_WRONLY | O_TRUNC)) == -1) fatal("failed to open %s for writing", fname); len = strlen("dof-data-"); for (mark = 0, i = 0; i < sz; i++) { if (strncmp(&buf[i], "dof-data-", len) != 0) continue; /* * This is only a match if it's in the 0th column. */ if (i != 0 && buf[i - 1] != '\n') continue; if (msg++ == 0) { error("cleaned up old anonymous " "enabling in %s\n", fname); } /* * We have a match. First write out our data up until now. */ if (i != mark) { if (write(fd, &buf[mark], i - mark) != i - mark) fatal("failed to write to %s", fname); } /* * Now scan forward until we scan past a newline. */ for (j = i; j < sz && buf[j] != '\n'; j++) continue; /* * Reset our mark. */ if ((mark = j + 1) >= sz) break; i = j; } if (mark < sz) { if (write(fd, &buf[mark], sz - mark) != sz - mark) fatal("failed to write to %s", fname); } (void) close(fd); free(buf);}static voidetcsystem_prune(void){ struct stat sbuf; size_t sz; char *buf, *start, *end; int fd; char *fname = g_etcfile, *tmpname; if ((fd = open(fname, O_RDONLY)) == -1) fatal("failed to open %s", fname); if (fstat(fd, &sbuf) == -1) fatal("failed to fstat %s", fname); if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) fatal("failed to allocate memory for %s", fname); if (read(fd, buf, sz) != sz) fatal("failed to read %s", fname); buf[sz] = '\0'; (void) close(fd); if ((start = strstr(buf, g_etcbegin)) == NULL) goto out; if (strlen(buf) != sz) { fatal("embedded nul byte in %s; manual repair of %s " "required\n", fname, fname); } if (strstr(start + 1, g_etcbegin) != NULL) { fatal("multiple start sentinels in %s; manual repair of %s " "required\n", fname, fname); } if ((end = strstr(buf, g_etcend)) == NULL) { fatal("missing end sentinel in %s; manual repair of %s " "required\n", fname, fname); } if (start > end) { fatal("end sentinel preceeds start sentinel in %s; manual " "repair of %s required\n", fname, fname); } end += strlen(g_etcend) + 1; bcopy(end, start, strlen(end) + 1); tmpname = alloca(sz = strlen(fname) + 80); (void) snprintf(tmpname, sz, "%s.dtrace.%d", fname, getpid()); if ((fd = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, sbuf.st_mode)) == -1) fatal("failed to create %s", tmpname); if (write(fd, buf, strlen(buf)) < strlen(buf)) { (void) unlink(tmpname); fatal("failed to write to %s", tmpname); } (void) close(fd); if (chown(tmpname, sbuf.st_uid, sbuf.st_gid) != 0) { (void) unlink(tmpname); fatal("failed to chown(2) %s to uid %d, gid %d", tmpname, (int)sbuf.st_uid, (int)sbuf.st_gid); } if (rename(tmpname, fname) == -1) fatal("rename of %s to %s failed", tmpname, fname); error("cleaned up forceload directives in %s\n", fname);out: free(buf);}static voidetcsystem_add(void){ const char *mods[20]; int nmods, line; if ((g_ofp = fopen(g_ofile = g_etcfile, "a")) == NULL) fatal("failed to open output file '%s'", g_ofile); oprintf("%s\n", g_etcbegin); for (line = 0; g_etc[line] != NULL; line++) oprintf("%s\n", g_etc[line]); nmods = dtrace_provider_modules(g_dtp, mods, sizeof (mods) / sizeof (char *) - 1); if (nmods >= sizeof (mods) / sizeof (char *)) fatal("unexpectedly large number of modules!"); mods[nmods++] = "dtrace"; for (line = 0; line < nmods; line++) oprintf("forceload: drv/%s\n", mods[line]); oprintf("%s\n", g_etcend); if (fclose(g_ofp) == EOF) fatal("failed to close output file '%s'", g_ofile); error("added forceload directives to %s\n", g_ofile);}/* * Execute the specified program by enabling the corresponding instrumentation. * If -e has been specified, we get the program info but do not enable it. If * -v has been specified, we print a stability report for the program. */static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -