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