systemtap对用户级和内核级代码提供了静态和动态跟踪的功能。Systemtap采用其他的内核框架做源:静态探针用tracepoints、动态探针用kprobes、用户级别的探针用uprobes。这些源也为perf、LTTng所用。
由于 systemtap 运行需要内核的调试信息支撑,默认发行版的内核在配置时这些调试开关没有打开,所以安装完systemtap也是无法去探测内核信息的。
Systemtap 工作原理是通过将脚本语句翻译成C语句,编译成内核模块。模块加载之后,将所有探测的事件以钩子的方式挂到内核上,当任何处理器上的某个事件发生时,相应钩子上句柄就会被执行。最后,当systemtap会话结束之后,钩子从内核上取下,移除模块。
工作原理如下图:
安装
安装分为两部分:一部分为是systemtap工具本身,另一部分是内核调试信息。
在ubuntu中使用apt-get install systemtap命令进行安装。
因为systemtap需要内核信息来防止指令,所以需要安装debug info,先通过命令uname -r查看内核版本,然后安装linux-image-[uname –r]-
dbgsym
。
Ubuntu参考:
https://wiki.ubuntu.com/DebuggingProgramCrash#Built-in_debug_symbol_packages_.28.2A-dbg.29
其中4.4.0-63的下载链接如下:
http://launchpadlibrarian.net/304789714/linux-image-4.4.0-63-generic-dbgsym_4.4.0-63.84_amd64.ddeb
4.14.0下载地址:
https://launchpad.net/ubuntu/artful/amd64/linux-image-4.13.0-43-generic-dbgsym/4.13.0-43.48
ubuntu16的其他相关下载地址:
https://packages.ubuntu.com/zh-cn/xenial/amd64/linux-image-4.13.0-43-generic/download
或者直接运行stap-prep命令来进行安装。
也可以使用一个老外写的脚来下载,如下:
wget
http://www.domaigne.com/download/tools/get-dbgsym
chmod +x get-dbgsym
sudo ./get-dbgsy
另外,实例脚本位于:/usr/share/systemtap/tapset中。
红帽手动配置debuginfo
编译完内核后,执行如下命令:
#ln -s /kernel/linux-4.15.15/vmlinux /boot/vmlinux-`uname -r`
#ln -s /lib/modules/`uname -r` /usr/lib/debug/lib/modules/`uname -r`
#cd /usr/lib/debug/lib/modules/`uname -r`
然后执行如下脚本:
for file in `find -name ‘*.ko’ -print`
do
buildid=`eu-readelf -n $file| grep Build.ID: | awk ‘{print $3}’`
dir=`echo $buildid | cut -c1-2`
fn=`echo $buildid | cut -c3-`
mkdir -p /usr/lib/debug/.build-id/$dir
ln -s $file /usr/lib/debug/.build-id/$dir/$fn
ln -s $file /usr/lib/debug/.build-id/$dir/${fn}.debug
done
探针
探针的定义由句号分隔。示例如下:
begin:程序开始
end:程序开始
syscall.read: 系统调用read()的开始
syscall.read.return:系统调用read()的结束。
kernel.function(“sys_read”):内核函数sys_read()的开始
kernel.function(“sys_read”).return:内核函数sys_read的结束
socket.send:发送包
timer.ms(100):每100ms触发一次探针
timer.profile:按内核时钟频率对所有的CPU都触发的探针,用于采样/剖析。
process(“a.out”).statement(
*@main.c:100
): 跟踪目标进程,可执行文件a.out,main.c的100行。
tapset
一组相关的探针被称为tapset。
syscall:系统调用
ioblock:块设备接口和IO调度器
scheduler:内核CPU调度器事件
memory:进程和虚拟内存使用
scsi:SCSI目标事件
networking:网络设备事件
tcp:TCP协议事件
socket:套接字事件
此外systemtap还提供了许多action和内置变量,例如execname()获取进程名,pid()获取当前进程ID,print_backtrace()打印内核栈的回溯信息。
开销
systemtap 在编译阶段会消耗CPU资源。也可以在不同的系统上编译systemtap程序,然后将缓存结果传输给目标系统。
实战
执行如下代码:
# stap -ve ‘probe begin {log(“hello!”) exit()}’
实例代码
创建open.stp代码如下:
#!/usr/bin/stap
probe begin
{
log(“begin to probe”)
}
probe syscall.open
{
printf (“%s(%d) open (%s)\n”,execname(), pid(), argstr)
}
probe timer.ms(4000) # after 4 seconds
{
exit ()
}
probe end
{
log(“end to probe”)
}
使用
#stap open.stp 开始执行。
这个脚本会在系统中调用open时候,将调用者的执行名字和进程号给打印出来,只要有人调用open就会打印,无所遁形。Systemtap提供了很多可以被printf函数调用的函数,除了execname(),pid()外,还有tid()等等。
常用的有:tid(),uid(),cpu(),gettimeofday_s(),ctime(),pp(),thread_indent(),
因为发行版本本身不包含debuginfo,所以在使用时候难免有些阻碍。
相比oprofile,systemtap适合做跟踪,而oprofile适合做性能诊断。
参考
官方源码:
https://sourceware.org/systemtap/documentation.html
《SystemTap_Begginers_Guide.pdf》