use crate::{
addressmap::AddressMap,
error::Error,
pcode::decoder::InstructionIterator,
util::read_u32_le,
vb::{
constantpool::ConstantPool,
controlprop::ControlPropertyIter,
procedure::{self, ProcDscInfo},
},
};
#[derive(Debug)]
pub struct PCodeMethod<'a> {
proc_dsc: ProcDscInfo<'a>,
pcode_bytes: &'a [u8],
data_const_va: u32,
pcode_va: u32,
proc_dsc_va: u32,
stub_va: u32,
}
impl<'a> PCodeMethod<'a> {
pub fn parse(map: &AddressMap<'a>, methods_va: u32, index: u16) -> Result<Self, 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)?;
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 proc_dsc_va = if stub_head[0] == 0xBA {
read_u32_le(stub_data, 1)?
} else if stub_head == &[0x33, 0xC0, 0xBA] {
read_u32_le(stub_data, 3)?
} else {
method_va
};
let pdi_header = map.slice_from_va(proc_dsc_va, ProcDscInfo::MIN_SIZE)?;
let pdi_tmp = ProcDscInfo::parse(pdi_header)?;
let full_size = (pdi_tmp.total_size()? as usize).max(ProcDscInfo::MIN_SIZE);
let pdi_data = map.slice_from_va(proc_dsc_va, full_size)?;
let proc_dsc = ProcDscInfo::parse(pdi_data)?;
let proc_size = proc_dsc.proc_size()?;
let pcode_va = proc_dsc_va.wrapping_sub(u32::from(proc_size));
let pcode_data = map.slice_from_va(pcode_va, proc_size as usize)?;
let pcode_bytes = pcode_data
.get(..proc_size as usize)
.ok_or(Error::Truncated {
needed: proc_size as usize,
available: pcode_data.len(),
})?;
let obj_info_va = proc_dsc.object_info_va()?;
let oi_data = map.slice_from_va(obj_info_va, procedure::OBJECT_INFO_MIN_SIZE)?;
let data_const_va = procedure::read_constants_va(oi_data)?;
Ok(Self {
proc_dsc,
pcode_bytes,
data_const_va,
pcode_va,
proc_dsc_va,
stub_va: method_va,
})
}
#[inline]
pub fn proc_dsc(&self) -> &ProcDscInfo<'a> {
&self.proc_dsc
}
#[inline]
pub fn frame_size(&self) -> Result<u16, Error> {
self.proc_dsc.frame_size()
}
#[inline]
pub fn proc_size(&self) -> Result<u16, Error> {
self.proc_dsc.proc_size()
}
#[inline]
pub fn pcode_bytes(&self) -> &'a [u8] {
self.pcode_bytes
}
#[inline]
pub fn data_const_va(&self) -> u32 {
self.data_const_va
}
#[inline]
pub fn pcode_va(&self) -> u32 {
self.pcode_va
}
#[inline]
pub fn proc_dsc_va(&self) -> u32 {
self.proc_dsc_va
}
#[inline]
pub fn stub_va(&self) -> u32 {
self.stub_va
}
pub fn instructions(&self) -> Result<InstructionIterator<'a>, Error> {
Ok(InstructionIterator::new(
self.pcode_bytes,
self.proc_dsc.proc_size()?,
))
}
#[inline]
pub fn cleanup_entries(&self) -> ControlPropertyIter<'a> {
self.proc_dsc.cleanup_entries()
}
pub fn constant_pool<'m>(&self, map: &'m AddressMap<'a>) -> ConstantPool<'m>
where
'a: 'm,
{
ConstantPool::new(map, self.data_const_va)
}
}