Commit Graph
234 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5 3463789597 Find the companion ELF when a game is launched by folder, and keep line info
Two things kept the companion ELF from doing its job.

The first is the one that mattered: fileToStart is the game's own *directory*
for folder-launched homebrew (IdentifiedFileType::PSP_PBP_DIRECTORY), which is
the normal case when you pick a homebrew in the UI. The search navigated up from
it regardless, landing in PSP/GAME and listing sibling games - all directories,
all skipped - so app.elf sitting right next to the EBOOT was never found. It only
ever worked when the path pointed at the EBOOT itself, which is how headless is
invoked, which is why it looked fine from there. Searches the directory itself
now when that's what it's given.

The second: line info didn't survive loading a savestate. Modules aren't just
re-registered there, they're destroyed and rebuilt (KernelObjectPool::Clear), so
removing a module's lines in ~PSPModule threw the table away on every state
load. The previous commit worked around it by re-reading the companion, which
was both wasteful and no help at all to an ELF launched directly - those bytes
are long gone by then.

SymbolMap already solves this and line info now does it the same way: keep what
you have, and let whatever next claims the address range replace it. AddModule
replaces by key and is called for every module load, including ones with no line
info of their own, so a range gets retired when it's genuinely reused. The whole
table goes when the game does, in PSP_Shutdown. That also means the savestate
path has nothing to re-read, so state loads no longer pay to re-parse a
multi-megabyte ELF.

The tradeoff is a window between a module unloading and its range being reclaimed
where a lookup can still answer for it. For a debugger that's a stale file:line
on an address nothing owns, against certain and total loss on every state load.

Verified with --auto-save-load-symbols off, launched both ways: by directory
(the case that was broken) and by EBOOT path, both give 3734 symbols and 98383
line rows.

pspautotests 314/314, UnitTest 55/55.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 14:19:58 +02:00
Henrik RydgårdandClaude Opus 5 a6dd949df4 Load ELF debug info regardless of the symbol auto-save setting
bAutoSaveLoadSymbols is about writing .ppsym files back out and reading them in
again. It had also come to gate reading debug info that's simply sitting next to
the game, which is a different thing and shouldn't need asking for: the main
ELF's own symbols were already loaded unconditionally, but the companion ELF's
symbols and all line info were not.

Now the ELF is always the baseline - main or companion, symbols and line info -
and the setting only adds the .ppsym half on top of it.

Line info also loads from the module being loaded, not just from a companion,
so an ELF launched directly brings its own. A PRX has no .debug section for it
to find (prxgen strips them), so that's a cheap no-op for the usual EBOOT case,
which the companion path still covers.

That second source needs the two shapes distinguished, so AddModule takes an
explicit address delta rather than assuming a base: a companion links at zero
and wants the module's base added, while an ELF loaded at the addresses it asked
for already has final ones (bRelocate is just e_type != ET_EXEC). Rows that
don't land inside the module after that are dropped either way, which is a
better check than the old "offset smaller than the module" one.

Splitting the companion's identity check out of the symbol loader lets line info
reuse it, and drops an accidental requirement along the way: it used to reject
any companion without a symbol table, so an ELF built with -g but stripped of
its symbols would have contributed no line numbers either.

Verified with --auto-save-load-symbols off: CrossCraft's companion app.elf loads
3734 symbols and 98383 line rows where it previously loaded neither.

The direct-ELF path is not verified at runtime - it needs a bootable ELF that
carries DWARF, and there isn't one to hand. Both candidates here (pspautotests'
.elf builds and CrossCraft's own app.elf) are linked at address 0 and fail to
boot on that alone, which is pre-existing loader behaviour and nothing to do
with this.

pspautotests 314/314, UnitTest 55/55.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 13:58:03 +02:00
Henrik RydgårdandClaude Opus 5 c5e7c4890a Debugger: decode DWARF line info, and show source locations
Homebrew commonly ships its unstripped ELF next to the EBOOT, which is already
how the symbol loader turns z_un_08841f98 into a function name. That same ELF
carries a DWARF .debug_line section, so the addresses can be mapped to source
files and lines too - and a backtrace stops being four hex numbers:

  08841f98  move sp,fp          mesh.zig:163
  0883afa4  li v0,0x0           MenuState.zig:821
  088260d8  andi at,v0,0xFFFF   State.zig:40
  0882a27c  andi at,v0,0xFFFF   engine.zig:468

