Decompilation unk files generation
This commit is contained in:
parent
d323bb28fc
commit
746709f40c
503 changed files with 45757 additions and 31 deletions
182
docs/dosbox-x.debugger.md
Normal file
182
docs/dosbox-x.debugger.md
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
Information about the DOSBox-X Debugger
|
||||
|
||||
Debugger interface
|
||||
------------------
|
||||
|
||||
In builds where it is enabled, DOSBox-X supports breaking into the debugger
|
||||
interface, which is shown on the console.
|
||||
|
||||
A mapper shortcut is provided to break into the debugger on demand. Normally
|
||||
this shortcut is set to Alt+Pause (Mac: Alt+F12).
|
||||
|
||||
In Windows, DOSBox-X can create a console and show the debugger interface
|
||||
on it.
|
||||
|
||||
On other systems including Linux and Mac OS X, DOSBox-X must be started
|
||||
from a terminal in order to enable the debugger.
|
||||
|
||||
The debugger interface should scale and respond to resizing of the
|
||||
terminal window.
|
||||
|
||||
WARNING: Fitting to the window was added in DOSBox-X. The debugger
|
||||
interface in DOSBox SVN requires a minimum terminal window
|
||||
size to function, and may segfault if the terminal is too
|
||||
small.
|
||||
|
||||
The debugger interface is written against the "ncurses" library.
|
||||
|
||||
The window regions of the debugger interface are:
|
||||
- Register Overview
|
||||
- Data view
|
||||
- Code Overview
|
||||
- Variable (not shown by default)
|
||||
- Output
|
||||
|
||||
The register window will show at all times the contents of the CPU
|
||||
registers and segment registers as well as other important CPU
|
||||
state.
|
||||
|
||||
Data view allows viewing the contents of memory while debugging.
|
||||
The location shown is controlled by a segment:offset pair.
|
||||
|
||||
In DOSBox-X, the Data view also permits viewing data as a linear
|
||||
(pageable) offset and as a physical memory view (outside the
|
||||
CPU's paging control).
|
||||
|
||||
The code overview/disassembly window shows the contents of a
|
||||
memory location as disassembled x86 instructions. Normally, this
|
||||
is set to the instruction pointer, but it can be set anywhere.
|
||||
Decoding is based on the CPU mode.
|
||||
|
||||
The variable list is used when the debugger is given variables
|
||||
to debug by.
|
||||
|
||||
The output window allows you to scroll through the last 1000
|
||||
or so log messages written from within the codebase by LOG()
|
||||
or LOG_MSG(). If the window is scrolled to the bottom, new
|
||||
messages will appear by default.
|
||||
|
||||
The lowest row of the terminal is reserved for a line where
|
||||
the user can enter debugger commands. An underscore shows
|
||||
where the cursor is positioned.
|
||||
|
||||
The code and data views have been fixed in DOSBox-X to indicate
|
||||
when data is not available to view for a specific segment:offset
|
||||
or linear address.
|
||||
|
||||
If the CPU is in protected mode, and the segment portion refers
|
||||
to a segment that does not exist, or the offset extends past
|
||||
the limit of that segment, the code or data view will show
|
||||
'na' instead of a byte value.
|
||||
|
||||
If 80386 paging is enabled, and the segment:offset or linear
|
||||
address refers to a page that is not present, then the data
|
||||
view will show 'pf' to indicate this.
|
||||
|
||||
na = segment does not exist, or offset exceeds segment limit
|
||||
|
||||
pf = segment:offset or linear address is paged out or
|
||||
not present according to page tables.
|
||||
|
||||
Debugging a program and breaking on start
|
||||
-----------------------------------------
|
||||
|
||||
DOSBox-X includes a built-in command to launch a program and
|
||||
break at the entry point.
|
||||
|
||||
DEBUGBOX [command] [options]
|
||||
|
||||
You can also type DEBUGBOX without a parameter to start the
|
||||
debugger.
|
||||
|
||||
Debugger keyboard shortcuts
|
||||
---------------------------
|
||||
|
||||
Tab/Shift+Tab Switch to the next/previous window
|
||||
F3/F6 Previous command in history
|
||||
F4/F7 Next command in history
|
||||
F5 Resume emulation
|
||||
F8 Toggle printable characters display in data view
|
||||
F9 Set/clear breakpoint
|
||||
F10 Single step (over)
|
||||
F11 Single step (into)
|
||||
Up arrow Scroll up one line (if applicable)
|
||||
Down arrow Scroll down one line (if applicable)
|
||||
Left arrow Move cursor left in command line
|
||||
Right arrow Move cursor right in command line
|
||||
Page Up/Fn+Up Scroll up by window height (if applicable)
|
||||
Page Down/Fn+Down Scroll down by window height (if applicable)
|
||||
Home/Fn+Left Scroll to top (in Output window)
|
||||
End/Fn+Right Scroll to bottom (in Output window)
|
||||
Insert Toggle insert/overwrite mode in command line
|
||||
Alt+D Set data view to DS:SI
|
||||
Alt+E Set data view to ES:DI
|
||||
Alt+X Set data view to DS:DX
|
||||
Alt+B Set data view to ES:BX
|
||||
Alt+S Set data view to SS:SP
|
||||
|
||||
Debugger commands
|
||||
-----------------
|
||||
|
||||
MOVEWINDN Move current window down
|
||||
MOVEWINDU Move current window up
|
||||
SHOWWIN <winname> Show window (by name)
|
||||
HIDEWIN <winname> Hide window (by name)
|
||||
MEMDUMP <seg> <off> <bytecount> Dump memory to file (MEMDUMP.TXT)
|
||||
MEMDUMPBIN <seg> <off> <bytecount> Dump memory to file (MEMDUMP.BIN)
|
||||
IV <seg> <off> <name> Insert variable
|
||||
SV <name> Save variables to <name>
|
||||
LV <name> Load variables from <name>
|
||||
SR <reg> <value> Set register <reg> value to <value>
|
||||
SM <seg> <off> [bytes in hex] Set memory at <seg>:<off> to byte values given
|
||||
BP <seg> <off> Add breakpoint (real mode)
|
||||
BPM <seg> <off> Add breakpoint (protected mode)
|
||||
BPLM <offset> Add breakpoint (linear/virtual address)
|
||||
BPINT <intnum> Add breakpoint on interrupt
|
||||
BPINT <intnum> <value> Add breakpoint on interrupt and AH=<value>
|
||||
BPLIST List breakpoints
|
||||
BPDEL <breakpoint number> Delete breakpoint
|
||||
RUN Resume emulation
|
||||
RUNWATCH Resume emulation, but show state while running
|
||||
A20 Show A20 gate state
|
||||
A20 ON Turn on A20 gate
|
||||
A20 OFF Turn off A20 gate
|
||||
PIC Show interrupt controller state
|
||||
PIC MASKIRQ <irq> Mask IRQ at interrupt controller
|
||||
PIC UNMASKIRQ <irq> Unmask IRQ at interrupt controller
|
||||
PIC ACKIRQ <irq> Acknowledge IRQ at interrupt controller
|
||||
PIC LOWERIRQ <irq> Manually lower interrupt signal
|
||||
PIC RAISEIRQ <irq> Manually raise interrupt signal
|
||||
C <seg> <off> Set code view to address
|
||||
D <seg> <off> Set data view to address (segment:offset)
|
||||
DV <offset> Set data view to address (linear/virtual address)
|
||||
DP <offset> Set data view to address (physical)
|
||||
LOG <hexadecimal count> Log CPU state, for the specified number of instructions, to LOGCPU.TXT
|
||||
LOGS <hexadecimal count> Log CPU state, short log, to LOGCPU.TXT
|
||||
LOGL <hexadecimal count> Log CPU state, long log, to LOGCPU.TXT
|
||||
INTT <intnum> Trace interrupt
|
||||
INT <intnum> Start interrupt
|
||||
CALLBACKS Show callbacks of interrupts.
|
||||
SELINFO <n> Show selector information
|
||||
DOS MCBS Dump DOS kernel MCB chain (conventional memory allocation chain)
|
||||
DOS KERN Dump DOS kernel memory allocation list
|
||||
DOS XMS Dump XMS (extended memory) allocation list
|
||||
DOS EMS Dump EMS (expanded memory) allocation list
|
||||
BIOS MEM Dump BIOS allocation and layout list
|
||||
GDT Dump GDT (global descriptor table)
|
||||
LDT Dump LDT (local descriptor table)
|
||||
IDT Dump IDT (interrupt descriptor table)
|
||||
PAGING Dump page table information
|
||||
CPU Dump additional CPU information
|
||||
VGA cmd VGA related debugging commands.
|
||||
PC98 cmd PC98 related debugging commands.
|
||||
EMU MEM/MACHINE Show emulator memory or machine info.
|
||||
INTVEC <file> Dump interrupt vector table to <file>
|
||||
INTHAND <intnum> Set code view to start of interrupt handler
|
||||
EXTEND Toggle additional information
|
||||
TIMERIRQ Start timer IRQ
|
||||
TIME <time> Display or change the internal time
|
||||
DATE <date> Display or change the internal date
|
||||
HEAVYLOG Toggle heavy CPU logging
|
||||
ZEROPROTECT Toggle zero protection
|
||||
HELP Show some debugger commands for reference
|
||||
189
docs/function-knowledge-roadmap.md
Normal file
189
docs/function-knowledge-roadmap.md
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
# Roadmap To Full Function Knowledge
|
||||
|
||||
## Purpose
|
||||
|
||||
This note turns the current `CRUSADER.EXE` decompilation state into a concrete path toward broad, evidence-backed function coverage.
|
||||
|
||||
`Full function knowledge` here does not mean every body must already have a perfect gameplay-facing name. It means every reachable function should end up in one of three states:
|
||||
|
||||
- stable behavioral name with caller/context evidence,
|
||||
- conservative structural name with a documented local contract,
|
||||
- or an explicit blocker entry that explains why boundary repair, caller recovery, or data typing is still required.
|
||||
|
||||
## Current Baseline
|
||||
|
||||
- The live `CRUSADER.EXE` function table currently sits at `3032` total functions, with `1795` non-anonymous names and `1237` remaining `FUN_/nullfn_` placeholders. That puts the current raw naming floor at about `59.2%` known versus `40.8%` still anonymous.
|
||||
- `plan-mid.md` currently pegs overall useful decompilation progress at about `59%`, with a reasonable band of `56%` to `64%`.
|
||||
- The strongest live lanes are still gameplay/input/projectiles, VM/runtime structure, startup/display, cheat/debug controls, and several class-lift pilot families.
|
||||
- The main remaining coverage gaps are no longer random single functions. They cluster around a few recurring problems: upstream caller policy, overlapped function boundaries, weak segment-ledger promotion, and structurally named families that still lack their final behavioral label.
|
||||
- The hottest anonymous segment concentrations are now easier to state concretely too: `1000` still holds `166` unknowns, `10e8` holds `62`, `1190` holds `35`, `13e8` holds `23`, and `13c8` holds `22`. That means broad sweeps are still best spent in a mixed strategy: keep harvesting low-risk UI/process helpers in the partially named menu/gump lanes while using separate deeper passes for the denser engine/runtime segments.
|
||||
|
||||
## Definition Of Done
|
||||
|
||||
Treat the roadmap as materially complete when all of the following are true:
|
||||
|
||||
1. `crusader_segment_coverage_ledger.csv` has no remaining `None` rows for code segments that have active live function objects.
|
||||
2. Every hot caller-dense range has either named functions or a documented boundary-repair blocker.
|
||||
3. Top far-call targets are at least `95%` behaviorally classified, not just structurally named.
|
||||
4. The VM/USECODE selector path is caller-backed far enough upstream that the remaining masked-create helpers are no longer anonymous policy wrappers.
|
||||
5. The `0x4588` callback family has a defensible subsystem label or a tightly bounded residual uncertainty note.
|
||||
6. Parser/animation/video helper ranges no longer sit in the ledger as broad unmapped holes.
|
||||
|
||||
## Workstreams
|
||||
|
||||
### 1. Keep The Write Path Healthy
|
||||
|
||||
The current batch confirmed another practical workflow rule: analysis can continue while the GUI owns the live project, but explicit write-back through the external MCP edit path fails when the project lock is held by the GUI session.
|
||||
|
||||
Use this order:
|
||||
|
||||
1. Do read-only decompile/xref analysis against the live open session.
|
||||
2. Stage small rename/comment batches in notes.
|
||||
3. Apply them only when one of these is true:
|
||||
- the active MCP session has a real writable context, or
|
||||
- the GUI is closed and the local PyGhidra write fallback can open the project.
|
||||
|
||||
### 2. Finish Low-Risk Live Naming Families First
|
||||
|
||||
The next fastest gains are in live clusters where neighboring functions are already named and only a few destructor/helper slots remain anonymous.
|
||||
|
||||
Current best examples:
|
||||
|
||||
- seg033 NPC action / surrender / guard / loiter process lane
|
||||
- healer / battery-charger utility process cleanup lane
|
||||
- compact helper functions whose callers are already named and whose local contract is obvious from one decompile
|
||||
|
||||
These batches should stay small: `1` to `5` renames plus provenance comments.
|
||||
|
||||
### 3. Push One Layer Upstream From Structural Names
|
||||
|
||||
A large fraction of the remaining unknowns are no longer local-contract mysteries. They are caller-policy mysteries.
|
||||
|
||||
Highest-payoff upstream fronts remain:
|
||||
|
||||
1. VM / USECODE selector and masked-create caller policy
|
||||
2. collision-storage queue producer policy above `AreaSearch_CollideMove`
|
||||
3. startup/display residual presentation handoff selectors
|
||||
4. watch/controller ownership around the seg049 lane
|
||||
|
||||
The rule for these passes is simple: prefer caller recovery over renaming isolated helpers in place.
|
||||
|
||||
### 4. Convert Segment Holes Into Tracked Families
|
||||
|
||||
The ledger is still lagging behind the actual live state in a few places. Segment rows should not stay at `None` once a real family footprint is known.
|
||||
|
||||
Promotion rule:
|
||||
|
||||
- `Foothold`: one real subsystem lane plus several stable names
|
||||
- `Partial`: multiple connected helpers and at least one caller-backed behavioral claim
|
||||
- `Deep`: enough coverage that new work mostly expands or refines the lane instead of discovering it
|
||||
|
||||
### 5. Repair Boundaries Only Where They Unlock Coverage
|
||||
|
||||
Large overlap-heavy ranges still matter, but they should be attacked in payoff order:
|
||||
|
||||
1. caller-dense windows that block multiple names
|
||||
2. parser/animation/video windows with direct downstream value
|
||||
3. residual startup/display overlap only when it blocks a live rename or caller chain
|
||||
|
||||
Current standing examples include `000c:db68`, `000e:ffb0`, and several sparse gaps in `0007` and `000b`.
|
||||
|
||||
### 6. Turn Structural Object Families Into Behavioral Ones
|
||||
|
||||
Two families still deserve focused classification work because they block naming quality across many segments:
|
||||
|
||||
1. the VM selector / owner-resource family
|
||||
2. the `0x4588` callback / allocator / presentation family
|
||||
|
||||
## Batch Discipline
|
||||
|
||||
For each rename batch:
|
||||
|
||||
1. Verify the body locally by decompile or disassembly.
|
||||
2. Verify at least one caller or neighboring family anchor when the name is behavioral rather than purely structural.
|
||||
3. Add a short Ghidra comment preserving why the name is safe.
|
||||
4. Update the ledger if a segment can be promoted.
|
||||
5. Update `plan-mid.md` only when the real next resume point changed.
|
||||
|
||||
## Latest Applied Rename Batch
|
||||
|
||||
This batch is now landed in `CRUSADER.EXE`. The practical workflow lesson still stands: read-only MCP analysis can run against the GUI-owned session, but the external write path had to fall back to local PyGhidra after the GUI-held project lock blocked explicit write access.
|
||||
|
||||
- `1100:0437` -> `SurrenderProcess_Destroy`
|
||||
- `1100:0913` -> `NPC_DoRandomIdleAnimTwiceIfNotBusy`
|
||||
- `1128:1e14` -> `CruHealer_Destroy`
|
||||
- `1128:1fbe` -> `BatteryChargerProcess_Destroy`
|
||||
|
||||
Evidence summary:
|
||||
|
||||
- `1100:0437` resets the surrender vtable root, clears the local NPC flag bit, and destroys the two embedded dispatch-entry children.
|
||||
- `1100:0913` is only called from `GuardProcess_Run` and `LoiterProcess_Run`; it gates on `NPC_IsBusy`, seeds a two-way random choice, and then calls `NPC_DoAnim` twice.
|
||||
- `1128:1e14` and `1128:1fbe` are clear destructor slots for the healer and battery-charger process families because they restore the process vtable root, stop the family-specific sound, clear avatar stasis, and destroy the embedded child entries.
|
||||
- The next seg033 pass also closed four more slot-1 destructor entries directly from the live process-function tables: `PaceProcess_Destroy`, `GuardProcess_Destroy`, `LoiterProcess_Destroy`, and `StandProcess_Destroy` are now confirmed from `g_*ProcessFnPtr` table ownership rather than from weaker local shape alone.
|
||||
- The same vtable-driven cleanup method now also widened beyond seg033: `NPCActionProcess_Destroy`, `DeathSilenceProcess_Destroy`, `PathfinderProcess_Destroy`, `TeleporterProcess_Destroy`, and `EggHatcherProcess_Destroy` are all now grounded directly in their live `g_*ProcessFnPtr` slot-1 ownership rather than left as anonymous generic destructors.
|
||||
- The current AI-lane residue is narrower again: the base `NPCActionProcess` no-op run body, the shared slot-10 no-op body, the loiter-only slot-10 override, and the common process-vtable slot stubs are now all named structurally. The remaining uncertainty in this immediate window is therefore mostly semantic rather than object-identity: exactly what slot-10/slot-11 mean at the behavior-policy level, not which functions own those slots.
|
||||
- The same slot-1 cleanup method now generalizes beyond the AI families too: `SnapProcess_Destroy`, `VideoPlayer_Destroy`, `GameTimeProcess_Destroy`, `WaitProcess_Destroy`, and `SpriteProcess_Destroy` are now live as verified vtable-owned process destructors, which makes the broader process-family cleanup lane more systematic instead of one-off.
|
||||
- The parser/animation-adjacent media lane now has its first comparable foothold too. `FlicPlayProcess_Destroy`, `FlicWaitProcess_Destroy`, `MusicPlayerProcess_RunNoop`, `MusicPlayerProcess_Destroy`, `AssProcess_Destroy`, `FlicWaitProcess_VtableSlot10TickAndMaybeAdvance`, `MusicPlayerProcess_VtableSlot10Noop`, `AssProcess_VtableSlot5ClearCreatedFlag`, and `AssProcess_VtableSlot6SetCreatedFlag` are now live from direct `g_*ProcessFnPtr` slot ownership and local body evidence. The remaining gap in this lane is no longer basic object identity; it is the deeper connection between these process families and the older raw `000e:` parser/video helper anchors.
|
||||
- That same lane now extends one level deeper into the video helper stack: `VideoPlayer_InitializePlayback`, `VideoPlayer_OpenMediaFiles`, `VideoPlayer_AllocPlaybackBuffers`, `VideoPlayer_OpenMoviListAndPrimeStreams`, `VideoPlayer_StopAndDestroyWrapper`, and `VideoPlayerProcess_VtableSlot11Noop` are now live from direct caller relationships (`PlayFlicProbably_1468_3f77`, `FlicPlay_1468_4169`, `VideoPlayer_Run`), MOVI-string evidence, and the `g_videoPlayerProcessFnPtr` slot map. The next high-value unknowns in this lane are now the remaining unnamed video helper bodies around palette/error handling and the still-unmapped raw `000e:` parser/video equivalents.
|
||||
- The chunk-processing layer is now materially clearer too: `File_Exists`, `VideoPlayer_FormatErrorMessage`, `VideoPlayer_AdvanceChunkCursor`, `VideoPlayer_AdvanceChunkCursorWrapper`, `VideoPlayer_LoadAudioChunk`, `VideoPlayer_LoadVideoChunk`, and `VideoPlayer_BlitDecodedFrame` are live from direct chunk-tag evidence (`01wb`, `00db`, `00dc`), caller placement inside the playback loop, and the now-named MOVI setup path. That leaves fewer anonymous helpers in the video lane; the remaining gaps are concentrated in subtitle/palette helpers and the four concrete blitters that `VideoPlayer_BlitDecodedFrame` dispatches to.
|
||||
- A separate music/save-state mini-cluster also closed cleanly after switching lanes: `Music_RestorePreviousTrackFromStack`, `Music_LoadStateAndReplayCurrentTrack`, and `Music_SaveState` are now live from direct `Savegame_LoadProbably` / `Savegame_QuickSave` caller evidence and the explicit music-track stack behavior around `g_musicTrack` and `DAT_1478_3b75`. That gives the audio side a foothold outside the video/process lane and reduces ambiguity around transient-screen music restoration.
|
||||
- The savegame UI cluster is now fully closed at the `13d0:` helper level: `SavegameSlot_GetLabelPtr`, `SavegameSlot_SetLabel`, `File_CloseAndMaybeFree`, `SavegameNameField_MapInputChar`, `SavegameNameField_HandleKey`, `SavegameNameField_Draw`, `SavegameMenu_Destroy`, `SavegameMenu_HandleKey`, `SavegameMenu_HandleSlotAction`, `SavegameSlot_DrawCornerDecorations`, `SavegameSlotGump_Create`, `SavegameSlotGump_Destroy`, `SavegameSlot_HandleClick`, `SavegameSlot_BeginEditOrActivate`, and `SavegameSlot_Select` are now live from direct save/load-gump caller evidence. That removes the remaining anonymous helpers from the savegame menu lane instead of leaving a partly named cluster behind.
|
||||
- A fresh `13c8:` top-level menu cluster now has its shell named too: `MainMenu_Destroy`, `MainMenu_DrawCornerDecorations`, `MainMenu_HandleButtonClick`, `MainMenu_HandleKey`, and `MainMenu_ActivateSelection` are live from direct caller behavior and the selection-dispatch cases that open difficulty, save/load, credits, and related modal flows. The remaining work in that lane is now below the shell level, inside the subordinate modal/menu bodies rather than the main dispatcher itself.
|
||||
- The tiny remaining ASS cluster also closed one concrete gap: `ASS_StoreInitCallbackState` is now named from the direct `Init_ASS` / `Uninit_ASS` lifecycle, where it is passed as the callback address in the ASS init data and later unwound through the stored global state. That leaves the ASS lane with no anonymous helpers in its small top-level init/process callback path.
|
||||
- The small residual `10f8:` item-type lane is now also cleaner: `ItemScript_AppendBytes` and `ItemTypeflagRecord_ResetDefaults` are live as structural helpers beside the already named typename-record functions. These are not deep semantic wins, but they remove the remaining obvious placeholders from that compact item-type helper cluster.
|
||||
- A larger ownership-backed process batch is now live too: `MapJumpProcess_Destroy`, `FadeProcess1_Destroy`, `AnimProcess_Destroy`, `ItemProcess_Destroy`, `SuperSpriteProcess_Destroy`, `OneFrameDelayProc_Destroy`, `CameraProcess_Destroy`, `KeyDaemonProcess_Destroy`, `KeyboardProcess_Destroy`, `AccWaitProcess_Destroy`, `SystemTimerProcess_Destroy`, `BiosProcess_Destroy`, `CustomWaitProcess_Destroy`, `DumbTimerProcess_Destroy`, `CycleProcess_Destroy`, `FadeProcAlt_Destroy`, and `MyTimerProcess_Destroy` were all closed from direct `g_*FnPtr` slot-1 ownership. This is a high-confidence unknown-count reduction batch rather than a semantic deep dive, but it materially shrinks the remaining anonymous process families.
|
||||
- A companion slot-method batch is now live as well: `MapJumpProcess_VtableSlot10AdvanceItemFind`, `AnimProcess_VtableSlot10DispatchByPort`, `FadeProcess2_VtableSlot10BlendTowardTargetPalette`, `AttackProcess_VtableSlot10DispatchByClip`, `WaitProcessFamily_VtableSlot10DispatchByPair`, `AccWaitProcess_VtableSlot10DispatchByAnimation`, `BiosProcess_VtableSlot10DosRealFarCall`, `CustomWaitProcess_VtableSlot11ArmAndRun`, `MyTimerProcess_VtableSlot10IncrementCounterOnTick`, `BaseCameraProcess_VtableSlot10SetViewportRect`, and `BaseCameraProcess_VtableSlot11FreeBuffer` are now named from direct `g_*FnPtr` ownership plus local body contracts. That broad-pass work keeps reducing placeholder density without overclaiming semantics that still depend on table decoding.
|
||||
- A further broad UI/gump pass is also live: `StdIntHandlerProcess_Destroy`, `GumpShared_DestroyNoop`, `GumpShared_VtableSlot3Noop`, `GumpShared_VtableSlot7Noop`, `GumpShared_VtableSlot8Noop`, `GumpShared_VtableSlot9Noop`, `GumpShared_VtableSlot10Noop`, `GumpShared_VtableSlot16Noop`, `GumpShared_VtableSlot17Noop`, `ButtonGump_Destroy`, `KeypadGump_Destroy`, `KeypadButtonGump_Destroy`, `HelpGump_Destroy`, `HelpGump_RunAmbientSfxTick`, `RunCreditsProcess_Destroy`, `QuickSaveLoadExitGump_Destroy`, and `Gump13f80383_Destroy` are now named from direct table ownership and trivial body evidence. This removes a large amount of UI placeholder noise before any deeper dialog-by-dialog semantics are needed, and it also corrects the earlier too-narrow keyboard-only labels on gump slots that are actually reused across multiple families.
|
||||
- Another small structural process-family batch is now live too: `AnimProcess_RunNoop`, `Process1048_0000_RunNoop`, `Process1048_0000_Destroy`, `AnimPrimitiveProcessSomethingElse_Destroy`, `AnimPrimitiveProcessFamily_VtableSlot11CallSlot3`, `Process1188_0000_RunOnTimerDelta`, and `Process1188_0000_Destroy` were closed from direct table ownership and trivial local contracts. They are still generic where the owner families remain unnamed, but they further reduce the anonymous surface for later semantic passes.
|
||||
- A further tiny broad-sweep batch is now live from adjacency-backed structural evidence: `SystemTimerProcess_RunNoop`, `Gump13f80383_VtableSlot10Noop`, and `Gump13f80383_VtableSlot11Noop`. These were deliberately limited to obvious no-op slots sitting directly inside already-partially-named families, keeping the sweep conservative while still trimming another few placeholders.
|
||||
- Another small broad-sweep cluster is now live in the main-menu neighborhood: `MainMenuOptionsPanel_Create`, `MainMenuOptionButtonGump_Create`, `MainMenuOptionButtonGump_HandlePointerEvent`, `MainMenuOptionButtonGump_Draw`, and `Gump13f80383_Draw`. This batch came from direct local-family layout evidence rather than deep semantic tracing: one parent options-panel constructor, one repeatedly-instantiated button-gump constructor, its pointer-event and draw methods, and the obvious draw method in the already-named `13f8:` gump family.
|
||||
- That same small main-menu cluster tightened one step further immediately after: `MainMenuOptionButtonGump_SelectPeer` is now live from the direct paired-button state flip and peer-search body that `MainMenuOptionButtonGump_HandlePointerEvent` calls on hit. This keeps the batch conservative while closing the one remaining obvious helper in that local family.
|
||||
- The broad sweep then picked up another small owner-safe UI batch in the help lane too: `HelpGump_RefreshPage`, `HelpGump_HandleAdvanceAction`, and `HelpGump_HandleNavigationKey` are now live from direct caller links inside `HelpGump_Create` plus the shared page-state field at `+0x49`. That leaves the remaining `13e8:` help-family residue narrower and more obviously local.
|
||||
|
||||
## Latest Applied Helper Batch
|
||||
|
||||
This next pair is now landed in the live session through the write-capable MCP script path:
|
||||
|
||||
- `10f8:0437` -> `ItemType_GetTypenameRecordPtrAtIndex`
|
||||
- `10f8:045b` -> `ItemType_FindTypenameRecordIndex`
|
||||
|
||||
Current best read:
|
||||
|
||||
- `10f8:0437` is the tiny `0x20`-stride helper behind the `typename.dat` table: it returns the base pointer of the requested `1`-based record and returns `0` for index `0`.
|
||||
- `10f8:045b` scans the same `typename.dat` record table from a requested starting index, optionally uppercases both the query and the candidate record name, and returns the matching record index or `-1`.
|
||||
|
||||
That closes the local seg032 helper batch and confirms a more useful write rule for future work: when the edit-plan endpoint refuses to commit in-session, the live write-capable script path can still land small targeted renames and provenance comments without leaving the open GUI workflow.
|
||||
|
||||
## Latest Applied Broad-Sweep UI Batch
|
||||
|
||||
This next conservative broad-sweep batch is now landed in the live session through the MCP-backed write path:
|
||||
|
||||
- `12f8:02e4` -> `GumpShared_DestroyCommon`
|
||||
- `13f8:0237` -> `QuickSaveLoadExitGump_HandleChildButtonEvent`
|
||||
- `13f8:0299` -> `QuickSaveLoadExitGump_HandleKey`
|
||||
- `13f8:0349` -> `QuickSaveLoadExitGump_DrawLabel`
|
||||
- `13f8:0383` -> `QuickSaveLoadExitGump_Create`
|
||||
- `13c8:2f37` -> `MainMenuOptionsPanelButtonGump_Create`
|
||||
- `13c8:2fca` -> `MainMenuOptionsPanelButtonGump_DrawLabel`
|
||||
- `13c8:3004` -> `MainMenuOptionsPanelButtonGump_Select`
|
||||
- `13c8:3030` -> `MainMenuOptionsPanelButtonGump_Deselect`
|
||||
|
||||
Current best read:
|
||||
|
||||
- `12f8:02e4` is the shared gump base destroy path used by `HelpGump_Destroy`, `QuickSaveLoadExitGump_Destroy`, `Gump13f80383_Destroy`, and several sibling UI families: it releases the linked child at `+0x42/+0x44`, clears that link, and then runs the common unlink/free helper path.
|
||||
- The `13f8:` mini-cluster is now a real quick-save/load/exit modal family instead of a partly named shell. `QuickSaveLoadExitGump_Create` is called directly from `World_HandleKeyboardInput`, `QuickSaveLoadExitGump_DrawLabel` consumes the local label fields at `+0x47/+0x49/+0x4b`, and `QuickSaveLoadExitGump_HandleKey` plus `QuickSaveLoadExitGump_HandleChildButtonEvent` both funnel into the same local action-dispatch slot.
|
||||
- The `13c8:2f37..3030` cluster is now also tighter than a generic unnamed button wrapper. `MainMenuOptionsPanel_Create` calls `MainMenuOptionsPanelButtonGump_Create` six times, the wrapper sits directly over the generic `1308:032b` button-gump constructor, and the adjacent `DrawLabel` / `Select` / `Deselect` bodies all operate on the same local label/selected-state fields.
|
||||
- The same `13c8:` lane now also has a clearer main options-menu core. `MainMenuOptionsMenu_Destroy` saves options back to config before teardown, `MainMenuOptionsMenu_Create` builds the option-entry table and rectangle layout, `MainMenuOptionsMenu_GetOptionRect` owns the per-index placement math, and the adjacent `HandleChildButtonEvent` / `HandleKey` / `DrawTitle` / `MainMenuOptionsMenuButtonGump_DrawLabel` bodies close another chunk of placeholder-heavy UI surface without forcing final option-by-option semantics.
|
||||
- This batch is deliberately broad rather than deep: it trims placeholder-heavy UI surface without pretending the remaining dialog/menu semantics are already solved.
|
||||
|
||||
## Recommended Next Steps
|
||||
|
||||
1. Keep sweeping the same `12f8` / `13c8` / `13f8` UI-gump neighborhood for more structurally obvious virtual slots and tiny wrappers before switching back to deeper caller-policy work.
|
||||
2. Promote more ledger rows directly from already-verified notes so the `None` set shrinks before the next broad sweep.
|
||||
3. Resume the VM selector lane from the earlier policy layer above the now-named movement/collision producer surface.
|
||||
4. Revisit the parser/animation lane and map the live equivalents of the old raw `000e:` parser/video helper anchors, starting from the now-named FLIC/media process families and the newly named video helper stack (`VideoPlayer_InitializePlayback`, `VideoPlayer_OpenMediaFiles`, `VideoPlayer_AllocPlaybackBuffers`, `VideoPlayer_OpenMoviListAndPrimeStreams`, `VideoPlayer_LoadAudioChunk`, `VideoPlayer_LoadVideoChunk`).
|
||||
5. Keep harvesting small caller-closed side clusters like the music/save-state helpers when a larger lane stalls; they are low-risk ways to keep the global unknown count moving down.
|
||||
6. Savegame UI is now a completed side cluster at the helper/gump-handler level; future work there should only be broader semantic polish if needed, not placeholder cleanup.
|
||||
7. The `13c8:` main-menu shell plus the new options-panel and options-menu helper clusters is now a good staging point for later work on subordinate menu/dialog bodies if a future pass wants another UI-heavy cluster.
|
||||
8. Keep the next write batch small enough that every rename can carry a one-sentence provenance comment.
|
||||
9. Continue treating explicit write-path health as part of the workflow, not as an afterthought, so future rename batches do not stall at commit time.
|
||||
118
docs/jp-remorse-hidden-debugger-investigation.md
Normal file
118
docs/jp-remorse-hidden-debugger-investigation.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Japanese No Remorse Hidden Debugger Investigation
|
||||
|
||||
## Scope
|
||||
|
||||
This note records a first debugger-focused pass on the Win32 Japanese build `/ja/CRUSADER.EXE`, following the stronger No Regret result.
|
||||
|
||||
Question for this pass:
|
||||
|
||||
- did the JP build keep the old hidden usecode debugger itself,
|
||||
- or did it only keep the broader cheat/debug framework (`-laurie`, `JASSICA16`, immortality, `-debug`, `-u`, and related launch/key features)?
|
||||
|
||||
## Short Answer
|
||||
|
||||
Current best read: the JP Win32 build clearly preserves broad executable cheat/debug machinery, but this pass did **not** recover evidence that the classic hidden usecode debugger UI/event subsystem survived in recognizable form.
|
||||
|
||||
The strongest current reason is simple and specific: the live JP image does not contain the classic debugger-only English UI string bundle seen in the DOS-side hidden debugger, while the same live byte-search method **does** recover known surviving JP cheat/debug strings such as `JASSICA16`, `Immortality enabled.`, and `Cheats are now active.`
|
||||
|
||||
That makes the current comparison result asymmetrical:
|
||||
|
||||
- `REGRET.EXE` still shows the hidden debugger subsystem and a recovered write-side bootstrap
|
||||
- JP `/ja/CRUSADER.EXE` still shows broad cheat/debug support, but not the classic hidden debugger signature set from this first pass
|
||||
|
||||
## Verified Findings From This Pass
|
||||
|
||||
### 1. The byte-search method is valid on the live JP target
|
||||
|
||||
Live `search_bytes` against the active JP program recovered known strings that earlier JP notes already proved were real.
|
||||
|
||||
Positive-control hits from this pass:
|
||||
|
||||
- `JASSICA16` -> hit at `0047b1cc`
|
||||
- `Immortality enabled.` -> hit at `004192b6`
|
||||
- `Cheats are now active.` -> hit at `004192cb`
|
||||
|
||||
This matters because it rules out the simplest failure mode. The JP image is searchable with the current tool flow, and ordinary internal English cheat/debug strings are still present as raw bytes.
|
||||
|
||||
### 2. The classic hidden-debugger string bundle does not appear in the JP image
|
||||
|
||||
Live `search_bytes` against the active JP program returned **no hits** for the following classic hidden-debugger UI strings:
|
||||
|
||||
- `Goto Line`
|
||||
- `Watch what?`
|
||||
- `Inspect what?`
|
||||
- `Global name`
|
||||
- `Search for`
|
||||
- `FILE NOT FOUND`
|
||||
- `Unable to open this file`
|
||||
- `Nothing to find`
|
||||
- `Not found`
|
||||
- `Done`
|
||||
|
||||
This is the main result of the pass.
|
||||
|
||||
Those strings are not generic cheat/debug text. They are the most characteristic UI vocabulary of the hidden usecode debugger's file-open, goto-line, watch, inspect, global-edit, and search flows.
|
||||
|
||||
### 3. That absence is stronger than a simple localization explanation
|
||||
|
||||
The JP build still retains multiple English internal cheat/debug strings, including the positive-control strings above. That means the absence of the debugger-only English UI bundle is not well explained by a blanket `everything was translated or removed from string form` theory.
|
||||
|
||||
The current safest read is therefore not merely `the strings were probably renamed`; it is:
|
||||
|
||||
> if the classic hidden usecode debugger survived in JP, it did not survive with the usual recognizable English UI string bundle that identifies the DOS-side debugger in Remorse and Regret.
|
||||
|
||||
### 4. This pass does not overturn the earlier JP cheat/debug findings
|
||||
|
||||
Nothing in this pass weakens the earlier JP Win32 cheat/debug note.
|
||||
|
||||
Those earlier closures still stand:
|
||||
|
||||
- `-laurie` still survives
|
||||
- `JASSICA16` still survives
|
||||
- the option-key cheat handler still contains the immortality path
|
||||
- `-debug` still survives
|
||||
- `-u` still survives as a usecode startup override
|
||||
|
||||
What changed here is narrower: the first debugger-specific comparison did **not** find a recognizable hidden usecode-debugger UI signature in the JP build.
|
||||
|
||||
## Current Interpretation
|
||||
|
||||
The current best cross-build ladder is now:
|
||||
|
||||
1. retail No Remorse still has the hidden debugger pieces but currently lacks a recovered writer/bootstrap for the debugger-state global
|
||||
2. No Regret still has the hidden debugger pieces **and** a recovered write-side bootstrap at `1398:0000`
|
||||
3. JP Win32 No Remorse still has broad cheat/debug machinery, but this first debugger-focused pass did not recover the classic hidden usecode-debugger signature bundle
|
||||
|
||||
That means JP is not currently the build that reduces the retail unlock problem.
|
||||
|
||||
Right now, No Regret is still the strongest sibling build for explaining what retail No Remorse seems to be missing.
|
||||
|
||||
## Practical Consequence
|
||||
|
||||
For the minimum-modification retail debugger-entry problem, the highest-value comparison is now still:
|
||||
|
||||
- retail No Remorse versus No Regret bootstrap/state-hook paths,
|
||||
|
||||
not:
|
||||
|
||||
- retail No Remorse versus JP generic cheat/debug preservation.
|
||||
|
||||
JP remains useful as evidence that the Windows port retained cheat/debug behavior broadly, but it does not currently provide the same debugger-bootstrap leverage that No Regret does.
|
||||
|
||||
## Remaining Uncertainty
|
||||
|
||||
This pass is still a first cut, not an absolute negative proof.
|
||||
|
||||
The following possibilities remain open:
|
||||
|
||||
1. the JP build could retain some debugger-related logic with different text or no user-facing text
|
||||
2. the JP port could have retained a lower-level break/inspection helper without the original DOS debugger UI
|
||||
3. a deeper JP function-side scan around the Win32 usecode runtime could still recover a non-string-anchored debugger path
|
||||
|
||||
But none of those are currently evidenced by this pass.
|
||||
|
||||
## Recommended Next Step
|
||||
|
||||
Treat No Regret as the primary sibling-build anchor for the hidden-debugger unlock problem.
|
||||
|
||||
If more time goes into JP, the next pass should be a deeper function-side scan around the Win32 usecode runtime and any debug-only message/menu handlers, not another broad string search.
|
||||
1080
docs/regret-hidden-debugger-investigation.md
Normal file
1080
docs/regret-hidden-debugger-investigation.md
Normal file
File diff suppressed because it is too large
Load diff
294
docs/retail-debugger-entry-options.md
Normal file
294
docs/retail-debugger-entry-options.md
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
# Retail Usecode Debugger Entry Options
|
||||
|
||||
This note consolidates the current best entry-path analysis for the hidden retail usecode debugger in live `CRUSADER.EXE`.
|
||||
|
||||
Question:
|
||||
|
||||
- What is the lowest-modification path that could realistically get the hidden debugger menu working?
|
||||
- Can ordinary usecode or a `-u` startup override reach it without another fragile executable patch?
|
||||
- If retail still cannot do it cleanly, what should the next comparison pass in No Regret and JP No Remorse look for?
|
||||
|
||||
## Short Answer
|
||||
|
||||
Current best answer:
|
||||
|
||||
- No zero-modification retail entry path is currently evidenced.
|
||||
- `-debug`, `-laurie`, `jassica16`, `~`, and `Ctrl+Q` still do **not** provide a proven bootstrap into the hidden debugger.
|
||||
- The hidden debugger UI is real and usable, but it expects a live seg1408 break-state object at `1478:659c/659e` and valid current-unit/runtime context.
|
||||
- The cleanest non-EXE exploration path is now the `-u` usecode-root override, but current evidence still does **not** show a script-visible way to construct the break-state object or write `1478:659c/659e`.
|
||||
- The smallest structurally defensible executable patch is still the current interpreter-callsite-retarget family, but that remains more complex than a one-site tweak and therefore is not the preferred next move unless cross-build comparison fails.
|
||||
- The best next investigation is a comparison pass in `REGRET.EXE` and JP `/ja/CRUSADER.EXE` looking specifically for a surviving writer/bootstrap path for `1478:659c/659e`, a constructor caller for `1408:0000`, or a direct caller to the seg109 wrappers.
|
||||
|
||||
## New Live-Ghidra Findings From This Pass
|
||||
|
||||
### 1. The missing retail bootstrap is still missing
|
||||
|
||||
Fresh live data-use recovery on `1478:659c` still shows reads only.
|
||||
|
||||
Current confirmed reader families:
|
||||
|
||||
- `Interpreter_NextUsecodeOp` at multiple sites including `1418:049e`, `1418:04b1`, `1418:0519`, and several later helper windows
|
||||
- `usecode_debugger_open_for_current_unit` at `13a0:00af` / `13a0:0165`
|
||||
- `usecode_debugger_format_expression_to_shared_buffer` at `13a0:03db` / `13a0:03f4`
|
||||
- `usecode_debugger_handle_event` at `13a0:1e13`, `13a0:1e3b`, `13a0:1e5d`, `13a0:20b2`, `13a0:20b6`
|
||||
- one additional seg109 local helper `FUN_13a0_1791`
|
||||
|
||||
What is still missing:
|
||||
|
||||
- no recovered retail writer to `1478:659c/659e`
|
||||
- no recovered retail caller of `1408:0000 Create`
|
||||
- no recovered direct caller of `13a0:0086 usecode_debugger_open_for_current_unit`
|
||||
- no recovered direct caller of `13a0:020d usecode_debugger_open_modal`
|
||||
|
||||
That keeps the current retail model unchanged:
|
||||
|
||||
- the seg109 UI is real
|
||||
- the seg1408 break-state object is real
|
||||
- the interpreter callback lane is real
|
||||
- but retail still looks like an orphaned debugger subsystem whose bootstrap/entry wiring was removed or compiled out
|
||||
|
||||
### 2. The UI wrappers are valid, but they are not safe cold-entry targets
|
||||
|
||||
Fresh decompile reads tighten the wrapper roles:
|
||||
|
||||
#### `13a0:0086 usecode_debugger_open_for_current_unit`
|
||||
|
||||
- immediately calls `usecode_debugger_gump_create(..., mode=1)`
|
||||
- pulls the current unit name from `Remorse::UsecodeDebuggerBreakState::CurrentEntryGetUnitName(_DAT_1478_659c)`
|
||||
- resolves a usecode path under `s_usecode`
|
||||
- loads the corresponding unit file into the debugger pane
|
||||
- centers on `current_line - 1`
|
||||
- then enters `Dispatch_ModalGump`
|
||||
|
||||
Implication:
|
||||
|
||||
- this wrapper is closest to the original intended debugger experience
|
||||
- but it absolutely expects a valid debugger object and current-entry state first
|
||||
|
||||
#### `13a0:020d usecode_debugger_open_modal`
|
||||
|
||||
- also calls `usecode_debugger_gump_create`, but with generic mode `0`
|
||||
- skips current-unit preload and line-centering
|
||||
- enters the same modal debugger gump
|
||||
|
||||
Implication:
|
||||
|
||||
- this is the safer force-open target than `13a0:0086`
|
||||
- but it still assumes the surrounding caller/context is sane enough for the debugger gump to live
|
||||
|
||||
### 3. `usecode_debugger_gump_create` proves the debugger control bundle is complete once the gump exists
|
||||
|
||||
Fresh decompile of `13a0:19b1 usecode_debugger_gump_create` now gives the cleanest current constructor summary.
|
||||
|
||||
Verified behavior:
|
||||
|
||||
- allocates a `0x50`-byte root gump object when `this == null`
|
||||
- builds the debugger menubar and child panes
|
||||
- initializes the shared watch table
|
||||
- resolves the base `usecode` path with `Filespec_GetFullPath(0, s_usecode, 0, 0)`
|
||||
- registers the debugger/control event bundle through `NewGump_1360_0f2a`
|
||||
|
||||
Recovered registered event set from this pass:
|
||||
|
||||
- `0x13d`
|
||||
- `0x443`
|
||||
- `0x142`
|
||||
- `0x141`
|
||||
- `0x143`
|
||||
- `0x23f`
|
||||
- `0x43e`
|
||||
- `0x41f`
|
||||
- `0x417`
|
||||
- `0x431`
|
||||
- `0x411`
|
||||
- `0x410`
|
||||
- `0x441`
|
||||
- `0x421`
|
||||
- `0x22d`
|
||||
|
||||
Current direct callers are still only:
|
||||
|
||||
- `13a0:009b` from `usecode_debugger_open_for_current_unit`
|
||||
- `13a0:0256` from `usecode_debugger_open_modal`
|
||||
|
||||
This strengthens one important boundary:
|
||||
|
||||
- `0x410` is a real debugger-gump event once the debugger UI has already been created
|
||||
- it is not evidence that retail gameplay already has a reachable path that creates the gump
|
||||
|
||||
### 4. `0x410` remains parallel debugger UI state, not the debugger bootstrap itself
|
||||
|
||||
`usecode_debugger_handle_event` at `13a0:1df3` still confirms the same split, but the current decompile makes it easier to summarize.
|
||||
|
||||
Verified cases include debugger-style commands for:
|
||||
|
||||
- open file
|
||||
- resume / break-next / single-step state changes
|
||||
- go to line
|
||||
- watch / inspect / clear watches
|
||||
- change global memory
|
||||
- find / search again
|
||||
- local breakpoint/debug actions
|
||||
|
||||
Relevant `0x410` detail:
|
||||
|
||||
- incoming event `0x410` is rewritten to local state `0x0e`
|
||||
- case `0x0e` clears one local selection/watch slot and refreshes debugger state
|
||||
|
||||
Implication:
|
||||
|
||||
- the debugger's own event machine knows what to do with `0x410`
|
||||
- but only after the debugger gump already exists and is registered
|
||||
- this does **not** give us a new no-patch retail entry path by itself
|
||||
|
||||
## What This Means For Usecode As An Entry Path
|
||||
|
||||
## Current Best Read
|
||||
|
||||
The `-u` retail override is now the best non-EXE exploration tool, but not yet a proven debugger-entry solution.
|
||||
|
||||
Why it still matters:
|
||||
|
||||
- `startup_apply_u_override_if_present` at `1420:0cdf` is a real startup hook
|
||||
- it is called from `Init_Everything` at `1048:05d3`
|
||||
- it swaps the single live usecode runtime root rather than layering a second source
|
||||
- that replacement root is then consumed by ordinary compiled paths like `Usecode_ItemCallEvent`, `UsecodeProcess_CreateProcess`, and `Interpreter_NextUsecodeOp`
|
||||
|
||||
So `-u` gives a practical route to:
|
||||
|
||||
- replace scripted behavior with minimal executable modification
|
||||
- test whether a data-driven/usecode-side path can indirectly reach an otherwise hidden compiled control lane
|
||||
|
||||
But the current negative evidence is still stronger than the hopeful side:
|
||||
|
||||
- no recovered usecode intrinsic or compiled helper currently reads like `open usecode debugger`
|
||||
- no recovered usecode-visible primitive currently reads like `construct debugger break state`
|
||||
- no recovered usecode-visible primitive currently writes `1478:659c/659e`
|
||||
- current script/event scans still do not show a plain usecode literal/ordinal trail for event `0x410`
|
||||
|
||||
Current safest conclusion:
|
||||
|
||||
- a `-u` archive replacement is the least invasive *experimental platform*
|
||||
- it is not yet an evidence-backed direct debugger unlock
|
||||
|
||||
## Best Script-Side Host Families If We Try `-u`
|
||||
|
||||
If the next step is an asset-only experiment, the best current targets remain:
|
||||
|
||||
- `MONITNS` / monitor-computer families
|
||||
- `SURCAMNS` / `SURCAMEW`
|
||||
- `NPCTRIG`
|
||||
|
||||
Why these are stronger than a generic chest or one-off gadget:
|
||||
|
||||
- they already sit near real modal UI / camera / event-control behavior
|
||||
- they are more plausible bridges into a hidden control/event lane than ordinary loot or animation scripts
|
||||
|
||||
What they still do **not** currently prove:
|
||||
|
||||
- direct debugger construction
|
||||
- direct seg109 wrapper calls
|
||||
- direct `1478:659c/659e` bootstrap
|
||||
|
||||
So the immediate asset-only goal should be framed narrowly:
|
||||
|
||||
- not `open the debugger from usecode directly`
|
||||
- but `test whether any scripted family can reach a compiled control path closer to the hidden debugger than the currently known public gumps`
|
||||
|
||||
## Ranked Entry Options By Modification Cost
|
||||
|
||||
### 1. Zero-modification retail route
|
||||
|
||||
Current status: no proven path.
|
||||
|
||||
Still ruled out by current evidence:
|
||||
|
||||
- `-debug`
|
||||
- `-laurie`
|
||||
- `jassica16`
|
||||
- `~`
|
||||
- `Ctrl+Q` / event `0x410`
|
||||
|
||||
Why:
|
||||
|
||||
- they toggle debug/cheat/display behavior
|
||||
- they do not currently create the seg1408 break-state object or enter the seg109 wrappers
|
||||
|
||||
### 2. Asset-only route via `-u` replacement `EUSECODE.FLX`
|
||||
|
||||
Current status: lowest-modification practical experiment, but unproven as a debugger route.
|
||||
|
||||
Advantages:
|
||||
|
||||
- no retail EXE byte changes required
|
||||
- fully reversible by swapping the override directory/archive
|
||||
- reaches normal compiled usecode consumers
|
||||
|
||||
Limitations:
|
||||
|
||||
- still no direct evidence that usecode can create/write the required debugger state
|
||||
- more likely to find an indirect bridge than a direct `open debugger` primitive
|
||||
|
||||
Current recommendation:
|
||||
|
||||
- prefer this over new ad hoc retail EXE patching if the goal is only to test indirect control-flow ideas
|
||||
|
||||
### 3. Minimal executable route: interpreter-callsite-retarget family
|
||||
|
||||
Current status: still the smallest structurally defensible retail patch family.
|
||||
|
||||
Why it remains the floor:
|
||||
|
||||
- one-site retarget ideas fail because they do not also create/store the debugger object
|
||||
- direct shared-callback patching is too global and has already caused startup failures
|
||||
- direct cold-calls into the UI wrappers use the wrong stack/context
|
||||
|
||||
What the current viable family still needs:
|
||||
|
||||
- lazy create-or-reuse of the seg1408 break-state object
|
||||
- store into `1478:659c/659e`
|
||||
- preserve deferred interpreter timing
|
||||
- sanitize wrapper arguments before the seg109 UI entry
|
||||
|
||||
So even the best retail EXE path is still not a tiny one-byte/two-byte unlock.
|
||||
|
||||
### 4. Cross-build bootstrap recovery
|
||||
|
||||
Current status: best next investigation.
|
||||
|
||||
Why this is now preferred over more retail patch fishing:
|
||||
|
||||
- if No Regret or JP No Remorse kept any surviving debugger bootstrap, it could collapse the retail problem from `invent a new path` to `port or mimic one missing write/call`
|
||||
- that is more likely to produce a truly minimal modification than another speculative retail patch chain
|
||||
|
||||
## Current Recommendation
|
||||
|
||||
If the goal is the minimum modification that still has a realistic chance to work, the order should now be:
|
||||
|
||||
1. Compare `REGRET.EXE` and JP `/ja/CRUSADER.EXE` for any surviving debugger bootstrap/writer.
|
||||
2. Keep `-u` / replacement `EUSECODE.FLX` as the preferred low-risk experiment surface for any script-side proxy ideas.
|
||||
3. Do **not** resume broader retail executable patching unless the cross-build pass fails to yield a clearer bootstrap or the existing O/P family gets one clean runtime confirmation target.
|
||||
|
||||
That ranking fits both the new live evidence and the user's practical constraint that complex retail patch attempts have already been unstable.
|
||||
|
||||
## Cross-Build Exploration Note
|
||||
|
||||
When this moves to No Regret and JP No Remorse, the focused targets should be:
|
||||
|
||||
1. any write to the debugger global pointer equivalent of `1478:659c/659e`
|
||||
2. any caller of `1408:0000 Create` or its build-specific equivalent
|
||||
3. any direct caller of `usecode_debugger_open_for_current_unit`
|
||||
4. any direct caller of `usecode_debugger_open_modal`
|
||||
5. any non-stub debugger vtable slot replacing retail `1408:046f` / `1408:0474`
|
||||
6. any command-line or cheat/debug hotkey path that lands near the seg109 wrappers or seg1408 constructor
|
||||
7. any usecode/runtime path that seeds current-unit state for the debugger without using the orphaned retail bootstrap
|
||||
|
||||
## Bottom Line
|
||||
|
||||
Retail No Remorse still looks like it shipped with a real hidden usecode debugger whose UI, event dispatcher, and break-state object all survived, but whose bootstrap path did not.
|
||||
|
||||
That means the lowest-modification *currently evidenced* route is no longer "guess one more retail patch". It is:
|
||||
|
||||
- first, look for the missing bootstrap in sibling builds,
|
||||
- second, use `-u` and a replacement `EUSECODE.FLX` only as a low-risk exploration surface,
|
||||
- and only third, return to the interpreter-callsite-retarget patch family if the cross-build pass gives no smaller bootstrap to port.
|
||||
Loading…
Add table
Add a link
Reference in a new issue