Найти исходные файлы со ссылкой на неопределенный символ в общей библиотеке - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть общая библиотека (я полагаю, в формате ELF), созданная из исходного кода C ++. Библиотека построена в режиме отладки.

Учитывая неопределенный символ этой библиотеки, я бы хотел определить исходный файл (-ы) (или объектный файл (-ы)), из которого он получен.

Как это можно сделать? (Я полагаю, что это вполне возможно для отладочной версии библиотеки.)

Рекурсивный grep не является опцией, потому что меня интересуют только исходные файлы, из которых состоит библиотека. Неопределенный символ может исходить из внешнего заголовочного файла, поэтому поиск исходного кода самой библиотеки ничего не найдет.

1 Ответ

0 голосов
/ 06 ноября 2018

Ваша общая библиотека, созданная с отладочной информацией, ссылается на неопределенный внешний переменная, как в примере, который я собираюсь построить:

foo.cpp

 namespace bar {
     extern int undefined;
 };

 int foo()
 {
     return bar::undefined;
 }

Я помещаю неопределенный символ в пространство имен, чтобы получить случай, когда он переименовано в компоновщик, так как вы говорите о C ++.

Компиляция и ссылка с отладочной информацией:

 $ g++ -shared -g -fPIC -o libfoo.so foo.cpp

Вот оно в таблице символов библиотеки, raw:

 $ 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, a.k.a bar::undefined, на который есть ссылка в foo.cpp, который был скомпилирован в build-directory /home/imk/develop/so/scrap.

...