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