我正在尝试通过libdtrace使用dtrace(在Snow Leopard上; 10.6.4)。我想在我自己的程序中捕获我的dtrace脚本的打印输出。一种方法是将输出转到临时文件并从那里读取。但是,libdtrace支持一个回调函数来直接捕获我更喜欢的输出。
我认为回调只会传递我可以使用的格式化字符串,但似乎并非如此。例如,在下面的测试程序中,我希望打印输出为“process pid = 86138”。但是,它总是打印出“process pid = 1”(当使用'dtrace -n'运行时,dtrace脚本正常工作)。
我做错了什么?我应该如何使用传递给缓冲区处理程序的数据? (具体来说,来自printf和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;
}
答案 0 :(得分:0)
缓冲输出似乎在OSX上被打破。这些行为似乎以某种扭曲的方式在消费者的背景下以某种方式执行。例如,ustack()
根本不起作用。另一方面,copyinstr()
似乎运作正常。
您可以绕过输出缓冲但仍然通过使用管道获得大致相同的结果:
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);
}
错误处理留给读者练习。