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.

Compiler-Parameter · lbfdump · 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 (#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 (#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   <entry>

Für das Disassembly gehören lbf_opcodes.tsv und lbf_builtins.tsv ins Arbeitsverzeichnis — sonst zeigt lbfdump OP_<n> 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 (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:

  1. Version: lyxc –version (und ob Repo- oder installierte Fassung).
  2. Kleinstes Programm, das den Fehler zeigt — meist zehn Zeilen.
  3. Ist und Erwartet, beides als echte Ausgabe.
  4. Verhalten mit -O0 gegenüber der Vorgabe.
  5. 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.