nx_dwline_roundtrip_gate.nx source
↩ module page · 156 lines · 8990 B
1// nx_dwline_roundtrip_gate.nx -- DOES OUR DWARF ENCODER PRODUCE A TABLE OUR DECODER READS BACK?
2//
3// WHY THIS EXISTS. DDR-002 shipped .debug_line (compiler emits .file/.loc -> nxasm builds the line
4// program -> ELF carries the section) and named its own falsification condition:
5// "If nx_addr2line cannot round-trip a table nx_dwline_* produced, the two organs disagree
6// about the format and the arc is blocked on reconciling them."
7// That condition was NEVER TESTED. The capability had no gate at all, and by this estate's own
8// doctrine an ungated capability cannot be honestly graded on /compare -- whose subtitle promises
9// "Nishi cells measured (gates with dates)". This file is that measurement.
10//
11// WHY IT IS A REAL TWO-SYSTEM CHECK. nx_dwarf_line.nx (encoder) and nx_addr2line_lib.nx (decoder)
12// share NO code and deliberately repeat the DWARF opcode constants separately. So agreement here is
13// evidence, not a system agreeing with itself. Do not "clean up" that duplication.
14//
15// WHY THESE ADDRESSES. 0x400096 -> line 5 and 0x4000AD -> line 9 are the exact pairs an EXTERNAL
16// oracle (GNU readelf) resolved from a real sovereign ELF built from nx_probe_dbgtiny.nx. Pinning
17// the gate to externally-confirmed values means a regression cannot be hidden by changing both
18// sides at once.
19//
20// CALL SEQUENCE IS COPIED FROM PRODUCTION (nxasm_x86_main.nx: new -> header -> set_address ->
21// record* -> end_sequence -> finish). A gate that exercised a different sequence would be measuring
22// something other than what ships -- the instrument-subject mismatch this estate keeps paying for.
23//
24// license_tier: ORIGINAL expect_exit: 0
25import "syscalls.nx"
26import "nx_dwarf_line.nx"
27import "nx_addr2line_lib.nx"
28import "nx_gate_verdict.nx"
29
30const DRG_A0: i64 = 0x400096 // readelf-confirmed: line 5
31const DRG_A1: i64 = 0x4000AD // readelf-confirmed: line 9
32const DRG_A2: i64 = 0x4000C0 // third row, so "distinct lines" is testable
33const DRG_MID: i64 = 0x4000A0 // strictly between A0 and A1
34const DRG_BEFORE: i64 = 0x400000 // strictly before the first row
35const DRG_CAP: i64 = 65536
36
37// little-endian u32 read, so the gate can check nx_dwline_finish's unit_length patch itself
38// rather than trusting the encoder's own report of how many bytes it wrote.
39func drg_u32(b: *u8, off: i64) -> i64 {
40 var v: i64 = 0
41 v = v + (b[off] as i64)
42 v = v + ((b[off+1] as i64) * 256)
43 v = v + ((b[off+2] as i64) * 65536)
44 v = v + ((b[off+3] as i64) * 16777216)
45 return v
46}
47
48// Build a line program EXACTLY the way nxasm_x86_main.nx does.
49func drg_build(outlen: *i64) -> *u8 {
50 let name: *u8 = "nx_probe_dbgtiny.nx" as *u8
51 let foff: *i64 = sys_mmap(16) as *i64
52 let flen: *i64 = sys_mmap(16) as *i64
53 foff[0] = 0
54 flen[0] = 19
55
56 let dw: *NxDwLine = nx_dwline_new(DRG_CAP)
57 nx_dwline_header(dw, name, foff, flen, 1)
58 nx_dwline_set_address(dw, DRG_A0)
59 nx_dwline_record(dw, DRG_A0, 1, 5)
60 nx_dwline_record(dw, DRG_A1, 1, 9)
61 nx_dwline_record(dw, DRG_A2, 1, 12)
62 nx_dwline_end_sequence(dw)
63 nx_dwline_finish(dw)
64
65 outlen[0] = nx_dwline_size(dw)
66 return nx_dwline_bytes(dw)
67}
68
69func main() -> i64 {
70 let ctr: *i64 = gv_ctr()
71 gv_head("=== NX-DWLINE-ROUNDTRIP GATE -- sovereign DWARF encoder vs sovereign decoder ===" as *u8)
72
73 let lenbox: *i64 = sys_mmap(16) as *i64
74 let buf: *u8 = drg_build(lenbox)
75 let blen: i64 = lenbox[0]
76
77 // T1 -- non-vacuity. Every assertion below is meaningless if nothing was encoded.
78 gv_check("encoder-produced-bytes" as *u8, (blen > 32) as i64, ctr)
79
80 // T2 -- nx_dwline_finish patches unit_length to (used - 4), checked by re-reading the bytes.
81 gv_check("unit-length-patched" as *u8, (drg_u32(buf, 0) == blen - 4) as i64, ctr)
82
83 // SECTION entry point: the encoder emits a complete v5 unit (header + program), so the decoder
84 // must be handed the unit. Using nx_a2l_run here fed a header to a program VM and found nothing.
85 let r0: *NxA2LResult = nx_a2l_run_section(buf, blen, DRG_A0)
86 let r1: *NxA2LResult = nx_a2l_run_section(buf, blen, DRG_A1)
87 let r2: *NxA2LResult = nx_a2l_run_section(buf, blen, DRG_A2)
88
89 // T3/T4/T5 -- the readelf-confirmed pairs survive OUR decoder.
90 gv_check("row0-addr-0x400096-is-line-5" as *u8, ((r0.found == 1) & (r0.line == 5)) as i64, ctr)
91 gv_check("row1-addr-0x4000AD-is-line-9" as *u8, ((r1.found == 1) & (r1.line == 9)) as i64, ctr)
92 gv_check("row2-line-12" as *u8, ((r2.found == 1) & (r2.line == 12)) as i64, ctr)
93
94 // T6 -- exact row address is reported, not merely "some row".
95 gv_check("row0-reports-its-own-address" as *u8, (r0.addr == DRG_A0) as i64, ctr)
96
97 // T7 -- LOAD-BEARING. An address BETWEEN two rows must resolve to the PRECEDING row. A decoder
98 // that returned the nearest row, or the next one, or simply the last row it parsed, passes
99 // T3..T5 and FAILS here. A TOOTH THE WRONG IMPLEMENTATION ALSO PASSES IS NOT A TOOTH.
100 let rm: *NxA2LResult = nx_a2l_run_section(buf, blen, DRG_MID)
101 gv_check("between-rows-resolves-to-preceding" as *u8, ((rm.found == 1) & (rm.line == 5) & (rm.addr == DRG_A0)) as i64, ctr)
102
103 // T8 -- file index survives the v5 entry-0 duplicate in the header.
104 // BOUND TO found. This tooth PASSED while the decoder was returning nothing at all, because
105 // NxA2LResult initialises file_idx to 1 -- it was asserting the default, not the round-trip.
106 // A TOOTH THAT PASSES ON THE FAILURE STATE IS NOT A TOOTH.
107 gv_check("file-index-roundtrips" as *u8, ((r0.found == 1) & (r0.file_idx == 1)) as i64, ctr)
108
109 // The header parse must be REAL, not incidental: a unit claiming DWARF v4 must be refused
110 // rather than decoded at a guessed offset. Mutate the version field of a valid unit.
111 let mut4: *u8 = sys_mmap(DRG_CAP)
112 var ci: i64 = 0
113 while ci < blen { mut4[ci] = buf[ci]; ci = ci + 1 }
114 mut4[4] = 4 as u8
115 let r4: *NxA2LResult = nx_a2l_run_section(mut4, blen, DRG_A0)
116 gv_check("neg-control-wrong-dwarf-version-refused" as *u8, (r4.found == 0) as i64, ctr)
117
118 // And the bare-program entry point must STILL behave as before on a unit (finds nothing),
119 // which is what proves the two contracts are genuinely distinct rather than one wrapping a bug.
120 let rbare: *NxA2LResult = nx_a2l_run(buf, blen, DRG_A0)
121 gv_check("bare-program-entry-unchanged-on-a-unit" as *u8, (rbare.found == 0) as i64, ctr)
122
123 // T9 -- NEGATIVE CONTROL. Before the first address there is no row, and the decoder must SAY SO
124 // rather than produce a confident wrong answer. found=0 is the only honest result.
125 let rb: *NxA2LResult = nx_a2l_run_section(buf, blen, DRG_BEFORE)
126 gv_check("neg-control-before-first-addr-not-found" as *u8, (rb.found == 0) as i64, ctr)
127
128 // T10 -- NEGATIVE CONTROL on the INSTRUMENT. Fed a buffer that is not a line program at all, the
129 // decoder must not report a hit. Without this, a decoder that always answered "found" would pass
130 // every positive tooth above.
131 let zeros: *u8 = sys_mmap(256)
132 let rz: *NxA2LResult = nx_a2l_run_section(zeros, 256, DRG_A0)
133 gv_check("neg-control-not-a-line-program" as *u8, (rz.found == 0) as i64, ctr)
134
135 // T11 -- ANTI-VACUITY on the decode: the three rows must yield three DISTINCT lines. A decoder
136 // returning a constant satisfies any single positive assertion.
137 gv_check("three-rows-three-distinct-lines" as *u8, ((r0.line != r1.line) & (r1.line != r2.line) & (r0.line != r2.line)) as i64, ctr)
138
139 // DIAGNOSTIC. A gate that reports only PASS/FAIL cannot say WHY, and the failure pattern here
140 // (positives fail, negative controls pass) is consistent with the decoder never finding a row at
141 // all -- but "consistent with" is not "measured". Print what it actually returned.
142 gv_puts("\n --- decoder returned ---\n" as *u8)
143 gv_puts(" section_bytes=" as *u8); gv_num(blen); gv_puts("\n" as *u8)
144 gv_puts(" A0 found=" as *u8); gv_num(r0.found); gv_puts(" line=" as *u8); gv_num(r0.line)
145 gv_puts(" addr=" as *u8); gv_num(r0.addr); gv_puts(" file=" as *u8); gv_num(r0.file_idx); gv_puts("\n" as *u8)
146 gv_puts(" A1 found=" as *u8); gv_num(r1.found); gv_puts(" line=" as *u8); gv_num(r1.line)
147 gv_puts(" addr=" as *u8); gv_num(r1.addr); gv_puts("\n" as *u8)
148 gv_puts(" A2 found=" as *u8); gv_num(r2.found); gv_puts(" line=" as *u8); gv_num(r2.line)
149 gv_puts(" addr=" as *u8); gv_num(r2.addr); gv_puts("\n" as *u8)
150
151 // EXIT CODE MUST TRACK THE VERDICT. First version returned 0 unconditionally, so /api/gate_run
152 // -- which derives its verdict FROM THE EXIT CODE -- reported GREEN over a gate printing RED 5/11.
153 // A GATE WHOSE EXIT CODE DOES NOT CARRY ITS VERDICT SILENTLY BLESSES EVERY FAILURE IT FINDS.
154 return gv_verdict("nx_dwline_roundtrip_gate" as *u8, ctr,
155 "encoder nx_dwarf_line.nx vs independent decoder nx_addr2line_lib.nx; addresses pinned to GNU readelf output on a real sovereign ELF" as *u8)
156}