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