Reputation: 41
I want to know how to use bpftrace tool to probe the local variable in a kernel function, like:
int fun1(arg0, arg1, arg2)
{
....
ret1 = arg0->param1;
var1 = xxxx;
.... ;
}
bpftrace can probe the data of arg0, arg1 and arg2
but how to probe the variable data of var1.
Upvotes: 3
Views: 659
Reputation: 350
I was just looking at the same thing, so for posterity... Bpftrace by itself cannot do it yet.
There's just not enough information in BTF for this, but if you have debug informations you can use perf or bpftrace based on what perf found. It could be possible to have bpftrace use DWARF directly if support is added but it's not there yet.
This answer is based on this comment: https://github.com/bpftrace/bpftrace/issues/1901#issuecomment-881855742
To give a concrete example, taking an arbitrary kernel function (for modules perf requires -m module
), we can get newattrs.ia_valid used for truncate like this (that's the first function I found):
[root@c9 ~]# perf probe -L do_truncate
<do_truncate@/usr/src/debug/kernel-5.14.0-284.30.1.el9_2/linux-5.14.0-284.30.1.el9_2.x86_64/fs/open.c:0>
0 int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
loff_t length, unsigned int time_attrs, struct file *filp)
{
3 int ret;
struct iattr newattrs;
/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
if (length < 0)
return -EINVAL;
10 newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | time_attrs;
12 if (filp) {
13 newattrs.ia_file = filp;
14 newattrs.ia_valid |= ATTR_FILE;
}
/* Remove suid, sgid, and file capabilities on truncate too */
18 ret = dentry_needs_remove_privs(dentry);
19 if (ret < 0)
return ret;
21 if (ret)
22 newattrs.ia_valid |= ret | ATTR_FORCE;
24 inode_lock(dentry->d_inode);
/* Note any delegations or leases have already been broken: */
26 ret = notify_change(mnt_userns, dentry, &newattrs, NULL);
27 inode_unlock(dentry->d_inode);
28 return ret;
}
long vfs_truncate(const struct path *path, loff_t length)
[root@c9 ~]# perf probe -V do_truncate:26
Available variables at do_truncate:26
@<do_truncate+109>
struct dentry* dentry
struct iattr newattrs
struct user_namespace* mnt_userns
[root@c9 ~]# > dummy
[root@c9 ~]# perf probe do_truncate:26 newattrs.ia_valid
[root@c9 ~]# perf record -e probe:do_truncate_L26 sh -c '> dummy'
[ perf record: Woken up 1 times to write data ]
perf record: Captured and wrote 0.014 MB perf.data (1 samples) ]
[root@c9 ~]# perf script
sh 48158 [003] 41990.971339: probe:do_truncate_L26: (ffffffffae5c250d) ia_valid=0xa068
[root@c9 ~]# perf probe --dry-run -v do_truncate:26 newattrs.ia_valid
...
Probe point found: do_truncate+109
...
Writing event: p:probe/do_truncate_L26 _text+3941645 ia_valid=+0(%sp):x32
# a 32 bits hex value (x32) at offset 0 above %sp
[root@c9 ~]# bpftrace -e 'kprobe:do_truncate+109 {
printf("Got %x\n", *(int32*)reg("sp"));
}'
Attaching 1 probe...
Got a068
Or dereferencing the struct in bpftrace (thanks BTF! the address is the same because ia_valid is the first value of the struct but I'm looking up newattrs
here in pref instead of newattrs.ia_valid
)
[root@c9 ~]# perf probe --dry-run -v do_truncate:26 newattrs
Writing event: p:probe/do_truncate_L26 _text+3941645 newattrs=+0(%sp):x64
[root@c9 ~]# bpftrace -e 'kprobe:do_truncate+109 {
printf("Got %x\n", ((struct iattr *)reg("sp"))->ia_valid);
}'
Attaching 1 probe...
Got a068
Upvotes: 1