refactor: use openwa_core::mem::classify_pointer in dump_region
Browse filesReplace 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 |
-
///
|
| 89 |
-
///
|
| 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;
|
| 120 |
}
|
| 121 |
|
| 122 |
-
let
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 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 |
}
|