2010-09-25 3 views
4

J'essaie d'utiliser dtrace via libdtrace (sur Snow Leopard; 10.6.4). Je veux attraper la sortie imprimée de mon script dtrace dans mon propre programme. Une façon de le faire serait d'avoir la sortie aller à un fichier temporaire et de le lire à partir de là. Cependant, libdtrace supporte une fonction de rappel pour attraper directement la sortie que je préfère. J'ai supposé que le rappel me passerait juste des chaînes formatées que je pourrais consommer, mais cela ne semble pas être le cas. Par exemple, dans le programme de test ci-dessous, l'impression devrait être "process pid = 86138". Cependant, il imprime toujours "process pid = 1" (le script dtrace fonctionne bien, lorsqu'il est exécuté avec 'dtrace -n').sortie tamponnée libdtrace

Qu'est-ce que je fais mal? Comment dois-je consommer les données transmises au gestionnaire de tampon? (Plus précisément, les données issues des actions printf et tracemem sont ce qui m'intéresse).

#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; 
} 

Répondre

0

La sortie en tampon semble être interrompue sous OSX. Les actions semblent être en quelque sorte exécutées dans le contexte du consommateur d'une manière tordue. ustack() ne fonctionne pas du tout, par exemple. copyinstr() d'autre part semble fonctionner correctement.

Vous pouvez contourner encore en mémoire tampon de sortie encore obtenir la plupart du temps le même résultat en utilisant une tuyauterie:

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); 
} 

La gestion des erreurs est laissée en exercice au lecteur.

Questions connexes