Commit Graph
47092 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5 8594592f9c Pair HI16 relocations with the right LO16 when loading a PRX
CrossCraft Classic jumps to 0xae870000 a few seconds in, after a couple of
button presses, and dies. It runs fine on a real PSP.

The jump is a Zig interface call - std.mem.Allocator is {ptr, vtable} and the
crash is `lw t9, 0(vtable); jalr t9`. The vtable pointer had come out as
0x089191E0 instead of 0x089291E0, exactly 64KB low, so t9 was loaded from the
middle of compiler_rt.udivmod and the "function pointer" was really the
instruction word `sw a3,0(s4)`.

That pointer is built by a lui/addiu pair, and which LO16 completes a given
HI16 decides one thing: whether the high half carries. We were pairing each
HI16 with the next non-HI16 relocation in the table, which can't work in
general. A PRX relocation carries no symbol index - r_info holds segment
numbers - so the table cannot express the pairing. prxgen does order it so a
HI16 is followed by a LO16 for the same symbol, but not necessarily by *its*
LO16: LLVM schedules several luis together and their addius come back
permuted, here even earlier in the table than the lui they belong to. Two
LO16s for one symbol usually yield the same high half, which is why this has
gone unnoticed for so long - it only bites when their low halves land on
opposite sides of 0x8000. This game has two .rodata references in one
function that do exactly that, and the loader swapped them.

Pair the way the compiler generated it instead: the lui loads a register, and
the instruction completing it is the next one using that register as a base -
unless another lui reloads that register first, in which case the candidate
belongs to that one. Falls back to the old scan when the register trail goes
cold (the value gets copied before use), so nothing that worked before stops.

Checked exhaustively against an oracle: the pre-link ELF still has a symbol,
and thus a section, for every relocation, so any pairing whose result lands
outside that section is wrong. Over this module's 8589 HI16 relocations the
old rule puts 22 outside their section; the new one puts 0, and never picks a
LO16 belonging to a different symbol. Both the register match and the reload
guard are needed - without the guard it scores worse than the old rule.

Impact is narrow. On GCC-built PRXs (pspautotests) the chosen LO16 differs for
2-4 relocations per module and the emitted instruction changes in none of
them. On this LLVM-built module 449 pairings differ and 46 emitted addresses
change, i.e. 46 pointers that were quietly 64KB off.

pspautotests 314/314, unit tests 51/51.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 18:47:26 +02:00
Henrik Rydgård 2a1df9f0b8 Merge pull request #22106 from hrydgard/more-thread-fixes
More debugger threading fixes by Claude
2026-08-17 14:10:15 +02:00
Henrik RydgårdandClaude Opus 5 a96dfc1390 Share SetupCRT with the unit tests so they can't pop a modal dialog
UnitTest.exe runs on CI and from tooling, where an assert or an abort() puts
up a message box that nothing will ever click, and the run just hangs until it
is killed. Headless already solved this; move its SetupCRT() into Common
(ExceptionHandlerSetup, which is where the rest of the process-level fault
setup lives) and call it from the unit tests too.

No behaviour change for headless. The OS-level SetErrorMode() call is now
guarded for UWP, which doesn't have it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik Rydgård 0ac822d7f1 Libretro buildfix 2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 75ff0d406c Rename Memory::Lock() to Core_LockAgainstShutdown(), move it to Core
It stopped being about memory when CPU_Shutdown started holding it across the
whole teardown - it's what keeps kernel objects, the symbol map and the memory
map from being freed while another thread reads them. The old name invited the
reading that it locks memory *access*, which it has never done.

Memory::Reinit() now holds it across both halves rather than relying on
Memory::Shutdown()'s own acquire: between Shutdown() and Init() there is no
memory map at all, and a reader could slip into that gap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 f57a102027 Win32 debugger: take the shutdown lock everywhere core state is read
Seven GUI-thread readers held only g_frameMutex, which guards against the CPU
thread mutating state but not against the core being torn down - and two of
PSP_Shutdown's paths (EmuScreen::sendMessage, ProcessScreenSwitches) run outside
that span entirely. CtrlThreadList::reloadThreads walking kernel objects that
__KernelShutdown had freed was the concrete crash; the symbol map readers
(CDisasm::Show/NotifyMapLoaded, CtrlModuleList, CtrlWatchList) had the same
shape.

