崩溃位置需用gdb ./my_service core加载原始带-g二进制文件后执行bt定位#0帧;若无行号则检查file输出是否含debug_info;系统库崩溃时重点分析#1帧的指针参数;多线程需thread apply all bt全面排查。

崩溃位置直接看 bt,但得先加载对的可执行文件
GDB 本身不“知道”崩溃在哪,它只是把 core 文件里保存的寄存器和栈帧,对照你提供的可执行文件(my_service)反向还原调用路径。如果可执行文件没带调试符号(编译时没加 -g),bt 只能显示函数名和地址,看不到源码行号。
- 必须用**原始编译出的二进制文件**加载 core,不能是重新编译过的、strip 过的或不同版本的
- 运行命令是:
gdb ./my_service /tmp/core/core-my_service-12345-1625097600 - 进 GDB 后第一件事就是输:
bt—— 它展示的是崩溃时最顶层的栈帧(#0),通常就是出问题的那一行函数入口 - 如果想看更全的上下文(比如局部变量值),用:
bt full
bt 显示地址但没行号?检查编译是否带 -g
常见现象:bt 输出里只有类似 #1 0x0000000000401a2d in process_request (),没有 at src/server.c:356。这说明调试信息缺失。
- 重新编译时务必加
-g:例如gcc -g -o my_service server.c - 确认文件确实含调试段:
file my_service应输出包含with debug_info - 如果生产环境不能留调试符号,至少保留一份带
-g的副本专用于 core 分析 - 别用
strip my_service—— 它会直接删掉所有调试信息,bt就永远看不到源码行了
崩溃点在系统库(如 __memcpy_ssse3)?重点查上一级调用
当 bt 最顶上是 libc 或其他系统函数(比如 #0 0x00007f8e5a1f4a25 in __memcpy_ssse3 ()),说明你的代码传了非法指针进去,真正的 bug 在它的调用者那里。
- 跳到上一帧看是谁调的:
frame 1,再执行info locals和info args - 特别注意
info args输出的指针值:是不是0x0(空指针)、是不是明显超出范围(比如0x7fff00000000这种高位地址) - 用
print /x $rdi(x86_64)或print /x $rsi查看 memcpy 的源/目标地址寄存器值 - 这种场景下,
bt的 #1 行才是你该修的代码位置
多线程程序崩溃,bt 只显示主线程?用 thread apply all bt
默认 bt 只显示当前线程(通常是触发信号的那个),但真正的问题可能藏在另一个线程里 —— 比如死锁、资源争用、子线程访问已释放内存。
- 先看有哪些线程:
info threads - 列出所有线程的完整调用栈:
thread apply all bt - 如果某线程卡在
pthread_mutex_lock或__lll_lock_wait,配合info mutex(需 glibc 调试包)查谁持有了锁 - 注意线程 ID(GDB 内部编号)和 OS PID 的区别:
thread 2切换到第二个线程,不是 PID=2 的进程
bt 是起点,不是终点。真正耗时间的,往往是判断哪一帧的参数或内存状态异常——而这个判断,依赖你对业务逻辑和内存模型的理解,GDB 只负责把现场如实摊开给你看。











