systemtap对用户级和内核级代码提供了静态和动态跟踪的功能。Systemtap采用其他的内核框架做源:静态探针用tracepoints、动态探针用kprobes、用户级别的探针用uprobes。这些源也为perf、LTTng所用。

由于 systemtap 运行需要内核的调试信息支撑,默认发行版的内核在配置时这些调试开关没有打开,所以安装完systemtap也是无法去探测内核信息的。

Systemtap 工作原理是通过将脚本语句翻译成C语句,编译成内核模块。模块加载之后,将所有探测的事件以钩子的方式挂到内核上,当任何处理器上的某个事件发生时,相应钩子上句柄就会被执行。最后,当systemtap会话结束之后,钩子从内核上取下,移除模块。

工作原理如下图:

systemtap概述及实例_linux

安装

安装分为两部分:一部分为是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》

https://sourceware.org/systemtap/archpaper.pdf

官方实例:https://sourceware.org/systemtap/examples/