Linux系统中使用SystemTap调试内核

Linux系统中使用SystemTap调试内核

 
SystemTap 是一种新颖的 Linux 内核诊断工具,提供了一种从运行中的 Linux 内核快速和安全地获取信息的能力。SystemTap 是内核研发人员和系统管理员的福音,因为这使得他们能够通过编写或重用简单的脚本来收集内核的实时数据,而无需再忍受修改源码、编译内核、重启系统的漫长煎熬。本文介绍了 SystemTap 的安装、使用和基本原理,并用一些有趣的例子揭示了 SystemTap 提供的强大能力。

在 SystemTap 出现之前,对于 Linux 程式员或系统管理员而言,调试内核往往是一场噩梦。例如,您怀疑传递给系统调用 read 的参数 fd 出了问题,想把他打印出来,您需要做的是:首先得到一份内核源码,找到 sys_read() 的函数体中插入 printk() 语句,接下来重新编译内核,然后用新的内核重新启动系统。谢天谢地,您总算看到了您想要看到的东西,但是您马上会发现碰到了一个新的麻烦:除非重新启动系统到原来的内核,printk() 会无休止地打印下去。

SystemTap 的目的就是要把人们从这种泥潭中解救出来。SystemTap 提供了一个简单的命令行接口和强大的脚本语言,同时预定义了丰富的脚本库。基于内核中的 kprobe,SystemTap允许您自由地从运行中的内核无害地收集调试信息和性能数据,来用于之后的分析和处理。您能够随时开始或停止这种收集过程,而无需漫长的修改代码、编译内核和重启系统的悲惨循环。SystemTap 使得上面的问题变得简单了,简单得只需要一条命令就能够做到:

stap -e 'probe syscall.read { printf("fd = %d/n",fd) }


SystemTap的功能和Sun的DTrace和IBM的dprobe工具相似。但是和他们不同的是, SystemTap是遵循GPL的开源软件项目。他的出现使得Linux社区也拥有了功能强大而且易于使用的动态内核调试工具。现在,SystemTap 的主要研发成员来自于RedHat、IBM、Intel和Hitachi,其中还包括来自IBM中国研发中央的工程师。

安装SystemTap

在安装SystemTap之前,需要确保系统中已安装了其他两个软件包:

kernel-debuginfo RPM:SystemTap需要通过内核调试信息来定位内核函数和变量的位置。对于通常的发行版,并没有安装kernel-debuginfo RPM,我们能够到发行版的下载站点下载。对于我的ThinkPad上的Fedora Core 6,这个地址是: http://download.fedora.redhat.com/pub/fedora/linux/core/6/i386/debug/

elfutils RPM:SystemTap需要elfutils软件包提供的库函数来分析调试信息。现在的SystemTap需要安装elfutils-0.123以上版本。现在最新的版本是0.124-0.1。假如需要,我们能够从SystemTap的站点下载RPM或源码来升级。下载地址是: ftp://sources.redhat.com/pub/SystemTap/elfutils/i386/

接下来就能够安装SystemTap了,这有通过RPM或源码安装两种方式:

1. 通过RPM安装Fedora Core 6缺省情况下已安装了systemtap。

2.通过源码安装,从SystemTap的FTP站点下载最新的源码。

然后安装如下:

/root > tar -jxf SystemTap-20061104.tar.bz2

/root > cd src

/root/src> ./configure

/root/src> make

/root/src> make install


运行SystemTap。

运行SystemTap首先需要root权限。

运行SystemTap有三种形式:

1. 从文档(通常以.stp作为文档名后缀)中读入并运行脚本:stap [选项] 文档名。

2. 从标准输入中读入并运行脚本: stap [选项]。

3. 运行命令行中的脚本:stap [选项] -e 脚本。

