searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

systemtap使用

2023-06-26 02:57:25
10
0

1. 简介

SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux内核或者应用程序的信息采集。
比如:获取一个函数里面运行时的变量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非常有帮助

2. 何时使用

 
定位(内核)函数位置
查看函数被调用时的调用堆栈、局部变量、参数
查看函数指针变量实际指的是哪个函数
查看代码的执行轨迹(哪些行被执行了)
查看内核或者进程的执行流程
调试内存泄露或者内存重复释放
统计函数调用次数
嵌入探针里面执行代码(比如c代码),可以改变变量
如果是独立的%{%},配合#include头文件,可以写正常的c函数定义与实现,但要被探针调用还要使用systemtap支持的方式
限制:
    参数与返回值long/sting
    支持在探针的位置,插入代码,由于是以3号中断的方式执行,所以没法在探针位置执行跳转的goto/returen/break/continue等
 

3. 原理

 SystemTap的处理流程有5个步骤:解析script文件(parse)、细化(elaborate)、script文件翻译成C语言代码(translate)、编译C语言代码(生成内核模块)(build)、加载内核模块(run)

 

 

4. 安装

 
systemtap-client systemtap-devel systemtap-runtime
内核包:
    kernel-3.10.0-229.el7.x86_64.rpm
    kernel-devel-3.10.0-229.el7.x86_64.rpm
    kernel-debuginfo-common-x86_64-3.10.0-229.el7.x86_64.rpm
    kernel-debuginfo-3.10.0-229.el7.x86_64.rpm
注意内核的rpm -qpi/-qi 编译时间是否一致, 不一致会出现很多问题
 

5. 入门

5.1 资料

安装后,可以通过一下方式获取示例或者帮助
man stap
/usr/share/systemtap/

5.2 示例

 
stap -e 'probe begin{printf("Hello, World"); exit();}'
Hello, World
stap -v my_hello.stp          //打印某个文件的所有函数的调用
probe kernel.function("*@net/core/neighbour.c")
{
    printf("%s\n", ppfunc())
}
//打印某个文件(neighbour.c)中某个函数(neigh_update)支持的探针位置
//目前看探针位置的代码是还未执行,所以要插入查询的代码,应该在对应行号之后。
stap -L 'kernel.statement("neigh_update@net/core/neighbour.c:*")'
//打印某个探针位置对应的可访问变量
stap -L 'kernel.function("neigh_update@net/core/neighbour.c:*"")'
//编译ko,到目的机器执行staprun
stap -p4 -v my_hello.stp -m my_hello
cp ./my_hello.ko /lib/modules/3.10.0-229.el7.x86_64/systemtap/
staprun my_hello
 

5.3 常用参数说明

 
比较常用和有用的参数:
-e SCRIPT               Run given script.
-l PROBE                List matching probes.
-L PROBE                List matching probes and local variables.
-D NM=VAL               emit macro definition into generated C code
-o FILE                 send script output to file, instead of stdout.
-x PID                  sets target() to PID
-p NUM                  执行几个阶段,正常包括5个阶段 parse, elaborate, translate, compile,run
-g                      guru mode如果stp脚本有嵌入c代码的话,需要添加的参数
 

6. 脚本语言

6.1 probe

“probe” <=> “探测”, 是SystemTap进行具体地收集数据的关键字。

 

 
“probe point” 是probe动作的时机,也称探测点。也就是probe程序监视的某事件点,一旦侦测的事件触发了,则probe将从此处插入内核或者用户进程中。
“probe handle” 是当probe插入内核或者用户进程后所做的具体动作。
用法:
    probe probe-point { statement }
探测点语法  PATTERN对应 func[@file] 或者 func@file:linenumber
    kernel.function(PATTERN)
    kernel.function(PATTERN).call
    kernel.function(PATTERN).return
    kernel.function(PATTERN).return.maxactive(VALUE)
    kernel.function(PATTERN).inline
    kernel.function(PATTERN).label(LPATTERN)
    module(MPATTERN).function(PATTERN)
    module(MPATTERN).function(PATTERN).call
    module(MPATTERN).function(PATTERN).return.maxactive(VALUE)
    module(MPATTERN).function(PATTERN).inline
    kernel.statement(PATTERN)
    kernel.statement(ADDRESS).absolute
    module(MPATTERN).statement(PATTERN)
    process(PROCESSPATH).function(PATTERN)
    process(PROCESSPATH).function(PATTERN).call
    process(PROCESSPATH).function(PATTERN).return
    process(PROCESSPATH).function(PATTERN).inline
    process(PROCESSPATH).statement(PATTERN)
示例:
    kernel.function("*init*")
    module("ext3").function("*")
    kernel.statement("*@kernel/time.c:296")
    process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request")
    return探测点可以使用$return获取返回值,示例:固定的让某个函数的返回值为1
        stap -g -e 'probe kernel.function("devmem_is_allowed").return { $return = 1 }'
 

 

