0
点赞
收藏
分享

微信扫一扫

在bpfTrace中使用USDT


本作品采用​​知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议​​进行许可。

本作品 (李兆龙​ 博文, 由 李兆龙​ 创作),由 李兆龙 确认,转载请注明版权。

引言

USDT的全称是​​user-level statically defined tracing​​,是一种在用户态中埋点,以支持动态追踪的方案,埋点的优点基本可以阐述为以下三点:

  1. 防止inline而导致无法监测到函数
  2. 随版本迭代接口功能可以保证没有变化
  3. 在不进行追踪时插入一条nop指令,在进行追踪时替换为int3。在不追踪时最大程度节省性能,代价只是一条nop和elf文件中多一个NOTE段,其中存储着probe的一些偏移信息。

不过目前这种USDT的埋点方案我还没有找到如何在SystemTap去使用([3]中描述量一种情况),[1]中描述了systemTap中usdt的使用,我们这篇来看一看如何在bpfTrace中使用USDT,这里我们使用Folly中的Traceing工具(folly/tracing)去实现需求,这里其实Folly中只用到了​​StaticTracepoint-ELFx86.h​​​和​​StaticTracepoint.h​​这两个文件而已,所以我们完全可以把这两个文件直接拷贝到我们的项目中,使得项目原生支持USDT。

例子

我们先看一个简单的例子:

#include "StaticTracepoint.hpp"
#include <unistd.h>

int main() {
sleep(5);
int one = 10;
int two = 20;
for (size_t i = 0; i < 100; i++) {
one = two = i;
TRACING_SDT(lizhaolong, yunwenqi, one, two);
}
sleep(10000);
return 0;
}

执行如下指令​​g++ -fno-omit-frame-pointer -O0 -g main.cpp​​​,然后我们gdb进去看看汇编,执行​​disassemble /m main​​就可以看到函数对应的源码和汇编了:

在bpfTrace中使用USDT_信号量


我们可以看到bpfTrace没有开始追踪时,这个地方是一条空指令,因为​​StaticTracepoint-ELFx86.h​​​中插入汇编时有一条​​__volatile__​​​,所以这个nop指令也不会被优化。当我们把bpfTrace挂上时,即执行如下指令​​sudo bpftrace -e 'usdt:/home/lizhaolong.lzl/usdt/a.out:lizhaolong:yunwenqi {printf("%d %d\n", arg0, arg1)}'​​,我们可以看到这样的输出:

在bpfTrace中使用USDT_linux_02


此时gdb进去,可以看到如下显示:

在bpfTrace中使用USDT_#include_03


这里其实就是去利用uprobes去执行动态追踪了。我们也可以在elf文件中看到probe已经存在的证据:

在bpfTrace中使用USDT_#include_04


好巧不巧,这里的Location的偏移就是我们设定的probe的起始地址,后面还有后面要提的信号量的偏移。

除了正常的埋点意外,还可以把代码写成下面这样:

#include "StaticTracepoint.hpp"
#include <unistd.h>

// 必须放到全局变量处,这是一个信号量的声明,有extern "C" 前缀
TRACING_SDT_DEFINE_SEMAPHORE(lizhaolong, yunwenqi)

int main() {
sleep(5);
int one = 10;
int two = 20;
for (size_t i = 0; i < 100; i++) {
one = two = i;
if (TRACING_SDT_IS_ENABLED(lizhaolong, yunwenqi)) {
one *= 10;
two *= 10;
TRACING_SDT_WITH_SEMAPHORE(lizhaolong, yunwenqi, one, two);
}
}
sleep(10000);
return 0;
}

其实就是可能在把参数传向probe时可能需要做一些处理,这些处理可能是比较昂贵的,所以自然没有被追踪时我们不希望这些代码被执行,此时可以设定一个信号量,在被追踪时才被设置,其实本质就是一个​​volatile unsigned short​​。

在bpfTrace中使用USDT_信号量_05


在bpfTrace中使用USDT_i++_06


我们可以看到信号量的地址其实已经是写在elf文件中了的。此时我们用一个if判断跳过了昂贵的参数处理过程。

参考:

  1. ​​https://github.com/agentzh/usdt-sample​​
  2. ​​https://github.com/facebook/folly​​
  3. ​​Adding User Space Probing to an Application (heapsort example)​​


举报

相关推荐

0 条评论