4. 直接运行脚本文档(需要可执行属性并且第一行加上#!/usr/bin/stap):./脚本文档名用"Ctrl C"中止SystemTap的运行。

systemtap的选项还在不断的扩展和更新中,其中最常用的选项包括:

-v -- 打印中间信息;

-p NUM -- 运行完Pass Num后停止(缺省是运行到Pass 5);

-k -- 运行结束后保留临时文档不删除;

-b -- 使用RelayFS文档系统来将数据从内核空间传输到用户空间;

-M -- 仅当使用-b选项时有效,运行结束时不合并每个CPU的单独数据文档;

-o FILE -- 输出到文档,而不是输出到标准输出;

-c CMD -- 启动探测后,运行CMD命令,直到命令结束后退出;

-g -- 采用guru模式,允许脚本中嵌入C语句;



其他更多选项请参看stap的手册。

SystemTap的语法

我们利用一个简单的systemtap脚本来介绍一下SystemTap的语法:

#!/usr/local/bin/stap

global count

function report(stat) {

printf("stat=%d/n", stat)

}

probe kernel.function("sys_read") {

count

}

probe end {

report()

}


探测点(probe):每个systemtap脚本中至少需要定义一个探测点,也就是指定了在内核的什么位置进行探测。探测点名称后面紧跟的一组大括号内定义了每次内核运行到该探测点时需要运行的操作,这些操作完成后再返回探测点,继续下面的指令。这里给出了systemtap现在支持的任何探测点类型。

全局变量(global):用来定义全局变量。单个探测点函数体中使用的局部变量无需预先定义,但是假如一个变量需要在多个探测点函数体中使用,则需要定义为全局变量。

函数(function):用来定义探测点函数体中需要用到的函数。除了能够用脚本语言定义函数以外,还能够用C语言来定义函数,只是这时函数名后面的大括号对需要换成%{ %}。例如,前面的report()函数能够写成:

function report(stat) %{

_stp_printf("stat=%d/n", THIS->stat);

%}


SystemTap的例子

了解了SystemTap的基本用法,下面让我们来看几个有趣的例子。统计当前系统中调用最多的前10个系统调用,在进行性能分析的时候,我们常常需要知道那些函数调用次数最多,才能有的放矢地展开分析。下面这个简单的例子能够打印出在过去的5秒钟里调用次数最多的那些系统调用。

#!/usr/bin/env stap

#

# display the top 10 syscalls called in last 5 seconds

#

global syscalls

function print_top () {

cnt=0

log ("SYSCALL/t/t/t/tCOUNT")

foreach ([name] in syscalls-) {

printf("%-20s/t/t]/n",name, syscalls[name])

if (cnt == 10)

break

}

printf("--------------------------------------/n")

delete syscalls

}

probe syscall.* {

syscalls[probefunc()]

}

probe timer.ms(5000) {

print_top ()

}


他的输出结果一目了然:




看看是谁在偷偷动我的文档

有时候,我们假如中了恶意的病毒软件,会发现某些文档莫名其妙的被修改,下面这个例子能够帮您监控谁在修改您的文档。

#!/usr/bin/env stap

#

# monitor who is messing my file of secrets

#

probe generic.fop.open {

if(filename == "secrets")

printf("%s is opening my file: %s/n", execname(), filename)

}


我们运行这个脚本,在另外一个窗口做一些操作,来看看他的输出结果:




打印ANSI字符串



SystemTap不但仅是个简单的调试工具,强大的脚本语言能力让他同样能做一些有趣的事情,下面这个例子就能够对输出的字符进行美化:

#!/usr/bin/env stap

#

# print colorful ANSI strings

#

probe begin {

printf("a // b |");

for (c = 40; c < 48; c )

printf(" %d ", c);

printf("/12");

for (l = 0; l < 71; l )

printf("-");

printf("/12");

for (r = 30; r < 38; r )

for (t = 0; t < 2; t ) {

printf("%d |", r);

for (c = 40; c < 48; c )

printf("/033[%d;%d%s %s /033[0;0m",

r, c, !t ? "m" : ";1m", !t ? "Normal" : "Bold ");

printf("/12");

}

exit();

}


来看看他的输出:




SystemTap的基本原理




现在,大家已熟悉了SystemTap的基本用法。在结束之前,让我们再来了解一下SystemTap的基本原理和工作流程以加深理解。

能够看出,SystemTap运行的过程依次分为五个阶段,通常称为Pass 1 - Pass 5。就像前面介绍用法的时候提到的,在命令行中加上-p NUM选项能够使得SystemTap在运行完Pass NUM之后停止,而不是运行到Pass 5。这允许您分析SystemTap在每一个阶段的输出,对于调试脚本尤其有用。

下面来介绍每一个阶段的主要功能:

Pass 1 - parse:这个阶段主要是检查输入脚本是否存在语法错误,例如大括号是否匹配,变量定义是否规范等。

Pass 2 - elaborate:这个阶段主要是对输入脚本中定义的探测点或用到的函数展开,不但需要综合SystemTap的预定义脚本库,还需要分析内核或内核模块的调试信息。

Pass 3 - translate: 在这个阶段,将展开后的脚本转换成C文档。前三个阶段的功能类似于编译器,将.stp文档编译成为完整的.c文档,因此又被合起来称为转换器(translator)。

Pass 4 - build:在这个阶段,将C源文档编译成内核模块,在这过程中还会用到SystemTap的运行时库函数。

Pass 5 - run:这个阶段,将编译好的内核模块插入内核,开始进行数据收集和传输。

小结

SystemTap是个全新的工具,但已表现出了强大的功能和广泛的适用性。SystemTap使得动态收集Linux内核信息和性能数据变得轻而易举,这就使人能够从繁琐的数据采集中解放出来,而专注于数据的处理和分析,这无疑是内核研发人员和系统管理人员的福音。随着越来越多用户的体验,越来越多的bug会被报告和修正,越来越多的新功能会被添加,SystemTap也会变得越来越稳定和完善。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值