mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
ImDebugger: Source column on the breakpoint list, and record learnings
Adds the source location column to the breakpoint list, the last of the places worth surfacing line info. Exec breakpoints get a real location; memchecks and register breakpoints get "-", since a watched data range and a register aren't tied to a code address. Fixed a pre-existing misalignment found while adding the column: the register breakpoint row never emitted a cell for the Log column, so every following cell sat one to the left - the register name appeared under "Type", the condition under "OpCode" and the hit count under "Cond", with the last column left blank. It has a Log checkbox now like the other two rows (register breakpoints do support the log action), and the register name moved to Size/Label where the memcheck row puts its size. AGENTS.md gets what this stretch of work turned up: - Most files here are CRLF, including every .vcxproj, Android.mk, Makefile.common and AGENTS.md itself. Patching one with a script that reads with universal newlines and writes with newline='' silently rewrites the whole file - it turned a two-line addition into a 5000-line diff, which is invisible in an editor and obvious in git diff --stat. - Don't pipe Python containing backslashes through a bash heredoc; the quoting mangles them and anchors just fail to match for no visible reason. - Headless registers its own debug-output listener, so exception and crash messages never reach the log - they go to stdout, block-buffered when redirected, and taskkill //F discards the buffer instead of flushing. Give the run a short --timeout and let it exit if you need to read a crash trace. - 0xFFFFFFFF decodes to vflush, a real VFPU instruction, so it's useless as "garbage" for testing illegal-instruction handling. - A wsdbg script has to stay connected long enough for what it asked for; ending with :quit straight after cpu.runUntilTime looks exactly like a broken feature. - Where DWARF line info is and isn't available, since it's much narrower than it sounds. - Corrected the note claiming broadcast.config.set only accepts logger and input; it takes all five categories now. UnitTest 55/55. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
This commit is contained in:
1 parent
3f0c2da5a9
commit
14b6623330
2 files changed
+50
-7
No files matched your search
@@ -9,6 +9,16 @@ Ignore the folder ai_instructions in the root directory, it's old stuff from con
|
||||
1. Keep style changes minimal unless requested. Follow existing code patterns and conventions.
|
||||
2. Keep cross-platform parity in mind when changing shared code. See below for more multiplatform tips
|
||||
3. Never `git push` (to any remote) without asking the user first. Committing locally is fine when asked; pushing requires explicit approval.
|
||||
4. **Most files in this repo are CRLF** - `.vcxproj`, `.vcxproj.filters`, `android/jni/Android.mk`,
|
||||
`libretro/Makefile.common`, `AGENTS.md`, and much of the source. If you patch one with a script, read *and*
|
||||
write with `newline=''`; reading with Python's default universal-newline translation and writing with
|
||||
`newline=''` silently converts the whole file, turning a two-line addition into a 5000-line diff. Check
|
||||
`git diff --stat` before committing - a whole-file rewrite is obvious there and invisible in the editor.
|
||||
Prefer the Edit tool, which does exact string replacement and can't do this.
|
||||
5. **Don't feed Python to `bash -c` via a heredoc when the code contains backslashes.** The quoting mangles them,
|
||||
and an anchor string like `'...MemBlockInfo.cpp \\\r\n'` silently fails to match, so the patch reports
|
||||
"anchor missing" for reasons that aren't visible. Write the script to a file and run that instead, building
|
||||
separators with `chr(92)` if need be.
|
||||
|
||||
## Core Safety Checks
|
||||
|
||||
@@ -341,8 +351,20 @@ A working invocation, and the traps around it:
|
||||
- Response field names are not uniform: `memory.read_u32` answers with `value`, while `cpu.getReg` answers with
|
||||
`uintValue`. A parser defaulting a missing key to 0 will quietly report zeroes - read the handler's comment in
|
||||
`Core/Debugger/WebSocket/*Subscriber.cpp` rather than guessing.
|
||||
- `broadcast.config.set` currently rejects the `game` and `stepping` keys that `docs/WebSocketDebugger.md` lists,
|
||||
erroring with "Unsupported 'disallowed' object key". Only `logger` and `input` work.
|
||||
- `broadcast.config.set` accepts all five categories now (`logger`, `input`, `game`, `stepping`, `breakpoint`);
|
||||
it used to reject `game` and `stepping` until each had happened to fire once.
|
||||
- **A script has to keep the connection open long enough for what it asked for to happen.** `cpu.runUntilTime`
|
||||
followed immediately by `:quit` disconnects before the run even starts, and it looks exactly like the feature
|
||||
not working. End with a `:wait cpu.stepping <seconds>`.
|
||||
- **Exception and crash messages do not reach the log in headless.** It registers its own debug-output listener
|
||||
(`SendDebugOutput` in `headless/Headless.cpp`) that `fwrite`s to stdout, which is block-buffered when you
|
||||
redirect it to a file - so the output sits in the CRT buffer while the process runs, and `taskkill //F` throws
|
||||
it away rather than flushing. To actually read a crash trace, give that run a short `--timeout` and `wait` for
|
||||
the process to exit on its own.
|
||||
- **`0xFFFFFFFF` is not an invalid instruction** - it decodes to `vflush`, a real Allegrex VFPU op, so writing it
|
||||
over code to test illegal-instruction handling just runs it. Check what an encoding actually is with
|
||||
`memory.disasm` before assuming it's garbage; the interpreter raises `ExecExceptionType::ILLEGAL` only when
|
||||
`MIPSGetInstruction` has no interpreter for it (`tge`/`tlt`/`teq` and friends).
|
||||
- **To line input injection up with a wall-clock repro, use `cpu.status`'s `us` field** (emulated microseconds), not
|
||||
`ticks`. The PSP's clock frequency is changeable and games do change it - CrossCraft Classic runs at 333MHz, so
|
||||
`ticks / 222000000` is off by a factor of 1.5. `clockHz` is reported alongside.
|
||||
@@ -354,6 +376,15 @@ unstripped ELF next to the EBOOT (`app.elf` alongside `app.prx`, common for Zig/
|
||||
the function and data names out of it, so the disassembly reads `world.init_empty` instead of `z_un_088c00f0`.
|
||||
prxgen strips the symbol table on the way to the PRX, which is why the loaded module has none of its own.
|
||||
|
||||
The same flag also loads DWARF line info from that ELF (`Core/Debugger/LineInfo.h`), so addresses turn into
|
||||
`mesh.zig:163` in backtraces, crash traces, breakpoint hits and log lines, both call stack views, and the
|
||||
disassembly status bar. Availability is narrow and worth knowing before relying on it: **PRX conversion strips
|
||||
every `.debug` section**, verified across all 437 pspautotests `.prx` and CrossCraft's own `app.prx`, and of 24
|
||||
installed homebrew EBOOTs *none* carry debug info - CrossCraft only does because it ships `app.elf` separately.
|
||||
So it's there for homebrew you're developing (or a plain `.elf` you built), never for a commercial game. DWARF 2
|
||||
through 4 are decoded (psp-gcc emits 2, Zig 4); v5 re-encoded the file table and its units are skipped with a
|
||||
warning rather than mis-parsed.
|
||||
|
||||
That same file is also a ground-truth oracle for anything the loader computes. It still has the symbol table (so
|
||||
an address can be turned into a
|
||||
function name) and the full `.rel.*` sections *with symbol indices*, which the PRX format throws away. That makes it
|
||||
|
||||
Reference in new issue
Block a user