Я знаю, что для этого нет стандартной функции C. Мне было интересно, как это можно сделать в Windows и * nix? (Windows XP - моя самая важная ОС для этого прямо сейчас.)
83
Я знаю, что для этого нет стандартной функции C. Мне было интересно, как это можно сделать в Windows и * nix? (Windows XP - моя самая важная ОС для этого прямо сейчас.)
Ответы:
glibc предоставляет функцию backtrace ().
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
источник
char ** backtrace_symbols (void *const *buffer, int size)
void backtrace_symbols_fd(void *const *buffer, int size, int fd)
который, например, может отправлять вывод напрямую в stdout / err.backtrace_symbols()
отстой. Он требует экспорта всех символов и не поддерживает символы DWARF (отладочные). libbacktrace - намного лучший вариант во многих (большинстве) случаях.Есть backtrace () и backtrace_symbols ():
На странице руководства:
#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); ...
Один из способов использовать это более удобным способом / ООП - сохранить результат 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 < frames; ++i) { printf("%s\n", strs[i]); } free(strs); } };
...
try { throw MyException("Oops!"); } catch ( MyException e ) { e.printStackTrace(); }
Да да!
Примечание: включение флагов оптимизации может сделать итоговую трассировку стека неточной. В идеале эту возможность следует использовать с включенными флагами отладки и выключенными флагами оптимизации.
источник
Для Windows проверьте API StackWalk64 () (также в 32-битной Windows). Для UNIX вы должны использовать собственный способ ОС или вернуться к функции backtrace () glibc, если она доступна.
Однако обратите внимание, что использование Stacktrace в машинном коде редко бывает хорошей идеей - не потому, что это невозможно, а потому, что вы обычно пытаетесь достичь неправильного результата.
В большинстве случаев люди пытаются получить трассировку стека, скажем, в исключительных обстоятельствах, например, когда обнаружено исключение, утверждение не выполняется или - что самое худшее и самое неправильное из всех - когда вы получаете фатальное «исключение» или сигнал вроде нарушение сегментации.
Учитывая последнюю проблему, большинство API-интерфейсов потребуют от вас явного выделения памяти или могут сделать это внутренне. Если вы сделаете это в том нестабильном состоянии, в котором ваша программа может находиться в настоящее время, это может действительно ухудшить ситуацию. Например, отчет о сбое (или coredump) будет отражать не фактическую причину проблемы, а вашу неудачную попытку ее решить).
Я предполагаю, что вы пытаетесь решить эту проблему с обработкой фатальных ошибок, поскольку большинство людей, кажется, пытаются это сделать, когда дело доходит до получения трассировки стека. Если это так, я бы положился на отладчик (во время разработки) и позволил бы процессу coredump в продакшене (или мини-дампу в Windows). Вместе с правильным управлением символами у вас не должно возникнуть проблем с посмертным выяснением причинной инструкции.
источник
Вы должны использовать библиотеку размотки .
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, чтобы получить исходную функцию / номер строки соответствующего ПК.источник
Не существует независимого от платформы способа сделать это.
Ближайшее, что вы можете сделать, - это запустить код без оптимизации. Таким образом, вы можете подключиться к процессу (используя визуальный отладчик C ++ или GDB) и получить полезную трассировку стека.
источник
Для Windows
CaptureStackBackTrace()
это также вариант, который требует меньше кода подготовки на стороне пользователя, чемStackWalk64()
это требуется . (Кроме того, для аналогичного сценария, который у меня был, вCaptureStackBackTrace()
итоге работал лучше (более надежно), чемStackWalk64()
.)источник
В Solaris есть команда pstack , которая также была скопирована в Linux.
источник
Вы можете сделать это, переместив стопку назад. В действительности, однако, часто проще добавить идентификатор в стек вызовов в начале каждой функции и вставить его в конце, а затем просто пройтись по нему, распечатав содержимое. Это немного похоже на PITA, но работает хорошо и в конечном итоге сэкономит ваше время.
источник
Последние несколько лет я использую libbacktrace Яна Ланса Тейлора. Он намного чище, чем функции библиотеки GNU C, требующие экспорта всех символов. Он предоставляет больше возможностей для генерации трассировки, чем libunwind. И наконец, что не менее важно, ASLR не побеждает его, как подходы, требующие внешних инструментов, таких как
addr2line
.Libbacktrace изначально была частью дистрибутива GCC, но теперь она доступна автором как отдельная библиотека под лицензией BSD:
https://github.com/ianlancetaylor/libbacktrace
На момент написания я бы не стал использовать ничего другого, если мне не нужно генерировать обратные трассировки на платформе, которая не поддерживается libbacktrace.
источник