Если вы хотите сделать это крайне не переносимым, вы можете просто прочитать регистр EBP и самостоятельно пройтись по стеку. Это будет работать только для архитектуры x86, а также предполагает, что используемая среда выполнения C правильно инициализирует EBP в 0 перед вызовом первой функции.
uint32_t read_ebp(void)
{
uint32_t my_ebp;
__asm
{
mov ebp, my_ebp
}
return my_ebp;
}
void backtrace(void)
{
uint32_t ebp = read_ebp();
printf("backtrace:\n");
while(ebp != 0)
{
printf("0x%08x\n", ebp);
ebp = ((uint32_t *)ebp)[1];
}
}