在共享库中查找引用未定义符号的源文件

时间:2018-11-06 11:58:34

标签: c++ ubuntu shared-libraries

我有一个从C ++源代码构建的共享库(我想是ELF格式)。该库以调试模式构建。

给出该库的未定义符号,我想确定其来源文件(-s)(或目标文件(-s))。

该怎么办? (我想该库的调试版本很有可能。)

递归grep不是一个选项,因为我只对库所组成的源文件感兴趣。未定义的符号可能来自外部头文件,因此使用该库本身的源代码将找不到任何内容。

1 个答案:

答案 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中编译的。