Я хочу, чтобы мои обработчики исключений и функции отладки могли печатать обратные трассировки стека вызовов, в основном так же, как библиотечная функция backtrace() в glibc. К сожалению, моя библиотека C (Newlib) не поддерживает такой вызов.
У меня есть что-то вроде этого:
#include <unwind.h> // GCC's internal unwinder, part of libgcc
_Unwind_Reason_Code trace_fcn(_Unwind_Context *ctx, void *d)
{
int *depth = (int*)d;
printf("\t#%d: program counter at %08x\n", *depth, _Unwind_GetIP(ctx));
(*depth)++;
return _URC_NO_REASON;
}
void print_backtrace_here()
{
int depth = 0;
_Unwind_Backtrace(&trace_fcn, &depth);
}
что в основном работает, но результирующие трассировки не всегда полны. Например, если я делаю
int func3() { print_backtrace_here(); return 0; }
int func2() { return func3(); }
int func1() { return func2(); }
int main() { return func1(); }
обратная трассировка показывает только func3() и main(). (Это явно игрушечный пример, но я проверил дизассемблирование и подтвердил, что все эти функции здесь полностью, а не оптимизированы или встроены.)
Обновление: я попробовал этот код обратной трассировки на старой системе ARM7, но с теми же (или, по крайней мере, максимально эквивалентными) параметрами компилятора и скриптом компоновщика, и он печатает правильную полную обратную трассировку (т. е. func1 и func2 не пропущены) и, действительно, он даже прослеживает путь от main к коду инициализации загрузки. Так что, по-видимому, проблема не в скрипте компоновщика или параметрах компилятора. (Кроме того, после разборки было подтверждено, что в этом тесте ARM7 указатель кадра также не используется).
Код скомпилирован с -fomit-frame-pointer, но моя платформа (голое железо ARM Cortex M3) определяет ABI, который в любом случае не использует указатель кадра. (Предыдущая версия этой системы использовала старый ABI APCS на ARM7 с принудительными кадрами стека и указателем кадра, а также отслеживанием, подобным здесь, что отлично сработало).
Вся система скомпилирована с параметром -fexception, который гарантирует, что необходимые метаданные, используемые _Unwind, будут включены в файл ELF. (Я думаю, что _Unwind предназначен для обработки исключений).
Итак, мой вопрос: Существует ли "стандартный" общепринятый способ получения надежной обратной трассировки во встроенных системах с использованием GCC?
Я не возражаю против того, чтобы возиться со сценариями компоновщика и кодом crt0, если это необходимо, но я не хочу рисковать самой цепочкой инструментов.
Спасибо!