Always g_frameMutex first, then Memory::Lock().

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 4a10fa2808 Hold the shutdown lock across all of CPU_Shutdown
It was only held across Memory::Shutdown(), but everything else in there frees
state the debugger UIs read from other threads - kernel objects
(__KernelShutdown), the symbol map, replacements - so a Win32 debugger window
painting while a game is reset could read freed memory. It's recursive, so the
nested acquire in Memory::Shutdown() is unaffected.

No lock-order risk: on the paths where CPU_Shutdown already runs under
g_frameMutex it now takes these in the same frame-then-shutdown order the GUI
side uses, and on the paths where it doesn't (EmuScreen::sendMessage,
ProcessScreenSwitches - both above where NativeFrame takes the guard) it takes
only this one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 933d39406a AGENTS.md: document the debugger threading invariant now that lifecycleLock is gone
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 caf863df79 Remove the WebSocket debugger's lifecycleLock
Nothing needs it any more. Every handler either does its emulator-state access
inside Core_RunOnCPUThread(), which serializes it against startup and shutdown
because those run on the CPU thread too, or only touches state that carries its
own lock - the log ring buffer, ctrlMutex, GPUStepping's rendezvous.

Good riddance: it had to be held across an entire handler, including the
blocking wait inside Core_RunOnCPUThread(), so the CPU thread taking it on
STOPPING deadlocked against a debugger request in flight. That needed a
drain-while-waiting workaround, which now goes away with it.

Verified with the instrumented shutdown repro from that fix, which still exits
cleanly with no lock at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 a0f223d933 Move the last debugger core access onto the CPU thread
Three things still touched CPU-thread-owned state from the WebSocket thread:

- Breakpoint conditions were compiled in Parse(), and resolving symbols in an
  expression goes through g_symbolMap, which is destroyed on shutdown. Compiled
  inside the queued callback now, before anything is mutated, so a bad
  expression still fails without leaving a breakpoint behind.
- gpu.record.dump dereferenced the gpu pointer, which is created and destroyed
  on the CPU thread.
- gpu.stats.feed bumped PSP_ForceDebugStats' plain counter.

Also makes g_bootState atomic - it's read as a fast-fail from the debugger
thread all over while the CPU and loader threads move it along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 3273e8081e Push game and stepping events from the CPU thread instead of polling for them
GameBroadcaster and SteppingBroadcaster ran per connection on the WebSocket
thread, so every connected debugger was reading pc, the tick count, coreState,
the UI state and the param SFO out from under the CPU thread on every lap of its
loop - up to 1000 times a second in high-activity mode.

Inverted: the CPU thread notices the transition once in WebSocketDebuggerTick(),
formats the event there, and drops it into a per-connection mailbox that the
connection's own thread drains and sends. Same events, same conditions, no core
reads off the CPU thread, and no per-connection polling of emulator state.

The tick hangs off Core_ProcessCPUQueue(), the one function reliably called on
the CPU thread both in game (Core_RunLoopUntil) and at the menu (NativeFrame).
It polls even with nothing connected, since skipping would let the "previous
state" go stale and fire a bogus event at whoever connects next.

Behavior preserved including the awkward bit: a debugger that connects while the
CPU is already stopped still gets an immediate cpu.stepping, which used to fall
out of SteppingBroadcaster's counter starting at 0. That's now an explicit
per-connection prime instead of an accident.

Part of removing the WebSocket debugger's lifecycleLock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 14e8ba8486 Make numVBlanks atomic
The WebSocket debugger reads it from its own thread (input.buttons.press counts
down frames against it) while the CPU thread bumps it.

Note the input subscriber and broadcaster need no other changes for thread
safety: __CtrlUpdateButtons, __CtrlSetAnalogXY, __CtrlPeekButtons and
__CtrlPeekAnalog all take ctrlMutex internally, so routing them through
Core_RunOnCPUThread() would only add a blocking round trip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 8858c8ec58 MemoryInfoSubscriber: read core state on the CPU thread
memory.info.list/search walk MemBlockInfo's slab maps and memory.info.set writes
to them, all straight from the WebSocket thread. Route through
Core_RunOnCPUThread(), pulling the isAlive/IsValidAddress checks into the same
trip - checking them outside it only tells you what was true a moment ago.

memory.info.config now reports the value after applying 'detailed' rather than
before, which is what the docs always claimed.

Part of removing the WebSocket debugger's lifecycleLock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:10:51 +02:00
Henrik Rydgård fbfcb8925e Merge pull request #22099 from n00mkrad/softgpu-dither-opt
Allow disabling dithering when using software rendering
2026-08-17 12:47:57 +02:00
Henrik RydgårdandClaude Opus 5 3a669891dc Replay and GPUDisasm subscribers: read core state on the CPU thread
replay.* mutates and reads replay/RTC state that the CPU thread consumes as it
runs, and gpu.displaylist.disasm reads through the gpu pointer and emulated
memory. Both did it straight from the WebSocket thread. Route through
Core_RunOnCPUThread(), and fold the "is a game running" checks into the same
trip rather than testing before it, where the answer could already be stale.

