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