بنقرة واحدة
mtdedimod-debugging
Debugging crash dumps, PDB symbols, and UE4SS Lua GC issues in MTDediMod
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Debugging crash dumps, PDB symbols, and UE4SS Lua GC issues in MTDediMod
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Building, packaging, and deploying MTDediMod releases (server and client mods)
SSH access to AMC servers and debugging amc-backend services
Managing ragenix-encrypted secrets in the AMC monorepo
| name | mtdedimod-debugging |
| description | Debugging crash dumps, PDB symbols, and UE4SS Lua GC issues in MTDediMod |
The MTDediMod cross-compilation build pipeline produces Windows DLLs from Linux/macOS via Clang/LLD. The server runs on NixOS under Wine/Proton. UE5 generates minidumps that must be matched with PDB symbols for analysis.
ssh root@amc-peripheral 'ls -lt /var/lib/motortown-server/MotorTown/Saved/Crashes/*/UEMinidump.dmp | head -5'
UE5's built-in crash reporter writes dumps to MotorTown/Saved/Crashes/UECC-Windows-*/UEMinidump.dmp. No custom exception filter is needed.
scp root@amc-peripheral:/var/lib/motortown-server/MotorTown/Saved/Crashes/.../UEMinidump.dmp /tmp/latest.dmp
ssh root@amc-peripheral 'cat /var/lib/motortown-server/.mod-cache/extracted-*/BUILD_REVISION.txt'
.sym formatnix-shell -p dump_syms --run "dump_syms symbols-archive/<tag>/UE4SS.pdb > /tmp/UE4SS.sym"
minidump_stackwalknix-shell -p breakpad --run "minidump_stackwalk /tmp/latest.dmp symbols-archive/<tag>/"
This prints thread stacks. Look for Thread 0 (crashed) to find the faulting instruction.
.sym file# Python script to resolve addresses from the .sym file
with open('/tmp/UE4SS.sym') as f:
syms = f.read().splitlines()
funcs = []
for line in syms:
if line.startswith('FUNC '):
parts = line.split()
addr = int(parts[1], 16)
size = int(parts[2], 16)
name = parts[4] if len(parts) > 4 else parts[3]
funcs.append((addr, size, name))
def resolve(addr):
for a, s, n in funcs:
if a <= addr < a + s:
return f'{n} + {hex(addr - a)}'
return f'[unknown {hex(addr)}]'
Symptom: PDBs exist and have matching GUIDs, but minidump-stackwalk cannot auto-match them. minidump_dump shows no CODEVIEW records in the module list.
Root cause: lld-link with /DEBUG:FULL creates valid PDBs and embeds RSDS CodeView records in the PE binary, but fails to write the IMAGE_DEBUG_DIRECTORY entry that points to the RSDS record.
Fix: A Python post-link patcher (tools/patch-pe-debug-dir.py) locates the embedded RSDS record and writes the missing IMAGE_DEBUG_DIRECTORY (type=2 CODEVIEW) entry. Integrated into buildScript and buildClientScript in flake.nix so it auto-runs after linking.
Symptom: EXCEPTION_ACCESS_VIOLATION_READ at 0x0 in UE4SS.dll, crash inside luaC_checkfinalizer at lgc.c:1035. Call stack includes:
convert_struct_to_lua_tableUFunction::constructlua_setmetatableluaC_checkfinalizerTrigger: Heavy nested struct-to-table conversion, e.g. /player_vehicles/*/list?complete=1 iterating through Net_Parts with nested TArrays.
Root cause: Two interacting bugs:
Lua 5.4.7 weak-table + metatable GC bug (upstream, fixed in Lua master but not 5.4.7):
When a metatable is created on an all-weak table during the GC propagate phase, the table must be re-linked to grayagain so its metatable is traversed. Without this fix the GC lists become corrupted.
Patch (patches-ue4ss/lua-lgc-weak-table-metatable-fix.patch):
else { /* all weak */
if (g->gcstate == GCSpropagate)
linkgclist(h, g->grayagain); /* must visit again its metatable */
else
linkgclist(h, g->allweak); /* must clear collected entries */
}
UE4SS convert_struct_to_lua_table creates userdata via UFunction::construct:
Delegate/function properties trigger UFunction::construct which calls lua_setmetatable on fresh userdata. This is the exact path that crashes when GC lists are corrupted.
Patch (patches-ue4ss/ue4ss-skip-delegate-properties-in-struct-conversion.patch):
Skip delegate/function properties during struct-to-table conversion:
if (can_handle && (field->IsA<Unreal::FDelegateProperty>() ||
field->IsA<Unreal::FMulticastDelegateProperty>() ||
field->IsA<Unreal::FMulticastInlineDelegateProperty>() ||
field->IsA<Unreal::FMulticastSparseDelegateProperty>()))
{
can_handle = false;
}
Related upstream PRs:
nix run --no-update-lock-file .#archive-symbols
This copies symbols/ into symbols-archive/<git-tag>/ with BUILD_REVISION.txt.
A new build produces a new PDB — it will not work for old crash dumps. You must keep archived PDBs per-release.
nix run --no-update-lock-file .#analyze-crash -- /path/to/crash.dmp
This loads the minidump and attaches the matching PDBs for basic inspection.
In toolchain.cmake and setup_cross_compile.sh:
/Zi — compiler debug info (release builds)/DEBUG:FULL — linker produces full PDBsThe package scripts extract PDBs into symbols/ (server) and symbols-client/ (client) — these are not shipped in release zips.
amc-peripheral via NixOS deployasean-mt-server via NixOS deployBoth servers are accessed via Tailscale SSH.