SystemTap的架构

SystemTap用于检查运行的内核的两种方法是 Kprobes和 返回探针。但是理解任何内核的最关键要素是内核的映射,它提供符号信息(比如函数、变量以及它们的地址)。有了内核映射之后,就可以解决任何符号的地址,以及更改探针的行为。

Kprobes从 2.6.9 版本开始就添加到主流的 Linux 内核中,并且为探测内核提供一般性服务。它提供一些不同的服务,但最重要的两种服务是 Kprobe 和Kretprobe。Kprobe特定于架构,它在需要检查的指令的第一个字节中插入一个断点指令。当调用该指令时,将执行针对探针的特定处理函数。执行完成之后,接着执行原始的指令(从断点开始)。

Kretprobes有所不同,它操作调用函数的返回结果。注意,因为一个函数可能有多个返回点,所以听起来事情有些复杂。不过,它实际使用一种称为 trampoline的简单技术。您将向函数条目添加一小段代码,而不是检查函数中的每个返回点。这段代码使用 trampoline地址替换堆栈上的返回地址 —— Kretprobe 地址。当该函数存在时,它没有返回到调用方,而是调用 Kretprobe(执行它的功能),然后从 Kretprobe返回到实际的调用方。

图 1展示了 SystemTap 的基本流程,涉及到 3 个交互实用程序和 5 个阶段。该流程首先从 SystemTap 脚本开始。您使用 stap 实用程序将 stap脚本转换成提供探针行为的内核模块。stap 流程从将脚本转换成解析树开始 (pass 1)。然后使用细化(elaboration)步骤 (pass 2)中关于当前运行的内核的符号信息解析符号。接下来,转换流程将解析树转换成 C源代码 (pass
3) 并使用解析后的信息和 tapset脚本(SystemTap 定义的库,包含有用的功能)。stap 的最后步骤是构造使用本地内核模块构建进程的内核模块 (pass 4)。

 1. SystemTap流程

有了可用的内核模块之后,stap 完成了自己的任务,并将控制权交给其他两个实用程序 SystemTap:staprun和 stapio。这两个实用程序协调工作,负责将模块安装到内核中并将输出发送到 stdout (pass 5)。如果在 shell中按组合键 Ctrl-C 或脚本退出,将执行清除进程,这将导致卸载模块并退出所有相关的实用程序。

SystemTap 的一个有趣特性是缓存脚本转换的能力。如果安装后的脚本没有更改,您可以使用现有的模块,而不是重新构建模块。图 2显示了 user-space 和 kernel-space元素以及基于 stap 的转换流程。

图 2.从 kernel/user-space 角度了解 SystemTap流程

3 Systemtap工作原理

tapsets是一个脚本库,包含了许多tapset,每一个tapset一般为某一内核子系统或特定的功能块预定义了一套探测点、辅助函数或全局变量供用户脚本或其它的tapset引用,它定义的一些数据能够被每一个探测点处理函数或脚本使用,这些数据通常通过使用处理函数语句块(HSB Handler Statement Block)来出口,HSB语句块中的变量就是被出口的数据。tapset一般由该内核子系统的开发者或对子系统非常了解的开发者编写,既使用了脚本语言,也使用了C语言,并且它已经被测试和验证,可以安全使用。tapsets属于Systemtap发行包的一部分。

Systemtap实现了一个脚本转换器/翻译器,当用户执行一个Systemtap脚本时,Systemtap将首先对它进行分析和一些安全检查,如果它引用了Systemtap预定义的脚本库提供的函数,Systemtap也将读取脚本库得到相应的代码,对于一些内核变量或符号的引用,它必须根据内核调试信息来解析到相应的地址。然后,它被转换成C代码,在这个转换中,Systemtap将根据需要增加必要的锁和安全检查代码。探测点之间共享的变量将被转换成恰当的静态声明并有锁保护,每组本地变量被转换到一个合成的调用帧结构中以避免消耗内核的栈空间。关联到探测点的处理函数被封装成一个接口函数,那调用恰当的kprobe接口函数来注册该探测点。

