Ходить по стеку довольно быстро - большая часть медлительности в backtrace()
связана с поиском имен символов. На x86 вы можете сделать следующее:
inline uint32_t get_ebp(void)
{
__asm__ __volatile__("mov %%ebp, %%eax");
}
int get_stack_depth(void)
{
uint32_t ebp = get_ebp();
int stack_depth = 0;
while(ebp != 0)
{
ebp = *(uint32_t *)ebp;
stack_depth++;
}
return stack_depth;
}
Это пройдёт по цепочке ebp
указателей. Имейте в виду, что это крайне непереносимо. Также обратите внимание, что при этом не будут учитываться функции, которые были встроены или оптимизированы с помощью хвостового вызова (конечно, backtrace()
имеет ту же проблему).
Еще одна важная проблема - условие завершения - после возврата до main()
часто нет никаких гарантий относительно того, что вы найдете в стеке. Так что, если libc не помещает нулевой указатель кадра, вы, скорее всего, будете иметь segfault. Вы можете получить значение завершения, посмотрев на него в самом начале main()
.