code wiki / _hdl_build / nx_doctor_sov_verify.nx
nx_doctor_sov_verify.nx source
↩ module page · 135 lines · 6792 B
1// nx_doctor_sov_verify.nx -- the NISHI DOCTOR's one-step batch sovereign verifier (operator: "have the
2// nishi doctor get tutored to do this in one step and less than ten seconds"). ONE invocation builds +
3// runs + reports MANY modules through the pure-sovereign path (nx_cc -> nxasm_x86 -> run, NO gcc, NO .sh,
4// NO shell loop -- the loop is NishiLang, so it never hits the wsl $VAR-mangling trap). Each module:
5// compile (stdout->/tmp/<m>.s, stderr muted, recompile-retry), assemble+link with nxasm_x86_main, run,
6// capture the real exit via sys_wait4. Prints one line per module + a PASS/FAIL summary; exits 0 iff all
7// passed (treats the module's own expect_exit==0 convention). Usage:
8// nx_doctor_sov_verify <module1> <module2> ...
9// license_tier: ORIGINAL Reuses the sovereign spine from nx_sov_build_run.
10import "nx_syscalls.nx"
11const DSV_MAGIC_4096: i64 = 4096
12
13const DSV_MIN_ASM_BYTES: i64 = 128
14const DSV_MAX_RETRIES: i64 = 12
15const DSV_RUN_TIMEOUT_MS: i64 = 8000 // the <10s law: a hung module is KILLED + reported, never waited on
16
17func dsv_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
18func dsv_putn(v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=48+(m%10); m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(1, bb, k); return 0 }
19func dsv_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
20
21// fork + stdout/stderr redirect + execve; parent waits; returns child's WEXITSTATUS.
22func dsv_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 {
23 let pid: i64 = sys_fork()
24 if pid == 0 {
25 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) }
26 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) }
27 sys_execve(path, argv, envp)
28 sys_exit(127)
29 }
30 let st: *i64 = sys_mmap(16) as *i64
31 sys_wait4(pid, st, 0)
32 return (st[0] >> 8) & 0xff
33}
34
35func dsv_filesize(path: *u8) -> i64 {
36 let fd: i64 = sys_openat_rd(path)
37 if fd < 0 { return 0 }
38 let buf: *u8 = sys_mmap(DSV_MAGIC_4096)
39 var total: i64 = 0
40 var n: i64 = sys_read(fd, buf, DSV_MAGIC_4096)
41 while n > 0 { total = total + n; n = sys_read(fd, buf, DSV_MAGIC_4096) }
42 sys_close(fd)
43 return total
44}
45
46// build ONE module through the sovereign path; return its run-exit, or a negative code on build failure.
47// -3 = compile-fail (empty .s after retries) ; -4 = nxasm-fail (unencoded instruction)
48func dsv_build_run_one(name: *u8, compiler: *u8, asm_tool: *u8, envp: *i64, devnull: i64) -> i64 {
49 let src: *u8 = sys_mmap(512); var o: i64 = 0
50 o = dsv_cat(src, o, "runtime/_hdl_build/" as *u8); o = dsv_cat(src, o, name); o = dsv_cat(src, o, ".nx" as *u8); src[o] = 0 as u8
51 let chk: i64 = sys_openat_rd(src)
52 if chk < 0 { o = 0; o = dsv_cat(src, o, "runtime/" as *u8); o = dsv_cat(src, o, name); o = dsv_cat(src, o, ".nx" as *u8); src[o] = 0 as u8 }
53 if chk >= 0 { sys_close(chk) }
54 let spath: *u8 = sys_mmap(256); o = 0
55 o = dsv_cat(spath, o, "/tmp/" as *u8); o = dsv_cat(spath, o, name); o = dsv_cat(spath, o, ".s" as *u8); spath[o] = 0 as u8
56 let elfpath: *u8 = sys_mmap(256); o = 0
57 o = dsv_cat(elfpath, o, "/tmp/" as *u8); o = dsv_cat(elfpath, o, name); o = dsv_cat(elfpath, o, ".sov.elf" as *u8); elfpath[o] = 0 as u8
58
59 var asmbytes: i64 = 0
60 var tries: i64 = 0
61 while tries < DSV_MAX_RETRIES {
62 let sfd: i64 = sys_openat_wr(spath, 0x1a4)
63 let cc: *i64 = sys_mmap(8*4) as *i64
64 cc[0] = compiler as i64; cc[1] = src as i64; cc[2] = 0
65 dsv_run(compiler, cc, envp, sfd, devnull)
66 sys_close(sfd)
67 asmbytes = dsv_filesize(spath)
68 if asmbytes > DSV_MIN_ASM_BYTES { tries = DSV_MAX_RETRIES }
69 if tries != DSV_MAX_RETRIES { tries = tries + 1 }
70 }
71 if asmbytes <= DSV_MIN_ASM_BYTES { return 0 - 3 }
72
73 let aa: *i64 = sys_mmap(8*4) as *i64
74 aa[0] = asm_tool as i64; aa[1] = spath as i64; aa[2] = elfpath as i64; aa[3] = 0
75 let rc_a: i64 = dsv_run(asm_tool, aa, envp, 0 - 1, devnull)
76 if rc_a != 0 { return 0 - 4 }
77
78 let rr: *i64 = sys_mmap(8*4) as *i64
79 rr[0] = elfpath as i64; rr[1] = 0
80 return dsv_run_watchdog(elfpath, rr, envp, DSV_RUN_TIMEOUT_MS) // stdout passes through; hung = killed
81}
82
83// run under a SOVEREIGN WATCHDOG: a timer child sleeps then kills the test pid. A module that
84// hangs (the 7-minute jam-check spin) is killed at the deadline and reported as -9, instead of
85// the Doctor inheriting the hang. wait4 on both children -- no zombies.
86func dsv_run_watchdog(path: *u8, argv: *i64, envp: *i64, timeout_ms: i64) -> i64 {
87 let pid: i64 = sys_fork()
88 if pid == 0 {
89 sys_execve(path, argv, envp)
90 sys_exit(127)
91 }
92 let wd: i64 = sys_fork()
93 if wd == 0 {
94 sys_sleep_ms(timeout_ms)
95 nx_kill(pid, 9)
96 sys_exit(0)
97 }
98 let st: *i64 = sys_mmap(16) as *i64
99 sys_wait4(pid, st, 0)
100 nx_kill(wd, 9)
101 let st2: *i64 = sys_mmap(16) as *i64
102 sys_wait4(wd, st2, 0)
103 if (st[0] % 256) != 0 { return 0 - 9 } // signal-killed (timeout watchdog or crash)
104 return (st[0] >> 8) & 0xff
105}
106
107func main(argc: i64, argv: *i64) -> i64 {
108 if argc < 2 { dsv_puts("usage: nx_doctor_sov_verify <module1> <module2> ...\n" as *u8); sys_exit(2); return 2 }
109 let compiler: *u8 = "_offc/nx_cc_known_good.elf" as *u8
110 let asm_tool: *u8 = "_offc/nxasm_x86_main.elf" as *u8
111 let envp: *i64 = sys_mmap(8*4) as *i64
112 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
113 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
114
115 dsv_puts("=== NISHI DOCTOR sovereign batch verify (nx_cc->nxasm_x86->run, no gcc/sh) ===\n" as *u8)
116 var pass: i64 = 0
117 var total: i64 = 0
118 var i: i64 = 1
119 while i < argc {
120 let name: *u8 = argv[i] as *u8
121 let rc: i64 = dsv_build_run_one(name, compiler, asm_tool, envp, devnull)
122 total = total + 1
123 dsv_puts(" DOCTOR module=" as *u8); dsv_puts(name); dsv_puts(" exit=" as *u8); dsv_putn(rc)
124 if rc == 0 { dsv_puts(" PASS\n" as *u8); pass = pass + 1 }
125 if rc == 0 - 3 { dsv_puts(" BUILD-FAIL(compile)\n" as *u8) }
126 if rc == 0 - 4 { dsv_puts(" BUILD-FAIL(nxasm-unencoded)\n" as *u8) }
127 if rc == 0 - 9 { dsv_puts(" TIMEOUT/SIGNAL(watchdog-killed)\n" as *u8) }
128 if rc > 0 { dsv_puts(" FAIL(runtime exit)\n" as *u8) }
129 i = i + 1
130 }
131 dsv_puts("DOCTOR SUMMARY pass=" as *u8); dsv_putn(pass); dsv_puts("/" as *u8); dsv_putn(total); dsv_puts("\n" as *u8)
132 if pass == total { sys_exit(0) }
133 sys_exit(1)
134 return 1
135}