6.2 基本语法

 
SystemTap脚本语法比较简单,与C语言类似,只是每一行结尾";"是可选的。主要语句如下:
    if/else、while、for/foreach、break/continue、return、next、delete、try/catch
其中:
    next:主要在probe探测点逻辑处理中使用,调用此语句时,立刻从调用函数中退出。不同于exit()的是,next只是退出当前的调用函数,而此SystemTap并没有终了,但exit()则会终止SystemTap。
变量:
    不需要明确声明变量类型,脚本语言会根据函数参数等自动判断变量是什么类型的。
    局部变量:在声明的probe和block(”{ }“范围内的部分)内有效。
    全局变量:用”global“声明的变量,在此SystemTap的整个动作过程中都有效。全局变量的声明位置没有具体要求。需要注意的是,全局变量默认有锁保护,使用过多会有性能损失,如果用全局变量保存指针,可能出现指针所指的内容被进程修改,在探测点中拿不到真正的数据。
    获取进程中的变量(全局变量、局部变量、参数)直接在变量名前面加$即可(后面会有例子)
注释:
    # ...... : Shell语言风格    
    //...... : C++语言风格    
    /*......*/ : C语言风格
操作符:
    比较运算符、算数运算符基本上与C语言一样,需要特别指出的是:
    (1)、.操作符:连接两个字符串,类似于php;
    (2)、=~和!~:正则匹配和正则不匹配;
函数定义:
    function indent:string (delta:long){
      return _generic_indent(-1, "",  delta)
    }
    function _generic_indent (idx, desc, delta)
    {
      ts = __indent_timestamp ()
      if (! _indent_counters[idx]) _indent_timestamps[idx] = ts
      depth = _generic_indent_depth(idx, delta)
      return sprintf("%6d (%d:%d) %s:%-*s", (ts - _indent_timestamps[idx]), depth, delta, desc, depth, "")
    }  
    function strlen:long(s:string) %{
        STAP_RETURN(strlen(STAP_ARG_s));
    %}
    //这里_generic_indent不用声明long/string, 可能是因为调用的是indent函数,_generic_indent是二次调用?
 
0条评论
作者已关闭评论
f****n
5文章数
0粉丝数
f****n
5 文章 | 0 粉丝
f****n
5文章数
0粉丝数
f****n
5 文章 | 0 粉丝
原创

systemtap使用

2023-06-26 02:57:25
10
0

1. 简介

SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux内核或者应用程序的信息采集。
比如:获取一个函数里面运行时的变量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非常有帮助

2. 何时使用

 
定位(内核)函数位置
查看函数被调用时的调用堆栈、局部变量、参数
查看函数指针变量实际指的是哪个函数
查看代码的执行轨迹(哪些行被执行了)
查看内核或者进程的执行流程
调试内存泄露或者内存重复释放
统计函数调用次数
嵌入探针里面执行代码(比如c代码),可以改变变量
如果是独立的%{%},配合#include头文件,可以写正常的c函数定义与实现,但要被探针调用还要使用systemtap支持的方式
限制:
    参数与返回值long/sting
    支持在探针的位置,插入代码,由于是以3号中断的方式执行,所以没法在探针位置执行跳转的goto/returen/break/continue等
 

3. 原理

 SystemTap的处理流程有5个步骤:解析script文件(parse)、细化(elaborate)、script文件翻译成C语言代码(translate)、编译C语言代码(生成内核模块)(build)、加载内核模块(run)

 

 

4. 安装

 
systemtap-client systemtap-devel systemtap-runtime
内核包:
    kernel-3.10.0-229.el7.x86_64.rpm
    kernel-devel-3.10.0-229.el7.x86_64.rpm
    kernel-debuginfo-common-x86_64-3.10.0-229.el7.x86_64.rpm
    kernel-debuginfo-3.10.0-229.el7.x86_64.rpm
注意内核的rpm -qpi/-qi 编译时间是否一致, 不一致会出现很多问题
 

5. 入门

5.1 资料

安装后,可以通过一下方式获取示例或者帮助
man stap
/usr/share/systemtap/

5.2 示例

 
stap -e 'probe begin{printf("Hello, World"); exit();}'
Hello, World
stap -v my_hello.stp          //打印某个文件的所有函数的调用
probe kernel.function("*@net/core/neighbour.c")
{
    printf("%s\n", ppfunc())
}
//打印某个文件(neighbour.c)中某个函数(neigh_update)支持的探针位置
//目前看探针位置的代码是还未执行,所以要插入查询的代码,应该在对应行号之后。
stap -L 'kernel.statement("neigh_update@net/core/neighbour.c:*")'
//打印某个探针位置对应的可访问变量
stap -L 'kernel.function("neigh_update@net/core/neighbour.c:*"")'
//编译ko,到目的机器执行staprun
stap -p4 -v my_hello.stp -m my_hello
cp ./my_hello.ko /lib/modules/3.10.0-229.el7.x86_64/systemtap/
staprun my_hello
 

