一、简介
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
网友评论