nx_toolchain.nx source
↩ module page · 169 lines · 5498 B
1// nx_toolchain.nx -- unified entry point for the off-C tools.
2//
3// Replaces the binutils + qemu suite with a single binary that
4// dispatches subcommands:
5//
6// nx readelf <path.elf> -- full ELF dump
7// nx nm <path.elf> -- list symbols
8// nx objdump <path.elf> -- section headers
9// nx dis <path.bin> <off> -- disassemble bytes
10// nx run <path.elf> -- load + simulate
11// nx help -- list commands
12//
13// Compile this once into a tiny binary; it covers the entire
14// off-C inspection / debug / run workflow. No more invoking
15// 5+ separate binutils tools per session.
16//
17// Pairs with nxc_native_wrap (the bootstrap-verification binary)
18// as the day-to-day developer-facing tool.
19
20// nx_safety_envelope:
21// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
22// sil_target: SIL1
23// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
24// verdict: NOT_YET_EVALUATED
25
26import "syscalls.nx"
27import "nx_elf_read.nx"
28import "nx_objdump.nx"
29import "nx_nm.nx"
30import "nx_readelf.nx"
31import "nx_dis.nx"
32import "nx_loader.nx"
33import "nx_rv64_sim.nx"
34
35// Read entire file into a fresh mmap'd buffer.
36func nx_tc_read_file(path: *u8, out_len: *i64) -> *u8 {
37 let fd: i64 = sys_openat_rd(path)
38 if fd < 0 { *out_len = 0; return 0 as *u8 }
39 let cap: i64 = 16777216 // 16 MB max
40 let buf: *u8 = sys_mmap(cap)
41 var total: i64 = 0
42 var go: i64 = 1
43 while go == 1 {
44 let base: i64 = buf as i64
45 let tail: *u8 = (base + total) as *u8
46 let n: i64 = sys_read(fd, tail, cap - total)
47 if n <= 0 { go = 0 }
48 if n > 0 { total = total + n }
49 if total >= cap { go = 0 }
50 }
51 sys_close(fd)
52 *out_len = total
53 return buf
54}
55
56// Compare a NUL-terminated C-string against a literal byte sequence.
57// streq canonical in runtime.nx.
58
59func nx_tc_help(fd: i64) -> i64 {
60 sys_write(fd, "nx-toolchain commands:\n" as *u8, 23)
61 sys_write(fd, " nx readelf <elf> -- full ELF dump\n" as *u8, 38)
62 sys_write(fd, " nx nm <elf> -- list symbols\n" as *u8, 37)
63 sys_write(fd, " nx objdump <elf> -- section headers\n" as *u8, 41)
64 sys_write(fd, " nx dis <bin> <bytes> -- disassemble RV64\n" as *u8, 47)
65 sys_write(fd, " nx run <elf> -- simulate ELF (RV64I)\n" as *u8, 46)
66 sys_write(fd, " nx help -- this message\n" as *u8, 37)
67 return 0
68}
69
70func main(argc: i64, argv: *i64) -> i64 {
71 if argc < 2 {
72 nx_tc_help(2)
73 return 1
74 }
75 let cmd: *u8 = (argv[1]) as *u8
76
77 if streq(cmd, "help" as *u8) == 1 {
78 nx_tc_help(1)
79 return 0
80 }
81
82 if streq(cmd, "readelf" as *u8) == 1 {
83 if argc < 3 {
84 sys_write(2, "usage: nx readelf <elf>\n" as *u8, 24)
85 return 1
86 }
87 let len_raw: *u8 = sys_mmap(16)
88 let len: *i64 = len_raw as *i64
89 *len = 0
90 let buf: *u8 = nx_tc_read_file((argv[2]) as *u8, len)
91 if buf == (0 as *u8) {
92 sys_write(2, "open failed\n" as *u8, 12)
93 return 2
94 }
95 nx_readelf_all(buf, *len, 1)
96 return 0
97 }
98
99 if streq(cmd, "nm" as *u8) == 1 {
100 if argc < 3 {
101 sys_write(2, "usage: nx nm <elf>\n" as *u8, 19)
102 return 1
103 }
104 let len_raw: *u8 = sys_mmap(16)
105 let len: *i64 = len_raw as *i64
106 *len = 0
107 let buf: *u8 = nx_tc_read_file((argv[2]) as *u8, len)
108 if buf == (0 as *u8) { return 2 }
109 nx_nm_print(buf, *len, 1)
110 return 0
111 }
112
113 if streq(cmd, "objdump" as *u8) == 1 {
114 if argc < 3 {
115 sys_write(2, "usage: nx objdump <elf>\n" as *u8, 24)
116 return 1
117 }
118 let len_raw: *u8 = sys_mmap(16)
119 let len: *i64 = len_raw as *i64
120 *len = 0
121 let buf: *u8 = nx_tc_read_file((argv[2]) as *u8, len)
122 if buf == (0 as *u8) { return 2 }
123 nx_objdump_section_headers(buf, *len, 1)
124 return 0
125 }
126
127 if streq(cmd, "dis" as *u8) == 1 {
128 if argc < 3 {
129 sys_write(2, "usage: nx dis <bin>\n" as *u8, 20)
130 return 1
131 }
132 let len_raw: *u8 = sys_mmap(16)
133 let len: *i64 = len_raw as *i64
134 *len = 0
135 let buf: *u8 = nx_tc_read_file((argv[2]) as *u8, len)
136 if buf == (0 as *u8) { return 2 }
137 // Disassemble all bytes 0..len in 4-byte steps.
138 nx_dis_range(buf, 0, *len, 1)
139 return 0
140 }
141
142 if streq(cmd, "run" as *u8) == 1 {
143 if argc < 3 {
144 sys_write(2, "usage: nx run <elf>\n" as *u8, 20)
145 return 1
146 }
147 let len_raw: *u8 = sys_mmap(16)
148 let len: *i64 = len_raw as *i64
149 *len = 0
150 let buf: *u8 = nx_tc_read_file((argv[2]) as *u8, len)
151 if buf == (0 as *u8) { return 2 }
152 let mem: *u8 = sys_mmap(16777216)
153 let entry: i64 = nx_loader_load(buf, *len, mem, 16777216)
154 if entry < 0 {
155 sys_write(2, "load failed\n" as *u8, 12)
156 return 3
157 }
158 let cpu: *NxRv64Cpu = nx_rv64_cpu_new(mem, 16777216, entry)
159 nx_rv64_cpu_set_sp(cpu, 16777216 - 64)
160 let r: i64 = nx_rv64_run(cpu, 100000000)
161 if r == 0 { return cpu.exit_code }
162 if r > 0 { return 4 } // budget
163 return 5 // illegal
164 }
165
166 sys_write(2, "unknown command\n" as *u8, 16)
167 nx_tc_help(2)
168 return 1
169}