systemtap工具

一、简介

    systemtap是Linux下一个非常有用的调试(跟踪/探测)工具,常用于Linux内核或者应用程序的信息采集,比如:获取一个函数里面运行时的变量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非常有帮助。

二、适用情景解决的问题

1 解决的问题

需要获取正在运行的Linux系统的信息,如系统调用等。

  • 最原始的方法是,找到内核调用的代码,加上我们需要获得信息的代码,重新编译内核、安装并选择我们新编译的内核重启。
  • 之后内核引入了一种Kprobe机制,可以用来动态地收集调试和性能信息的工具,用户可以用它跟踪运行中内核任何函数或执行的指令等。但Kprobe并没有提供一种易用的框架,用户需要自己去写模块,然后安装。
  • systemtap是利用Kprobe提供的API来实现动态地监控和跟踪运行中的Linux内核的工具,相比Kprobe,systemtap更加简单,提供给用户简单的命令行接口,以及编写内核指令的脚本语言。

2 适用情景

  • 定位(内核)函数位置
  • 查看函数被调用时的调用堆栈、局部变量、参数
  • 查看函数指针变量实际指的是哪个函数
  • 查看代码的执行轨迹(哪些行被执行了)
  • 查看内核或者进程的执行流程
  • 调试内存泄露或者内存重复释放
  • 统计函数调用次数
    ...

三、安装与运行

    systemtap运行需要内核的调试信息支撑,默认发行版的内核在配置时这些调试开关没有打开。systemtap依赖的package:elfutils(提供分析调试信息的库函数)、gcc(C语言编译器)、linux-headers-generic(编译内核模块所需的内核头文件以及模块配置信息)、kernel-devel、kernel-debuginfo(内核调试信息)。如果调用用户态进程,还需要该程序有调试符号,否则无法调试。以下是ubuntu16.04 TLS的安装过程。

0 判断内核是否支持systemtap

在 /boot 目录下查看当前版本的配置信息,是否包含如下的编译选项:

cat /boot/config-`uname -r` | egrep 'CONFIG_(DEBUG_INFO|KPROBES|DEBUG_FS|RELAY)='

如果没有上述的配置项,则需要重新编译,需要打开调试信息、Kprobe 和 debugfs ,确保 .config 文件中看到上面的四个选项。

1 源码安装systemtap

wget ftp://sources.redhat.com/pub/systemtap/releases/systemtap-4.1.tar.gz
tar -zxvf systemtap-4.1.tar.gz
wget https://sourceware.org/elfutils/ftp/0.176/elfutils-0.176.tar.bz2
tar -jxvf elfutils-0.176.tar.bz2
cd systemtap-4.1
./configure --with-elfutils=/home/ubuntu16/elfutils-0.176 --with-prefix=/usr

在编译过程中会出现一些error,要求各种依赖库,安装即可:

sudo apt-get install zlib1g-dev
sudo apt-get install libcurl4-openssl-dev -y
sudo apt-get install -y libmicrohttpd-dev -y
sudo apt-get install libsqlite3-dev -y
sudo apt-get install -y libarchive-dev -y
sudo apt-get install m4 -y
sudo apt-get install -y gawk

报错提示,跟着提示安装即可:

./configure  '--with-elfutils=/home/ubuntu16/elfutils-0.176' '--with-prefix=/usr' python='/usr/bin/python2' pyexecdir='${exec_prefix}/lib/python2.7/dist-packages' python3='/usr/bin/python3' py3execdir='${exec_prefix}/lib/python3.5/site-packages' --prefix=/home/ubuntu16/systemtap-4.1-17624

将systemtap加入/usr/lib

ln -s systemtap /usr/local/bin

2 安装内核调试包

# 查看需要的包
stap-prep
# 查看内核版本
uname -r

参考:https://blog.csdn.net/u011944141/article/details/89512116

# 创建 /etc/apt/sources.list.d/ddebs.list
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list
echo -e "deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse\ndeb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ddebs.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F2EDC64DC5AEE1F6B9C621F0C8CAB6595FDFF622
sudo apt-get update
# 继续检测
stap-prep
# Please install linux-image-4.15.0-112-generic-dbgsym
sudo apt-get install linux-image-4.15.0-112-generic-dbgsym
# 再次检测安装环境
stap-prep
# 运行测试执行脚本
sudo ./stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'

3 测试示例

sudo stap -v -e 'probe begin { printf("Hello, World!\n"); exit() }'
sudo stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'

四、工作原理

    systemtap的核心思想是定义一个事件(event),以及给出处理该事件的句柄(Handler)。当一个特定的事件发生时,内核运行该处理句柄,就像快速调用一个子函数一样,处理完之后恢复到内核原始状态。这里有两个概念:

  • 事件(Event):systemtap 定义了很多种事件,例如进入或退出某个内核函数、定时器时间到、整个systemtap会话启动或退出等等。
  • 句柄(Handler):就是一些脚本语句,描述了当事件发生时要完成的工作,通常是从事件的上下文提取数据,将它们存入内部变量中,或者打印出来。
        Systemtap 工作原理是通过将脚本语句翻译成C语句,编译成内核模块。模块加载之后,将所有探测的事件以钩子的方式挂到内核上,当任何处理器上的某个事件发生时,相应钩子上句柄就会被执行。最后,当systemtap会话结束之后,钩子从内核上取下,移除模块。整个过程用一个命令 stap 就可以完成,处理流程如下图。


    systemtap 处理流程

        Systemtap的处理流程有5个步骤:

  • Pass1:Parse 解析script文件
  • Pass2:Elaborate 细化
  • Pass3:Translate script文件翻译成C语言代码
  • Pass4:Compile 编译C语言代码(生成内核模块)
  • Pass5:Run 加载内核模块

参考

1、https://www.cnblogs.com/hazir/p/systemtap_introduction.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。