xref: /freebsd/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c (revision 096a5c6cd28c417456d5ce3598be15e6b656af5c)
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