原理
systemtap原理类似与Runtime Hook技术,先找到函数的入口地址,然后保存函数的入口代码,再动态修改这部分代码,当内核调用函数时,systemtap就会执行检测点的修改代码,从而打印出我们需要的信息。
X86环境
Linux CentOS 3.10.0-514.2.2.el7.x86_64
安装:sudo yum install systemtap (安装时间较长)
版本信息:
Systemtap translator/driver (version 3.3/0.172, rpm 3.3-3.el7)
Copyright (C) 2005-2018 Red Hat, Inc. and others
This is free software; see the source for copying conditions.
tested kernel versions: 2.6.18 ... 4.18-rc0
实现
stap可以使用2种方式实现:
1、stap + 文本,文本中实现函数
2、./stap.sh,脚本中注明脚本解释器
分析
下面脚本实现功能是打印出内核调用do_timer函数的信息。
#!/usr/bin/stap -v
probe kernel.function("do_timer").return {
printf("call do_timer from 0x%x\n", caller_addr());
}
超级用户运行此脚本,打印如下:
[systemtap]$ sudo ./stap.sh
语法检查
Pass 1: parsed user script and 470 library scripts using 239544virt/41312res/3408shr/37952data kb, in 240usr/170sys/671real ms.
分析统计
Pass 2: analyzed script: 1 probe, 7 functions, 5 embeds, 0 globals using 365180virt/168216res/4760shr/163588data kb, in 1900usr/1930sys/6704real ms.
转换为C代码
Pass 3: translated to C into "/tmp/stapeLJkFD/stap_16b421a9b64012d46f93109e9c4710e2_4427_src.c" using 365180virt/168496res/5040shr/163588data kb, in 180usr/70sys/345real ms.
编译为内核ko模块
Pass 4: compiled C into "stap_16b421a9b64012d46f93109e9c4710e2_4427.ko" in 3200usr/1160sys/5194real ms.
加载运行
Pass 5: starting run.
WARNING: Missing unwind data for a module, rerun with 'stap -d kernel'
打印调用信息
call do_timer from 0xffff88003c603f80
call do_timer from 0xffff88003c683ea8
地址信息需要使用addr2line工具进行转换才能看出函数名称。
修改脚本实现dump_stack函数功能。
#!/usr/bin/stap -v
probe kernel.function("do_timer").return {
print_backtrace();
printf("\n");
}
0xffffffff810eb9a0 : do_timer+0x0/0x20 [kernel]
0xffffffff810f2d00 : tick_do_update_jiffies64+0x70/0xd0 [kernel]
0xffffffff819afed0 : __end_rodata+0x3ed0/0x4000 [kernel]
0xffffffff810f3c77 : tick_nohz_idle_exit+0x67/0x150 [kernel] (inexact)
0xffffffff810e7cf1 : cpu_startup_entry+0x171/0x290 [kernel] (inexact)
0xffffffff81674627 : rest_init+0x77/0x80 [kernel] (inexact)
0xffffffff81b0a05a : start_kernel+0x42c/0x44d [kernel] (inexact)
0xffffffff81b09a37 : unknown_bootoption+0x0/0x186 [kernel] (inexact)
0xffffffff81b09120 : early_idt_handler+0x0/0xb7 [kernel] (inexact)
0xffffffff81b095ee : x86_64_start_reservations+0x2a/0x2c [kernel] (inexact)
0xffffffff81b09742 : x86_64_start_kernel+0x152/0x175 [kernel] (inexact)
好处是不用重新编译和重新烧写或者启动内核,方便调试。
实现捕获进行切换的动作信息脚本如下:
#!/usr/bin/stap -v
probe kernel.function("__switch_to") {
if (tast_execname($next_p) == "vim") {
printf("switch from [%s] \t to \t [%s]\n",
task_execname($prev_p),
task_execname($next_p));
}
}
probe end {
printf("\nDONE\n");
}
运行打印错误如下:
Pass 1: parsed user script and 470 library scripts using 239548virt/41316res/3408shr/37956data kb, in 220usr/70sys/287real ms.
WARNING: function __switch_to is blacklisted: keyword at ./stap.sh:3:1
source: probe kernel.function("__switch_to") {
^
semantic error: while resolving probe point: identifier 'kernel' at :3:7
source: probe kernel.function("__switch_to") {
^
semantic error: no match (similar functions: __switch_to, switch_mm, switch_idt, __stop_tx, __switch_to_xtra)
Pass 2: analyzed script: 1 probe, 0 functions, 0 embeds, 0 globals using 276036virt/78768res/4332shr/74444data kb, in 650usr/120sys/778real ms.
Pass 2: analysis failed. [man error::pass2]
难道是我内核版本太低导致没有这个函数吗?没道理啊
ARM环境
版本4.0
Systemtap
下载地址
,下载后解压编译:
cd systemtap-4.0;mkdir build;cd build
../configure --host=arm-linux --prefix=$PWD CC=/home/wangyubo/ifoton/logread-build-tools/OS2000-70/openwrt/staging_dir/toolchain-arm_gcc-imx6ul/bin/arm-linux-gnueabihf-gcc
问题1
configure: error: missing elfutils development headers/libraries (install elfutils-devel, libebl-dev, libdw-dev and/or libebl-devel)
sudo yum install libdw-dev提示没有可用软件包 libdw-dev,手动网上
下载libdw-dev
,下载i386平台包,但格式是deb,安装alien工具转换为rpm:
sudo yum install alien
alien -r libdw-dev_0.175-2_i386.deb 进行转换
安装rmp包:
[yubo.wang@localhost systemtap]$ sudo rpm -ivh libdw-dev-0.175-3.i386.rpm
准备中... ################################# [100%]
file / from install of libdw-dev-0.175-3.i386 conflicts with file from package filesystem-3.2-21.el7.x86_64
file /usr/lib from install of libdw-dev-0.175-3.i386 conflicts with file from package filesystem-3.2-21.el7.x86_64
file /usr/include/elfutils/libdw.h from install of libdw-dev-0.175-3.i386 conflicts with file from package elfutils-devel-0.172-2.el7.x86_64
file /usr/include/elfutils/libdwelf.h from install of libdw-dev-0.175-3.i386 conflicts with file from package elfutils-devel-0.172-2.el7.x86_64
安装成功后还是提示错误:
configure: error: missing elfutils development headers/libraries (install elfutils-devel, libebl-dev, libdw-dev and/or libebl-devel)
为何? 难道要用Ubuntu才行吗?
直接使用命令在x86平台配置也失败:./configure【这里可以make编译试下?在ubuntu 14.04 x86环境安装了libdw-dev后配置后也是下面的打印,make编译通过】
configure: For a private or temporary build of systemtap, we recommend
configure: configuring with a prefix. For example, try
configure: ./configure python='/usr/bin/python2' pyexecdir='${exec_prefix}/lib64/python2.7/site-packages' --prefix=/home/yubo.wang/systemtap-4.0-104354
configure: Running systemtap uninstalled, entirely out of the build tree,
configure: is not supported.
编译出版本信息如下,arm平台待验证。。。
切换版本
还是提示一样的问题,无改善,后续使用ubuntu测试一下,再不行的话就只有手写C代码,自己编译ko文件进行插入监测测试,需要使用到的函数:kprobe, jprobe, jretprobe