Как использовать команду addr2line в linux

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

Ответ 1

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

(gdb) info symbol 0x4005BDC 

Ответ 2

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

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

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

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

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

Ответ 3

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

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

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

Ниже приведено сообщение из man addr2line.

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

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

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

Пример.

Возьмите 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 <[email protected]>
  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 <[email protected]>
    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
??:?

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

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

Ответ 4

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

Например:

$ 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

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

addr2line -f -e a.out 0x4005BDC