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