我想学习linux ebpf vm,如果我写了一个ebpf程序test.c,使用了llvm:
clang -O2 -target bpf -o test.o test.c.如何在经典bpf中获得像tcpdump -d这样的ebpf程序集,谢谢。

最佳答案

这取决于您“学习linux ebpf vm”的确切含义。

语言本身

如果您要学习 eBPF的说明,类似于汇编语言,则可以从密件抄送项目中查看the documentation from the kernel(非常密集)或this summarized version of the syntax

虚拟机

如果您喜欢来了解eBPF虚拟机内部的工作原理,则可以查看各种演示文稿(我推荐D. Borkmann的演示文稿),在这里我列出了in this blog post;或者,您可以直接在linux/kernel/bpf(特别是文件 core.c )下的内核源代码中阅读。另外,还有一个simpler userspace implementation可用。

转储eBPF指令

现在,如果您想查看从C编译到eBPF的代码,这里有一些解决方案。

读取目标文件

就我而言,我使用 tc-bpf man page中显示的命令进行编译:

__bcc() {
        clang -O2 -emit-llvm -c $1 -o - | \
        llc -march=bpf -filetype=obj -o "`basename $1 .c`.o"
}
alias bcc=__bcc

该代码被转换为eBPF,并存储在生成的ELF文件的其中一个部分中。然后,我可以使用objdumpreadelf等工具检查程序。例如,如果我的程序在classifier部分中:
$ bcc return_zero.c
$ readelf -x classifier return_zero.o

Hex dump of section 'classifier':
   0x00000000 b7000000 02000000 95000000 00000000 ................

在上面的输出中,显示了两条指令(小尾数-以0x开头的第一个字段是该节内的偏移量)。我们可以对此进行分析以形成说明并获得:
b7 0 0 0000 00000002 // Load 0x02 in register r0
95 0 0 0000 00000000 // Exit and return value in r0

[2019年4月编辑]转储内核中加载的eBPF程序

可以将已加载程序的指令(然后可能附加到可用的BPF Hook 之一)以eBPF汇编指令或机器指令(如果程序已JIT编译)转储。依赖libbpf的bpftool是执行此类操作的必备工具。例如,可以使用以下命令查看当前正在加载的程序,并记录其ID:
# bpftool prog show

然后转储给定ID的程序的指令非常简单:
# bpftool prog dump xlated id <id>
# bpftool prog dump jited  id <id>

分别用于eBPF或JITed(如果有)指令。如有必要,输出也可以格式化为JSON。

进阶工具

根据用于将BPF注入(inject)内核的工具的不同,通常可以转储内核内验证程序的输出,该输出包含大多数以人类友好的方式格式化的指令。

使用bcc set of tools(与上一个命令不直接相关,并且与旧的16位编译器完全不相关),您可以为BPF对象实例获取此by using the relevant flags,而对于tc filter add dev eth0 bpf obj … verbose,则可以使用verbose关键字来完成此操作。

拆装机

前面提到的用户空间实现(uBPF)具有自己的汇编程序和反汇编程序,您可能会对它们感兴趣:它将“人类友好的”指令(add32 r0, r1等)用作输入,并转换为目标文件,反之亦然,分别。

但是可能更有趣的是,LLVM本身支持调试信息以及BPF反汇编程序:到目前为止,它已被合并,其作者(A. Starovoitov)已在netdev邮件中发送了有关它的an email。列表。这意味着在clang/LLVM 4.0+中,您应该能够使用llvm-objdump -S -no-show-raw-insn my_file.o获得格式正确的输出。

关于linux - 如何获得linux ebpf程序集?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39998050/

10-08 22:07
查看更多