如何在汇编代码中设置断点?能否用GDB调试Linux启动汇编代码?
调试Linux启动汇编代码(header.S)及GDB可行性解答
GDB完全可行,而且是调试Linux内核启动流程(包括header.S这类汇编入口代码)的标准工具,通常和QEMU配合使用,下面是具体的调试步骤和关键操作:
1. 编译带调试信息的内核
内核默认编译会剥离调试符号,必须先开启调试信息配置:
- 执行
make menuconfig,进入Kernel hacking->Compile-time checks and compiler options,勾选Compile the kernel with debug info(对应CONFIG_DEBUG_INFO) - 保存配置后,执行
make -j$(nproc)编译内核,确保生成的vmlinux包含完整调试符号
2. 用QEMU启动内核并开启调试模式
使用以下命令启动QEMU,让它暂停在启动初期并监听调试端口:
qemu-system-x86_64 -kernel arch/x86/boot/bzImage -s -S
-s:默认开启TCP端口1234,供GDB连接-S:启动后立即暂停,不自动执行代码,等待GDB指令
3. 连接GDB并加载调试符号
打开另一个终端,启动GDB并连接QEMU:
gdb vmlinux
- 在GDB中执行
target remote localhost:1234,建立和QEMU的调试连接 - 若
header.S属于boot阶段的setup程序,可额外加载setup的符号文件:file arch/x86/boot/setup.elf
4. 设置断点并开始单步调试
- 定位关键位置:
若知道header.S入口的内存地址,直接用break *0x<入口地址>设置断点;若符号存在,可直接用break Main(针对header.S中的Main函数);要追踪到start_kernel,直接设置break start_kernel - 单步调试指令:
si:单步执行一条汇编指令(会进入函数调用,比如Main函数内部)ni:单步执行一条汇编指令(跳过函数调用,直接执行下一条)
- 查看寄存器、PC及内存状态:
info registers:查看所有寄存器的当前值(x86架构下PC对应rip寄存器)x/10i $rip:显示当前PC附近的10条汇编指令x/16xw 0x<内存地址>:查看指定内存地址开始的16个32位十六进制值display $rip:设置自动显示PC值,每次单步后自动更新display $rax:追踪特定寄存器(比如rax)的变化,替换成你需要关注的寄存器即可
5. 追踪内核解包过程
内核解包完成后会从setup阶段跳转到vmlinux的入口,此时GDB会自动识别新的指令流,若符号加载正常,就能继续追踪到start_kernel的执行;若跳转后符号不匹配,可重新执行file vmlinux确保符号正确加载
关于Visual Studio的补充
VS可以通过WSL配合GDB调试,或者使用VS的GDB插件连接QEMU,但GDB+QEMU是更轻量、原生的Linux内核调试方案,适合专注于启动汇编代码的追踪
内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

