From 21a0d7a4cbde38d8c10f3ba9d890b57517d232c5 Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Sat, 9 Jan 2021 14:19:44 +0000 Subject: [PATCH] Revised documentation for `dcb-exe::exe`. --- dcb-exe/src/exe.rs | 100 +++++++++++++++++-------------- dcb-exe/src/exe/iter.rs | 4 +- dcb-exe/src/exe/pos.rs | 9 ++- dcb-tools/src/decompiler/main.rs | 4 +- 4 files changed, 66 insertions(+), 51 deletions(-) diff --git a/dcb-exe/src/exe.rs b/dcb-exe/src/exe.rs index 3540e6f..cf661fa 100644 --- a/dcb-exe/src/exe.rs +++ b/dcb-exe/src/exe.rs @@ -1,7 +1,7 @@ //! Executable //! -//! This module contains the executable portion of the game, -//! as well as tools to decompile and recompile it. +//! This module defines the `Exe` type, which encompasses the whole +//! executable part of the game file (`SLUS_013`). // Modules pub mod data; @@ -15,7 +15,7 @@ pub mod pos; // Exports pub use data::{Data, DataTable, DataType}; pub use error::DeserializeError; -pub use func::Func; +pub use func::{Func, FuncTable}; pub use header::Header; pub use pos::Pos; @@ -24,39 +24,73 @@ use dcb_bytes::{ByteArray, Bytes}; use dcb_io::GameFile; use std::io::{Read, Seek, Write}; -use self::func::FuncTable; - /// The game executable #[derive(PartialEq, Eq, Clone, Debug)] -//#[derive(serde::Serialize, serde::Deserialize)] -#[allow(clippy::as_conversions)] // `SIZE` always fits pub struct Exe { /// The executable header - pub header: Header, + header: Header, - /// All bytes within the exe - pub bytes: Box<[u8; Self::SIZE as usize]>, + /// All bytes within the executable + bytes: Box<[u8]>, /// The data table. - pub data_table: DataTable, + data_table: DataTable, /// The function table. - pub func_table: FuncTable, + func_table: FuncTable, } impl Exe { - /// End memory address of the executable - pub const END_MEM_ADDRESS: Pos = Pos(Self::START_MEM_ADDRESS.0 + Self::SIZE); - /// Size of the executable + /// Size of the executable section. pub const SIZE: u32 = 0x68000; - /// Start address of the executable + /// Start address of the executable in the game file. pub const START_ADDRESS: dcb_io::Data = dcb_io::Data::from_u64(0x58b9000); - /// Start memory address of the executable - pub const START_MEM_ADDRESS: Pos = Pos(0x80010000); +} + +// Memory address +impl Exe { + /// End memory address of the executable. + pub const MEM_END_ADDRESS: Pos = Self::MEM_START_ADDRESS.add_offset_u32(Self::SIZE); + /// Memory range of the executable + pub const MEM_RANGE: std::ops::Range = Self::MEM_START_ADDRESS..Self::MEM_END_ADDRESS; + /// Start memory address of the executable. + pub const MEM_START_ADDRESS: Pos = Pos(0x80010000); } impl Exe { - /// Deserializes the card table from a game file + /// Returns this executable's header + #[must_use] + pub const fn header(&self) -> &Header { + &self.header + } + + /// Returns this executable's bytes + #[must_use] + pub const fn bytes(&self) -> &[u8] { + &*self.bytes + } + + /// Creates an iterator over this executable + #[must_use] + pub const fn iter(&self) -> iter::Iter { + iter::Iter::new(self) + } + + /// Returns a parsing iterator for all instructions + #[must_use] + pub const fn parse_iter(&self) -> inst::ParseIter { + inst::ParseIter::new(&*self.bytes, Self::MEM_START_ADDRESS) + } + + /// Returns the instruction at `pos` + #[must_use] + pub fn get(&self, pos: Pos) -> Option { + inst::ParseIter::new(&*self.bytes, pos).next().map(|(_, inst)| inst) + } +} + +impl Exe { + /// Deserializes the executable from a game file pub fn deserialize(file: &mut GameFile) -> Result { // Seek to the table file.seek(std::io::SeekFrom::Start(Self::START_ADDRESS.as_u64())) @@ -78,7 +112,7 @@ impl Exe { file.read_exact(bytes.as_mut()).map_err(DeserializeError::ReadData)?; // Parse all instructions - let insts = inst::ParseIter::new(&*bytes, Self::START_MEM_ADDRESS); + let insts = inst::ParseIter::new(&*bytes, Self::MEM_START_ADDRESS); // Parse all data and code let known_data_table = DataTable::get_known().map_err(DeserializeError::KnownDataTable)?; @@ -96,30 +130,4 @@ impl Exe { func_table, }) } - - /* - /// Returns a parsing iterator for all instructions - #[must_use] - pub const fn parse_iter(&self) -> inst::ParseIter { - inst::ParseIter::new(&*self.bytes, Self::START_MEM_ADDRESS) - } - - /// Returns this executable's bytes - #[must_use] - pub const fn bytes(&self) -> &[u8] { - &*self.bytes - } - */ - - /// Creates an iterator over this executable - #[must_use] - pub const fn iter(&self) -> iter::Iter { - iter::Iter::new(self) - } - - /// Returns the instruction at `pos` - #[must_use] - pub fn get(&self, pos: Pos) -> Option { - inst::ParseIter::new(&*self.bytes, pos).next().map(|(_, inst)| inst) - } } diff --git a/dcb-exe/src/exe/iter.rs b/dcb-exe/src/exe/iter.rs index 328c231..9406746 100644 --- a/dcb-exe/src/exe/iter.rs +++ b/dcb-exe/src/exe/iter.rs @@ -21,7 +21,7 @@ impl<'a> Iter<'a> { pub(crate) const fn new(exe: &'a Exe) -> Self { Self { exe, - cur_pos: Exe::START_MEM_ADDRESS, + cur_pos: Exe::MEM_START_ADDRESS, } } } @@ -43,7 +43,7 @@ impl<'a> Iterator for Iter<'a> { fn next(&mut self) -> Option { // If we're at the end, return `None` - if self.cur_pos == Exe::END_MEM_ADDRESS { + if self.cur_pos == Exe::MEM_END_ADDRESS { return None; } diff --git a/dcb-exe/src/exe/pos.rs b/dcb-exe/src/exe/pos.rs index 698a2d6..7616ce7 100644 --- a/dcb-exe/src/exe/pos.rs +++ b/dcb-exe/src/exe/pos.rs @@ -16,10 +16,17 @@ use crate::Exe; pub struct Pos(pub u32); impl Pos { + /// Adds a `u32` offset to this position + // TODO: Remove once we can `impl const Add` + #[must_use] + pub(crate) const fn add_offset_u32(self, offset: u32) -> Self { + Self(self.0 + offset) + } + /// Returns the memory position of this position #[must_use] pub fn as_mem_idx(self) -> usize { - usize::try_from(self - Exe::START_MEM_ADDRESS).expect("Failed to compute index") + usize::try_from(self - Exe::MEM_START_ADDRESS).expect("Failed to compute index") } } diff --git a/dcb-tools/src/decompiler/main.rs b/dcb-tools/src/decompiler/main.rs index c9bfbb7..ae3dd8c 100644 --- a/dcb-tools/src/decompiler/main.rs +++ b/dcb-tools/src/decompiler/main.rs @@ -95,7 +95,7 @@ fn main() -> Result<(), anyhow::Error> { log::debug!("Deserializing executable"); let exe = dcb_exe::Exe::deserialize(&mut game_file).context("Unable to parse game executable")?; - println!("Header:\n{}", exe.header); + println!("Header:\n{}", exe.header()); for item in exe.iter() { match item { @@ -159,7 +159,7 @@ fn main() -> Result<(), anyhow::Error> { // If it's standalone, print it by it's own ExeItem::Inst(pos, inst) => { - println!("{}: {}", pos, inst.fmt_value(pos, &*exe.bytes)); + println!("{}: {}", pos, inst.fmt_value(pos, exe.bytes())); }, }