Как можно получить трассировку стека в C?

Я знаю, что нет стандартной функции C, чтобы сделать это. Мне было интересно, какие методы для этого в Windows и * nix? (Windows XP - моя самая важная ОС, чтобы сделать это прямо сейчас.)

Ответы на вопрос(11)

Для UNIX вы должны использовать родной способ ОС или сделать возврат к glibc backtrace (), если таковой имеется.

Заметим, однако, что использование Stacktrace в нативном коде редко бывает хорошей идеей - не потому, что это невозможно, а потому, что вы обычно пытаетесь достичь неправильного результата.

В большинстве случаев люди пытаются получить стековую трассировку, скажем, в исключительных обстоятельствах, например, при обнаружении исключения, сбое утверждения или - наихудшем и наиболее неправильном из них - когда вы получаете фатальное «исключение» или сигнал типа нарушение сегментации.

Учитывая последнюю проблему, большинство API-интерфейсов потребует от вас явного выделения памяти или может сделать это внутренне. Выполнение этого в хрупком состоянии, в котором ваша программа может находиться в данный момент, может на самом деле ухудшить ситуацию. Например, отчет о сбое (или coredump) не будет отражать фактическую причину проблемы, но ваша неудачная попытка ее устранить).

Я предполагаю, что вы пытаетесь достичь этой фатальной обработки ошибок, поскольку большинство людей, кажется, пытаются это сделать, когда дело доходит до получения трассировки стека. Если это так, я бы положился на отладчик (во время разработки) и запуск процесса coredump (или мини-дамп на окнах). Вместе с правильным управлением символами у вас не должно возникнуть проблем с поиском вызывающей инструкции после смерти.

 j_random_hacker19 февр. 2009 г., 13:30
Вы правы в том, что пытаетесь выделить память в обработчике сигналов или исключений. Одним из возможных выходов является выделение фиксированного количества «аварийного» пространства при запуске программы или использование статического буфера.
 Kobor4213 июл. 2012 г., 09:59
Другим выходом является создание службы coredump, которая работает независимо
Решение Вопроса

https: //www.codeproject.com/kb/threads/stackwalker.asp

Код немного ИМХО, но он работает хорошо. Только для Windows.

 squelart16 нояб. 2009 г., 03:52
Link не работает. Должно ли это быть Codeproject.com / KB / темы / StackWalker.aspx ?
 Vladislav Rastrusny09 мар. 2011 г., 20:11
Меня устраивае
 PeterT08 авг. 2011 г., 09:58
Кстати, более свежий код сохраняется @ Stackwalker.codeplex.com но страница кода проекта по-прежнему полезна в качестве основной документации.

пройдя стопку назад. В действительности, однако, часто проще добавить идентификатор в стек вызовов в начале каждой функции и вставить его в конец, а затем просто пройтись по этому содержимому. Это немного PITA, но он работает хорошо и в итоге сэкономит ваше время.

 Spidey31 авг. 2012 г., 22:45
Не могли бы вы объяснить, как "прогуливать стопку назад" более подробно?
 Trevor Boyd Smith09 сент. 2011 г., 19:55
Но подождите, это еще не все! Функция backtrace () предоставляет только массив указателей void *, представляющих функции стека вызовов. «Это не очень полезно. Арг.» Не бойся! glibc предоставляет функцию, которая преобразует все адреса void * (адреса функции callstack) в читаемые человеком строковые символы.char ** backtrace_symbols (void *const *buffer, int size)
 Erwan Legrand08 февр. 2018 г., 12:18
backtrace_symbols() отстой. Он требует экспорта всех символов и не поддерживает символы DWARF (отладки). libbacktrace - намного лучший вариант во многих (большинстве) случаях.
 wkz24 апр. 2012 г., 15:47
Существует такжеvoid backtrace_symbols_fd(void *const *buffer, int size, int fd) который может отправить вывод напрямую, например, в stdout / err.
 Trevor Boyd Smith09 сент. 2011 г., 19:53
glibc FTW ... снова. (Это еще одна причина, почему я считаю glibc абсолютным золотым стандартом, когда речь заходит о программировании на C (как и компиляторе, который идет с ним).)
 Conrad Meyer16 окт. 2011 г., 02:20
Caveat: я думаю, что работает только для C-функций. @Trevor: это просто поиск символов по адресу в таблице ELF.

Post Mortem Debugging

Хотя сейчас у меня проблемы с x64 реализация этого.

CaptureStackBackTrace() также опция, которая требует меньше подготовительного кода на стороне пользователя, чемStackWalk64() делает. (Также для похожего сценария, который у меня был,CaptureStackBackTrace() работал лучше (надежнее), чемStackWalk64().)

