当前停在即将执行的那行,list(或 l)默认显示当前行及上下各5行并用箭头标出,info line则精确给出文件、行号及地址。

当前停在哪一行?用 list 和 info line 最直接
程序中断后,第一反应不是猜,而是确认位置。最常用的是 list(简写 l),它默认显示当前行附近 10 行源码(含当前行上下各 5 行),箭头指向即将执行的那行。info line 则更精确:它告诉你当前 PC 指向哪一行、哪个文件、甚至具体到哪条语句的起始地址。
常见误区是只敲一次 l 就以为看到“开头”了——其实它按上次位置续列。如果刚进 gdb 或断点在函数中间,l 可能根本没显示函数入口。这时候补一句 l 1 或 l main 更稳妥。
-
l:从上次位置继续列出 10 行(回车可重复) -
l 1:从源文件第 1 行开始列 -
l main:列出main函数全部代码(如果符号可用) -
info line:输出类似Line 42 of "server.c" starts at address 0x4006a8 <handle_request> and ends at 0x4006b0</handle_request>
怎么知道正在哪个函数里?frame 和 bt 是核心
单靠 list 不足以判断调用上下文——比如你停在一个内联函数或回调里,list 显示的可能是被调用者的代码,但你实际处于上层函数的某次调用中。frame(简写 f)命令会明确告诉你当前栈帧的函数名、参数、源文件和行号;bt(backtrace)则展示完整调用链,从当前函数一路往上到 main 或线程入口。
注意:bt 默认只显示函数名和地址,加 bt full 才会展开每层的局部变量和参数值,但会显著变慢,尤其在深层递归或大结构体场景下慎用。
-
f:打印当前栈帧(含函数名、参数、文件:行号) -
bt:只显示调用栈函数名和地址 -
bt 3:仅显示栈顶 3 层,适合快速定位 -
bt -2:只显示栈底最后 2 层(如main和其直接调用者)
想边看代码边调试?tui 模式比纯命令直观得多
反复敲 l + f + bt 很机械,tui 模式把源码、汇编、寄存器、命令行整合在一个终端窗口里,实时高亮当前执行行。启动方式很简单:gdb -tui ./myapp,或进 gdb 后按 Ctrl+x a 切换。
容易被忽略的是:tui 下滚动源码窗格时,list 命令不再生效——它只作用于命令行模式。另外,某些终端(如 tmux 分屏、Windows Terminal 的旧版本)对 tui 支持不稳,出现乱码或无法刷新时,先试 refresh 命令,不行就退回到纯命令行模式用 l + f 组合。
-
Ctrl+x a:开启/关闭tui模式 -
Ctrl+x 2:在tui中切换源码/汇编/寄存器窗格 -
Ctrl+p/Ctrl+n:在tui源码窗格中上下翻页
为什么有时 list 显示 “No symbol table is loaded”?
这不是操作错误,是编译环节缺失调试信息。GDB 查源码依赖可执行文件里的 .debug_* 段,而 gcc 默认不生成。必须加 -g 编译:gcc -g -o server server.c。验证是否成功:运行 file server,输出里要有 with debug_info 字样。
另一个隐蔽原因是源文件路径变动。比如你在 /home/user/proj 编译,后来把整个目录移到 /tmp/proj,GDB 仍会按原路径找 server.c,导致 list 失败但 frame 仍能显示函数名。此时用 set substitute-path /home/user/proj /tmp/proj 告诉 GDB 路径映射关系。
- 编译必须带
-g,C++ 项目建议用-g3包含宏定义信息 -
file命令是第一道验证关卡 - 路径迁移后,
set substitute-path比重新编译更省事
frame 显示在 foo(),但 list 却只显示汇编;或者 bt 里一堆 ?? 地址。这些信号都在提醒:调试符号不全、优化干扰(-O2 会内联/删函数)、或源码与二进制不匹配。先盯住 file 和 info files 输出,再动手查代码。











