c++ - 在共享库中查找引用未定义符号的源文件
问题描述
我有一个从 C++ 源代码构建的共享库(我想是 ELF 格式)。该库以调试模式构建。
给定这个库的未定义符号,我想确定它来自的源文件(-s)(或目标文件(-s))。
怎么做到呢?(我想库的调试版本很有可能。)
递归 grep 不是一个选项,因为我只对库包含的源文件感兴趣。未定义的符号可能来自外部头文件,因此对库本身的源代码进行 greing 将找不到任何内容。
解决方案
您使用调试信息构建的共享库引用了一个未定义的外部变量,例如我将要构建的示例:
foo.cpp
namespace bar {
extern int undefined;
};
int foo()
{
return bar::undefined;
}
我将未定义的符号放在命名空间中只是为了得到一个将其命名为链接器的情况,因为您正在谈论 C++。
使用调试信息编译和链接:
$ g++ -shared -g -fPIC -o libfoo.so foo.cpp
这是在库的符号表中,原始的:
$ nm --undefined-only libfoo.so | grep undefined
U _ZN3bar9undefinedE
并解构:
$ nm -C --undefined-only libfoo.so | grep undefined
U bar::undefined
现在,如果我们转储调试信息,我们会看到:
$ readelf --debug-dump=info libfoo.so
Contents of the .debug_info section:
Compilation Unit @ offset 0x0:
Length: 0x6d (32-bit)
Version: 4
Abbrev Offset: 0x0
Pointer Size: 8
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_producer : (indirect string, offset: 0x0): GNU C++14 7.3.0 -mtune=generic -march=x86-64 -g -fPIC -fstack-protector-strong
<10> DW_AT_language : 4 (C++)
<11> DW_AT_name : (indirect string, offset: 0x8f): foo.cpp
<15> DW_AT_comp_dir : (indirect string, offset: 0x74): /home/imk/develop/so/scrap
<19> DW_AT_low_pc : 0x5ba
<21> DW_AT_high_pc : 0xf
<29> DW_AT_stmt_list : 0x0
<1><2d>: Abbrev Number: 2 (DW_TAG_namespace)
<2e> DW_AT_name : bar
<32> DW_AT_decl_file : 1
<33> DW_AT_decl_line : 1
<34> DW_AT_sibling : <0x48>
<2><38>: Abbrev Number: 3 (DW_TAG_variable)
<39> DW_AT_name : (indirect string, offset: 0x6a): undefined
<3d> DW_AT_decl_file : 1
<3e> DW_AT_decl_line : 2
<3f> DW_AT_linkage_name: (indirect string, offset: 0x57): _ZN3bar9undefinedE
<43> DW_AT_type : <0x48>
<47> DW_AT_external : 1
<47> DW_AT_declaration : 1
<2><47>: Abbrev Number: 0
<1><48>: Abbrev Number: 4 (DW_TAG_base_type)
<49> DW_AT_byte_size : 4
<4a> DW_AT_encoding : 5 (signed)
<4b> DW_AT_name : int
<1><4f>: Abbrev Number: 5 (DW_TAG_subprogram)
<50> DW_AT_external : 1
<50> DW_AT_name : foo
<54> DW_AT_decl_file : 1
<55> DW_AT_decl_line : 5
<56> DW_AT_linkage_name: (indirect string, offset: 0x4f): _Z3foov
<5a> DW_AT_type : <0x48>
<5e> DW_AT_low_pc : 0x5ba
<66> DW_AT_high_pc : 0xf
<6e> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa)
<70> DW_AT_GNU_all_call_sites: 1
<1><70>: Abbrev Number: 0
其中我们的符号由为 .编译的第一个(也是唯一一个)编译单元中_ZN3bar9undefinedE
的条目描述。它的链接名称由记录给出:<2>
libfoo.so
<3f> DW_AT_linkage_name: (indirect string, offset: 0x57): _ZN3bar9undefinedE
因此,要获取引用的源文件的名称bar::undefined
,我们希望:-
从调试信息中提取所有行块,例如:
...Compilation Unit...
...
...
..._ZN3bar9undefinedE...
然后从中提取所有块,例如:
...DW_TAG_compile_unit...
...
...DW_AT_comp_dir...
然后在这些块中,打印最后两行。这是一种方法 - 很可能不是最专业的方法 - 这样做:
$ readelf --debug-dump=info libfoo.so | awk '/Compilation Unit/, /_ZN3bar9undefinedE/' | awk '/DW_TAG_compile_unit/,/DW_AT_comp_dir/' | grep -B1 'DW_AT_comp_dir'
<11> DW_AT_name : (indirect string, offset: 0x8f): foo.cpp
<15> DW_AT_comp_dir : (indirect string, offset: 0x74): /home/imk/develop/so/scrap
我们得到 1 个命中(当然,因为只编译了一个源文件),告诉我们_ZN3bar9undefinedE
akabar::undefined
被引用foo.cpp
,它是在 build-directory 中编译的/home/imk/develop/so/scrap
。
推荐阅读
- node.js - npm install 挂在 loadIdealTree:loadAllDepsIntoIdealTree: sill install loadIdealTree
- express - Redis mocha 测试用例问题
- python-3.x - OSError:[Errno 22] Invalid argument 读取 python 日志配置文件时
- sql - sqlserver 2012 中不允许对系统目录进行临时更新
- node.js - 承诺多方
- java - 在 BlankFragment 上看不到 RecyclerView、CardView
- javascript - 下拉菜单不起作用
- intel - 将英特尔 MKL 双数组与 MKL_Complex16 数组(和 exp)相乘?
- javascript - 如果在页面中找到单词“Cheese”,则更改 windows.location.href 目录的 jQuery 代码
- maven - spring什么时候使用application-dev.properties vs application.properties