#pragma once #include // Mid-asm hook on the AC6 PAC stream-worker's work-item dispatch site. // // Wired to `0x82343E78` in `rex_sub_82343E18` (the streamer's `bctrl` that // dispatches the next queued work item). At the moment of the call, // `ctr` holds the guest function pointer about to run (the work item's // virtual method[1]) and `r28` holds the work item itself. // // Gated by env var `AC6_TRACE_PAC_WORK_ITEMS=1`. When enabled, each // distinct dispatch target is logged once. The decoder we are hunting for // will appear here as a target that runs after a compressed PAC entry // has been fully streamed. void ac6PacWorkerDispatchHook(PPCRegister& r28, PPCRegister& ctr); // Second-level dispatch probe, installed at the first `bctrl` inside each of // the five non-error PAC stream-worker state handlers (rex_sub_82345608, // _738, _860, _A00, _B28). Each handler invokes a different vtable slot on // the same streaming sub-class; this hook records the target function each // slot resolves to. The mode-1 decoder is reached through one of these slots. // // All five sites share this single hook; cross-reference the captured target // addresses against `[AC6 PAC] compressed entry written` lines to identify // the decoder. void ac6PacWorkerL2DispatchHook(PPCRegister& r3, PPCRegister& r4, PPCRegister& r5, PPCRegister& r6, PPCRegister& ctr); // Mid-asm hook on the AC6 mode-1 decoder's post-decode site. // // Wired to `0x821CCC5C` in the streamer's per-entry processing function, // immediately after `add r11,r9,r11` resolves the compress-table entry // record pointer. At this point the prior `bl 0x822CF510` has decompressed // the entry, `r4` holds the destination buffer's guest VA, `r11` points at // the entry record (codec_mode at +1, csize at +8, usize at +12), `r10` // has the entry tag (low 16 bits), and `*(r31+22888)` holds the source // offset. Captured originally as a hand-edit in the Apr 23 build that // produced FHM-magic'd dumps; re-introduced here as a proper midasm hook // so codegen regeneration doesn't lose it. void ac6PacDecoderDumpHook(PPCRegister& r4, PPCRegister& r10, PPCRegister& r11, PPCRegister& r31); // Forward decl for the dumper sink (defined in src/ac6_pac_decode_dump.cpp). void Ac6DumpPacDecodedEntry(uint16_t entry_index, uint8_t codec_mode, uint32_t compressed_size, uint32_t decompressed_size, uint32_t source_offset, const uint8_t* host_data); // --------------------------------------------------------------------------- // Codec-internals tracing probes. // // Each probe is a mid-asm hook on a specific PPC function entry inside the // mode-1 decoder pipeline. All probes are gated by env var // AC6_TRACE_CODEC_INTERNALS=1 and rate-limited to the first 3 mode-1 decoder // invocations so log volume stays manageable. // // Decoder pipeline (top-down): // sub_822CF510 codec dispatcher -> ac6PacCodecDispatchProbe // sub_822CF2F8 mode-1 entry -> ac6PacMode1EntryProbe (one-shot ROM dump) // sub_822CCB50 bit fetcher -> ac6PacBitFetcherProbe // sub_822CEAC0 dynamic header -> ac6PacDynamicHeaderProbe // sub_822CDB38 tree builder -> ac6PacTreeBuilderProbe // sub_822CD068 / sub_822CD758 -> ac6PacBlockConsumerProbe // // The bit-fetcher probe is the highest-value: it logs every byte the codec // consumes, which lets us verify whether the .compressed.bin bytes are read // verbatim or transformed before reaching the bit buffer. void ac6PacCodecDispatchProbe(PPCRegister& r3); void ac6PacMode1EntryProbe(PPCRegister& r3); void ac6PacBitFetcherProbe(PPCRegister& r3, PPCRegister& r4, PPCRegister& r5); void ac6PacDynamicHeaderProbe(PPCRegister& r3, PPCRegister& r4); void ac6PacTreeBuilderProbe(PPCRegister& r3); void ac6PacBlockConsumerProbe(PPCRegister& r3);