use crate::{
addressmap::AddressMap,
error::Error,
project::PCodeMethod,
util::{read_u16_le, read_u32_le},
};
#[derive(Debug)]
pub enum MethodEntry<'a> {
Null,
PCode(PCodeMethod<'a>),
Native {
va: u32,
},
Runtime {
va: u32,
},
}
impl<'a> MethodEntry<'a> {
pub(crate) fn classify(
map: &AddressMap<'a>,
methods_va: u32,
index: u16,
) -> Result<MethodEntry<'a>, Error> {
let entry_va = methods_va.wrapping_add(u32::from(index).wrapping_mul(4));
let entry_data = map.slice_from_va(entry_va, 4)?;
let method_va = read_u32_le(entry_data, 0)?;
if method_va == 0 {
return Ok(MethodEntry::Null);
}
if !map.is_va_in_image(method_va) {
return Ok(MethodEntry::Runtime { va: method_va });
}
let stub_data = map.slice_from_va(method_va, 12)?;
let stub_head = stub_data.first_chunk::<3>().ok_or(Error::Truncated {
needed: 3,
available: stub_data.len(),
})?;
let is_stub = stub_head[0] == 0xBA || (stub_head == &[0x33, 0xC0, 0xBA]);
if is_stub {
let pcode = PCodeMethod::parse(map, methods_va, index)?;
return Ok(MethodEntry::PCode(pcode));
}
let maybe_proc_table = read_u32_le(stub_data, 0)?;
let maybe_proc_size = read_u16_le(stub_data, 8)?;
if map.is_va_in_image(maybe_proc_table) && maybe_proc_size > 0 && maybe_proc_size < 0x8000 {
if let Ok(pcode) = PCodeMethod::parse(map, methods_va, index) {
return Ok(MethodEntry::PCode(pcode));
}
}
Ok(MethodEntry::Native { va: method_va })
}
}