在某些情况下,我们需要分析核心的过程,尽管通过 BPF 该技术可以显示函数传入的参数和返回结果,但最好直接调试过程 GDB 直接进行单步调试。本文采用的编译方法如下,在一台上 16 核 CentOS 7.7 基于内核源代码的编译(主要考虑编译效率) VirtualBox 的 Ubuntu 20.04 在系统中,使用 Qemu GDB 单步调试,网上查看了很多文章,最后单步跟踪,无法在断点停止,多次尝试查询文档,最终发现需要在核启动参数上添加 nokaslr ,本文总结了整个施工过程。
嵌入式高级教程分类整理,看起来很方便。因为内容多,这里截取一些图片。
嵌入式高级教程分类整理,看起来很方便。因为内容多,这里截取一些图片。
需要的朋友可以通过私信内核获得。
Linux 内核编译
运行编译内核和文件制作系统 CentOS 7.7 的机器上。从国内清华大学下载源代码:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/, 此处选择 linux-4.19.172.tar.gz 版本。详细的编译步骤如下:
$ sudo yum group install "Development Tools"$ yum install ncurses-devel bison flex elfutils-libelf-devel openssl-devel$ wget http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.19.172.tar.gz$ tar xzvf linux-4.19.172.tar.gz$ cd linux-4.19.172/$ make menuconfig
在内核编译选项中,开启如下 “Compile the kernel with debug info”, 4.19.172 默认选择中默认:
Kernel hacking —> Compile-time checks and compiler options —>[ ]Compile the kernel with debug info
上述配置完成后,将在当前目录中生成 .config 文件,我们可以用 grep 进行验证:
# grep CONFIG_DEBUG_INFO .configCONFIG_DEBUG_INFO=y然后我们编译内核:
$ nproc # 查看当前的系统核数$ make -j 12 # 或者采用 make bzImage 进行编译, -j N,表示使用多少核并行编译# 在未压缩的核文件中 gdb 需要加载读取 symbol 符号信息,因为包含调试信息,所以比较大$ ls -hl vmlinux-rwxr-xr-x 1 root root 449M Feb 3 14:46 vmlinux# 压缩后的镜像文件$ ls -hl ./arch/x86_64/boot/bzImagelrwxrwxrwx 1 root root 22 Feb 3 14:47 ./arch/x86_64/boot/bzImage -> ../../x86/boot/bzImage$ ls -hl ./arch/x86/boot/bzImage-rw-r--r-- 1 root root 7.6M Feb 3 14:47 ./arch/x86/boot/bzImage启动内存文件系统制作
# 首先安装静态依赖,否则会有报错,参见后续排错章节$ yum install -y glibc-static.x86_64 -y$ wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2$ tar -xvf busybox-1.32.1.tar.bz2$ cd busybox-1.32.1/$ make menuconfig# 相关文件将在安装完成后生成 _install 目录下$ make && make install$ cd _install$ mkdir proc$ mkdir sys$ touch init# init 内容见后续章节,内核启动的初始程序$ vim init# 必须设置可执行文件$ chmod x init$ find . | cpio -o --format=newc > ./rootfs.imgcpio: File ./rootfs.img grew, 2758144 new bytes not copied10777 blocks$ ls -hl rootfs.img-rw-r--r-- 1 root root 5.3M Feb 2 11:23 rootfs.img其中上述的 init 文件内容如下,打印启动日志和系统的整个启动过程需要时间:
错误排查
编译过程中出现以下错误:
/bin/ld: cannot find -lcrypt/bin/ld: cannot find -lm/bin/ld: cannot find -lresolv/bin/ld: cannot find -lrtcollect2: error: ld returned 1 exit statusNote: if build needs additional libraries, put them in CONFIG_EXTRA_LDLIBS.Example: CONFIG_EXTRA_LDLIBS="pthread dl tirpc audit pam"错误的原因是我们依赖静态编译的底层库没有安装,如果你不知道这些库是什么 rpm 如果安装包提供,可以通过 yum provides 检查命令,然后安装相关依赖包进行重新编译。
$ yum provides */libm.a// ...glibc-static-2.17-317.el7.x86_64 : C library static libraries for -static linking.Repo : baseMatched from:Filename : /usr/lib64/libm.a
3. Qemu 启动内核
准备好以上步骤后,我们需要调试 Ubuntu 20.04 安装在系统中 Qemu 其中调测工具 Ubuntu 系统使用 VirtualBox 安装。
$ apt install qemu qemu-utils qemu-kvm virt-manager libvirt-daemon-system libvirt-clients bridge-utils
编译上述内容 vmlinux、bzImage、rootfs.img 我们目前正在复制编译的源码 Unbuntu 机器中。
拷贝 Linux 主要是编译源代码 gdb 在调试过程中检查源代码 vmlinux 和 linux 在本例中,源代码在同一目录中 vmlinux 位于 linux-4.19.172 源目录中。
$ qemu-system-x86_64 -kernel ./bzImage -initrd ./rootfs.img -append "nokaslr console=ttyS0" -s -S -nographic使用上述命令启动调试,启动后将停止在界面上,等待远程 gdb 调试后再使用 GDB 在调试前,可以使用以下命令进程来测试内核启动是否正常。
nokaslr
必须添加参数,以防止内核起始地址随机化,这将导致 gdb 断点不能命中;参数说明可见这里[2]。-s :监听在 gdb 1234 端口;-S :说明启动后挂起,等待 gdb 连接;-nographic:不启动图形界面,调试信息输出到终端和参数 console=ttyS0 组合使用;4. GDB 调试
在使用 qemu-system-x86_64 命令启动内核后,进入我们从编译机上复制的内核 Linux 在核源代码目录中,我们将在另一个终端启动 gdb 命令:
我们可以通过 eclipse-cdt 调试可视化项目。
”File“ -> “New” -> “Project” ,然后选择 ”Makefile Project with Existing Code“ 根据导入代码进行选项。
在 “Run” -> “Debug Configurations” 在选项中选项 ”C/C A