必须用 gdb -tui 启动才能启用源码+汇编双视图,Ctrl+x 2 切三栏布局;-tui 依赖 ncurses,缺失时静默退化;info line 是桥接源码与汇编的唯一可靠命令,用于验证调试信息映射是否有效。

gdb 启动时就启用源码+汇编双视图
必须用 -tui 模式启动,否则默认是纯命令行界面,layout asm 或 layout src 无法生效。直接运行 gdb -tui ./a.out,进入后立刻按 Ctrl+x 然后按 2(即 Ctrl+x 2),就能切到「源码 + 汇编 + 寄存器」三栏布局。
注意:-tui 模式依赖终端支持 ncurses,某些精简环境(如容器内、最小化 Alpine)可能没装 ncurses-libs,会静默退回到普通模式——此时 layout 命令报错或无响应,不是你操作错了,是底层缺失。
disassemble 和 list 不能自动联动,得靠 info line 定位
单独执行 disassemble main 只显示汇编;list main 只显示源码。二者之间没有视觉锚点,除非你知道某条汇编对应哪一行源码。
真正能桥接两者的命令是 info line:
-
info line 15→ 显示第 15 行源码在内存中的起始/结束地址(比如0x401120 <main></main>) -
info line main→ 显示整个函数的源码范围对应的地址区间 - 拿到地址后,再用
x/10i 0x401120查看该地址附近的汇编指令
这个过程手动但可靠。很多教程跳过这步,直接说“layout asm 就能看到”,其实前提是程序已停在某行、且该行有调试信息映射——而 info line 是验证映射是否存在的唯一方式。
源码和汇编对不齐?八成是编译没带 -g 或优化干扰
常见现象:断点打在 list 显示的第 8 行,step 后却停在第 12 行;或者 disassemble 输出里根本看不到对应源码行的注释。
原因很集中:
- 编译时没加
-g:用readelf -S ./a.out | grep debug确认有没有.debug_*节区 - 用了
-O2或更高优化:GCC 会重排、内联、删空行,导致行号映射失效;调试阶段务必用-O0 -g - 源文件路径变了:GDB 默认在编译目录找源码,如果移动了文件,要用
directory /path/to/src手动追加搜索路径
想实时对照,别只盯 layout,试试 tui reg 和 stepi
layout reg 会把寄存器也拉进视图,配合 stepi(单步一条汇编指令)和 nexti(跳过 call 指令),你能清楚看到每条指令执行前后 %rax、%rip 的变化,同时源码窗口自动高亮当前逻辑行(只要映射有效)。
这时候要注意:stepi 不关心 C 语句边界,它只数 CPU 指令;而 next 是按源码行走的——两者混用容易误判执行流。真要对照,先 stepi 几步确认当前 %rip 指向哪条汇编,再用 info line *$rip 反查对应源码行,比凭感觉猜稳得多。
最易被忽略的一点:layout 视图里的源码行号是“逻辑行号”,不是文件物理行号。预处理宏展开、空行合并都会让它和原始 .c 文件行数不一致——所以别拿编辑器里 Ctrl+G 跳转的行号去硬对 gdb 的 list 输出。


















