Stack unwinding

Mechanism

1. Frame pointers … the old default way

  • Frame pointers are enabled by default.
  • Strong optimization (“-O2”, “-O3”) will implicitly disable frame pointers.

2. Unwind tables … a separate binary section

  • Unwind tables are enabled by default.
  • Disabling exceptions (“-fno-exceptions”) may implicitly disable unwind tables.

Showcase

#include <stdio.h>

void print()
{
    printf("Test");
    *((char*)NULL) = 0;
}

int main()
{
    print();
    return 0;
}

With backtrace

% clang++ test.cpp -w -O1 -fno-inline
% lldb a.out                         
(lldb) r
Target 0: (a.out) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x100003f84)
  * frame #0: 0x0000000100003f84 a.out`print() + 20
    frame #1: 0x0000000100003f94 a.out`main + 12
    frame #2: 0x000000018249f154 dyld`start + 2476

Without backtrace

% clang++ test.cpp -w -O1 -fno-inline -fomit-frame-pointer -fno-unwind-tables
% lldb a.out
(lldb) r
Target 0: (a.out) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x100003f8c)
  * frame #0: 0x0000000100003f8c a.out`print() + 16