Surfaced in three places: per frame in hle.backtrace, in the "hit" object that
cpu.breakpoint.hit and cpu.stepping share, and appended to the disassembly
window's status bar. The breakpoint case keys on the pc rather than the address,
since for a memory breakpoint the useful source location is the instruction that
did the access, not the data it touched.

Storage is a plain sorted table of absolute addresses per module. SymbolMap
keeps module-relative addresses because its .ppsym files are meant to be
reloaded by a different game that pulls in the same module; none of this is ever
written anywhere - it's regenerated from the ELF each boot - so there'd be
nothing for relative addresses to buy. Each module owns its own rows and file
names outright and is keyed the way SymbolMap::UnloadModule is, so unloading one
module drops its lines and nobody else's.

The subtle part is end-of-sequence markers. Without them a lookup for an address
in a gap - a compilation unit built without debug info - confidently reports the
last line of an unrelated file. A prototype run over one test binary
mis-attributed 70 of its 349 functions that way, so sequence ends are recorded
as rows with line 0 and a lookup landing on one reports nothing instead.

DWARF 2 through 4 are decoded (psp-gcc emits 2, Zig 4). Version 5 re-encoded the
file table, so those units are skipped with a warning rather than mis-parsed -
nothing targeting the PSP produces it today.

Scope, since it's narrower than it sounds: PRX conversion strips every .debug
section. I checked all 437 pspautotests .prx and CrossCraft's own app.prx -
none have any. Of 24 installed homebrew EBOOTs, zero carry debug info; CrossCraft
only does because it ships app.elf separately. So this helps someone developing
homebrew, and does nothing at all for a commercial game.

Costs about 1.2 MB for a large Zig binary (98383 rows, 438 files) and nothing
for anything without debug info. Follows bAutoSaveLoadSymbols like the symbols
do.

pspautotests 314/314, UnitTest 55/55, CoreUWP builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 13:42:14 +02:00
Henrik RydgårdandClaude Opus 5 d72623c4a0 Load symbols from the unstripped ELF homebrew ships next to its EBOOT
Homebrew almost always ships the ELF it was built from alongside the EBOOT -
app.elf next to app.prx - but prxgen strips the symbol table on the way to the
PRX, so the module PPSSPP loads has no names at all and MIPSAnalyst calls every
function it finds z_un_<address>. Working out what any of them are meant hand-
parsing that ELF with a throwaway script, which is how the CrossCraft
relocation bug got identified.

So read it directly. On module load, scan the game's own directory for an ELF
with a symbol table and add its STT_FUNC/STT_OBJECT entries at the module's
base. CrossCraft picks up 3734 symbols, and the disassembly turns from
z_un_088c00f0 into world.init_empty, with static_allocator.alloc at the vtable
entry it calls - the two functions that took the longest to identify by hand.

Matching is the part worth getting right, since a wrong match puts confident
nonsense at real addresses, which beats having no names only in the sense that
it's worse. A candidate has to be a 32-bit ELF with a symbol table whose
highest section ends within a page of the loaded module's size - the companion
links at base 0 and covers the same image, so that's a tight check, and
unrelated ELFs sitting in the same folder fail it. Symbols outside the module
are skipped individually too.

Names go in with updateName, so they win over the analyzer's placeholders
rather than losing to whichever got there first. Gated on the existing
bAutoSaveLoadSymbols setting (off by default), which already means "keep symbol
names around for me" and avoids a directory scan per module load otherwise.

pspautotests 314/314.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 09:32:04 +02:00
Henrik RydgårdandClaude Opus 5 d0253732f6 Honor a module's declared segment alignment when allocating it
ElfReader read the first loadable segment's p_align into firstSegAlign but only
ever used it to round down textStart for symbol bookkeeping - the allocation
itself used the block allocator's default grain. A module whose relocations are
only valid at a more strictly aligned base therefore got loaded somewhere it
couldn't work, and the symptom is addresses off by a multiple of 64KB rather
than an outright failure.

