Debugging ausführbarer Dateien
-g erzeugt Zeilentabellen für den Erlang-Quelltext. Sie funktionieren auf
jeder Optimierungsstufe sowie mit --emit, positionalem Linken mit -o und
Projektzielen.
Zeilentabellen
- Jede erzeugte Funktion und jeder anonyme Fun erhält einen Debug-Scope, benannt
nach seinem Erlang-Namen (
leaf,-main/1-fun-0-), in der Datei, die ihn deklariert, sodass eine Funktion aus einer eingebundenen.hrlzu dieser Datei gehört. Er hat keinen Linkage-Namen: GDB würde sonst das native Symbol (clausev1_...) anzeigen. - Jeder Ausdruck ist an seiner physischen Quelltextzeile verortet. Code, zu dem ein Makro expandiert, ist am Aufruf des Makros verortet; eingebundener Code an seiner Zeile in der eingebundenen Datei.
- Es werden keine Variablen oder Typen beschrieben, Sprache
DW_LANG_lo_user. Die Übersetzungseinheit ist trotzdemFullDebug: LLVM lässt die Funktions-Scopes einerLineTablesOnly-Einheit aus DWARF weg, sofern nichts geinlinet wurde, und Debugger benennen Frames dann nach Symbol. - Format: CodeView für MSVC-Ziele, sonst DWARF 5. Ohne
-gtragen Objekte keine Zeilentabellen (IR-Inspektion und--emit llvm-irbehalten dennoch die Orte, die ihre Quelltextkommentare brauchen).
Linken
-g reicht -g an den Clang-Treiber weiter. MSVC-Ziele schreiben außerdem eine
PDB, die die ausführbare Datei nur über den Dateinamen nennt
(/PDBALTPATH:%_PDB%); sie wird als <name>.pdb neben der ausführbaren Datei
veröffentlicht, nach ihr, in derselben verzögerten Veröffentlichung.
ELF-Dateien behalten DWARF in sich. Mach-O-Dateien bräuchten dsymutil über
die bereitgestellten Objekte, bevor die Bereitstellung entfernt wird; das wird
nicht ausgeführt, daher verlieren ausführbare Dateien unter macOS beim Linken
ihre Zeilentabellen.
Erlang-Aufrufstapel
Erzeugter Code wechselt zwischen Funktionen durch Endübergaben über den
Prozess-Stack (Ausführungsmodell), daher zeigt ein
nativer Backtrace die aktuelle Erlang-Funktion und dann den Scheduler
(ProcessStack::run, Executor::work). Die Erlang-Frames des angehaltenen
Prozesses gibt die Runtime-Hilfsfunktion
clause::runtime::debug_erlang_stack() aus, den innersten zuerst, als
module:function/arity; sie liest den laufenden Prozess des Threads und die
kompilierten Namen der Frames, nie die Atomtabellen der Runtime:
(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
GDB schreibt den Aufruf call clause::runtime::debug_erlang_stack() nach
set language c++ (Frames von Erlang-Code haben keine Sprache, in der GDB
C++-Namen parst). Es benennt die Frames twice () at /path/debug.hrl:5.
Ausführbare Dateien mit -Os können die Hilfsfunktion zusammen mit anderem
nicht referenziertem Code verlieren.
Tests
linking_debug_info: IR-Metadaten (Dateien und Zeilen von Subprogrammen, ein in der eingebundenen Datei verortetes Makro) und Abschnitte mit Zeilentabellen in Objekten für x86-64 und x86 Windows, x86-64, AArch64 und ARMv7 Linux und arm64 macOS bei O0/O2, und keine ohne-g.linking_debugger: linkt das Fixture mit-gbei O0/O2 (und unter Windows eine PDB daneben) und steuert dann LLDB (unter Windows das der LLVM-Installation) oder GDB: Breakpoints indebug.hrlunddebug.erlhalten intwiceundleafan, und die Hilfsfunktion gibt ihre Erlang-Stacks aus. Ein Debugger, der nicht startet (das LLDB eines LLVM-Releases ohne seine Python-Bibliothek), wird übergangen; Exit 77 (übersprungen), wenn keiner existiert. Validiert mit LLDB unter Windows x64 und GDB 16 unter Linux x86-64.
Clause