Loads a single module standalone - no game, no boot - and writes a report:
module header and segments, the export and import tables with NIDs resolved to
names through the HLE tables, one annotated disassembly file per function, and
a call graph as JSON.
Reuses the emulator's own loader rather than parsing PRXes a second time, so
decryption, decompression, relocation and import resolution can't drift from
what actually runs. Only enough of the system is brought up to load a module:
memory map, timing, HLE tables and the kernel allocators. Nothing executes.
Two things beyond a plain disassembly, both aimed at the questions that come up
when reading unfamiliar MIPS:
- lui/addiu (and lui/load) pairs are folded and reported as the address they
form, which is how every global and constant table gets reached.
- Per function, a register evidence block instead of a guessed signature. A
MIPS function that takes two arguments and passes the second one down often
never reads it, so 'never read but live across a call' is reported as
forwarded rather than quietly dropped from the signature.
SetForceRealModuleLoads() is needed because modules like sceAudiocodec_Driver
have no DisableHLEFlags bit and so can't be turned off the normal way - they'd
fake-load and there would be nothing to look at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Which modules we HLE is decided when each module is loaded, and the syscall
stubs written into memory then are what a savestate captures. But the setting
was read live, so loading a state re-resolved its imports against whatever the
config said now - and if that disagreed with how the state was made, every call
into the module landed on an unresolved stub returning LIBRARY_NOT_YET_LINKED.
Thrillville just retried sceMpegInit forever.
Latch the flags on first use after boot, save them in the state, and restore
them on load. Changing the setting now takes effect on the next boot, which is
the only point it could have taken effect anyway.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
The MP4 libraries turn out to be the easiest place to hand a game Sony's own
code: libmp4.prx needs only sceAudiocodecInit and sceAudiocodecDecode from us
plus ordinary kernel calls, and mp4msv.prx - where the 41 functions libmp4
leans on live - imports nothing at all. So with a firmware dump present the
pair can be loaded for real and left to decode through our sceAudiocodec.
Adds DisableHLEFlags::sceMp4, which loads and starts both modules when the
game asks sceUtility for the MP4 module, and a --disable-hle bitmask so a
headless run can ask for this without a config file.
Two things had to be fixed to make it work at all:
- ModuleMgrForUser 0xD2FBC957 was unimplemented, and libmp4 calls it to get
the gp of each callback it is handed. Implemented as
sceKernelGetModuleGPByAddress.
- Headless forced every module to HLE unconditionally, which silently undid
the flag, and it did so before ApplyToConfig() had even parsed it.
Tested with Speedball 2 - Evolution, which uses sceMp4 for its music: the game
goes from 255645 calls into our stubs and 39 unresolved imports, to zero of
each and 1943 AAC frames decoded through sceAudiocodec.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A call through a still-pending import gets written as a generic "invalid
syscall" opcode (WriteFuncMissingStub) that no longer carries the
original module name or NID by the time it's actually invoked - but the
address of the syscall instruction itself is exactly the stubAddr every
pending FuncSymbolImport already records. Added
KernelFindImportByStubAddr() to search loaded modules' importedFuncs for
a match, and use it in GetSyscallFuncPointer's unknown-syscall path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Testing has shown that this seems to work great and fixes issues. These
two modules are just a parser and a shim over sceMpeg, and we're better
off running the original code, instead of re-implementing it.
sceMpeg still needs accuracy improvements though, and it's built on some
pretty low level components so it will be harder to peel off the next
level of the HLE onion.
Se #20200.
Some games survive with a loaded sceAtrac, and start talking to
sceAudioCodec instead, the underlying library, though unsuccessfully
since it's not properly implemented yet.
Fixes#19935. Forgot to update the formatting for the reporting case.
I'll clean this up in a more general way later, I don't like how this code currently looks.