M-27: D146 unknown-GBI-opcode -> end DL instead of abort(); tools_pc/debug.ps1

D146 (port/fast3d/gfx_pc.cpp): an unrecognised opcode in the DL walk called
sysFatalError() -> abort() -> whole process dies with no ge007.crash.log
(the crash handler does not cover abort). Seen on the real post-Dam
MISSION COMPLETE screen: "[FATAL] Unknown GBI opcode 0x40c03 at
0x70161a8c" - a front-end 3D model (dossier, D75/D144 family) whose display
list was never built, sitting at a valid DRAM address full of junk. D144
guarded the bad matrix pointer; the walk then hit more garbage. Now: log
loudly (rate-limited x20) and `return` to end the (sub-)DL so the frame
finishes. A real level-render desync is still visible in the log.

tools_pc/debug.ps1: launch the port under gdb from the repo root so a
playtest crash always leaves a backtrace (abort/fatal or silent exit).
-Menu <id> sets GE_STARTMENU; passes through -level_XX etc. Prints the
FATAL line + backtrace + crash log when the game exits.

Verified: GE_STARTMENU=13 mission-complete -> Next chain renders, no abort,
no crash (D75 model cosmetics aside).
This commit is contained in:
James Dansereau committed 2026-08-30 15:27:23 -04:00
1 parent 080056b125
commit cea9ce0df9
2 files changed
+98 -2

No files matched your search

+20 -2
View File
@@ -2757,8 +2757,26 @@ static void gfx_run_dl(Gfx* cmd) {
i * 4, r[i], r[i + 1], r[i + 2], r[i + 3]);
}
}
sysFatalError("Unknown GBI opcode 0x%02x at %p.\nw0 %08x\nw1 %08x", opcode, cmd, cmd->words.w0, cmd->words.w1);
break;
/* D146: an unknown opcode means the DL walk has desynced or
* this DL is garbage (a front-end 3D model whose display list
* was never built - the D75 / D144 family - lives at a valid
* DRAM address full of junk). Aborting the whole process over
* one bad menu model is the wrong trade for a breadth-first
* port: end this (sub-)DL and let the frame finish. Still
* logged loudly, rate-limited, so a real level-render desync
* is not hidden. */
{
static int warned = 0;
if (warned < 20) {
warned++;
sysLogPrintf(LOG_ERROR,
"D146: unknown GBI opcode 0x%02x at %p (w0=%llx w1=%llx) - ending DL",
opcode, (void *)cmd,
(unsigned long long)cmd->words.w0,
(unsigned long long)cmd->words.w1);
}
}
return;
}
}
++cmd;
+78
View File
@@ -0,0 +1,78 @@
<#
debug.ps1 - launch the PC port under gdb so a playtest crash always leaves
a backtrace, even when it is an abort()/sysFatalError (no ge007.crash.log)
or a silent exit.
Usage (from repo root):
.\tools_pc\debug.ps1 # front-end / menu playtest
.\tools_pc\debug.ps1 -level_09 # boot straight into a level
.\tools_pc\debug.ps1 -Menu 13 # GE_STARTMENU=13 (mission-complete)
.\tools_pc\debug.ps1 -Menu 13 -Page 1 -Diff 0
.\tools_pc\debug.ps1 -InputLog # also GE_INPUTLOG=1
Everything gdb prints goes to gdb.txt. When the game exits (crash or
clean) the script prints the FATAL line, the backtrace, and the crash
log if one was written.
#>
[CmdletBinding()]
param(
[int]$Menu = -1,
[int]$Page = 1,
[int]$Diff = 0,
[switch]$InputLog,
[string]$Gdb = "C:\msys64\mingw64\bin\gdb.exe",
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$GameArgs
)
$ErrorActionPreference = "Stop"
$exe = "build-pc\ge007.x86_64.exe"
if (-not (Test-Path $exe)) { throw "build the port first: bash build-pc.sh ntsc-final" }
if (-not (Test-Path $Gdb)) { throw "gdb not found at $Gdb (pass -Gdb <path>)" }
Remove-Item -ErrorAction SilentlyContinue ge007.crash.log, gdb.txt
if ($Menu -ge 0) {
$env:GE_STARTMENU = "$Menu"
$env:GE_STARTMENU_PAGE = "$Page"
$env:GE_STARTMENU_DIFF = "$Diff"
Write-Host "GE_STARTMENU=$Menu page=$Page diff=$Diff" -ForegroundColor Cyan
} else {
Remove-Item -ErrorAction SilentlyContinue Env:\GE_STARTMENU, Env:\GE_STARTMENU_PAGE, Env:\GE_STARTMENU_DIFF
}
if ($InputLog) { $env:GE_INPUTLOG = "1" } else { Remove-Item -ErrorAction SilentlyContinue Env:\GE_INPUTLOG }
$gdbArgs = @(
"-batch",
"-ex", "set pagination off",
"-ex", "set confirm off",
"-ex", "run",
"-ex", "echo `n==== BACKTRACE ====`n",
"-ex", "bt full",
"-ex", "echo `n==== REGISTERS ====`n",
"-ex", "info registers",
"-ex", "echo `n==== ALL THREADS ====`n",
"-ex", "thread apply all bt",
"--args", $exe
) + $GameArgs
Write-Host "launching under gdb - play until it crashes, output -> gdb.txt" -ForegroundColor Green
& $Gdb @gdbArgs 2>&1 | Tee-Object -FilePath gdb.txt | Out-Null
Write-Host "`n===================== RESULT =====================" -ForegroundColor Yellow
$fatal = Select-String -Path gdb.txt -Pattern "FATAL|Unknown GBI|assertion|abort\(\)" | Select-Object -First 5
if ($fatal) { Write-Host "-- fatal / abort --" -ForegroundColor Red; $fatal | ForEach-Object { $_.Line } }
Write-Host "`n-- backtrace --" -ForegroundColor Red
$bt = Get-Content gdb.txt
$i = ($bt | Select-String -Pattern "==== BACKTRACE ====" | Select-Object -First 1).LineNumber
if ($i) { $bt[$i..([Math]::Min($i + 45, $bt.Count - 1))] | Where-Object { $_ -match '\S' } }
else { $bt | Select-String -Pattern "^#\d+|\.c:\d|\.cpp:\d|SIG|exited with code" | Select-Object -Last 40 | ForEach-Object { $_.Line } }
if (Test-Path ge007.crash.log) {
Write-Host "`n-- ge007.crash.log --" -ForegroundColor Red
Get-Content ge007.crash.log
} else {
Write-Host "`n(no ge007.crash.log - abort()/fatal or clean exit; see backtrace above)" -ForegroundColor DarkGray
}
Write-Host "`nfull gdb output: gdb.txt" -ForegroundColor DarkGray