Part of removing the WebSocket debugger's lifecycleLock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 12:26:05 +02:00
Henrik RydgårdandClaude Opus 5 a59b5c6dd5 GameSubscriber: read core state on the CPU thread
game.status, game.reset and version all read PSP_GetBootState(), g_paramSFO,
GetUIState() and PSP_CoreParameter() straight from the WebSocket thread, where
they race with a game being torn down or booted. Route them through
Core_RunOnCPUThread() like the other subscribers already do.

Part of removing the WebSocket debugger's lifecycleLock, which is currently what
stops these racing with teardown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 12:26:05 +02:00
Henrik Rydgård 1019976f45 Merge pull request #22100 from hrydgard/debugger-stepping
Debugger: Fix various stepping problems, clean up code
2026-08-17 12:25:39 +02:00
Henrik RydgårdandClaude Opus 5 707275b46a Fix deadlock when stopping a game with a debugger request in flight
The WebSocket thread holds lifecycleLock across a whole event handler, and
handlers do their real work through Core_RunOnCPUThread(), which blocks until
the CPU thread drains the queue. Meanwhile PSP_Shutdown() ->
Core_NotifyLifecycle(STOPPING) took that same lock on the CPU thread. So the
debugger thread waited for the CPU thread while the CPU thread waited for the
lock the debugger thread was holding, and neither ever moved.

