无调试信息二进制中GDB调用命名空间/类内C++函数的正确方法
这不是GDB的bug,属于不同功能依赖的符号数据源不同导致的预期行为。
原因解释
GDB处理C++符号时会用到两类不同的信息源:
- 一类是ELF文件自带的最小符号表:编译时即使不带任何调试参数也会生成,仅存储函数的地址、经过名称修饰的原始符号名,GDB可以对修饰名做demangle得到
ns::test()这类可读名称。info functions、break设置断点、Tab补全这些功能,只需要匹配demangle后的符号名就能工作,所以不带调试信息也能正常使用。 - 另一类是DWARF调试信息:需要编译时加
-ggdb/-g参数才会生成,里面包含了命名空间定义、类结构、函数所属作用域等完整的元信息。call命令执行前需要先解析C++表达式,验证ns是合法命名空间、cl是合法类、test是对应作用域下的成员,这些信息只有调试信息里才有,不带调试信息时GDB无法识别ns、cl的作用域定义,就会报符号不存在的错误。
可用的调用方法
不带调试信息时除了直接调用修饰名,还有两种更易用的方案:
1. 用单引号包裹完整函数名
直接用单引号把demangle后的完整函数名括起来,GDB会跳过作用域解析逻辑,直接匹配符号表中的完整名称,即可调用成功:
(gdb) call (void)'ns::test'() ns::test (gdb) call (void)'cl::test'() cl::test
这个方法不需要额外查询地址或者记忆修饰名,是最便捷的解决方案。
2. 通过函数地址调用
先用info functions拿到对应函数的地址,将地址强制转换为对应类型的函数指针后调用即可:
(gdb) info functions ns::test 0x0000000000001169 ns::test() (gdb) call (void(*)())0x1169() ns::test
内容的提问来源于stack exchange,提问作者Sparkette
相关产品推荐
相关产品推荐

