我想学习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文件的其中一个部分中。然后,我可以使用
objdump
或readelf
等工具检查程序。例如,如果我的程序在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/