Вопрос по cross-platform, windows, stack-trace, c, debugging – Как можно получить трассировку стека в C?
https: //www.codeproject.com/kb/threads/stackwalker.asp
Код немного ИМХО, но он работает хорошо. Только для Windows.
char ** backtrace_symbols (void *const *buffer, int size)
Trevor Boyd Smith
void backtrace_symbols_fd(void *const *buffer, int size, int fd)
который может отправить вывод напрямую, например, в stdout / err.
wkz
backtrace_symbols()
отстой. Он требует экспорта всех символов и не поддерживает символы DWARF (отладки). libbacktrace - намного лучший вариант во многих (большинстве) случаях.
Erwan Legrand
Со страницы руководства:
#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();
}
Та да!
Примечание: включение флагов оптимизации может сделать полученную трассировку стека неточной. В идеале эту функцию можно использовать при включенных флагах отладки и отключенных флагах оптимизации.
-rdynamic
аргумент, чтобы это работало
shuckc
Для UNIX вы должны использовать родной способ ОС или сделать возврат к glibc backtrace (), если таковой имеется.
Заметим, однако, что использование Stacktrace в нативном коде редко бывает хорошей идеей - не потому, что это невозможно, а потому, что вы обычно пытаетесь достичь неправильного результата.
В большинстве случаев люди пытаются получить стековую трассировку, скажем, в исключительных обстоятельствах, например, при обнаружении исключения, сбое утверждения или - наихудшем и наиболее неправильном из них - когда вы получаете фатальное «исключение» или сигнал типа нарушение сегментации.
Учитывая последнюю проблему, большинство API-интерфейсов потребует от вас явного выделения памяти или может сделать это внутренне. Выполнение этого в хрупком состоянии, в котором ваша программа может находиться в данный момент, может на самом деле ухудшить ситуацию. Например, отчет о сбое (или coredump) не будет отражать фактическую причину проблемы, но ваша неудачная попытка ее устранить).
Я предполагаю, что вы пытаетесь достичь этой фатальной обработки ошибок, поскольку большинство людей, кажется, пытаются это сделать, когда дело доходит до получения трассировки стека. Если это так, я бы положился на отладчик (во время разработки) и запуск процесса coredump (или мини-дамп на окнах). Вместе с правильным управлением символами у вас не должно возникнуть проблем с поиском вызывающей инструкции после смерти.
Ближайшее, что вы можете сделать, - запустить код без оптимизации. Таким образом, вы можете подключиться к процессу (используя отладчик Visual C ++ или GDB) и получить полезную трассировку стека.
Ты должен использовать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, чтобы получить исходную функцию / номер строки соответствующего ПК.
Pstack команда, которая также была скопирована в Linux.
то намного чище, чем функции в библиотеке GNU C, которые требуют экспорта всех символов. Он предоставляет больше полезности для генерации обратных трасс, чем libunwind. И последнее, но не менее важное, он не побежден ASLR, как и подходы, требующие внешних инструментов, таких какaddr2line
.
Libbacktrace изначально была частью дистрибутива GCC, но теперь она доступна автору как отдельная библиотека под лицензией BSD:
https: //github.com/ianlancetaylor/libbacktrac
На момент написания я не стал бы использовать что-либо еще, если бы мне не нужно было генерировать обратные трассировки на платформе, которая не поддерживается libbacktrace.
пройдя стопку назад. В действительности, однако, часто проще добавить идентификатор в стек вызовов в начале каждой функции и вставить его в конец, а затем просто пройтись по этому содержимому. Это немного PITA, но он работает хорошо и в итоге сэкономит ваше время.