code wiki / _hdl_build / nx_undefscan.nx
nx_undefscan.nx
buildroot/runtime/_hdl_build/nx_undefscan.nx
about
nx_undefscan.nx -- THE MISSING-SYMBOL CENSUS: report EVERY function a target calls that nobody in its
import closure defines, WITHOUT compiling it.
WHY THIS EXISTS. The compiler reports undefined symbols ONE AT A TIME, and only AFTER expand_imports
succeeds -- so a single mis-layered import hides an unknown number of missing functions behind it, and
the outer explanation (bad import) is always true enough to stop the investigation. Measured
2026-07-31: un-darkening 14 libs exposed SEVEN undefined functions no build could ever have reported --
nx_pctl_kill_by_cmdline (2 callers), the whole nx_fft decomposed API (4 consumers), nx_bm25_score
(5 callers). Each fix revealed the next, so the count was never knowable in advance. This organ makes
it knowable in ONE pass: walk the closure, collect every definition, collect every call site, print
the DIFFERENCE AS A LIST rather than as the first error.
WHAT IT IS NOT. A textual resolver, not the compiler. Two known ways it can be wrong, stated here so a
caller never has to guess:
- a call THROUGH A FUNCTION-POINTER VARIABLE looks like an undefined call (false positive)
- a symbol the compiler itself provides, if any exist, has no .nx definition (false positive)
Both are bounded by the POSITIVE CONTROL: a target that BUILDS must report ZERO. Any residue on a
building target IS that false-positive set, and must be fixed here rather than explained away.
PARTIAL IS NOT A SMALLER CLEAN (the 07-31 layerscan law, built in as a tooth). If any import in the
closure resolves to no file, or the queue overflows, the definition set is INCOMPLETE -- so every
undefined it prints may merely be defined in the file it could not read. In that state the verdict is
PARTIAL and a ZERO count exits NONZERO, because a clean report from a truncated scan is the exact lie
this class of instrument keeps telling.
nx_undefscan scan <target> -- target = basename WITHOUT .nx, resolved runtime/ then _hdl_build/
EXIT: 0 CLEAN+COMPLETE - 1 UNDEFINED FOUND - 2 usage - 3 target not found - 5 PARTIAL (cannot certify)
license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 31 | const US_MAXF: i64 = 512 |
| 32 | const US_NAMELEN: i64 = 64 |
| 33 | const US_SLOTS: i64 = 32768 |
| 34 | const US_PATHBUF: i64 = 1024 |
| 35 | const US_RTDIR: *u8 = "buildroot/runtime" as *u8 |
| 36 | const US_HDDIR: *u8 = "buildroot/runtime/_hdl_build" as *u8 |
| 37 | const US_HUBDIR: *u8 = "buildroot/runtime/hub" as *u8 |
| 38 | const US_WIKIDIR: *u8 = "buildroot/runtime/wiki" as *u8 |
| 96 | const US_FNV_OFF: i64 = 1469598103934665603 |
| 97 | const US_FNV_PRIME: i64 = 1099511628211 |
| 98 | const US_EXIT_UNDEF: i64 = 1 |
| 99 | const US_EXIT_USAGE: i64 = 2 |
| 100 | const US_EXIT_NOTFOUND: i64 = 3 |
| 101 | const US_EXIT_PARTIAL: i64 = 5 |
| 102 | const US_EXIT_SELFTEST: i64 = 4 |
| 103 | const US_BICONF: *u8 = "knowledge/undefscan_builtins.conf" as *u8 |
| 104 | const US_UNDEFCAP: i64 = 256 |
| 105 | const US_DIRBUF: i64 = 1048576 |
| 1020 | const US_ARUNK: i64 = 0 - 2 |
| 1021 | const US_ARAMB: i64 = 0 - 3 |
functions
| 47 | func us_resolve(path: *u8, nm: *u8) -> i64 |
| 73 | func us_dirp(id: i64) -> *u8 called by 1: us_resolve_dir |
| 83 | func us_resolve_dir(path: *u8, nm: *u8, prefid: i64) -> i64 |
| 115 | func us_puts(s: *u8) |
| 121 | func us_putn(p: *u8, n: i64) { sys_write(1, p, n) } |
| 123 | func us_puti(x: i64) |
| 140 | func us_isidst(c: i64) -> i64 |
| 147 | func us_isidc(c: i64) -> i64 called by 6: us_declare_nextus_scanus_scan_declsus_collect_declsus_collect_arityus_check_arity calls 1: us_isidst |
| 153 | func us_eqlit(p: *u8, L: i64, lit: *u8, litlen: i64) -> i64 |
| 165 | func us_iskw(p: *u8, L: i64) -> i64 |
| 196 | func us_is_dunder(p: *u8) -> i64 |
| 202 | func us_hash(s: *u8, n: i64) -> i64 |
| 215 | func us_slot(tab: *u8, i: i64) -> *u8 { return ((tab as i64) + i * US_NAMELEN) as *u8 } |
| 218 | func us_put(tab: *u8, s: *u8, n: i64) -> i64 |
| 246 | func us_has(tab: *u8, s: *u8, n: i64) -> i64 |
| 270 | func us_qpush(q: *u8, cnt: i64, src: *u8, n: i64) -> i64 |
| 290 | func us_path(out: *u8, dir: *u8, name: *u8) |
| 304 | func us_exists(path: *u8) -> i64 called by 5: us_resolveus_resolve_dirus_dupescanus_resolve_prefus_rootdir calls 2: sys_openat_rdsys_close |
| 314 | func us_load_builtins(tab: *u8) -> i64 |
| 356 | func us_declare_next(buf: *u8, n: i64, from: i64, defs: *u8) -> i64 |
| 376 | func us_isdig(c: i64) -> i64 called by 1: us_scan |
| 383 | func us_scan(buf: *u8, n: i64, defs: *u8, calls: *u8, refs: *u8, q: *u8, qcnt: i64) -> i64 called by 3: us_scan_oneus_arity_onemain calls 8: us_isdigus_isidcus_isidstus_eqlitus_declare_nextus_qpush+2 |
| 551 | func us_scan_decls(buf: *u8, n: i64, und: *u8, undcnt: i64, src: *u8, fname: *u8) -> i64 |
| 622 | func us_corpus_dir(dir: *u8, und: *u8, undcnt: i64, src: *u8) -> i64 called by 1: main calls 9: sys_openat_rdsys_mmapsys_getdents64dirent_reclendirent_namesys_read_file+3 |
| 674 | func us_collect_decls(buf: *u8, n: i64, tab: *u8) -> i64 |
| 735 | func us_scan_one(name: *u8, bi: *u8, flag: *i64) -> i64 |
| 807 | func us_sweep(dir: *u8, off0: i64, lim: i64, bi: *u8) -> i64 |
| 873 | func us_join(out: *u8, dir: *u8, name: *u8) called by 1: us_dupescan |
| 890 | func us_dupescan(dir: *u8) -> i64 |
| 1023 | func us_alen(s: *u8) -> i64 called by 1: us_arity_selftest |
| 1031 | func us_index(tab: *u8, s: *u8, n: i64) -> i64 |
| 1060 | func us_commas(buf: *u8, n: i64, op: i64) -> i64 |
| 1126 | func us_collect_arity(buf: *u8, n: i64, defs: *u8, defar: *i64) -> i64 |
| 1225 | func us_check_arity(buf: *u8, n: i64, defs: *u8, defar: *i64, fname: *u8) -> i64 called by 2: us_arity_selftestus_arity_one calls 8: us_isidstus_isidcus_iskwus_indexus_commasus_puts+2 |
| 1313 | func us_arity_selftest() -> i64 |
| 1385 | func us_resolve_pref(path: *u8, nm: *u8, pref: *u8) -> i64 |
| 1396 | func us_rootdir(nm: *u8, path: *u8) -> *u8 |
| 1408 | func us_arity_one(name: *u8, flag: *i64) -> i64 |
| 1500 | func main(argc: i64, argv: *i64) -> i64 |