c - libdtrace 缓冲输出

标签 c macos debugging dtrace

我正在尝试通过 libdtrace(在 Snow Leopard 上;10.6.4)使用 dtrace。我想在我自己的程序中捕获我的 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;
}

最佳答案

缓冲输出在 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);
}

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

关于c - libdtrace 缓冲输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3792486/

相关文章:

c - 无法从文本文件中读取数据。

c - 如何用C写一个DLL文件?

objective-c - 如何检查应用程序/二进制文件的另一个实例是否已经在运行

debugging - 在调试期间在 IDE 中显示 printf 消息

debugging - Chrome为什么在所有网站中都引用 “data:text/css,”?

actionscript-3 - Actionscript 3.0 中的行号常量?

c++ - 创建链接数未知的结构节点

c++ - 了解 C 中的基数排序

ipad - 在 iPad 上访问本地主机

macos - 如何在Mac或PC上实现cheatsheet或keycue等功能