在C中编写DTrace使用者

obe*_*tet 9 c freebsd dtrace

我喜欢写在FreeBSD 10.1 C程序实现了一个DTrace使用者使用libdtrace.

我知道我需要从调用开始dtrace_open()- 例如我找到了这个旧的演示文稿,但我甚至无法启动,因为没有dtrace.h安装(仅在系统源代码树中).

安装了共享库,例如/usr/sbin/dtrace,FreeBSD附带的工具可以充当DTrace使用者,并且此工具链接到/lib/libdtrace.so.2(通过符号链接指向/usr/lib/libdtrace.so).

任何基本的例子,包括构建指令(FreeBSD 10.1/clang)都会对我有所帮助.


编写自定义使用者的实际目标是创建一个可在Python和PyPy中使用的基于CFFI的包装器.意思是:上面的C程序只是为了入门,学习然后继续.

CFFI是将PyPy与共享库连接的推荐,现代,高性能方式.

CFFI可用于ABI和API级别.后者需要包含头文件,前者需要声明从lib中使用的东西.


改编自Adam的答案,这是一个适用于FreeBSD 10.1的完整示例.

Makefile:

all:
        cc \
         -I /usr/src/cddl/compat/opensolaris/include \
         -I /usr/src/cddl/contrib/opensolaris/lib/libdtrace/common/ \
         -I /usr/src/sys/cddl/compat/opensolaris \
         -I /usr/src/sys/cddl/contrib/opensolaris/uts/common/ \
         hello_dtrace.c \
         -l dtrace -l proc -l ctf -l elf -l z -l rtld_db -l pthread -l util \
         -o hello_dtrace
Run Code Online (Sandbox Code Playgroud)

hello_dtrace.c:

#include <dtrace.h>
#include <signal.h>
#include <stdio.h>

static dtrace_hdl_t* g_dtp;

static int chewrec (const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg) {
   printf("chewing dtrace record ..\n");
   // A NULL rec indicates that we've processed the last record.
   if (rec == NULL) {
      return (DTRACE_CONSUME_NEXT);
   }
   return (DTRACE_CONSUME_THIS);
}

static const char* g_prog = "BEGIN { printf(\"hello from dtrace\\n\"); }";
//static const char* g_prog = "syscall::open*:entry { printf(\"%s %s\\n\", execname, copyinstr(arg0)); }";

static int g_intr;
static int g_exited;

static void intr (int signo) {
   g_intr = 1;
}


int main (int argc, char** argv) {
   int err;

   if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
      fprintf(stderr, "failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err));
      return -1;
   }
   printf("Dtrace initialized\n");

   (void) dtrace_setopt(g_dtp, "bufsize", "4m");
   (void) dtrace_setopt(g_dtp, "aggsize", "4m");
   printf("dtrace options set\n");

   dtrace_prog_t* prog;
   if ((prog = dtrace_program_strcompile(g_dtp, g_prog, DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL) {
      fprintf(stderr, "failed to compile dtrace program\n");
      return -1;
   } else {
      printf("dtrace program compiled\n");
   }

   dtrace_proginfo_t info;
   if (dtrace_program_exec(g_dtp, prog, &info) == -1) {
      fprintf(stderr, "failed to enable dtrace probes\n");
      return -1;
   } else {
      printf("dtrace probes enabled\n");
   }

   struct sigaction act;
   (void) sigemptyset(&act.sa_mask);
   act.sa_flags = 0;
   act.sa_handler = intr;
   (void) sigaction(SIGINT, &act, NULL);
   (void) sigaction(SIGTERM, &act, NULL);

   if (dtrace_go(g_dtp) != 0) {
      fprintf(stderr, "could not start instrumentation\n");
      return -1;
   } else {
      printf("instrumentation started ..\n");
   }

   int done = 0;
   do {
      if (!g_intr && !done) {
         dtrace_sleep(g_dtp);
      }

      if (done || g_intr || g_exited) {
         done = 1;
         if (dtrace_stop(g_dtp) == -1) {
            fprintf(stderr, "could not stop tracing\n");
            return -1;
         }
      }

      switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
         case DTRACE_WORKSTATUS_DONE:
            done = 1;
            break;
         case DTRACE_WORKSTATUS_OKAY:
            break;
         default:
            fprintf(stderr, "processing aborted");
            return -1;
      }
   } while (!done);

   printf("closing dtrace\n");
   dtrace_close(g_dtp);

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

跑步:

[oberstet@brummer2 ~/hello_dtrace]$ make; sudo ./hello_dtrace
cc  -I /usr/src/cddl/contrib/opensolaris/lib/libdtrace/common/  -I /usr/src/sys/cddl/compat/opensolaris  -I /usr/src/sys/cddl/contrib/opensolaris/uts/common/  hello_dtrace.c  -l dtrace  -l proc  -l ctf  -l elf  -l rtld_db  -l z  -l pthread  -l util  -o hello_dtrace
Dtrace initialized
dtrace options set
dtrace program compiled
dtrace probes enabled
instrumentation started ..
chewing dtrace record ..
hello from dtrace
chewing dtrace record ..
^Cclosing dtrace
Run Code Online (Sandbox Code Playgroud)

小智 9

libdtraceAPI不一定适用于稳定的消费者,但它很容易从一些现有的消费者要学会上手.最简单和最现代的是plockstat用户土地锁定统计的illumos实用程序.

以下是简单DTrace使用者程序的基本流程:

dtrace_open()得到一个dtrace_hdl_t,一个用于配置选项的其他libdtrace交互的句柄
dtrace_setopt()(-xflag to dtrace(1M))
dtrace_strcompile()来编译你的D程序的字符串,
dtrace_program_exec()将该程序发送到内核
dtrace_go()以检测系统并开始记录数据
dtrace_close()以便最后清理

对于主数据收集循环(在dtrace_go()和之间dtrace_close())执行以下操作:

dtrace_sleep()根据DTrace选项(切换和聚合)暂停
dtrace_work()以处理已
dtrace_stop()中止的跟踪数据

有关更多信息,请参阅主循环plockstat.c.

对于其他简单的DTrace消费者,请查看intrstatlockstat.对于厨房水槽,请查看dtrace(1M)命令行实用程序的代码.