产生的C代码包含了一些对运行时tapset的引用,运行时tapset库提供了许多Systemtap接口函数,如通用的查询表、受限内存管理、启动、关闭、I/O操作以及其它一些函数。生成的C代码编译链接之后生成一个可加载的内核模块。为了快速得到运行结果,Systemtap使用了relayfs,当加载生成的内核模块后,该模块的初始化函数初始化自身,然后调用kprobe接口函数注册脚本中定义的探测点。当内核运行到注册的探测点时,相应的处理函数被调用,用户在处理函数中的输出语句将调用relayfs接口函数输出结果数据,用户在处理函数也可以调用一些内核的性能测量函数。当用户主动停止或脚本设定的条件满足时,模块将调用退出函数卸载已经注册的探测点并做一些清理处理就卸载模块自身。

Systemtap在运行时启动了一个进程,它专门负责通过relayfs读去模块的输出数据并即时地输出给用户。(注:要probe的代码必须有调试信息,可以查看探测点的上下文变量)

 

SystemTap实用实例

监控函数的性能

#show exec time of function(@2) and the tid who execute it
global t, call_time
probe process(@1).function(@2).call
{
t = gettimeofday_ns();
}
probe process(@1).function(@2).return
{
call_time <<< gettimeofday_ns()-t;
}
probe timer.s(1)
{
if(@count(call_time)>0)
{
printf("avg time %d total :%d/n", @avg(call_time), @count(call_time));
delete call_time;
}
else
{
println("no call");
}
}
probe begin
{
println("Ready");
}

该脚本用于测试由参数传递的函数运行时所占用的时间,即每秒打印一次平均执行时间,以及调用次数。通过这样一个脚本可以大概的确定我们要probe的函数的性能以及它相对于线程的使用时间。“<<<”表示数组操作,把上面的function改为statement,可probe行范围。@avg(call_time)计算数组内所有元素和的平均值,count(call_time)计算数组元素个数。

监控所有的系统调用

global syscalllist
probe begin {
printf("System Call Monitoring Started (10 seconds).../n")
}
probe syscall.*
{
syscalllist[pid(), execname()]++
}
probe timer.ms(10000) {
foreach ( [pid, procname] in syscalllist ) {
printf("%s[%d] = %d/n", procname, pid, syscalllist[pid, procname] )
}
exit()
}

统计10s内的所有系统调用及次数。

监控某个程序的所有系统调用

global syscalllist
probe begin {
printf("Syslog Monitoring Started (10 seconds).../n")
}
probe syscall.*
{
if (execname() == @1) {
syscalllist[name]++
}
}
probe timer.ms(10000) {
foreach ( name in syscalllist ) {
printf("%s = %d/n", name, syscalllist[name] )
}
printf("------------------------/n");
}

收集网络包

global recv, xmit

probe begin {
printf("Starting network capture (Ctl-C to end)/n")
}
probe netdev.receive {
recv[dev_name, pid(), execname()] <<< length
}
probe netdev.transmit {
xmit[dev_name, pid(), execname()] <<< length
}
probe end {
printf("/nEnd Capture/n/n")
printf("Iface Process........ PID.. RcvPktCnt XmtPktCnt/n")
foreach ([dev, pid, name] in recv) {
recvcount = @count(recv[dev, pid, name])
xmitcount = @count(xmit[dev, pid, name])
printf( "%5s %-15s %-5d %9d %9d/n", dev, name, pid, recvcount, xmitcount )
}
delete recv
delete xmit
}

count计算某个进程接收和发送的报文数,通过avg可计算收到(发送)的报文平均长度,sum可计算收到(发送)的报文的总长度。该收集的数据与dstat有点相似,但它又能够指出具体的进程使用情况,比dstat要详细些。

监听某个signal:sig_send.stp

probe signal.send{
if (sig_name == "SIGKILL")
printf("%s was send to %s(pid:%d) by %s uid:%d", sig_name, pid_name, sig_pid, execname(),uid())
}
$stap -L signal.send
$sudo stap sig_send.stp

监测某个函数的某个区间执行情况(行),对于行经常出现行地址错误,所以多调整一下用-L单独测试

probe process(@1).statement(@2)
{
num++;
t = gettimeofday_ns();
}
probe process(@1).statement(@3)
{
call_time = gettimeofday_ns()-t;
printf("\n%s exec time:%d", @3,call_time);
}

sudo stap insline.stp "libexec/mysqld" "*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11388" "*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11391"

通过使用-L可以测试某条语句是否是正确的:

