1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26/*
27 * Copyright (c) 2012 by Delphix. All rights reserved.
28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
30 */
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/wait.h>
35
36#include <dtrace.h>
37#include <stdlib.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <string.h>
41#include <strings.h>
42#include <unistd.h>
43#include <limits.h>
44#include <fcntl.h>
45#include <errno.h>
46#include <signal.h>
47#ifdef illumos
48#include <alloca.h>
49#endif
50#include <libgen.h>
51#ifdef illumos
52#include <libproc.h>
53#endif
54#ifdef __FreeBSD__
55#include <locale.h>
56#include <spawn.h>
57#endif
58
59#undef NORETURN /* needed because libxo redefines it */
60#include <libxo/xo.h>
61
62typedef struct dtrace_cmd {
63	void (*dc_func)(struct dtrace_cmd *);	/* function to compile arg */
64	dtrace_probespec_t dc_spec;		/* probe specifier context */
65	char *dc_arg;				/* argument from main argv */
66	const char *dc_name;			/* name for error messages */
67	const char *dc_desc;			/* desc for error messages */
68	dtrace_prog_t *dc_prog;			/* program compiled from arg */
69	char dc_ofile[PATH_MAX];		/* derived output file name */
70} dtrace_cmd_t;
71
72#define	DMODE_VERS	0	/* display version information and exit (-V) */
73#define	DMODE_EXEC	1	/* compile program for enabling (-a/e/E) */
74#define	DMODE_ANON	2	/* compile program for anonymous tracing (-A) */
75#define	DMODE_LINK	3	/* compile program for linking with ELF (-G) */
76#define	DMODE_LIST	4	/* compile program and list probes (-l) */
77#define	DMODE_HEADER	5	/* compile program for headergen (-h) */
78
79#define	E_SUCCESS	0
80#define	E_ERROR		1
81#define	E_USAGE		2
82
83static const char DTRACE_OPTSTR[] =
84	"3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:Op:P:qs:SU:vVwx:X:Z";
85
86static char **g_argv;
87static int g_argc;
88static char **g_objv;
89static int g_objc;
90static dtrace_cmd_t *g_cmdv;
91static int g_cmdc;
92static struct ps_prochandle **g_psv;
93static int g_psc;
94static int g_pslive;
95static char *g_pname;
96static int g_quiet;
97static int g_flowindent;
98static int g_intr;
99static int g_impatient;
100static int g_newline;
101#ifdef __FreeBSD__
102static int g_siginfo;
103#endif
104static int g_total;
105static int g_cflags;
106static int g_oflags;
107static int g_verbose;
108static int g_exec = 1;
109static int g_mode = DMODE_EXEC;
110static int g_status = E_SUCCESS;
111static int g_grabanon = 0;
112static const char *g_ofile = NULL;
113static FILE *g_ofp;
114static dtrace_hdl_t *g_dtp;
115#ifdef illumos
116static char *g_etcfile = "/etc/system";
117static const char *g_etcbegin = "* vvvv Added by DTrace";
118static const char *g_etcend = "* ^^^^ Added by DTrace";
119
120static const char *g_etc[] =  {
121"*",
122"* The following forceload directives were added by dtrace(1M) to allow for",
123"* tracing during boot.  If these directives are removed, the system will",
124"* continue to function, but tracing will not occur during boot as desired.",
125"* To remove these directives (and this block comment) automatically, run",
126"* \"dtrace -A\" without additional arguments.  See the \"Anonymous Tracing\"",
127"* chapter of the Solaris Dynamic Tracing Guide for details.",
128"*",
129NULL };
130#endif
131
132static int
133usage(FILE *fp)
134{
135	static const char predact[] = "[[ predicate ] action ]";
136
137	(void) fprintf(fp, "Usage: %s [-32|-64] [-aACdeFGhHlqSvVwZ] "
138	    "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] "
139	    "[-o output] [-p pid] [-s script] [-U name]\n\t"
140	    "[-x opt[=val]] [-X a|c|s|t]\n\n"
141	    "\t[-P provider %s]\n"
142	    "\t[-m [ provider: ] module %s]\n"
143	    "\t[-f [[ provider: ] module: ] func %s]\n"
144	    "\t[-n [[[ provider: ] module: ] func: ] name %s]\n"
145	    "\t[-i probe-id %s] [ args ... ]\n\n", g_pname,
146	    predact, predact, predact, predact, predact);
147
148	(void) fprintf(fp, "\tpredicate -> '/' D-expression '/'\n");
149	(void) fprintf(fp, "\t   action -> '{' D-statements '}'\n");
150
151	(void) fprintf(fp, "\n"
152	    "\t-32 generate 32-bit D programs and ELF files\n"
153	    "\t-64 generate 64-bit D programs and ELF files\n\n"
154	    "\t-a  claim anonymous tracing state\n"
155	    "\t-A  generate driver.conf(4) directives for anonymous tracing\n"
156	    "\t-b  set trace buffer size\n"
157	    "\t-c  run specified command and exit upon its completion\n"
158	    "\t-C  run cpp(1) preprocessor on script files\n"
159	    "\t-d  dump script after syntactic transformations\n"
160	    "\t-D  define symbol when invoking preprocessor\n"
161	    "\t-e  exit after compiling request but prior to enabling probes\n"
162	    "\t-f  enable or list probes matching the specified function name\n"
163	    "\t-F  coalesce trace output by function\n"
164	    "\t-G  generate an ELF file containing embedded dtrace program\n"
165	    "\t-h  generate a header file with definitions for static probes\n"
166	    "\t-H  print included files when invoking preprocessor\n"
167	    "\t-i  enable or list probes matching the specified probe id\n"
168	    "\t-I  add include directory to preprocessor search path\n"
169	    "\t-l  list probes matching specified criteria\n"
170	    "\t-L  add library directory to library search path\n"
171	    "\t-m  enable or list probes matching the specified module name\n"
172	    "\t-n  enable or list probes matching the specified probe name\n"
173	    "\t-o  set output file\n"
174	    "\t-O  print output upon exiting (specific to oformat)\n"
175	    "\t-p  grab specified process-ID and cache its symbol tables\n"
176	    "\t-P  enable or list probes matching the specified provider name\n"
177	    "\t-q  set quiet mode (only output explicitly traced data)\n"
178	    "\t-s  enable or list probes according to the specified D script\n"
179	    "\t-S  print D compiler intermediate code\n"
180	    "\t-U  undefine symbol when invoking preprocessor\n"
181	    "\t-v  set verbose mode (report stability attributes, arguments)\n"
182	    "\t-V  report DTrace API version\n"
183	    "\t-w  permit destructive actions\n"
184	    "\t-x  enable or modify compiler and tracing options\n"
185	    "\t-X  specify ISO C conformance settings for preprocessor\n"
186	    "\t-Z  permit probe descriptions that match zero probes\n");
187
188	return (E_USAGE);
189}
190
191static void
192verror(const char *fmt, va_list ap)
193{
194	int error = errno;
195
196	(void) fprintf(stderr, "%s: ", g_pname);
197	(void) vfprintf(stderr, fmt, ap);
198
199	if (fmt[strlen(fmt) - 1] != '\n')
200		(void) fprintf(stderr, ": %s\n", strerror(error));
201}
202
203/*PRINTFLIKE1*/
204static void
205fatal(const char *fmt, ...)
206{
207	va_list ap;
208
209	va_start(ap, fmt);
210	verror(fmt, ap);
211	va_end(ap);
212
213	/*
214	 * Close the DTrace handle to ensure that any controlled processes are
215	 * correctly restored and continued.
216	 */
217	if (g_dtp)
218		dtrace_close(g_dtp);
219
220	exit(E_ERROR);
221}
222
223/*PRINTFLIKE1*/
224static void
225dfatal(const char *fmt, ...)
226{
227#if !defined(illumos) && defined(NEED_ERRLOC)
228	char *p_errfile = NULL;
229	int errline = 0;
230#endif
231	va_list ap;
232
233	va_start(ap, fmt);
234
235	(void) fprintf(stderr, "%s: ", g_pname);
236	if (fmt != NULL)
237		(void) vfprintf(stderr, fmt, ap);
238
239	va_end(ap);
240
241	if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') {
242		(void) fprintf(stderr, ": %s\n",
243		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
244	} else if (fmt == NULL) {
245		(void) fprintf(stderr, "%s\n",
246		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
247	}
248#if !defined(illumos) && defined(NEED_ERRLOC)
249	dt_get_errloc(g_dtp, &p_errfile, &errline);
250	if (p_errfile != NULL)
251		printf("File '%s', line %d\n", p_errfile, errline);
252#endif
253
254	/*
255	 * Close the DTrace handle to ensure that any controlled processes are
256	 * correctly restored and continued.
257	 */
258	dtrace_close(g_dtp);
259
260	exit(E_ERROR);
261}
262
263/*PRINTFLIKE1*/
264static void
265error(const char *fmt, ...)
266{
267	va_list ap;
268
269	va_start(ap, fmt);
270	verror(fmt, ap);
271	va_end(ap);
272}
273
274/*PRINTFLIKE1*/
275static void
276notice(const char *fmt, ...)
277{
278	va_list ap;
279
280	if (g_quiet)
281		return; /* -q or quiet pragma suppresses notice()s */
282
283	va_start(ap, fmt);
284	verror(fmt, ap);
285	va_end(ap);
286}
287
288/*PRINTFLIKE1*/
289static void
290oprintf(const char *fmt, ...)
291{
292	va_list ap;
293	int n;
294
295	if (g_ofp == NULL)
296		return;
297
298	va_start(ap, fmt);
299	n = vfprintf(g_ofp, fmt, ap);
300	va_end(ap);
301
302	if (n < 0) {
303		if (errno != EINTR) {
304			fatal("failed to write to %s",
305			    g_ofile ? g_ofile : "<stdout>");
306		}
307		clearerr(g_ofp);
308	}
309}
310
311static char **
312make_argv(char *s)
313{
314	const char *ws = "\f\n\r\t\v ";
315	char **argv = malloc(sizeof (char *) * (strlen(s) / 2 + 1));
316	int argc = 0;
317	char *p = s;
318
319	if (argv == NULL)
320		return (NULL);
321
322	for (p = strtok(s, ws); p != NULL; p = strtok(NULL, ws))
323		argv[argc++] = p;
324
325	if (argc == 0)
326		argv[argc++] = s;
327
328	argv[argc] = NULL;
329	return (argv);
330}
331
332static void
333dof_prune(const char *fname)
334{
335	struct stat sbuf;
336	size_t sz, i, j, mark, len;
337	char *buf;
338	int msg = 0, fd;
339
340	if ((fd = open(fname, O_RDONLY)) == -1) {
341		/*
342		 * This is okay only if the file doesn't exist at all.
343		 */
344		if (errno != ENOENT)
345			fatal("failed to open %s", fname);
346		return;
347	}
348
349	if (fstat(fd, &sbuf) == -1)
350		fatal("failed to fstat %s", fname);
351
352	if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL)
353		fatal("failed to allocate memory for %s", fname);
354
355	if (read(fd, buf, sz) != sz)
356		fatal("failed to read %s", fname);
357
358	buf[sz] = '\0';
359	(void) close(fd);
360
361	if ((fd = open(fname, O_WRONLY | O_TRUNC)) == -1)
362		fatal("failed to open %s for writing", fname);
363
364	len = strlen("dof-data-");
365
366	for (mark = 0, i = 0; i < sz; i++) {
367		if (strncmp(&buf[i], "dof-data-", len) != 0)
368			continue;
369
370		/*
371		 * This is only a match if it's in the 0th column.
372		 */
373		if (i != 0 && buf[i - 1] != '\n')
374			continue;
375
376		if (msg++ == 0) {
377			error("cleaned up old anonymous "
378			    "enabling in %s\n", fname);
379		}
380
381		/*
382		 * We have a match.  First write out our data up until now.
383		 */
384		if (i != mark) {
385			if (write(fd, &buf[mark], i - mark) != i - mark)
386				fatal("failed to write to %s", fname);
387		}
388
389		/*
390		 * Now scan forward until we scan past a newline.
391		 */
392		for (j = i; j < sz && buf[j] != '\n'; j++)
393			continue;
394
395		/*
396		 * Reset our mark.
397		 */
398		if ((mark = j + 1) >= sz)
399			break;
400
401		i = j;
402	}
403
404	if (mark < sz) {
405		if (write(fd, &buf[mark], sz - mark) != sz - mark)
406			fatal("failed to write to %s", fname);
407	}
408
409	(void) close(fd);
410	free(buf);
411}
412
413#ifdef __FreeBSD__
414/*
415 * Use nextboot(8) to tell the loader to load DTrace kernel modules during
416 * the next boot of the system. The nextboot(8) configuration is removed during
417 * boot, so it will not persist indefinitely.
418 */
419static void
420bootdof_add(void)
421{
422	char * const nbargv[] = {
423		"nextboot", "-a",
424		"-e", "dtraceall_load=\"YES\"",
425		"-e", "dtrace_dof_load=\"YES\"",
426		"-e", "dtrace_dof_name=\"/boot/dtrace.dof\"",
427		"-e", "dtrace_dof_type=\"dtrace_dof\"",
428		NULL,
429	};
430	pid_t child;
431	int err, status;
432
433	err = posix_spawnp(&child, "nextboot", NULL, NULL, nbargv,
434	    NULL);
435	if (err != 0) {
436		error("failed to execute nextboot: %s", strerror(err));
437		exit(E_ERROR);
438	}
439
440	if (waitpid(child, &status, 0) != child)
441		fatal("waiting for nextboot");
442	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
443		error("nextboot returned with status %d", status);
444		exit(E_ERROR);
445	}
446}
447#else
448static void
449etcsystem_prune(void)
450{
451	struct stat sbuf;
452	size_t sz;
453	char *buf, *start, *end;
454	int fd;
455	char *fname = g_etcfile, *tmpname;
456
457	if ((fd = open(fname, O_RDONLY)) == -1)
458		fatal("failed to open %s", fname);
459
460	if (fstat(fd, &sbuf) == -1)
461		fatal("failed to fstat %s", fname);
462
463	if ((buf = malloc((sz = sbuf.st_size) + 1)) == NULL)
464		fatal("failed to allocate memory for %s", fname);
465
466	if (read(fd, buf, sz) != sz)
467		fatal("failed to read %s", fname);
468
469	buf[sz] = '\0';
470	(void) close(fd);
471
472	if ((start = strstr(buf, g_etcbegin)) == NULL)
473		goto out;
474
475	if (strlen(buf) != sz) {
476		fatal("embedded nul byte in %s; manual repair of %s "
477		    "required\n", fname, fname);
478	}
479
480	if (strstr(start + 1, g_etcbegin) != NULL) {
481		fatal("multiple start sentinels in %s; manual repair of %s "
482		    "required\n", fname, fname);
483	}
484
485	if ((end = strstr(buf, g_etcend)) == NULL) {
486		fatal("missing end sentinel in %s; manual repair of %s "
487		    "required\n", fname, fname);
488	}
489
490	if (start > end) {
491		fatal("end sentinel preceeds start sentinel in %s; manual "
492		    "repair of %s required\n", fname, fname);
493	}
494
495	end += strlen(g_etcend) + 1;
496	bcopy(end, start, strlen(end) + 1);
497
498	tmpname = alloca(sz = strlen(fname) + 80);
499	(void) snprintf(tmpname, sz, "%s.dtrace.%d", fname, getpid());
500
501	if ((fd = open(tmpname,
502	    O_WRONLY | O_CREAT | O_EXCL, sbuf.st_mode)) == -1)
503		fatal("failed to create %s", tmpname);
504
505	if (write(fd, buf, strlen(buf)) < strlen(buf)) {
506		(void) unlink(tmpname);
507		fatal("failed to write to %s", tmpname);
508	}
509
510	(void) close(fd);
511
512	if (chown(tmpname, sbuf.st_uid, sbuf.st_gid) != 0) {
513		(void) unlink(tmpname);
514		fatal("failed to chown(2) %s to uid %d, gid %d", tmpname,
515		    (int)sbuf.st_uid, (int)sbuf.st_gid);
516	}
517
518	if (rename(tmpname, fname) == -1)
519		fatal("rename of %s to %s failed", tmpname, fname);
520
521	error("cleaned up forceload directives in %s\n", fname);
522out:
523	free(buf);
524}
525
526static void
527etcsystem_add(void)
528{
529	const char *mods[20];
530	int nmods, line;
531
532	if ((g_ofp = fopen(g_ofile = g_etcfile, "a")) == NULL)
533		fatal("failed to open output file '%s'", g_ofile);
534
535	oprintf("%s\n", g_etcbegin);
536
537	for (line = 0; g_etc[line] != NULL; line++)
538		oprintf("%s\n", g_etc[line]);
539
540	nmods = dtrace_provider_modules(g_dtp, mods,
541	    sizeof (mods) / sizeof (char *) - 1);
542
543	if (nmods >= sizeof (mods) / sizeof (char *))
544		fatal("unexpectedly large number of modules!");
545
546	mods[nmods++] = "dtrace";
547
548	for (line = 0; line < nmods; line++)
549		oprintf("forceload: drv/%s\n", mods[line]);
550
551	oprintf("%s\n", g_etcend);
552
553	if (fclose(g_ofp) == EOF)
554		fatal("failed to close output file '%s'", g_ofile);
555
556	error("added forceload directives to %s\n", g_ofile);
557}
558#endif /* !__FreeBSD__ */
559
560static void
561print_probe_info(const dtrace_probeinfo_t *p)
562{
563	char buf[BUFSIZ];
564	char *user;
565	int i;
566
567	oprintf("\n\tProbe Description Attributes\n");
568
569	oprintf("\t\tIdentifier Names: %s\n",
570	    dtrace_stability_name(p->dtp_attr.dtat_name));
571	oprintf("\t\tData Semantics:   %s\n",
572	    dtrace_stability_name(p->dtp_attr.dtat_data));
573	oprintf("\t\tDependency Class: %s\n",
574	    dtrace_class_name(p->dtp_attr.dtat_class));
575
576	oprintf("\n\tArgument Attributes\n");
577
578	oprintf("\t\tIdentifier Names: %s\n",
579	    dtrace_stability_name(p->dtp_arga.dtat_name));
580	oprintf("\t\tData Semantics:   %s\n",
581	    dtrace_stability_name(p->dtp_arga.dtat_data));
582	oprintf("\t\tDependency Class: %s\n",
583	    dtrace_class_name(p->dtp_arga.dtat_class));
584
585	oprintf("\n\tArgument Types\n");
586
587	for (i = 0; i < p->dtp_argc; i++) {
588		if (p->dtp_argv[i].dtt_flags & DTT_FL_USER)
589			user = "userland ";
590		else
591			user = "";
592		if (ctf_type_name(p->dtp_argv[i].dtt_ctfp,
593		    p->dtp_argv[i].dtt_type, buf, sizeof (buf)) == NULL)
594			(void) strlcpy(buf, "(unknown)", sizeof (buf));
595		oprintf("\t\targs[%d]: %s%s\n", i, user, buf);
596	}
597
598	if (p->dtp_argc == 0)
599		oprintf("\t\tNone\n");
600
601	oprintf("\n");
602}
603
604/*ARGSUSED*/
605static int
606info_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
607    dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last)
608{
609	dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
610	dtrace_probedesc_t *pdp = &edp->dted_probe;
611	dtrace_probeinfo_t p;
612
613	if (edp == *last)
614		return (0);
615
616	oprintf("\n%s:%s:%s:%s\n",
617	    pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
618
619	if (dtrace_probe_info(dtp, pdp, &p) == 0)
620		print_probe_info(&p);
621
622	*last = edp;
623	return (0);
624}
625
626/*
627 * Execute the specified program by enabling the corresponding instrumentation.
628 * If -e has been specified, we get the program info but do not enable it.  If
629 * -v has been specified, we print a stability report for the program.
630 */
631static void
632exec_prog(const dtrace_cmd_t *dcp)
633{
634	dtrace_ecbdesc_t *last = NULL;
635	dtrace_proginfo_t dpi;
636
637	if (!g_exec) {
638		dtrace_program_info(g_dtp, dcp->dc_prog, &dpi);
639	} else if (dtrace_program_exec(g_dtp, dcp->dc_prog, &dpi) == -1) {
640		dfatal("failed to enable '%s'", dcp->dc_name);
641	} else {
642		notice("%s '%s' matched %u probe%s\n",
643		    dcp->dc_desc, dcp->dc_name,
644		    dpi.dpi_matches, dpi.dpi_matches == 1 ? "" : "s");
645	}
646
647	if (g_verbose) {
648		oprintf("\nStability attributes for %s %s:\n",
649		    dcp->dc_desc, dcp->dc_name);
650
651		oprintf("\n\tMinimum Probe Description Attributes\n");
652		oprintf("\t\tIdentifier Names: %s\n",
653		    dtrace_stability_name(dpi.dpi_descattr.dtat_name));
654		oprintf("\t\tData Semantics:   %s\n",
655		    dtrace_stability_name(dpi.dpi_descattr.dtat_data));
656		oprintf("\t\tDependency Class: %s\n",
657		    dtrace_class_name(dpi.dpi_descattr.dtat_class));
658
659		oprintf("\n\tMinimum Statement Attributes\n");
660
661		oprintf("\t\tIdentifier Names: %s\n",
662		    dtrace_stability_name(dpi.dpi_stmtattr.dtat_name));
663		oprintf("\t\tData Semantics:   %s\n",
664		    dtrace_stability_name(dpi.dpi_stmtattr.dtat_data));
665		oprintf("\t\tDependency Class: %s\n",
666		    dtrace_class_name(dpi.dpi_stmtattr.dtat_class));
667
668		if (!g_exec) {
669			(void) dtrace_stmt_iter(g_dtp, dcp->dc_prog,
670			    (dtrace_stmt_f *)info_stmt, &last);
671		} else
672			oprintf("\n");
673	}
674
675	g_total += dpi.dpi_matches;
676}
677
678/*
679 * Print out the specified DOF buffer as a set of ASCII bytes appropriate for
680 * storing in a driver.conf(4) file associated with the dtrace driver.
681 */
682static void
683anon_prog(const dtrace_cmd_t *dcp, dof_hdr_t *dof, int n)
684{
685	const uchar_t *p, *q;
686
687	if (dof == NULL)
688		dfatal("failed to create DOF image for '%s'", dcp->dc_name);
689
690	p = (uchar_t *)dof;
691	q = p + dof->dofh_filesz;
692
693#ifdef __FreeBSD__
694	/*
695	 * On FreeBSD, the DOF file is read directly during boot - just write
696	 * two hex characters per byte.
697	 */
698	oprintf("dof-data-%d=", n);
699
700	while (p < q)
701		oprintf("%02x", *p++);
702
703	oprintf("\n");
704#else
705	oprintf("dof-data-%d=0x%x", n, *p++);
706
707	while (p < q)
708		oprintf(",0x%x", *p++);
709
710	oprintf(";\n");
711#endif
712
713	dtrace_dof_destroy(g_dtp, dof);
714}
715
716/*
717 * Link the specified D program in DOF form into an ELF file for use in either
718 * helpers, userland provider definitions, or both.  If -o was specified, that
719 * path is used as the output file name.  If -o wasn't specified and the input
720 * program is from a script whose name is %.d, use basename(%.o) as the output
721 * file name.  Otherwise we use "d.out" as the default output file name.
722 */
723static void
724link_prog(dtrace_cmd_t *dcp)
725{
726	char *p;
727
728	if (g_cmdc == 1 && g_ofile != NULL) {
729		(void) strlcpy(dcp->dc_ofile, g_ofile, sizeof (dcp->dc_ofile));
730	} else if ((p = strrchr(dcp->dc_arg, '.')) != NULL &&
731	    strcmp(p, ".d") == 0) {
732		p[0] = '\0'; /* strip .d suffix */
733		(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
734		    "%s.o", basename(dcp->dc_arg));
735	} else if (g_cmdc > 1) {
736		(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
737		    "d.out.%td", dcp - g_cmdv);
738	} else {
739		(void) snprintf(dcp->dc_ofile, sizeof (dcp->dc_ofile),
740		    "d.out");
741	}
742
743	if (dtrace_program_link(g_dtp, dcp->dc_prog, DTRACE_D_PROBES,
744	    dcp->dc_ofile, g_objc, g_objv) != 0)
745		dfatal("failed to link %s %s", dcp->dc_desc, dcp->dc_name);
746}
747
748/*ARGSUSED*/
749static int
750list_probe(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
751{
752	dtrace_probeinfo_t p;
753
754	oprintf("%5d %10s %17s %33s %s\n", pdp->dtpd_id,
755	    pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
756
757	if (g_verbose && dtrace_probe_info(dtp, pdp, &p) == 0)
758		print_probe_info(&p);
759
760	if (g_intr != 0)
761		return (1);
762
763	return (0);
764}
765
766/*ARGSUSED*/
767static int
768list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
769    dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last)
770{
771	dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc;
772
773	if (edp == *last)
774		return (0);
775
776	if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) {
777		error("failed to match %s:%s:%s:%s: %s\n",
778		    edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod,
779		    edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name,
780		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
781	}
782
783	*last = edp;
784	return (0);
785}
786
787/*
788 * List the probes corresponding to the specified program by iterating over
789 * each statement and then matching probes to the statement probe descriptions.
790 */
791static void
792list_prog(const dtrace_cmd_t *dcp)
793{
794	dtrace_ecbdesc_t *last = NULL;
795
796	(void) dtrace_stmt_iter(g_dtp, dcp->dc_prog,
797	    (dtrace_stmt_f *)list_stmt, &last);
798}
799
800static void
801compile_file(dtrace_cmd_t *dcp)
802{
803	char *arg0;
804	FILE *fp;
805
806	if ((fp = fopen(dcp->dc_arg, "r")) == NULL)
807		fatal("failed to open %s", dcp->dc_arg);
808
809	arg0 = g_argv[0];
810	g_argv[0] = dcp->dc_arg;
811
812	if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp,
813	    g_cflags, g_argc, g_argv)) == NULL)
814		dfatal("failed to compile script %s", dcp->dc_arg);
815
816	g_argv[0] = arg0;
817	(void) fclose(fp);
818
819	dcp->dc_desc = "script";
820	dcp->dc_name = dcp->dc_arg;
821}
822
823static void
824compile_str(dtrace_cmd_t *dcp)
825{
826	char *p;
827
828	if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg,
829	    dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL)
830		dfatal("invalid probe specifier %s", dcp->dc_arg);
831
832	if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL)
833		*p = '\0'; /* crop name for reporting */
834
835	dcp->dc_desc = "description";
836	dcp->dc_name = dcp->dc_arg;
837}
838
839/*ARGSUSED*/
840static void
841prochandler(struct ps_prochandle *P, const char *msg, void *arg)
842{
843#ifdef illumos
844	const psinfo_t *prp = Ppsinfo(P);
845	int pid = Pstatus(P)->pr_pid;
846	char name[SIG2STR_MAX];
847#else
848	int wstatus = proc_getwstat(P);
849	int pid = proc_getpid(P);
850#endif
851
852	if (msg != NULL) {
853		notice("pid %d: %s\n", pid, msg);
854		return;
855	}
856
857#ifdef illumos
858	switch (Pstate(P)) {
859#else
860	switch (proc_state(P)) {
861#endif
862	case PS_UNDEAD:
863#ifdef illumos
864		/*
865		 * Ideally we would like to always report pr_wstat here, but it
866		 * isn't possible given current /proc semantics.  If we grabbed
867		 * the process, Ppsinfo() will either fail or return a zeroed
868		 * psinfo_t depending on how far the parent is in reaping it.
869		 * When /proc provides a stable pr_wstat in the status file,
870		 * this code can be improved by examining this new pr_wstat.
871		 */
872		if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) {
873			notice("pid %d terminated by %s\n", pid,
874			    proc_signame(WTERMSIG(prp->pr_wstat),
875			    name, sizeof (name)));
876#else
877		if (WIFSIGNALED(wstatus)) {
878			notice("pid %d terminated by %d\n", pid,
879			    WTERMSIG(wstatus));
880#endif
881#ifdef illumos
882		} else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) {
883			notice("pid %d exited with status %d\n",
884			    pid, WEXITSTATUS(prp->pr_wstat));
885#else
886		} else if (WEXITSTATUS(wstatus) != 0) {
887			notice("pid %d exited with status %d\n",
888			    pid, WEXITSTATUS(wstatus));
889#endif
890		} else {
891			notice("pid %d has exited\n", pid);
892		}
893		g_pslive--;
894		break;
895
896	case PS_LOST:
897		notice("pid %d exec'd a set-id or unobservable program\n", pid);
898		g_pslive--;
899		break;
900	}
901}
902
903/*ARGSUSED*/
904static int
905errhandler(const dtrace_errdata_t *data, void *arg)
906{
907	error(data->dteda_msg);
908	return (DTRACE_HANDLE_OK);
909}
910
911/*ARGSUSED*/
912static int
913drophandler(const dtrace_dropdata_t *data, void *arg)
914{
915	if (!dtrace_oformat(g_dtp)) {
916		error(data->dtdda_msg);
917	}
918
919	return (DTRACE_HANDLE_OK);
920}
921
922/*ARGSUSED*/
923static int
924setopthandler(const dtrace_setoptdata_t *data, void *arg)
925{
926	if (strcmp(data->dtsda_option, "quiet") == 0)
927		g_quiet = data->dtsda_newval != DTRACEOPT_UNSET;
928
929	if (strcmp(data->dtsda_option, "flowindent") == 0)
930		g_flowindent = data->dtsda_newval != DTRACEOPT_UNSET;
931
932	return (DTRACE_HANDLE_OK);
933}
934
935#define	BUFDUMPHDR(hdr) \
936	(void) printf("%s: %s%s\n", g_pname, hdr, strlen(hdr) > 0 ? ":" : "");
937
938#define	BUFDUMPSTR(ptr, field) \
939	(void) printf("%s: %20s => ", g_pname, #field);	\
940	if ((ptr)->field != NULL) {			\
941		const char *c = (ptr)->field;		\
942		(void) printf("\"");			\
943		do {					\
944			if (*c == '\n') {		\
945				(void) printf("\\n");	\
946				continue;		\
947			}				\
948							\
949			(void) printf("%c", *c);	\
950		} while (*c++ != '\0');			\
951		(void) printf("\"\n");			\
952	} else {					\
953		(void) printf("<NULL>\n");		\
954	}
955
956#define	BUFDUMPASSTR(ptr, field, str) \
957	(void) printf("%s: %20s => %s\n", g_pname, #field, str);
958
959#define	BUFDUMP(ptr, field) \
960	(void) printf("%s: %20s => %lld\n", g_pname, #field, \
961	    (long long)(ptr)->field);
962
963#define	BUFDUMPPTR(ptr, field) \
964	(void) printf("%s: %20s => %s\n", g_pname, #field, \
965	    (ptr)->field != NULL ? "<non-NULL>" : "<NULL>");
966
967/*ARGSUSED*/
968static int
969bufhandler(const dtrace_bufdata_t *bufdata, void *arg)
970{
971	const dtrace_aggdata_t *agg = bufdata->dtbda_aggdata;
972	const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc;
973	const dtrace_probedesc_t *pd;
974	uint32_t flags = bufdata->dtbda_flags;
975	char buf[512], *c = buf, *end = c + sizeof (buf);
976	int i, printed;
977
978	struct {
979		const char *name;
980		uint32_t value;
981	} flagnames[] = {
982	    { "AGGVAL",		DTRACE_BUFDATA_AGGVAL },
983	    { "AGGKEY",		DTRACE_BUFDATA_AGGKEY },
984	    { "AGGFORMAT",	DTRACE_BUFDATA_AGGFORMAT },
985	    { "AGGLAST",	DTRACE_BUFDATA_AGGLAST },
986	    { "???",		UINT32_MAX },
987	    { NULL }
988	};
989
990	if (bufdata->dtbda_probe != NULL) {
991		pd = bufdata->dtbda_probe->dtpda_pdesc;
992	} else if (agg != NULL) {
993		pd = agg->dtada_pdesc;
994	} else {
995		pd = NULL;
996	}
997
998	BUFDUMPHDR(">>> Called buffer handler");
999	BUFDUMPHDR("");
1000
1001	BUFDUMPHDR("  dtrace_bufdata");
1002	BUFDUMPSTR(bufdata, dtbda_buffered);
1003	BUFDUMPPTR(bufdata, dtbda_probe);
1004	BUFDUMPPTR(bufdata, dtbda_aggdata);
1005	BUFDUMPPTR(bufdata, dtbda_recdesc);
1006
1007	(void) snprintf(c, end - c, "0x%x ", bufdata->dtbda_flags);
1008	c += strlen(c);
1009
1010	for (i = 0, printed = 0; flagnames[i].name != NULL; i++) {
1011		if (!(flags & flagnames[i].value))
1012			continue;
1013
1014		(void) snprintf(c, end - c,
1015		    "%s%s", printed++ ? " | " : "(", flagnames[i].name);
1016		c += strlen(c);
1017		flags &= ~flagnames[i].value;
1018	}
1019
1020	if (printed)
1021		(void) snprintf(c, end - c, ")");
1022
1023	BUFDUMPASSTR(bufdata, dtbda_flags, buf);
1024	BUFDUMPHDR("");
1025
1026	if (pd != NULL) {
1027		BUFDUMPHDR("  dtrace_probedesc");
1028		BUFDUMPSTR(pd, dtpd_provider);
1029		BUFDUMPSTR(pd, dtpd_mod);
1030		BUFDUMPSTR(pd, dtpd_func);
1031		BUFDUMPSTR(pd, dtpd_name);
1032		BUFDUMPHDR("");
1033	}
1034
1035	if (rec != NULL) {
1036		BUFDUMPHDR("  dtrace_recdesc");
1037		BUFDUMP(rec, dtrd_action);
1038		BUFDUMP(rec, dtrd_size);
1039
1040		if (agg != NULL) {
1041			uint8_t *data;
1042			int lim = rec->dtrd_size;
1043
1044			(void) sprintf(buf, "%d (data: ", rec->dtrd_offset);
1045			c = buf + strlen(buf);
1046
1047			if (lim > sizeof (uint64_t))
1048				lim = sizeof (uint64_t);
1049
1050			data = (uint8_t *)agg->dtada_data + rec->dtrd_offset;
1051
1052			for (i = 0; i < lim; i++) {
1053				(void) snprintf(c, end - c, "%s%02x",
1054				    i == 0 ? "" : " ", *data++);
1055				c += strlen(c);
1056			}
1057
1058			(void) snprintf(c, end - c,
1059			    "%s)", lim < rec->dtrd_size ? " ..." : "");
1060			BUFDUMPASSTR(rec, dtrd_offset, buf);
1061		} else {
1062			BUFDUMP(rec, dtrd_offset);
1063		}
1064
1065		BUFDUMPHDR("");
1066	}
1067
1068	if (agg != NULL) {
1069		dtrace_aggdesc_t *desc = agg->dtada_desc;
1070
1071		BUFDUMPHDR("  dtrace_aggdesc");
1072		BUFDUMPSTR(desc, dtagd_name);
1073		BUFDUMP(desc, dtagd_varid);
1074		BUFDUMP(desc, dtagd_id);
1075		BUFDUMP(desc, dtagd_nrecs);
1076		BUFDUMPHDR("");
1077	}
1078
1079	return (DTRACE_HANDLE_OK);
1080}
1081
1082/*ARGSUSED*/
1083static int
1084chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
1085{
1086	dtrace_actkind_t act;
1087	uintptr_t addr;
1088
1089	if (rec == NULL) {
1090		/*
1091		 * We have processed the final record; output the newline if
1092		 * we're not in quiet mode.
1093		 */
1094		if (!g_quiet)
1095			oprintf("\n");
1096
1097		return (DTRACE_CONSUME_NEXT);
1098	}
1099
1100	act = rec->dtrd_action;
1101	addr = (uintptr_t)data->dtpda_data;
1102
1103	if (act == DTRACEACT_EXIT) {
1104		g_status = *((uint32_t *)addr);
1105		return (DTRACE_CONSUME_NEXT);
1106	}
1107
1108	return (DTRACE_CONSUME_THIS);
1109}
1110
1111/*ARGSUSED*/
1112static int
1113chew(const dtrace_probedata_t *data, void *arg)
1114{
1115	dtrace_probedesc_t *pd = data->dtpda_pdesc;
1116	processorid_t cpu = data->dtpda_cpu;
1117	static int heading;
1118
1119	if (g_impatient) {
1120		g_newline = 0;
1121		return (DTRACE_CONSUME_ABORT);
1122	}
1123
1124	if (heading == 0) {
1125		if (!g_flowindent) {
1126			if (!g_quiet) {
1127				oprintf("%3s %6s %32s\n",
1128				    "CPU", "ID", "FUNCTION:NAME");
1129			}
1130		} else {
1131			oprintf("%3s %-41s\n", "CPU", "FUNCTION");
1132		}
1133		heading = 1;
1134	}
1135
1136	if (!g_flowindent) {
1137		if (dtrace_oformat(g_dtp)) {
1138			dtrace_oformat_probe(g_dtp, data, cpu, pd);
1139		} else if (!g_quiet) {
1140			char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2];
1141
1142			(void) snprintf(name, sizeof (name), "%s:%s",
1143			    pd->dtpd_func, pd->dtpd_name);
1144
1145			oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name);
1146		}
1147	} else {
1148		int indent = data->dtpda_indent;
1149		char *name;
1150		size_t len;
1151
1152		if (data->dtpda_flow == DTRACEFLOW_NONE) {
1153			len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5;
1154			name = alloca(len);
1155			(void) snprintf(name, len, "%*s%s%s:%s", indent, "",
1156			    data->dtpda_prefix, pd->dtpd_func,
1157			    pd->dtpd_name);
1158		} else {
1159			len = indent + DTRACE_FUNCNAMELEN + 5;
1160			name = alloca(len);
1161			(void) snprintf(name, len, "%*s%s%s", indent, "",
1162			    data->dtpda_prefix, pd->dtpd_func);
1163		}
1164
1165		oprintf("%3d %-41s ", cpu, name);
1166	}
1167
1168	return (DTRACE_CONSUME_THIS);
1169}
1170
1171static void
1172go(void)
1173{
1174	int i;
1175
1176	struct {
1177		char *name;
1178		char *optname;
1179		dtrace_optval_t val;
1180	} bufs[] = {
1181		{ "buffer size", "bufsize" },
1182		{ "aggregation size", "aggsize" },
1183		{ "speculation size", "specsize" },
1184		{ "dynamic variable size", "dynvarsize" },
1185		{ NULL }
1186	}, rates[] = {
1187		{ "cleaning rate", "cleanrate" },
1188		{ "status rate", "statusrate" },
1189		{ NULL }
1190	};
1191
1192	for (i = 0; bufs[i].name != NULL; i++) {
1193		if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1)
1194			fatal("couldn't get option %s", bufs[i].optname);
1195	}
1196
1197	for (i = 0; rates[i].name != NULL; i++) {
1198		if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1)
1199			fatal("couldn't get option %s", rates[i].optname);
1200	}
1201
1202	if (dtrace_go(g_dtp) == -1)
1203		dfatal("could not enable tracing");
1204
1205	for (i = 0; bufs[i].name != NULL; i++) {
1206		dtrace_optval_t j = 0, mul = 10;
1207		dtrace_optval_t nsize;
1208
1209		if (bufs[i].val == DTRACEOPT_UNSET)
1210			continue;
1211
1212		(void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize);
1213
1214		if (nsize == DTRACEOPT_UNSET || nsize == 0)
1215			continue;
1216
1217		if (nsize >= bufs[i].val - sizeof (uint64_t))
1218			continue;
1219
1220		for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10)
1221			continue;
1222
1223		if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) {
1224			error("%s lowered to %lld%c\n", bufs[i].name,
1225			    (long long)nsize >> (mul - 10), " kmgtpe"[j]);
1226		} else {
1227			error("%s lowered to %lld bytes\n", bufs[i].name,
1228			    (long long)nsize);
1229		}
1230	}
1231
1232	for (i = 0; rates[i].name != NULL; i++) {
1233		dtrace_optval_t nval;
1234		char *dir;
1235
1236		if (rates[i].val == DTRACEOPT_UNSET)
1237			continue;
1238
1239		(void) dtrace_getopt(g_dtp, rates[i].optname, &nval);
1240
1241		if (nval == DTRACEOPT_UNSET || nval == 0)
1242			continue;
1243
1244		if (rates[i].val == nval)
1245			continue;
1246
1247		dir = nval > rates[i].val ? "reduced" : "increased";
1248
1249		if (nval <= NANOSEC && (NANOSEC % nval) == 0) {
1250			error("%s %s to %lld hz\n", rates[i].name, dir,
1251			    (long long)NANOSEC / (long long)nval);
1252			continue;
1253		}
1254
1255		if ((nval % NANOSEC) == 0) {
1256			error("%s %s to once every %lld seconds\n",
1257			    rates[i].name, dir,
1258			    (long long)nval / (long long)NANOSEC);
1259			continue;
1260		}
1261
1262		error("%s %s to once every %lld nanoseconds\n",
1263		    rates[i].name, dir, (long long)nval);
1264	}
1265}
1266
1267/*ARGSUSED*/
1268static void
1269intr(int signo)
1270{
1271	if (!g_intr)
1272		g_newline = 1;
1273
1274	if (g_intr++)
1275		g_impatient = 1;
1276}
1277
1278#ifdef __FreeBSD__
1279static void
1280siginfo(int signo __unused)
1281{
1282
1283	g_siginfo++;
1284	g_newline = 1;
1285}
1286#endif
1287
1288static void
1289installsighands(void)
1290{
1291	struct sigaction act, oact;
1292
1293	(void) sigemptyset(&act.sa_mask);
1294	act.sa_flags = 0;
1295	act.sa_handler = intr;
1296
1297	if (sigaction(SIGINT, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
1298		(void) sigaction(SIGINT, &act, NULL);
1299
1300	if (sigaction(SIGTERM, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
1301		(void) sigaction(SIGTERM, &act, NULL);
1302
1303#ifdef __FreeBSD__
1304	if (sigaction(SIGPIPE, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
1305		(void) sigaction(SIGPIPE, &act, NULL);
1306
1307	if (sigaction(SIGUSR1, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
1308		(void) sigaction(SIGUSR1, &act, NULL);
1309
1310	act.sa_handler = siginfo;
1311	if (sigaction(SIGINFO, NULL, &oact) == 0 && oact.sa_handler != SIG_IGN)
1312		(void) sigaction(SIGINFO, &act, NULL);
1313#endif
1314}
1315
1316int
1317main(int argc, char *argv[])
1318{
1319	dtrace_bufdesc_t buf;
1320	dtrace_status_t status[2];
1321	dtrace_optval_t opt;
1322	dtrace_cmd_t *dcp;
1323
1324	g_ofp = stdout;
1325	int done = 0, mode = 0;
1326	int err, i, c, new_argc, libxo_specified;
1327	int print_upon_exit = 0;
1328	char *p, **v;
1329	struct ps_prochandle *P;
1330	pid_t pid;
1331
1332#ifdef __FreeBSD__
1333	/* For %'d and the like. */
1334	(void) setlocale(LC_NUMERIC, "");
1335
1336	/* For %T. */
1337	(void) setlocale(LC_TIME, "");
1338#endif
1339
1340	g_pname = basename(argv[0]);
1341
1342	if (argc == 1)
1343		return (usage(stderr));
1344
1345	if ((g_argv = malloc(sizeof (char *) * argc)) == NULL ||
1346	    (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL ||
1347	    (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL)
1348		fatal("failed to allocate memory for arguments");
1349
1350	new_argc = xo_parse_args(argc, argv);
1351	if (new_argc < 0)
1352		return (usage(stderr));
1353
1354	if (new_argc != argc)
1355		libxo_specified = 1;
1356
1357	argc = new_argc;
1358
1359	g_argv[g_argc++] = argv[0];	/* propagate argv[0] to D as $0/$$0 */
1360	argv[0] = g_pname;		/* rewrite argv[0] for getopt errors */
1361
1362	bzero(status, sizeof (status));
1363	bzero(&buf, sizeof (buf));
1364
1365	/*
1366	 * Make an initial pass through argv[] processing any arguments that
1367	 * affect our behavior mode (g_mode) and flags used for dtrace_open().
1368	 * We also accumulate arguments that are not affiliated with getopt
1369	 * options into g_argv[], and abort if any invalid options are found.
1370	 */
1371	for (optind = 1; optind < argc; optind++) {
1372		while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
1373			switch (c) {
1374			case '3':
1375				if (strcmp(optarg, "2") != 0) {
1376					(void) fprintf(stderr,
1377					    "%s: illegal option -- 3%s\n",
1378					    argv[0], optarg);
1379					return (usage(stderr));
1380				}
1381				g_oflags &= ~DTRACE_O_LP64;
1382				g_oflags |= DTRACE_O_ILP32;
1383				break;
1384
1385			case '6':
1386				if (strcmp(optarg, "4") != 0) {
1387					(void) fprintf(stderr,
1388					    "%s: illegal option -- 6%s\n",
1389					    argv[0], optarg);
1390					return (usage(stderr));
1391				}
1392				g_oflags &= ~DTRACE_O_ILP32;
1393				g_oflags |= DTRACE_O_LP64;
1394				break;
1395
1396			case 'a':
1397				g_grabanon++; /* also checked in pass 2 below */
1398				break;
1399
1400			case 'A':
1401				g_mode = DMODE_ANON;
1402				g_exec = 0;
1403				mode++;
1404				break;
1405
1406			case 'e':
1407				g_exec = 0;
1408				done = 1;
1409				break;
1410
1411			case 'h':
1412				g_mode = DMODE_HEADER;
1413				g_oflags |= DTRACE_O_NODEV;
1414				g_cflags |= DTRACE_C_ZDEFS; /* -h implies -Z */
1415				g_exec = 0;
1416				mode++;
1417				break;
1418
1419			case 'G':
1420				g_mode = DMODE_LINK;
1421				g_oflags |= DTRACE_O_NODEV;
1422				g_cflags |= DTRACE_C_ZDEFS; /* -G implies -Z */
1423				g_exec = 0;
1424				mode++;
1425				break;
1426
1427			case 'l':
1428				g_mode = DMODE_LIST;
1429				g_cflags |= DTRACE_C_ZDEFS; /* -l implies -Z */
1430				mode++;
1431				break;
1432
1433			case 'V':
1434				g_mode = DMODE_VERS;
1435				mode++;
1436				break;
1437
1438			default:
1439				if (strchr(DTRACE_OPTSTR, c) == NULL)
1440					return (usage(stderr));
1441			}
1442		}
1443
1444		if (optind < argc)
1445			g_argv[g_argc++] = argv[optind];
1446	}
1447
1448	if (mode > 1) {
1449		(void) fprintf(stderr, "%s: only one of the [-AGhlV] options "
1450		    "can be specified at a time\n", g_pname);
1451		return (E_USAGE);
1452	}
1453
1454	if (g_mode == DMODE_VERS)
1455		return (printf("%s: %s\n", g_pname, _dtrace_version) <= 0);
1456
1457	/*
1458	 * If we're in linker mode and the data model hasn't been specified,
1459	 * we try to guess the appropriate setting by examining the object
1460	 * files. We ignore certain errors since we'll catch them later when
1461	 * we actually process the object files.
1462	 */
1463	if (g_mode == DMODE_LINK &&
1464	    (g_oflags & (DTRACE_O_ILP32 | DTRACE_O_LP64)) == 0 &&
1465	    elf_version(EV_CURRENT) != EV_NONE) {
1466		int fd;
1467		Elf *elf;
1468		GElf_Ehdr ehdr;
1469
1470		for (i = 1; i < g_argc; i++) {
1471			if ((fd = open64(g_argv[i], O_RDONLY)) == -1)
1472				break;
1473
1474			if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
1475				(void) close(fd);
1476				break;
1477			}
1478
1479			if (elf_kind(elf) != ELF_K_ELF ||
1480			    gelf_getehdr(elf, &ehdr) == NULL) {
1481				(void) close(fd);
1482				(void) elf_end(elf);
1483				break;
1484			}
1485
1486			(void) close(fd);
1487			(void) elf_end(elf);
1488
1489			if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
1490				if (g_oflags & DTRACE_O_ILP32) {
1491					fatal("can't mix 32-bit and 64-bit "
1492					    "object files\n");
1493				}
1494				g_oflags |= DTRACE_O_LP64;
1495			} else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1496				if (g_oflags & DTRACE_O_LP64) {
1497					fatal("can't mix 32-bit and 64-bit "
1498					    "object files\n");
1499				}
1500				g_oflags |= DTRACE_O_ILP32;
1501			} else {
1502				break;
1503			}
1504		}
1505	}
1506
1507	/*
1508	 * Open libdtrace.  If we are not actually going to be enabling any
1509	 * instrumentation attempt to reopen libdtrace using DTRACE_O_NODEV.
1510	 */
1511	while ((g_dtp = dtrace_open(DTRACE_VERSION, g_oflags, &err)) == NULL) {
1512		if (!(g_oflags & DTRACE_O_NODEV) && !g_exec && !g_grabanon) {
1513			g_oflags |= DTRACE_O_NODEV;
1514			continue;
1515		}
1516
1517		fatal("failed to initialize dtrace: %s\n",
1518		    dtrace_errmsg(NULL, err));
1519	}
1520
1521#if defined(__i386__)
1522	/* XXX The 32-bit seems to need more buffer space by default -sson */
1523	(void) dtrace_setopt(g_dtp, "bufsize", "12m");
1524	(void) dtrace_setopt(g_dtp, "aggsize", "12m");
1525#else
1526	(void) dtrace_setopt(g_dtp, "bufsize", "4m");
1527	(void) dtrace_setopt(g_dtp, "aggsize", "4m");
1528#endif
1529	(void) dtrace_setopt(g_dtp, "temporal", "yes");
1530
1531	/*
1532	 * If -G is specified, enable -xlink=dynamic and -xunodefs to permit
1533	 * references to undefined symbols to remain as unresolved relocations.
1534	 * If -A is specified, enable -xlink=primary to permit static linking
1535	 * only to kernel symbols that are defined in a primary kernel module.
1536	 */
1537	if (g_mode == DMODE_LINK) {
1538		(void) dtrace_setopt(g_dtp, "linkmode", "dynamic");
1539		(void) dtrace_setopt(g_dtp, "unodefs", NULL);
1540
1541		/*
1542		 * Use the remaining arguments as the list of object files
1543		 * when in linker mode.
1544		 */
1545		g_objc = g_argc - 1;
1546		g_objv = g_argv + 1;
1547
1548		/*
1549		 * We still use g_argv[0], the name of the executable.
1550		 */
1551		g_argc = 1;
1552	} else if (g_mode == DMODE_ANON)
1553		(void) dtrace_setopt(g_dtp, "linkmode", "primary");
1554
1555
1556	if (libxo_specified)
1557		dtrace_oformat_configure(g_dtp);
1558
1559	/*
1560	 * Now that we have libdtrace open, make a second pass through argv[]
1561	 * to perform any dtrace_setopt() calls and change any compiler flags.
1562	 * We also accumulate any program specifications into our g_cmdv[] at
1563	 * this time; these will compiled as part of the fourth processing pass.
1564	 */
1565	for (optind = 1; optind < argc; optind++) {
1566		while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
1567			switch (c) {
1568			case 'a':
1569				if (dtrace_setopt(g_dtp, "grabanon", 0) != 0)
1570					dfatal("failed to set -a");
1571				break;
1572
1573			case 'b':
1574				if (dtrace_setopt(g_dtp,
1575				    "bufsize", optarg) != 0)
1576					dfatal("failed to set -b %s", optarg);
1577				break;
1578
1579			case 'B':
1580				g_ofp = NULL;
1581				break;
1582
1583			case 'C':
1584				g_cflags |= DTRACE_C_CPP;
1585				break;
1586
1587			case 'd':
1588				g_cflags |= DTRACE_C_SUGAR;
1589				break;
1590
1591			case 'D':
1592				if (dtrace_setopt(g_dtp, "define", optarg) != 0)
1593					dfatal("failed to set -D %s", optarg);
1594				break;
1595
1596			case 'f':
1597				dcp = &g_cmdv[g_cmdc++];
1598				dcp->dc_func = compile_str;
1599				dcp->dc_spec = DTRACE_PROBESPEC_FUNC;
1600				dcp->dc_arg = optarg;
1601				break;
1602
1603			case 'F':
1604				if (dtrace_setopt(g_dtp, "flowindent", 0) != 0)
1605					dfatal("failed to set -F");
1606				break;
1607
1608			case 'H':
1609				if (dtrace_setopt(g_dtp, "cpphdrs", 0) != 0)
1610					dfatal("failed to set -H");
1611				break;
1612
1613			case 'i':
1614				dcp = &g_cmdv[g_cmdc++];
1615				dcp->dc_func = compile_str;
1616				dcp->dc_spec = DTRACE_PROBESPEC_NAME;
1617				dcp->dc_arg = optarg;
1618				break;
1619
1620			case 'I':
1621				if (dtrace_setopt(g_dtp, "incdir", optarg) != 0)
1622					dfatal("failed to set -I %s", optarg);
1623				break;
1624
1625			case 'L':
1626				if (dtrace_setopt(g_dtp, "libdir", optarg) != 0)
1627					dfatal("failed to set -L %s", optarg);
1628				break;
1629
1630			case 'm':
1631				dcp = &g_cmdv[g_cmdc++];
1632				dcp->dc_func = compile_str;
1633				dcp->dc_spec = DTRACE_PROBESPEC_MOD;
1634				dcp->dc_arg = optarg;
1635				break;
1636
1637			case 'n':
1638				dcp = &g_cmdv[g_cmdc++];
1639				dcp->dc_func = compile_str;
1640				dcp->dc_spec = DTRACE_PROBESPEC_NAME;
1641				dcp->dc_arg = optarg;
1642				break;
1643
1644			case 'P':
1645				dcp = &g_cmdv[g_cmdc++];
1646				dcp->dc_func = compile_str;
1647				dcp->dc_spec = DTRACE_PROBESPEC_PROVIDER;
1648				dcp->dc_arg = optarg;
1649				break;
1650
1651			case 'O':
1652				print_upon_exit = 1;
1653				break;
1654
1655			case 'q':
1656				if (dtrace_setopt(g_dtp, "quiet", 0) != 0)
1657					dfatal("failed to set -q");
1658				break;
1659
1660			case 'o':
1661				g_ofile = optarg;
1662				break;
1663
1664			case 's':
1665				dcp = &g_cmdv[g_cmdc++];
1666				dcp->dc_func = compile_file;
1667				dcp->dc_spec = DTRACE_PROBESPEC_NONE;
1668				dcp->dc_arg = optarg;
1669				break;
1670
1671			case 'S':
1672				g_cflags |= DTRACE_C_DIFV;
1673				break;
1674
1675			case 'U':
1676				if (dtrace_setopt(g_dtp, "undef", optarg) != 0)
1677					dfatal("failed to set -U %s", optarg);
1678				break;
1679
1680			case 'v':
1681				g_verbose++;
1682				break;
1683
1684			case 'w':
1685				if (dtrace_setopt(g_dtp, "destructive", 0) != 0)
1686					dfatal("failed to set -w");
1687				break;
1688
1689			case 'x':
1690				if ((p = strchr(optarg, '=')) != NULL)
1691					*p++ = '\0';
1692
1693				if (dtrace_setopt(g_dtp, optarg, p) != 0)
1694					dfatal("failed to set -x %s", optarg);
1695				break;
1696
1697			case 'X':
1698				if (dtrace_setopt(g_dtp, "stdc", optarg) != 0)
1699					dfatal("failed to set -X %s", optarg);
1700				break;
1701
1702			case 'Z':
1703				g_cflags |= DTRACE_C_ZDEFS;
1704				break;
1705
1706			default:
1707				if (strchr(DTRACE_OPTSTR, c) == NULL)
1708					return (usage(stderr));
1709			}
1710		}
1711	}
1712
1713	if (g_ofp == NULL && g_mode != DMODE_EXEC) {
1714		(void) fprintf(stderr, "%s: -B not valid in combination"
1715		    " with [-AGl] options\n", g_pname);
1716		return (E_USAGE);
1717	}
1718
1719	if (g_ofp == NULL && g_ofile != NULL) {
1720		(void) fprintf(stderr, "%s: -B not valid in combination"
1721		    " with -o option\n", g_pname);
1722		return (E_USAGE);
1723	}
1724
1725	/*
1726	 * In our third pass we handle any command-line options related to
1727	 * grabbing or creating victim processes.  The behavior of these calls
1728	 * may been affected by any library options set by the second pass.
1729	 */
1730	for (optind = 1; optind < argc; optind++) {
1731		while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != -1) {
1732			switch (c) {
1733			case 'c':
1734				if ((v = make_argv(optarg)) == NULL)
1735					fatal("failed to allocate memory");
1736
1737				P = dtrace_proc_create(g_dtp, v[0], v, NULL, NULL);
1738				if (P == NULL)
1739					dfatal(NULL); /* dtrace_errmsg() only */
1740
1741				g_psv[g_psc++] = P;
1742				free(v);
1743				break;
1744
1745			case 'p':
1746				errno = 0;
1747				pid = strtol(optarg, &p, 10);
1748
1749				if (errno != 0 || p == optarg || p[0] != '\0')
1750					fatal("invalid pid: %s\n", optarg);
1751
1752				P = dtrace_proc_grab(g_dtp, pid, 0);
1753				if (P == NULL)
1754					dfatal(NULL); /* dtrace_errmsg() only */
1755
1756				g_psv[g_psc++] = P;
1757				break;
1758			}
1759		}
1760	}
1761
1762	/*
1763	 * In our fourth pass we finish g_cmdv[] by calling dc_func to convert
1764	 * each string or file specification into a compiled program structure.
1765	 */
1766	for (i = 0; i < g_cmdc; i++)
1767		g_cmdv[i].dc_func(&g_cmdv[i]);
1768
1769	if (g_mode != DMODE_LIST) {
1770		if (dtrace_handle_err(g_dtp, &errhandler, NULL) == -1)
1771			dfatal("failed to establish error handler");
1772
1773		if (dtrace_handle_drop(g_dtp, &drophandler, NULL) == -1)
1774			dfatal("failed to establish drop handler");
1775
1776		if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
1777			dfatal("failed to establish proc handler");
1778
1779		if (dtrace_handle_setopt(g_dtp, &setopthandler, NULL) == -1)
1780			dfatal("failed to establish setopt handler");
1781
1782		if (g_ofp == NULL &&
1783		    dtrace_handle_buffered(g_dtp, &bufhandler, NULL) == -1)
1784			dfatal("failed to establish buffered handler");
1785	}
1786
1787	(void) dtrace_getopt(g_dtp, "flowindent", &opt);
1788	g_flowindent = opt != DTRACEOPT_UNSET;
1789
1790	(void) dtrace_getopt(g_dtp, "grabanon", &opt);
1791	g_grabanon = opt != DTRACEOPT_UNSET;
1792
1793	(void) dtrace_getopt(g_dtp, "quiet", &opt);
1794	g_quiet = opt != DTRACEOPT_UNSET;
1795
1796	if (dtrace_oformat(g_dtp)) {
1797		if (dtrace_setopt(g_dtp, "quiet", 0) != 0)
1798			dfatal("failed to set quiet (caused by oformat)");
1799	}
1800
1801	/*
1802	 * Now make a fifth and final pass over the options that have been
1803	 * turned into programs and saved in g_cmdv[], performing any mode-
1804	 * specific processing.  If g_mode is DMODE_EXEC, we will break out
1805	 * of the switch() and continue on to the data processing loop.  For
1806	 * other modes, we will exit dtrace once mode-specific work is done.
1807	 */
1808	switch (g_mode) {
1809	case DMODE_EXEC:
1810		if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL)
1811			fatal("failed to open output file '%s'", g_ofile);
1812
1813		if (dtrace_oformat(g_dtp))
1814			dtrace_set_outfp(g_ofp);
1815
1816		for (i = 0; i < g_cmdc; i++)
1817			exec_prog(&g_cmdv[i]);
1818
1819		if (done && !g_grabanon) {
1820			dtrace_close(g_dtp);
1821			return (g_status);
1822		}
1823		break;
1824
1825	case DMODE_ANON:
1826		if (g_ofile == NULL)
1827#ifdef illumos
1828			g_ofile = "/kernel/drv/dtrace.conf";
1829#else
1830			/*
1831			 * On FreeBSD, anonymous DOF data is written to
1832			 * the DTrace DOF file.
1833			 */
1834			g_ofile = "/boot/dtrace.dof";
1835#endif
1836
1837		dof_prune(g_ofile); /* strip out any old DOF directives */
1838#ifdef illumos
1839		etcsystem_prune(); /* string out any forceload directives */
1840#endif
1841
1842		if (g_cmdc == 0) {
1843			dtrace_close(g_dtp);
1844			return (g_status);
1845		}
1846
1847		if ((g_ofp = fopen(g_ofile, "a")) == NULL)
1848			fatal("failed to open output file '%s'", g_ofile);
1849
1850		if (dtrace_oformat(g_dtp))
1851			dtrace_set_outfp(g_ofp);
1852
1853		for (i = 0; i < g_cmdc; i++) {
1854			anon_prog(&g_cmdv[i],
1855			    dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i);
1856		}
1857
1858		/*
1859		 * Dump out the DOF corresponding to the error handler and the
1860		 * current options as the final DOF property in the .conf file.
1861		 */
1862		anon_prog(NULL, dtrace_geterr_dof(g_dtp), i++);
1863		anon_prog(NULL, dtrace_getopt_dof(g_dtp), i++);
1864
1865		if (fclose(g_ofp) == EOF)
1866			fatal("failed to close output file '%s'", g_ofile);
1867
1868		/*
1869		 * These messages would use notice() rather than error(), but
1870		 * we don't want them suppressed when -A is run on a D program
1871		 * that itself contains a #pragma D option quiet.
1872		 */
1873		error("saved anonymous enabling in %s\n", g_ofile);
1874
1875#ifdef __FreeBSD__
1876		bootdof_add();
1877#else
1878		etcsystem_add();
1879		error("run update_drv(1M) or reboot to enable changes\n");
1880#endif
1881
1882		dtrace_close(g_dtp);
1883		return (g_status);
1884
1885	case DMODE_LINK:
1886		if (g_cmdc == 0) {
1887			(void) fprintf(stderr, "%s: -G requires one or more "
1888			    "scripts or enabling options\n", g_pname);
1889			dtrace_close(g_dtp);
1890			return (E_USAGE);
1891		}
1892
1893		for (i = 0; i < g_cmdc; i++)
1894			link_prog(&g_cmdv[i]);
1895
1896		if (g_cmdc > 1 && g_ofile != NULL) {
1897			char **objv = alloca(g_cmdc * sizeof (char *));
1898
1899			for (i = 0; i < g_cmdc; i++)
1900				objv[i] = g_cmdv[i].dc_ofile;
1901
1902			if (dtrace_program_link(g_dtp, NULL, DTRACE_D_PROBES,
1903			    g_ofile, g_cmdc, objv) != 0)
1904				dfatal(NULL); /* dtrace_errmsg() only */
1905		}
1906
1907		dtrace_close(g_dtp);
1908		return (g_status);
1909
1910	case DMODE_LIST:
1911		if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL)
1912			fatal("failed to open output file '%s'", g_ofile);
1913
1914		installsighands();
1915
1916		oprintf("%5s %10s %17s %33s %s\n",
1917		    "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
1918
1919		for (i = 0; i < g_cmdc; i++)
1920			list_prog(&g_cmdv[i]);
1921
1922		if (g_cmdc == 0)
1923			(void) dtrace_probe_iter(g_dtp, NULL, list_probe, NULL);
1924
1925		dtrace_close(g_dtp);
1926		return (g_status);
1927
1928	case DMODE_HEADER:
1929		if (g_cmdc == 0) {
1930			(void) fprintf(stderr, "%s: -h requires one or more "
1931			    "scripts or enabling options\n", g_pname);
1932			dtrace_close(g_dtp);
1933			return (E_USAGE);
1934		}
1935
1936		if (g_ofile == NULL) {
1937			char *p;
1938
1939			if (g_cmdc > 1) {
1940				(void) fprintf(stderr, "%s: -h requires an "
1941				    "output file if multiple scripts are "
1942				    "specified\n", g_pname);
1943				dtrace_close(g_dtp);
1944				return (E_USAGE);
1945			}
1946
1947			if ((p = strrchr(g_cmdv[0].dc_arg, '.')) == NULL ||
1948			    strcmp(p, ".d") != 0) {
1949				(void) fprintf(stderr, "%s: -h requires an "
1950				    "output file if no scripts are "
1951				    "specified\n", g_pname);
1952				dtrace_close(g_dtp);
1953				return (E_USAGE);
1954			}
1955
1956			p[0] = '\0'; /* strip .d suffix */
1957			g_ofile = p = g_cmdv[0].dc_ofile;
1958			(void) snprintf(p, sizeof (g_cmdv[0].dc_ofile),
1959			    "%s.h", basename(g_cmdv[0].dc_arg));
1960		}
1961
1962		if ((g_ofp = fopen(g_ofile, "w")) == NULL)
1963			fatal("failed to open header file '%s'", g_ofile);
1964
1965		oprintf("/*\n * Generated by dtrace(1M).\n */\n\n");
1966
1967		if (dtrace_program_header(g_dtp, g_ofp, g_ofile) != 0 ||
1968		    fclose(g_ofp) == EOF)
1969			dfatal("failed to create header file %s", g_ofile);
1970
1971		dtrace_close(g_dtp);
1972		return (g_status);
1973	}
1974
1975	/*
1976	 * If -a and -Z were not specified and no probes have been matched, no
1977	 * probe criteria was specified on the command line and we abort.
1978	 */
1979	if (g_total == 0 && !g_grabanon && !(g_cflags & DTRACE_C_ZDEFS))
1980		dfatal("no probes %s\n", g_cmdc ? "matched" : "specified");
1981
1982	/*
1983	 * Start tracing.  Once we dtrace_go(), reload any options that affect
1984	 * our globals in case consuming anonymous state has changed them.
1985	 */
1986	go();
1987
1988	(void) dtrace_getopt(g_dtp, "flowindent", &opt);
1989	g_flowindent = opt != DTRACEOPT_UNSET;
1990
1991	(void) dtrace_getopt(g_dtp, "grabanon", &opt);
1992	g_grabanon = opt != DTRACEOPT_UNSET;
1993
1994	(void) dtrace_getopt(g_dtp, "quiet", &opt);
1995	g_quiet = opt != DTRACEOPT_UNSET;
1996
1997	(void) dtrace_getopt(g_dtp, "destructive", &opt);
1998	if (opt != DTRACEOPT_UNSET)
1999		notice("allowing destructive actions\n");
2000
2001	installsighands();
2002
2003	/*
2004	 * Now that tracing is active and we are ready to consume trace data,
2005	 * continue any grabbed or created processes, setting them running
2006	 * using the /proc control mechanism inside of libdtrace.
2007	 */
2008	for (i = 0; i < g_psc; i++)
2009		dtrace_proc_continue(g_dtp, g_psv[i]);
2010
2011	g_pslive = g_psc; /* count for prochandler() */
2012
2013	dtrace_oformat_setup(g_dtp);
2014	do {
2015		if (!g_intr && !done)
2016			dtrace_sleep(g_dtp);
2017
2018#ifdef __FreeBSD__
2019		/*
2020		 * XXX: Supporting SIGINFO with oformat makes little sense, as
2021		 * it can't really produce sensible DTrace output.
2022		 *
2023		 * If needed, we could support it by having an imaginary
2024		 * "SIGINFO" probe that we can construct in the output but leave
2025		 * it out for now.
2026		 */
2027		if (g_siginfo && !dtrace_oformat(g_dtp)) {
2028			(void)dtrace_aggregate_print(g_dtp, g_ofp, NULL);
2029			g_siginfo = 0;
2030		}
2031#endif
2032
2033		if (g_newline) {
2034			/*
2035			 * Output a newline just to make the output look
2036			 * slightly cleaner.  Note that we do this even in
2037			 * "quiet" mode...
2038			 */
2039			oprintf("\n");
2040			g_newline = 0;
2041		}
2042
2043		if (done || g_intr || (g_psc != 0 && g_pslive == 0)) {
2044			done = 1;
2045			if (dtrace_stop(g_dtp) == -1)
2046				dfatal("couldn't stop tracing");
2047		}
2048
2049		switch (dtrace_work(g_dtp, g_ofp, chew, chewrec, NULL)) {
2050		case DTRACE_WORKSTATUS_DONE:
2051			done = 1;
2052			break;
2053		case DTRACE_WORKSTATUS_OKAY:
2054			break;
2055		default:
2056			if (!g_impatient && dtrace_errno(g_dtp) != EINTR)
2057				dfatal("processing aborted");
2058		}
2059
2060		if (g_ofp != NULL && fflush(g_ofp) == EOF)
2061			clearerr(g_ofp);
2062	} while (!done);
2063
2064	if (!dtrace_oformat(g_dtp))
2065		oprintf("\n");
2066
2067	/*
2068	 * Since there is no way to format a probe here and machine-readable
2069	 * output makes little sense without explicitly asking for it, we print
2070	 * nothing upon Ctrl-C if oformat is specified. If the user wishes to
2071	 * get output upon exit, they must write an explicit dtrace:::END probe
2072	 * to do so.
2073	 */
2074	if ((!g_impatient && !dtrace_oformat(g_dtp)) ||
2075	    (!g_impatient && print_upon_exit)) {
2076		if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 &&
2077		    dtrace_errno(g_dtp) != EINTR)
2078			dfatal("failed to print aggregations");
2079	}
2080
2081	dtrace_oformat_teardown(g_dtp);
2082	dtrace_close(g_dtp);
2083	return (g_status);
2084}
2085