Как заставить backtrace () / backtrace_symbols () печатать имена функций?

91

Специфична для Linux backtrace()и backtrace_symbols()позволяет производить трассировку вызовов программы. Однако он печатает только адреса функций, а не их имена для моей программы. Как я могу заставить их печатать и имена функций? Я попытался компиляции программы с -g, а также -ggdb. В приведенном ниже тестовом примере это просто напечатано:

    BACKTRACE ------------
    ./a.out () [0x8048616]
    ./a.out () [0x8048623]
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
    ./a.out () [0x8048421]
    ----------------------
    

Я бы хотел, чтобы первые 2 элемента также отображали имена функций fooиmain

Код:

Lyke
источник
кстати, функция backtrace_symbols_fdвыполняет ту же операцию, что и backtrace_symbols(), но результирующие строки сразу записываются в файловый дескриптор fd.
nhnghia
Я подробно протестировал несколько методов по адресу: stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ответы:

65

Символы берутся из таблицы динамических символов; вам нужна -rdynamicопция gcc, которая заставляет его передавать компоновщику флаг, который гарантирует, что все символы будут помещены в таблицу.

(См. Страницу параметров ссылки в руководстве GCC и / или страницу обратных трасс в руководстве по glibc .)

Мэтью Слэттери
источник
10
Однако это не работает для статических символов. libunwindчто @Nemo упоминает, работает для статических функций.
Натан Кидд
В проекте CMake это было ошибочно установлено как ADD_COMPILE_OPTIONS(-rdynamic). Вместо этого он должен быть ADD_LINK_OPTIONS(-rdynamic)или эквивалентным, чтобы иметь желаемое поведение.
Стефан
30

Используйте команду addr2line для сопоставления адресов исполняемых файлов с именем файла исходного кода + номером строки. Дай-f возможность получать имена функций.

Или попробуйте libunwind .

Немо
источник
3
Строка addr2 хороша тем, что включает в себя имя файла и номер строки в выводе, но она не работает, как только загрузчик выполняет перемещение.
Erwan Legrand
... а с ASLR перемещения происходят чаще, чем когда-либо.
Erwan Legrand
@ErwanLegrand: До ASLR я думал, что перемещения были предсказуемыми и addr2lineработали надежно даже для адресов в общих объектах (?) Но да, на современных платформах вам нужно было бы знать фактический адрес загрузки перемещаемого объекта даже для выполнения этой операции в принципе .
Nemo
Я не могу точно сказать, насколько хорошо он работал до ASLR. В настоящее время это применимо только для кода внутри «обычных» исполняемых файлов и не работает для кода внутри DSO и PIE (Position Independent Executables). К счастью, libunwind подходит для всех этих случаев.
Erwan Legrand
Я забыл об этой дискуссии. Libbacktrace, о котором я не знал в то время, - лучший вариант. (См. Мой новый ответ.)
Эрван Легран,
12

Отличный Libbacktrace от Яна Ланса Тейлора решает эту проблему. Он обрабатывает раскрутку стека и поддерживает как обычные символы ELF, так и символы отладки DWARF.

Libbacktrace не требует экспорта всех символов, что было бы некрасиво, и ASLR не нарушает его.

Libbacktrace изначально была частью дистрибутива GCC. Теперь отдельную версию можно найти на Github:

https://github.com/ianlancetaylor/libbacktrace

Эрван Легран
источник
2

ответ вверху содержит ошибку, если ret == -1 и errno - EINTER, вам следует попробовать еще раз, но не считать ret как скопированные (не собираюсь создавать учетную запись только для этого, если вам это не нравится)

Billg
источник
0

Увеличить обратную трассировку

Очень удобно, потому что печатает как:

  • несвязанные имена функций C ++
  • номера строк

автоматически для вас.

Сводка использования:

Я предоставил минимальный исполняемый пример для него и многих других методов в: стек вызовов печати на C или C ++

Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
Вопрос помечен тегом [c], а не [c ++].
Яков Галка