本文介绍了libdtrace缓冲输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过libdtrace使用DTrace(雪豹; 10.6.4)。我要赶我自己的节目中我的DTrace脚本的打印输出。这样做的一种方法是将有输出去到一个临时文件,并从那里读取。然而,libdtrace支持一个回调函数,直接赶输出,我想preFER。

我认为回调将只是通过我的格式的字符串,我可以消费,但是这似乎并不如此。例如,在下面的测试程序,我期望的打印输出是进程pid = 86138。然而,它总是打印出进程的PID = 1(DTrace脚本正常工作,当'的DTrace -n跑了)。

我是什么做错了吗?我应该如何消费传递给缓存管理器中的数据? (具体而言,从printf和tracemem操作的数据是什么我感兴趣的)。

 的#include< dtrace.h>
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;马赫/ mach.h>
#包括LT&;的Mach-O / loader.h>
#包括LT&;的Mach-O / dyld.h>
#包括LT&;的Mach-O / fat.h>
#包括LT&; SYS / sysctl.h>
#包括LT&;&signal.h中GT;静态为const char * g_prog =
  pid86138 ::写:条目
  {
  的printf(\\进程的PID =%d个\\\\ñ\\,PID);
  };静态INT dcmdbuffered(常量dtrace_bufdata_t * bufdata,无效* ARG){
  如果((bufdata->!dtbda_recdesc = NULL)及及(bufdata-> dtbda_recdesc-> dtrd_action == DTRACEACT_PRINTF))
    的printf(BUF:%S \\ n,bufdata-> dtbda_buffered);  返回DTRACE_HANDLE_OK;
}静态INT咀嚼(常量dtrace_probedata_t *数据,无效* ARG){
  返回DTRACE_CONSUME_THIS;
}静态INT chewrec(常量dtrace_probedata_t *数据常量dtrace_recdesc_t * REC,无效* ARG){
  如果(REC == NULL)
    返回(DTRACE_CONSUME_NEXT);
  返回(DTRACE_CONSUME_THIS);
}INT主(INT ARGC,字符** argv的){
  INT犯错,做= 0;
  dtrace_proginfo_t信息;  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,&安培;信息);
  dtrace_setopt(g_dtp了strsize,4096);
  dtrace_setopt(g_dtpBUFSIZE,4M);
  dtrace_setopt(g_dtp,牌坊,x86_64的);
  dtrace_go(g_dtp);  而(dtrace_work(g_dtp,NULL,咀嚼,chewrec,NULL)== DTRACE_WORKSTATUS_OKAY)
    dtrace_sleep(g_dtp);  dtrace_stop(g_dtp);
  dtrace_close(g_dtp);
  返回0;
}


解决方案

缓冲输出似乎在OSX被打破。这些行动似乎在消费者中的一些扭曲的方式背景下以某种方式执行。 的ustack()不工作的时候,例如。 copyinstr()子,另一方面似乎正常工作。

您可以绕过输出缓冲,但仍通过管道得到几乎相同的结果:

  INT FDS [2];如果(管(FDS)!= 0)
    (0)断言;INT标志=的fcntl(FDS [0],F_GETFL,0);
断言(旗!= -1);
的fcntl(FDS [0],F_SETFL,旗帜| O_NONBLOCK);FILE * faux_stdout = fdopen(FDS [1],一个);
断言(faux_stdout);而(dtrace_work(g_dtp,faux_stdout,咀嚼,chewrec,NULL)== DTRACE_WORKSTATUS_OKAY){
    焦炭BUF [1024];
    为(;;){
        ssiz​​e_t供num_read =读(FDS [0],buf中,的sizeof(buf中));
        如果(num_read&下; = 0)
            打破;
        / *你的过程这里的缓冲区* /
        FWRITE(BUF,1,num_read,标准输出);
    }
    dtrace_sleep(g_dtp);
}

错误处理作为练习留给读者。

I'm trying to use dtrace through libdtrace (on Snow Leopard; 10.6.4). I want to catch the printed output of my dtrace script within my own program. One way to do so would be to have the output go to a temporary file and read it from there. However, libdtrace supports a callback function to catch the output directly which I'd prefer.

I assumed the callback would just pass me formatted strings that I could consume, but this does not seem to be the case. For example, in the below test program, I'd expect the printout to be "process pid = 86138". However, it always prints out "process pid = 1" (the dtrace script works fine, when ran with 'dtrace -n').

What am I doing wrong ? How should I be consuming the data passed to the buffer handler ? (Specifically, data from printf and tracemem actions are what I'm interested in).

#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;
}
解决方案

Buffered output seems to be broken on OSX. The actions seem to be somehow executed in the consumer's context in some twisted way. ustack() doesn't work at all, for example. copyinstr() on the other hand seems to function properly.

You can circumvent output buffering yet still get mostly the same result by 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 is left as an exercise to the reader.

这篇关于libdtrace缓冲输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 02:26
查看更多