1、获取数据结构成员
比如数据结构如下:
root@jusse ~/develop# cat -n cc_stap_test.c
#include <stdio.h>
typedef struct str {
int len;
char *data;
} str_t;
typedef struct policy {
str_t name;
int id;
} policy_t;
int main(int argc, char *argv[])
{
policy_t policy;
policy_t *p = &policy;
p->id = 111;
p->name.data = "test";
p->name.len = sizeof("test")-1;
printf("p->id: %d, p->name.data: %s, p->name.len: %d\n", p->id, p->name.data, p->name.len);
return 0;
}
root@jusse ~/develop# gcc -Wall -g -o cc_stap_test ./cc_stap_test.c
如果要在第22行设置个statement探测点获取局部变量p中name的data,那怎么写stp呢,这个问题在刚学SystemTap时困扰了我两天,不过后来仔细看官方文档时才知道,最直觉的写法就像下面这个:
probe process("./cc_stap_test").statement("main@./cc_stap_test.c:22")
{
printf("policy name: %s\n", $p->name.data);
}
$p是指针,通过->箭头可以直接访问name,这个没有问题,但name不是指针而是一个结构啊,难道不是像C语言一样用点号来访问它里面的成员吗。这是C语言的思路,可惜是不对的,SystemTap已经把点号用来做字符串连接符了,所以 SystemTap把结构变量或者结构指针变量统一对待,都是通过->来访问结构里面或者结构指针所指结构里面的成员 ,上面例子正确写法如下:
probe process("./cc_stap_test").statement("main@./cc_stap_test.c:22")
{
printf("policy name: %s\n", $p->name->data);
}
2、打印整个数据结构
在调试的时候,有时我们需要输出整个数据结构,看看结构里面变量的值到底是什么。比如上面的例子中我们想打印变量p中所有成员的值,应该是这样:
root@jusse ~/develop# cat cc_stap_test.stp
probe process("./cc_stap_test").statement("main@./cc_stap_test.c:22")
{
printf("$p$: %s", $p$$);
}
root@jusse ~/develop# stap cc_stap_test.stp -c './cc_stap_test'
p->id: 111, p->name.data: test, p->name.len: 4
$p$: {.name={...}, .id=111}, $p$$: {.name={.len=4, .data="test"}, .id=111}
root@jusse ~/develop#
就是在 变量的后面加$, 或者,其中 加$是表示获取结构中基本数据类型的字符串值 ,像上面$p$就只输出id的值,name就省略了;变量后面加功能与加一个$类似,只是它要展开结构里面的结构,上面的输出已经很明显了。
问题:
[root@localhost stap_test]# stap cc_stap_test.stp -c './cc_stap_test'
semantic error: type mismatch (long vs. string) : identifier '$p' at cc_stap_test.stp:3:30
source: printf("policy name: %s\n", $p->name->data);
^
Pass 2: analysis failed. [man error::pass2]
Number of similar error messages suppressed: 1.
Rerun with -v to see them.
原因:
printf("policy name: %s\n", $p->name->data);
这里要打印的是字符串,但$p->name->data后面没有加$符号,所以报type mismatch (long vs. string)这种错误
解决:
$p->name->data$,这样就是打印字符串了,其中 加$是表示获取结构中基本数据类型的字符串值 ,若打印数值则不用加$
3、修改函数变量
还是上面的例子,cc_stap_test.c第18行给id赋了值111,在第20行,我们也可以用SystamTap修改id的值:
root@jusse ~/develop# cat cc_stap_set_var.stp
probe process("./cc_stap_test").statement("main@./cc_stap_test.c:20")
{
$p->id = 222;
printf("$p$: %s, $p$);
}
root@jusse ~/develop# stap -g cc_stap_set_var.stp -c './cc_stap_test'
p->id: 222, p->name.data: test, p->name.len: 4
$p$: {.name={...}, .id=222}, $p$$: {.name={.len=0, .data="test"}, .id=222}
直接赋值即可,只是需要注意的是stap要加-g参数在guru模式下才能修改变量的值。
4、获取结构体数组的值
probe module("md_mod").function("md_open").call
{
printf("-----\n")
printf("%s\n",$gdisk[2]->node->node_id$)
printf("%s\n",@var("gdisk@md.c")[2]->node->disk_id$)
printf("%s\n",@var("gdisk@md.c")[2]->node->disk_major$)
printf("%s\n",@var("gdisk@md.c")[2]->node->disk_minor$)
printf("%s\n",$gdisk[2]$$)
}
引用结构的成员变量:
@var("varname@file.c")->fild
引用数组的元素:
@var("var@file.c")[N]
变量的地址:
&@var("var@file.c")
变量的引用有两种风格:
$varname // 引用变量varname
$var->field // 引用结构的成员变量
$var[N] // 引用数组的元素
&$var // 变量的地址
@var("varname") // 引用变量varname
@var("var@src/file.c") // 引用src/file.c在被编译时的全局变量varname
@var("varname@file.c")->field // 引用结构的成员变量
@var("var@file.c")[N] // 引用数组的元素
&@var("var@file.c") // 变量的地址
$var$ // provide a string that includes the values of basic type values
$var$$ // provide a string that includes all values of nested data types
$$vars // 一个包含所有函数参数、局部变量的字符串
$$locals // 一个包含所有局部变量的字符串
$$params // 一个包含所有函数参数的字符串

本文介绍了如何使用SystemTap脚本获取和修改C程序中数据结构的成员,包括打印整个数据结构、修改函数变量及获取结构体数组的值。通过实例详细解析了SystemTap语法,如使用`->`访问结构成员,以及`$`用于获取基本类型值的字符串表示。

9522

被折叠的 条评论
为什么被折叠?



