非常感谢@fche 为我指明了正确的方向。正如他所说,systemtap
的symdata()
函数可用于在给定地址检索符号信息,包括大小。所以我们可以编写自己的sizeof()
函数来解析它以提取大小为:
function sizeof(address:long) {
tokenize(symdata(address), "/");
return strtol(tokenize("",""),16);
}
如果我们查看该symdata()
函数的定义,我们会发现它本身就是一个systemtap
使用_stp_snprint_addr()
C 函数的函数,它本身调用_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);
%}
(请注意,我们需要-g
( guru ),因为我们使用的是嵌入式 C)。
现在,要获得数组大小,我们需要数组元素的大小。一种方法是使用数组的 2 个元素之间的地址偏移量。所以我们可以将我们的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
预期的结果。
对于sizeof()
,另一种方法是使用 Csizeof()
运算符:
$ sudo stap -ge '
%{ #include <net/af_unix.h> %}
probe begin {
printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %} );
exit();
}'
512
(也需要-g
)但随后信息是从内核源代码(头文件)中检索的,而不是调试信息,因此虽然这适用于在头文件中定义的内核数组,但该方法不一定适用于所有数组。