Со страницы руководства:

     #include <execinfo.h>
     #include <stdio.h>
     ...
     void* callstack[128];
     int i, frames = backtrace(callstack, 128);
     char** strs = backtrace_symbols(callstack, frames);
     for (i = 0; i < frames; ++i) {
         printf("%s\n", strs[i]);
     }
     free(strs);
     ...

Один из способов использовать это более удобным способом / OOP - сохранить результат backtrace_symbols () в конструкторе класса исключений. Таким образом, всякий раз, когда вы генерируете исключение такого типа, у вас есть трассировка стека. Затем просто предоставьте функцию для распечатки. Например


class MyException : public std::exception {

    char ** strs;
    MyException( const std::string & message ) {
         int i, frames = backtrace(callstack, 128);
         strs = backtrace_symbols(callstack, frames);
    }

    void printStackTrace() {
        for (i = 0; i 

...


try {
   throw MyException("Oops!");
} catch ( MyException e ) {
    e.printStackTrace();
}

Та да!

Примечание: включение флагов оптимизации может сделать полученную трассировку стека неточной. В идеале эту функцию можно использовать при включенных флагах отладки и отключенных флагах оптимизации.

 shuckc07 окт. 2011 г., 11:18
gcc требует-rdynamic аргумент, чтобы это работало
 Woodrow Barlow07 июл. 2016 г., 21:57
@ shuckc только для преобразования адреса в символьную строку, что может быть выполнено извне с использованием других инструментов, если это необходимо.

Ближайшее, что вы можете сделать, - запустить код без оптимизации. Таким образом, вы можете подключиться к процессу (используя отладчик Visual C ++ или GDB) и получить полезную трассировку стека.

 ephemient31 янв. 2010 г., 07:49
@ Кевин: Даже на встроенных машинах обычно есть способ получить заглушку удаленного отладчика или, по крайней мере, дамп ядра. Может быть, не раз он будет развернут на поле, хотя ...
 Trevor Boyd Smith09 сент. 2011 г., 20:00
если вы используете gcc-glibc на выбранной вами платформе windows / linux / mac ... тогда backtrace () и backtrace_symbols () будут работать на всех трех платформах. Учитывая это утверждение, я бы использовал слова «нет [портативного] способа сделать это».
 Kevin19 сент. 2008 г., 23:19
Это не помогает мне, когда происходит сбой на встроенном компьютере в полевых условиях. :

Ты должен использоватьunwind library.

unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;

while (unw_step(&cursor) > 0) {
  unw_get_reg(&cursor, UNW_REG_IP, &ip);
  unw_get_reg(&cursor, UNW_REG_SP, &sp);
  if (ctr >= 10) break;
  a[ctr++] = ip;
}

Ваш подход также будет работать нормально, если вы не позвоните из общей библиотеки.

Вы можете использоватьaddr2line команда в Linux, чтобы получить исходную функцию / номер строки соответствующего ПК.

 Erwan Legrand08 февр. 2018 г., 12:13
addr2line не подходит для перемещаемого кода в системах с ASLR (т. е. большинство из того, что люди использовали в течение последнего десятилетия).
 Ogre Psalm3323 сент. 2010 г., 16:43
Хорошо, этот комментарий стоил того, хотя бы из-за упоминания полезной команды addr2line!
 Mawg31 янв. 2010 г., 08:19
"функция источника / номер строки"? Что если ссылки оптимизированы для уменьшения размера кода? Я скажу, однако, что это выглядит как полезный проект. Жаль, что нет возможности получить регистры. Я обязательно посмотрю на это. Вы знаете, что он абсолютно независим от процессора? Просто работает на всем, что имеет компилятор C?

то намного чище, чем функции в библиотеке GNU C, которые требуют экспорта всех символов. Он предоставляет больше полезности для генерации обратных трасс, чем libunwind. И последнее, но не менее важное, он не побежден ASLR, как и подходы, требующие внешних инструментов, таких какaddr2line.

Libbacktrace изначально была частью дистрибутива GCC, но теперь она доступна автору как отдельная библиотека под лицензией BSD:

https: //github.com/ianlancetaylor/libbacktrac

На момент написания я не стал бы использовать что-либо еще, если бы мне не нужно было генерировать обратные трассировки на платформе, которая не поддерживается libbacktrace.

Pstack команда, которая также была скопирована в Linux.

 ephemient31 янв. 2010 г., 07:48
Полезно, но не совсем C (это внешняя утилита).
 Ciro Costa31 окт. 2015 г., 20:32
также из описания (раздел: ограничения) ": pstack в настоящее время работает только в Linux, только на компьютере x86 с 32-разрядными двоичными файлами ELF (64-разрядная версия не поддерживается)"

Ваш ответ на вопрос