GDB分析剥离动态库的Core Dump时符号函数名错误是否正常?
正常回溯信息(本地复现)
#0 0x00007f06ff7e96ad in Numbers::AddOne(int) () from libnums.so #1 0x00007f06ff7e968d in Numbers::AddTwo(int, int) () from libnums.so #2 0x00007f06ff7e9668 in Numbers::AddThree(int, int, int) () from libnums.so #3 0x000055ae3a2a67ec in ?? () #4 0x00007f06feadac87 in __libc_start_main (main=0x55ae3a2a67ba, argc=1, argv=0x7ffd3e8f5eb8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffd3e8f5ea8) at ../csu/libc-start.c:310 #5 0x000055ae3a2a66da in ?? ()
确认二进制已剥离
通过info sharedlibrary验证:
0x00007f06ff7e9560 0x00007f06ff7e96b1 Yes (*) libnums.so
生产环境Core Dump异常表现(恢复符号前)
#0 0x00007f06ff7e96ad in Numbers::SomeFunctionElsewhere() () from libnums.so #1 0x00007f06ff7e968d in Numbers::MultiplyFive() () from libnums.so #2 0x00007f06ff7e9668 in Numbers::DivideByZero() () from libnums.so
注意:所有函数参数类型完全消失,且函数名被错误映射
核心疑问
- 上述现象是否完全正常?还是符号剥离/保存流程存在错误?
- 将
.so与对应.so.debug文件合并能否解决问题? - 该现象是否与
-rdynamic或-fPIC编译选项有关?
当前符号剥离流程(遗留脚本)
objcopy --only-keep-debug $filename $outFolder/$filename.debug strip --strip-debug --strip-unneeded $filename # Default links for debug symbol files already exist for libc* and friends. If you # don't remove them first, you'll get an "Invalid operation" error objcopy --remove-section=.gnu_debuglink $filename objcopy --add-gnu-debuglink=$outFolder/$filename.debug $filename
符号合并使用的命令
eu-unstrip x.so x.so.debug -o x.so
开发环境补充测试情况
成功复现两种矛盾现象:
添加符号文件获取行号,但丢失参数信息:
在.gdbinit中配置:add-symbol-file mylib.so.debug 0xdeadbeef回溯结果:
#0 0x00007f06ff7e96ad in Numbers::AddThree(NO PARAM INFO) () from test.cpp:123使用
eu-unstrip合并符号后,结果完全一致。不添加符号文件,无法获取行号,但参数信息正常:
#0 0x00007f06ff7e96ad in Numbers::AddThree(int, int, int) () from libnums.so
1. 异常现象是否正常?符号流程是否有误?
生产环境中出现函数名错误映射+参数丢失的情况不正常,说明符号剥离/保存流程存在问题,导致调试符号与剥离后的二进制无法正确关联。
开发环境的矛盾现象是因为:单独加载.debug文件时,GDB无法正确关联二进制中的动态符号表信息——参数类型实际来自二进制的动态符号表(未被strip --strip-unneeded移除的部分),而调试符号文件提供行号等信息,但如果关联方式错误,GDB会优先使用调试符号中的函数信息,却无法匹配到动态符号表的参数数据。
2. 合并.so与.so.debug能否解决问题?
如果.so.debug文件是正确生成的,合并操作应该能解决问题,但前提是合并过程正确。你的eu-unstrip命令本身没问题,若合并后仍出现参数丢失,说明原始符号剥离流程可能破坏了动态符号表,或者.so.debug与剥离后的.so不匹配。
3. 与-rdynamic或-fPIC的关系?
-fPIC是编译共享库的必要选项,只要共享库能正常加载,该选项就与符号问题无关。-rdynamic会导出更多符号到动态符号表,C++的函数参数类型是通过名字改编(mangling)存储在动态符号表中的。你开发环境中不加载符号文件时能看到参数,说明编译流程已经导出了足够的符号,该选项不是问题根源。
符号剥离流程修正建议
现有流程中strip --strip-debug --strip-unneeded会移除动态符号表中“不必要”的符号,但可能误删C++函数签名对应的关键信息。建议调整:
- 将
strip --strip-debug --strip-unneeded改为strip --strip-debug,保留完整动态符号表,确保回溯时能解析参数类型。 - 确认
objcopy --only-keep-debug生成的.so.debug与剥离后的.so是同一编译产物,未经过其他修改。
开发环境矛盾现象的解释
直接使用剥离后的.so时,GDB从动态符号表解析经过名字改编的函数名,反推出参数类型;手动用add-symbol-file加载.so.debug时,若基地址不正确或符号无法对应,就会出现“能看到行号但丢失参数”的情况。正确做法是依赖流程中添加的.gnu_debuglink,只要.so.debug放在GDB能找到的路径,GDB会自动关联,同时获取行号和参数信息。
内容的提问来源于stack exchange,提问作者JoeManiaci

