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
usage(FILE * fp)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
verror(const char * fmt,va_list ap)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
fatal(const char * fmt,...)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
dfatal(const char * fmt,...)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
error(const char * fmt,...)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
notice(const char * fmt,...)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
oprintf(const char * fmt,...)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 **
make_argv(char * s)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
dof_prune(const char * fname)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
bootdof_add(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
etcsystem_prune(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
etcsystem_add(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
print_probe_info(const dtrace_probeinfo_t * p)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
info_stmt(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * stp,dtrace_ecbdesc_t ** last)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
exec_prog(const dtrace_cmd_t * dcp)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
anon_prog(const dtrace_cmd_t * dcp,dof_hdr_t * dof,int n)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
link_prog(dtrace_cmd_t * dcp)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
list_probe(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,void * arg)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
list_stmt(dtrace_hdl_t * dtp,dtrace_prog_t * pgp,dtrace_stmtdesc_t * stp,dtrace_ecbdesc_t ** last)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
list_prog(const dtrace_cmd_t * dcp)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
compile_file(dtrace_cmd_t * dcp)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
compile_str(dtrace_cmd_t * dcp)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
prochandler(struct ps_prochandle * P,const char * msg,void * arg)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