将eBPF模块移植到rCore-Tutorial-v3#
当前,rCore-Tutorial-v3暂未支持eBPF技术,无法运行eBPF程序,但是它的一个分支rCore-Tutorial-2022A已经有了eBPF支持,且将相关代码封装成了三个模块。所以,为了实现eBPF Server,我们将这三个模块移植到了rCore-Tutorial-v3上。移植过程中遇到的主要障碍是rCore-Tutorial-v3 的中断处理流程中使用了较新的Trap::Breakpoint模块,而rCore-Tutorial-2022A用的是Trap::Exception模块,需要在这两个模块之间进行转换。
考虑到用户在大部分情况下都是使用函数名,变量名等符号而不是具体的地址来设置断点,eBPF模块需要有将符号转换为地址的功能。rCore-Tutorial-2022A的eBPF模块预留了这个功能的接口但并没有实现,而我们在rCore-Tutorial-v3的eBPF模块中实现了这个功能。
实现符号转地址功能的第一步是获取完整的符号表。在2.2.1节中我们已经详细描述了如何做到在编译、链接时保留符号信息且操作系统仍能正常运行,在此基础上,我们首先通过内嵌汇编的方式,在内核的数据段中分配了3MiB的连续空间用于存放符号表;其次修改用于构建内核的Makefile脚本,使得Makefile在构建内核后通过调用nm工具从内核镜像中提取内核符号信息并保存为文本文件;最后利用dd命令,将符号文件注入到内核镜像中。
需要注意的是,Rust编译器会对函数名进行名字改编(Name Mangling),这会对eBPF模块的符号解析功能造成障碍。在早期版本的Rust工具链中,可以通过添加rustflags = [“-Zsymbol-mangling-version=v0”] 编译参数关闭名字改编;在近期版本的Rust工具链中这个编译参数不再有效,需要用rustfilt工具将保存有内核符号信息的文本文件中的所有被名字改编的符号还原为原本的符号。
在有了完整且可解析的符号表并成功注入内核后,我们编写了一个工具函数用于在符号表中搜索特定的符号并返回符号对应的地址,从而实现了预留的符号解析接口。