2010-09-25 3 views
4

Я пытаюсь использовать dtrace через libdtrace (на Snow Leopard; 10.6.4). Я хочу поймать печатный результат моего сценария dtrace в моей собственной программе. Один из способов сделать это - заставить выход перейти во временный файл и прочитать его оттуда. Однако libdtrace поддерживает функцию обратного вызова, чтобы поймать вывод, который я бы предпочел.libdtrace буферизованный вывод

Я предположил, что обратный вызов просто передаст мне форматированные строки, которые я мог бы использовать, но это, похоже, не так. Например, в приведенной ниже тестовой программе я ожидаю, что распечатка будет «process pid = 86138». Тем не менее, он всегда печатает «process pid = 1» (сценарий dtrace отлично работает, когда он запускается с помощью «dtrace -n»).

Что я делаю неправильно? Как я должен использовать данные, переданные обработчику буфера? (В частности, меня интересуют данные от printf и tracemem actions).

#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

Буферный выход, по-видимому, сломан на 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); 
} 

Обработка ошибок в качестве упражнения для читателя.

Смежные вопросы