Instrument: file.read offset tracer + XMA-PARAM probe (voice RE)
Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 1m52s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped

Additive, cvar-gated instrumentation used to reverse-engineer Project
Sylpheed's cutscene-voice storage (movie -> continuous sound-stream cue
region). Default-off; no behaviour change.

- event_log.cc: MaybeEmitFileRead emits `file.read` events with the real
  NtReadFile ByteOffset (from r10), length, handle->path, and buffer VA, so a
  sound.pNN read offset can be mapped to a sound.pak TOC entry.
  Gate: --phase_a_fileio_only=true --phase_a_event_log_path=<file>.
- cpu_flags.cc: phase_a_fileio_only cvar (+ xma_param_probe).
- xma_context_new.cc: XMA-PARAM probe in XmaContextNew::Decode (the decoder the
  title actually uses) logging ctx/buffer/read-offset/channels/packets/byte_size
  /signature — to confirm which bytes get decoded for a given cutscene.

Used to produce /tmp/rt_fileio.jsonl (RT01A playthrough), which cracked the
movie->voice mapping now implemented in sylpheed-reborn. Next: run the same
file.read trace on an unbound hokyu (e.g. hokyu_LS_s03A) to resolve which
VOICE_D the game streams for the 13 manifest-unbound resupply cutscenes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-23 06:56:45 +02:00
parent 7b6902e08f
commit 201553aea3
3 changed files with 93 additions and 1 deletions

View File

@@ -30,6 +30,7 @@
DECLARE_string(phase_a_event_log_path);
DECLARE_bool(kernel_emit_contention);
DECLARE_bool(phase_a_trace_args);
DECLARE_bool(phase_a_fileio_only);
DECLARE_string(phase_a_hash_probe);
namespace xe {
@@ -683,8 +684,20 @@ void MaybeEmitFileRead(const char* name, ::xe::cpu::ppc::PPCContext* ctx) {
void EmitImportAndCallWithCtx(const char* module_name, uint16_t ord,
const char* name, void* ppc_context) {
::xe::kernel::phase_a::EmitImportCall(module_name, ord, name);
auto* ctx = reinterpret_cast<::xe::cpu::ppc::PPCContext*>(ppc_context);
if (cvars::phase_a_fileio_only) {
// Lightweight file-I/O-only mode: emit ONLY file opens (name + resolved
// path) and file.read events (path/offset/length). No import.call/kernel.call
// per-export spam, so a timing-sensitive title stays performant. For
// non-file exports both helpers early-out on a cheap name check.
std::string path = ResolvePathArg(name, ctx);
if (!path.empty()) {
::xe::kernel::phase_a::EmitKernelCallWithPath(name, path.c_str());
}
MaybeEmitFileRead(name, ctx);
return;
}
::xe::kernel::phase_a::EmitImportCall(module_name, ord, name);
std::string path = ResolvePathArg(name, ctx);
if (cvars::phase_a_trace_args) {
// Extraction mode: raw GPR args + resolved path, plus file.read detail.
@@ -700,6 +713,10 @@ void EmitImportAndCallWithCtx(const char* module_name, uint16_t ord,
}
}
void EmitReturn(const char* name, uint64_t return_value) {
// File-I/O-only tracing captures everything on the call side (opens + reads),
// so suppress the per-export return spam — it dominated the log (millions of
// lines / GBs) and perturbs timing.
if (cvars::phase_a_fileio_only) return;
::xe::kernel::phase_a::EmitKernelReturn(name, return_value);
}
} // namespace phase_a_bridge