Merge pull request #40 from InusualZ/dol-improv
Dol Library Improvement by @InusualZ
This commit is contained in:
commit
6a3476639a
|
@ -298,7 +298,10 @@ impl Ins {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_branch(&self) -> bool {
|
pub fn is_branch(&self) -> bool {
|
||||||
matches!(self.op, Opcode::B | Opcode::Bc | Opcode::Bcctr | Opcode::Bclr)
|
matches!(
|
||||||
|
self.op,
|
||||||
|
Opcode::B | Opcode::Bc | Opcode::Bcctr | Opcode::Bclr
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_direct_branch(&self) -> bool {
|
pub fn is_direct_branch(&self) -> bool {
|
||||||
|
|
|
@ -498,7 +498,7 @@ fn test_ins_mfmsr() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_mfspr() {
|
fn test_ins_mfspr() {
|
||||||
assert_asm!(0x7E1A02A6, "mfspr r16, 832");
|
assert_asm!(0x7E1A02A6, "mfspr r16, 26");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -508,7 +508,7 @@ fn test_ins_mfsr() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_mftb() {
|
fn test_ins_mftb() {
|
||||||
assert_asm!(0x7C8C42E6, "mftb r4, 392");
|
assert_asm!(0x7C8C42E6, "mftb r4, 268");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -539,7 +539,7 @@ fn test_ins_mtmsr() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ins_mtspr() {
|
fn test_ins_mtspr() {
|
||||||
assert_asm!(0x7E75FBA6, "mtspr 703, r19");
|
assert_asm!(0x7E75FBA6, "mtspr 1013, r19");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -24,6 +24,8 @@ pub enum Error {
|
||||||
OverlappingSections(u32, u32),
|
OverlappingSections(u32, u32),
|
||||||
#[error("Section sizes too large")]
|
#[error("Section sizes too large")]
|
||||||
SectionsTooLarge,
|
SectionsTooLarge,
|
||||||
|
#[error("Attempted to access {0:08X} past DOL bounds")]
|
||||||
|
OutOfBounds(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bincode::Error> for Error {
|
impl From<bincode::Error> for Error {
|
||||||
|
@ -107,16 +109,44 @@ impl Dol {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads bytes into a destination buffer given a virtual address.
|
pub fn section_data(&self, section: &DolSection) -> &[u8] {
|
||||||
pub fn virtual_read(&self, dest: &mut [u8], virtual_addr: u32) {
|
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;
|
let offset = (virtual_addr - self.memory_offset) as usize;
|
||||||
// TODO Gracefully handle errors.
|
if offset + (read_len as usize) < self.memory.len() {
|
||||||
dest.copy_from_slice(&self.memory[offset..offset + dest.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)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum DolSectionType {
|
pub enum DolSectionType {
|
||||||
|
Text,
|
||||||
Data,
|
Data,
|
||||||
Bss,
|
Bss,
|
||||||
}
|
}
|
||||||
|
@ -132,15 +162,22 @@ pub struct DolSection {
|
||||||
|
|
||||||
pub struct DolHeader {
|
pub struct DolHeader {
|
||||||
pub sections: Vec<DolSection>,
|
pub sections: Vec<DolSection>,
|
||||||
|
pub entry_point: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&DolHeaderData> for DolHeader {
|
impl From<&DolHeaderData> for DolHeader {
|
||||||
fn from(header: &DolHeaderData) -> Self {
|
fn from(header: &DolHeaderData) -> Self {
|
||||||
let mut sections = Vec::with_capacity(DolHeaderData::SECTION_COUNT);
|
let mut sections = Vec::with_capacity(DolHeaderData::SECTION_COUNT);
|
||||||
for i in 0..DolHeaderData::SECTION_COUNT {
|
for i in 0..DolHeaderData::SECTION_COUNT {
|
||||||
|
let kind = if i < 7 {
|
||||||
|
DolSectionType::Text
|
||||||
|
} else {
|
||||||
|
DolSectionType::Data
|
||||||
|
};
|
||||||
|
|
||||||
if header.section_sizes[i] > 0 {
|
if header.section_sizes[i] > 0 {
|
||||||
sections.push(DolSection {
|
sections.push(DolSection {
|
||||||
kind: DolSectionType::Data,
|
kind,
|
||||||
index: i,
|
index: i,
|
||||||
offset: header.section_offsets[i],
|
offset: header.section_offsets[i],
|
||||||
target: header.section_targets[i],
|
target: header.section_targets[i],
|
||||||
|
@ -159,7 +196,21 @@ impl From<&DolHeaderData> for DolHeader {
|
||||||
}
|
}
|
||||||
// Sort sections by target address to prepare them for mapping.
|
// Sort sections by target address to prepare them for mapping.
|
||||||
sections.sort_by_key(|s| s.target);
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,8 @@ fn main() {
|
||||||
let dol = Dol::read_from(&dol_file).expect("Invalid DOL file");
|
let dol = Dol::read_from(&dol_file).expect("Invalid DOL file");
|
||||||
drop(dol_file);
|
drop(dol_file);
|
||||||
let mut bytes = vec![0u8; (stop_addr - start_addr) as usize];
|
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.
|
// Create control flow graph.
|
||||||
let ins_list: Vec<Ins> = disasm_iter(&bytes, start_addr).collect();
|
let ins_list: Vec<Ins> = disasm_iter(&bytes, start_addr).collect();
|
||||||
|
|
Loading…
Reference in New Issue