我有一个从C ++源代码构建的共享库(我想是ELF格式)。该库以调试模式构建。
给出该库的未定义符号,我想确定其来源文件(-s)(或目标文件(-s))。
该怎么办? (我想该库的调试版本很有可能。)
递归grep不是一个选项,因为我只对库所组成的源文件感兴趣。未定义的符号可能来自外部头文件,因此使用该库本身的源代码将找不到任何内容。
答案 0 :(得分:0)
使用调试信息构建的共享库引用了未定义的外部 变量,就像我要构建的示例一样:
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...
我们得到1次点击(当然,因为只编译了一个源文件),告诉我们$ 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
,
又称为_ZN3bar9undefinedE
,又称为bar::undefined
,该{@ 1}}是在构建目录foo.cpp
中编译的。