use crate::memory::binary::find_code_bounds;
use crate::memory::constants::*;
use crate::memory::fname::{FNamePool, FNameReader};
use crate::memory::reflection::discover_uclass_metaclass_exhaustive;
use crate::memory::source::MemorySource;
use anyhow::{bail, Result};
pub fn analyze_dump(source: &dyn MemorySource) -> Result<()> {
eprintln!("=== BL4 Dump Analysis ===\n");
eprintln!("Step 1: Finding code bounds from PE header...");
let code_bounds = find_code_bounds(source)?;
eprintln!(" Found {} code ranges", code_bounds.ranges.len());
eprintln!("\nStep 2: Discovering FNamePool...");
let pool = match FNamePool::discover(source) {
Ok(p) => {
eprintln!(" FNamePool at {:#x}", p.header_addr);
eprintln!(
" {} blocks, cursor at {}",
p.current_block + 1,
p.current_cursor
);
p
}
Err(e) => {
eprintln!(" ERROR: Could not discover FNamePool: {}", e);
bail!("FNamePool discovery failed - cannot continue analysis");
}
};
let mut fname_reader = FNameReader::new(pool);
eprintln!("\nStep 3: Verifying FName resolution...");
let class_idx = match fname_reader.find_class_index(source) {
Ok(idx) => {
eprintln!(
" FName 'Class' found at index {} (SDK constant was {})",
idx, FNAME_CLASS_INDEX
);
idx
}
Err(e) => {
eprintln!(" ERROR: Could not find 'Class' FName: {}", e);
FNAME_CLASS_INDEX }
};
let object_idx = match fname_reader.find_object_index(source) {
Ok(idx) => {
eprintln!(
" FName 'Object' found at index {} (SDK constant was {})",
idx, FNAME_OBJECT_INDEX
);
idx
}
Err(e) => {
eprintln!(" ERROR: Could not find 'Object' FName: {}", e);
FNAME_OBJECT_INDEX }
};
for (idx, expected) in [(class_idx, "Class"), (object_idx, "Object")] {
match fname_reader.read_name(source, idx) {
Ok(name) => {
let status = if name == expected { "OK" } else { "MISMATCH" };
eprintln!(
" FName {} = \"{}\" (expected \"{}\") [{}]",
idx, name, expected, status
);
}
Err(e) => {
eprintln!(" FName {} = ERROR: {}", idx, e);
}
}
}
eprintln!("\nStep 4: Finding UClass metaclass...");
match discover_uclass_metaclass_exhaustive(source, &mut fname_reader) {
Ok(info) => {
eprintln!("\n=== UClass Metaclass Found ===");
eprintln!(" Address: {:#x}", info.address);
eprintln!(" Vtable: {:#x}", info.vtable);
eprintln!(" ClassPrivate offset: {:#x}", info.class_offset);
eprintln!(" NamePrivate offset: {:#x}", info.name_offset);
eprintln!(" FName: {} (\"{}\")", info.fname_index, info.name);
eprintln!("\nRecommended constant updates:");
eprintln!(
" pub const UCLASS_METACLASS_ADDR: usize = {:#x};",
info.address
);
eprintln!(
" pub const UCLASS_METACLASS_VTABLE: usize = {:#x};",
info.vtable
);
eprintln!(
" pub const UOBJECT_CLASS_OFFSET: usize = {:#x};",
info.class_offset
);
eprintln!(
" pub const UOBJECT_NAME_OFFSET: usize = {:#x};",
info.name_offset
);
}
Err(e) => {
eprintln!(" Failed: {}", e);
}
}
Ok(())
}