2011-12-24 2 views
28

glibc предоставляет backtrace() и backtrace_symbols(), чтобы получить трассировку стека запущенной программы. Но для этого программа должна быть построена с флагом -rdynamic линкера.gcc debug symbols (-g flag) vs linking -rdynamic option

В чем разница между -g флагом, переданным gcc vs linker's -rdynamic флагом? Для примера кода я действительно прочитал, чтобы сравнить выходы. -rdynamic, похоже, дает больше информации под Symbol table '.dynsym' Но я не совсем уверен, что это за информация.

Даже если I strip программа, построенная с использованием -rdynamic, backtrace_symbols() продолжает работать.

Когда strip удаляет все символы из двоичного кода, почему он оставляет все, что было добавлено флагом -rdynamic?

Edit: Последующий вопросы, основанные на ответ Мэта ниже ..

Для того же образца кода вы взяли это различие я вижу -g & -rdynamic

без опции ..

Symbol table '.dynsym' contains 4 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

    Symbol table '.symtab' contains 70 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 
     2: 000000000040021c  0 SECTION LOCAL DEFAULT 2 

с -g есть больше разделов, больше записей в .symtab таблица, но .dynsym остается такой же ..

 [26] .debug_aranges PROGBITS   0000000000000000 0000095c 
      0000000000000030 0000000000000000   0  0  1 
     [27] .debug_pubnames PROGBITS   0000000000000000 0000098c 
      0000000000000023 0000000000000000   0  0  1 
     [28] .debug_info  PROGBITS   0000000000000000 000009af 
      00000000000000a9 0000000000000000   0  0  1 
     [29] .debug_abbrev  PROGBITS   0000000000000000 00000a58 
      0000000000000047 0000000000000000   0  0  1 
     [30] .debug_line  PROGBITS   0000000000000000 00000a9f 
      0000000000000038 0000000000000000   0  0  1 
     [31] .debug_frame  PROGBITS   0000000000000000 00000ad8 
      0000000000000058 0000000000000000   0  0  8 
     [32] .debug_loc  PROGBITS   0000000000000000 00000b30 
      0000000000000098 0000000000000000   0  0  1 

    Symbol table '.dynsym' contains 4 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

    Symbol table '.symtab' contains 77 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 

с -rdynamic никаких дополнительными разделы отладки, .symtab запись не 70 (так же, как ваниль Gcc вызова), но больше .dynsym записей ..

Symbol table '.dynsym' contains 19 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 218 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
     2: 00000000005008e8  0 OBJECT GLOBAL DEFAULT ABS _DYNAMIC 
     3: 0000000000400750 57 FUNC GLOBAL DEFAULT 12 __libc_csu_fini 
     4: 00000000004005e0  0 FUNC GLOBAL DEFAULT 10 _init 
     5: 0000000000400620  0 FUNC GLOBAL DEFAULT 12 _start 
     6: 00000000004006f0 86 FUNC GLOBAL DEFAULT 12 __libc_csu_init 
     7: 0000000000500ab8  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
     8: 00000000004006de 16 FUNC GLOBAL DEFAULT 12 main 
     9: 0000000000500aa0  0 NOTYPE WEAK DEFAULT 23 data_start 
     10: 00000000004007c8  0 FUNC GLOBAL DEFAULT 13 _fini 
     11: 00000000004006d8  6 FUNC GLOBAL DEFAULT 12 foo 
     12: 0000000000500ab8  0 NOTYPE GLOBAL DEFAULT ABS _edata 
     13: 0000000000500a80  0 OBJECT GLOBAL DEFAULT ABS _GLOBAL_OFFSET_TABLE_ 
     14: 0000000000500ac0  0 NOTYPE GLOBAL DEFAULT ABS _end 
     15: 00000000004007d8  4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used 
     16: 0000000000500aa0  0 NOTYPE GLOBAL DEFAULT 23 __data_start 
     17: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
     18: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__  

    Symbol table '.symtab' contains 70 entries: 
     Num: Value   Size Type Bind Vis  Ndx Name 
     0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000400200  0 SECTION LOCAL DEFAULT 1 
     2: 000000000040021c  0 SECTION LOCAL DEFAULT 2 

