code wiki / (root) / nx_dwline_roundtrip_gate.nx

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}