Your shared library, built with debug info, references an undefined external
variable, like the example I'm just going to build:
foo.cpp
namespace bar {
extern int undefined;
};
int foo()
{
return bar::undefined;
}
I'm putting the undefined symbol in a namespace just to get a case where it's
name-mangled to the linker, since you're talking about C++.
Compile and link, with debug info:
$ g++ -shared -g -fPIC -o libfoo.so foo.cpp
Here it is in the library's symbol table, raw:
$ nm --undefined-only libfoo.so | grep undefined
U _ZN3bar9undefinedE
and demangled:
$ nm -C --undefined-only libfoo.so | grep undefined
U bar::undefined
Now if we dump the debug-info we see this:
$ 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
in which our symbol _ZN3bar9undefinedE is described by entry <2> in the
first (and only) compilation unit that was compiled for libfoo.so. It's
linkage name is given by the record:
<3f> DW_AT_linkage_name: (indirect string, offset: 0x57): _ZN3bar9undefinedE
So, to get the name of the source file(s) in which bar::undefined is
referenced, we want to:-
Extract from the debug info all blocks of lines like:
...Compilation Unit...
...
...
..._ZN3bar9undefinedE...
Then out of them, extract all blocks like:
...DW_TAG_compile_unit...
...
...DW_AT_comp_dir...
Then out of those blocks, print the last two lines. Here is one way - very likely
not the most expert way - of doing it:
$ 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
We get 1 hit (of course, since only one source file was compiled), telling us that _ZN3bar9undefinedE,
a.k.a bar::undefined, is referenced in foo.cpp, which was compiled in build-directory /home/imk/develop/so/scrap.