mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Host unit-test harness
Compile and test individual firmware translation units on the build host with
gcc + AddressSanitizer + UBSan — no SDCC, no flashing, no hardware. This is
the fast inner loop for the logic-level bugs in ../../NOTES/08-findings.md
(parser, line editor, HTTP header, DHCP): edit → make → see red/green in
seconds instead of a minutes-long flash-and-reboot cycle.
Run
cd test
make # build + run all tests (ASan/UBSan on)
make clean
Exit status is non-zero if any check fails, a sanitizer trips, or the watchdog fires — so it drops straight into CI.
How it works
sdcc_shim.h(force-included) erases SDCC 8051 keywords (__xdata,__code,__banked, …) so firmware sources compile under host gcc. It changes no logic — the code under test is byte-for-byte the firmware source.hw_mock.c/hw_mock.hsimulate the ASIC edge: a flat register file behindreg_read/reg_writeand theSFR_DATA_*registers, with a table engine that performs a VLAN or L2 operation the momentTBL_CTRLis written, fetches a MIB counter onSTAT_GETand drops entries onL2_TBL_FLUSH_CTRL. Nothing ever reports busy, so a polling loop runs once. The header states the VLAN and L2 entry layouts independently of the firmware, so a test can hold whatrtl837x_port.cwrites against whatpage_impl.creads.env_tables.ccarries the globals and leaf calls those two modules link against;stub/stands in for the two headers only a firmware build generates, so the harness needs no SDCC build first.support.c/support.hmock the hardware edges: the 16-byte serial ring (sbuf), the command/history buffers, and the character-output sink (write_charetc.). Buffers are sized exactly as on target, so ASan redzones catch the same off-by-one overflows the 8051 hits.- Builds define
RTLP_HOST_TEST, which hides the firmware's libc-named prototypes (memset/strlen/…) inrtl837x_common.hso they don't clash with glibc. Argument order matches libc, so on-host callers transparently use the C library. This guard is compiled out of normal firmware builds — zero on-target effect. - A SIGALRM watchdog (
watchdog_arm) turns an infinite-loop bug into a fast test failure instead of a hung runner.
Current coverage
| Test binary | TU under test | Findings exercised |
|---|---|---|
test_cmd_editor |
cmd_editor.c |
C4 — full-line hang + cmd_buffer 1-byte overflow; basic entry & backspace regressions |
test_port_tables |
rtl837x_port.c |
VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
test_page_json |
httpd/page_impl.c + rtl837x_port.c |
/vlan.json, /vlanlist, /l2.json (walk, wrap marker, paging inside outbuf), 64-bit counters in /status.json and /counters.json |
Adding a test for another module
- Write
test_<module>.cwithmain()driving the module's entry points andCHECK(cond, msg)assertions. - Add any missing mocked symbols to
support.c(only what the linker asks for). - Add a target in the
Makefilelistingtest_<module>.c support.c ../<module>.c. - If the module calls a firmware libc-name (
memcpy/strcpy/…), it will use the C library on host (compatible arg order); provide afw_*-style mock only if the semantics differ in a way the test cares about.
Good next targets (pure logic, high finding density): cmd_parser.c (C6/C8),
the HTTP header parser in httpd/httpd.c (S1), dhcp.c (S5).