Three bugs caused NOT_BOOT (timeout):
1. Wrong sysent table base: first _nosys match is entry 428, not entry 0.
Entry 0 is the indirect syscall handler. Fixed with backward scan.
2. Raw VA written to chained fixup pointer slot: struct.pack("<Q", cave_va)
corrupts the fixup chain from sysent[439] onward. Fixed with proper
auth rebase encoding (_encode_chained_auth_ptr).
3. Missing PAC parameters: dispatch uses BLRAA X8, X17 with X17=0xBCAD.
Chained fixup must encode diversity=0xBCAD, key=IA, addrDiv=0.
Chain 'next' field preserved from original entry.
Boot-tested OK via testing ramdisk.
Root cause: find_string("vnode_getattr") matched "%s: vnode_getattr: %d"
format string inside an AppleImage4 function. The old code then took that
function as vnode_getattr itself, causing BL to call into AppleImage4 with
wrong arguments → PAC failure on indirect branch at a2+48.
Fix: _find_vnode_getattr_via_string() now scans backward from the string
ref for a BL instruction and extracts its target — the real vnode_getattr
(sub_FFFFFE0007CCD1B4 at foff 0xCC91B4).
Bisection confirmed: variants A (stack frame) and B (+ tpidr_el1) boot OK,
variant C (+ BL vnode_getattr) panics with old resolution, boots OK with fix.
Boot-tested: full C23 patch with corrected vnode_getattr — BOOTS OK.
Root cause: backward branch search found PAC validation B.EQ (target fell
within error region range) instead of the kernel_map guard B.NE. New approach
walks backward from panic string ADRP to find CMP+B.cond where the branch
goes forward past the panic, then makes it unconditional. Also enables B6
and B8 in find_all(). Boot-tested: PASS.
Old approach patched vnode-type assertion BLs (CBZ→panic). New approach
scans backward from function end for the shared MOV W0,#1 kill return
before the LDP x29,x30 epilogue and changes it to MOV W0,#0. Single
instruction converts all 5+ kill paths to success. Boot-tested OK.
Root cause: "most-called BL target" heuristic in _proc_info picked copyio
(4 calls, 0x28C bytes) over the real _proc_security_policy (2 calls,
0x134 bytes). Lowered size filter threshold from 0x300 to 0x200 to
correctly exclude utility functions like copyio. Boot-tested: PASS.