sudo stap -L 'process("/usr/local/mysql/libexec/mysqld").function("apply_event")'

sudo stap -L 'process("libexec/mysqld").statement("*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11388")'

参考:

http://www.ibm.com/developerworks/cn/linux/l-systemtap/

http://www.ibm.com/developerworks/cn/linux/l-cn-systemtap3/

systemtap原理及使用的更多相关文章

  1. SystemTap 工作原理

    <systemtap原理及使用> https://www.cnblogs.com/youngerchina/p/5624588.html 这篇帖子前边系统介绍了systemtap的工作原理 ...

  2. Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap

    Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...

  3. Linux下性能测量和调试诊断工具Systemtap

    一.简介 SystemTap是一个诊断Linux系统性能或功能问题的开源软件.它使得对运行时的Linux系统进行诊断调式变得更容易.更简单.有了它,开发者或调试人员不再需要重编译.安装新内核.重启动等 ...

  4. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

  5. Linux内核调试方法【转】

    转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...

  6. 内核调试神器SystemTap — 更多功能与原理(三)

    a linux trace/probe tool. 官网:https://sourceware.org/systemtap/ 用户空间 SystemTap探测用户空间程序需要utrace的支持,3.5 ...

  7. 内核探测工具systemtap简介

    systemtap是内核开发者必须要掌握的一个工具,本文我将简单介绍一下此工具,后续将会有系列文章介绍systemtap的用法. 什么是systemtap 假如现在有这么一个需求:需要获取正在运行的 ...

  8. kprobe原理解析(一)

    kprobe是linux内核的一个重要特性,是一个轻量级的内核调试工具,同时它又是其他一些更高级的内核调试工具(比如perf和systemtap)的“基础设施”,4.0版本的内核中,强大的eBPF特性 ...

  9. 转 -Linux 自检和 SystemTap (强大的内核调试工具)---包含下载地址

    下载: http://www.oschina.net/p/systemtap/ https://sourceware.org/systemtap/ftp/releases/   Linux 自检和 S ...

随机推荐

  1. jQuery(20161108)

    jQuery的引入包必须要在其他引入包的最上方,否则会出错.因为如果在页面加载完成后还未执行jQuery包,那么jQuery的引入包就没用了 如果浏览器报错:Uncaught Error: Boots ...

  2. Git修改提交注释

    修改本地最近一次已提交的注释 git commit --amend 如果已经上传到了github上,因此github的提交和已修改的提交不一样,推送到远程可以用下面命令强制修改 git push or ...

  3. EventBus通信小能手

     1.EventBus简介 EventBus 是由 greenrobot 组织开发的一个 Android 事件发布/订阅轻量级框架,特点:代码简洁,是一种发布订阅设计模式(观察者设计模式). Even ...

  4. Sublime Text 3常用插件

    操作:按下Ctrl+Shift+P调出命令面板 输入install 调出 Install Package 选项并回车,然后在列表中选中要安装的插件. 常用插件: 1---- Bracket Highl ...

  5. 读书笔记 effective c++ Item 41 理解隐式接口和编译期多态

    1. 显示接口和运行时多态 面向对象编程的世界围绕着显式接口和运行时多态.举个例子,考虑下面的类(无意义的类), class Widget { public: Widget(); virtual ~W ...

  6. 重温Javascript(一)

    工作中要用到JavaScript,一组复习笔记. 一些看法 1. 想想JavaScript目前最常用的宿主环境,浏览器或者服务端V8,都是单线程,所以不用过多的考虑并发的问题,如果是协程来实现异步的方 ...

  7. Java基础之面试题

    本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的章节分为上下两篇,第一篇将要讨论面向对象编程和它的特点,关于Java和它的功能 ...

  8. 手机自动化测试:appium源码分析之bootstrap七

    手机自动化测试:appium源码分析之bootstrap七   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.poptest测试 ...

  9. Android实现网络多线程断点续传下载

    本示例介绍在Android平台下通过HTTP协议实现断点续传下载. 我们编写的是Andorid的HTTP协议多线程断点下载应用程序.直接使用单线程下载HTTP文件对我们来说是一件非常简单的事.那么,多 ...

  10. 取消putty右键粘贴功能

    还是非常喜欢putty的.就是右键默认的粘贴功能比较讨人厌.