Drain the CPU queue while waiting for the lock instead of blocking on it. Core
state is still alive at STOPPING (it's notified before CPU_Shutdown), so running
those queued callbacks then is safe, and it lets the debugger thread finish and
release the lock.

Verified with a temporary instrumented build - a 3s sleep inside a handler while
holding lifecycleLock, arranged to overlap the game's shutdown - which hangs
reliably on the old code and exits cleanly with this change.

lifecycleLock stays for now: roughly half the subscribers and all the
broadcasters still read core state directly on the WebSocket thread instead of
going through the queue, and this is what keeps that from racing with teardown.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:34:01 +02:00
Henrik RydgårdandClaude Opus 5 81511e7a08 Fix deadlock between the Win32 debugger's paint handlers and the CPU thread
Reported hang: the CPU thread held g_frameMutex (NativeFrame) and blocked on
g_shutdownLock inside a queued memory.read, while the GUI thread held
g_shutdownLock (CtrlMemView::onPaint) and blocked on g_frameMutex. Textbook
ABBA.

The CPU thread's order is structural - NativeFrame wraps everything below it in
g_frameMutex, and both Core_ProcessCPUQueue() and runImDebugger() ->
DisassembleRange() lock memory from under there - so the GUI side is the one
that has to match. Swaps the three handlers that had it backwards
(CtrlMemView::onPaint, CtrlDisAsmView::onPaint, CtrlStackTraceView::
loadStackTrace) to take g_frameMutex first. They already took both locks, so
this is ordering only, and g_shutdownLock is recursive so nesting is fine.

Also drops the Memory::MemoryInitedLock from the WebSocket LockMemory(), which
is what made the CPU thread want that lock in the first place. It was guarding
against another thread tearing down the memory system, but that doesn't happen:
Memory::Shutdown() is only reached via CPU_Shutdown() <- PSP_Shutdown(), whose
callers all run on the CPU thread, and Memory::Reinit() runs from
Memory::DoState() on savestate load, likewise. WebSocket.cpp additionally holds
lifecycleLock across the whole handler and takes it on STOPPING.

Note this second part isn't sufficient on its own - ImMemView's copy-disassembly
path also locks memory from inside the frame span - which is why the ordering
fix is the real one.

Not removing Memory::Lock() from the Win32 paint handlers: teardown isn't fully
inside the g_frameMutex span yet. EmuScreen::render()'s PSP_Shutdown() is, but
the ones in EmuScreen::sendMessage() (game reset, loading a new game) run from
g_screenManager->sendMessage(), above where NativeFrame takes the guard. Closing
that is the prerequisite, and is left for later.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:29:44 +02:00
Henrik Rydgård 8784b709e8 Claude findings 2026-08-17 00:29:42 +02:00
Henrik RydgårdandClaude Opus 5 35a91b757a Move the temporary breakpoint out of the user's breakpoint list
step-over, step-out and run-until plant a one-shot breakpoint at the address
they want execution to return to. Keeping it in breakPoints_ alongside the
user's own meant the two kept colliding:

- Adding a log-only user breakpoint at the same address hijacked the temporary
  one. AddBreakPoint() didn't match across temp-ness so both existed, and then
  ChangeBreakPoint() looked up "the first enabled breakpoint at this address" -
  a log-only breakpoint isn't enabled, so the temporary one won and had its
  action overwritten to log-only. It lost PAUSE and the step never came back.
- RemoveBreakPoint() erased up to two entries per address to catch an
  overlapping temporary one, so deleting either deleted both - including the
  interpreter's cleanup path in CheckExecBreakpoints() taking the user's
  breakpoint with it.
- ExecBreakPoint() handled one breakpoint per address, so with both at the same
  address only one of them did anything: the step completed but the user's log
  line never printed.
- Nothing dropped it when something *else* stopped us first, so an interrupted
  step left a breakpoint armed at an address nobody was waiting for anymore,
  which later fired as a phantom stop.

It's a single TempBreakPoint member now, invisible to the breakpoint lists and
untouched by user edits. One is enough: step over/out and cross-thread step into
all require the CPU to already be stepping and resume it immediately, so only
one can be in flight, and run-until now replaces rather than stacking (two
pending run-untils had no coherent meaning, and the loser stayed armed).

Behavior follows what other debuggers do. Both breakpoints at an address are
evaluated independently and their actions combine, so a log-only breakpoint
logs without stopping and still lets the step finish. Core_Break() drops the
temporary breakpoint on any stop, whatever the reason - the same way gdb deletes
its step-resume breakpoint and lldb discards the thread plan.

Two things to be careful of, both covered by the new TempBreakpoints test:
HasBreakPoints() has to account for it, or the interpreter's checked run loop
and the JIT skip breakpoint checking entirely and a step with no user
breakpoints set never returns; and IsAddressBreakPoint() (user-facing, for the
lists and disassembly markers) is now separate from NeedsBreakCheckAt() (what
the JIT frontends and interpreter ask), since only the latter should see it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:29:26 +02:00
Henrik RydgårdandClaude Opus 5 0c510ca62e Add BreakpointManager::ChangeBreakPointAddress, use it from the ImDebugger
ChangeBreakPointAddress() moves the breakpoint keeping its action, condition and
log format, invalidates both ends, refuses to land on an existing breakpoint,
and resets the hit count since it belonged to the old address. The edit form now
works on a copy of the address and commits on deactivation rather than per
keystroke, so typing one address doesn't churn through every prefix of it.

The breakpoint edit form assigned straight to bp.addr and then invalidated the
icache at "bp.addr - 4, 8" - which by then is the *new* address - need both.

Also clear the selection after Delete in both edit forms - the reference into
the vector is dangling from that point on. Harmless today, but only because
nothing happens to touch it below.

Covered by a new Breakpoints unit test (verified to fail without the duplicate
check and the hit reset).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:28:39 +02:00
Henrik RydgårdandClaude Opus 5 d4500d9353 hle.data.add: apply the requested name, and report the real one
AddLabel() won't overwrite an existing label. That's deliberate and right for
bulk import - a real ELF symbol name shouldn't lose to the analyzer's later
z_un_* - but wrong when someone is explicitly naming an address, so a second
hle.data.add at the same address silently kept the old name. The response echoed
the requested name back either way, so there was no sign anything had been
ignored.

Force the requested name in with SetLabelName() now, except when a function
starts at that address and owns the label - renaming that function isn't what
"label this data" should mean, and it would undo the care hle.data.remove takes
not to destroy it. Either way the response now reports the name the symbol
actually ended up with rather than the one that was asked for.

Also, in the ImDebugger memcheck edit form: the Enabled checkbox didn't mark the
memcheck as changed, and the condition combo marked it changed on every frame
the popup was open rather than when a condition was actually picked (Selectable
returns true only on click, BeginCombo stays true while open).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:28:26 +02:00
Henrik RydgårdandClaude Opus 5 6a05ef290d Fix four WebSocket debugger bugs found while stress testing
memory.readString could kill the connection: it copied raw emulated memory
straight into a JSON string, so any address not holding valid UTF-8 produced an
invalid WebSocket text frame.

hle.data.remove wiped the name of a function sharing the address. Labels are
shared between data and function symbols, so removing the data label left the
function showing up in hle.func.list with an empty name.

hle.data.add silently did nothing outside a loaded module. GetModuleIndex()
returns -1 for e.g. a heap or stack address, and symbols under that index never
reach the active maps - so the add reported success while the symbol was
invisible to list, and rename/remove then failed with "No data symbol found".
Falls back to module index 0 ("no module, absolute address"), which is the right
answer for a label the user put somewhere after a memory.search.

hle.thread.list reported the thread's stack base address in a field called
initialStackSize. Renamed to initialStack, matching the SceKernelThreadInfo
field it comes from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 00:25:39 +02:00
Henrik Rydgård ae76fec2d5 Merge pull request #22102 from robertkirkman/cmake-libpng-minimum-1.6
Lower minimum libpng version requirement to 1.6 for ARM targets that are not Android or iOS
2026-08-16 23:26:09 +02:00
Henrik Rydgård 0e15445b54 Fix memchecks 2026-08-16 23:09:15 +02:00
Henrik Rydgård 9b9083d3e5 Fix for headless port problem by Claude 2026-08-16 23:09:12 +02:00
Robert Kirkman 4039ddc9cf Lower minimum libpng version requirement to 1.6 for ARM targets that are not Android or iOS
- Fixes https://github.com/hrydgard/ppsspp/issues/22101
2026-08-16 14:16:48 -05:00
Henrik Rydgård 22ea384186 Bugfix 2026-08-16 19:53:52 +02:00
Henrik Rydgård 8d0d601b5b Clean up how the instruction cache is invalidated from the breakpoint manager 2026-08-16 18:10:02 +02:00
Henrik Rydgård f3d31846bb Enable breakpoint processing when stepping 2026-08-16 17:37:05 +02:00
Henrik Rydgård 14405c08cf Remove the concept of stepSize from the debugger 2026-08-16 16:59:54 +02:00
Henrik Rydgård c13f6e82fe Default new breakpoints to have the LOG action, because why not 2026-08-16 16:59:54 +02:00
Henrik Rydgård c457dbbd2f Debugger breakpoints: Rename "Result" to "Action" 2026-08-16 16:59:54 +02:00
Henrik Rydgård 9f90512ef6 Make instruction cache invalidation (for us, jit cache invalidation) clearer 2026-08-16 16:59:52 +02:00
nmkd 8e9a8b8d76 Allow disabling dithering when using software rendering 2026-08-16 15:27:41 +02:00
Henrik Rydgård a49f4523cb Correct when we process the stepping queue. Also, the jitLock mutex is no longer needed. 2026-08-16 13:33:26 +02:00
Henrik Rydgård 1848262bea Style 2026-08-16 13:33:26 +02:00
Henrik Rydgård 2e52881848 Merge pull request #22096 from hrydgard/platform-headless-fixes
Get rid of the confusing old USING_WIN_UI define, avoid assert dialogs in headless mode
2026-08-16 13:32:53 +02:00
Henrik Rydgård 5cffcd34ad Get rid of the confusing old USING_WIN_UI define. Make a more clear system property for headless. 2026-08-16 12:19:41 +02:00
Henrik Rydgård 45e11ee90f Merge pull request #22097 from hrydgard/unresolved-syscall
Log unresolved syscalls properly
2026-08-15 21:57:51 +02:00
Henrik Rydgård 67ddf899ba Plumb through the PC value for syscalls, so we can get better diagnostics for unresolved ones. 2026-08-15 19:14:13 +02:00
Henrik Rydgård ae14ebb6ac IRWriter: Remove the confusing and inefficient AddConstant 2026-08-15 18:31:20 +02:00
Henrik Rydgård 2096179dce Drive-by code cleanup 2026-08-15 18:31:20 +02:00
Henrik Rydgård 6be9fe50b2 Merge pull request #22092 from hrydgard/debugger-work
Debugger bugfixes and coding style fixes
2026-08-14 15:41:04 +02:00
Henrik Rydgård 5ce4cbc18a Fix some function name shenanigans 2026-08-14 14:55:06 +02:00
Henrik Rydgård f5bd302694 Improve DescribeAddress, show the description of the currently selected line in disassembly 2026-08-14 14:38:33 +02:00
Henrik Rydgård 1ce23df734 Fix BreakReason 2026-08-14 14:09:06 +02:00
Henrik Rydgård 1c21f95270 Comment and cleanup in MIPSTables.cpp 2026-08-14 13:28:23 +02:00
Henrik Rydgård 14509b7815 Code style updates in SymbolMap.cpp, fix claudism 2026-08-14 13:19:12 +02:00