5.3 常用参数说明

 
比较常用和有用的参数:
-e SCRIPT               Run given script.
-l PROBE                List matching probes.
-L PROBE                List matching probes and local variables.
-D NM=VAL               emit macro definition into generated C code
-o FILE                 send script output to file, instead of stdout.
-x PID                  sets target() to PID
-p NUM                  执行几个阶段,正常包括5个阶段 parse, elaborate, translate, compile,run
-g                      guru mode如果stp脚本有嵌入c代码的话,需要添加的参数
 

6. 脚本语言

6.1 probe

“probe” <=> “探测”, 是SystemTap进行具体地收集数据的关键字。

 

 
“probe point” 是probe动作的时机,也称探测点。也就是probe程序监视的某事件点,一旦侦测的事件触发了,则probe将从此处插入内核或者用户进程中。
“probe handle” 是当probe插入内核或者用户进程后所做的具体动作。
用法:
    probe probe-point { statement }
探测点语法  PATTERN对应 func[@file] 或者 func@file:linenumber
    kernel.function(PATTERN)
    kernel.function(PATTERN).call
    kernel.function(PATTERN).return
    kernel.function(PATTERN).return.maxactive(VALUE)
    kernel.function(PATTERN).inline
    kernel.function(PATTERN).label(LPATTERN)
    module(MPATTERN).function(PATTERN)
    module(MPATTERN).function(PATTERN).call
    module(MPATTERN).function(PATTERN).return.maxactive(VALUE)
    module(MPATTERN).function(PATTERN).inline
    kernel.statement(PATTERN)
    kernel.statement(ADDRESS).absolute
    module(MPATTERN).statement(PATTERN)
    process(PROCESSPATH).function(PATTERN)
    process(PROCESSPATH).function(PATTERN).call
    process(PROCESSPATH).function(PATTERN).return
    process(PROCESSPATH).function(PATTERN).inline
    process(PROCESSPATH).statement(PATTERN)
示例:
    kernel.function("*init*")
    module("ext3").function("*")
    kernel.statement("*@kernel/time.c:296")
    process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request")
    return探测点可以使用$return获取返回值,示例:固定的让某个函数的返回值为1
        stap -g -e 'probe kernel.function("devmem_is_allowed").return { $return = 1 }'
 

 

6.2 基本语法

 
SystemTap脚本语法比较简单,与C语言类似,只是每一行结尾";"是可选的。主要语句如下:
    if/else、while、for/foreach、break/continue、return、next、delete、try/catch
其中:
    next:主要在probe探测点逻辑处理中使用,调用此语句时,立刻从调用函数中退出。不同于exit()的是,next只是退出当前的调用函数,而此SystemTap并没有终了,但exit()则会终止SystemTap。
变量:
    不需要明确声明变量类型,脚本语言会根据函数参数等自动判断变量是什么类型的。
    局部变量:在声明的probe和block(”{ }“范围内的部分)内有效。
    全局变量:用”global“声明的变量,在此SystemTap的整个动作过程中都有效。全局变量的声明位置没有具体要求。需要注意的是,全局变量默认有锁保护,使用过多会有性能损失,如果用全局变量保存指针,可能出现指针所指的内容被进程修改,在探测点中拿不到真正的数据。
    获取进程中的变量(全局变量、局部变量、参数)直接在变量名前面加$即可(后面会有例子)
注释:
    # ...... : Shell语言风格    
    //...... : C++语言风格    
    /*......*/ : C语言风格
操作符:
    比较运算符、算数运算符基本上与C语言一样,需要特别指出的是:
    (1)、.操作符:连接两个字符串,类似于php;
    (2)、=~和!~:正则匹配和正则不匹配;
函数定义:
    function indent:string (delta:long){
      return _generic_indent(-1, "",  delta)
    }
    function _generic_indent (idx, desc, delta)
    {
      ts = __indent_timestamp ()
      if (! _indent_counters[idx]) _indent_timestamps[idx] = ts
      depth = _generic_indent_depth(idx, delta)
      return sprintf("%6d (%d:%d) %s:%-*s", (ts - _indent_timestamps[idx]), depth, delta, desc, depth, "")
    }  
    function strlen:long(s:string) %{
        STAP_RETURN(strlen(STAP_ARG_s));
    %}
    //这里_generic_indent不用声明long/string, 可能是因为调用的是indent函数,_generic_indent是二次调用?
 
文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0