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