12be1a816SJohn Birrell /* 22be1a816SJohn Birrell * CDDL HEADER START 32be1a816SJohn Birrell * 42be1a816SJohn Birrell * The contents of this file are subject to the terms of the 52be1a816SJohn Birrell * Common Development and Distribution License (the "License"). 62be1a816SJohn Birrell * You may not use this file except in compliance with the License. 72be1a816SJohn Birrell * 82be1a816SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92be1a816SJohn Birrell * or http://www.opensolaris.org/os/licensing. 102be1a816SJohn Birrell * See the License for the specific language governing permissions 112be1a816SJohn Birrell * and limitations under the License. 122be1a816SJohn Birrell * 132be1a816SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 142be1a816SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152be1a816SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 162be1a816SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 172be1a816SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 182be1a816SJohn Birrell * 192be1a816SJohn Birrell * CDDL HEADER END 202be1a816SJohn Birrell */ 212be1a816SJohn Birrell 222be1a816SJohn Birrell /* 232be1a816SJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 242be1a816SJohn Birrell * Use is subject to license terms. 252be1a816SJohn Birrell */ 2609e6105fSMark Johnston /* 2709e6105fSMark Johnston * Copyright (c) 2012 by Delphix. All rights reserved. 288e648814SRui Paulo * Copyright (c) 2013, Joyent, Inc. All rights reserved. 2993f27766SDomagoj Stolfa * Copyright (c) 2023, Domagoj Stolfa. All rights reserved. 3009e6105fSMark Johnston */ 312be1a816SJohn Birrell 322be1a816SJohn Birrell #include <sys/types.h> 332be1a816SJohn Birrell #include <sys/stat.h> 342be1a816SJohn Birrell #include <sys/wait.h> 352be1a816SJohn Birrell 362be1a816SJohn Birrell #include <dtrace.h> 372be1a816SJohn Birrell #include <stdlib.h> 382be1a816SJohn Birrell #include <stdarg.h> 392be1a816SJohn Birrell #include <stdio.h> 40a6847cf6SJohn Birrell #include <string.h> 412be1a816SJohn Birrell #include <strings.h> 422be1a816SJohn Birrell #include <unistd.h> 432be1a816SJohn Birrell #include <limits.h> 442be1a816SJohn Birrell #include <fcntl.h> 452be1a816SJohn Birrell #include <errno.h> 462be1a816SJohn Birrell #include <signal.h> 47bc96366cSSteven Hartland #ifdef illumos 482be1a816SJohn Birrell #include <alloca.h> 49a6847cf6SJohn Birrell #endif 502be1a816SJohn Birrell #include <libgen.h> 51bc96366cSSteven Hartland #ifdef illumos 522be1a816SJohn Birrell #include <libproc.h> 53a6847cf6SJohn Birrell #endif 54b5290286SMark Johnston #ifdef __FreeBSD__ 55b946eedeSAndriy Gapon #include <locale.h> 56b5290286SMark Johnston #include <spawn.h> 57b5290286SMark Johnston #endif 582be1a816SJohn Birrell 5993f27766SDomagoj Stolfa #undef NORETURN /* needed because libxo redefines it */ 6093f27766SDomagoj Stolfa #include <libxo/xo.h> 6193f27766SDomagoj Stolfa 622be1a816SJohn Birrell typedef struct dtrace_cmd { 632be1a816SJohn Birrell void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */ 642be1a816SJohn Birrell dtrace_probespec_t dc_spec; /* probe specifier context */ 652be1a816SJohn Birrell char *dc_arg; /* argument from main argv */ 662be1a816SJohn Birrell const char *dc_name; /* name for error messages */ 672be1a816SJohn Birrell const char *dc_desc; /* desc for error messages */ 682be1a816SJohn Birrell dtrace_prog_t *dc_prog; /* program compiled from arg */ 692be1a816SJohn Birrell char dc_ofile[PATH_MAX]; /* derived output file name */ 702be1a816SJohn Birrell } dtrace_cmd_t; 712be1a816SJohn Birrell 722be1a816SJohn Birrell #define DMODE_VERS 0 /* display version information and exit (-V) */ 732be1a816SJohn Birrell #define DMODE_EXEC 1 /* compile program for enabling (-a/e/E) */ 742be1a816SJohn Birrell #define DMODE_ANON 2 /* compile program for anonymous tracing (-A) */ 752be1a816SJohn Birrell #define DMODE_LINK 3 /* compile program for linking with ELF (-G) */ 762be1a816SJohn Birrell #define DMODE_LIST 4 /* compile program and list probes (-l) */ 772be1a816SJohn Birrell #define DMODE_HEADER 5 /* compile program for headergen (-h) */ 782be1a816SJohn Birrell 792be1a816SJohn Birrell #define E_SUCCESS 0 802be1a816SJohn Birrell #define E_ERROR 1 812be1a816SJohn Birrell #define E_USAGE 2 822be1a816SJohn Birrell 832be1a816SJohn Birrell static const char DTRACE_OPTSTR[] = 8493f27766SDomagoj Stolfa "3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:Op:P:qs:SU:vVwx:X:Z"; 852be1a816SJohn Birrell 862be1a816SJohn Birrell static char **g_argv; 872be1a816SJohn Birrell static int g_argc; 882be1a816SJohn Birrell static char **g_objv; 892be1a816SJohn Birrell static int g_objc; 902be1a816SJohn Birrell static dtrace_cmd_t *g_cmdv; 912be1a816SJohn Birrell static int g_cmdc; 922be1a816SJohn Birrell static struct ps_prochandle **g_psv; 932be1a816SJohn Birrell static int g_psc; 942be1a816SJohn Birrell static int g_pslive; 952be1a816SJohn Birrell static char *g_pname; 962be1a816SJohn Birrell static int g_quiet; 972be1a816SJohn Birrell static int g_flowindent; 982be1a816SJohn Birrell static int g_intr; 992be1a816SJohn Birrell static int g_impatient; 1002be1a816SJohn Birrell static int g_newline; 101be9cb745SMark Johnston #ifdef __FreeBSD__ 102be9cb745SMark Johnston static int g_siginfo; 103be9cb745SMark Johnston #endif 1042be1a816SJohn Birrell static int g_total; 1052be1a816SJohn Birrell static int g_cflags; 1062be1a816SJohn Birrell static int g_oflags; 1072be1a816SJohn Birrell static int g_verbose; 1082be1a816SJohn Birrell static int g_exec = 1; 1092be1a816SJohn Birrell static int g_mode = DMODE_EXEC; 1102be1a816SJohn Birrell static int g_status = E_SUCCESS; 1112be1a816SJohn Birrell static int g_grabanon = 0; 1122be1a816SJohn Birrell static const char *g_ofile = NULL; 113a6847cf6SJohn Birrell static FILE *g_ofp; 1142be1a816SJohn Birrell static dtrace_hdl_t *g_dtp; 115bc96366cSSteven Hartland #ifdef illumos 1162be1a816SJohn Birrell static char *g_etcfile = "/etc/system"; 1172be1a816SJohn Birrell static const char *g_etcbegin = "* vvvv Added by DTrace"; 1182be1a816SJohn Birrell static const char *g_etcend = "* ^^^^ Added by DTrace"; 1192be1a816SJohn Birrell 1202be1a816SJohn Birrell static const char *g_etc[] = { 1212be1a816SJohn Birrell "*", 1222be1a816SJohn Birrell "* The following forceload directives were added by dtrace(1M) to allow for", 1232be1a816SJohn Birrell "* tracing during boot. If these directives are removed, the system will", 1242be1a816SJohn Birrell "* continue to function, but tracing will not occur during boot as desired.", 1252be1a816SJohn Birrell "* To remove these directives (and this block comment) automatically, run", 1262be1a816SJohn Birrell "* \"dtrace -A\" without additional arguments. See the \"Anonymous Tracing\"", 1272be1a816SJohn Birrell "* chapter of the Solaris Dynamic Tracing Guide for details.", 1282be1a816SJohn Birrell "*", 1292be1a816SJohn Birrell NULL }; 130a6847cf6SJohn Birrell #endif 1312be1a816SJohn Birrell 1322be1a816SJohn Birrell static int 1332be1a816SJohn Birrell usage(FILE *fp) 1342be1a816SJohn Birrell { 1352be1a816SJohn Birrell static const char predact[] = "[[ predicate ] action ]"; 1362be1a816SJohn Birrell 1371e136a9cSChristos Margiolis (void) fprintf(fp, "Usage: %s [-32|-64] [-aACdeFGhHlqSvVwZ] " 1382be1a816SJohn Birrell "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " 1392be1a816SJohn Birrell "[-o output] [-p pid] [-s script] [-U name]\n\t" 1402be1a816SJohn Birrell "[-x opt[=val]] [-X a|c|s|t]\n\n" 1412be1a816SJohn Birrell "\t[-P provider %s]\n" 1422be1a816SJohn Birrell "\t[-m [ provider: ] module %s]\n" 1432be1a816SJohn Birrell "\t[-f [[ provider: ] module: ] func %s]\n" 1442be1a816SJohn Birrell "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" 1452be1a816SJohn Birrell "\t[-i probe-id %s] [ args ... ]\n\n", g_pname, 1462be1a816SJohn Birrell predact, predact, predact, predact, predact); 1472be1a816SJohn Birrell 1482be1a816SJohn Birrell (void) fprintf(fp, "\tpredicate -> '/' D-expression '/'\n"); 1492be1a816SJohn Birrell (void) fprintf(fp, "\t action -> '{' D-statements '}'\n"); 1502be1a816SJohn Birrell 1512be1a816SJohn Birrell (void) fprintf(fp, "\n" 1522be1a816SJohn Birrell "\t-32 generate 32-bit D programs and ELF files\n" 1532be1a816SJohn Birrell "\t-64 generate 64-bit D programs and ELF files\n\n" 1542be1a816SJohn Birrell "\t-a claim anonymous tracing state\n" 1552be1a816SJohn Birrell "\t-A generate driver.conf(4) directives for anonymous tracing\n" 1562be1a816SJohn Birrell "\t-b set trace buffer size\n" 1572be1a816SJohn Birrell "\t-c run specified command and exit upon its completion\n" 1582be1a816SJohn Birrell "\t-C run cpp(1) preprocessor on script files\n" 1591e136a9cSChristos Margiolis "\t-d dump script after syntactic transformations\n" 1602be1a816SJohn Birrell "\t-D define symbol when invoking preprocessor\n" 1612be1a816SJohn Birrell "\t-e exit after compiling request but prior to enabling probes\n" 1622be1a816SJohn Birrell "\t-f enable or list probes matching the specified function name\n" 1632be1a816SJohn Birrell "\t-F coalesce trace output by function\n" 1642be1a816SJohn Birrell "\t-G generate an ELF file containing embedded dtrace program\n" 1652be1a816SJohn Birrell "\t-h generate a header file with definitions for static probes\n" 1662be1a816SJohn Birrell "\t-H print included files when invoking preprocessor\n" 1672be1a816SJohn Birrell "\t-i enable or list probes matching the specified probe id\n" 1682be1a816SJohn Birrell "\t-I add include directory to preprocessor search path\n" 1692be1a816SJohn Birrell "\t-l list probes matching specified criteria\n" 1702be1a816SJohn Birrell "\t-L add library directory to library search path\n" 1712be1a816SJohn Birrell "\t-m enable or list probes matching the specified module name\n" 1722be1a816SJohn Birrell "\t-n enable or list probes matching the specified probe name\n" 1732be1a816SJohn Birrell "\t-o set output file\n" 17493f27766SDomagoj Stolfa "\t-O print output upon exiting (specific to oformat)\n" 1752be1a816SJohn Birrell "\t-p grab specified process-ID and cache its symbol tables\n" 1762be1a816SJohn Birrell "\t-P enable or list probes matching the specified provider name\n" 1772be1a816SJohn Birrell "\t-q set quiet mode (only output explicitly traced data)\n" 1782be1a816SJohn Birrell "\t-s enable or list probes according to the specified D script\n" 1792be1a816SJohn Birrell "\t-S print D compiler intermediate code\n" 1802be1a816SJohn Birrell "\t-U undefine symbol when invoking preprocessor\n" 1812be1a816SJohn Birrell "\t-v set verbose mode (report stability attributes, arguments)\n" 1822be1a816SJohn Birrell "\t-V report DTrace API version\n" 1832be1a816SJohn Birrell "\t-w permit destructive actions\n" 1842be1a816SJohn Birrell "\t-x enable or modify compiler and tracing options\n" 1852be1a816SJohn Birrell "\t-X specify ISO C conformance settings for preprocessor\n" 1862be1a816SJohn Birrell "\t-Z permit probe descriptions that match zero probes\n"); 1872be1a816SJohn Birrell 1882be1a816SJohn Birrell return (E_USAGE); 1892be1a816SJohn Birrell } 1902be1a816SJohn Birrell 1912be1a816SJohn Birrell static void 1922be1a816SJohn Birrell verror(const char *fmt, va_list ap) 1932be1a816SJohn Birrell { 1942be1a816SJohn Birrell int error = errno; 1952be1a816SJohn Birrell 1962be1a816SJohn Birrell (void) fprintf(stderr, "%s: ", g_pname); 1972be1a816SJohn Birrell (void) vfprintf(stderr, fmt, ap); 1982be1a816SJohn Birrell 1992be1a816SJohn Birrell if (fmt[strlen(fmt) - 1] != '\n') 2002be1a816SJohn Birrell (void) fprintf(stderr, ": %s\n", strerror(error)); 2012be1a816SJohn Birrell } 2022be1a816SJohn Birrell 2032be1a816SJohn Birrell /*PRINTFLIKE1*/ 2042be1a816SJohn Birrell static void 2052be1a816SJohn Birrell fatal(const char *fmt, ...) 2062be1a816SJohn Birrell { 2072be1a816SJohn Birrell va_list ap; 2082be1a816SJohn Birrell 2092be1a816SJohn Birrell va_start(ap, fmt); 2102be1a816SJohn Birrell verror(fmt, ap); 2112be1a816SJohn Birrell va_end(ap); 2122be1a816SJohn Birrell 213cf4e0cc1SJustin T. Gibbs /* 214cf4e0cc1SJustin T. Gibbs * Close the DTrace handle to ensure that any controlled processes are 215cf4e0cc1SJustin T. Gibbs * correctly restored and continued. 216cf4e0cc1SJustin T. Gibbs */ 217cf4e0cc1SJustin T. Gibbs if (g_dtp) 218cf4e0cc1SJustin T. Gibbs dtrace_close(g_dtp); 219cf4e0cc1SJustin T. Gibbs 2202be1a816SJohn Birrell exit(E_ERROR); 2212be1a816SJohn Birrell } 2222be1a816SJohn Birrell 2232be1a816SJohn Birrell /*PRINTFLIKE1*/ 2242be1a816SJohn Birrell static void 2252be1a816SJohn Birrell dfatal(const char *fmt, ...) 2262be1a816SJohn Birrell { 227bc96366cSSteven Hartland #if !defined(illumos) && defined(NEED_ERRLOC) 228a6847cf6SJohn Birrell char *p_errfile = NULL; 229a6847cf6SJohn Birrell int errline = 0; 230a6847cf6SJohn Birrell #endif 2312be1a816SJohn Birrell va_list ap; 2322be1a816SJohn Birrell 2332be1a816SJohn Birrell va_start(ap, fmt); 2342be1a816SJohn Birrell 2352be1a816SJohn Birrell (void) fprintf(stderr, "%s: ", g_pname); 2362be1a816SJohn Birrell if (fmt != NULL) 2372be1a816SJohn Birrell (void) vfprintf(stderr, fmt, ap); 2382be1a816SJohn Birrell 2392be1a816SJohn Birrell va_end(ap); 2402be1a816SJohn Birrell 2412be1a816SJohn Birrell if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { 2422be1a816SJohn Birrell (void) fprintf(stderr, ": %s\n", 2432be1a816SJohn Birrell dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 2442be1a816SJohn Birrell } else if (fmt == NULL) { 2452be1a816SJohn Birrell (void) fprintf(stderr, "%s\n", 2462be1a816SJohn Birrell dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 2472be1a816SJohn Birrell } 248bc96366cSSteven Hartland #if !defined(illumos) && defined(NEED_ERRLOC) 249a6847cf6SJohn Birrell dt_get_errloc(g_dtp, &p_errfile, &errline); 250a6847cf6SJohn Birrell if (p_errfile != NULL) 251a6847cf6SJohn Birrell printf("File '%s', line %d\n", p_errfile, errline); 252a6847cf6SJohn Birrell #endif 2532be1a816SJohn Birrell 2542be1a816SJohn Birrell /* 2552be1a816SJohn Birrell * Close the DTrace handle to ensure that any controlled processes are 2562be1a816SJohn Birrell * correctly restored and continued. 2572be1a816SJohn Birrell */ 2582be1a816SJohn Birrell dtrace_close(g_dtp); 2592be1a816SJohn Birrell 2602be1a816SJohn Birrell exit(E_ERROR); 2612be1a816SJohn Birrell } 2622be1a816SJohn Birrell 2632be1a816SJohn Birrell /*PRINTFLIKE1*/ 2642be1a816SJohn Birrell static void 2652be1a816SJohn Birrell error(const char *fmt, ...) 2662be1a816SJohn Birrell { 2672be1a816SJohn Birrell va_list ap; 2682be1a816SJohn Birrell 2692be1a816SJohn Birrell va_start(ap, fmt); 2702be1a816SJohn Birrell verror(fmt, ap); 2712be1a816SJohn Birrell va_end(ap); 2722be1a816SJohn Birrell } 2732be1a816SJohn Birrell 2742be1a816SJohn Birrell /*PRINTFLIKE1*/ 2752be1a816SJohn Birrell static void 2762be1a816SJohn Birrell notice(const char *fmt, ...) 2772be1a816SJohn Birrell { 2782be1a816SJohn Birrell va_list ap; 2792be1a816SJohn Birrell 2802be1a816SJohn Birrell if (g_quiet) 2812be1a816SJohn Birrell return; /* -q or quiet pragma suppresses notice()s */ 2822be1a816SJohn Birrell 2832be1a816SJohn Birrell va_start(ap, fmt); 2842be1a816SJohn Birrell verror(fmt, ap); 2852be1a816SJohn Birrell va_end(ap); 2862be1a816SJohn Birrell } 2872be1a816SJohn Birrell 2882be1a816SJohn Birrell /*PRINTFLIKE1*/ 2892be1a816SJohn Birrell static void 2902be1a816SJohn Birrell oprintf(const char *fmt, ...) 2912be1a816SJohn Birrell { 2922be1a816SJohn Birrell va_list ap; 2932be1a816SJohn Birrell int n; 2942be1a816SJohn Birrell 2952be1a816SJohn Birrell if (g_ofp == NULL) 2962be1a816SJohn Birrell return; 2972be1a816SJohn Birrell 2982be1a816SJohn Birrell va_start(ap, fmt); 2992be1a816SJohn Birrell n = vfprintf(g_ofp, fmt, ap); 3002be1a816SJohn Birrell va_end(ap); 3012be1a816SJohn Birrell 3022be1a816SJohn Birrell if (n < 0) { 3032be1a816SJohn Birrell if (errno != EINTR) { 3042be1a816SJohn Birrell fatal("failed to write to %s", 3052be1a816SJohn Birrell g_ofile ? g_ofile : "<stdout>"); 3062be1a816SJohn Birrell } 3072be1a816SJohn Birrell clearerr(g_ofp); 3082be1a816SJohn Birrell } 3092be1a816SJohn Birrell } 3102be1a816SJohn Birrell 3112be1a816SJohn Birrell static char ** 3122be1a816SJohn Birrell make_argv(char *s) 3132be1a816SJohn Birrell { 3142be1a816SJohn Birrell const char *ws = "\f\n\r\t\v "; 3152be1a816SJohn Birrell char **argv = malloc(sizeof (char *) * (strlen(s) / 2 + 1)); 3162be1a816SJohn Birrell int argc = 0; 3172be1a816SJohn Birrell char *p = s; 3182be1a816SJohn Birrell 3192be1a816SJohn Birrell if (argv == NULL) 3202be1a816SJohn Birrell return (NULL); 3212be1a816SJohn Birrell 3222be1a816SJohn Birrell for (p = strtok(s, ws); p != NULL; p = strtok(NULL, ws)) 3232be1a816SJohn Birrell argv[argc++] = p; 3242be1a816SJohn Birrell 3252be1a816SJohn Birrell if (argc == 0) 3262be1a816SJohn Birrell argv[argc++] = s; 3272be1a816SJohn Birrell 3282be1a816SJohn Birrell argv[argc] = NULL; 3292be1a816SJohn Birrell return (argv); 3302be1a816SJohn Birrell } 3312be1a816SJohn Birrell 3322be1a816SJohn Birrell static void 3332be1a816SJohn Birrell dof_prune(const char *fname) 3342be1a816SJohn Birrell { 3352be1a816SJohn Birrell struct stat sbuf; 3362be1a816SJohn Birrell size_t sz, i, j, mark, len; 3372be1a816SJohn Birrell char *buf; 3382be1a816SJohn Birrell int msg = 0, fd; 3392be1a816SJohn Birrell 3402be1a816SJohn Birrell if ((fd = open(fname, O_RDONLY)) == -1) { 3412be1a816SJohn Birrell /* 3422be1a816SJohn Birrell * This is okay only if the file doesn't exist at all. 3432be1a816SJohn Birrell */ 3442be1a816SJohn Birrell if (errno != ENOENT) 3452be1a816SJohn Birrell fatal("failed to open %s", fname); 3462be1a816SJohn Birrell return; 3472be1a816SJohn Birrell } 3482be1a816SJohn Birrell 3492be1a816SJohn Birrell if (fstat(fd, &sbuf) == -1) 3502be1a816SJohn Birrell fatal("failed to fstat %s", fname); 3512be1a816SJohn Birrell 3522be1a816SJohn Birrell if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) 3532be1a816SJohn Birrell fatal("failed to allocate memory for %s", fname); 3542be1a816SJohn Birrell 3552be1a816SJohn Birrell if (read(fd, buf, sz) != sz) 3562be1a816SJohn Birrell fatal("failed to read %s", fname); 3572be1a816SJohn Birrell 3582be1a816SJohn Birrell buf[sz] = '\0'; 3592be1a816SJohn Birrell (void) close(fd); 3602be1a816SJohn Birrell 3612be1a816SJohn Birrell if ((fd = open(fname, O_WRONLY | O_TRUNC)) == -1) 3622be1a816SJohn Birrell fatal("failed to open %s for writing", fname); 3632be1a816SJohn Birrell 3642be1a816SJohn Birrell len = strlen("dof-data-"); 3652be1a816SJohn Birrell 3662be1a816SJohn Birrell for (mark = 0, i = 0; i < sz; i++) { 3672be1a816SJohn Birrell if (strncmp(&buf[i], "dof-data-", len) != 0) 3682be1a816SJohn Birrell continue; 3692be1a816SJohn Birrell 3702be1a816SJohn Birrell /* 3712be1a816SJohn Birrell * This is only a match if it's in the 0th column. 3722be1a816SJohn Birrell */ 3732be1a816SJohn Birrell if (i != 0 && buf[i - 1] != '\n') 3742be1a816SJohn Birrell continue; 3752be1a816SJohn Birrell 3762be1a816SJohn Birrell if (msg++ == 0) { 3772be1a816SJohn Birrell error("cleaned up old anonymous " 3782be1a816SJohn Birrell "enabling in %s\n", fname); 3792be1a816SJohn Birrell } 3802be1a816SJohn Birrell 3812be1a816SJohn Birrell /* 3822be1a816SJohn Birrell * We have a match. First write out our data up until now. 3832be1a816SJohn Birrell */ 3842be1a816SJohn Birrell if (i != mark) { 3852be1a816SJohn Birrell if (write(fd, &buf[mark], i - mark) != i - mark) 3862be1a816SJohn Birrell fatal("failed to write to %s", fname); 3872be1a816SJohn Birrell } 3882be1a816SJohn Birrell 3892be1a816SJohn Birrell /* 3902be1a816SJohn Birrell * Now scan forward until we scan past a newline. 3912be1a816SJohn Birrell */ 3922be1a816SJohn Birrell for (j = i; j < sz && buf[j] != '\n'; j++) 3932be1a816SJohn Birrell continue; 3942be1a816SJohn Birrell 3952be1a816SJohn Birrell /* 3962be1a816SJohn Birrell * Reset our mark. 3972be1a816SJohn Birrell */ 3982be1a816SJohn Birrell if ((mark = j + 1) >= sz) 3992be1a816SJohn Birrell break; 4002be1a816SJohn Birrell 4012be1a816SJohn Birrell i = j; 4022be1a816SJohn Birrell } 4032be1a816SJohn Birrell 4042be1a816SJohn Birrell if (mark < sz) { 4052be1a816SJohn Birrell if (write(fd, &buf[mark], sz - mark) != sz - mark) 4062be1a816SJohn Birrell fatal("failed to write to %s", fname); 4072be1a816SJohn Birrell } 4082be1a816SJohn Birrell 4092be1a816SJohn Birrell (void) close(fd); 4102be1a816SJohn Birrell free(buf); 4112be1a816SJohn Birrell } 4122be1a816SJohn Birrell 413b5290286SMark Johnston #ifdef __FreeBSD__ 414b5290286SMark Johnston /* 415b5290286SMark Johnston * Use nextboot(8) to tell the loader to load DTrace kernel modules during 416b5290286SMark Johnston * the next boot of the system. The nextboot(8) configuration is removed during 417b5290286SMark Johnston * boot, so it will not persist indefinitely. 418b5290286SMark Johnston */ 419b5290286SMark Johnston static void 420b5290286SMark Johnston bootdof_add(void) 421b5290286SMark Johnston { 422b5290286SMark Johnston char * const nbargv[] = { 423b5290286SMark Johnston "nextboot", "-a", 424b5290286SMark Johnston "-e", "dtraceall_load=\"YES\"", 425b5290286SMark Johnston "-e", "dtrace_dof_load=\"YES\"", 426b5290286SMark Johnston "-e", "dtrace_dof_name=\"/boot/dtrace.dof\"", 427b5290286SMark Johnston "-e", "dtrace_dof_type=\"dtrace_dof\"", 428b5290286SMark Johnston NULL, 429b5290286SMark Johnston }; 430b5290286SMark Johnston pid_t child; 431b5290286SMark Johnston int err, status; 432b5290286SMark Johnston 433b5290286SMark Johnston err = posix_spawnp(&child, "nextboot", NULL, NULL, nbargv, 434b5290286SMark Johnston NULL); 435b5290286SMark Johnston if (err != 0) { 436b5290286SMark Johnston error("failed to execute nextboot: %s", strerror(err)); 437b5290286SMark Johnston exit(E_ERROR); 438b5290286SMark Johnston } 439b5290286SMark Johnston 440b5290286SMark Johnston if (waitpid(child, &status, 0) != child) 441b5290286SMark Johnston fatal("waiting for nextboot"); 442b5290286SMark Johnston if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 443b5290286SMark Johnston error("nextboot returned with status %d", status); 444b5290286SMark Johnston exit(E_ERROR); 445b5290286SMark Johnston } 446b5290286SMark Johnston } 447b5290286SMark Johnston #else 4482be1a816SJohn Birrell static void 4492be1a816SJohn Birrell etcsystem_prune(void) 4502be1a816SJohn Birrell { 4512be1a816SJohn Birrell struct stat sbuf; 4522be1a816SJohn Birrell size_t sz; 4532be1a816SJohn Birrell char *buf, *start, *end; 4542be1a816SJohn Birrell int fd; 4552be1a816SJohn Birrell char *fname = g_etcfile, *tmpname; 4562be1a816SJohn Birrell 4572be1a816SJohn Birrell if ((fd = open(fname, O_RDONLY)) == -1) 4582be1a816SJohn Birrell fatal("failed to open %s", fname); 4592be1a816SJohn Birrell 4602be1a816SJohn Birrell if (fstat(fd, &sbuf) == -1) 4612be1a816SJohn Birrell fatal("failed to fstat %s", fname); 4622be1a816SJohn Birrell 4632be1a816SJohn Birrell if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL) 4642be1a816SJohn Birrell fatal("failed to allocate memory for %s", fname); 4652be1a816SJohn Birrell 4662be1a816SJohn Birrell if (read(fd, buf, sz) != sz) 4672be1a816SJohn Birrell fatal("failed to read %s", fname); 4682be1a816SJohn Birrell 4692be1a816SJohn Birrell buf[sz] = '\0'; 4702be1a816SJohn Birrell (void) close(fd); 4712be1a816SJohn Birrell 4722be1a816SJohn Birrell if ((start = strstr(buf, g_etcbegin)) == NULL) 4732be1a816SJohn Birrell goto out; 4742be1a816SJohn Birrell 4752be1a816SJohn Birrell if (strlen(buf) != sz) { 4762be1a816SJohn Birrell fatal("embedded nul byte in %s; manual repair of %s " 4772be1a816SJohn Birrell "required\n", fname, fname); 4782be1a816SJohn Birrell } 4792be1a816SJohn Birrell 4802be1a816SJohn Birrell if (strstr(start + 1, g_etcbegin) != NULL) { 4812be1a816SJohn Birrell fatal("multiple start sentinels in %s; manual repair of %s " 4822be1a816SJohn Birrell "required\n", fname, fname); 4832be1a816SJohn Birrell } 4842be1a816SJohn Birrell 4852be1a816SJohn Birrell if ((end = strstr(buf, g_etcend)) == NULL) { 4862be1a816SJohn Birrell fatal("missing end sentinel in %s; manual repair of %s " 4872be1a816SJohn Birrell "required\n", fname, fname); 4882be1a816SJohn Birrell } 4892be1a816SJohn Birrell 4902be1a816SJohn Birrell if (start > end) { 4912be1a816SJohn Birrell fatal("end sentinel preceeds start sentinel in %s; manual " 4922be1a816SJohn Birrell "repair of %s required\n", fname, fname); 4932be1a816SJohn Birrell } 4942be1a816SJohn Birrell 4952be1a816SJohn Birrell end += strlen(g_etcend) + 1; 4962be1a816SJohn Birrell bcopy(end, start, strlen(end) + 1); 4972be1a816SJohn Birrell 4982be1a816SJohn Birrell tmpname = alloca(sz = strlen(fname) + 80); 4992be1a816SJohn Birrell (void) snprintf(tmpname, sz, "%s.dtrace.%d", fname, getpid()); 5002be1a816SJohn Birrell 5012be1a816SJohn Birrell if ((fd = open(tmpname, 5022be1a816SJohn Birrell O_WRONLY | O_CREAT | O_EXCL, sbuf.st_mode)) == -1) 5032be1a816SJohn Birrell fatal("failed to create %s", tmpname); 5042be1a816SJohn Birrell 5052be1a816SJohn Birrell if (write(fd, buf, strlen(buf)) < strlen(buf)) { 5062be1a816SJohn Birrell (void) unlink(tmpname); 5072be1a816SJohn Birrell fatal("failed to write to %s", tmpname); 5082be1a816SJohn Birrell } 5092be1a816SJohn Birrell 5102be1a816SJohn Birrell (void) close(fd); 5112be1a816SJohn Birrell 5122be1a816SJohn Birrell if (chown(tmpname, sbuf.st_uid, sbuf.st_gid) != 0) { 5132be1a816SJohn Birrell (void) unlink(tmpname); 5142be1a816SJohn Birrell fatal("failed to chown(2) %s to uid %d, gid %d", tmpname, 5152be1a816SJohn Birrell (int)sbuf.st_uid, (int)sbuf.st_gid); 5162be1a816SJohn Birrell } 5172be1a816SJohn Birrell 5182be1a816SJohn Birrell if (rename(tmpname, fname) == -1) 5192be1a816SJohn Birrell fatal("rename of %s to %s failed", tmpname, fname); 5202be1a816SJohn Birrell 5212be1a816SJohn Birrell error("cleaned up forceload directives in %s\n", fname); 5222be1a816SJohn Birrell out: 5232be1a816SJohn Birrell free(buf); 5242be1a816SJohn Birrell } 5252be1a816SJohn Birrell 5262be1a816SJohn Birrell static void 5272be1a816SJohn Birrell etcsystem_add(void) 5282be1a816SJohn Birrell { 5292be1a816SJohn Birrell const char *mods[20]; 5302be1a816SJohn Birrell int nmods, line; 5312be1a816SJohn Birrell 5322be1a816SJohn Birrell if ((g_ofp = fopen(g_ofile = g_etcfile, "a")) == NULL) 5332be1a816SJohn Birrell fatal("failed to open output file '%s'", g_ofile); 5342be1a816SJohn Birrell 5352be1a816SJohn Birrell oprintf("%s\n", g_etcbegin); 5362be1a816SJohn Birrell 5372be1a816SJohn Birrell for (line = 0; g_etc[line] != NULL; line++) 5382be1a816SJohn Birrell oprintf("%s\n", g_etc[line]); 5392be1a816SJohn Birrell 5402be1a816SJohn Birrell nmods = dtrace_provider_modules(g_dtp, mods, 5412be1a816SJohn Birrell sizeof (mods) / sizeof (char *) - 1); 5422be1a816SJohn Birrell 5432be1a816SJohn Birrell if (nmods >= sizeof (mods) / sizeof (char *)) 5442be1a816SJohn Birrell fatal("unexpectedly large number of modules!"); 5452be1a816SJohn Birrell 5462be1a816SJohn Birrell mods[nmods++] = "dtrace"; 5472be1a816SJohn Birrell 5482be1a816SJohn Birrell for (line = 0; line < nmods; line++) 5492be1a816SJohn Birrell oprintf("forceload: drv/%s\n", mods[line]); 5502be1a816SJohn Birrell 5512be1a816SJohn Birrell oprintf("%s\n", g_etcend); 5522be1a816SJohn Birrell 5532be1a816SJohn Birrell if (fclose(g_ofp) == EOF) 5542be1a816SJohn Birrell fatal("failed to close output file '%s'", g_ofile); 5552be1a816SJohn Birrell 5562be1a816SJohn Birrell error("added forceload directives to %s\n", g_ofile); 5572be1a816SJohn Birrell } 558b5290286SMark Johnston #endif /* !__FreeBSD__ */ 5592be1a816SJohn Birrell 5602be1a816SJohn Birrell static void 5612be1a816SJohn Birrell print_probe_info(const dtrace_probeinfo_t *p) 5622be1a816SJohn Birrell { 5632be1a816SJohn Birrell char buf[BUFSIZ]; 5648e648814SRui Paulo char *user; 5652be1a816SJohn Birrell int i; 5662be1a816SJohn Birrell 5672be1a816SJohn Birrell oprintf("\n\tProbe Description Attributes\n"); 5682be1a816SJohn Birrell 5692be1a816SJohn Birrell oprintf("\t\tIdentifier Names: %s\n", 5702be1a816SJohn Birrell dtrace_stability_name(p->dtp_attr.dtat_name)); 5712be1a816SJohn Birrell oprintf("\t\tData Semantics: %s\n", 5722be1a816SJohn Birrell dtrace_stability_name(p->dtp_attr.dtat_data)); 5732be1a816SJohn Birrell oprintf("\t\tDependency Class: %s\n", 5742be1a816SJohn Birrell dtrace_class_name(p->dtp_attr.dtat_class)); 5752be1a816SJohn Birrell 5762be1a816SJohn Birrell oprintf("\n\tArgument Attributes\n"); 5772be1a816SJohn Birrell 5782be1a816SJohn Birrell oprintf("\t\tIdentifier Names: %s\n", 5792be1a816SJohn Birrell dtrace_stability_name(p->dtp_arga.dtat_name)); 5802be1a816SJohn Birrell oprintf("\t\tData Semantics: %s\n", 5812be1a816SJohn Birrell dtrace_stability_name(p->dtp_arga.dtat_data)); 5822be1a816SJohn Birrell oprintf("\t\tDependency Class: %s\n", 5832be1a816SJohn Birrell dtrace_class_name(p->dtp_arga.dtat_class)); 5842be1a816SJohn Birrell 5852be1a816SJohn Birrell oprintf("\n\tArgument Types\n"); 5862be1a816SJohn Birrell 5872be1a816SJohn Birrell for (i = 0; i < p->dtp_argc; i++) { 5888e648814SRui Paulo if (p->dtp_argv[i].dtt_flags & DTT_FL_USER) 5898e648814SRui Paulo user = "userland "; 5908e648814SRui Paulo else 5918e648814SRui Paulo user = ""; 5922be1a816SJohn Birrell if (ctf_type_name(p->dtp_argv[i].dtt_ctfp, 5932be1a816SJohn Birrell p->dtp_argv[i].dtt_type, buf, sizeof (buf)) == NULL) 5942be1a816SJohn Birrell (void) strlcpy(buf, "(unknown)", sizeof (buf)); 5958e648814SRui Paulo oprintf("\t\targs[%d]: %s%s\n", i, user, buf); 5962be1a816SJohn Birrell } 5972be1a816SJohn Birrell 5982be1a816SJohn Birrell if (p->dtp_argc == 0) 5992be1a816SJohn Birrell oprintf("\t\tNone\n"); 6002be1a816SJohn Birrell 6012be1a816SJohn Birrell oprintf("\n"); 6022be1a816SJohn Birrell } 6032be1a816SJohn Birrell 6042be1a816SJohn Birrell /*ARGSUSED*/ 6052be1a816SJohn Birrell static int 6062be1a816SJohn Birrell info_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 6072be1a816SJohn Birrell dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) 6082be1a816SJohn Birrell { 6092be1a816SJohn Birrell dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 6102be1a816SJohn Birrell dtrace_probedesc_t *pdp = &edp->dted_probe; 6112be1a816SJohn Birrell dtrace_probeinfo_t p; 6122be1a816SJohn Birrell 6132be1a816SJohn Birrell if (edp == *last) 6142be1a816SJohn Birrell return (0); 6152be1a816SJohn Birrell 6162be1a816SJohn Birrell oprintf("\n%s:%s:%s:%s\n", 6172be1a816SJohn Birrell pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); 6182be1a816SJohn Birrell 6192be1a816SJohn Birrell if (dtrace_probe_info(dtp, pdp, &p) == 0) 6202be1a816SJohn Birrell print_probe_info(&p); 6212be1a816SJohn Birrell 6222be1a816SJohn Birrell *last = edp; 6232be1a816SJohn Birrell return (0); 6242be1a816SJohn Birrell } 6252be1a816SJohn Birrell 6262be1a816SJohn Birrell /* 6272be1a816SJohn Birrell * Execute the specified program by enabling the corresponding instrumentation. 6282be1a816SJohn Birrell * If -e has been specified, we get the program info but do not enable it. If 6292be1a816SJohn Birrell * -v has been specified, we print a stability report for the program. 6302be1a816SJohn Birrell */ 6312be1a816SJohn Birrell static void 6322be1a816SJohn Birrell exec_prog(const dtrace_cmd_t *dcp) 6332be1a816SJohn Birrell { 6342be1a816SJohn Birrell dtrace_ecbdesc_t *last = NULL; 6352be1a816SJohn Birrell dtrace_proginfo_t dpi; 6362be1a816SJohn Birrell 6372be1a816SJohn Birrell if (!g_exec) { 6382be1a816SJohn Birrell dtrace_program_info(g_dtp, dcp->dc_prog, &dpi); 6392be1a816SJohn Birrell } else if (dtrace_program_exec(g_dtp, dcp->dc_prog, &dpi) == -1) { 6402be1a816SJohn Birrell dfatal("failed to enable '%s'", dcp->dc_name); 6412be1a816SJohn Birrell } else { 6422be1a816SJohn Birrell notice("%s '%s' matched %u probe%s\n", 6432be1a816SJohn Birrell dcp->dc_desc, dcp->dc_name, 6442be1a816SJohn Birrell dpi.dpi_matches, dpi.dpi_matches == 1 ? "" : "s"); 6452be1a816SJohn Birrell } 6462be1a816SJohn Birrell 6472be1a816SJohn Birrell if (g_verbose) { 6482be1a816SJohn Birrell oprintf("\nStability attributes for %s %s:\n", 6492be1a816SJohn Birrell dcp->dc_desc, dcp->dc_name); 6502be1a816SJohn Birrell 6512be1a816SJohn Birrell oprintf("\n\tMinimum Probe Description Attributes\n"); 6522be1a816SJohn Birrell oprintf("\t\tIdentifier Names: %s\n", 6532be1a816SJohn Birrell dtrace_stability_name(dpi.dpi_descattr.dtat_name)); 6542be1a816SJohn Birrell oprintf("\t\tData Semantics: %s\n", 6552be1a816SJohn Birrell dtrace_stability_name(dpi.dpi_descattr.dtat_data)); 6562be1a816SJohn Birrell oprintf("\t\tDependency Class: %s\n", 6572be1a816SJohn Birrell dtrace_class_name(dpi.dpi_descattr.dtat_class)); 6582be1a816SJohn Birrell 6592be1a816SJohn Birrell oprintf("\n\tMinimum Statement Attributes\n"); 6602be1a816SJohn Birrell 6612be1a816SJohn Birrell oprintf("\t\tIdentifier Names: %s\n", 6622be1a816SJohn Birrell dtrace_stability_name(dpi.dpi_stmtattr.dtat_name)); 6632be1a816SJohn Birrell oprintf("\t\tData Semantics: %s\n", 6642be1a816SJohn Birrell dtrace_stability_name(dpi.dpi_stmtattr.dtat_data)); 6652be1a816SJohn Birrell oprintf("\t\tDependency Class: %s\n", 6662be1a816SJohn Birrell dtrace_class_name(dpi.dpi_stmtattr.dtat_class)); 6672be1a816SJohn Birrell 6682be1a816SJohn Birrell if (!g_exec) { 6692be1a816SJohn Birrell (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, 6702be1a816SJohn Birrell (dtrace_stmt_f *)info_stmt, &last); 6712be1a816SJohn Birrell } else 6722be1a816SJohn Birrell oprintf("\n"); 6732be1a816SJohn Birrell } 6742be1a816SJohn Birrell 6752be1a816SJohn Birrell g_total += dpi.dpi_matches; 6762be1a816SJohn Birrell } 6772be1a816SJohn Birrell 6782be1a816SJohn Birrell /* 6792be1a816SJohn Birrell * Print out the specified DOF buffer as a set of ASCII bytes appropriate for 6802be1a816SJohn Birrell * storing in a driver.conf(4) file associated with the dtrace driver. 6812be1a816SJohn Birrell */ 6822be1a816SJohn Birrell static void 6832be1a816SJohn Birrell anon_prog(const dtrace_cmd_t *dcp, dof_hdr_t *dof, int n) 6842be1a816SJohn Birrell { 6852be1a816SJohn Birrell const uchar_t *p, *q; 6862be1a816SJohn Birrell 6872be1a816SJohn Birrell if (dof == NULL) 6882be1a816SJohn Birrell dfatal("failed to create DOF image for '%s'", dcp->dc_name); 6892be1a816SJohn Birrell 6902be1a816SJohn Birrell p = (uchar_t *)dof; 691066d9631SMark Johnston q = p + dof->dofh_filesz; 6922be1a816SJohn Birrell 693b5290286SMark Johnston #ifdef __FreeBSD__ 694b5290286SMark Johnston /* 695b5290286SMark Johnston * On FreeBSD, the DOF file is read directly during boot - just write 696b5290286SMark Johnston * two hex characters per byte. 697b5290286SMark Johnston */ 698b5290286SMark Johnston oprintf("dof-data-%d=", n); 699b5290286SMark Johnston 700b5290286SMark Johnston while (p < q) 701b5290286SMark Johnston oprintf("%02x", *p++); 702b5290286SMark Johnston 703b5290286SMark Johnston oprintf("\n"); 704b5290286SMark Johnston #else 7052be1a816SJohn Birrell oprintf("dof-data-%d=0x%x", n, *p++); 7062be1a816SJohn Birrell 7072be1a816SJohn Birrell while (p < q) 7082be1a816SJohn Birrell oprintf(",0x%x", *p++); 7092be1a816SJohn Birrell 7102be1a816SJohn Birrell oprintf(";\n"); 711a6847cf6SJohn Birrell #endif 712a6847cf6SJohn Birrell 7132be1a816SJohn Birrell dtrace_dof_destroy(g_dtp, dof); 7142be1a816SJohn Birrell } 7152be1a816SJohn Birrell 7162be1a816SJohn Birrell /* 7172be1a816SJohn Birrell * Link the specified D program in DOF form into an ELF file for use in either 7182be1a816SJohn Birrell * helpers, userland provider definitions, or both. If -o was specified, that 7192be1a816SJohn Birrell * path is used as the output file name. If -o wasn't specified and the input 7202be1a816SJohn Birrell * program is from a script whose name is %.d, use basename(%.o) as the output 7212be1a816SJohn Birrell * file name. Otherwise we use "d.out" as the default output file name. 7222be1a816SJohn Birrell */ 7232be1a816SJohn Birrell static void 7242be1a816SJohn Birrell link_prog(dtrace_cmd_t *dcp) 7252be1a816SJohn Birrell { 7262be1a816SJohn Birrell char *p; 7272be1a816SJohn Birrell 7282be1a816SJohn Birrell if (g_cmdc == 1 && g_ofile != NULL) { 7292be1a816SJohn Birrell (void) strlcpy(dcp->dc_ofile, g_ofile, sizeof (dcp->dc_ofile)); 7302be1a816SJohn Birrell } else if ((p = strrchr(dcp->dc_arg, '.')) != NULL && 7312be1a816SJohn Birrell strcmp(p, ".d") == 0) { 7322be1a816SJohn Birrell p[0] = '\0'; /* strip .d suffix */ 7332be1a816SJohn Birrell (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 7342be1a816SJohn Birrell "%s.o", basename(dcp->dc_arg)); 7351dcc79e3SDimitry Andric } else if (g_cmdc > 1) { 7361dcc79e3SDimitry Andric (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 7371dcc79e3SDimitry Andric "d.out.%td", dcp - g_cmdv); 7382be1a816SJohn Birrell } else { 7392be1a816SJohn Birrell (void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile), 7401dcc79e3SDimitry Andric "d.out"); 7412be1a816SJohn Birrell } 7422be1a816SJohn Birrell 7432be1a816SJohn Birrell if (dtrace_program_link(g_dtp, dcp->dc_prog, DTRACE_D_PROBES, 7442be1a816SJohn Birrell dcp->dc_ofile, g_objc, g_objv) != 0) 7452be1a816SJohn Birrell dfatal("failed to link %s %s", dcp->dc_desc, dcp->dc_name); 7462be1a816SJohn Birrell } 7472be1a816SJohn Birrell 7482be1a816SJohn Birrell /*ARGSUSED*/ 7492be1a816SJohn Birrell static int 7502be1a816SJohn Birrell list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) 7512be1a816SJohn Birrell { 7522be1a816SJohn Birrell dtrace_probeinfo_t p; 7532be1a816SJohn Birrell 7542be1a816SJohn Birrell oprintf("%5d %10s %17s %33s %s\n", pdp->dtpd_id, 7552be1a816SJohn Birrell pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); 7562be1a816SJohn Birrell 7572be1a816SJohn Birrell if (g_verbose && dtrace_probe_info(dtp, pdp, &p) == 0) 7582be1a816SJohn Birrell print_probe_info(&p); 7592be1a816SJohn Birrell 760486de25dSMark Johnston if (g_intr != 0) 761486de25dSMark Johnston return (1); 762486de25dSMark Johnston 7632be1a816SJohn Birrell return (0); 7642be1a816SJohn Birrell } 7652be1a816SJohn Birrell 7662be1a816SJohn Birrell /*ARGSUSED*/ 7672be1a816SJohn Birrell static int 7682be1a816SJohn Birrell list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, 7692be1a816SJohn Birrell dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) 7702be1a816SJohn Birrell { 7712be1a816SJohn Birrell dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; 7722be1a816SJohn Birrell 7732be1a816SJohn Birrell if (edp == *last) 7742be1a816SJohn Birrell return (0); 7752be1a816SJohn Birrell 7762be1a816SJohn Birrell if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) { 7772be1a816SJohn Birrell error("failed to match %s:%s:%s:%s: %s\n", 7782be1a816SJohn Birrell edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, 7792be1a816SJohn Birrell edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name, 7802be1a816SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 7812be1a816SJohn Birrell } 7822be1a816SJohn Birrell 7832be1a816SJohn Birrell *last = edp; 7842be1a816SJohn Birrell return (0); 7852be1a816SJohn Birrell } 7862be1a816SJohn Birrell 7872be1a816SJohn Birrell /* 7882be1a816SJohn Birrell * List the probes corresponding to the specified program by iterating over 7892be1a816SJohn Birrell * each statement and then matching probes to the statement probe descriptions. 7902be1a816SJohn Birrell */ 7912be1a816SJohn Birrell static void 7922be1a816SJohn Birrell list_prog(const dtrace_cmd_t *dcp) 7932be1a816SJohn Birrell { 7942be1a816SJohn Birrell dtrace_ecbdesc_t *last = NULL; 7952be1a816SJohn Birrell 7962be1a816SJohn Birrell (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, 7972be1a816SJohn Birrell (dtrace_stmt_f *)list_stmt, &last); 7982be1a816SJohn Birrell } 7992be1a816SJohn Birrell 8002be1a816SJohn Birrell static void 8012be1a816SJohn Birrell compile_file(dtrace_cmd_t *dcp) 8022be1a816SJohn Birrell { 8032be1a816SJohn Birrell char *arg0; 8042be1a816SJohn Birrell FILE *fp; 8052be1a816SJohn Birrell 8062be1a816SJohn Birrell if ((fp = fopen(dcp->dc_arg, "r")) == NULL) 8072be1a816SJohn Birrell fatal("failed to open %s", dcp->dc_arg); 8082be1a816SJohn Birrell 8092be1a816SJohn Birrell arg0 = g_argv[0]; 8102be1a816SJohn Birrell g_argv[0] = dcp->dc_arg; 8112be1a816SJohn Birrell 8122be1a816SJohn Birrell if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp, 8132be1a816SJohn Birrell g_cflags, g_argc, g_argv)) == NULL) 8142be1a816SJohn Birrell dfatal("failed to compile script %s", dcp->dc_arg); 8152be1a816SJohn Birrell 8162be1a816SJohn Birrell g_argv[0] = arg0; 8172be1a816SJohn Birrell (void) fclose(fp); 8182be1a816SJohn Birrell 8192be1a816SJohn Birrell dcp->dc_desc = "script"; 8202be1a816SJohn Birrell dcp->dc_name = dcp->dc_arg; 8212be1a816SJohn Birrell } 8222be1a816SJohn Birrell 8232be1a816SJohn Birrell static void 8242be1a816SJohn Birrell compile_str(dtrace_cmd_t *dcp) 8252be1a816SJohn Birrell { 8262be1a816SJohn Birrell char *p; 8272be1a816SJohn Birrell 8282be1a816SJohn Birrell if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg, 8292be1a816SJohn Birrell dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL) 8302be1a816SJohn Birrell dfatal("invalid probe specifier %s", dcp->dc_arg); 8312be1a816SJohn Birrell 8322be1a816SJohn Birrell if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL) 8332be1a816SJohn Birrell *p = '\0'; /* crop name for reporting */ 8342be1a816SJohn Birrell 8352be1a816SJohn Birrell dcp->dc_desc = "description"; 8362be1a816SJohn Birrell dcp->dc_name = dcp->dc_arg; 8372be1a816SJohn Birrell } 8382be1a816SJohn Birrell 8392be1a816SJohn Birrell /*ARGSUSED*/ 8402be1a816SJohn Birrell static void 8412be1a816SJohn Birrell prochandler(struct ps_prochandle *P, const char *msg, void *arg) 8422be1a816SJohn Birrell { 843bc96366cSSteven Hartland #ifdef illumos 8442be1a816SJohn Birrell const psinfo_t *prp = Ppsinfo(P); 8452be1a816SJohn Birrell int pid = Pstatus(P)->pr_pid; 8462be1a816SJohn Birrell char name[SIG2STR_MAX]; 8470f2bd1e8SRui Paulo #else 8480f2bd1e8SRui Paulo int wstatus = proc_getwstat(P); 8490f2bd1e8SRui Paulo int pid = proc_getpid(P); 8500f2bd1e8SRui Paulo #endif 8512be1a816SJohn Birrell 8522be1a816SJohn Birrell if (msg != NULL) { 8532be1a816SJohn Birrell notice("pid %d: %s\n", pid, msg); 8542be1a816SJohn Birrell return; 8552be1a816SJohn Birrell } 8562be1a816SJohn Birrell 857bc96366cSSteven Hartland #ifdef illumos 8582be1a816SJohn Birrell switch (Pstate(P)) { 8590f2bd1e8SRui Paulo #else 8600f2bd1e8SRui Paulo switch (proc_state(P)) { 8610f2bd1e8SRui Paulo #endif 8622be1a816SJohn Birrell case PS_UNDEAD: 863bc96366cSSteven Hartland #ifdef illumos 8642be1a816SJohn Birrell /* 8652be1a816SJohn Birrell * Ideally we would like to always report pr_wstat here, but it 8662be1a816SJohn Birrell * isn't possible given current /proc semantics. If we grabbed 8672be1a816SJohn Birrell * the process, Ppsinfo() will either fail or return a zeroed 8682be1a816SJohn Birrell * psinfo_t depending on how far the parent is in reaping it. 8692be1a816SJohn Birrell * When /proc provides a stable pr_wstat in the status file, 8702be1a816SJohn Birrell * this code can be improved by examining this new pr_wstat. 8712be1a816SJohn Birrell */ 8722be1a816SJohn Birrell if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 8732be1a816SJohn Birrell notice("pid %d terminated by %s\n", pid, 8742be1a816SJohn Birrell proc_signame(WTERMSIG(prp->pr_wstat), 8752be1a816SJohn Birrell name, sizeof (name))); 8760f2bd1e8SRui Paulo #else 8770f2bd1e8SRui Paulo if (WIFSIGNALED(wstatus)) { 8780f2bd1e8SRui Paulo notice("pid %d terminated by %d\n", pid, 8790f2bd1e8SRui Paulo WTERMSIG(wstatus)); 8800f2bd1e8SRui Paulo #endif 881bc96366cSSteven Hartland #ifdef illumos 8822be1a816SJohn Birrell } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { 8832be1a816SJohn Birrell notice("pid %d exited with status %d\n", 8842be1a816SJohn Birrell pid, WEXITSTATUS(prp->pr_wstat)); 8850f2bd1e8SRui Paulo #else 8860f2bd1e8SRui Paulo } else if (WEXITSTATUS(wstatus) != 0) { 8870f2bd1e8SRui Paulo notice("pid %d exited with status %d\n", 8880f2bd1e8SRui Paulo pid, WEXITSTATUS(wstatus)); 8890f2bd1e8SRui Paulo #endif 8902be1a816SJohn Birrell } else { 8912be1a816SJohn Birrell notice("pid %d has exited\n", pid); 8922be1a816SJohn Birrell } 8932be1a816SJohn Birrell g_pslive--; 8942be1a816SJohn Birrell break; 8952be1a816SJohn Birrell 8962be1a816SJohn Birrell case PS_LOST: 8972be1a816SJohn Birrell notice("pid %d exec'd a set-id or unobservable program\n", pid); 8982be1a816SJohn Birrell g_pslive--; 8992be1a816SJohn Birrell break; 9002be1a816SJohn Birrell } 9012be1a816SJohn Birrell } 9022be1a816SJohn Birrell 9032be1a816SJohn Birrell /*ARGSUSED*/ 9042be1a816SJohn Birrell static int 9052be1a816SJohn Birrell errhandler(const dtrace_errdata_t *data, void *arg) 9062be1a816SJohn Birrell { 9072be1a816SJohn Birrell error(data->dteda_msg); 9082be1a816SJohn Birrell return (DTRACE_HANDLE_OK); 9092be1a816SJohn Birrell } 9102be1a816SJohn Birrell 9112be1a816SJohn Birrell /*ARGSUSED*/ 9122be1a816SJohn Birrell static int 9132be1a816SJohn Birrell drophandler(const dtrace_dropdata_t *data, void *arg) 9142be1a816SJohn Birrell { 91593f27766SDomagoj Stolfa if (!dtrace_oformat(g_dtp)) { 9162be1a816SJohn Birrell error(data->dtdda_msg); 91793f27766SDomagoj Stolfa } 91893f27766SDomagoj Stolfa 9192be1a816SJohn Birrell return (DTRACE_HANDLE_OK); 9202be1a816SJohn Birrell } 9212be1a816SJohn Birrell 9222be1a816SJohn Birrell /*ARGSUSED*/ 9232be1a816SJohn Birrell static int 9242be1a816SJohn Birrell setopthandler(const dtrace_setoptdata_t *data, void *arg) 9252be1a816SJohn Birrell { 9262be1a816SJohn Birrell if (strcmp(data->dtsda_option, "quiet") == 0) 9272be1a816SJohn Birrell g_quiet = data->dtsda_newval != DTRACEOPT_UNSET; 9282be1a816SJohn Birrell 9292be1a816SJohn Birrell if (strcmp(data->dtsda_option, "flowindent") == 0) 9302be1a816SJohn Birrell g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET; 9312be1a816SJohn Birrell 9322be1a816SJohn Birrell return (DTRACE_HANDLE_OK); 9332be1a816SJohn Birrell } 9342be1a816SJohn Birrell 9352be1a816SJohn Birrell #define BUFDUMPHDR(hdr) \ 9362be1a816SJohn Birrell (void) printf("%s: %s%s\n", g_pname, hdr, strlen(hdr) > 0 ? ":" : ""); 9372be1a816SJohn Birrell 9382be1a816SJohn Birrell #define BUFDUMPSTR(ptr, field) \ 9392be1a816SJohn Birrell (void) printf("%s: %20s => ", g_pname, #field); \ 9402be1a816SJohn Birrell if ((ptr)->field != NULL) { \ 9412be1a816SJohn Birrell const char *c = (ptr)->field; \ 9422be1a816SJohn Birrell (void) printf("\""); \ 9432be1a816SJohn Birrell do { \ 9442be1a816SJohn Birrell if (*c == '\n') { \ 9452be1a816SJohn Birrell (void) printf("\\n"); \ 9462be1a816SJohn Birrell continue; \ 9472be1a816SJohn Birrell } \ 9482be1a816SJohn Birrell \ 9492be1a816SJohn Birrell (void) printf("%c", *c); \ 9502be1a816SJohn Birrell } while (*c++ != '\0'); \ 9512be1a816SJohn Birrell (void) printf("\"\n"); \ 9522be1a816SJohn Birrell } else { \ 9532be1a816SJohn Birrell (void) printf("<NULL>\n"); \ 9542be1a816SJohn Birrell } 9552be1a816SJohn Birrell 9562be1a816SJohn Birrell #define BUFDUMPASSTR(ptr, field, str) \ 9572be1a816SJohn Birrell (void) printf("%s: %20s => %s\n", g_pname, #field, str); 9582be1a816SJohn Birrell 9592be1a816SJohn Birrell #define BUFDUMP(ptr, field) \ 9602be1a816SJohn Birrell (void) printf("%s: %20s => %lld\n", g_pname, #field, \ 9612be1a816SJohn Birrell (long long)(ptr)->field); 9622be1a816SJohn Birrell 9632be1a816SJohn Birrell #define BUFDUMPPTR(ptr, field) \ 9642be1a816SJohn Birrell (void) printf("%s: %20s => %s\n", g_pname, #field, \ 9652be1a816SJohn Birrell (ptr)->field != NULL ? "<non-NULL>" : "<NULL>"); 9662be1a816SJohn Birrell 9672be1a816SJohn Birrell /*ARGSUSED*/ 9682be1a816SJohn Birrell static int 9692be1a816SJohn Birrell bufhandler(const dtrace_bufdata_t *bufdata, void *arg) 9702be1a816SJohn Birrell { 9712be1a816SJohn Birrell const dtrace_aggdata_t *agg = bufdata->dtbda_aggdata; 9722be1a816SJohn Birrell const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc; 9732be1a816SJohn Birrell const dtrace_probedesc_t *pd; 9742be1a816SJohn Birrell uint32_t flags = bufdata->dtbda_flags; 9752be1a816SJohn Birrell char buf[512], *c = buf, *end = c + sizeof (buf); 9762be1a816SJohn Birrell int i, printed; 9772be1a816SJohn Birrell 9782be1a816SJohn Birrell struct { 9792be1a816SJohn Birrell const char *name; 9802be1a816SJohn Birrell uint32_t value; 9812be1a816SJohn Birrell } flagnames[] = { 9822be1a816SJohn Birrell { "AGGVAL", DTRACE_BUFDATA_AGGVAL }, 9832be1a816SJohn Birrell { "AGGKEY", DTRACE_BUFDATA_AGGKEY }, 9842be1a816SJohn Birrell { "AGGFORMAT", DTRACE_BUFDATA_AGGFORMAT }, 9852be1a816SJohn Birrell { "AGGLAST", DTRACE_BUFDATA_AGGLAST }, 9862be1a816SJohn Birrell { "???", UINT32_MAX }, 9872be1a816SJohn Birrell { NULL } 9882be1a816SJohn Birrell }; 9892be1a816SJohn Birrell 9902be1a816SJohn Birrell if (bufdata->dtbda_probe != NULL) { 9912be1a816SJohn Birrell pd = bufdata->dtbda_probe->dtpda_pdesc; 9922be1a816SJohn Birrell } else if (agg != NULL) { 9932be1a816SJohn Birrell pd = agg->dtada_pdesc; 9942be1a816SJohn Birrell } else { 9952be1a816SJohn Birrell pd = NULL; 9962be1a816SJohn Birrell } 9972be1a816SJohn Birrell 9982be1a816SJohn Birrell BUFDUMPHDR(">>> Called buffer handler"); 9992be1a816SJohn Birrell BUFDUMPHDR(""); 10002be1a816SJohn Birrell 10012be1a816SJohn Birrell BUFDUMPHDR(" dtrace_bufdata"); 10022be1a816SJohn Birrell BUFDUMPSTR(bufdata, dtbda_buffered); 10032be1a816SJohn Birrell BUFDUMPPTR(bufdata, dtbda_probe); 10042be1a816SJohn Birrell BUFDUMPPTR(bufdata, dtbda_aggdata); 10052be1a816SJohn Birrell BUFDUMPPTR(bufdata, dtbda_recdesc); 10062be1a816SJohn Birrell 10072be1a816SJohn Birrell (void) snprintf(c, end - c, "0x%x ", bufdata->dtbda_flags); 10082be1a816SJohn Birrell c += strlen(c); 10092be1a816SJohn Birrell 10102be1a816SJohn Birrell for (i = 0, printed = 0; flagnames[i].name != NULL; i++) { 10112be1a816SJohn Birrell if (!(flags & flagnames[i].value)) 10122be1a816SJohn Birrell continue; 10132be1a816SJohn Birrell 10142be1a816SJohn Birrell (void) snprintf(c, end - c, 10152be1a816SJohn Birrell "%s%s", printed++ ? " | " : "(", flagnames[i].name); 10162be1a816SJohn Birrell c += strlen(c); 10172be1a816SJohn Birrell flags &= ~flagnames[i].value; 10182be1a816SJohn Birrell } 10192be1a816SJohn Birrell 10202be1a816SJohn Birrell if (printed) 10212be1a816SJohn Birrell (void) snprintf(c, end - c, ")"); 10222be1a816SJohn Birrell 10232be1a816SJohn Birrell BUFDUMPASSTR(bufdata, dtbda_flags, buf); 10242be1a816SJohn Birrell BUFDUMPHDR(""); 10252be1a816SJohn Birrell 10262be1a816SJohn Birrell if (pd != NULL) { 10272be1a816SJohn Birrell BUFDUMPHDR(" dtrace_probedesc"); 10282be1a816SJohn Birrell BUFDUMPSTR(pd, dtpd_provider); 10292be1a816SJohn Birrell BUFDUMPSTR(pd, dtpd_mod); 10302be1a816SJohn Birrell BUFDUMPSTR(pd, dtpd_func); 10312be1a816SJohn Birrell BUFDUMPSTR(pd, dtpd_name); 10322be1a816SJohn Birrell BUFDUMPHDR(""); 10332be1a816SJohn Birrell } 10342be1a816SJohn Birrell 10352be1a816SJohn Birrell if (rec != NULL) { 10362be1a816SJohn Birrell BUFDUMPHDR(" dtrace_recdesc"); 10372be1a816SJohn Birrell BUFDUMP(rec, dtrd_action); 10382be1a816SJohn Birrell BUFDUMP(rec, dtrd_size); 10392be1a816SJohn Birrell 10402be1a816SJohn Birrell if (agg != NULL) { 10412be1a816SJohn Birrell uint8_t *data; 10422be1a816SJohn Birrell int lim = rec->dtrd_size; 10432be1a816SJohn Birrell 10442be1a816SJohn Birrell (void) sprintf(buf, "%d (data: ", rec->dtrd_offset); 10452be1a816SJohn Birrell c = buf + strlen(buf); 10462be1a816SJohn Birrell 10472be1a816SJohn Birrell if (lim > sizeof (uint64_t)) 10482be1a816SJohn Birrell lim = sizeof (uint64_t); 10492be1a816SJohn Birrell 10502be1a816SJohn Birrell data = (uint8_t *)agg->dtada_data + rec->dtrd_offset; 10512be1a816SJohn Birrell 10522be1a816SJohn Birrell for (i = 0; i < lim; i++) { 10532be1a816SJohn Birrell (void) snprintf(c, end - c, "%s%02x", 10542be1a816SJohn Birrell i == 0 ? "" : " ", *data++); 10552be1a816SJohn Birrell c += strlen(c); 10562be1a816SJohn Birrell } 10572be1a816SJohn Birrell 10582be1a816SJohn Birrell (void) snprintf(c, end - c, 10592be1a816SJohn Birrell "%s)", lim < rec->dtrd_size ? " ..." : ""); 10602be1a816SJohn Birrell BUFDUMPASSTR(rec, dtrd_offset, buf); 10612be1a816SJohn Birrell } else { 10622be1a816SJohn Birrell BUFDUMP(rec, dtrd_offset); 10632be1a816SJohn Birrell } 10642be1a816SJohn Birrell 10652be1a816SJohn Birrell BUFDUMPHDR(""); 10662be1a816SJohn Birrell } 10672be1a816SJohn Birrell 10682be1a816SJohn Birrell if (agg != NULL) { 10692be1a816SJohn Birrell dtrace_aggdesc_t *desc = agg->dtada_desc; 10702be1a816SJohn Birrell 10712be1a816SJohn Birrell BUFDUMPHDR(" dtrace_aggdesc"); 10722be1a816SJohn Birrell BUFDUMPSTR(desc, dtagd_name); 10732be1a816SJohn Birrell BUFDUMP(desc, dtagd_varid); 10742be1a816SJohn Birrell BUFDUMP(desc, dtagd_id); 10752be1a816SJohn Birrell BUFDUMP(desc, dtagd_nrecs); 10762be1a816SJohn Birrell BUFDUMPHDR(""); 10772be1a816SJohn Birrell } 10782be1a816SJohn Birrell 10792be1a816SJohn Birrell return (DTRACE_HANDLE_OK); 10802be1a816SJohn Birrell } 10812be1a816SJohn Birrell 10822be1a816SJohn Birrell /*ARGSUSED*/ 10832be1a816SJohn Birrell static int 10842be1a816SJohn Birrell chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) 10852be1a816SJohn Birrell { 10862be1a816SJohn Birrell dtrace_actkind_t act; 10872be1a816SJohn Birrell uintptr_t addr; 10882be1a816SJohn Birrell 10892be1a816SJohn Birrell if (rec == NULL) { 10902be1a816SJohn Birrell /* 10912be1a816SJohn Birrell * We have processed the final record; output the newline if 10922be1a816SJohn Birrell * we're not in quiet mode. 10932be1a816SJohn Birrell */ 10942be1a816SJohn Birrell if (!g_quiet) 10952be1a816SJohn Birrell oprintf("\n"); 10962be1a816SJohn Birrell 10972be1a816SJohn Birrell return (DTRACE_CONSUME_NEXT); 10982be1a816SJohn Birrell } 10992be1a816SJohn Birrell 11002be1a816SJohn Birrell act = rec->dtrd_action; 11012be1a816SJohn Birrell addr = (uintptr_t)data->dtpda_data; 11022be1a816SJohn Birrell 11032be1a816SJohn Birrell if (act == DTRACEACT_EXIT) { 11042be1a816SJohn Birrell g_status = *((uint32_t *)addr); 11052be1a816SJohn Birrell return (DTRACE_CONSUME_NEXT); 11062be1a816SJohn Birrell } 11072be1a816SJohn Birrell 11082be1a816SJohn Birrell return (DTRACE_CONSUME_THIS); 11092be1a816SJohn Birrell } 11102be1a816SJohn Birrell 11112be1a816SJohn Birrell /*ARGSUSED*/ 11122be1a816SJohn Birrell static int 11132be1a816SJohn Birrell chew(const dtrace_probedata_t *data, void *arg) 11142be1a816SJohn Birrell { 11152be1a816SJohn Birrell dtrace_probedesc_t *pd = data->dtpda_pdesc; 11162be1a816SJohn Birrell processorid_t cpu = data->dtpda_cpu; 11172be1a816SJohn Birrell static int heading; 11182be1a816SJohn Birrell 11192be1a816SJohn Birrell if (g_impatient) { 11202be1a816SJohn Birrell g_newline = 0; 11212be1a816SJohn Birrell return (DTRACE_CONSUME_ABORT); 11222be1a816SJohn Birrell } 11232be1a816SJohn Birrell 11242be1a816SJohn Birrell if (heading == 0) { 11252be1a816SJohn Birrell if (!g_flowindent) { 11262be1a816SJohn Birrell if (!g_quiet) { 11272be1a816SJohn Birrell oprintf("%3s %6s %32s\n", 11282be1a816SJohn Birrell "CPU", "ID", "FUNCTION:NAME"); 11292be1a816SJohn Birrell } 11302be1a816SJohn Birrell } else { 11312be1a816SJohn Birrell oprintf("%3s %-41s\n", "CPU", "FUNCTION"); 11322be1a816SJohn Birrell } 11332be1a816SJohn Birrell heading = 1; 11342be1a816SJohn Birrell } 11352be1a816SJohn Birrell 11362be1a816SJohn Birrell if (!g_flowindent) { 113793f27766SDomagoj Stolfa if (dtrace_oformat(g_dtp)) { 113893f27766SDomagoj Stolfa dtrace_oformat_probe(g_dtp, data, cpu, pd); 113993f27766SDomagoj Stolfa } else if (!g_quiet) { 11402be1a816SJohn Birrell char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; 11412be1a816SJohn Birrell 11422be1a816SJohn Birrell (void) snprintf(name, sizeof (name), "%s:%s", 11432be1a816SJohn Birrell pd->dtpd_func, pd->dtpd_name); 11442be1a816SJohn Birrell 11452be1a816SJohn Birrell oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name); 11462be1a816SJohn Birrell } 11472be1a816SJohn Birrell } else { 11482be1a816SJohn Birrell int indent = data->dtpda_indent; 11492be1a816SJohn Birrell char *name; 11502be1a816SJohn Birrell size_t len; 11512be1a816SJohn Birrell 11522be1a816SJohn Birrell if (data->dtpda_flow == DTRACEFLOW_NONE) { 11532be1a816SJohn Birrell len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5; 11542be1a816SJohn Birrell name = alloca(len); 11552be1a816SJohn Birrell (void) snprintf(name, len, "%*s%s%s:%s", indent, "", 11562be1a816SJohn Birrell data->dtpda_prefix, pd->dtpd_func, 11572be1a816SJohn Birrell pd->dtpd_name); 11582be1a816SJohn Birrell } else { 11592be1a816SJohn Birrell len = indent + DTRACE_FUNCNAMELEN + 5; 11602be1a816SJohn Birrell name = alloca(len); 11612be1a816SJohn Birrell (void) snprintf(name, len, "%*s%s%s", indent, "", 11622be1a816SJohn Birrell data->dtpda_prefix, pd->dtpd_func); 11632be1a816SJohn Birrell } 11642be1a816SJohn Birrell 11652be1a816SJohn Birrell oprintf("%3d %-41s ", cpu, name); 11662be1a816SJohn Birrell } 11672be1a816SJohn Birrell 11682be1a816SJohn Birrell return (DTRACE_CONSUME_THIS); 11692be1a816SJohn Birrell } 11702be1a816SJohn Birrell 11712be1a816SJohn Birrell static void 11722be1a816SJohn Birrell go(void) 11732be1a816SJohn Birrell { 11742be1a816SJohn Birrell int i; 11752be1a816SJohn Birrell 11762be1a816SJohn Birrell struct { 11772be1a816SJohn Birrell char *name; 11782be1a816SJohn Birrell char *optname; 11792be1a816SJohn Birrell dtrace_optval_t val; 11802be1a816SJohn Birrell } bufs[] = { 11812be1a816SJohn Birrell { "buffer size", "bufsize" }, 11822be1a816SJohn Birrell { "aggregation size", "aggsize" }, 11832be1a816SJohn Birrell { "speculation size", "specsize" }, 11842be1a816SJohn Birrell { "dynamic variable size", "dynvarsize" }, 11852be1a816SJohn Birrell { NULL } 11862be1a816SJohn Birrell }, rates[] = { 11872be1a816SJohn Birrell { "cleaning rate", "cleanrate" }, 11882be1a816SJohn Birrell { "status rate", "statusrate" }, 11892be1a816SJohn Birrell { NULL } 11902be1a816SJohn Birrell }; 11912be1a816SJohn Birrell 11922be1a816SJohn Birrell for (i = 0; bufs[i].name != NULL; i++) { 11932be1a816SJohn Birrell if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1) 11942be1a816SJohn Birrell fatal("couldn't get option %s", bufs[i].optname); 11952be1a816SJohn Birrell } 11962be1a816SJohn Birrell 11972be1a816SJohn Birrell for (i = 0; rates[i].name != NULL; i++) { 11982be1a816SJohn Birrell if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1) 11992be1a816SJohn Birrell fatal("couldn't get option %s", rates[i].optname); 12002be1a816SJohn Birrell } 12012be1a816SJohn Birrell 12022be1a816SJohn Birrell if (dtrace_go(g_dtp) == -1) 12032be1a816SJohn Birrell dfatal("could not enable tracing"); 12042be1a816SJohn Birrell 12052be1a816SJohn Birrell for (i = 0; bufs[i].name != NULL; i++) { 12062be1a816SJohn Birrell dtrace_optval_t j = 0, mul = 10; 12072be1a816SJohn Birrell dtrace_optval_t nsize; 12082be1a816SJohn Birrell 12092be1a816SJohn Birrell if (bufs[i].val == DTRACEOPT_UNSET) 12102be1a816SJohn Birrell continue; 12112be1a816SJohn Birrell 12122be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize); 12132be1a816SJohn Birrell 12142be1a816SJohn Birrell if (nsize == DTRACEOPT_UNSET || nsize == 0) 12152be1a816SJohn Birrell continue; 12162be1a816SJohn Birrell 12172be1a816SJohn Birrell if (nsize >= bufs[i].val - sizeof (uint64_t)) 12182be1a816SJohn Birrell continue; 12192be1a816SJohn Birrell 12202be1a816SJohn Birrell for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10) 12212be1a816SJohn Birrell continue; 12222be1a816SJohn Birrell 12232be1a816SJohn Birrell if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) { 12242be1a816SJohn Birrell error("%s lowered to %lld%c\n", bufs[i].name, 12252be1a816SJohn Birrell (long long)nsize >> (mul - 10), " kmgtpe"[j]); 12262be1a816SJohn Birrell } else { 12272be1a816SJohn Birrell error("%s lowered to %lld bytes\n", bufs[i].name, 12282be1a816SJohn Birrell (long long)nsize); 12292be1a816SJohn Birrell } 12302be1a816SJohn Birrell } 12312be1a816SJohn Birrell 12322be1a816SJohn Birrell for (i = 0; rates[i].name != NULL; i++) { 12332be1a816SJohn Birrell dtrace_optval_t nval; 12342be1a816SJohn Birrell char *dir; 12352be1a816SJohn Birrell 12362be1a816SJohn Birrell if (rates[i].val == DTRACEOPT_UNSET) 12372be1a816SJohn Birrell continue; 12382be1a816SJohn Birrell 12392be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, rates[i].optname, &nval); 12402be1a816SJohn Birrell 12412be1a816SJohn Birrell if (nval == DTRACEOPT_UNSET || nval == 0) 12422be1a816SJohn Birrell continue; 12432be1a816SJohn Birrell 12442be1a816SJohn Birrell if (rates[i].val == nval) 12452be1a816SJohn Birrell continue; 12462be1a816SJohn Birrell 12472be1a816SJohn Birrell dir = nval > rates[i].val ? "reduced" : "increased"; 12482be1a816SJohn Birrell 12492be1a816SJohn Birrell if (nval <= NANOSEC && (NANOSEC % nval) == 0) { 12502be1a816SJohn Birrell error("%s %s to %lld hz\n", rates[i].name, dir, 12512be1a816SJohn Birrell (long long)NANOSEC / (long long)nval); 12522be1a816SJohn Birrell continue; 12532be1a816SJohn Birrell } 12542be1a816SJohn Birrell 12552be1a816SJohn Birrell if ((nval % NANOSEC) == 0) { 12562be1a816SJohn Birrell error("%s %s to once every %lld seconds\n", 12572be1a816SJohn Birrell rates[i].name, dir, 12582be1a816SJohn Birrell (long long)nval / (long long)NANOSEC); 12592be1a816SJohn Birrell continue; 12602be1a816SJohn Birrell } 12612be1a816SJohn Birrell 12622be1a816SJohn Birrell error("%s %s to once every %lld nanoseconds\n", 12632be1a816SJohn Birrell rates[i].name, dir, (long long)nval); 12642be1a816SJohn Birrell } 12652be1a816SJohn Birrell } 12662be1a816SJohn Birrell 12672be1a816SJohn Birrell /*ARGSUSED*/ 12682be1a816SJohn Birrell static void 12692be1a816SJohn Birrell intr(int signo) 12702be1a816SJohn Birrell { 12712be1a816SJohn Birrell if (!g_intr) 12722be1a816SJohn Birrell g_newline = 1; 12732be1a816SJohn Birrell 127496b32677SGeorge V. Neville-Neil if (g_intr++) 12752be1a816SJohn Birrell g_impatient = 1; 12762be1a816SJohn Birrell } 12772be1a816SJohn Birrell 1278be9cb745SMark Johnston #ifdef __FreeBSD__ 1279be9cb745SMark Johnston static void 1280be9cb745SMark Johnston siginfo(int signo __unused) 1281be9cb745SMark Johnston { 1282be9cb745SMark Johnston 1283be9cb745SMark Johnston g_siginfo++; 1284be9cb745SMark Johnston g_newline = 1; 1285be9cb745SMark Johnston } 1286be9cb745SMark Johnston #endif 1287be9cb745SMark Johnston 1288486de25dSMark Johnston static void 1289486de25dSMark Johnston installsighands(void) 1290486de25dSMark Johnston { 1291486de25dSMark Johnston struct sigaction act, oact; 1292486de25dSMark Johnston 1293486de25dSMark Johnston (void) sigemptyset(&act.sa_mask); 1294486de25dSMark Johnston act.sa_flags = 0; 1295486de25dSMark Johnston act.sa_handler = intr; 1296486de25dSMark Johnston 1297486de25dSMark Johnston if (sigaction(SIGINT, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1298486de25dSMark Johnston (void) sigaction(SIGINT, &act, NULL); 1299486de25dSMark Johnston 1300486de25dSMark Johnston if (sigaction(SIGTERM, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1301486de25dSMark Johnston (void) sigaction(SIGTERM, &act, NULL); 1302486de25dSMark Johnston 1303be9cb745SMark Johnston #ifdef __FreeBSD__ 1304486de25dSMark Johnston if (sigaction(SIGPIPE, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1305486de25dSMark Johnston (void) sigaction(SIGPIPE, &act, NULL); 1306486de25dSMark Johnston 1307486de25dSMark Johnston if (sigaction(SIGUSR1, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1308486de25dSMark Johnston (void) sigaction(SIGUSR1, &act, NULL); 1309be9cb745SMark Johnston 1310be9cb745SMark Johnston act.sa_handler = siginfo; 1311be9cb745SMark Johnston if (sigaction(SIGINFO, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN) 1312be9cb745SMark Johnston (void) sigaction(SIGINFO, &act, NULL); 1313486de25dSMark Johnston #endif 1314486de25dSMark Johnston } 1315486de25dSMark Johnston 13162be1a816SJohn Birrell int 13172be1a816SJohn Birrell main(int argc, char *argv[]) 13182be1a816SJohn Birrell { 13192be1a816SJohn Birrell dtrace_bufdesc_t buf; 13202be1a816SJohn Birrell dtrace_status_t status[2]; 13212be1a816SJohn Birrell dtrace_optval_t opt; 13222be1a816SJohn Birrell dtrace_cmd_t *dcp; 13232be1a816SJohn Birrell 1324a6847cf6SJohn Birrell g_ofp = stdout; 13252be1a816SJohn Birrell int done = 0, mode = 0; 132693f27766SDomagoj Stolfa int err, i, c, new_argc, libxo_specified; 132793f27766SDomagoj Stolfa int print_upon_exit = 0; 1328a6847cf6SJohn Birrell char *p, **v; 13292be1a816SJohn Birrell struct ps_prochandle *P; 13302be1a816SJohn Birrell pid_t pid; 13312be1a816SJohn Birrell 1332b946eedeSAndriy Gapon #ifdef __FreeBSD__ 1333b946eedeSAndriy Gapon /* For %'d and the like. */ 1334b946eedeSAndriy Gapon (void) setlocale(LC_NUMERIC, ""); 1335b946eedeSAndriy Gapon 1336b946eedeSAndriy Gapon /* For %T. */ 1337b946eedeSAndriy Gapon (void) setlocale(LC_TIME, ""); 1338b946eedeSAndriy Gapon #endif 1339b946eedeSAndriy Gapon 13402be1a816SJohn Birrell g_pname = basename(argv[0]); 13412be1a816SJohn Birrell 13422be1a816SJohn Birrell if (argc == 1) 13432be1a816SJohn Birrell return (usage(stderr)); 13442be1a816SJohn Birrell 13452be1a816SJohn Birrell if ((g_argv = malloc(sizeof (char *) * argc)) == NULL || 13462be1a816SJohn Birrell (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL || 13472be1a816SJohn Birrell (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL) 13482be1a816SJohn Birrell fatal("failed to allocate memory for arguments"); 13492be1a816SJohn Birrell 135093f27766SDomagoj Stolfa new_argc = xo_parse_args(argc, argv); 135193f27766SDomagoj Stolfa if (new_argc < 0) 135293f27766SDomagoj Stolfa return (usage(stderr)); 135393f27766SDomagoj Stolfa 135493f27766SDomagoj Stolfa if (new_argc != argc) 135593f27766SDomagoj Stolfa libxo_specified = 1; 135693f27766SDomagoj Stolfa 135793f27766SDomagoj Stolfa argc = new_argc; 135893f27766SDomagoj Stolfa 13592be1a816SJohn Birrell g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */ 13602be1a816SJohn Birrell argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ 13612be1a816SJohn Birrell 13622be1a816SJohn Birrell bzero(status, sizeof (status)); 13632be1a816SJohn Birrell bzero(&buf, sizeof (buf)); 13642be1a816SJohn Birrell 13652be1a816SJohn Birrell /* 13662be1a816SJohn Birrell * Make an initial pass through argv[] processing any arguments that 13672be1a816SJohn Birrell * affect our behavior mode (g_mode) and flags used for dtrace_open(). 13682be1a816SJohn Birrell * We also accumulate arguments that are not affiliated with getopt 13692be1a816SJohn Birrell * options into g_argv[], and abort if any invalid options are found. 13702be1a816SJohn Birrell */ 13712be1a816SJohn Birrell for (optind = 1; optind < argc; optind++) { 1372a6847cf6SJohn Birrell while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 13732be1a816SJohn Birrell switch (c) { 13742be1a816SJohn Birrell case '3': 13752be1a816SJohn Birrell if (strcmp(optarg, "2") != 0) { 13762be1a816SJohn Birrell (void) fprintf(stderr, 13772be1a816SJohn Birrell "%s: illegal option -- 3%s\n", 13782be1a816SJohn Birrell argv[0], optarg); 13792be1a816SJohn Birrell return (usage(stderr)); 13802be1a816SJohn Birrell } 1381*096a5c6cSMark Johnston g_oflags &= ~DTRACE_O_MODEL_MASK; 13822be1a816SJohn Birrell g_oflags |= DTRACE_O_ILP32; 13832be1a816SJohn Birrell break; 13842be1a816SJohn Birrell 13852be1a816SJohn Birrell case '6': 13862be1a816SJohn Birrell if (strcmp(optarg, "4") != 0) { 13872be1a816SJohn Birrell (void) fprintf(stderr, 13882be1a816SJohn Birrell "%s: illegal option -- 6%s\n", 13892be1a816SJohn Birrell argv[0], optarg); 13902be1a816SJohn Birrell return (usage(stderr)); 13912be1a816SJohn Birrell } 1392*096a5c6cSMark Johnston g_oflags &= ~DTRACE_O_MODEL_MASK; 13932be1a816SJohn Birrell g_oflags |= DTRACE_O_LP64; 13942be1a816SJohn Birrell break; 13952be1a816SJohn Birrell 13962be1a816SJohn Birrell case 'a': 13972be1a816SJohn Birrell g_grabanon++; /* also checked in pass 2 below */ 13982be1a816SJohn Birrell break; 13992be1a816SJohn Birrell 14002be1a816SJohn Birrell case 'A': 14012be1a816SJohn Birrell g_mode = DMODE_ANON; 14022be1a816SJohn Birrell g_exec = 0; 14032be1a816SJohn Birrell mode++; 14042be1a816SJohn Birrell break; 14052be1a816SJohn Birrell 14062be1a816SJohn Birrell case 'e': 14072be1a816SJohn Birrell g_exec = 0; 14082be1a816SJohn Birrell done = 1; 14092be1a816SJohn Birrell break; 14102be1a816SJohn Birrell 14112be1a816SJohn Birrell case 'h': 14122be1a816SJohn Birrell g_mode = DMODE_HEADER; 14132be1a816SJohn Birrell g_oflags |= DTRACE_O_NODEV; 14142be1a816SJohn Birrell g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */ 14152be1a816SJohn Birrell g_exec = 0; 14162be1a816SJohn Birrell mode++; 14172be1a816SJohn Birrell break; 14182be1a816SJohn Birrell 14192be1a816SJohn Birrell case 'G': 14202be1a816SJohn Birrell g_mode = DMODE_LINK; 14212be1a816SJohn Birrell g_oflags |= DTRACE_O_NODEV; 14222be1a816SJohn Birrell g_cflags |= DTRACE_C_ZDEFS; /* -G implies -Z */ 14232be1a816SJohn Birrell g_exec = 0; 14242be1a816SJohn Birrell mode++; 14252be1a816SJohn Birrell break; 14262be1a816SJohn Birrell 14272be1a816SJohn Birrell case 'l': 14282be1a816SJohn Birrell g_mode = DMODE_LIST; 14292be1a816SJohn Birrell g_cflags |= DTRACE_C_ZDEFS; /* -l implies -Z */ 14302be1a816SJohn Birrell mode++; 14312be1a816SJohn Birrell break; 14322be1a816SJohn Birrell 14332be1a816SJohn Birrell case 'V': 14342be1a816SJohn Birrell g_mode = DMODE_VERS; 14352be1a816SJohn Birrell mode++; 14362be1a816SJohn Birrell break; 14372be1a816SJohn Birrell 14382be1a816SJohn Birrell default: 14392be1a816SJohn Birrell if (strchr(DTRACE_OPTSTR, c) == NULL) 14402be1a816SJohn Birrell return (usage(stderr)); 14412be1a816SJohn Birrell } 14422be1a816SJohn Birrell } 14432be1a816SJohn Birrell 14442be1a816SJohn Birrell if (optind < argc) 14452be1a816SJohn Birrell g_argv[g_argc++] = argv[optind]; 14462be1a816SJohn Birrell } 14472be1a816SJohn Birrell 14482be1a816SJohn Birrell if (mode > 1) { 14492be1a816SJohn Birrell (void) fprintf(stderr, "%s: only one of the [-AGhlV] options " 14502be1a816SJohn Birrell "can be specified at a time\n", g_pname); 14512be1a816SJohn Birrell return (E_USAGE); 14522be1a816SJohn Birrell } 14532be1a816SJohn Birrell 14542be1a816SJohn Birrell if (g_mode == DMODE_VERS) 14552be1a816SJohn Birrell return (printf("%s: %s\n", g_pname, _dtrace_version) <= 0); 14562be1a816SJohn Birrell 14572be1a816SJohn Birrell /* 14582be1a816SJohn Birrell * If we're in linker mode and the data model hasn't been specified, 14592be1a816SJohn Birrell * we try to guess the appropriate setting by examining the object 14602be1a816SJohn Birrell * files. We ignore certain errors since we'll catch them later when 14612be1a816SJohn Birrell * we actually process the object files. 14622be1a816SJohn Birrell */ 1463*096a5c6cSMark Johnston if (g_mode == DMODE_LINK && (g_oflags & DTRACE_O_MODEL_MASK) == 0 && 14642be1a816SJohn Birrell elf_version(EV_CURRENT) != EV_NONE) { 14652be1a816SJohn Birrell int fd; 14662be1a816SJohn Birrell Elf *elf; 14672be1a816SJohn Birrell GElf_Ehdr ehdr; 14682be1a816SJohn Birrell 14692be1a816SJohn Birrell for (i = 1; i < g_argc; i++) { 14702be1a816SJohn Birrell if ((fd = open64(g_argv[i], O_RDONLY)) == -1) 14712be1a816SJohn Birrell break; 14722be1a816SJohn Birrell 14732be1a816SJohn Birrell if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 14742be1a816SJohn Birrell (void) close(fd); 14752be1a816SJohn Birrell break; 14762be1a816SJohn Birrell } 14772be1a816SJohn Birrell 14782be1a816SJohn Birrell if (elf_kind(elf) != ELF_K_ELF || 14792be1a816SJohn Birrell gelf_getehdr(elf, &ehdr) == NULL) { 14802be1a816SJohn Birrell (void) close(fd); 14812be1a816SJohn Birrell (void) elf_end(elf); 14822be1a816SJohn Birrell break; 14832be1a816SJohn Birrell } 14842be1a816SJohn Birrell 14852be1a816SJohn Birrell (void) close(fd); 14862be1a816SJohn Birrell (void) elf_end(elf); 14872be1a816SJohn Birrell 14882be1a816SJohn Birrell if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 14892be1a816SJohn Birrell if (g_oflags & DTRACE_O_ILP32) { 14902be1a816SJohn Birrell fatal("can't mix 32-bit and 64-bit " 14912be1a816SJohn Birrell "object files\n"); 14922be1a816SJohn Birrell } 14932be1a816SJohn Birrell g_oflags |= DTRACE_O_LP64; 14942be1a816SJohn Birrell } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 14952be1a816SJohn Birrell if (g_oflags & DTRACE_O_LP64) { 14962be1a816SJohn Birrell fatal("can't mix 32-bit and 64-bit " 14972be1a816SJohn Birrell "object files\n"); 14982be1a816SJohn Birrell } 14992be1a816SJohn Birrell g_oflags |= DTRACE_O_ILP32; 15002be1a816SJohn Birrell } else { 15012be1a816SJohn Birrell break; 15022be1a816SJohn Birrell } 15032be1a816SJohn Birrell } 15042be1a816SJohn Birrell } 15052be1a816SJohn Birrell 15062be1a816SJohn Birrell /* 15072be1a816SJohn Birrell * Open libdtrace. If we are not actually going to be enabling any 15082be1a816SJohn Birrell * instrumentation attempt to reopen libdtrace using DTRACE_O_NODEV. 15092be1a816SJohn Birrell */ 15102be1a816SJohn Birrell while ((g_dtp = dtrace_open(DTRACE_VERSION, g_oflags, &err)) == NULL) { 15112be1a816SJohn Birrell if (!(g_oflags & DTRACE_O_NODEV) && !g_exec && !g_grabanon) { 15122be1a816SJohn Birrell g_oflags |= DTRACE_O_NODEV; 15132be1a816SJohn Birrell continue; 15142be1a816SJohn Birrell } 15152be1a816SJohn Birrell 15162be1a816SJohn Birrell fatal("failed to initialize dtrace: %s\n", 15172be1a816SJohn Birrell dtrace_errmsg(NULL, err)); 15182be1a816SJohn Birrell } 15192be1a816SJohn Birrell 1520a6847cf6SJohn Birrell #if defined(__i386__) 1521a6847cf6SJohn Birrell /* XXX The 32-bit seems to need more buffer space by default -sson */ 1522a6847cf6SJohn Birrell (void) dtrace_setopt(g_dtp, "bufsize", "12m"); 1523a6847cf6SJohn Birrell (void) dtrace_setopt(g_dtp, "aggsize", "12m"); 1524a6847cf6SJohn Birrell #else 15252be1a816SJohn Birrell (void) dtrace_setopt(g_dtp, "bufsize", "4m"); 15262be1a816SJohn Birrell (void) dtrace_setopt(g_dtp, "aggsize", "4m"); 1527a6847cf6SJohn Birrell #endif 152809e6105fSMark Johnston (void) dtrace_setopt(g_dtp, "temporal", "yes"); 15292be1a816SJohn Birrell 15302be1a816SJohn Birrell /* 15312be1a816SJohn Birrell * If -G is specified, enable -xlink=dynamic and -xunodefs to permit 15322be1a816SJohn Birrell * references to undefined symbols to remain as unresolved relocations. 15332be1a816SJohn Birrell * If -A is specified, enable -xlink=primary to permit static linking 15342be1a816SJohn Birrell * only to kernel symbols that are defined in a primary kernel module. 15352be1a816SJohn Birrell */ 15362be1a816SJohn Birrell if (g_mode == DMODE_LINK) { 15372be1a816SJohn Birrell (void) dtrace_setopt(g_dtp, "linkmode", "dynamic"); 15382be1a816SJohn Birrell (void) dtrace_setopt(g_dtp, "unodefs", NULL); 15392be1a816SJohn Birrell 15402be1a816SJohn Birrell /* 15412be1a816SJohn Birrell * Use the remaining arguments as the list of object files 15422be1a816SJohn Birrell * when in linker mode. 15432be1a816SJohn Birrell */ 15442be1a816SJohn Birrell g_objc = g_argc - 1; 15452be1a816SJohn Birrell g_objv = g_argv + 1; 15462be1a816SJohn Birrell 15472be1a816SJohn Birrell /* 15482be1a816SJohn Birrell * We still use g_argv[0], the name of the executable. 15492be1a816SJohn Birrell */ 15502be1a816SJohn Birrell g_argc = 1; 15512be1a816SJohn Birrell } else if (g_mode == DMODE_ANON) 15522be1a816SJohn Birrell (void) dtrace_setopt(g_dtp, "linkmode", "primary"); 15532be1a816SJohn Birrell 155493f27766SDomagoj Stolfa 155593f27766SDomagoj Stolfa if (libxo_specified) 155693f27766SDomagoj Stolfa dtrace_oformat_configure(g_dtp); 155793f27766SDomagoj Stolfa 15582be1a816SJohn Birrell /* 15592be1a816SJohn Birrell * Now that we have libdtrace open, make a second pass through argv[] 15602be1a816SJohn Birrell * to perform any dtrace_setopt() calls and change any compiler flags. 15612be1a816SJohn Birrell * We also accumulate any program specifications into our g_cmdv[] at 15622be1a816SJohn Birrell * this time; these will compiled as part of the fourth processing pass. 15632be1a816SJohn Birrell */ 15642be1a816SJohn Birrell for (optind = 1; optind < argc; optind++) { 1565a6847cf6SJohn Birrell while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 15662be1a816SJohn Birrell switch (c) { 15672be1a816SJohn Birrell case 'a': 15682be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "grabanon", 0) != 0) 15692be1a816SJohn Birrell dfatal("failed to set -a"); 15702be1a816SJohn Birrell break; 15712be1a816SJohn Birrell 15722be1a816SJohn Birrell case 'b': 15732be1a816SJohn Birrell if (dtrace_setopt(g_dtp, 15742be1a816SJohn Birrell "bufsize", optarg) != 0) 15752be1a816SJohn Birrell dfatal("failed to set -b %s", optarg); 15762be1a816SJohn Birrell break; 15772be1a816SJohn Birrell 15782be1a816SJohn Birrell case 'B': 15792be1a816SJohn Birrell g_ofp = NULL; 15802be1a816SJohn Birrell break; 15812be1a816SJohn Birrell 15822be1a816SJohn Birrell case 'C': 15832be1a816SJohn Birrell g_cflags |= DTRACE_C_CPP; 15842be1a816SJohn Birrell break; 15852be1a816SJohn Birrell 15861e136a9cSChristos Margiolis case 'd': 15871e136a9cSChristos Margiolis g_cflags |= DTRACE_C_SUGAR; 15881e136a9cSChristos Margiolis break; 15891e136a9cSChristos Margiolis 15902be1a816SJohn Birrell case 'D': 15912be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "define", optarg) != 0) 15922be1a816SJohn Birrell dfatal("failed to set -D %s", optarg); 15932be1a816SJohn Birrell break; 15942be1a816SJohn Birrell 15952be1a816SJohn Birrell case 'f': 15962be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 15972be1a816SJohn Birrell dcp->dc_func = compile_str; 15982be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_FUNC; 15992be1a816SJohn Birrell dcp->dc_arg = optarg; 16002be1a816SJohn Birrell break; 16012be1a816SJohn Birrell 16022be1a816SJohn Birrell case 'F': 16032be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "flowindent", 0) != 0) 16042be1a816SJohn Birrell dfatal("failed to set -F"); 16052be1a816SJohn Birrell break; 16062be1a816SJohn Birrell 16072be1a816SJohn Birrell case 'H': 16082be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "cpphdrs", 0) != 0) 16092be1a816SJohn Birrell dfatal("failed to set -H"); 16102be1a816SJohn Birrell break; 16112be1a816SJohn Birrell 16122be1a816SJohn Birrell case 'i': 16132be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 16142be1a816SJohn Birrell dcp->dc_func = compile_str; 16152be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_NAME; 16162be1a816SJohn Birrell dcp->dc_arg = optarg; 16172be1a816SJohn Birrell break; 16182be1a816SJohn Birrell 16192be1a816SJohn Birrell case 'I': 16202be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "incdir", optarg) != 0) 16212be1a816SJohn Birrell dfatal("failed to set -I %s", optarg); 16222be1a816SJohn Birrell break; 16232be1a816SJohn Birrell 16242be1a816SJohn Birrell case 'L': 16252be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "libdir", optarg) != 0) 16262be1a816SJohn Birrell dfatal("failed to set -L %s", optarg); 16272be1a816SJohn Birrell break; 16282be1a816SJohn Birrell 16292be1a816SJohn Birrell case 'm': 16302be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 16312be1a816SJohn Birrell dcp->dc_func = compile_str; 16322be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_MOD; 16332be1a816SJohn Birrell dcp->dc_arg = optarg; 16342be1a816SJohn Birrell break; 16352be1a816SJohn Birrell 16362be1a816SJohn Birrell case 'n': 16372be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 16382be1a816SJohn Birrell dcp->dc_func = compile_str; 16392be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_NAME; 16402be1a816SJohn Birrell dcp->dc_arg = optarg; 16412be1a816SJohn Birrell break; 16422be1a816SJohn Birrell 16432be1a816SJohn Birrell case 'P': 16442be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 16452be1a816SJohn Birrell dcp->dc_func = compile_str; 16462be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_PROVIDER; 16472be1a816SJohn Birrell dcp->dc_arg = optarg; 16482be1a816SJohn Birrell break; 16492be1a816SJohn Birrell 165093f27766SDomagoj Stolfa case 'O': 165193f27766SDomagoj Stolfa print_upon_exit = 1; 165293f27766SDomagoj Stolfa break; 165393f27766SDomagoj Stolfa 16542be1a816SJohn Birrell case 'q': 16552be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "quiet", 0) != 0) 16562be1a816SJohn Birrell dfatal("failed to set -q"); 16572be1a816SJohn Birrell break; 16582be1a816SJohn Birrell 16592be1a816SJohn Birrell case 'o': 16602be1a816SJohn Birrell g_ofile = optarg; 16612be1a816SJohn Birrell break; 16622be1a816SJohn Birrell 16632be1a816SJohn Birrell case 's': 16642be1a816SJohn Birrell dcp = &g_cmdv[g_cmdc++]; 16652be1a816SJohn Birrell dcp->dc_func = compile_file; 16662be1a816SJohn Birrell dcp->dc_spec = DTRACE_PROBESPEC_NONE; 16672be1a816SJohn Birrell dcp->dc_arg = optarg; 16682be1a816SJohn Birrell break; 16692be1a816SJohn Birrell 16702be1a816SJohn Birrell case 'S': 16712be1a816SJohn Birrell g_cflags |= DTRACE_C_DIFV; 16722be1a816SJohn Birrell break; 16732be1a816SJohn Birrell 16742be1a816SJohn Birrell case 'U': 16752be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "undef", optarg) != 0) 16762be1a816SJohn Birrell dfatal("failed to set -U %s", optarg); 16772be1a816SJohn Birrell break; 16782be1a816SJohn Birrell 16792be1a816SJohn Birrell case 'v': 16802be1a816SJohn Birrell g_verbose++; 16812be1a816SJohn Birrell break; 16822be1a816SJohn Birrell 16832be1a816SJohn Birrell case 'w': 16842be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "destructive", 0) != 0) 16852be1a816SJohn Birrell dfatal("failed to set -w"); 16862be1a816SJohn Birrell break; 16872be1a816SJohn Birrell 16882be1a816SJohn Birrell case 'x': 16892be1a816SJohn Birrell if ((p = strchr(optarg, '=')) != NULL) 16902be1a816SJohn Birrell *p++ = '\0'; 16912be1a816SJohn Birrell 16922be1a816SJohn Birrell if (dtrace_setopt(g_dtp, optarg, p) != 0) 16932be1a816SJohn Birrell dfatal("failed to set -x %s", optarg); 16942be1a816SJohn Birrell break; 16952be1a816SJohn Birrell 16962be1a816SJohn Birrell case 'X': 16972be1a816SJohn Birrell if (dtrace_setopt(g_dtp, "stdc", optarg) != 0) 16982be1a816SJohn Birrell dfatal("failed to set -X %s", optarg); 16992be1a816SJohn Birrell break; 17002be1a816SJohn Birrell 17012be1a816SJohn Birrell case 'Z': 17022be1a816SJohn Birrell g_cflags |= DTRACE_C_ZDEFS; 17032be1a816SJohn Birrell break; 17042be1a816SJohn Birrell 17052be1a816SJohn Birrell default: 17062be1a816SJohn Birrell if (strchr(DTRACE_OPTSTR, c) == NULL) 17072be1a816SJohn Birrell return (usage(stderr)); 17082be1a816SJohn Birrell } 17092be1a816SJohn Birrell } 17102be1a816SJohn Birrell } 17112be1a816SJohn Birrell 17122be1a816SJohn Birrell if (g_ofp == NULL && g_mode != DMODE_EXEC) { 17132be1a816SJohn Birrell (void) fprintf(stderr, "%s: -B not valid in combination" 17142be1a816SJohn Birrell " with [-AGl] options\n", g_pname); 17152be1a816SJohn Birrell return (E_USAGE); 17162be1a816SJohn Birrell } 17172be1a816SJohn Birrell 17182be1a816SJohn Birrell if (g_ofp == NULL && g_ofile != NULL) { 17192be1a816SJohn Birrell (void) fprintf(stderr, "%s: -B not valid in combination" 17202be1a816SJohn Birrell " with -o option\n", g_pname); 17212be1a816SJohn Birrell return (E_USAGE); 17222be1a816SJohn Birrell } 17232be1a816SJohn Birrell 17242be1a816SJohn Birrell /* 17252be1a816SJohn Birrell * In our third pass we handle any command-line options related to 17262be1a816SJohn Birrell * grabbing or creating victim processes. The behavior of these calls 17272be1a816SJohn Birrell * may been affected by any library options set by the second pass. 17282be1a816SJohn Birrell */ 17292be1a816SJohn Birrell for (optind = 1; optind < argc; optind++) { 1730a6847cf6SJohn Birrell while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) { 17312be1a816SJohn Birrell switch (c) { 17322be1a816SJohn Birrell case 'c': 17332be1a816SJohn Birrell if ((v = make_argv(optarg)) == NULL) 17342be1a816SJohn Birrell fatal("failed to allocate memory"); 17352be1a816SJohn Birrell 173656b35563SCraig Rodrigues P = dtrace_proc_create(g_dtp, v[0], v, NULL, NULL); 17372be1a816SJohn Birrell if (P == NULL) 17382be1a816SJohn Birrell dfatal(NULL); /* dtrace_errmsg() only */ 17392be1a816SJohn Birrell 17402be1a816SJohn Birrell g_psv[g_psc++] = P; 17412be1a816SJohn Birrell free(v); 17422be1a816SJohn Birrell break; 17432be1a816SJohn Birrell 17442be1a816SJohn Birrell case 'p': 17452be1a816SJohn Birrell errno = 0; 17462be1a816SJohn Birrell pid = strtol(optarg, &p, 10); 17472be1a816SJohn Birrell 17482be1a816SJohn Birrell if (errno != 0 || p == optarg || p[0] != '\0') 17492be1a816SJohn Birrell fatal("invalid pid: %s\n", optarg); 17502be1a816SJohn Birrell 17512be1a816SJohn Birrell P = dtrace_proc_grab(g_dtp, pid, 0); 17522be1a816SJohn Birrell if (P == NULL) 17532be1a816SJohn Birrell dfatal(NULL); /* dtrace_errmsg() only */ 17542be1a816SJohn Birrell 17552be1a816SJohn Birrell g_psv[g_psc++] = P; 17562be1a816SJohn Birrell break; 17572be1a816SJohn Birrell } 17582be1a816SJohn Birrell } 17592be1a816SJohn Birrell } 17602be1a816SJohn Birrell 17612be1a816SJohn Birrell /* 17622be1a816SJohn Birrell * In our fourth pass we finish g_cmdv[] by calling dc_func to convert 17632be1a816SJohn Birrell * each string or file specification into a compiled program structure. 17642be1a816SJohn Birrell */ 17652be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) 17662be1a816SJohn Birrell g_cmdv[i].dc_func(&g_cmdv[i]); 17672be1a816SJohn Birrell 17682be1a816SJohn Birrell if (g_mode != DMODE_LIST) { 17692be1a816SJohn Birrell if (dtrace_handle_err(g_dtp, &errhandler, NULL) == -1) 17702be1a816SJohn Birrell dfatal("failed to establish error handler"); 17712be1a816SJohn Birrell 17722be1a816SJohn Birrell if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1) 17732be1a816SJohn Birrell dfatal("failed to establish drop handler"); 17742be1a816SJohn Birrell 17752be1a816SJohn Birrell if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1) 17762be1a816SJohn Birrell dfatal("failed to establish proc handler"); 17772be1a816SJohn Birrell 17782be1a816SJohn Birrell if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1) 17792be1a816SJohn Birrell dfatal("failed to establish setopt handler"); 17802be1a816SJohn Birrell 17812be1a816SJohn Birrell if (g_ofp == NULL && 17822be1a816SJohn Birrell dtrace_handle_buffered(g_dtp, &bufhandler, NULL) == -1) 17832be1a816SJohn Birrell dfatal("failed to establish buffered handler"); 17842be1a816SJohn Birrell } 17852be1a816SJohn Birrell 17862be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "flowindent", &opt); 17872be1a816SJohn Birrell g_flowindent = opt != DTRACEOPT_UNSET; 17882be1a816SJohn Birrell 17892be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "grabanon", &opt); 17902be1a816SJohn Birrell g_grabanon = opt != DTRACEOPT_UNSET; 17912be1a816SJohn Birrell 17922be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "quiet", &opt); 17932be1a816SJohn Birrell g_quiet = opt != DTRACEOPT_UNSET; 17942be1a816SJohn Birrell 179593f27766SDomagoj Stolfa if (dtrace_oformat(g_dtp)) { 179693f27766SDomagoj Stolfa if (dtrace_setopt(g_dtp, "quiet", 0) != 0) 179793f27766SDomagoj Stolfa dfatal("failed to set quiet (caused by oformat)"); 179893f27766SDomagoj Stolfa } 179993f27766SDomagoj Stolfa 18002be1a816SJohn Birrell /* 18012be1a816SJohn Birrell * Now make a fifth and final pass over the options that have been 18022be1a816SJohn Birrell * turned into programs and saved in g_cmdv[], performing any mode- 18032be1a816SJohn Birrell * specific processing. If g_mode is DMODE_EXEC, we will break out 18042be1a816SJohn Birrell * of the switch() and continue on to the data processing loop. For 18052be1a816SJohn Birrell * other modes, we will exit dtrace once mode-specific work is done. 18062be1a816SJohn Birrell */ 18072be1a816SJohn Birrell switch (g_mode) { 18082be1a816SJohn Birrell case DMODE_EXEC: 18092be1a816SJohn Birrell if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 18102be1a816SJohn Birrell fatal("failed to open output file '%s'", g_ofile); 18112be1a816SJohn Birrell 181293f27766SDomagoj Stolfa if (dtrace_oformat(g_dtp)) 181393f27766SDomagoj Stolfa dtrace_set_outfp(g_ofp); 181493f27766SDomagoj Stolfa 18152be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) 18162be1a816SJohn Birrell exec_prog(&g_cmdv[i]); 18172be1a816SJohn Birrell 18182be1a816SJohn Birrell if (done && !g_grabanon) { 18192be1a816SJohn Birrell dtrace_close(g_dtp); 18202be1a816SJohn Birrell return (g_status); 18212be1a816SJohn Birrell } 18222be1a816SJohn Birrell break; 18232be1a816SJohn Birrell 18242be1a816SJohn Birrell case DMODE_ANON: 18252be1a816SJohn Birrell if (g_ofile == NULL) 1826bc96366cSSteven Hartland #ifdef illumos 18272be1a816SJohn Birrell g_ofile = "/kernel/drv/dtrace.conf"; 1828a6847cf6SJohn Birrell #else 1829a6847cf6SJohn Birrell /* 1830a6847cf6SJohn Birrell * On FreeBSD, anonymous DOF data is written to 1831b5290286SMark Johnston * the DTrace DOF file. 1832a6847cf6SJohn Birrell */ 1833a6847cf6SJohn Birrell g_ofile = "/boot/dtrace.dof"; 1834a6847cf6SJohn Birrell #endif 18352be1a816SJohn Birrell 18362be1a816SJohn Birrell dof_prune(g_ofile); /* strip out any old DOF directives */ 1837bc96366cSSteven Hartland #ifdef illumos 18382be1a816SJohn Birrell etcsystem_prune(); /* string out any forceload directives */ 1839a6847cf6SJohn Birrell #endif 18402be1a816SJohn Birrell 18412be1a816SJohn Birrell if (g_cmdc == 0) { 18422be1a816SJohn Birrell dtrace_close(g_dtp); 18432be1a816SJohn Birrell return (g_status); 18442be1a816SJohn Birrell } 18452be1a816SJohn Birrell 18462be1a816SJohn Birrell if ((g_ofp = fopen(g_ofile, "a")) == NULL) 18472be1a816SJohn Birrell fatal("failed to open output file '%s'", g_ofile); 18482be1a816SJohn Birrell 184993f27766SDomagoj Stolfa if (dtrace_oformat(g_dtp)) 185093f27766SDomagoj Stolfa dtrace_set_outfp(g_ofp); 185193f27766SDomagoj Stolfa 18522be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) { 18532be1a816SJohn Birrell anon_prog(&g_cmdv[i], 18542be1a816SJohn Birrell dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i); 18552be1a816SJohn Birrell } 18562be1a816SJohn Birrell 18572be1a816SJohn Birrell /* 18582be1a816SJohn Birrell * Dump out the DOF corresponding to the error handler and the 18592be1a816SJohn Birrell * current options as the final DOF property in the .conf file. 18602be1a816SJohn Birrell */ 18612be1a816SJohn Birrell anon_prog(NULL, dtrace_geterr_dof(g_dtp), i++); 18622be1a816SJohn Birrell anon_prog(NULL, dtrace_getopt_dof(g_dtp), i++); 18632be1a816SJohn Birrell 18642be1a816SJohn Birrell if (fclose(g_ofp) == EOF) 18652be1a816SJohn Birrell fatal("failed to close output file '%s'", g_ofile); 18662be1a816SJohn Birrell 18672be1a816SJohn Birrell /* 18682be1a816SJohn Birrell * These messages would use notice() rather than error(), but 18692be1a816SJohn Birrell * we don't want them suppressed when -A is run on a D program 18702be1a816SJohn Birrell * that itself contains a #pragma D option quiet. 18712be1a816SJohn Birrell */ 18722be1a816SJohn Birrell error("saved anonymous enabling in %s\n", g_ofile); 1873b5290286SMark Johnston 1874b5290286SMark Johnston #ifdef __FreeBSD__ 1875b5290286SMark Johnston bootdof_add(); 1876b5290286SMark Johnston #else 18772be1a816SJohn Birrell etcsystem_add(); 18782be1a816SJohn Birrell error("run update_drv(1M) or reboot to enable changes\n"); 1879a6847cf6SJohn Birrell #endif 18802be1a816SJohn Birrell 18812be1a816SJohn Birrell dtrace_close(g_dtp); 18822be1a816SJohn Birrell return (g_status); 18832be1a816SJohn Birrell 18842be1a816SJohn Birrell case DMODE_LINK: 18852be1a816SJohn Birrell if (g_cmdc == 0) { 18862be1a816SJohn Birrell (void) fprintf(stderr, "%s: -G requires one or more " 18872be1a816SJohn Birrell "scripts or enabling options\n", g_pname); 18882be1a816SJohn Birrell dtrace_close(g_dtp); 18892be1a816SJohn Birrell return (E_USAGE); 18902be1a816SJohn Birrell } 18912be1a816SJohn Birrell 18922be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) 18932be1a816SJohn Birrell link_prog(&g_cmdv[i]); 18942be1a816SJohn Birrell 18952be1a816SJohn Birrell if (g_cmdc > 1 && g_ofile != NULL) { 18962be1a816SJohn Birrell char **objv = alloca(g_cmdc * sizeof (char *)); 18972be1a816SJohn Birrell 18982be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) 18992be1a816SJohn Birrell objv[i] = g_cmdv[i].dc_ofile; 19002be1a816SJohn Birrell 19012be1a816SJohn Birrell if (dtrace_program_link(g_dtp, NULL, DTRACE_D_PROBES, 19022be1a816SJohn Birrell g_ofile, g_cmdc, objv) != 0) 19032be1a816SJohn Birrell dfatal(NULL); /* dtrace_errmsg() only */ 19042be1a816SJohn Birrell } 19052be1a816SJohn Birrell 19062be1a816SJohn Birrell dtrace_close(g_dtp); 19072be1a816SJohn Birrell return (g_status); 19082be1a816SJohn Birrell 19092be1a816SJohn Birrell case DMODE_LIST: 19102be1a816SJohn Birrell if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) 19112be1a816SJohn Birrell fatal("failed to open output file '%s'", g_ofile); 19122be1a816SJohn Birrell 1913486de25dSMark Johnston installsighands(); 1914486de25dSMark Johnston 19152be1a816SJohn Birrell oprintf("%5s %10s %17s %33s %s\n", 19162be1a816SJohn Birrell "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME"); 19172be1a816SJohn Birrell 19182be1a816SJohn Birrell for (i = 0; i < g_cmdc; i++) 19192be1a816SJohn Birrell list_prog(&g_cmdv[i]); 19202be1a816SJohn Birrell 19212be1a816SJohn Birrell if (g_cmdc == 0) 19222be1a816SJohn Birrell (void) dtrace_probe_iter(g_dtp, NULL, list_probe, NULL); 19232be1a816SJohn Birrell 19242be1a816SJohn Birrell dtrace_close(g_dtp); 19252be1a816SJohn Birrell return (g_status); 19262be1a816SJohn Birrell 19272be1a816SJohn Birrell case DMODE_HEADER: 19282be1a816SJohn Birrell if (g_cmdc == 0) { 19292be1a816SJohn Birrell (void) fprintf(stderr, "%s: -h requires one or more " 19302be1a816SJohn Birrell "scripts or enabling options\n", g_pname); 19312be1a816SJohn Birrell dtrace_close(g_dtp); 19322be1a816SJohn Birrell return (E_USAGE); 19332be1a816SJohn Birrell } 19342be1a816SJohn Birrell 19352be1a816SJohn Birrell if (g_ofile == NULL) { 19362be1a816SJohn Birrell char *p; 19372be1a816SJohn Birrell 19382be1a816SJohn Birrell if (g_cmdc > 1) { 19392be1a816SJohn Birrell (void) fprintf(stderr, "%s: -h requires an " 19402be1a816SJohn Birrell "output file if multiple scripts are " 19412be1a816SJohn Birrell "specified\n", g_pname); 19422be1a816SJohn Birrell dtrace_close(g_dtp); 19432be1a816SJohn Birrell return (E_USAGE); 19442be1a816SJohn Birrell } 19452be1a816SJohn Birrell 19462be1a816SJohn Birrell if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL || 19472be1a816SJohn Birrell strcmp(p, ".d") != 0) { 19482be1a816SJohn Birrell (void) fprintf(stderr, "%s: -h requires an " 19492be1a816SJohn Birrell "output file if no scripts are " 19502be1a816SJohn Birrell "specified\n", g_pname); 19512be1a816SJohn Birrell dtrace_close(g_dtp); 19522be1a816SJohn Birrell return (E_USAGE); 19532be1a816SJohn Birrell } 19542be1a816SJohn Birrell 19552be1a816SJohn Birrell p[0] = '\0'; /* strip .d suffix */ 19562be1a816SJohn Birrell g_ofile = p = g_cmdv[0].dc_ofile; 19572be1a816SJohn Birrell (void) snprintf(p, sizeof (g_cmdv[0].dc_ofile), 19582be1a816SJohn Birrell "%s.h", basename(g_cmdv[0].dc_arg)); 19592be1a816SJohn Birrell } 19602be1a816SJohn Birrell 19612be1a816SJohn Birrell if ((g_ofp = fopen(g_ofile, "w")) == NULL) 19622be1a816SJohn Birrell fatal("failed to open header file '%s'", g_ofile); 19632be1a816SJohn Birrell 19642be1a816SJohn Birrell oprintf("/*\n * Generated by dtrace(1M).\n */\n\n"); 19652be1a816SJohn Birrell 19662be1a816SJohn Birrell if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 || 19672be1a816SJohn Birrell fclose(g_ofp) == EOF) 19682be1a816SJohn Birrell dfatal("failed to create header file %s", g_ofile); 19692be1a816SJohn Birrell 19702be1a816SJohn Birrell dtrace_close(g_dtp); 19712be1a816SJohn Birrell return (g_status); 19722be1a816SJohn Birrell } 19732be1a816SJohn Birrell 19742be1a816SJohn Birrell /* 19752be1a816SJohn Birrell * If -a and -Z were not specified and no probes have been matched, no 19762be1a816SJohn Birrell * probe criteria was specified on the command line and we abort. 19772be1a816SJohn Birrell */ 19782be1a816SJohn Birrell if (g_total == 0 && !g_grabanon && !(g_cflags & DTRACE_C_ZDEFS)) 19792be1a816SJohn Birrell dfatal("no probes %s\n", g_cmdc ? "matched" : "specified"); 19802be1a816SJohn Birrell 19812be1a816SJohn Birrell /* 19822be1a816SJohn Birrell * Start tracing. Once we dtrace_go(), reload any options that affect 19832be1a816SJohn Birrell * our globals in case consuming anonymous state has changed them. 19842be1a816SJohn Birrell */ 19852be1a816SJohn Birrell go(); 19862be1a816SJohn Birrell 19872be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "flowindent", &opt); 19882be1a816SJohn Birrell g_flowindent = opt != DTRACEOPT_UNSET; 19892be1a816SJohn Birrell 19902be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "grabanon", &opt); 19912be1a816SJohn Birrell g_grabanon = opt != DTRACEOPT_UNSET; 19922be1a816SJohn Birrell 19932be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "quiet", &opt); 19942be1a816SJohn Birrell g_quiet = opt != DTRACEOPT_UNSET; 19952be1a816SJohn Birrell 19962be1a816SJohn Birrell (void) dtrace_getopt(g_dtp, "destructive", &opt); 19972be1a816SJohn Birrell if (opt != DTRACEOPT_UNSET) 19982be1a816SJohn Birrell notice("allowing destructive actions\n"); 19992be1a816SJohn Birrell 2000486de25dSMark Johnston installsighands(); 2001a6847cf6SJohn Birrell 20022be1a816SJohn Birrell /* 20032be1a816SJohn Birrell * Now that tracing is active and we are ready to consume trace data, 20042be1a816SJohn Birrell * continue any grabbed or created processes, setting them running 20052be1a816SJohn Birrell * using the /proc control mechanism inside of libdtrace. 20062be1a816SJohn Birrell */ 20072be1a816SJohn Birrell for (i = 0; i < g_psc; i++) 20082be1a816SJohn Birrell dtrace_proc_continue(g_dtp, g_psv[i]); 20092be1a816SJohn Birrell 20102be1a816SJohn Birrell g_pslive = g_psc; /* count for prochandler() */ 20112be1a816SJohn Birrell 201293f27766SDomagoj Stolfa dtrace_oformat_setup(g_dtp); 20132be1a816SJohn Birrell do { 20142be1a816SJohn Birrell if (!g_intr && !done) 20152be1a816SJohn Birrell dtrace_sleep(g_dtp); 20162be1a816SJohn Birrell 2017be9cb745SMark Johnston #ifdef __FreeBSD__ 201893f27766SDomagoj Stolfa /* 201993f27766SDomagoj Stolfa * XXX: Supporting SIGINFO with oformat makes little sense, as 202093f27766SDomagoj Stolfa * it can't really produce sensible DTrace output. 202193f27766SDomagoj Stolfa * 202293f27766SDomagoj Stolfa * If needed, we could support it by having an imaginary 202393f27766SDomagoj Stolfa * "SIGINFO" probe that we can construct in the output but leave 202493f27766SDomagoj Stolfa * it out for now. 202593f27766SDomagoj Stolfa */ 202693f27766SDomagoj Stolfa if (g_siginfo && !dtrace_oformat(g_dtp)) { 2027be9cb745SMark Johnston (void)dtrace_aggregate_print(g_dtp, g_ofp, NULL); 2028be9cb745SMark Johnston g_siginfo = 0; 2029be9cb745SMark Johnston } 2030be9cb745SMark Johnston #endif 2031be9cb745SMark Johnston 20322be1a816SJohn Birrell if (g_newline) { 20332be1a816SJohn Birrell /* 20342be1a816SJohn Birrell * Output a newline just to make the output look 20352be1a816SJohn Birrell * slightly cleaner. Note that we do this even in 20362be1a816SJohn Birrell * "quiet" mode... 20372be1a816SJohn Birrell */ 20382be1a816SJohn Birrell oprintf("\n"); 20392be1a816SJohn Birrell g_newline = 0; 20402be1a816SJohn Birrell } 20412be1a816SJohn Birrell 20422be1a816SJohn Birrell if (done || g_intr || (g_psc != 0 && g_pslive == 0)) { 20432be1a816SJohn Birrell done = 1; 20442be1a816SJohn Birrell if (dtrace_stop(g_dtp) == -1) 20452be1a816SJohn Birrell dfatal("couldn't stop tracing"); 20462be1a816SJohn Birrell } 20472be1a816SJohn Birrell 20482be1a816SJohn Birrell switch (dtrace_work(g_dtp, g_ofp, chew, chewrec, NULL)) { 20492be1a816SJohn Birrell case DTRACE_WORKSTATUS_DONE: 20502be1a816SJohn Birrell done = 1; 20512be1a816SJohn Birrell break; 20522be1a816SJohn Birrell case DTRACE_WORKSTATUS_OKAY: 20532be1a816SJohn Birrell break; 20542be1a816SJohn Birrell default: 20552be1a816SJohn Birrell if (!g_impatient && dtrace_errno(g_dtp) != EINTR) 20562be1a816SJohn Birrell dfatal("processing aborted"); 20572be1a816SJohn Birrell } 20582be1a816SJohn Birrell 20592be1a816SJohn Birrell if (g_ofp != NULL && fflush(g_ofp) == EOF) 20602be1a816SJohn Birrell clearerr(g_ofp); 20612be1a816SJohn Birrell } while (!done); 20622be1a816SJohn Birrell 206393f27766SDomagoj Stolfa if (!dtrace_oformat(g_dtp)) 20642be1a816SJohn Birrell oprintf("\n"); 20652be1a816SJohn Birrell 206693f27766SDomagoj Stolfa /* 206793f27766SDomagoj Stolfa * Since there is no way to format a probe here and machine-readable 206893f27766SDomagoj Stolfa * output makes little sense without explicitly asking for it, we print 206993f27766SDomagoj Stolfa * nothing upon Ctrl-C if oformat is specified. If the user wishes to 207093f27766SDomagoj Stolfa * get output upon exit, they must write an explicit dtrace:::END probe 207193f27766SDomagoj Stolfa * to do so. 207293f27766SDomagoj Stolfa */ 207393f27766SDomagoj Stolfa if ((!g_impatient && !dtrace_oformat(g_dtp)) || 207493f27766SDomagoj Stolfa (!g_impatient && print_upon_exit)) { 20752be1a816SJohn Birrell if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 && 20762be1a816SJohn Birrell dtrace_errno(g_dtp) != EINTR) 20772be1a816SJohn Birrell dfatal("failed to print aggregations"); 20782be1a816SJohn Birrell } 20792be1a816SJohn Birrell 208093f27766SDomagoj Stolfa dtrace_oformat_teardown(g_dtp); 20812be1a816SJohn Birrell dtrace_close(g_dtp); 20822be1a816SJohn Birrell return (g_status); 20832be1a816SJohn Birrell } 2084