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