paavohtl Claude Opus 4.6 commited on
Commit
49bc5b6
·
1 Parent(s): 33fa915

refactor: use openwa_core::mem::classify_pointer in dump_region

Browse files

Replace inline pointer classification logic in dump_region with calls to
the shared classify_pointer function. Remove duplicated IsBadReadPtr
extern and can_read helper (now live in openwa_core::mem).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

crates/openwa-wormkit/src/replacements/input.rs CHANGED
@@ -31,10 +31,6 @@ use openwa_core::engine::ddgame::{offsets, TeamArenaRef};
31
  use openwa_core::engine::{DDGame, DDGameWrapper};
32
  use openwa_core::rebase::rb;
33
 
34
- extern "system" {
35
- fn IsBadReadPtr(lp: *const u8, ucb: u32) -> i32;
36
- }
37
-
38
  /// Trampoline to the original TurnManager_ProcessFrame.
39
  static ORIG_TURN_MANAGER: AtomicU32 = AtomicU32::new(0);
40
 
@@ -77,30 +73,16 @@ unsafe fn get_ddgame() -> *mut DDGame {
77
  (*wrapper_ptr).ddgame
78
  }
79
 
80
- /// Check if a pointer is safe to read.
81
- #[inline]
82
- pub unsafe fn can_read(ptr: u32, size: u32) -> bool {
83
- ptr >= 0x10000 && IsBadReadPtr(ptr as *const u8, size) == 0
84
- }
85
-
86
  /// Dump a memory region as DWORDs with automatic classification.
87
  ///
