mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-04 06:38:48 +00:00
better debug support
This commit is contained in:
Vendored
+1
@@ -24,6 +24,7 @@
|
||||
"autorun": [
|
||||
"monitor reset shellhalt",
|
||||
"load hello_psyq.elf",
|
||||
"source scripts/gdb/gdb_tape_atoms.gdb",
|
||||
"tbreak main",
|
||||
"continue"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
-- gte_debug.lua — defensive version + prints error context.
|
||||
local ok, err = pcall(function()
|
||||
print("[debug] PCSX exists:", PCSX ~= nil)
|
||||
print("[debug] PCSX.WebServer exists:", PCSX and PCSX.WebServer ~= nil)
|
||||
print("[debug] PCSX.WebServer.Handlers exists:", PCSX and PCSX.WebServer and PCSX.WebServer.Handlers ~= nil)
|
||||
if not PCSX.WebServer then
|
||||
print("[debug] creating PCSX.WebServer...")
|
||||
PCSX.WebServer = {}
|
||||
end
|
||||
if not PCSX.WebServer.Handlers then
|
||||
print("[debug] creating PCSX.WebServer.Handlers...")
|
||||
PCSX.WebServer.Handlers = {}
|
||||
end
|
||||
print("[debug] type of Handlers:", type(PCSX.WebServer.Handlers))
|
||||
|
||||
PCSX.WebServer.Handlers.gte = function(req)
|
||||
local r = PCSX.getRegisters()
|
||||
local out = { "pc=0x" .. string.format("%x", r.pc) }
|
||||
for i = 0, 31 do
|
||||
out[#out + 1] = string.format("D[%d]=0x%08x C[%d]=0x%08x",
|
||||
i, r.CP2D.r[i], i, r.CP2C.r[i])
|
||||
end
|
||||
return table.concat(out, "\n")
|
||||
end
|
||||
print("[debug] handler registered")
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
print("[debug] ERROR: " .. tostring(err))
|
||||
end
|
||||
+13
-2
@@ -321,11 +321,12 @@ function ps1-meta { param(
|
||||
[Parameter(Mandatory=$true)][string[]]$sources,
|
||||
[Parameter(Mandatory=$true)][string]$metadata,
|
||||
[string]$out_root = (join-path $path_build 'gen'),
|
||||
[string[]]$passes = @('--all')
|
||||
[string[]]$passes = @('--all'),
|
||||
[string[]]$extra_args = @()
|
||||
)
|
||||
$script = join-path $path_scripts 'ps1_meta.lua'
|
||||
write-host "ps1-meta $($sources.Count) source(s), passes=$($passes -join ',')" ` -ForegroundColor Magenta
|
||||
$arg_list = @($passes) + @('--metadata', $metadata) + @('--out-root', $out_root)
|
||||
$arg_list = @($passes) + @('--metadata', $metadata) + @('--out-root', $out_root) + @($extra_args)
|
||||
foreach ($s in $sources) { $arg_list += @('--source', $s) }
|
||||
& luajit $script @arg_list
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
@@ -383,6 +384,16 @@ function build-gte_hello {
|
||||
)
|
||||
link-modules $link_modules $elf $link_args
|
||||
make-binary $elf $exe
|
||||
|
||||
# Post-link: emit ONLY build/gen/gdb_tape_atoms_runtime.gdb. The per-source
|
||||
# *.atoms.sourcemap.txt was already generated by the pre-link --all call,
|
||||
# so we skip --atoms-source-map here to avoid re-doing the work. The
|
||||
# gdb-runtime emission requires --elf (for nm-based address lookup) so it
|
||||
# MUST happen post-link. ON by default per user pref 2026-07-11.
|
||||
ps1-meta -sources $atom_sources -metadata $path_atom_metadata `
|
||||
-out_root (join-path $path_build 'gen') `
|
||||
-passes @('--gdb-runtime') `
|
||||
-extra_args @('--elf', $elf)
|
||||
}
|
||||
build-gte_hello
|
||||
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
# scripts/launch_debug_session.ps1
|
||||
#
|
||||
# Wrapper around pcsx-redux.exe + gdb-multiarch that auto-launches the
|
||||
# gdb_tape_atoms.gdb helper and (optionally) hot-reloads the .ps-exe.
|
||||
#
|
||||
# Generated by track gdb_tape_atom_debugging_20260711 — see
|
||||
# C:\projects\Pikuma\ps1-ai\docs\gdb_tape_atom_debugging.md for the manual.
|
||||
#
|
||||
# usage:
|
||||
# .\launch_debug_session.ps1 # bare gdb attach (assumes pcsx-redux is up)
|
||||
# .\launch_debug_session.ps1 -AutoLoadAtoms # also source gdb_tape_atoms.gdb on startup
|
||||
# .\launch_debug_session.ps1 -AutoResetEmu # hot-reload the .ps-exe before attaching
|
||||
# .\launch_debug_session.ps1 -AutoStartEmu # launch pcsx-redux.exe if not running
|
||||
#
|
||||
# All three flags can be combined: -AutoStartEmu -AutoResetEmu -AutoLoadAtoms
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$AutoLoadAtoms,
|
||||
[switch]$AutoResetEmu,
|
||||
[switch]$AutoStartEmu,
|
||||
[string]$ExePath = (Join-Path $PSScriptRoot '..\build\hello_gte.ps-exe'),
|
||||
[string]$ElfPath = (Join-Path $PSScriptRoot '..\build\hello_gte.elf')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ── Pre-checks (E10: pcsx-redux on :3333, E11: gdb-multiarch in PATH) ──
|
||||
|
||||
function Test-Prerequisites {
|
||||
# E11: gdb-multiarch must be in PATH.
|
||||
if (-not (Get-Command gdb-multiarch -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "gdb-multiarch not found in PATH. Install via scoop or .\update_deps.ps1." -ErrorAction Stop
|
||||
exit 1
|
||||
}
|
||||
|
||||
# E10: pcsx-redux must be reachable on :3333 (or we auto-start).
|
||||
$tcp = New-Object System.Net.Sockets.TcpClient
|
||||
try {
|
||||
$async = $tcp.BeginConnect('localhost', 3333, $null, $null)
|
||||
$connected = $async.AsyncWaitHandle.WaitOne(2000, $false) -and -not $async.IsFaulted
|
||||
} catch {
|
||||
$connected = $false
|
||||
}
|
||||
$tcp.Close()
|
||||
|
||||
if (-not $connected) {
|
||||
if ($AutoStartEmu) {
|
||||
Write-Host "pcsx-redux not running; auto-starting..." -ForegroundColor Cyan
|
||||
$pcsxExe = (Join-Path $PSScriptRoot '..\toolchain\pcsx-redux\vsprojects\x64\Release\pcsx-redux.exe')
|
||||
if (-not (Test-Path $pcsxExe)) {
|
||||
Write-Error "pcsx-redux.exe not found at $pcsxExe. Build it first, or pass -ExePath + start pcsx-redux manually." -ErrorAction Stop
|
||||
exit 1
|
||||
}
|
||||
Start-Process -FilePath $pcsxExe -PassThru | Out-Null
|
||||
Start-Sleep -Seconds 3
|
||||
} else {
|
||||
Write-Error "Cannot connect to pcsx-redux at localhost:3333. Start pcsx-redux first (or pass -AutoStartEmu)." -ErrorAction Stop
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ── Optional: hot-reload .ps-exe via pcsx-redux's web server (port 8080) ──
|
||||
|
||||
function Invoke-HotReload {
|
||||
$absolutePath = [System.IO.Path]::GetFullPath($ExePath)
|
||||
$uri = 'http://localhost:8080/api/v1/load-exec'
|
||||
$body = @{ filename = $absolutePath } | ConvertTo-Json
|
||||
try {
|
||||
Invoke-RestMethod -Uri $uri -Method Post -Body $body -ContentType 'application/json' | Out-Null
|
||||
Write-Host "Hot-reloaded $absolutePath into pcsx-redux." -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Warning "Could not hot-reload via pcsx-redux web server (port 8080): $_"
|
||||
}
|
||||
}
|
||||
|
||||
# ── Main ──
|
||||
|
||||
Test-Prerequisites
|
||||
if ($AutoResetEmu) { Invoke-HotReload }
|
||||
|
||||
$gdbScript = Join-Path $PSScriptRoot 'gdb\gdb_tape_atoms.gdb'
|
||||
|
||||
$gdbArgs = @(
|
||||
'-q'
|
||||
'-ex', "file $ElfPath"
|
||||
'-ex', 'target remote localhost:3333'
|
||||
)
|
||||
if ($AutoLoadAtoms) {
|
||||
$gdbArgs += @('-ex', "source $gdbScript")
|
||||
}
|
||||
|
||||
Write-Host "Launching gdb-multiarch (script: $gdbScript, elf: $ElfPath)..." -ForegroundColor Cyan
|
||||
& gdb-multiarch @gdbArgs
|
||||
@@ -0,0 +1,94 @@
|
||||
# scripts/launch_pcsx_debug.ps1
|
||||
#
|
||||
# One-shot launcher for debug sessions: starts pcsx-redux with the .ps-exe
|
||||
# loaded, the gdb stub enabled, AND the pcsx_debug_helper Lua plugin loaded
|
||||
# so external CLI tools (gdb's `shell` command, etc.)
|
||||
# can read GTE state via http://localhost:8080/api/v1/lua/gte
|
||||
# (the gdb stub doesn't expose COP2 at all).
|
||||
#
|
||||
# usage:
|
||||
# .\scripts\launch_pcsx_debug.ps1
|
||||
# .\scripts\launch_pcsx_debug.ps1 -ExePath build\hello_gte.ps-exe
|
||||
# .\scripts\launch_pcsx_debug.ps1 -HelperZip scripts\pcsx_debug_helper.zip
|
||||
#
|
||||
# After launch:
|
||||
# - gdb: target remote localhost:3333
|
||||
# - web: curl http://localhost:8080/api/v1/lua/gte
|
||||
#
|
||||
# Companion: scripts/debug_psyq.ps1 (bare launch — no .ps-exe, no helper).
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$PcsxPath = (Join-Path $PSScriptRoot '..\toolchain\pcsx-redux\vsprojects\x64\Release\pcsx-redux.exe'),
|
||||
[string]$ExePath = (Join-Path $PSScriptRoot '..\build\hello_gte.ps-exe'),
|
||||
[string]$HelperZip = (Join-Path $PSScriptRoot 'pcsx_debug_helper.zip'),
|
||||
[int] $GdbPort = 3333,
|
||||
[int] $WebPort = 8080
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ── Pre-checks ──
|
||||
foreach ($p in @($PcsxPath, $ExePath, $HelperZip)) {
|
||||
if (-not (Test-Path $p)) {
|
||||
Write-Error "Missing: $p"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Kill any existing pcsx-redux so the archive file isn't locked.
|
||||
Get-Process pcsx-redux -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
# ── Launch ──
|
||||
$absExe = [System.IO.Path]::GetFullPath($ExePath)
|
||||
$absZip = [System.IO.Path]::GetFullPath($HelperZip)
|
||||
|
||||
$args = @(
|
||||
'-gdb', '-run'
|
||||
'-loadexe', "`"$absExe`""
|
||||
'-archive', "`"$absZip`""
|
||||
)
|
||||
|
||||
Write-Host "Launching pcsx-redux..." -ForegroundColor Cyan
|
||||
Write-Host " ps-exe : $absExe"
|
||||
Write-Host " helper zip: $absZip"
|
||||
Write-Host " gdb : localhost:$GdbPort"
|
||||
Write-Host " web : localhost:$WebPort/api/v1/lua/gte"
|
||||
Write-Host ""
|
||||
|
||||
Start-Process -FilePath $PcsxPath -ArgumentList $args | Out-Null
|
||||
|
||||
# ── Wait for both endpoints to come up ──
|
||||
$deadline = (Get-Date).AddSeconds(15)
|
||||
while ((Get-Date) -lt $deadline) {
|
||||
$gdbUp = $false
|
||||
$webUp = $false
|
||||
try {
|
||||
$tcp = New-Object System.Net.Sockets.TcpClient
|
||||
$tcp.BeginConnect('localhost', $GdbPort, $null, $null) | Out-Null
|
||||
Start-Sleep -Milliseconds 100
|
||||
$gdbUp = $tcp.Connected
|
||||
$tcp.Close()
|
||||
} catch { $gdbUp = $false }
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/" -UseBasicParsing -TimeoutSec 1 -ErrorAction SilentlyContinue
|
||||
$webUp = $r.StatusCode -ne 0
|
||||
} catch { $webUp = $false }
|
||||
if ($gdbUp -and $webUp) { break }
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
|
||||
# ── Smoke-test the gte handler ──
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri "http://localhost:$WebPort/api/v1/lua/gte" -UseBasicParsing -TimeoutSec 5
|
||||
$firstLine = ([System.Text.Encoding]::UTF8.GetString($r.Content) -split "`n")[0]
|
||||
Write-Host "GTE handler OK: $firstLine" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Warning "GTE handler NOT responding: $_"
|
||||
Write-Host "Check the pcsx-redux Lua Console for debug cli messages." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "pcsx-redux running. PIDs:" -ForegroundColor Cyan
|
||||
Get-Process pcsx-redux | Select-Object Id, ProcessName | Format-Table
|
||||
@@ -2,22 +2,23 @@
|
||||
---
|
||||
--- Reads the pre-scanned SourceScan payload (produced once upstream by `duffle.scan_source`)
|
||||
--- for `MipsAtom_(name)` (kind="atom"), `MipsAtomComp_` / `MipsAtomComp_Proc_` (kind="comp_*"),
|
||||
--- and `MipsCode code_<name>` (kind="raw_atom") declarations. Walks each atom's
|
||||
--- pre-tokenized body (`{{tok=string, rel=integer}, ...}` from `duffle.tokenize_body`), counts
|
||||
--- per-token word contributions via `ctx.shared.word_counts`, and emits one
|
||||
--- `WORD N LINE L TEXT T` line per `.word` to `gen/<basename>.atoms.sourcemap.txt`.
|
||||
--- and `MipsCode code_<name>` (kind="raw_atom") declarations.
|
||||
--- Walks each atom's pre-tokenized body (`{{tok=string, rel=integer}, ...}` from `duffle.tokenize_body`),
|
||||
--- counts per-token word contributions via `ctx.shared.word_counts`, and emits one
|
||||
--- `WORD N LINE L TEXT T` line per `.word` to `<out_root>/<basename>.atoms.sourcemap.txt`.
|
||||
---
|
||||
--- **Two output forms** (per the workspace's per-emission-form pattern from
|
||||
--- `guide_metaprogram_ssdl.md`):
|
||||
--- 1. **Canonical text form** — `<source_dir>/gen/<basename>.atoms.sourcemap.txt`.
|
||||
--- Always emitted. Format-version-tagged for forward-compat.
|
||||
--- 2. **gdb-runtime form** — `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` (pure
|
||||
--- gdb command script; addresses pre-computed via `nm`; the 9 user commands
|
||||
--- defined as `define ... end` blocks). Emitted ONLY when
|
||||
--- `ctx.flags.gdb_runtime` is true AND `ctx.flags.elf_path` points to an
|
||||
--- existing ELF. The gdb runtime form lets `gdb-multiarch --without-python`
|
||||
--- users (the common case on Windows MinGW builds) load the source-map data
|
||||
--- via `source <path>` — no Python/Tcl/Guile required.
|
||||
--- 1. **Canonical text form** — `<out_root>/<basename>.atoms.sourcemap.txt`.
|
||||
--- Always emitted. Format-version-tagged for forward-compat.
|
||||
--- Lives in `<out_root>/` (build/gen) NOT `<source_dir>/gen/`. This file is a **build report**, not a compile artifact.
|
||||
--- Matches the convention used by `annotation.lua` (`<out_root>/<basename>.errors.h`) + `static_analysis.lua` (`<out_root>/<basename>.static_analysis.txt`).
|
||||
--- Compile artifacts (`*.macs.h`, `*.offsets.h`) stay in `<source_dir>/gen/`.
|
||||
--- 2. **gdb-runtime form** — `<ctx.out_root>/gdb_tape_atoms_runtime.gdb`
|
||||
--- (pure gdb command script; addresses pre-computed via `nm`; the 9 user commands defined as `define ... end` blocks).
|
||||
--- Emitted ONLY when `ctx.flags.gdb_runtime` is true AND `ctx.flags.elf_path` points to an existing ELF.
|
||||
--- The gdb runtime form lets `gdb-multiarch --without-python` users (the common case on Windows MinGW builds)
|
||||
--- load the source-map data via `source <path>` — no Python/Tcl/Guile required.
|
||||
---
|
||||
--- **Output format** (canonical text form):
|
||||
--- ```
|
||||
@@ -33,16 +34,14 @@
|
||||
--- ENDATOM
|
||||
--- ```
|
||||
---
|
||||
--- Marker calls (`atom_label(...)`, `atom_offset(...)`) emit 0 `.word`s. They share the
|
||||
--- same walking convention as `passes/offsets.lua :: scan_atom_body`: markers do NOT
|
||||
--- advance the word-offset counter, but if a marker is bundled on the same token with a
|
||||
--- trailing instruction (e.g. `atom_label(foo) load_half_u(...)`), the trailing
|
||||
--- instruction's word count is added. This matches `offsets.lua :: count_marker_rest`.
|
||||
--- Marker calls (`atom_label(...)`, `atom_offset(...)`) emit 0 `.word`s.
|
||||
--- They share the same walking convention as `passes/offsets.lua :: scan_atom_body`:
|
||||
--- markers do NOT advance the word-offset counter, but if a marker is bundled on the same token with a
|
||||
--- trailing instruction (e.g. `atom_label(foo) load_half_u(...)`),
|
||||
--- the trailing instruction's word count is added. This matches `offsets.lua :: count_marker_rest`.
|
||||
---
|
||||
--- **Conventions:** tabs (1/level), EmmyLua annotations, no regex,
|
||||
--- Lua 5.3 compatible. See "lua.md" in the ps1-ai styleguides.
|
||||
---
|
||||
--- Provenance: generated 2026-07-11 by track gdb_tape_atom_debugging_20260711.
|
||||
--- Lua 5.3 compatible.
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
-- Module-scope requires + package.path setup
|
||||
@@ -68,19 +67,6 @@ local FORMAT_VERSION = 1
|
||||
local LABEL_MARKER = "atom_label"
|
||||
local OFFSET_MARKER = "atom_offset"
|
||||
|
||||
-- gdb-runtime file header + atom-count default for C2 alias table (32 entries).
|
||||
local C2_DATA_ALIASES = {
|
||||
"v0.xy", "v0.z", "v1.xy", "v1.z", "v2.xy", "v2.z",
|
||||
"rgb", "otz",
|
||||
"ir0", "ir1", "ir2", "ir3",
|
||||
"sxy0", "sxy1", "sxy2", "sxyp",
|
||||
"sz0", "sz1", "sz2", "sz3",
|
||||
"rgb_fifo", "mac0_in",
|
||||
"?", "?", "?", "?",
|
||||
"mac0", "mac1", "mac2", "mac3",
|
||||
"mac4", "mac5", "mac6", "mac7",
|
||||
}
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
-- Type declarations
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
@@ -106,9 +92,9 @@ local function is_marker_token(tok)
|
||||
return leading == LABEL_MARKER or leading == OFFSET_MARKER
|
||||
end
|
||||
|
||||
--- Count words contributed by the non-marker portion of `tok` (after the marker's
|
||||
--- closing `)`). Mirrors offsets.lua:182 `count_marker_rest`. Returns 0 if there's
|
||||
--- no trailing content after the marker call.
|
||||
--- Count words contributed by the non-marker portion of `tok` (after the marker's closing `)`).
|
||||
--- Mirrors offsets.lua:182 `count_marker_rest`.
|
||||
--- Returns 0 if there's no trailing content after the marker call.
|
||||
--- @param tok string
|
||||
--- @param wc table
|
||||
--- @return integer
|
||||
@@ -120,9 +106,9 @@ local function count_marker_rest(tok, wc)
|
||||
return count_token_words(rest, wc)
|
||||
end
|
||||
|
||||
--- Compute per-word entries for an atom. Shared between the canonical text form
|
||||
--- (per-source `.atoms.sourcemap.txt`) and the gdb-runtime form
|
||||
--- (`gdb_tape_atoms_runtime.gdb`).
|
||||
--- Compute per-word entries for an atom.
|
||||
--- Shared between the canonical text form (per-source `.atoms.sourcemap.txt`)
|
||||
--- and the gdb-runtime form (`gdb_tape_atoms_runtime.gdb`).
|
||||
---
|
||||
--- Returns a list of `{pos, line, text}` entries + the total word count.
|
||||
--- Markers contribute 0 entries (the marker call emits 0 `.word`s).
|
||||
@@ -245,8 +231,8 @@ local function gdb_escape(s)
|
||||
return (s:gsub("\\", "\\\\"):gsub('"', '\\"'))
|
||||
end
|
||||
|
||||
--- Build the list of atoms with addresses + word entries. Shared helper for the
|
||||
--- gdb-runtime file emission.
|
||||
--- Build the list of atoms with addresses + word entries.
|
||||
--- Shared helper for the gdb-runtime file emission.
|
||||
--- @param ctx PassCtx
|
||||
--- @return table[] -- list of {idx, name, src_path, file_base, addr, size_bytes, words, entries}
|
||||
local function build_atom_table(ctx)
|
||||
@@ -302,15 +288,13 @@ local function build_atom_table(ctx)
|
||||
return matched
|
||||
end
|
||||
|
||||
--- Append the 9 gdb command definitions to `lines`. Pure gdb scripting —
|
||||
--- no Python, no Tcl, no Guile required. **Fully hardcoded per-atom** because
|
||||
--- gdb doesn't do nested `$` substitution in var names — `$__atom_name_$__i`
|
||||
--- inside a `while` loop is treated as one literal identifier, not a concat.
|
||||
--- Append the 9 gdb command definitions to `lines`. Pure gdb scripting no Python, no Tcl, no Guile required.
|
||||
--- **Fully hardcoded per-atom** because gdb doesn't do nested `$` substitution in var names
|
||||
--- `$__atom_name_$__i` inside a `while` loop is treated as one literal identifier, not a concat.
|
||||
---
|
||||
--- Each command is a static sequence of `printf` / `tbreak` / `if ... end`
|
||||
--- blocks. The Lua pass emits N atoms' worth of lines — no runtime iteration.
|
||||
--- With 7 atoms + ~200 word entries, the runtime file is ~2000 lines, all
|
||||
--- auto-generated, no human edit ever.
|
||||
--- Each command is a static sequence of `printf` / `tbreak` / `if ... end` blocks.
|
||||
--- The Lua pass emits N atoms' worth of lines — no runtime iteration.
|
||||
--- With 7 atoms + ~200 word entries, the runtime file is ~2000 lines, all auto-generated, no human edit ever.
|
||||
--- @param lines table -- output line buffer (mutated in place)
|
||||
--- @param matched table -- list of atom records from `build_atom_table`
|
||||
local function append_gdb_commands(lines, matched)
|
||||
@@ -382,10 +366,11 @@ local function append_gdb_commands(lines, matched)
|
||||
lines[#lines + 1] = " set $__pc = (unsigned int)$pc"
|
||||
lines[#lines + 1] = " set $__matched = 0"
|
||||
for _, a in ipairs(matched) do
|
||||
local end_addr = a.addr + a.words * 4
|
||||
-- Precompute end_addr (gdb 12.1's expression evaluator chokes on `addr + words*4`).
|
||||
lines[#lines + 1] = string.format(
|
||||
" if $__pc >= $__atom_addr_%d && $__pc < $__atom_addr_%d + $__atom_words_%d * 4",
|
||||
a.idx, a.idx, a.idx)
|
||||
" set $__end_%d = $__atom_addr_%d + $__atom_words_%d * 4", a.idx, a.idx, a.idx)
|
||||
lines[#lines + 1] = string.format(
|
||||
" if $__pc >= $__atom_addr_%d && $__pc < $__end_%d", a.idx, a.idx)
|
||||
lines[#lines + 1] = string.format(
|
||||
' printf "atom: code_%%s\\n", $__atom_name_%d', a.idx)
|
||||
lines[#lines + 1] = ' printf "addr: 0x%08x\\n", $__pc'
|
||||
@@ -425,14 +410,19 @@ local function append_gdb_commands(lines, matched)
|
||||
|
||||
-- ── stepi_inside_atom ──
|
||||
-- Hardcoded one if-containment-check per atom (no loop).
|
||||
-- Precompute end_addr in Lua so we don't ask gdb to evaluate `addr + words*4`
|
||||
-- inside the if condition (gdb 12.1's expression evaluator chokes on the
|
||||
-- `*` and emits a misleading 'function malloc' error in some gdb builds).
|
||||
lines[#lines + 1] = "define stepi_inside_atom"
|
||||
lines[#lines + 1] = " set $__in_atom = 0"
|
||||
lines[#lines + 1] = " set $__did_step = 0"
|
||||
lines[#lines + 1] = " set $__pc = (unsigned int)$pc"
|
||||
for _, a in ipairs(matched) do
|
||||
local end_addr = a.addr + a.words * 4
|
||||
-- Precompute end_addr in the convenience var (single expression gdb handles).
|
||||
lines[#lines + 1] = string.format(
|
||||
" if $pc >= $__atom_addr_%d && $pc < $__atom_addr_%d + $__atom_words_%d * 4",
|
||||
a.idx, a.idx, a.idx)
|
||||
" set $__end_%d = $__atom_addr_%d + $__atom_words_%d * 4", a.idx, a.idx, a.idx)
|
||||
lines[#lines + 1] = string.format(
|
||||
" if $__pc >= $__atom_addr_%d && $__pc < $__end_%d", a.idx, a.idx)
|
||||
lines[#lines + 1] = " set $__in_atom = 1"
|
||||
lines[#lines + 1] = " stepi"
|
||||
lines[#lines + 1] = " set $__did_step = 1"
|
||||
@@ -448,30 +438,29 @@ local function append_gdb_commands(lines, matched)
|
||||
lines[#lines + 1] = "end"
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
-- ── show_c2 (32 entries) ──
|
||||
-- Hardcoded with `$c2_data[N]` (COP2 data regs). Requires target attached.
|
||||
-- ── show_c2 ──
|
||||
-- GTE data regs (COP2). pcsx-redux's gdb stub doesn't expose COP2 (only
|
||||
-- 72 regs: 32 GPR + COP0 + FPR).
|
||||
-- curl http://localhost:8080/api/v1/lua/gte
|
||||
-- We keep the command definition as a stub that points the user at the plugin.
|
||||
lines[#lines + 1] = "define show_c2"
|
||||
for i = 0, 31 do
|
||||
local alias = C2_DATA_ALIASES[i + 1] or "?"
|
||||
lines[#lines + 1] = string.format(
|
||||
' printf "C2[%%2d] 0x%%08x [%%s]\\n", %d, $c2_data[%d], "%s"',
|
||||
i, i, alias)
|
||||
end
|
||||
lines[#lines + 1] = ' echo "[gdb_tape_atoms] show_c2: gdb stub does not expose COP2 in this build."'
|
||||
lines[#lines + 1] = ' echo "[gdb_tape_atoms] Use scripts/pcsx_debug_helper.zip + curl http://localhost:8080/api/v1/lua/gte"'
|
||||
lines[#lines + 1] = ' echo "[gdb_tape_atoms] (or pcsx-redux Debug > Registers window for a native view)"'
|
||||
lines[#lines + 1] = "end"
|
||||
lines[#lines + 1] = "document show_c2"
|
||||
lines[#lines + 1] = " Pretty-print all 32 C2 data registers as hex + named alias. Requires target attached."
|
||||
lines[#lines + 1] = " Stub. The gdb stub in this pcsx-redux build does not expose COP2 regs."
|
||||
lines[#lines + 1] = " For GTE data + control state, use the pcsx_debug_helper Lua plugin or the"
|
||||
lines[#lines + 1] = " pcsx-redux Debug > Registers window."
|
||||
lines[#lines + 1] = "end"
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
-- ── show_c2ctl (32 entries) ──
|
||||
-- ── show_c2ctl ──
|
||||
lines[#lines + 1] = "define show_c2ctl"
|
||||
for i = 0, 31 do
|
||||
lines[#lines + 1] = string.format(
|
||||
' printf "C2CTL[%%2d] 0x%%08x\\n", %d, $c2_control[%d]', i, i)
|
||||
end
|
||||
lines[#lines + 1] = ' echo "[gdb_tape_atoms] show_c2ctl: see show_c2 for the same workaround."'
|
||||
lines[#lines + 1] = "end"
|
||||
lines[#lines + 1] = "document show_c2ctl"
|
||||
lines[#lines + 1] = " Pretty-print all 32 C2 control registers as hex. Requires target attached."
|
||||
lines[#lines + 1] = " Stub. Same workaround as show_c2."
|
||||
lines[#lines + 1] = "end"
|
||||
lines[#lines + 1] = ""
|
||||
|
||||
@@ -488,9 +477,8 @@ local function append_gdb_commands(lines, matched)
|
||||
end
|
||||
|
||||
--- Emit the gdb-runtime file (post-link). Pure gdb scripting — no Python.
|
||||
--- Reads ELF addresses via `mipsel-none-elf-nm -S`, embeds them in
|
||||
--- `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` so gdb loads the data via
|
||||
--- `set $var = ...` + `define ... end` blocks at source-time.
|
||||
--- Reads ELF addresses via `mipsel-none-elf-nm -S`, embeds them in `<ctx.out_root>/gdb_tape_atoms_runtime.gdb`
|
||||
--- so gdb loads the data via `set $var = ...` + `define ... end` blocks at source-time.
|
||||
--- @param ctx PassCtx
|
||||
local function emit_gdb_runtime(ctx)
|
||||
if not (ctx.flags and ctx.flags.gdb_runtime) then return end
|
||||
@@ -563,7 +551,7 @@ end
|
||||
|
||||
local M = {}
|
||||
|
||||
--- Pass entry: emit one `gen/<basename>.atoms.sourcemap.txt` per source file
|
||||
--- Pass entry: emit one `<out_root>/<basename>.atoms.sourcemap.txt` per source file
|
||||
--- that contains at least one `MipsAtom_(name)` / `MipsCode code_<name>` declaration.
|
||||
--- Optionally also emit `<ctx.out_root>/gdb_tape_atoms_runtime.gdb` when
|
||||
--- `ctx.flags.gdb_runtime` is true.
|
||||
@@ -591,7 +579,10 @@ function M.run(ctx)
|
||||
local n_raw_atoms = src.scan.raw_atoms and #src.scan.raw_atoms or 0
|
||||
if n_atoms + n_raw_atoms > 0 then
|
||||
local basename = duffle.basename_no_ext(src.path)
|
||||
local out_path = src.dir .. "/gen/" .. basename .. ".atoms.sourcemap.txt"
|
||||
-- Build report, NOT compile artifact: live in <out_root> alongside the other reports
|
||||
-- (annotation.lua's *.errors.h, static_analysis.lua's *.static_analysis.txt, gdb_tape_atoms_runtime.gdb).
|
||||
-- The per-source <source_dir>/gen/ is reserved for headers actually #included by C.
|
||||
local out_path = ctx.out_root .. "/" .. basename .. ".atoms.sourcemap.txt"
|
||||
local content = render_source_map(src, wc)
|
||||
|
||||
if not ctx.dry_run then
|
||||
@@ -612,4 +603,4 @@ function M.run(ctx)
|
||||
return { outputs = outputs, errors = errors, warnings = warnings }
|
||||
end
|
||||
|
||||
return M
|
||||
return M
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,55 @@
|
||||
-- autoexec.lua - pcsx_debug_helper plugin entry point.
|
||||
-- Packaged in scripts/pcsx_debug_helper.zip. Loaded by pcsx-redux via
|
||||
-- the -archive CLI flag (see scripts/launch_pcsx_debug.ps1).
|
||||
--
|
||||
-- Registers two web handlers for external CLI tools:
|
||||
-- /api/v1/lua/gte - full GTE state (32 data + 32 control regs + PC)
|
||||
-- /api/v1/lua/gp - GP state summary (screenshot endpoint + VRAM endpoint refs)
|
||||
--
|
||||
-- The GTE handler reads COP2 regs via PCSX.getRegisters().CP2D/CP2C. The
|
||||
-- pcsx-redux gdb stub doesn't expose COP2, so this is the only way for
|
||||
-- external tools to see GTE state.
|
||||
--
|
||||
-- The GP handler is a thin pointer: pcsx-redux's Lua API exposes only PCSX.GPU.takeScreenShot()
|
||||
-- (no GPUSTAT, no GP0/GP1 command log, no display state). For richer GP state, the existing web endpoints are the practical path:
|
||||
-- /api/v1/state/still - PNG screenshot
|
||||
-- /api/v1/gpu/vram/raw - VRAM raw bytes (1MB)
|
||||
--
|
||||
-- Companion: scripts/gdb/gdb_tape_atoms.gdb (covers GPRs + atom-aware stepping).
|
||||
|
||||
local function register_handlers()
|
||||
if not PCSX.WebServer then PCSX.WebServer = {} end
|
||||
if not PCSX.WebServer.Handlers then PCSX.WebServer.Handlers = {} end
|
||||
|
||||
-- ── GTE state ──
|
||||
PCSX.WebServer.Handlers.gte = function(req)
|
||||
local r = PCSX.getRegisters()
|
||||
local out = { "pc=0x" .. string.format("%x", r.pc) }
|
||||
for i = 0, 31 do
|
||||
out[#out + 1] = string.format("D[%d]=0x%08x C[%d]=0x%08x",
|
||||
i, r.CP2D.r[i], i, r.CP2C.r[i])
|
||||
end
|
||||
return table.concat(out, "\n")
|
||||
end
|
||||
|
||||
-- ── GP state (pointer to existing endpoints) ──
|
||||
-- pcsx-redux's Lua GPU API exposes only takeScreenShot(); no GPUSTAT / GP0 / GP1 command log / display state.
|
||||
-- We point to the existing web endpoints that DO expose those (when the emulator is actually rendering. Paused-at-BP frames won't have a fresh frame).
|
||||
PCSX.WebServer.Handlers.gp = function(req)
|
||||
local out = {
|
||||
"gpu_screenshot_png=http://localhost:8080/api/v1/state/still",
|
||||
"vram_raw=http://localhost:8080/api/v1/gpu/vram/raw (1MB VRAM)",
|
||||
"gpustat=NOT_AVAILABLE_VIA_LUA",
|
||||
"gp_command_log=NOT_AVAILABLE_VIA_LUA (use pcsx-redux Debug > GPU Logger)",
|
||||
"hint_run_emulator_unpaused_for_screenshot",
|
||||
}
|
||||
return table.concat(out, "\n")
|
||||
end
|
||||
end
|
||||
|
||||
local ok, err = pcall(register_handlers)
|
||||
if ok then
|
||||
print("[pcsx_debug_helper] handlers registered: gte, gp")
|
||||
else
|
||||
print("[pcsx_debug_helper] registration failed: " .. tostring(err))
|
||||
end
|
||||
Reference in New Issue
Block a user