bt 显示函数调用链,#0 是当前执行点而非错误根源;需用 frame 和 list 定位具体代码行,info args/locals 检查参数与局部变量;多线程下用 thread apply all bt 对比锁争用;core dump 时启用 set backtrace past-main 查看完整栈。

用 bt 看清函数调用链,但别只信顶层
程序停住后第一件事不是猜,是执行 bt。它输出的每一行都对应一个栈帧,从 #0(当前执行点)到最底下的 #n(通常是 __libc_start_main 或 main)。但注意:#0 只告诉你“卡在哪”,不等于“错在哪”。真正的问题往往藏在上层调用里——比如 #0 是 malloc 崩溃,实际原因可能是 #2 的指针越界写坏了堆管理结构。
用 frame 和 list 定位具体代码行
光看函数名不够,得确认它到底执行到哪一行、传了什么参数:
-
frame 2切到第 3 层栈帧(编号从 0 开始),再执行list显示源码上下文 - 如果
list报 “No symbol table is loaded”,说明编译没加-g,得重新编译 - 对关键帧执行
info args和info locals,检查参数是否为NULL、局部变量是否异常(如数组长度为负)
多线程下用 thread apply all bt 对比阻塞点
死锁或资源争用时,单看一个线程的 bt 没用,必须横向对比:
-
thread apply all bt一次性打印所有线程的调用栈 - 重点找重复出现的锁调用:
pthread_mutex_lock、std::mutex::lock,记下它们的参数地址(如$rdi寄存器值) - 如果两个线程都卡在
pthread_mutex_lock且$rdi相同,基本可断定在争同一把锁 - 再用
thread <n></n>切过去,执行info registers确认寄存器值,避免因优化导致显示不一致
core dump 场景下,bt 可能不完整,要补 set backtrace past-main
有些崩溃发生在 main 退出后(比如全局对象析构),默认 bt 会截断到 main 就停住:
- 启动 GDB 时先执行
set backtrace past-main on,再bt才能看到完整的销毁链 - 若 core 文件由
ulimit -c生成,确保调试的可执行文件和产生 core 的是同一个版本,否则行号和符号可能错位 - 遇到内联函数(如
std::vector::push_back)出现在栈中,bt full可能比bt多显示一层调用,但别依赖它——内联展开本身就不保证帧存在
bt 输出顺序下结论。


















