Automatically check for invalid extab relocations (#75)
* Begin work on extab reloc analysis code * Refactoring * Make format happy * Address feedback + improvements
This commit is contained in:
parent
c106123877
commit
26f52f65b7
|
@ -393,6 +393,15 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cwextab"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5aa7f13cc2fcb2bcfd3abc51bdbbf8f1fb729a69ed8c05ecbaa1a42197d1842"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "decomp-toolkit"
|
name = "decomp-toolkit"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -404,6 +413,7 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"cwdemangle",
|
"cwdemangle",
|
||||||
|
"cwextab 1.0.2",
|
||||||
"enable-ansi-support",
|
"enable-ansi-support",
|
||||||
"filetime",
|
"filetime",
|
||||||
"fixedbitset 0.5.7",
|
"fixedbitset 0.5.7",
|
||||||
|
@ -1018,7 +1028,7 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"cwdemangle",
|
"cwdemangle",
|
||||||
"cwextab",
|
"cwextab 0.3.1",
|
||||||
"filetime",
|
"filetime",
|
||||||
"flagset",
|
"flagset",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -32,6 +32,7 @@ base16ct = "0.2"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
crossterm = "0.28"
|
crossterm = "0.28"
|
||||||
cwdemangle = "1.0"
|
cwdemangle = "1.0"
|
||||||
|
cwextab = "1.0.2"
|
||||||
enable-ansi-support = "0.2"
|
enable-ansi-support = "0.2"
|
||||||
filetime = "0.2"
|
filetime = "0.2"
|
||||||
fixedbitset = "0.5"
|
fixedbitset = "0.5"
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
use cwextab::decode_extab;
|
||||||
use ppc750cl::Opcode;
|
use ppc750cl::Opcode;
|
||||||
use tracing::{debug_span, info_span};
|
use tracing::{debug_span, info_span};
|
||||||
use tracing_attributes::instrument;
|
use tracing_attributes::instrument;
|
||||||
|
@ -120,6 +121,7 @@ impl Tracker {
|
||||||
self.process_data(obj, section_index, section)?;
|
self.process_data(obj, section_index, section)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.check_extab_relocations(obj)?;
|
||||||
self.reject_invalid_relocations(obj)?;
|
self.reject_invalid_relocations(obj)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -147,6 +149,62 @@ impl Tracker {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check all of the extab relocations, and reject any invalid ones by checking against the decoded table data
|
||||||
|
/// of each table.
|
||||||
|
fn check_extab_relocations(&mut self, obj: &ObjInfo) -> Result<()> {
|
||||||
|
let mut to_reject = vec![];
|
||||||
|
let Some((section_index, section)) = obj.sections.by_name("extab")? else {
|
||||||
|
// No extab section found, return
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let mut decoded_reloc_addrs: BTreeSet<u32> = BTreeSet::new();
|
||||||
|
|
||||||
|
// Decode each exception table, and collect all of the relocations from the decoded data for each
|
||||||
|
for (_, symbol) in obj.symbols.for_section(section_index) {
|
||||||
|
let extab_name = &symbol.name;
|
||||||
|
let extab_start_addr: u32 = symbol.address as u32;
|
||||||
|
let extab_end_addr: u32 = extab_start_addr + symbol.size as u32;
|
||||||
|
let Ok(extab_data) = section.data_range(extab_start_addr, extab_end_addr) else {
|
||||||
|
log::warn!("Failed to get extab data for symbol {}", extab_name);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let data = match decode_extab(extab_data) {
|
||||||
|
Ok(decoded_data) => decoded_data,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!(
|
||||||
|
"Exception table decoding failed for symbol {}, reason: {}",
|
||||||
|
extab_name,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for reloc in data.relocations {
|
||||||
|
let reloc_addr = extab_start_addr + reloc.offset;
|
||||||
|
decoded_reloc_addrs.insert(reloc_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let section_start_addr = SectionAddress::new(section_index, section.address as u32);
|
||||||
|
let section_end_addr = section_start_addr + (section.size as u32);
|
||||||
|
|
||||||
|
// Check all the extab relocations against the list of relocations from the decoded tables. Any
|
||||||
|
// relocations that aren't in the list are invalid, and are removed (if a table fails to decode,
|
||||||
|
// however, its relocations are all removed).
|
||||||
|
for (&address, _) in self.relocations.range(section_start_addr..section_end_addr) {
|
||||||
|
if !decoded_reloc_addrs.contains(&address.address) {
|
||||||
|
log::debug!("Rejecting invalid extab relocation @ {}", address);
|
||||||
|
to_reject.push(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for address in to_reject {
|
||||||
|
self.relocations.remove(&address);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn process_code(&mut self, obj: &ObjInfo) -> Result<()> {
|
fn process_code(&mut self, obj: &ObjInfo) -> Result<()> {
|
||||||
if let Some(entry) = obj.entry {
|
if let Some(entry) = obj.entry {
|
||||||
let (section_index, _) = obj.sections.at_address(entry as u32)?;
|
let (section_index, _) = obj.sections.at_address(entry as u32)?;
|
||||||
|
|
Loading…
Reference in New Issue