diff --git a/dol/src/lib.rs b/dol/src/lib.rs index 4d53b44..890d322 100644 --- a/dol/src/lib.rs +++ b/dol/src/lib.rs @@ -24,6 +24,8 @@ pub enum Error { OverlappingSections(u32, u32), #[error("Section sizes too large")] SectionsTooLarge, + #[error("Attempted to access {0:08X} past DOL bounds")] + OutOfBounds(u32), } impl From for Error { @@ -107,11 +109,38 @@ impl Dol { }) } - /// Reads bytes into a destination buffer given a virtual address. - pub fn virtual_read(&self, dest: &mut [u8], virtual_addr: u32) { + pub fn section_data(&self, section: &DolSection) -> &[u8] { + self.virtual_data_at(section.target, section.size).unwrap() + } + + /// Returns a slice of DOL data. Does not support bss. + pub fn virtual_data_at(&self, virtual_addr: u32, read_len: u32) -> Result<&[u8]> { + if virtual_addr < self.memory_offset { + return Err(Error::OutOfBounds(virtual_addr)); + } + let offset = (virtual_addr - self.memory_offset) as usize; - // TODO Gracefully handle errors. - dest.copy_from_slice(&self.memory[offset..offset + dest.len()]) + if offset + (read_len as usize) < self.memory.len() { + Ok(&self.memory[offset..offset + (read_len as usize)]) + } else { + Err(Error::OutOfBounds(virtual_addr + read_len)) + } + } + + /// Reads bytes into a destination buffer given a virtual address. + pub fn virtual_read(&self, data: &mut [u8], virtual_addr: u32) -> Result<()> { + if virtual_addr < self.memory_offset { + return Err(Error::OutOfBounds(virtual_addr)); + } + + let offset = (virtual_addr - self.memory_offset) as usize; + let read_len = data.len(); + if offset + read_len < self.memory.len() { + data.copy_from_slice(&self.memory[offset..offset + data.len()]); + Ok(()) + } else { + Err(Error::OutOfBounds(virtual_addr + (read_len as u32))) + } } } @@ -132,6 +161,7 @@ pub struct DolSection { pub struct DolHeader { pub sections: Vec, + pub entry_point: u32, } impl From<&DolHeaderData> for DolHeader { @@ -159,7 +189,21 @@ impl From<&DolHeaderData> for DolHeader { } // Sort sections by target address to prepare them for mapping. sections.sort_by_key(|s| s.target); - Self { sections } + Self { + sections, + entry_point: header.entry_point, + } + } +} + +impl DolHeader { + pub fn section_at(&self, addr: u32) -> Option<&DolSection> { + for section in &self.sections { + if (section.target..(section.target + section.size)).contains(&addr) { + return Some(section); + } + } + None } } diff --git a/flow-graph/src/main.rs b/flow-graph/src/main.rs index de2c5cd..5f27efa 100644 --- a/flow-graph/src/main.rs +++ b/flow-graph/src/main.rs @@ -44,7 +44,8 @@ fn main() { let dol = Dol::read_from(&dol_file).expect("Invalid DOL file"); drop(dol_file); let mut bytes = vec![0u8; (stop_addr - start_addr) as usize]; - dol.virtual_read(&mut bytes, start_addr); + dol.virtual_read(&mut bytes, start_addr) + .expect("Invalid address range"); // Create control flow graph. let ins_list: Vec = disasm_iter(&bytes, start_addr).collect();