从 DTrace 脚本调用 C 函数

Posted

技术标签:

【中文标题】从 DTrace 脚本调用 C 函数【英文标题】:Calling C function from DTrace scripts 【发布时间】:2010-02-02 12:35:21 【问题描述】:

DTrace 是令人印象深刻的强大跟踪系统,最初来自 Solaris,但它已移植到 FreeBSD 和 Mac OSX。

DTrace 使用称为 D 的高级语言,与 AWK 或 C 不同。下面是一个示例:

io:::start
/pid == $1/

    printf("file %s offset %d size %d block %llu\n", args[2]->fi_pathname, 
        args[2]->fi_offset, args[0]->b_bcount, args[0]->b_blkno);

使用命令行 sudo dtrace -q -s <name>.d <pid> 记录所有源自该进程的 IO。

我的问题是,是否以及如何可以从 DTrace 脚本调用自定义 C 函数,以便在跟踪过程中对跟踪数据执行高级操作。

【问题讨论】:

【参考方案1】:

DTrace 明确阻止您执行此类操作,原因与您无法在 D 中编写循环相同:如果您以任何方式、形状或形式将其搞砸,整个系统都会崩溃。当 D 探针触发时,您处于 KERNEL 模式,而不是用户态。让我引用“Linux内核模块编程指南”:

所以,你想写一个内核模块。你知道 C,你写过很多 正常程序作为进程运行,现在你想要到达真正的地方 行动是,一个单一的野指针可以清除你的文件系统和一个 核心转储意味着重新启动。

这就是为什么你不想在 D 调查中扮演牛仔,以及为什么 D 的限制对你有好处。 =]

【讨论】:

【参考方案2】:

您应该能够在每次使用管道触发探针后至少过滤 dtrace 的输出。

sudo dtrace -n 'proc:::exec-success trace(curpsinfo->pr_psargs); ' | perl myscript.pl

myscript.pl:

#!/usr/bin/perl
而()
打印 $_;
print "另一个应用程序启动了,做点什么!";

【讨论】:

【参考方案3】:

由于@Sniggerfardimungus 提到的原因,不可能从探针内部调用任意 C,但大概您只想对正在收集的数据进行一些操作(将其存储在数据库中/进行一些计算或可视化使用它/等),这完全可以从 C 语言(以及通过其他几种语言中的 C 语言的包装器)实现。

为此,请使用libdtrace(标头在我的Mac OS X 机器上的/usr/include/dtrace.h)或它的包装器,例如node-libdtrace。基本思想是您可以构建自己的 DTrace 数据使用者(实际上,替换dtrace(1m) 命令行工具),它接收来自任何正在运行的脚本的输出。一旦你有了数据,你就可以用它做任何你想做的事情。

【讨论】:

【参考方案4】:

编辑我的原始答案为时已晚,但您也可以在 DTrace 脚本中使用 system() 命令生成一个子进程,该子进程在 DTrace 中发生事件时运行任意代码。这可能是destructive action,因此您必须在 D 脚本中使用-w 命令行选项或#pragma D option destructive 指令。请注意,如果您不小心使用,破坏性操作可能会挂起、无限循环、杀死或以其他方式破坏您正在探测的进程。 (而且我不建议使用内核破坏性操作,除非您真的不在乎您的系统是否会因意外弄乱而崩溃。)

您可以使用 system() 运行的脚本来调用您的任意 C 代码(或向另一个进程发送信号以调用它等)。

【讨论】:

以上是关于从 DTrace 脚本调用 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 dtrace 分析 C 代码

如何使用 dtrace 跟踪函数?

dtrace:如何从文件中获取符号链接目标

从 C 程序访问 dtrace 探针

是否可以通过函数地址从 lua 脚本调用任何主机 c/c++ 函数?

dtrace 将在将来运行的用户进程