88
- /// Each non-zero DWORD is classified as:
89
- /// - `[VTABLE]` — points into .rdata (likely a vtable or function pointer table);
90
- /// also dereferences `vt[0]` if readable
91
- /// - `[CODE]` — points into .text
92
- /// - `[DATA]` — points into .data/.bss
93
- /// - `[OBJECT]` — heap pointer whose first DWORD is a vtable; prints vtable address
94
- /// - `[ptr]` — any other readable heap pointer; prints the dereferenced DWORD
95
- /// - `[small=N]` — value < 0x10000 (integer / enum / flag)
96
- /// - `[value]` — anything else
97
- ///
98
- /// # Parameters
99
- /// - `base_ptr`: start of the object to dump (e.g. `turngame as *const u8`)
100
- /// - `offset`: byte offset within `base_ptr` to start the dump
101
- /// - `size`: number of bytes to dump (must be a multiple of 4)
102
- /// - `struct_name`: used as the prefix in log lines (e.g. `"CTaskTurnGame"`)
103
  pub unsafe fn dump_region(base_ptr: *const u8, offset: usize, size: usize, struct_name: &str) {
 
 
 
 
 
104
  let wa_base = rb(va::IMAGE_BASE);
105
  let delta = wa_base.wrapping_sub(va::IMAGE_BASE);
106
 
@@ -116,65 +98,48 @@ pub unsafe fn dump_region(base_ptr: *const u8, offset: usize, size: usize, struc
116
  let field_offset = offset + i * 4;
117
  let val = *(base_ptr.add(field_offset) as *const u32);
118
  if val == 0 {
119
- continue; // Skip zeros to reduce noise
120
  }
121
 
122
- let ghidra_val = val.wrapping_sub(delta);
123
-
124
- // Check if value itself is in .rdata (direct vtable pointer)
125
- if ghidra_val >= va::RDATA_START && ghidra_val < va::DATA_START {
126
- if can_read(val, 4) {
127
- let vt0 = *(val as *const u32);
128
- let _ = log_line(&format!(
129
- " +0x{:04X}: 0x{:08X} [VTABLE] g:0x{:08X} vt[0]=g:0x{:08X}",
130
- field_offset,
131
- val,
132
- ghidra_val,
133
- vt0.wrapping_sub(delta)
134
- ));
135
- } else {
136
- let _ = log_line(&format!(
137
- " +0x{:04X}: 0x{:08X} [VTABLE] g:0x{:08X} (unreadable)",
138
- field_offset, val, ghidra_val
139
- ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
- } else if ghidra_val >= va::TEXT_START && ghidra_val <= va::TEXT_END {
142
- let _ = log_line(&format!(
143
- " +0x{:04X}: 0x{:08X} [CODE] g:0x{:08X}",
144
- field_offset, val, ghidra_val
145
- ));
146
- } else if ghidra_val >= va::DATA_START && ghidra_val < 0x008C5000 {
147
- let _ = log_line(&format!(
148
- " +0x{:04X}: 0x{:08X} [DATA] g:0x{:08X}",
149
- field_offset, val, ghidra_val
150
- ));
151
  } else if val < 0x10000 {
152
  let _ = log_line(&format!(
153
  " +0x{:04X}: 0x{:08X} [small={}]",
154
  field_offset, val, val
155
  ));
156
- } else if can_read(val, 4) {
157
- // Heap pointer — safely read first DWORD to check for vtable
158
- let first = *(val as *const u32);
159
- let ghidra_first = first.wrapping_sub(delta);
160
- if ghidra_first >= va::RDATA_START && ghidra_first < va::DATA_START {
161
- // It's an object with a vtable!
162
- let vt0_str = if can_read(first, 4) {
163
- let vt0 = *(first as *const u32);
164
- format!("vt[0]=g:0x{:08X}", vt0.wrapping_sub(delta))
165
- } else {
166
- "vt[0]=?".to_string()
167
- };
168
- let _ = log_line(&format!(
169
- " +0x{:04X}: 0x{:08X} [OBJECT] vtable=g:0x{:08X} {}",
170
- field_offset, val, ghidra_first, vt0_str
171
- ));
172
- } else {
173
- let _ = log_line(&format!(
174
- " +0x{:04X}: 0x{:08X} [ptr] *=0x{:08X}",
175
- field_offset, val, first
176
- ));
177
- }
178
  } else {
179
  let _ = log_line(&format!(" +0x{:04X}: 0x{:08X} [value]", field_offset, val));
180
  }
 
31
  use openwa_core::engine::{DDGame, DDGameWrapper};
32
  use openwa_core::rebase::rb;
33
 
 
 
 
 
34
  /// Trampoline to the original TurnManager_ProcessFrame.
35
  static ORIG_TURN_MANAGER: AtomicU32 = AtomicU32::new(0);
36
 
 
73
  (*wrapper_ptr).ddgame
74
  }
75
 
 
 
 
 
 
 
76
  /// Dump a memory region as DWORDs with automatic classification.
77
  ///
78
+ /// Uses `openwa_core::mem::classify_pointer` for pointer detection.
79
+ /// See that module for the classification categories.
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  pub unsafe fn dump_region(base_ptr: *const u8, offset: usize, size: usize, struct_name: &str) {
81
+ use openwa_core::address::va;
82
+ use openwa_core::mem;
83
+ use openwa_core::rebase::rb;
84
+ use openwa_debug_proto::PointerKind;
85
+
86
  let wa_base = rb(va::IMAGE_BASE);
87
  let delta = wa_base.wrapping_sub(va::IMAGE_BASE);
88
 
 
98
  let field_offset = offset + i * 4;
99
  let val = *(base_ptr.add(field_offset) as *const u32);
100
  if val == 0 {
101
+ continue;
102
  }
103
 
104
+ if let Some(info) = mem::classify_pointer(val, delta) {
105
+ let detail_str = info.detail.as_deref().unwrap_or("");
106
+ match info.kind {
107
+ PointerKind::Vtable => {
108
+ let _ = log_line(&format!(
109
+ " +0x{:04X}: 0x{:08X} [VTABLE] g:0x{:08X} {}",
110
+ field_offset, val, info.ghidra_value, detail_str
111
+ ));
112
+ }
113
+ PointerKind::Code => {
114
+ let _ = log_line(&format!(
115
+ " +0x{:04X}: 0x{:08X} [CODE] g:0x{:08X}",
116
+ field_offset, val, info.ghidra_value
117
+ ));
118
+ }
119
+ PointerKind::Data => {
120
+ let _ = log_line(&format!(
121
+ " +0x{:04X}: 0x{:08X} [DATA] g:0x{:08X}",
122
+ field_offset, val, info.ghidra_value
123
+ ));
124
+ }
125
+ PointerKind::Object => {
126
+ let _ = log_line(&format!(
127
+ " +0x{:04X}: 0x{:08X} [OBJECT] {}",
128
+ field_offset, val, detail_str
129
+ ));
130
+ }
131
+ PointerKind::Heap => {
132
+ let _ = log_line(&format!(
133
+ " +0x{:04X}: 0x{:08X} [ptr] {}",
134
+ field_offset, val, detail_str
135
+ ));
136
+ }
137
  }
 
 
 
 
 
 
 
 
 
 
138
  } else if val < 0x10000 {
139
  let _ = log_line(&format!(
140
  " +0x{:04X}: 0x{:08X} [small={}]",
141
  field_offset, val, val
142
  ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  } else {
144
  let _ = log_line(&format!(" +0x{:04X}: 0x{:08X} [value]", field_offset, val));
145
  }