在ldd上看到了systemtap这个东西,他是基于kprobe的内核调试工具,这里主要描述一下systemtap前期的环境搭建,和运行简单的systemtap命令
主要有如下几个步骤
拉取内核源码
配置内核config和编译
编译systemtap源码
使用stap命令进行简单的测试使用
这里我使用的是ubuntu2004,可用直接通过apt命令拉取内核代码
apt download linux-source-5.13.0 得到linux-source-5.13.0_5.13.0-37.42_all.deb
安装这个deb
dpkg -i linux-source-5.13.0_5.13.0-37.42_all.deb 得到/usr/src/linux-source-5.13.0 tar xvjf linux-source-5.13.0.tar.bz2 cp -rf debian linux-source-5.13.0
在内核里面可用看到默认的defconfig arch/x86/configs/x86_64_defconfig
编译defconfig
make x86_64_defconfig
安装编译内核相关的依赖包
apt-get build-dep linux-source-5.13.0
systemtap依赖一些内核选项
CONFIG_DEBUG_FS CONFIG_DEBUG_KERNEL CONFIG_DEBUG_INFO CONFIG_KPROBES
这里修改.config加上即可
直接编译内核即可
make bindeb-pkg -j16
编译完成之后,会在上级目录生成对应的deb文件如下
linux-headers-5.13.19_5.13.19-3_amd64.deb linux-image-5.13.19-dbg_5.13.19-3_amd64.deb linux-image-5.13.19_5.13.19-3_amd64.deb linux-libc-dev_5.13.19-3_amd64.deb
直接安装上述deb即可
重启机器,让系统从新的内核上启动,开机之后,可用uname -a查看内核版本
/boot/vmlinuz -> vmlinuz-5.13.19 uname -a Linux kylin 5.13.19 #3 SMP Tue Apr 19 17:19:44 CST 2022 x86_64 x86_64 x86_64 GNU/Linux
内核准备好了,但是因为内核是5.13.19。而系统中默认安装的systemtap支持不了这么高的内核版本,如果使用ubuntu2004默认提供的systemtap,会报如下错误
fails with vermagic.h:6:2: error: #error "This header can be included from kernel/module.c or *.mod.c only"
所以需要编译新的systemtap
从git拉systemtap的仓库代码
git clone git://sourceware.org/git/systemtap.git
默认使用最新的分支
安装编译的依赖
apt-get build-dep systemtap
编译
./configure make all -j8 make install -j8
编完之后,stap默认安装在local目录
/usr/local/bin/stap --version Systemtap translator/driver (version 4.6/0.176, non-git sources) Copyright (C) 2005-2021 Red Hat, Inc. and others This is free software; see the source for copying conditions. tested kernel versions: 2.6.32 ... 5.15.0-rc7 enabled features: AVAHI BOOST_STRING_REF BPF LIBSQLITE3 NLS NSS
创建软链接
ln -s /usr/local/bin/stap /usr/bin/stap
从上面可用看到,这个stap可以支持最高到5.15.0-rc7的内核版本
stap -l 'kernel.function("acpi_*")'
上面命令运行之后,会查看到内核的以acpi_开头的所有函数
如果需要使用stp文件进行加载,最简单的hello world如下
probe begin { print ("Hello World\n") exit () }
通过stap命令运行
stap -v hello.stp
能够出现Hello World即可正常
下面测试最简单的内核ko。
编写hello驱动
cat hello.c #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit);
cat Makefile # If KERNELRELEASE is defined, we've been invoked from the # kernel build system and can use its language. CFLAGS_MODULE += -g ifneq ($(KERNELRELEASE),) obj-m := hello.o # Otherwise we were called directly from the command # line; invoke the kernel build system. else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif
make生成hello.ko
将其拷贝到stap识别的目录上
mkdir /usr/lib/modules/`uname -r`/extra/ cp hello.ko /usr/lib/modules/5.13.19/extra/hello.ko
查看stap能否识别到hello.ko
stap -l 'module("hello").function("*")' module("hello").function("hello_exit@/root/ko/hello.c:10") module("hello").function("hello_init@/root/ko/hello.c:5")
编写hello.stp 做简单测试
cat hello.stp #!/usr/bin/stap probe module("hello").function("hello_exit").call { printf("Stap say hello world!\n"); }
先加载ko
insmod /usr/lib/modules/5.13.19/extra/hello.ko
然后加载stap脚本
stap -v hello.stp Pass 1: parsed user script and 481 library scripts using 103440virt/86100res/7488shr/78676data kb, in 420usr/80sys/507real ms. Pass 2: analyzed script: 1 probe, 0 functions, 0 embeds, 0 globals using 105444virt/89108res/8400shr/80680data kb, in 40usr/90sys/123real ms. Pass 3: using cached /root/.systemtap/cache/2a/stap_2a22c74fa0e66004c4e56eb4b264ae1b_1029.c Pass 4: using cached /root/.systemtap/cache/2a/stap_2a22c74fa0e66004c4e56eb4b264ae1b_1029.ko Pass 5: starting run.
看到Pass 5了,说明脚本在监听了
在另一个终端卸载ko驱动 就能监听到hello_exit函数的调用了
rmmod hello 后终端会如下显示 Stap say hello world!
https://wiki.debian.org/BuildADebianKernelPackage
https://wiki.ubuntu.com/Kernel/Systemtap
https://sourceware.org/systemtap/wiki