Clause
← All documentation

Debugging executables

-g emits Erlang source line tables. They work at every optimization level and with --emit, positional -o linking and project targets.

Line tables

Linking

-g passes -g to the Clang driver. MSVC targets also write a PDB that the executable names by file name only (/PDBALTPATH:%_PDB%); it is published beside the executable as <name>.pdb, after the executable, in the same deferred publication. ELF executables keep DWARF inside. Mach-O executables keep only a debug map naming the staged objects, so dsymutil (beside the Clang driver, else on PATH) gathers their DWARF into <name>.dSYM before staging is removed; the bundle is published beside the executable, replacing the previous one. Darwin compile units record the working directory as their compile directory: the linker leaves a unit without one out of the debug map.

Erlang call stack

Generated code moves between functions by tail transfers through the process stack (execution model), so a native backtrace shows the current Erlang function and then the scheduler (ProcessStack::run, Executor::work). The Erlang frames of the stopped process are printed by the runtime helper clause::runtime::debug_erlang_stack(), innermost first, as module:function/arity; it reads the thread's running process and the frames' compiled names, never runtime atom tables:

(lldb) breakpoint set --file debug.erl --line 8
(lldb) run
* thread #1, stop reason = breakpoint 1.1
    frame #0: debug.exe`leaf at debug.erl:8
(lldb) expr -- clause::runtime::debug_erlang_stack()
  debug:leaf/1
  debug:middle/1
  debug:main/1

At -O2 small local functions and known funs run inlined in their caller (leaf inlining). Their code keeps its lines in the function's own scope, inlined at the call, so debuggers stop in them and show an inlined frame (debug.exe`leaf at debug.erl:8 [inlined]); the Erlang stack has the caller on top. LLDB reading a PDB finds the lines of an included file only in functions of their own, so it cannot break in an inlined function from a .hrl.

GDB spells the call call clause::runtime::debug_erlang_stack() after set language c++ (frames of Erlang code have no language GDB parses C++ names in). It names the frames twice () at /path/debug.hrl:5. -Os executables may drop the helper with other unreferenced code.

Tests