gdb 是基本命令,顺序不可颠倒;需确保可执行文件带-g调试符号且未strip,core文件真实存在、非空且权限正确,否则堆栈显示??或地址无法定位源码行。

gdb 加载 core 文件的基本命令怎么写
直接用 gdb ,顺序不能反。GDB 必须看到原始二进制(带调试符号的版本),否则堆栈里全是 ?? 或地址,没法看函数名和行号。
常见错误:用 release 版本的可执行文件去加载 core,结果 bt 一跑全是 (no debugging symbols found);或者 core 文件权限不对(比如被 ulimit -c 0 禁掉,实际没生成)。
实操建议:
- 确认 core 文件真实存在且非空:
ls -lh core*、file core.12345 - 确保调试信息没被 strip:运行
file ./myapp,输出应含with debug_info;若显示stripped,得重新编译加-g - core 文件名可能不是
core:Linux 默认是core.或由/proc/sys/kernel/core_pattern控制,别硬写死core
加载后怎么看崩溃点和完整调用链
输入 bt(即 backtrace)是最直接的方式,但默认只显示顶层几帧。真正有用的是 bt full——它会把每帧的局部变量也打出来,对判断空指针、越界访问特别关键。
注意:如果某帧显示 ??,不是 GDB 坏了,而是那一层没调试符号(比如系统库或第三方 .so 缺 .debug 包)。这时可以补装 libc6-dbg(Ubuntu/Debian)或 glibc-debuginfo(CentOS/RHEL)。
实操建议:
- 先
bt看崩溃位置,再frame切到具体帧,用info registers查寄存器值(比如rdi是空的?那很可能是空指针解引用) - 用
list查看崩溃行附近源码(前提是源文件路径没变,且 GDB 能找到) - 如果
bt卡住或显示不全,试试set backtrace past-main on和set backtrace limit 100
为什么 core 文件里看不到变量值或源码路径
核心就两点:调试符号缺失 + 源码路径变更。GDB 不存储源码,只存路径字符串;程序编译时的绝对路径(比如 /home/user/proj/src/main.cpp)会被记进 ELF 的 DWARF 信息里。运行时若换了机器或目录结构,GDB 就找不到文件。
实操建议:
- 编译时加
-g -O0(调试优先),避免-frecord-gcc-switches或-fdebug-prefix-map导致路径错乱 - 用
readelf -w ./myapp | grep -A2 "DW_AT_comp_dir"查编译时工作目录,然后在 GDB 里用set substitute-path /old/path /new/path修复 - 变量值看不到?检查是否被编译器优化掉了(
-O2以上常见)。加volatile临时标记关键变量,或改用-Og
多线程程序的 core 文件怎么定位具体线程崩溃
Linux 下 core 默认包含所有线程状态,但 bt 只显示当前线程(通常是崩溃线程)。得先用 info threads 列出全部线程,再用 thread 切过去看各自堆栈。
关键信号(如 SIGSEGV)只发给触发线程,所以崩溃线程通常有 Stopped due to signal SIGSEGV 提示。但要注意:有时主线程等在 pthread_join,而 worker 线程已崩,此时 thread apply all bt 比单看主线程更有用。
实操建议:
- 用
thread apply all bt一次性看所有线程堆栈,快速扫一遍哪个线程在可疑函数里(比如malloc、std::vector::at) - 结合
info registers和x/10i $pc(反汇编当前指令)确认是否访问了非法地址(比如0x0、0xfffffffffffff000) - 如果线程名是数字(如
Thread 3 (LWP 12345)),可用thread find 12345快速定位
最常被忽略的一点:core 文件本身不记录崩溃前的内存内容变化,只能反映快照瞬间的状态。如果问题涉及竞态或内存踩踏,光靠单个 core 往往不够,得配合 valgrind 或 AddressSanitizer 复现。另外,容器环境里 /proc/sys/kernel/core_pattern 通常被重定向到主机路径,得确认挂载和权限是否让 core 写进预期位置。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











