Many thanks to @fche for pointing me in the right direction. As he says, systemtap
's symdata()
function can be used to retrieve symbol information at a given address including the size. So we can write our own sizeof()
function that parses it to extract the size as:
function sizeof(address:long) {
tokenize(symdata(address), "/");
return strtol(tokenize("",""),16);
}
If we look at the definition of that symdata()
function, we see that it is itself a systemtap
function that makes use of the _stp_snprint_addr()
C function, itself calling _stp_kallsyms_lookup()
to retrieve data. That means we can also define our own sizeof()
using stp_kallsyms_lookup()
directly:
function sizeof:long (addr:long) %{ /* pure */ /* pragma:symbols */
STAP_RETVALUE = -1;
_stp_kallsyms_lookup(STAP_ARG_addr, (unsigned long*)&(STAP_RETVALUE), NULL, NULL, NULL);
%}
(note that we need -g
(guru) here as we're using embedded C).
Now, to get the array size, we need the size of the elements of the arrays. One approach can be to use the address offset between 2 elements of the array. So we could define our array_size()
function as:
function array_size(first:long, second:long) {
return sizeof(first) / (second - first);
}
(where sizeof()
is one or the other of the functions defined above).
And call it as:
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();
}
Which gives us 512
as expected.
For sizeof()
, another approach could be to use the C sizeof()
operator:
$ sudo stap -ge '
%{ #include <net/af_unix.h> %}
probe begin {
printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %} );
exit();
}'
512
(also needs -g
) but then the information is retrieved from the kernel source code (header files), not debug information, so while that would work for kernel arrays that are defined in header files, that approach won't necessary work for all arrays.