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