Research
This commit is contained in:
parent
28cbbe3470
commit
a9153546ae
56 changed files with 6731 additions and 258 deletions
|
|
@ -141,6 +141,80 @@ Implication:
|
|||
- 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
|
||||
|
||||
### 5. Retail still preserves a substantial debugger UI and command surface once the gump exists
|
||||
|
||||
The latest live `CRUSADER.EXE` decompile pass makes the surviving retail debugger capability map much clearer.
|
||||
|
||||
What retail can still do once a valid debugger object and gump already exist:
|
||||
|
||||
- `usecode_debugger_build_menubar` still builds the full hidden debugger menu bar with File, Run, Breakpoints, Search, and Data menus.
|
||||
- `usecode_debugger_translate_registered_event` still translates the registered debugger/control event bundle into the local debugger command ids consumed by `usecode_debugger_handle_event`.
|
||||
- `usecode_debugger_handle_event` still implements real debugger actions rather than decorative UI stubs: open file, run, break-next, single-step, go to line, watch, inspect, change global, search, search again, break to TDP, and watch clearing.
|
||||
- `usecode_debugger_source_pane_draw_visible_lines` still clamps the source viewport, highlights the current line, scans the breakpoint table for visible marks, and draws the loaded source rows from the `.unk` buffer.
|
||||
- `usecode_debugger_source_pane_handle_pointer_event` still converts pointer position into source line and column state and also drives scroll-style commands when the pointer is above or below the pane.
|
||||
- the child-pane split is now clearer in retail than in the earlier first-pass mirror list: one pane is the loaded source view, while the sibling `13a0:16ee/1791/193f` lane is a separate watch-pane create/draw/click surface.
|
||||
|
||||
The live retail file-loading path is now also much clearer than before.
|
||||
|
||||
- `usecode_debugger_source_pane_load_file` resets local source-pane cursor state, destroys any previous source buffer, allocates a fresh source-buffer object from the requested path, updates the pane's line-count field, and refreshes the child widgets.
|
||||
- `usecode_debugger_source_buffer_create_from_path` and `usecode_debugger_source_buffer_open_from_path` still build a dedicated far-memory file object, normalize the requested path, open the file, and pass it into the text-loader path.
|
||||
- `usecode_debugger_source_buffer_load_text` still reads the whole file into far memory, rejects obviously non-text inputs, and hands the buffer to `usecode_debugger_source_buffer_split_lines_in_place`.
|
||||
- `usecode_debugger_source_buffer_split_lines_in_place` still walks the loaded text, zero-terminates newline boundaries in place, and populates the per-line pointer table later consumed by draw, click, search, and goto-line logic.
|
||||
- `usecode_debugger_source_buffer_get_line_ptr` is still the shared accessor used by source draw, pointer handling, find/find-next, and source-pane command handling.
|
||||
|
||||
Retail source navigation helpers are now closed well enough to describe the pane behavior directly.
|
||||
|
||||
- `usecode_debugger_set_line_selection` clamps the requested line against the loaded file range, clears transient cursor state, optionally updates the anchor line, and forces a redraw.
|
||||
- `usecode_debugger_center_on_line` stores the target current line, computes a top-of-window line from the visible row count, and then delegates to `usecode_debugger_set_line_selection`.
|
||||
- this means retail still preserves the ordinary source-browser workflow expected from the strings: load file, jump to line, center on current line, search through lines, and redraw the viewport around the active selection.
|
||||
|
||||
The watch-pane side is also more concrete now.
|
||||
|
||||
- `usecode_debugger_watch_pane_create` still allocates a real watch child gump and installs the watch-pane vtable.
|
||||
- `usecode_debugger_watch_pane_draw` still iterates the shared 10-slot watch table at `1478:5580`, asks the break-state callback table to format each populated watch entry, and highlights the selected row.
|
||||
- `usecode_debugger_watch_pane_handle_click` still converts pointer Y position into a watch-row index, updates the selected watch slot, and triggers a repaint.
|
||||
- that is stronger evidence for `interactive watch list still survives` than the earlier weaker `watch-related strings still exist` wording.
|
||||
|
||||
Current safest interpretation:
|
||||
|
||||
- retail did not merely keep a few string tables or unused menu labels
|
||||
- retail still keeps a functioning debugger front-end shell with real search, breakpoint, watch, inspect, and source-view logic
|
||||
- the main missing piece is still how execution ever reaches that shell with valid live state
|
||||
|
||||
### 6. Retail callback and reachability limits are still the decisive difference from Regret
|
||||
|
||||
The same live pass also tightened the `what retail still cannot do` side.
|
||||
|
||||
Current direct-caller state in live `CRUSADER.EXE`:
|
||||
|
||||
- `usecode_debugger_open_for_current_unit` still has no recovered callers
|
||||
- `usecode_debugger_open_modal` still has no recovered callers
|
||||
- `Remorse::UsecodeDebuggerBreakState::Create` at `1408:0000` still has no recovered callers
|
||||
- `usecode_debugger_handle_event` is still only reached through `usecode_debugger_translate_registered_event` and `usecode_debugger_forward_child_event`
|
||||
|
||||
Current callback state is still the key retail blocker too:
|
||||
|
||||
- `Remorse::UsecodeDebuggerBreakState::OnBreakTriggeredNoop` at `1408:046f` is still the live slot-0 callback
|
||||
- `Remorse::UsecodeDebuggerBreakState::VtableSlot1ReturnZero` at `1408:0474` is still the live slot-1 callback
|
||||
- unlike Regret, retail still has no recovered bootstrap that rewires the break-state object onto a live frontend-aware vtable
|
||||
|
||||
So the retail-versus-Regret split is now even sharper:
|
||||
|
||||
- both builds preserve a large debugger UI/event subsystem
|
||||
- retail still lacks the recovered object bootstrap and live callback target that would naturally open the debugger on break
|
||||
- Regret keeps both the writer/bootstrap path and the vtable upgrade that turns break-state callback slot `0` into a real `open_for_current_unit` launch path
|
||||
|
||||
That is why retail still reads as `functional debugger shell plus dormant break-state object`, while Regret reads as `same shell plus a surviving end-to-end open-on-break path`.
|
||||
|
||||
One practical refinement from the latest retail pass is that the shell is not merely a static menu/window skeleton.
|
||||
|
||||
- the file-open path still reaches a real far-memory source-buffer loader
|
||||
- the search path still walks live source lines through `usecode_debugger_source_buffer_get_line_ptr`
|
||||
- the goto-line path still updates line selection through the same source-pane helpers used by current-line centering
|
||||
- the watch path still stores, formats, selects, clears, and redraws real watch rows
|
||||
|
||||
So the remaining barrier is still entry/bootstrap, not lack of interior debugger behavior after entry.
|
||||
|
||||
## What This Means For Usecode As An Entry Path
|
||||
|
||||
## Current Best Read
|
||||
|
|
@ -261,13 +335,112 @@ 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
|
||||
|
||||
## Retail Ghidra Naming Backlog
|
||||
|
||||
The current note corpus now supports a tighter retail seg109 naming batch than the live authoring summary currently reflects.
|
||||
|
||||
These are the most important retail debugger-side helpers to promote explicitly in the active `CRUSADER.EXE` database before any new patch design work:
|
||||
|
||||
- `13a0:2882` = `usecode_debugger_build_menubar`
|
||||
- `13a0:088f` = `usecode_debugger_source_pane_create`
|
||||
- `13a0:0ae8` = `usecode_debugger_source_pane_init_view_from_break_state`
|
||||
- `13a0:0ba7` = `usecode_debugger_source_pane_handle_command`
|
||||
- `13a0:0f16` = `usecode_debugger_source_pane_handle_pointer_event`
|
||||
- `13a0:1088` = `usecode_debugger_source_line_copy_for_display`
|
||||
- `13a0:1118` = `usecode_debugger_source_pane_draw_visible_lines`
|
||||
- `13a0:1413` = `usecode_debugger_source_pane_clamp_viewport`
|
||||
- `13a0:15ac` = `usecode_debugger_source_pane_load_file`
|
||||
- `13a0:16ee` = `usecode_debugger_watch_pane_create`
|
||||
- `13a0:1791` = `usecode_debugger_watch_pane_draw`
|
||||
- `13a0:193f` = `usecode_debugger_watch_pane_handle_click`
|
||||
- `13a0:1c2c` = `usecode_debugger_translate_registered_event`
|
||||
- `13a0:1dc6` = `usecode_debugger_forward_child_event`
|
||||
- `13a0:2c2e` = `usecode_debugger_source_buffer_create_from_path`
|
||||
- `13a0:2ca0` = `usecode_debugger_source_buffer_destroy`
|
||||
- `13a0:2d14` = `usecode_debugger_source_buffer_open_from_path`
|
||||
- `13a0:2e0a` = `usecode_debugger_source_buffer_load_text`
|
||||
- `13a0:2f4f` = `usecode_debugger_source_buffer_split_lines_in_place`
|
||||
- `13a0:301d` = `usecode_debugger_source_buffer_get_line_ptr`
|
||||
|
||||
Why this batch matters before more patching:
|
||||
|
||||
- it converts the remaining patch-target area from anonymous `FUN_13a0_xxxx` bodies into named UI, event, and source-buffer lanes
|
||||
- it reduces the chance of patching the wrong helper when the debugger gump is already on-screen but still miswired
|
||||
- it makes runtime-only experiments easier to reason about because the gump lifecycle, source loading, and event forwarding chain become legible in-session
|
||||
|
||||
The current strongest provenance for this retail batch is the combined retail `000b:* -> 13a0:*` table in `ne-segment1.md` plus the one-to-one structural match against the now-closed Regret `1398:*` family.
|
||||
|
||||
One live correction from the follow-up rename pass matters here: retail `13a0:16ee/1791/193f` reads as a watch-pane constructor/draw/click trio, while the source-pane lane remains centered on `13a0:088f/0ae8/0ba7/0f16/1088/1118/1413/15ac`. So the Regret-side structural match is still valuable, but the retail child-pane split is now sharper than the earlier first-pass list implied.
|
||||
|
||||
## Practical Alternatives To Manual Hex Patching
|
||||
|
||||
The current blocker is no longer `we do not know what to patch`. It is `the delivery path needs to stop depending on blind byte edits`.
|
||||
|
||||
### 1. Runtime-only proof via DOSBox-X debugger or equivalent live memory tooling
|
||||
|
||||
This is now the cleanest first confirmation path.
|
||||
|
||||
Use it to:
|
||||
|
||||
- keep the retail executable on disk unchanged
|
||||
- patch or seed the debugger object only in live memory
|
||||
- prove whether a create/store/open sequence is sufficient before committing to any permanent binary patch
|
||||
|
||||
What this should target first:
|
||||
|
||||
- seeding `1478:659c/659e` with a valid debugger-state object
|
||||
- reusing the existing interpreter callback lane at `1418:049e..04b5`
|
||||
- testing whether `13a0:020d` or the vtable callback path can open a stable debugger gump once state exists
|
||||
|
||||
This is especially attractive because it turns the current question from `did we edit the NE file correctly?` into `does the runtime model itself actually work?`
|
||||
|
||||
### 2. Scripted patch application to a writable clone, not manual hex editing
|
||||
|
||||
If a permanent retail patch is still wanted, the next step should be a reproducible patcher, not another manual byte-edit round.
|
||||
|
||||
That means:
|
||||
|
||||
- keep a dedicated writable clone of the executable
|
||||
- store each patch as `address + expected old bytes + new bytes + reason`
|
||||
- apply it through a scriptable patcher that validates the original bytes before writing
|
||||
- regenerate the same patch on demand instead of hand-transcribing offsets each time
|
||||
|
||||
This can be done with PowerShell or Python against raw file offsets even if Ghidra export remains unreliable.
|
||||
|
||||
### 3. Use Ghidra only for analysis and verified byte plans
|
||||
|
||||
The current evidence does not support treating Ghidra export as the final patch-delivery mechanism for this lane.
|
||||
|
||||
What still works well:
|
||||
|
||||
- identify the correct callsite and byte budget in Ghidra
|
||||
- annotate the patch rationale in-session
|
||||
- test the control-flow hypothesis on a writable target
|
||||
- then convert the verified result into an external patch manifest or launcher-side patcher
|
||||
|
||||
That keeps Ghidra in the role it is good at here: reverse-engineering and patch design, not blind final-binary distribution.
|
||||
|
||||
### 4. Keep `-u` as the low-risk data-side experiment surface
|
||||
|
||||
The `-u` override still does not solve the missing bootstrap, but it remains valuable for adjacent experiments that do not require byte writes.
|
||||
|
||||
Use it for:
|
||||
|
||||
- testing whether scripted monitor/camera/control families can get closer to debugger-adjacent compiled paths
|
||||
- validating source-file and unit-name assumptions without touching the executable
|
||||
- separating `data-side idea failed` from `patching workflow failed`
|
||||
|
||||
It should stay in the toolbox, but it should not be mistaken for a direct replacement for the missing retail bootstrap.
|
||||
|
||||
## 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.
|
||||
1. Promote the retail seg109 naming backlog above so the remaining debugger lanes are explicit in Ghidra.
|
||||
2. Use runtime-only memory seeding on a clean executable to prove or kill the bootstrap theory without committing file changes.
|
||||
3. Compare `REGRET.EXE` and JP `/ja/CRUSADER.EXE` for any surviving debugger bootstrap/writer that can replace a custom retail bootstrap.
|
||||
4. Keep `-u` / replacement `EUSECODE.FLX` as the preferred low-risk experiment surface for any script-side proxy ideas.
|
||||
5. Do **not** resume broader retail executable patching unless the runtime proof or cross-build pass yields one clear small patch plan that can be applied by script to a writable clone.
|
||||
|
||||
That ranking fits both the new live evidence and the user's practical constraint that complex retail patch attempts have already been unstable.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue