backtrace(bt)显示程序崩溃或停住的调用栈,#0为当前执行点;需配合bt full、frame n和info locals查看变量值以精确定位问题,前提是编译含-g且未启用激进优化。

直接看 backtrace 输出就能知道程序在哪一层崩溃或停住,但默认只显示函数名和行号,不带变量值——想定位真实问题,必须配合 full、frame 和 info locals 一起用。
bt 默认输出里,帧编号 0 是当前执行点
执行 bt 后,你会看到类似这样的输出:
#0 process_array (arr=0x0, size=5) at simple_program.c:12 #1 0x00005555555551a9 in main () at simple_program.c:25
其中 #0 是最顶层栈帧,也就是程序当前停住的位置(比如空指针解引用发生在这里);#1 是调用 process_array 的地方,依此类推。注意两点:
-
arr=0x0这种参数显示只在编译时加了-g且未开启激进优化(如-O2)时才可靠 - 如果某帧只显示地址(如
0x00007ffff7a0b000)而没有函数名,说明对应代码没调试信息(常见于系统库或未加-g编译的目标) - 帧编号不是内存地址,是 GDB 自己按调用顺序从 0 开始编的号,切换帧时要用这个编号,不是地址
bt full 才能看到局部变量,但有前提条件
bt full 会为每个栈帧补上参数和局部变量值,比如:
#0 process_array (arr=0x0, size=5) at simple_program.c:12 x = 10 i = 5
但这依赖三个条件同时满足:
- 编译时用了
-g(必须) - 没开高阶优化(
-O0或-Og推荐;-O2可能导致变量被优化掉,显示为<optimized out></optimized>) - 当前帧的变量作用域还有效(比如已 return 出函数,再看它的局部变量就不可靠)
遇到 <optimized out></optimized>,别硬猜,先切到上一帧(frame 1),再用 info locals 看那里是否保留了原始值。
切换栈帧查上下文,frame N 比 bt 更精准
bt 是“快照”,frame N 是“放大镜”。例如你发现 #0 在 printf 内部崩溃,实际问题可能出在 #2 传进来的指针:
-
frame 2切到第三层栈帧(编号从 0 开始) -
info args查它收到的参数值 -
info locals查它内部计算出的关键中间变量 -
print arr[0]直接尝试访问——如果仍报错,说明arr本身无效,问题就定位到更上层了
注意:frame 不改变程序状态,只是让后续的 print、info 命令作用于那个栈帧的上下文。
常见误判:看到 ?? 或地址就以为是系统问题
输出里出现这类内容很常见:
#0 0x00007ffff7a0b000 in ?? () #1 0x00005555555551a9 in main () at simple_program.c:25
这通常不是 GDB 坏了,而是:
- 崩溃点在动态链接库(如 libc)内部,且系统没装对应的
debuginfo包(Ubuntu/Debian 装libc6-dbg,CentOS/RHEL 装glibc-debuginfo) - 你的可执行文件用了
-s(strip)删掉了符号,或者链接时加了--strip-all - 多线程环境下,GDB 暂停时某个线程正运行在无调试信息的代码段
此时别死磕 ??,回到你自己的代码帧(比如 frame 1),检查传给系统函数的参数是否合法——绝大多数 segfault 都源于此。