Теперь эти вопросы у меня есть ..

  1. В gdb вы можете сделать bt, чтобы получить bactrace. Если это работает только с -g, зачем нам -rdynamic для работы backtrace_symbols?

  2. Сравнивая дополнения .symtab с -g & дополнений .dynsym с -rdynamic они не точно такой же .. Предоставляет ли либо один лучше отладочной по сравнению с другими? FWIW, размер производимого продукта выглядит следующим образом: с -g> с -rdynamic> без опции

  3. Что такое использование .dynsym? Это все символы, экспортируемые этим двоичным кодом? В этом случае почему foo входит в .dynsym, потому что мы не компилируем код как библиотеку.

  4. Если я свяжу свой код с использованием всех статических библиотек, то для работы backtrace_symbols -rdynamic не требуется?

+1

Так получилось, что трассировку, к сожалению, не использует символы отладки [если имеется], как и большинство других инструментов, в том числе БГД, Valgrind и т.д. –

ответ

39

Согласно документации:

Это указывает компоновщик добавить все символы, а не только те, используемые для динамической таблицы символов.

Это не символы отладки, они являются символами динамического компоновщика. Они не удаляются strip, так как это может (в большинстве случаев) разорвать исполняемый файл - они используются компоновщиком времени выполнения для выполнения заключительной стадии ссылки вашего исполняемого файла.

Пример:

$ cat t.c 
void foo() {} 
int main() { foo(); return 0; } 

компилировать и компоновать без -rdynamic (и никаких оптимизаций, очевидно)

$ gcc -O0 -o t t.c 
$ readelf -s t 

Symbol table '.dynsym' contains 3 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 

Symbol table '.symtab' contains 50 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000400270  0 SECTION LOCAL DEFAULT 1 
.... 
    27: 0000000000000000  0 FILE LOCAL DEFAULT ABS t.c 
    28: 0000000000600e14  0 NOTYPE LOCAL DEFAULT 18 __init_array_end 
    29: 0000000000600e40  0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 

Так исполняемый файл имеет .symtab со всем. Но обратите внимание, что .dynsym не упоминает foo - у него есть простые предметы. Для работы недостаточно информации для backtrace_symbols. Он опирается на информацию, присутствующую в этом разделе, на соответствие кодовым адресам с именами функций.

Теперь компилировать с -rdynamic:

$ gcc -O0 -o t t.c -rdynamic 
$ readelf -s t 

Symbol table '.dynsym' contains 17 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
    3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
    4: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS _edata 
    5: 0000000000601008  0 NOTYPE GLOBAL DEFAULT 24 __data_start 
    6: 0000000000400734  6 FUNC GLOBAL DEFAULT 13 foo 
    7: 0000000000601028  0 NOTYPE GLOBAL DEFAULT ABS _end 
    8: 0000000000601008  0 NOTYPE WEAK DEFAULT 24 data_start 
    9: 0000000000400838  4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 
    10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 
    11: 0000000000400650  0 FUNC GLOBAL DEFAULT 13 _start 
    12: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
    13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 
    14: 0000000000400618  0 FUNC GLOBAL DEFAULT 11 _init 
    15: 00000000004007e0  2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 
    16: 0000000000400828  0 FUNC GLOBAL DEFAULT 14 _fini 

Symbol table '.symtab' contains 50 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000400270  0 SECTION LOCAL DEFAULT 1 
.... 
    27: 0000000000000000  0 FILE LOCAL DEFAULT ABS t.c 
    28: 0000000000600e14  0 NOTYPE LOCAL DEFAULT 18 __init_array_end 
    29: 0000000000600e40  0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 

То же самое для символов в .symtab, но теперь foo имеет символ в секции динамического символа (и куча других символов появляются там сейчас тоже). Это делает работу backtrace_symbols - теперь у нее достаточно информации (в большинстве случаев) для наложения кодовых адресов с именами функций.

Газа, что:

$ strip --strip-all t 
$ readelf -s t 

