systemtap

How to retrieve and print the value of local a struct field in Systemtap without specifying line number?


I modified the kernel introducing a new socket option, as well as a new field in the sock struct. As of now, this works:

probe kernel.statement("sock_setsockopt@sock.c:730")
{
    printf("%ul\n", $sk->sk_foo)
}

But as soon as I use regex:

probe kernel.statement("sock_setsockopt@sock.c:*")
{
    printf("%ul\n", $sk->sk_foo)
}

I end up getting this error:

semantic error: not accessible at this address (pc: 0xffffffff81736f75) [man error::dwarf]: identifier '$sk' at sock_analysis.stp:22:9
        dieoffset: 0x9229d6a from /usr/lib/debug/lib/modules/5.4.114+/vmlinux
        function: sock_setsockopt at net/core/sock.c:724:1
        alternative locations: [0xffffffff81736f8d,0xffffffff8173706b], [0xffffffff8173706c,0xffffffff81737c2c]

The issue with the first example is that in the future, the linux source code might change, and so the systemtap script may no longer work.


Solution

  • The solution is to actually use function.return statement and use embedded C, to retrieve the values.

    %{
    #include <net/sock.h>
    #include <linux/net.h>
    %}
    
    function get_sk_value:long (val:long) %{
        struct socket *x = (struct socket *)STAP_ARG_val;
        STAP_RETURN(x->sk->sk_foo);
    %}
    
    
    probe kernel.function("sock_setsockopt").return
    {
        SO_NEW_SOCK_OPTION = 69
        if (@entry($optname) == SO_NEW_SOCK_OPTION)
            sprintf("%d", get_sk_val(@entry($sock)));
    }