如何在函数中使用 bpftrace 探测局部变量

问题描述 投票:0回答:1

我想知道如何使用 bpftrace 工具来探测内核函数中的局部变量,例如:

int fun1(arg0, arg1, arg2)
{     
    ....  
    ret1 = arg0->param1; 
    var1 = xxxx; 
    .... ;
}

bpftrace 可以探测 arg0、arg1 和 arg2 的数据

但是如何探测var1的变量数据。

variables kernel bpftrace
1个回答
0
投票

我只是在看同样的事情,所以为了后代...... Bpftrace 本身还不能做到这一点。

BTF 中对此没有足够的信息,但如果您有调试信息,您可以根据 perf 发现的内容使用 perf 或 bpftrace。如果添加了支持,则可以让 bpftrace 直接使用 DWARF,但目前还没有。
这个答案基于以下评论:https://github.com/bpftrace/bpftrace/issues/1901#issuecomment-881855742

举一个具体的例子,采用任意内核函数(对于模块性能需要

-m module
),我们可以得到用于截断的newattrs.ia_valid(这是我发现的第一个函数):

  1. 使用 perf 显示可能的线,获取可用于此类线的变量。列表行在终端中具有颜色,并且在那里更具可读性,但带有行号的行是可挂钩的。
[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
  1. 如果仅使用 perf:
[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
  1. 从 bpftrace 中,我们需要进一步了解 perf 做了什么,并使用从 regs 中找到的变量来挂钩其调试输出中列出的指令(截断调用本身在另一个 shell 中完成):
[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
© www.soinside.com 2019 - 2024. All rights reserved.