From 78368811c084450dc66cab17fb77bdb7c8742ba7 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sun, 13 Sep 2026 23:30:42 +0700 Subject: [PATCH] The x86 backend's DWARF is checked by a debugger, not by a transcript test_acceptance.ml's lldb case is the only part of the suite that says a person can debug a Flan program: a breakpoint on a Flan name, a backtrace with .flan files and lines, and locals with their own types. It ran against the LLVM backend only. An --x86 arm, with a narrower claim: the breakpoint and the backtrace, and that the program still prints what it printed. No frame variable, because x86.ml emits no DW_TAG_variable -- a slot there is a bump-allocated frame temporary whose lifetime the backend does not model. That gap between the two backends is now recorded in the place it will be read. Worth pinning rather than leaving to a handoff, because everything it exercises is bytes x86.ml wrote by hand -- a line program, a compile unit, an abbreviation table -- and a wrong byte in any of them is silent. debug_compile grows an ~x86 flag beside the ~dev one it already had. --- test/test_acceptance.ml | 49 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index 5455c9e..bd6be1b 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -3105,11 +3105,12 @@ ERR@7 unexpected token: not the kind the caller was reading else print_endline "acceptance: the DWARF verifier cases skipped (no opt)"; (* A debug build and a release build must still be the same program. *) - let debug_compile ?(dev = false) path = + let debug_compile ?(dev = false) ?(x86 = false) path = let exe = Filename.concat scratch ("flan-dbg-" ^ Filename.remove_extension (Filename.basename path) - ^ if dev then "-dev" else "") + ^ (if dev then "-dev" else "") + ^ if x86 then "-x86" else "") in let l = Load.program ~file:path (Reader.read_file path) in let p = Check.program l.Load.decls in @@ -3125,7 +3126,7 @@ ERR@7 unexpected token: not the kind the caller was reading in let p, csrcs, lflags = Reach.link ~dev l p in ignore - (Build.executable ~opts:{ Build.default with debug = true; dev } + (Build.executable ~opts:{ Build.default with debug = true; dev; x86 } ~csrcs ~lflags ~pnames p ~out:exe); exe in @@ -3258,7 +3259,47 @@ ERR@7 unexpected token: not the kind the caller was reading n; print_endline text end) - [ "flan.tick"; "flan.main at debug.flan:" ] + [ "flan.tick"; "flan.main at debug.flan:" ]; + + (* And the same program through the hand-written x86-64 backend, which + emits its own DWARF rather than handing LLVM metadata. + + The claim is narrower than the one above and deliberately so: a + breakpoint resolved on a Flan name, and a backtrace whose frames name + a .flan file and a line. No [frame variable], because [x86.ml] emits + no [DW_TAG_variable] -- a slot there is a bump-allocated frame + temporary whose lifetime the backend does not model, and a name + attached to an offset something else reuses would be a lie. That is + the gap between the two backends and this is where it is recorded. + + Worth pinning rather than leaving to a handoff's transcript, because + everything this exercises is bytes [x86.ml] wrote by hand -- a line + program, a compile unit and an abbreviation table -- and a wrong byte + in any of them is silent. The program still printing the same four + lines is checked too, since debug information that breaks the build + it describes has helped nobody. *) + let exe = debug_compile ~x86:true "programs/debug.flan" in + let code, text = run exe None in + if text <> expected || code <> 0 then begin + incr failures; + Printf.printf + "FAIL an --x86 --debug build of debug.flan runs the same\n\ + \ got: %S (exit %d)\n wanted: %S\n" + text code expected + end; + let _, text = + lldb_run exe [ "breakpoint set --name flan.tick"; "run"; "bt" ] + in + List.iter + (fun n -> + if not (contains text n) then begin + incr failures; + Printf.printf + "FAIL lldb: --x86 --debug names Flan files and lines\n\ + \ wanted %S\n" n; + print_endline text + end) + [ "flan.tick"; "at debug.flan:"; "flan.main at debug.flan:" ] end else print_endline "acceptance: lldb cases skipped (no lldb on PATH)";