CrossCraft Classic (Zig) declares p_align 0x10000 and hits exactly that. It
declares it deliberately: a stage of Zig's PSP pipeline emits mispaired
HI16/LO16 relocations, and a 64KB-aligned base makes that harmless - with no
low bits in the base no carry is ever needed, so which of a symbol's LO16
entries a HI16 was paired with stops affecting the result. PPSSPP put it at
0x08804000 instead, where the carry does matter: 46 of its addresses came out
64KB low, and it jumped through a bogus vtable a few seconds in. It now loads
at 0x08810000 and all 8405 lui/addiu pairs resolve correctly.

Worth being clear that the relocation code was never wrong here - it matches
what the hardware does, pairing a run of HI16 with the next non-HI16 entry and
applying the carry. Only the load address differed.

The two AllocAt paths can't move the module, since the caller picked the
address, so they just report a misaligned one instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 00:25:25 +02:00
Henrik Rydgård c5e4d0d90d Rename the get-memory-pointer functions to make it clear where CPU exceptions can happen. 2026-08-12 14:06:16 +02:00
Henrik Rydgård 3bd41376da More memory cleanup 2026-08-11 20:12:10 +02:00
Henrik Rydgård abb57c620f Adjust some log levels 2026-08-09 22:10:54 +02:00
Henrik Rydgård 5194382b7b Fix out-of-bounds reads in PARAM.SFO parser
ReadSFO dereferenced index table entries without checking the table fit
within the buffer, and GetDataOffset had no bounds checks at all (reading
attacker-controlled offsets and strcmp'ing without a terminator guard).

- Validate the index table fits entirely within the buffer in ReadSFO.
- Add a size parameter to GetDataOffset and validate the index table,
  key/data table positions, and key string termination before use.
2026-07-31 20:54:17 +02:00
Henrik Rydgård 4bf36fc7f8 Add command line option --vsh to try to boot the VSH. Logspam reduction, improve printf logs. 2026-07-27 14:58:59 +02:00
Herman Semenoff 5e2f51af8e gpu: elf: using reserve() for optimize inserts in for loop
From #21611
2026-04-28 10:53:32 +02:00
Henrik Rydgård 19a0441299 Fix crash in NPDRM iso detection (by rejecting invalid values and checking the header) 2026-02-17 15:27:56 +01:00
Henrik Rydgård a76ce9e73e Remove bad ID check 2026-01-29 22:10:28 +01:00
Henrik Rydgård 07d47a8cc1 Make UMD_VIDEO discs with game data detect as games.
Add special case for region for wacky STEALTH + Wipeout Pure disc, see #21166
2026-01-28 23:29:44 +01:00
Henrik Rydgård f5a211884b Minor cleanups, comments
Comments and warnings
2025-12-30 20:31:06 +01:00
Henrik Rydgård 0c4563c253 Throw in a check for the additional issue commented in #21073 2025-12-15 23:43:17 +01:00
Henrik Rydgård ed6ec0517b Fix #21073, plus an additional OOB read 2025-12-15 23:35:07 +01:00
Henrik Rydgård 69af603df9 Fix #21064 by removing manual memory management from ParamSFO. 2025-12-15 23:35:07 +01:00
Henrik Rydgård 1c49ad7b29 Support screen rotation on iOS (unrestricted) 2025-10-22 15:13:21 +02:00
Henrik Rydgård b304fbe0c9 Build armips in libretro builds (requirement for some lua functionality) 2025-10-08 09:45:44 -06:00
Nab 7edc3f0223 Add UNKNOWN region in place of OTHER 2025-09-06 17:18:57 +00:00
Nab 3c611355c6 Stricter check for 'H' region 2025-09-03 17:40:40 +00:00
Nab 5bfd4b390c GameRegion improvements 2025-09-03 14:17:55 +02:00
Henrik Rydgård bbe1a7edc1 Add simple ParamSFO viewer to ImDebugger 2025-09-01 13:53:44 +02:00
Henrik Rydgård c9acf8e80e More std::string_view 2025-08-31 20:20:59 +02:00
Henrik Rydgård 339ac7b866 Don't forget to copy over the MEMSIZE flag, when parsing PARAM.SFO for homebrew. 2025-06-06 18:50:47 +02:00
Henrik Rydgård c29e370e29 Remove global state from kirk engine 2025-06-05 22:46:24 +02:00
Henrik Rydgård 6bc625ecde More const-ness corrections 2025-06-05 22:46:23 +02:00
Henrik Rydgård e0a98ea54c Improve the "No game loaded" RA popup 2025-06-01 11:47:07 +02:00
Henrik Rydgård 4c631e77f5 RetroAchievements: Show region when showing the info popu. Refactor region detection a little. 2025-06-01 11:34:59 +02:00
Henrik Rydgård fab709af57 ELF loading: Shouldn't use ReadInstruction here, relocs might be unaligned. 2025-05-19 20:41:33 +02:00
Henrik Rydgård fba2489c79 Remove dubious parallelization in ELF loading, initialize a var, add some checks 2025-05-15 09:48:23 +02:00
Henrik Rydgård 41b77bf1ae More log cleanup 2025-04-14 22:27:51 +02:00
Henrik Rydgård 0df7a850a1 Only load PARAM.SFO once during startup 2025-03-26 09:24:14 +01:00
Henrik Rydgård 0f840e6240 Move JPEG error codes to the big enum, some include cleanup 2025-03-21 20:44:46 +01:00
Henrik Rydgård 3e198c53b2 More include cleanup 2024-12-18 13:57:26 +01:00
Henrik Rydgård cebb2ea96e Add missing return statement from PBPReader::GetSubFileAsString. Compiler should have rejected this.. 2024-11-04 01:15:00 +01:00
Henrik Rydgård eb5769c162 PBPReader sanity checks 2024-11-01 20:35:34 +01:00
Henrik Rydgård 6a7435341e Some reporting cleanups 2024-10-28 17:25:40 +01:00
Herman Semenov 192650f551 [Core/HLE/GPU/D3D11/GLES] Using for based loop C++17 and replaced on structured binding map C++17 2024-09-18 11:10:10 +02:00
Herman Semenov 3c66f149d3 [Common/Core/Windows] Removed excess check pointer before delete or free() 2024-09-17 11:34:42 +02:00
Henrik Rydgård 3a047369fd Add ability to install savedata from GameFAQs-style ZIP files 2024-09-05 17:12:10 +02:00
Henrik Rydgård e01ca5b057 Logging API change (refactor) (#19324)
* Rename LogType to Log

* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.

* Mac/ARM64 buildfix

* Do the same with the hle result log macros

* Rename the log names to mixed case while at it.

* iOS buildfix

* Qt buildfix attempt, ARM32 buildfix
2024-07-14 14:42:59 +02:00
Henrik Rydgård 404600faa3 SavedataParam/ParamSFO: Minor code cleanups 2024-04-07 12:31:45 +02:00
Henrik Rydgård 77133dd82c Fix a long-standing buffer overflow in savedata encryption
BuildHash pads the buffer up to its 16-byte aligned size with zeroes,
so there needs to be space for that. Or, we should just remove that
write, but let's do the smallest change that fixes the bug for now.
2024-04-07 11:42:51 +02:00
Henrik Rydgård fae1f4acd3 A null check and a locking simplification 2024-01-30 19:15:19 +01:00
Henrik Rydgård 0d28d3e009 Merge pull request #18562 from LunaMoo/crypto
Add more crypto keys
2024-01-28 19:17:31 +01:00
Henrik Rydgård 2e16fd3bcc Fix fake game ID generation to work with scoped storage 2024-01-23 01:06:56 +01:00
LunaMoo eaf488fb7b Oops 2023-12-17 06:35:53 +01:00
LunaMoo 0fd3f00a19 Add xor to other update functions looking at killzone liberation issue #12343 which needs 2 keys as well(seeds) 2023-12-17 03:34:20 +01:00