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:
Amber Brault 2024-10-03 03:13:23 -04:00 committed by GitHub
parent c106123877
commit 26f52f65b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 1 deletions

12
Cargo.lock generated
View File

@ -393,6 +393,15 @@ dependencies = [
"thiserror",
]
[[package]]
name = "cwextab"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5aa7f13cc2fcb2bcfd3abc51bdbbf8f1fb729a69ed8c05ecbaa1a42197d1842"
dependencies = [
"thiserror",
]
[[package]]
name = "decomp-toolkit"
version = "1.0.0"
@ -404,6 +413,7 @@ dependencies = [
"base64",
"crossterm",
"cwdemangle",
"cwextab 1.0.2",
"enable-ansi-support",
"filetime",
"fixedbitset 0.5.7",
@ -1018,7 +1028,7 @@ dependencies = [
"anyhow",
"byteorder",
"cwdemangle",
"cwextab",
"cwextab 0.3.1",
"filetime",
"flagset",
"log",

View File

@ -32,6 +32,7 @@ base16ct = "0.2"
base64 = "0.22"
crossterm = "0.28"
cwdemangle = "1.0"
cwextab = "1.0.2"
enable-ansi-support = "0.2"
filetime = "0.2"
fixedbitset = "0.5"

View File

@ -4,6 +4,7 @@ use std::{
};
use anyhow::{bail, Result};
use cwextab::decode_extab;
use ppc750cl::Opcode;
use tracing::{debug_span, info_span};
use tracing_attributes::instrument;
@ -120,6 +121,7 @@ impl Tracker {
self.process_data(obj, section_index, section)?;
}
}
self.check_extab_relocations(obj)?;
self.reject_invalid_relocations(obj)?;
Ok(())
}
@ -147,6 +149,62 @@ impl Tracker {
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<()> {
if let Some(entry) = obj.entry {
let (section_index, _) = obj.sections.at_address(entry as u32)?;