Merge PR #6 "Hardware pass (stage 1)" (dabao1955/feat/ete)

Merges the hardware-layer pass onto the dexsql commit: arm64 hardware
watchpoints, ETE differential tracing, kernel-side event injection, SPE/BRBE
sampling and crash forensics, address symbolization and interpreter-trace
de-slicing. 33 files, 6 new scripts, 6 new test modules, 4 new reference
documents.

The only conflict was in evidence/capability-matrix.json: both sides appended
to the same array tail. Resolved by keeping both -- the PR's seven entries
(44 rows total now) -- and re-validated as JSON before staging.

Verified on the merged tree, not on the PR branch alone:

  * check_repo.py, check_refs.py, check_commands.py, check_routing.py and
    check_budget.py all pass with zero problems;
  * pytest: 766 passed, 172 skipped, 25 xfailed -- the 141 tests this PR adds
    all pass alongside the 625 that were already there;
  * the PR's host-side claims were reproduced by hand, not taken on trust:
    `hw_watch.py plan --addr 0x1004 --len 4 --access w` returns
    `cr: 7701` (WCR 0x1E15) exactly as the record says, both refusals exit 2
    with the documented reason strings, and the kernel scaffold's
    generate/verify round trip returns RESULT=ok.

One documentation defect was found and fixed in the merge: EXTENSION-kernel-instrument.md
recorded `verified 3 kernel-side file(s)` while the same page's own generate
output lists four (kpm/src/kwatch.c, kpm/Makefile, lkm/kwatch.c, lkm/Makefile)
and the tool reports 4. The page now says 4.

Everything the PR ships that needs a device or a kernel toolchain stays
labelled unverified in the files themselves, which is the property that made
it mergeable.
This commit is contained in:
inliver233
2026-10-16 02:05:59 +08:00
33 changed files with 5358 additions and 6 deletions
@@ -0,0 +1,74 @@
# Extension verification — kernel-side instrumentation scaffold (templates, gates, verify)
Covers the hardware-layer pass that added `scripts/kernel_instrument_scaffold.py` and
`references/kernel-event-injection.md`. Strength labels as this directory's README defines
them. This pass follows `EXTENSION-kernel-weapons.md`'s shape deliberately: a generator whose
host behaviour is measured, kernel-side templates that have never been compiled or loaded
anywhere, and the gate table that says so.
Reference environment: Linux container host, Python 3.13, no `aarch64-none-elf-gcc`
(`gates` reports NOT FOUND — observed), no APatch/KernelPatch boot image, no device.
**Headline: `gates`/`generate`/`verify` are measured on the host. Every generated kernel-side
file carries a `NOT COMPILED AND NOT LOADED` banner that `verify` enforces. The
register-rewrite action is labelled experimental in the template itself — it was never run
anywhere, by anyone in this repository.**
---
## 1. Generate + verify round trip — observed
```
$ python skills/apk-reverse/scripts/kernel_instrument_scaffold.py generate \
--out work/kwatch --pid 12345 --watch w:0x7b2000123450:8:w --break b:0x7b20001234c0 --set-reg x0=0x1
wrote work/kwatch
kpm/src/kwatch.c kpm/Makefile lkm/kwatch.c lkm/Makefile
module.prop README.md post-fs-data.sh config/instrument.json
RESULT=ok
$ python skills/apk-reverse/scripts/kernel_instrument_scaffold.py verify --dir work/kwatch
verified 4 kernel-side file(s), 0 problem(s)
RESULT=ok
```
Spec validation reuses the hardware rules and refuses at generation, before any file is
written: a watch crossing its 8-byte window and a misaligned breakpoint PC both exit 2 with
the reason (`observed`, same refusal strings as `hw_watch.py plan` — one rule, one copy in
each tool, both unit-tested).
The generated KPM template embeds: `kfunc_def(...)` declarations **without** `extern` (the
loader-rejection lesson recorded in `EXTENSION-kernel-weapons.md`, restated in the template's
own header), a callback whose first statements are the cheap filter, and the watch config as
generated constants with *"regenerate rather than hand-edit"* in the config JSON.
## 2. The honesty devices this pass ships
- **The primitive map is a capability table, not a wishlist.** Each cell names what the route
can do, and the `no` cells (eBPF cannot create perf breakpoint events; a userspace module
cannot arm anything) are the rows that stop a reader from spending a day on a route that
cannot express the need.
- **The experimental action is fenced three times**: template comment, script header, and the
reference's stop table ("the first run is a measurement"). Rewriting `pt_regs` in a perf
overflow callback is mechanically what a ptrace stop does, and that is exactly as far as
the claim goes.
- **The userspace carrier cannot arm watchpoints and says so in its own README** — the same
structural correction `EXTENSION-kernel-weapons.md` made for syscall masking, applied
before anyone could misread this module the same way.
## 3. What this pass deliberately did not do
- Nothing was compiled: no `aarch64-none-elf-gcc` exists here, no KernelPatch image exists on
any reference device, and the LKM route has no matching kernel source. All three kernel
files are `unverified` templates and are labelled so in the files themselves.
- No claim about whether `register_hw_breakpoint` can be resolved from a KPM on any specific
KernelPatch revision is made; the template says to verify symbol names against the
revision's `kpmodule.h`, which is the same instruction the syscall-mask template gives.
## 4. Facts this pass pinned for the next one
- The kernel's **perf breakpoint layer owning the debug registers** is a gate in its own
right: if `CONFIG_HW_PERF_EVENTS` is out, both templates close regardless of root scheme.
Probe: `ls /sys/bus/event_source/devices/breakpoint` on the device.
- `verify` exists so the banner survives edits: someone will adapt a template on a real
device, strip the banner, and the next reader must be able to tell an adapted-unverified
file from a measured one. A banner replaced by a real measurement is the intended
outcome, and `kernel-event-injection.md`'s checklist says so.