Как использовать команду addr2line в Linux? - PullRequest
42 голосов
/ 04 октября 2011

Я пытаюсь использовать команду addr2line в Unix, но каждый раз она выдает тот же вывод, что и ??: 0. Я даю команду как addr2line -e a.out 0x4005BDC. Я получил этот адрес при запуске исполняемого файла a.out с помощью инструмента valgrind, чтобы найти утечку памяти. Я также скомпилировал исходный код с параметром -g.

Ответы [ 5 ]

30 голосов
/ 04 октября 2011

Вы также можете использовать gdb вместо addr2line для проверки адреса памяти.Загрузите исполняемый файл в gdb и напечатайте имя символа, который хранится по адресу. 16 Изучение таблицы символов .

(gdb) info symbol 0x4005BDC 
21 голосов
/ 15 мая 2015

Пожалуйста, проверьте:

  • Все ли функции в вашем двоичном коде скомпилированы с -g, addr2line только функции поддержки имеют отладочную информацию, которая скомпилирована с -g
  • Является ли ваше смещение действительным смещением. Это означает, что ваше смещение не должно быть адресом виртуальной памяти, а должно быть только смещением в разделе .text. В разделе .text означает, что адрес должен указывать на инструкцию в двоичном виде

использование addr2line

Ниже следует сообщение от man addr2line.

addr2line - преобразовать адреса в имена файлов и номера строк.

addresses должен быть адресом в исполняемом файле или смещением в разделе перемещаемого объекта.

Вывод будет выглядеть примерно так: FILENAME:LINENO, имя исходного файла и номер строки в файле

* * Пример 1 028.

Возьмите helloworld в качестве примера.

#include <stdio.h>
int main()
{
    printf("hello\n");
    return 0;
}

После компиляции с помощью gcc -g hello.c мы могли бы сначала использовать objdump, чтобы получить представление об информации о смещении в сгенерированном файле a.out.

Ниже приводится часть сброшенной разборки:

Disassembly of section .text:

0000000000400440 <_start>:
  400440:       31 ed                   xor    %ebp,%ebp
  400442:       49 89 d1                mov    %rdx,%r9
  400445:       5e                      pop    %rsi
  400446:       48 89 e2                mov    %rsp,%rdx
  400449:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  40044d:       50                      push   %rax
  40044e:       54                      push   %rsp
  40044f:       49 c7 c0 c0 05 40 00    mov    $0x4005c0,%r8
  400456:       48 c7 c1 50 05 40 00    mov    $0x400550,%rcx
  40045d:       48 c7 c7 36 05 40 00    mov    $0x400536,%rdi
  400464:       e8 b7 ff ff ff          callq  400420 <__libc_start_main@plt>
  400469:       f4                      hlt
  40046a:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

  ...

   0000000000400536 <main>:

#include <stdio.h>
int main()
{
  400536:       55                      push   %rbp
  400537:       48 89 e5                mov    %rsp,%rbp
    printf("hello\n");
  40053a:       bf d4 05 40 00          mov    $0x4005d4,%edi
  40053f:       e8 cc fe ff ff          callq  400410 <puts@plt>
    return 0;
  400544:       b8 00 00 00 00          mov    $0x0,%eax
}
  400549:       5d                      pop    %rbp
  40054a:       c3                      retq
  40054b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Самый левый столбец кода - это смещение в двоичном файле. __start функция взята из стандартной библиотеки C и предварительно скомпилирована без отладочной информации. Функция main взята из нашего кода helloworld, который содержит отладочную информацию, поскольку мы компилируем файл с -g.

Ниже выводится addr2line:

$ addr2line -e a.out 0x400442 #offset in the `__start` function
??:?
$ addr2line -e a.out 0x400536 #offset in the `main` function
hello.c:21
$ addr2line -e a.out 0x40054b -f #The last instruction of the `main` function
main
??:?

Из приведенного выше вывода можно сделать некоторые выводы:

  1. Только сегмент кода, созданный с флагом -g (что означает, что сегмент имеет отладочную информацию), может успешно генерировать информацию об имени файла и номере белья.
  2. Не все смещения тела функции, скомпилированные с флагом -g, успешно выведут имя файла и номер белья. Смещение 0x40054b является последней инструкцией после ret инструкции функции main, но мы не смогли получить информацию.
16 голосов
/ 04 октября 2011

Вам необходимо указать смещение для addr2line, а не виртуальный адрес (VA). Предположительно, если вы отключили рандомизацию адресного пространства, вы могли бы использовать полную виртуальную машину, но в большинстве современных ОС адресные пространства рандомизированы для нового процесса.

Учитывая VA 0x4005BDC от valgrind, найдите базовый адрес вашего процесса или библиотеки в памяти. Сделайте это, изучив файл /proc/<PID>/maps во время работы вашей программы. Интересующая линия - это сегмент text вашего процесса, который можно определить по разрешениям r-xp и названию вашей программы или библиотеки.

Скажем, базовый VA равен 0x0x4005000. Тогда вы найдете разницу между VA, поставляемым Valgrind, и базовым VA: 0xbdc. Затем добавьте это в add2line:

addr2line -e a.out -j .text 0xbdc

И посмотри, получит ли это твой номер строки.

11 голосов
/ 04 октября 2011

Именно так вы и используете.Существует вероятность того, что ваш адрес не соответствует чему-то непосредственно в вашем исходном коде.

Например:

$ cat t.c
#include <stdio.h>
int main()
{
    printf("hello\n");
    return 0;
}
$ gcc -g t.c
$ addr2line -e a.out 0x400534
/tmp/t.c:3
$ addr2line -e a.out 0x400550
??:0

0x400534 - это адрес main вмое дело.0x400408 также является допустимым адресом функции в a.out, но это фрагмент кода, сгенерированный / импортированный GCC, который не имеет отладочной информации.(В этом случае __libc_csu_init. Вы можете увидеть компоновку вашего исполняемого файла с помощью readelf -a your_exe.)

В других случаях, когда addr2line не удастся, вы подключаете библиотеку, в которой нет отладочной информации.

5 голосов
/ 24 апреля 2015

Попробуйте добавить параметр -f, чтобы отобразить имена функций:

addr2line -f -e a.out 0x4005BDC
...