====== Fehlersuche ======
Lyx erzeugt statische Binaries ohne Laufzeitumgebung — es gibt keinen Stacktrace mit Zeilennummern, wenn ein Programm stirbt. Dafür gibt es Werkzeuge, die vor und nach dem Absturz weiterhelfen. Der Guide zeigt sie in der Reihenfolge, in der man sie braucht.
→ [[lyx_-_programmiersprache:tools:compiler-parameter|Compiler-Parameter]] · [[lyx_-_programmiersprache:tools:lbfdump|lbfdump]] · [[lyx_-_programmiersprache:sprache:exit-codes|Exit-Codes]]
----
===== 1. Erst den Compiler fragen =====
Die meisten Fehler stehen schon in der Übersetzung — Lyx meldet seit 1.1.x deutlich mehr als früher:
fn main(): int64 {
var k: TKnoten; // Compile-Fehler: ohne new
PrintLn(IntToStr(Summe(k)));
return 0;
}
sema error (line 14): Variable hat Klassentyp ohne Startwert — `new` oder `null` angeben 'TKnoten'
Solche Meldungen sind neu: unbekannte Felder, falsche Stelligkeiten, doppelte Mitglieder, Vorwärtsverweise und Speicheranforderungen unter ''@flight_crit'' wurden früher still angenommen. **Wer ein älteres Projekt erstmals mit 1.1.x übersetzt, bekommt deshalb Meldungen — sie zeigen Fehler, die vorher stumm blieben.**
----
===== 2. Absturzstelle finden: %%--%%map-file =====
''--map-file'' schreibt neben das Programm eine ''.map''-Datei mit Sektionen, Adressen und Zeilennummern:
lyxc dbg.lyx --map-file -o dbg
Lyx-Abbildkarte fuer dbg2
Sektionen
NAME ADRESSE LAENGE
.text 0x00000000004000b0 114512
.data 0x000000000041c000 433
Symbole (nach Adresse)
ADRESSE OFFSET ZEILE NAME
0x000000000041aea7 0x000000000001adf7 4 Lies
0x000000000041af12 0x000000000001ae62 8 main
Die Absturzadresse liefert der Debugger:
gdb -q -batch -ex run -ex "info registers rip" ./dbg
Program received signal SIGSEGV, Segmentation fault.
0x000000000041aeda in ?? ()
rip 0x41aeda 0x41aeda
''0x41aeda'' liegt zwischen ''Lies'' (''0x41aea7'') und ''main'' (''0x41af12'') — der Absturz passierte also in ''Lies'', Quellzeile 4. **Die letzte Adresse unterhalb des Werts ist die gesuchte Funktion.**
Dieses Verfahren hat in der Praxis Fehler gefunden, die sonst tagelang gekostet hätten — etwa einen Absturz beim Schließen eines Dateidialogs, dessen Ursache zwei Funktionen entfernt lag.
----
===== 3. Symbole einbetten: %%--%%debug-symbols =====
lyxc dbg.lyx --debug-symbols -o dbg
Damit nennt der Debugger die Funktion direkt (''in main ()'' statt ''in ?? ()''). Die Kosten sind gering — im Test 115 KB gegenüber 124 KB. Für ''.lyu''-Units wirkt der Schalter seit lyxc 1.1.2J ebenfalls ([[https://github.com/SEOLizer/LyX-Compiler/issues/1555|#1555]]).
Die Zuordnung ist grob: Sie nennt das nächstgelegene Symbol, nicht zwingend die richtige Funktion. Für die genaue Stelle bleibt die ''.map''-Datei maßgeblich.
----
===== 4. Fehler eingrenzen: -O0 =====
''-O0'' schaltet Konstantenfaltung und tote Zweige ab. Verhält sich ein Programm mit ''-O0'' anders als ohne, liegt der Fehler im Codegen und nicht in der eigenen Logik — das ist die erste Frage, die ein Bericht beantworten sollte.
Die Stufen ''-O1'' bis ''-O3'' unterscheiden sich untereinander nicht; wirksam ist allein der Gegensatz ''-O0''/''--no-opt'' gegen alles andere.
----
===== 5. Vor dem Fehler: statische Werkzeuge =====
^ Schalter ^ Antwortet auf ^
| ''%%--%%call-graph'' | Wer ruft wen? Gibt es Rekursion? Was ist von ''main'' aus unerreichbar? |
| ''%%--%%static-analysis'' | Wie viel Stapel braucht jede Funktion? |
| ''%%--%%mcdc'' | Welche Bedingungen sind strukturell nicht abgedeckt? |
| ''%%--%%compile-unit'' | Übersetzt diese Unit für sich allein — bis in den Codegen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1587|#1587]]) |
| ''%%--%%symtab-dump'', ''%%--%%ast-dump'' | Was hat der Compiler tatsächlich verstanden? |
| ''%%--%%trace-imports'' | Welche Datei wurde für welchen Import genommen? |
Gemessen an einem Zweizeiler:
=== Aufrufgraph ===
Funktionen: 2, Aufrufkanten: 1
keine Rekursion
von main nicht erreichbar: 0
=== Statische Analyse: Stapelbedarf ===
Lies: 0 lokale Variablen, ca. 0 Byte Rahmen
main: 1 lokale Variablen, ca. 8 Byte Rahmen
groesster Rahmen: ca. 8 Byte
''--trace-imports'' ist der schnellste Weg zu der Frage „warum nimmt er die falsche Unit?" — etwa wenn eine veraltete Fassung im Include-Pfad liegt.
----
===== 6. Das Sicherheits-Audit lesen =====
Jeder Build gibt ein **LCBS Security Audit** aus: welche Capabilities implizit gelten, welche deklariert sind, ob W^X, RELRO und Stack-Canaries aktiv sind. Zwei Zeilen daraus sind für die Fehlersuche nützlich:
* ''Explizite Capabilities: keine'' — dann greift **kein** seccomp-Filter; ein Programm, das trotzdem an einem Syscall stirbt, hat ein anderes Problem.
* Stirbt ein Programm mit ''@capabilities'' stumm an einem Syscall, macht ''--seccomp-trap'' daraus ein ''SIGSYS'' **mit Syscall-Nummer**.
----
===== 7. Bytecode ansehen: lbfdump =====
Für das LBF-Zwischenformat gibt es ein eigenes Werkzeug:
lyxc prog.lyx --target=lyxos --emit=lbf -o prog.lbf
lbfdump -x prog.lbf # Header, Sektionen, Symbole
lbfdump -d prog.lbf # Disassembly
=== LBF File Header (LBF\0 IR) ===
Magic: LBF\0 (4C 42 46 00)
Version: 1
Entry index: 1
Functions: 2
Instructions: 14
=== Symbols (functions) ===
0 Verdopple
1 main
Für das Disassembly gehören ''lbf_opcodes.tsv'' und ''lbf_builtins.tsv'' ins Arbeitsverzeichnis — sonst zeigt ''lbfdump'' ''OP_'' statt der Namen.
----
===== 8. Typische Meldungen und was dahintersteckt =====
^ Meldung ^ Ursache ^
| ''Variable hat Klassentyp ohne Startwert'' | ''new'' oder ''null'' fehlt |
| ''unknown field 'x''' | Tippfehler oder Feld aus einer anderen Klasse — gilt seit 1.1.3D auch über Unit-Grenzen |
| ''undefined function 'T_Methode' — no codegen implementation found'' | Methode existiert nicht (mehr) oder ist nicht ''pub'' |
| ''falsche Argument-Anzahl im Aufruf von …'' | Stelligkeit stimmt nicht — auch bei Methoden importierter Klassen |
| ''Modul nicht gefunden (weder .lyx noch .lyu)'' | Include-Pfad; mit ''--trace-imports'' nachsehen |
| ''expected IDENT, got reserved word 'unit''' | Reserviertes Wort als Bezeichner ([[lyx_-_programmiersprache:sprache:syntax|Schlüsselwortliste]]) |
| ''Speicheranforderung unter @flight_crit nicht erlaubt'' | ''alloc''/''new''/lokales Feld im Regelzyklus |
| ''rc=139'' ohne Meldung | Speicherzugriffsfehler — weiter mit Schritt 2 |
----
===== 9. Wenn es der Compiler ist =====
Ein Bericht, der weiterhilft, enthält:
- **Version**: ''lyxc --version'' (und ob Repo- oder installierte Fassung).
- **Kleinstes Programm**, das den Fehler zeigt — meist zehn Zeilen.
- **Ist** und **Erwartet**, beides als echte Ausgabe.
- **Verhalten mit ''-O0''** gegenüber der Vorgabe.
- Bei Abstürzen: Adresse aus ''gdb'' und die passende Zeile aus der ''.map''-Datei.
Das ist derselbe Aufbau, den die Issues im Compiler-Repository verwenden — und der Grund, warum sie sich meist ohne Rückfrage bearbeiten lassen.
Letzte Aktualisierung: 2026-08-19 — alle Ausgaben mit ''lyxc 1.1.3I'' und ''lbfdump 1.1'' nachgemessen.