D591 - The title ships the index the asynchronous file path needs
Status: measured Date: 2026-09-08
Scanning instead of guessing, and the string next door
Every reading of the command buffer's header has been a guess at
which field is which, and each one has had to be corrected. So the
submit handler stopped guessing and scanned: every
non-zero word from -0x40 to +0x200 around the
buffer, reported by offset.
The header was as before. The negative offsets were not:
-0x28:0x626f6c672f616964 -0x20:0x616d656d61676c61 -0x18:0x722e73726567616e -0x10:0x537365
Little-endian, that is dia/glob algamema
nagers.r esS -
…/Media/globalgamemanagers.resS, sitting
immediately before the object. Which is a Unity companion file this
title does not ship, so the probe for it fails and that is ordinary:
D578 was right that the four missing paths are not the problem.
What it did was send somebody to look in the title directory.
ampr_emu.index,
in the title's own root
titles/PPSA03416-app0/ampr_emu.index 16,248 bytes
titles/PPSA03416-app0/fakelib/libSceAmpr.sprx 218,678 bytes
AMPRIDX3 is the magic. The dump ships a
replacement libSceAmpr and an index built for something to
emulate the asynchronous file path with, which is why
libSceAmpr(1 init) is a module the loader places rather
than a set of stubs orbistoun declares - and why the title imports
sceAmprAprCommandBufferConstructor and
sceAmprAprCommandBufferReadFile and calls neither. It is
not calling the library. The library was replaced.
The format, decoded and checked four times
+0x00 |
AMPRIDX3 |
+0x08 |
3 - a version |
+0x0c |
24 - the entry stride, and the entries are 24
bytes |
+0x10 |
141 - the entry count |
+0x30 |
the entries begin |
+0xd68 |
the names begin, at 48 + 141 * 24 |
An entry is
{u32 name_offset, u32 name_length, u64 size, u64 modified}.
Checked against the directory rather than believed, which is the only reason to state it:
| entry | index says | the directory says |
|---|---|---|
0 /app0/debug.log |
0 | 0 |
1 /app0/eboot.bin |
27,744,015 | 27,744,015 |
2 /app0/fakelib/libSceAmpr.sprx |
218,678 | 218,678 |
3 /app0/sce_sys/keystone |
96 | 96 |
26 /app0/Media/globalgamemanagers |
224,748 | 224,748 |
Entry 26 is the file the guest resolves, and 224,748 is the byte count D589's delivery experiment read out of it independently.
Why this is admissible, said plainly
This is guest material at rest, which
docs/PROVENANCE.md calls static evidence: read
out of a file in a title directory, nothing executed, nothing
disassembled, no vendor source. It is the same category as reading a
module's own import table, and it sits a tier below a name confirmed by
hash only in what somebody else needs to reproduce it - the title.
It is emphatically not the vendor's libSceAmpr. The
interesting file here is the replacement, and what is read is a
sixteen-kilobyte table of paths and sizes.
What this changes
sceKernelAprResolveFilepathsToIdsAndFileSizes has, for
the first time, a source of truth for what it should
answer: the path is in the index, the size is beside it, and
the identifier is plausibly the entry's position. Three sessions of
planting markers in its out-parameters were asking the guest a question
the title had already answered on disk.
What this does not establish
Which out-parameter takes which. The index says what the answers are; it says nothing about where to write them. That is still the measurement to make, and it is now a measurement with a known right answer rather than a search.
Nor that the identifier is the entry index. It is the obvious candidate and nothing has tested it. The index carries no explicit identifier field, which is itself evidence - a position is the only identifier available.
Nor what the remaining header words mean.
4618, 8056, 16 and
512 sit at +0x18 through +0x2c
and are not the name-table offset, which is arithmetic from the count.
Unused here, and unexplained.
Nor that every title carries one. This is one dump. A title without an index needs the mechanism understood rather than tabulated, and nothing here reaches that.