From 26f52f65b756d9a5b0d65368ce6c2ef98c239da1 Mon Sep 17 00:00:00 2001 From: Amber Brault Date: Thu, 3 Oct 2024 03:13:23 -0400 Subject: [PATCH] Automatically check for invalid extab relocations (#75) * Begin work on extab reloc analysis code * Refactoring * Make format happy * Address feedback + improvements --- Cargo.lock | 12 ++++++++- Cargo.toml | 1 + src/analysis/tracker.rs | 58 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 2d1368d..ddd0584 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 41262b6..73089c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/analysis/tracker.rs b/src/analysis/tracker.rs index af4cc5f..5e5fbee 100644 --- a/src/analysis/tracker.rs +++ b/src/analysis/tracker.rs @@ -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 = 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)?;