获取systemtap中目标数组的大小

时间:2015-03-13 14:03:56

标签: arrays linux systemtap

answer on a sister site中,我试图从Linux内核数组unix_socket_table@net/unix/af_unix.c转储信息,该信息定义为:

struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];

目前,我在stp脚本中对数组的大小进行了硬编码:

for (i = 0; i < 512; i++)

我怎么能避免这种情况?该信息(数组的大小)存储在调试信息中。 gdb可以告诉我:

$ gdb --batch --ex 'whatis unix_socket_table' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
type = struct hlist_head [512]
$ gdb --batch --ex 'p sizeof(unix_socket_table)/sizeof(*unix_socket_table)' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
$1 = 512

但是如何在systemtap中完成? AFAICT,systemtap没有sizeof()运算符。

2 个答案:

答案 0 :(得分:5)

如果是类型,可以使用@cast运算符:

size=&@cast(0,"$TYPENAME")[1]

但是,unix_socket_table不是一种类型。因此,计划B,对变量使用symdata(在附近的任何旧内核函数的范围内)。

probe begin /* kernel.function("*@net/unix/af_unix.c") */ {
    println(symdata(& @var("unix_socket_table")))
    exit()
}

结果在这里:

unix_socket_table+0x0/0x1000 [kernel]

第二个十六进制数是符号大小,在脚本处理时从ELF符号表计算,相当于此处的4096数字:

% readelf -s /usr/lib/debug/lib/modules/`uname -r`/vmlinux | grep unix_socket_table
71901: ffffffff82023dc0  4096 OBJECT  GLOBAL DEFAULT   28 unix_socket_table

您可以使用例如:

获取号码
probe begin {
    tokenize(symdata(@var("unix_socket_table@net/unix/af_unix.c")),"/");
    printf("%d\n", strtol(tokenize("",""), 16));
    exit()
}

答案 1 :(得分:3)

非常感谢@fche for pointing me in the right direction。正如他所说,systemtap的{​​{1}}函数可用于检索给定地址(包括大小)的符号信息。因此,我们可以编写自己的symdata()函数来解析它,将大小提取为:

sizeof()

如果我们看一下function sizeof(address:long) { tokenize(symdata(address), "/"); return strtol(tokenize("",""),16); } 函数的定义,我们会发现它本身就是一个symdata()函数,它使用systemtap C函数,它本身调用_stp_snprint_addr()检索数据。这意味着我们也可以直接使用_stp_kallsyms_lookup()定义我们自己的sizeof()

stp_kallsyms_lookup()

(请注意,我们需要function sizeof:long (addr:long) %{ /* pure */ /* pragma:symbols */ STAP_RETVALUE = -1; _stp_kallsyms_lookup(STAP_ARG_addr, (unsigned long*)&(STAP_RETVALUE), NULL, NULL, NULL); %} guru ),因为我们正在使用嵌入式C)。

现在,为了获得数组大小,我们需要数组元素的大小。一种方法可以是使用阵列的2个元素之间的地址偏移。因此,我们可以将-g函数定义为:

array_size()

(其中function array_size(first:long, second:long) { return sizeof(first) / (second - first); } 是上面定义的一个或另一个函数)。

并将其命名为:

sizeof()

这给了我们probe begin { printf("%d\n", array_size( &@var("unix_socket_table@net/unix/af_unix.c")[0], &@var("unix_socket_table@net/unix/af_unix.c")[1])); exit(); } 预期的效果。

对于512,另一种方法可能是使用C sizeof()运算符:

sizeof()

(也需要$ sudo stap -ge ' %{ #include <net/af_unix.h> %} probe begin { printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %} ); exit(); }' 512 )但是然后从内核源代码(头文件)中检索信息,而不是调试信息,所以虽然这对于头文件中定义的内核数组有用,但是这种方法赢了所有阵列的必要工作。