Libdtrace buffering output

I am trying to use dtrace via libdtrace (on Snow Leopard, 10.6.4). I want to catch the printed output of my dtrace script in my own program. One way to do this is to force the output to go to a temporary file and read it from there. However, libdtrace does support a callback function to catch the result I would prefer.

I assumed that the callback would just give me formatted strings that I could use, but that doesn't seem to be the case. For example, in the test program below, I expect the printout to be "process pid = 86138." However, it always prints "process pid = 1" (dtrace script works fine when it works with "dtrace -n").

What am I doing wrong? How should I use the data passed to the buffer handler? (In particular, I'm interested in data from printf and tracemem).

#include <dtrace.h> #include <stdio.h> #include <stdlib.h> #include <mach/mach.h> #include <mach-o/loader.h> #include <mach-o/dyld.h> #include <mach-o/fat.h> #include <sys/sysctl.h> #include <signal.h> static const char *g_prog = "pid86138::write:entry" "{" " printf(\"process pid = %d\\n\", pid);" "}"; static int dcmdbuffered(const dtrace_bufdata_t *bufdata, void *arg) { if((bufdata->dtbda_recdesc != NULL) && (bufdata->dtbda_recdesc->dtrd_action == DTRACEACT_PRINTF)) printf("BUF: %s\n", bufdata->dtbda_buffered); return DTRACE_HANDLE_OK; } static int chew(const dtrace_probedata_t *data, void *arg) { return DTRACE_CONSUME_THIS; } static int chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) { if(rec == NULL) return (DTRACE_CONSUME_NEXT); return (DTRACE_CONSUME_THIS); } int main(int argc, char **argv) { int err, done = 0; dtrace_proginfo_t info; dtrace_hdl_t *g_dtp = dtrace_open(DTRACE_VERSION, DTRACE_O_ILP32, &err); dtrace_prog_t *prog = dtrace_program_strcompile(g_dtp, g_prog, DTRACE_PROBESPEC_NAME, 0, 0, NULL); dtrace_handle_buffered(g_dtp, dcmdbuffered, NULL); dtrace_program_exec(g_dtp, prog, &info); dtrace_setopt(g_dtp, "strsize", "4096"); dtrace_setopt(g_dtp, "bufsize", "4m"); dtrace_setopt(g_dtp, "arch", "x86_64"); dtrace_go(g_dtp); while(dtrace_work(g_dtp, NULL, chew, chewrec, NULL) == DTRACE_WORKSTATUS_OKAY) dtrace_sleep(g_dtp); dtrace_stop(g_dtp); dtrace_close(g_dtp); return 0; } 
+4
source share
1 answer

The buffered output seems to be broken on OSX. It seems that the actions are somehow carried out in a consumer context. ustack() does not work at all, for example. On the other hand, copyinstr() working fine.

You can bypass output buffering, but still get basically the same result using pipe:

 int fds [2]; if (pipe (fds) != 0) assert (0); int flags = fcntl (fds [0], F_GETFL, 0); assert (flags != -1); fcntl (fds [0], F_SETFL, flags | O_NONBLOCK); FILE *faux_stdout = fdopen (fds [1], "a"); assert (faux_stdout); while(dtrace_work(g_dtp, faux_stdout, chew, chewrec, NULL) == DTRACE_WORKSTATUS_OKAY) { char buf [1024]; for (;;) { ssize_t num_read = read (fds [0], buf, sizeof (buf)); if (num_read <= 0) break; /* process your buffer here */ fwrite (buf, 1, num_read, stdout); } dtrace_sleep(g_dtp); } 

Error handling remains as an exercise for the reader.

0
source

All Articles