Symbol table '.dynsym' contains 17 entries: 
    Num: Value   Size Type Bind Vis  Ndx Name 
    0: 0000000000000000  0 NOTYPE LOCAL DEFAULT UND 
    1: 0000000000000000  0 FUNC GLOBAL DEFAULT UND [email protected]_2.2.5 (2) 
    2: 0000000000000000  0 NOTYPE WEAK DEFAULT UND __gmon_start__ 
    3: 0000000000000000  0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 
    4: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS _edata 
    5: 0000000000601008  0 NOTYPE GLOBAL DEFAULT 24 __data_start 
    6: 0000000000400734  6 FUNC GLOBAL DEFAULT 13 foo 
    7: 0000000000601028  0 NOTYPE GLOBAL DEFAULT ABS _end 
    8: 0000000000601008  0 NOTYPE WEAK DEFAULT 24 data_start 
    9: 0000000000400838  4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 
    10: 0000000000400750 136 FUNC GLOBAL DEFAULT 13 __libc_csu_init 
    11: 0000000000400650  0 FUNC GLOBAL DEFAULT 13 _start 
    12: 0000000000601018  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
    13: 000000000040073a 16 FUNC GLOBAL DEFAULT 13 main 
    14: 0000000000400618  0 FUNC GLOBAL DEFAULT 11 _init 
    15: 00000000004007e0  2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 
    16: 0000000000400828  0 FUNC GLOBAL DEFAULT 14 _fini 
$ ./t 
$ 

.symtab Нет нет, но динамическая таблица символов еще там, и запускается исполняемый. Так что backtrace_symbols все еще работает.

Газа динамической таблица символов:

$ strip -R .dynsym t 
$ ./t 
./t: relocation error: ./t: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference 

... и вы получите сломанный исполняемый файл.

Интересно, для чего используются .symtab и .dynsym здесь: Inside ELF Symbol Tables. Следует отметить, что .symtab не требуется во время выполнения, поэтому он отбрасывается загрузчиком. Этот раздел не остается в памяти процесса. .dynsym, с другой стороны, -, необходимый во время выполнения, поэтому он хранится в образе процесса. Таким образом, он доступен для таких вещей, как backtrace_symbols, для сбора информации о текущем процессе изнутри.

Так короче:

  • динамические символы не раздели strip так, что сделало бы Исполняемый не загружаемый
  • backtrace_symbols нуждается в динамических символов, чтобы выяснить, какой код принадлежит какой функции
  • backtrace_symbols делает не использовать отладочные символы

Следовательно, поведение, которое вы заметили.


Для ваших конкретных вопросов:

  1. gdb это отладчик. Он использует отладочную информацию в исполняемом файле и библиотеках для отображения соответствующей информации. Это много более сложный, чем backtrace_symbols, и проверяет фактические файлы на вашем диске в дополнение к живому процессу. backtrace_symbols нет, он полностью находится в процессе - поэтому он не может получить доступ к разделам, которые не загружаются в исполняемый образ. Отладочные разделы не загружаются в образ среды выполнения, поэтому они не могут их использовать.
  2. .dynsym не является частью отладки. Это раздел, используемый динамическим компоновщиком. .symbtab также не является частью отладки, но может использоваться отладчиком, имеющим доступ к исполняемым (и библиотечным) файлам. -rdynamicне создает разделы отладки, только эта расширенная таблица динамических символов. Рост исполняемого файла от -rdynamic полностью зависит от количества символов в этом исполняемом файле (и соображений выравнивания/дополнения). Он должен быть значительно меньше -g.
  3. За исключением статически связанных двоичных файлов, исполняемым файлам требуются внешние зависимости, разрешенные во время загрузки. Как и ссылку printf и некоторые процедуры запуска приложений из библиотеки C. Эти внешние символы должны быть указаны где-то в исполняемом файле: это то, что используется .dynsym, и поэтому exe имеет .dynsym, даже если вы не указали -rdynamic. Когда вы это укажете, компоновщик добавляет другие символы, которые не нужны процессу для работы, но могут использоваться такими вещами, как backtrace_symbols.
  4. backtrace_symbols не будет разрешать имена функций, если вы статически связываете. Даже если вы укажете -rdynamic, раздел .dynsym не будет отправлен исполняемому файлу. Никакие таблицы символов не загружаются в исполняемый образ, поэтому backtrace_symbols не может сопоставлять кодовые адресаты с символами.
+0

спасибо за ответ .. но я все еще очень смущен .. Позвольте мне войти мои вопросы как отдельный ответ, чтобы его можно было отформатировать лучше. – Manohar

+0

Сделайте ** не ** отправьте ответ как продолжение, это не то, как работает этот сайт. Измените исходный вопрос (или опубликуйте новый, если ваш новый вопрос достаточно отличается). – Mat

+0

@Santhosh: добавил информацию в конце и попытался прояснить все это. НТН. – Mat

Смежные вопросы