$ cat /posts/how-to-debug-linux-kernel-ebpf.txt |=------=[ 如何调试Linux内核中的eBPF子系统 / tr3e ]=------=| 本质上这篇文章等同于“如何调试Linux内核”,毕竟eBPF子系统也是Linux内核的一部分。因此本文所提到的调 试方法也可以作用于Linux内核的其他模块。 --[ 1 - 环境搭建 目前Linux内核调试上,比较方便的方式有两种`QEMU + GDB`和`VMware + GDB`,下面两个小节简要介绍这两种 调试环境的搭建流程。 ----[ 1.1 - QEMU + GDB 在使用qemu之前,通常需要构建一个内核镜像以及文件系统,不过我们可以用buildroot来简化这一流程。 * 构建命令 * ------------------------------------------------------------------------------------------------ git clone https://github.com/buildroot/buildroot cd buildroot make qemu_x86_64_defconfig make menuconfig # System configuration > # [*] Enable root login with password # Kernel > # [*] Linux Kernel > # Kernel version (Custom version) > # (<内核版本>) Kernel version # Target packages > # [*] Show packages that are also provided by busybox # Networking applications # [*] dhcpd # [*] ifupdown scripts # [*] iproute2 # [*] net-tools # [*] netcat # [*] openssh # Filesystem images # [*] ext2/3/4 root filesystem # ext2/3/4 variant (ext4) # make linux-menuconfig # Kernel hacking > # Compile-time checks and compiler options > # [*] Compile the kernel with debug info # [*] Provide GDB scripts for kernel debugging # # Enable a lot of BPF options... # make -j $(nproc) ------------------------------------------------------------------------------------------------ 完成构建后,output/images/目录如下 ├── bzImage ├── rootfs.ext2 ├── rootfs.ext4 -> rootfs.ext2 └── start-qemu.sh 其中start-qemu.sh是buildroot提供的快捷启动脚本。可以根据需要修改脚本: - 调试模式:-s / -S - 端口转发:-net user,hostfwd=tcp::<宿主机端口>-:<虚拟机端口>,如转发内部22端口至宿主机2222:-ne t user,hostfwd=tcp::2222-:22 - 关闭ASLR:-append "... nokaslr" * 调试命令 * ------------------------------------------------------------------------------------------------ [Terminal 1] sh output/images/start-qemu.sh [Terminal 2] gdb -q output/build/linux-<内核版本>/vmlinux (gdb) target remote :1234 ------------------------------------------------------------------------------------------------ ----[ 1.2 - VMware + GDB 这里说的VMware指的是VMware Fusion、VMware Workstation之类的虚拟机软件,其支持在宿主机上对虚拟机进 行调试。 相对于QEMU + GDB的方案,这个方案更加便捷但性能较差。只需要在相关虚拟机的vmx文件中进行如下设置: - debugStub.listen.guest32 = "TRUE" # 用于32位的虚拟机,VMware会监听在8832端口,并启动GDB会话 - debugStub.listen.guest64 = "TRUE" # 用于64位的虚拟机,VMware会监听在8864端口,并启动GDB会话 其他有用的选项: - debugStub.listen.guest32.remote = "TRUE" # 允许远程计算机调试 - debugStub.listen.guest64.remote = "TRUE" # 同上,用于64位的虚拟机 --[ 2 - 调试eBPF 一般情况下,我们要调试某段内置函数时,直接打断点触发即可,如verifier.c的do_check()或arraymap.c的 array_map_update_elem()等等。 但在有些情况下,我们期望直接调试JIT后的eBPF指令可以参照下表。 | eBPF Program Type | Kernel Function Name | |---------------------------------------|------------------------------------------| | | bpf_dispatcher_nop_func | | BPF_PROG_TYPE_SOCKET_FILTER | sk_filter_trim_cap | | BPF_PROG_TYPE_KPROBE | | | BPF_PROG_TYPE_SCHED_CLS | cls_bpf_classify | | BPF_PROG_TYPE_SCHED_ACT | tcf_bpf_act | | BPF_PROG_TYPE_TRACEPOINT | | | BPF_PROG_TYPE_XDP | netif_receive_generic_xdp ... | | BPF_PROG_TYPE_PERF_EVENT | | | BPF_PROG_TYPE_CGROUP_SKB | __cgroup_bpf_run_filter_skb | | BPF_PROG_TYPE_CGROUP_SOCK | __cgroup_bpf_run_filter_sk | | BPF_PROG_TYPE_LWT_IN | run_lwt_bpf | | BPF_PROG_TYPE_LWT_OUT | run_lwt_bpf | | BPF_PROG_TYPE_LWT_XMIT | run_lwt_bpf | | BPF_PROG_TYPE_SOCK_OPS | __cgroup_bpf_run_filter_sock_ops | | BPF_PROG_TYPE_SK_SKB | run_filter | | BPF_PROG_TYPE_CGROUP_DEVICE | __cgroup_bpf_check_dev_permission | | BPF_PROG_TYPE_SK_MSG | | | BPF_PROG_TYPE_RAW_TRACEPOINT | | | BPF_PROG_TYPE_CGROUP_SOCK_ADDR | __cgroup_bpf_run_filter_sock_addr | | BPF_PROG_TYPE_LWT_SEG6LOCAL | input_action_end_bpf | | BPF_PROG_TYPE_LIRC_MODE2 | | | BPF_PROG_TYPE_SK_REUSEPORT | run_bpf_filter | | BPF_PROG_TYPE_FLOW_DISSECTOR | bpf_flow_dissect | | BPF_PROG_TYPE_CGROUP_SYSCTL | __cgroup_bpf_run_filter_sysctl | | BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE | | | BPF_PROG_TYPE_CGROUP_SOCKOPT |`__cgroup_bpf_run_filter_{get,set}sockopt`| | BPF_PROG_TYPE_TRACING | | | BPF_PROG_TYPE_STRUCT_OPS | | | BPF_PROG_TYPE_EXT | | | BPF_PROG_TYPE_LSM | | | BPF_PROG_TYPE_SK_LOOKUP | | | BPF_PROG_TYPE_SYSCALL | | 另外,除了上述提到的使用gdb来调试,有些时候修改eBPF源码增加更多的verbose或者使用BPF_FUNC_trace_p rintk也不失为一种好方法。 --[ 3 - 参考资料 [1] https://ebpf.io/summit-2020-slides/eBPF_Summit_2020-Lightning-Lorenzo_Fontana-Debugging_the_ BPF_Virtual_Machine.pdf [2] https://wiki.osdev.org/VMware [3] https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/