无执行文件仅用调试符号文件,LLDB调试Core Dump的问题
背景
我有一个需要调试的core dump文件,但仅拥有该崩溃程序的调试符号文件。生成可执行文件与调试符号文件的命令如下:
$ gcc -g -O0 -o <exec> main.c $ objcopy --only-keep-debug <exec> <exec>.dbg $ strip --strip-debug --strip-unneeded <exec>
LLDB操作报错与尝试
运行LLDB并以core文件为目标,尝试添加符号文件时触发报错:
$ lldb -c <core-file> (lldb) target symbols add <exec>.dbg error: symbol file '<exec>.dbg' does not match any existing module
随后尝试先将.dbg文件作为模块添加,再添加符号文件,虽然没有报错,但符号并未成功加载——执行bt仅显示1个线程中的1个栈帧,gui模式下也无法查看代码:
$ lldb -c <core-file> (lldb) target modules add <exec>.dbg (lldb) target symbols add <exec>.dbg
疑问
- 几乎找不到关于LLDB“module”的相关信息;
- 不理解为何LLDB除了core文件和调试符号文件外还需要其他信息,core文件包含内存快照,调试符号文件具备解析core内容的所有符号;
- 是否可以仅用调试符号文件、无执行文件调试core文件?若LLDB不行,GDB或其他调试器是否可行?或是我生成调试符号文件的方式有误?
解答
关于LLDB的Module
LLDB里的Module指被调试程序的二进制组件,比如主可执行文件、动态链接库等。每个Module都有唯一标识(UUID、构建ID等),LLDB通过这个标识匹配对应的符号文件。加载core文件时,LLDB会从core中提取崩溃时加载的所有Module的标识信息,只有符号文件的标识与某个Module匹配,才能成功关联。
为何需要额外信息?
core文件的内存快照只记录程序崩溃时的内存状态,但LLDB需要二进制文件的代码段布局、指令结构等信息——这些内容不在core文件中,而是存储在原始可执行文件里。调试符号文件仅负责映射地址到代码行、变量名,没有二进制本身的结构信息,因此LLDB无法仅靠符号文件和core文件完成完整调试。
仅用符号文件调试的可行性及替代方案
LLDB的限制
LLDB无法仅依靠调试符号文件和core文件进行有效调试,必须要有对应的原始可执行文件(哪怕是strip后的版本)。它需要通过可执行文件获取Module的标识和二进制结构,才能关联符号文件。
GDB的情况
GDB在这方面更灵活,可通过指定符号文件和core文件调试,步骤如下:
$ gdb --core=<core-file> (gdb) symbol-file <exec>.dbg
你生成符号文件的方式是标准正确的(objcopy --only-keep-debug是通用的符号分离方法),若GDB仍无法正常解析,需确保符号文件和core文件对应的可执行文件是同一编译产物,未被修改过。
修复LLDB调试的方法
若能找到strip后的可执行文件,加载core时同时指定该可执行文件即可:
$ lldb <exec> -c <core-file>
LLDB会自动识别可执行文件的标识,之后你可以用target symbols add <exec>.dbg加载符号;若符号文件与可执行文件同名且在同一目录,LLDB会自动尝试加载。
内容的提问来源于stack exchange,提问作者Gordiig

