mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-13 23:26:15 +00:00
Begin REL analysis & rework lots of code to be section-address aware
This commit is contained in:
@@ -29,8 +29,10 @@ impl AnalyzerState {
|
||||
if end == 0 {
|
||||
continue;
|
||||
}
|
||||
let section_index =
|
||||
obj.section_for(start..end).context("Failed to locate section for function")?.index;
|
||||
let (section_index, _) = obj
|
||||
.sections
|
||||
.with_range(start..end)
|
||||
.context("Failed to locate section for function")?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("fn_{:08X}", start),
|
||||
@@ -48,10 +50,10 @@ impl AnalyzerState {
|
||||
)?;
|
||||
}
|
||||
for (&addr, &size) in &self.jump_tables {
|
||||
let section_index = obj
|
||||
.section_for(addr..addr + size)
|
||||
.context("Failed to locate section for jump table")?
|
||||
.index;
|
||||
let (section_index, _) = obj
|
||||
.sections
|
||||
.with_range(addr..addr + size)
|
||||
.context("Failed to locate section for jump table")?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("jumptable_{:08X}", addr),
|
||||
@@ -89,7 +91,7 @@ impl AnalyzerState {
|
||||
}
|
||||
}
|
||||
// Also check the beginning of every code section
|
||||
for section in obj.sections.iter().filter(|s| s.kind == ObjSectionKind::Code) {
|
||||
for (_, section) in obj.sections.by_kind(ObjSectionKind::Code) {
|
||||
self.function_entries.insert(section.address as u32);
|
||||
}
|
||||
|
||||
@@ -266,11 +268,7 @@ impl AnalyzerState {
|
||||
|
||||
fn detect_new_functions(&mut self, obj: &ObjInfo) -> Result<bool> {
|
||||
let mut found_new = false;
|
||||
for section in &obj.sections {
|
||||
if section.kind != ObjSectionKind::Code {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (_, section) in obj.sections.by_kind(ObjSectionKind::Code) {
|
||||
let section_start = section.address as u32;
|
||||
let section_end = (section.address + section.size) as u32;
|
||||
let mut iter = self.function_bounds.range(section_start..section_end).peekable();
|
||||
@@ -280,7 +278,7 @@ impl AnalyzerState {
|
||||
if first_end == 0 || first_end > second_begin {
|
||||
continue;
|
||||
}
|
||||
let addr = match skip_alignment(obj, first_end, second_begin) {
|
||||
let addr = match skip_alignment(section, first_end, second_begin) {
|
||||
Some(addr) => addr,
|
||||
None => continue,
|
||||
};
|
||||
@@ -298,7 +296,7 @@ impl AnalyzerState {
|
||||
}
|
||||
(Some((&last_begin, &last_end)), None) => {
|
||||
if last_end > 0 && last_end < section_end {
|
||||
let addr = match skip_alignment(obj, last_end, section_end) {
|
||||
let addr = match skip_alignment(section, last_end, section_end) {
|
||||
Some(addr) => addr,
|
||||
None => continue,
|
||||
};
|
||||
@@ -329,7 +327,7 @@ pub fn locate_sda_bases(obj: &mut ObjInfo) -> Result<bool> {
|
||||
executor.push(obj.entry as u32, VM::new(), false);
|
||||
let result = executor.run(
|
||||
obj,
|
||||
|ExecCbData { executor, vm, result, section: _, ins, block_start: _ }| {
|
||||
|ExecCbData { executor, vm, result, section_index: _, section: _, ins, block_start: _ }| {
|
||||
match result {
|
||||
StepResult::Continue | StepResult::LoadStore { .. } => {
|
||||
return Ok(ExecCbResult::Continue);
|
||||
|
||||
@@ -17,8 +17,8 @@ struct VisitedAddresses {
|
||||
|
||||
impl VisitedAddresses {
|
||||
pub fn new(obj: &ObjInfo) -> Self {
|
||||
let mut inner = Vec::with_capacity(obj.sections.len());
|
||||
for section in &obj.sections {
|
||||
let mut inner = Vec::with_capacity(obj.sections.count());
|
||||
for (_, section) in obj.sections.iter() {
|
||||
if section.kind == ObjSectionKind::Code {
|
||||
let size = (section.size / 4) as usize;
|
||||
inner.push(FixedBitSet::with_capacity(size));
|
||||
@@ -30,17 +30,17 @@ impl VisitedAddresses {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub fn contains(&self, section: &ObjSection, address: u32) -> bool {
|
||||
self.inner[section.index].contains(Self::bit_for(section, address))
|
||||
pub fn contains(&self, section_index: usize, section_address: u32, address: u32) -> bool {
|
||||
self.inner[section_index].contains(Self::bit_for(section_address, address))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, section: &ObjSection, address: u32) {
|
||||
self.inner[section.index].insert(Self::bit_for(section, address));
|
||||
pub fn insert(&mut self, section_index: usize, section_address: u32, address: u32) {
|
||||
self.inner[section_index].insert(Self::bit_for(section_address, address));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bit_for(section: &ObjSection, address: u32) -> usize {
|
||||
((address as u64 - section.address) / 4) as usize
|
||||
fn bit_for(section_address: u32, address: u32) -> usize {
|
||||
((address - section_address) / 4) as usize
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ pub struct ExecCbData<'a> {
|
||||
pub executor: &'a mut Executor,
|
||||
pub vm: &'a mut VM,
|
||||
pub result: StepResult,
|
||||
pub section_index: usize,
|
||||
pub section: &'a ObjSection,
|
||||
pub ins: &'a Ins,
|
||||
pub block_start: u32,
|
||||
@@ -79,8 +80,8 @@ impl Executor {
|
||||
pub fn run<Cb, R>(&mut self, obj: &ObjInfo, mut cb: Cb) -> Result<Option<R>>
|
||||
where Cb: FnMut(ExecCbData) -> Result<ExecCbResult<R>> {
|
||||
while let Some(mut state) = self.vm_stack.pop() {
|
||||
let section = match obj.section_at(state.address) {
|
||||
Ok(section) => section,
|
||||
let (section_index, section) = match obj.sections.at_address(state.address) {
|
||||
Ok(ret) => ret,
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
// return Ok(None);
|
||||
@@ -93,13 +94,14 @@ impl Executor {
|
||||
}
|
||||
|
||||
// Already visited block
|
||||
if self.visited.contains(section, state.address) {
|
||||
let section_address = section.address as u32;
|
||||
if self.visited.contains(section_index, section_address, state.address) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut block_start = state.address;
|
||||
loop {
|
||||
self.visited.insert(section, state.address);
|
||||
self.visited.insert(section_index, section_address, state.address);
|
||||
|
||||
let ins = match disassemble(section, state.address) {
|
||||
Some(ins) => ins,
|
||||
@@ -110,6 +112,7 @@ impl Executor {
|
||||
executor: self,
|
||||
vm: &mut state.vm,
|
||||
result,
|
||||
section_index,
|
||||
section,
|
||||
ins: &ins,
|
||||
block_start,
|
||||
@@ -118,7 +121,7 @@ impl Executor {
|
||||
state.address += 4;
|
||||
}
|
||||
ExecCbResult::Jump(addr) => {
|
||||
if self.visited.contains(section, addr) {
|
||||
if self.visited.contains(section_index, section_address, addr) {
|
||||
break;
|
||||
}
|
||||
block_start = addr;
|
||||
@@ -140,7 +143,7 @@ impl Executor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visited(&self, section: &ObjSection, address: u32) -> bool {
|
||||
self.visited.contains(section, address)
|
||||
pub fn visited(&self, section_index: usize, section_address: u32, address: u32) -> bool {
|
||||
self.visited.contains(section_index, section_address, address)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ use std::{collections::BTreeSet, num::NonZeroU32};
|
||||
use anyhow::{Context, Result};
|
||||
use ppc750cl::Ins;
|
||||
|
||||
use crate::obj::{ObjInfo, ObjSection, ObjSectionKind};
|
||||
use crate::{
|
||||
array_ref,
|
||||
obj::{ObjInfo, ObjSection, ObjSectionKind},
|
||||
};
|
||||
|
||||
pub mod cfa;
|
||||
pub mod executor;
|
||||
@@ -23,11 +26,11 @@ pub fn read_u32(data: &[u8], address: u32, section_address: u32) -> Option<u32>
|
||||
if data.len() < offset + 4 {
|
||||
return None;
|
||||
}
|
||||
Some(u32::from_be_bytes(data[offset..offset + 4].try_into().unwrap()))
|
||||
Some(u32::from_be_bytes(*array_ref!(data, offset, 4)))
|
||||
}
|
||||
|
||||
fn is_valid_jump_table_addr(obj: &ObjInfo, addr: u32) -> bool {
|
||||
matches!(obj.section_at(addr), Ok(section) if section.kind != ObjSectionKind::Bss)
|
||||
matches!(obj.sections.at_address(addr), Ok((_, section)) if section.kind != ObjSectionKind::Bss)
|
||||
}
|
||||
|
||||
fn get_jump_table_entries(
|
||||
@@ -38,7 +41,7 @@ fn get_jump_table_entries(
|
||||
function_start: u32,
|
||||
function_end: u32,
|
||||
) -> Result<(Vec<u32>, u32)> {
|
||||
let section = obj.section_at(addr).with_context(|| {
|
||||
let (_, section) = obj.sections.at_address(addr).with_context(|| {
|
||||
format!("Failed to get jump table entries @ {:#010X} size {:?}", addr, size)
|
||||
})?;
|
||||
let offset = (addr as u64 - section.address) as usize;
|
||||
@@ -90,9 +93,9 @@ pub fn uniq_jump_table_entries(
|
||||
Ok((BTreeSet::from_iter(entries.iter().cloned().filter(|&addr| addr != 0)), size))
|
||||
}
|
||||
|
||||
pub fn skip_alignment(obj: &ObjInfo, mut addr: u32, end: u32) -> Option<u32> {
|
||||
let mut data = match obj.section_data(addr, end) {
|
||||
Ok((_, data)) => data,
|
||||
pub fn skip_alignment(section: &ObjSection, mut addr: u32, end: u32) -> Option<u32> {
|
||||
let mut data = match section.data_range(addr, end) {
|
||||
Ok(data) => data,
|
||||
Err(_) => return None,
|
||||
};
|
||||
loop {
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::obj::{
|
||||
split::is_linker_generated_label, ObjDataKind, ObjInfo, ObjSectionKind, ObjSymbolKind,
|
||||
use crate::{
|
||||
obj::{ObjDataKind, ObjInfo, ObjSectionKind, ObjSymbolKind},
|
||||
util::split::is_linker_generated_label,
|
||||
};
|
||||
|
||||
pub fn detect_object_boundaries(obj: &mut ObjInfo) -> Result<()> {
|
||||
for section in obj.sections.iter().filter(|s| s.kind != ObjSectionKind::Code) {
|
||||
let section_start = section.address as u32;
|
||||
for (section_index, section) in
|
||||
obj.sections.iter_mut().filter(|(_, s)| s.kind != ObjSectionKind::Code)
|
||||
{
|
||||
let section_end = (section.address + section.size) as u32;
|
||||
|
||||
let mut replace_symbols = vec![];
|
||||
for (idx, symbol) in obj.symbols.for_range(section_start..section_end) {
|
||||
for (idx, symbol) in obj.symbols.for_section(section_index) {
|
||||
let mut symbol = symbol.clone();
|
||||
if is_linker_generated_label(&symbol.name) {
|
||||
continue;
|
||||
@@ -25,7 +27,7 @@ pub fn detect_object_boundaries(obj: &mut ObjInfo) -> Result<()> {
|
||||
if !symbol.size_known {
|
||||
let next_addr = obj
|
||||
.symbols
|
||||
.for_range(symbol.address as u32 + 1..section_end)
|
||||
.for_section_range(section_index, symbol.address as u32 + 1..)
|
||||
.next()
|
||||
.map_or(section_end, |(_, symbol)| symbol.address as u32);
|
||||
let new_size = next_addr - symbol.address as u32;
|
||||
@@ -35,9 +37,9 @@ pub fn detect_object_boundaries(obj: &mut ObjInfo) -> Result<()> {
|
||||
(2 | 4, 2) => expected_size,
|
||||
(..=8, 1 | 2 | 4) => {
|
||||
// alignment to double
|
||||
if obj.symbols.at_address(next_addr).any(|(_, sym)| sym.data_kind == ObjDataKind::Double)
|
||||
if obj.symbols.at_section_address(section_index, next_addr).any(|(_, sym)| sym.data_kind == ObjDataKind::Double)
|
||||
// If we're at a TU boundary, we can assume it's just padding
|
||||
|| obj.splits.contains_key(&(symbol.address as u32 + new_size))
|
||||
|| section.splits.has_split_at(symbol.address as u32 + new_size)
|
||||
{
|
||||
expected_size
|
||||
} else {
|
||||
@@ -63,10 +65,10 @@ pub fn detect_object_boundaries(obj: &mut ObjInfo) -> Result<()> {
|
||||
|
||||
pub fn detect_strings(obj: &mut ObjInfo) -> Result<()> {
|
||||
let mut symbols_set = Vec::<(usize, ObjDataKind, usize)>::new();
|
||||
for section in obj
|
||||
for (section_index, section) in obj
|
||||
.sections
|
||||
.iter()
|
||||
.filter(|s| matches!(s.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData))
|
||||
.filter(|(_, s)| matches!(s.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData))
|
||||
{
|
||||
enum StringResult {
|
||||
None,
|
||||
@@ -119,11 +121,10 @@ pub fn detect_strings(obj: &mut ObjInfo) -> Result<()> {
|
||||
}
|
||||
for (symbol_idx, symbol) in obj
|
||||
.symbols
|
||||
.for_section(section)
|
||||
.for_section(section_index)
|
||||
.filter(|(_, sym)| sym.data_kind == ObjDataKind::Unknown)
|
||||
{
|
||||
let (_section, data) =
|
||||
obj.section_data(symbol.address as u32, (symbol.address + symbol.size) as u32)?;
|
||||
let data = section.symbol_data(symbol)?;
|
||||
match is_string(data) {
|
||||
StringResult::None => {}
|
||||
StringResult::String { length, terminated } => {
|
||||
@@ -146,7 +147,7 @@ pub fn detect_strings(obj: &mut ObjInfo) -> Result<()> {
|
||||
}
|
||||
|
||||
for (symbol_idx, data_kind, size) in symbols_set {
|
||||
let mut symbol = obj.symbols.at(symbol_idx).clone();
|
||||
let mut symbol = obj.symbols[symbol_idx].clone();
|
||||
log::debug!("Setting {} ({:#010X}) to size {:#X}", symbol.name, symbol.address, size);
|
||||
symbol.data_kind = data_kind;
|
||||
symbol.size = size as u64;
|
||||
|
||||
@@ -21,8 +21,9 @@ pub const TRK_TABLE_SIZE: u32 = 0x1F34; // always?
|
||||
impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
||||
for (&start, _) in state.function_bounds.iter().filter(|&(_, &end)| end == 0) {
|
||||
let (section, data) = match obj.section_data(start, 0) {
|
||||
Ok((section, data)) => (section, data),
|
||||
let (section_index, section) = obj.sections.at_address(start)?;
|
||||
let data = match section.data_range(start, 0) {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if data.starts_with(TRK_TABLE_HEADER.as_bytes())
|
||||
@@ -33,7 +34,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||
name: "gTRKInterruptVectorTable".to_string(),
|
||||
demangled_name: None,
|
||||
address: start as u64,
|
||||
section: Some(section.index),
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
@@ -46,7 +47,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||
name: "gTRKInterruptVectorTableEnd".to_string(),
|
||||
demangled_name: None,
|
||||
address: end as u64,
|
||||
section: Some(section.index),
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
@@ -78,7 +79,11 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
const SLED_SIZE: usize = 19 * 4; // registers 14-31 + blr
|
||||
let mut clear_ranges: Vec<Range<u32>> = vec![];
|
||||
for (&start, _) in state.function_bounds.iter().filter(|&(_, &end)| end != 0) {
|
||||
let (section, data) = obj.section_data(start, 0)?;
|
||||
let (section_index, section) = obj.sections.at_address(start)?;
|
||||
let data = match section.data_range(start, 0) {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => continue,
|
||||
};
|
||||
for (needle, func, label) in &SLEDS {
|
||||
if data.starts_with(needle) {
|
||||
log::debug!("Found {} @ {:#010X}", func, start);
|
||||
@@ -87,7 +92,7 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
name: func.to_string(),
|
||||
demangled_name: None,
|
||||
address: start as u64,
|
||||
section: Some(section.index),
|
||||
section: Some(section_index),
|
||||
size: SLED_SIZE as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -101,7 +106,7 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
name: format!("{}{}", label, i),
|
||||
demangled_name: None,
|
||||
address: addr as u64,
|
||||
section: Some(section.index),
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
|
||||
@@ -3,12 +3,10 @@ use anyhow::{anyhow, Result};
|
||||
use crate::{
|
||||
analysis::{cfa::AnalyzerState, read_u32},
|
||||
obj::{
|
||||
signatures::{
|
||||
apply_signature, check_signatures, check_signatures_str, parse_signatures,
|
||||
FunctionSignature,
|
||||
},
|
||||
ObjInfo, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind,
|
||||
ObjInfo, ObjSectionKind, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
|
||||
ObjSymbolKind,
|
||||
},
|
||||
util::signatures::{apply_signature, check_signatures, check_signatures_str, parse_signatures},
|
||||
};
|
||||
|
||||
const SIGNATURES: &[(&str, &str)] = &[
|
||||
@@ -197,17 +195,23 @@ const POST_SIGNATURES: &[(&str, &str)] = &[
|
||||
|
||||
pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let entry = obj.entry as u32;
|
||||
if let Some(signature) =
|
||||
check_signatures_str(obj, entry, include_str!("../../assets/signatures/__start.yml"))?
|
||||
{
|
||||
apply_signature(obj, entry, &signature)?;
|
||||
let (entry_section_index, entry_section) = obj.sections.at_address(entry)?;
|
||||
if let Some(signature) = check_signatures_str(
|
||||
entry_section,
|
||||
entry,
|
||||
include_str!("../../assets/signatures/__start.yml"),
|
||||
)? {
|
||||
apply_signature(obj, entry_section_index, entry, &signature)?;
|
||||
}
|
||||
|
||||
for &(name, sig_str) in SIGNATURES {
|
||||
if let Some((_, symbol)) = obj.symbols.by_name(name)? {
|
||||
let addr = symbol.address as u32;
|
||||
if let Some(signature) = check_signatures_str(obj, addr, sig_str)? {
|
||||
apply_signature(obj, addr, &signature)?;
|
||||
let section_index =
|
||||
symbol.section.ok_or_else(|| anyhow!("Symbol '{}' missing section", name))?;
|
||||
let section = &obj.sections[section_index];
|
||||
if let Some(signature) = check_signatures_str(section, addr, sig_str)? {
|
||||
apply_signature(obj, section_index, addr, &signature)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,12 +221,13 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let mut analyzer = AnalyzerState::default();
|
||||
analyzer.process_function_at(obj, symbol.address as u32)?;
|
||||
for addr in analyzer.function_entries {
|
||||
let (section_index, section) = obj.sections.at_address(addr)?;
|
||||
if let Some(signature) = check_signatures_str(
|
||||
obj,
|
||||
section,
|
||||
addr,
|
||||
include_str!("../../assets/signatures/__init_cpp.yml"),
|
||||
)? {
|
||||
apply_signature(obj, addr, &signature)?;
|
||||
apply_signature(obj, section_index, addr, &signature)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -230,24 +235,27 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
|
||||
if let Some((_, symbol)) = obj.symbols.by_name("_ctors")? {
|
||||
// First entry of ctors is __init_cpp_exceptions
|
||||
let section = obj.section_at(symbol.address as u32)?;
|
||||
let target = read_u32(§ion.data, symbol.address as u32, section.address as u32)
|
||||
.ok_or_else(|| anyhow!("Failed to read _ctors data"))?;
|
||||
let ctors_section_index =
|
||||
symbol.section.ok_or_else(|| anyhow!("Missing _ctors symbol section"))?;
|
||||
let ctors_section = &obj.sections[ctors_section_index];
|
||||
let target =
|
||||
read_u32(&ctors_section.data, symbol.address as u32, ctors_section.address as u32)
|
||||
.ok_or_else(|| anyhow!("Failed to read _ctors data"))?;
|
||||
if target != 0 {
|
||||
let (target_section_index, target_section) = obj.sections.at_address(target)?;
|
||||
if let Some(signature) = check_signatures_str(
|
||||
obj,
|
||||
target_section,
|
||||
target,
|
||||
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
|
||||
)? {
|
||||
let address = symbol.address;
|
||||
let section_index = section.index;
|
||||
apply_signature(obj, target, &signature)?;
|
||||
obj.add_symbol(
|
||||
apply_signature(obj, target_section_index, target, &signature)?;
|
||||
obj.symbols.add(
|
||||
ObjSymbol {
|
||||
name: "__init_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(section_index),
|
||||
section: Some(ctors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -257,8 +265,8 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
if obj.split_for(address as u32).is_none() {
|
||||
obj.add_split(address as u32, ObjSplit {
|
||||
if obj.sections[ctors_section_index].splits.for_address(address as u32).is_none() {
|
||||
obj.add_split(ctors_section_index, address as u32, ObjSplit {
|
||||
unit: "__init_cpp_exceptions.cpp".to_string(),
|
||||
end: address as u32 + 4,
|
||||
align: None,
|
||||
@@ -271,30 +279,32 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
}
|
||||
|
||||
if let Some((_, symbol)) = obj.symbols.by_name("_dtors")? {
|
||||
let section = obj.section_at(symbol.address as u32)?;
|
||||
let dtors_section_index =
|
||||
symbol.section.ok_or_else(|| anyhow!("Missing _dtors symbol section"))?;
|
||||
let dtors_section = &obj.sections[dtors_section_index];
|
||||
let address = symbol.address;
|
||||
let section_address = section.address;
|
||||
let section_index = section.index;
|
||||
let section_address = dtors_section.address;
|
||||
// First entry of dtors is __destroy_global_chain
|
||||
let dgc_target = read_u32(§ion.data, address as u32, section_address as u32)
|
||||
let dgc_target = read_u32(&dtors_section.data, address as u32, section_address as u32)
|
||||
.ok_or_else(|| anyhow!("Failed to read _dtors data"))?;
|
||||
let fce_target = read_u32(§ion.data, address as u32 + 4, section_address as u32)
|
||||
let fce_target = read_u32(&dtors_section.data, address as u32 + 4, section_address as u32)
|
||||
.ok_or_else(|| anyhow!("Failed to read _dtors data"))?;
|
||||
let mut found_dgc = false;
|
||||
let mut found_fce = false;
|
||||
if dgc_target != 0 {
|
||||
let (target_section_index, target_section) = obj.sections.at_address(dgc_target)?;
|
||||
if let Some(signature) = check_signatures_str(
|
||||
obj,
|
||||
target_section,
|
||||
dgc_target,
|
||||
include_str!("../../assets/signatures/__destroy_global_chain.yml"),
|
||||
)? {
|
||||
apply_signature(obj, dgc_target, &signature)?;
|
||||
apply_signature(obj, target_section_index, dgc_target, &signature)?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__destroy_global_chain_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(section_index),
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -314,18 +324,19 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
}
|
||||
// Second entry of dtors is __fini_cpp_exceptions
|
||||
if fce_target != 0 {
|
||||
let (target_section_index, target_section) = obj.sections.at_address(fce_target)?;
|
||||
if let Some(signature) = check_signatures_str(
|
||||
obj,
|
||||
target_section,
|
||||
fce_target,
|
||||
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
|
||||
)? {
|
||||
apply_signature(obj, fce_target, &signature)?;
|
||||
apply_signature(obj, target_section_index, fce_target, &signature)?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__fini_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address: address + 4,
|
||||
section: Some(section_index),
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -344,8 +355,8 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
if found_fce {
|
||||
end += 4;
|
||||
}
|
||||
if obj.split_for(address as u32).is_none() {
|
||||
obj.add_split(address as u32, ObjSplit {
|
||||
if obj.sections[dtors_section_index].splits.for_address(address as u32).is_none() {
|
||||
obj.add_split(dtors_section_index, address as u32, ObjSplit {
|
||||
unit: "__init_cpp_exceptions.cpp".to_string(),
|
||||
end,
|
||||
align: None,
|
||||
@@ -363,19 +374,28 @@ pub fn apply_signatures_post(obj: &mut ObjInfo) -> Result<()> {
|
||||
log::info!("Checking post CFA signatures...");
|
||||
for &(_name, sig_str) in POST_SIGNATURES {
|
||||
let signatures = parse_signatures(sig_str)?;
|
||||
let mut iter = obj.symbols.by_kind(ObjSymbolKind::Function);
|
||||
let opt = loop {
|
||||
let Some((_, symbol)) = iter.next() else {
|
||||
break Option::<(u32, FunctionSignature)>::None;
|
||||
};
|
||||
if let Some(signature) = check_signatures(obj, symbol.address as u32, &signatures)? {
|
||||
break Some((symbol.address as u32, signature));
|
||||
let mut found_signature = None;
|
||||
'outer: for (section_index, section) in obj.sections.by_kind(ObjSectionKind::Code) {
|
||||
for (symbol_index, symbol) in obj
|
||||
.symbols
|
||||
.for_section(section_index)
|
||||
.filter(|(_, sym)| sym.kind == ObjSymbolKind::Function)
|
||||
{
|
||||
if let Some(signature) =
|
||||
check_signatures(section, symbol.address as u32, &signatures)?
|
||||
{
|
||||
found_signature = Some((symbol_index, signature));
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some((addr, signature)) = opt {
|
||||
drop(iter);
|
||||
apply_signature(obj, addr, &signature)?;
|
||||
break;
|
||||
}
|
||||
if let Some((symbol_index, signature)) = found_signature {
|
||||
let symbol = &obj.symbols[symbol_index];
|
||||
let section_index = symbol
|
||||
.section
|
||||
.ok_or_else(|| anyhow!("Symbol '{}' missing section", symbol.name))?;
|
||||
let address = symbol.address as u32;
|
||||
apply_signature(obj, section_index, address, &signature)?;
|
||||
}
|
||||
}
|
||||
log::info!("Done!");
|
||||
|
||||
@@ -164,7 +164,7 @@ impl FunctionSlices {
|
||||
function_end: Option<u32>,
|
||||
known_functions: &BTreeSet<u32>,
|
||||
) -> Result<ExecCbResult<bool>> {
|
||||
let ExecCbData { executor, vm, result, section, ins, block_start } = data;
|
||||
let ExecCbData { executor, vm, result, section_index, section, ins, block_start } = data;
|
||||
|
||||
// Track discovered prologue(s) and epilogue(s)
|
||||
self.check_prologue(section, ins)
|
||||
@@ -187,7 +187,7 @@ impl FunctionSlices {
|
||||
StepResult::Continue | StepResult::LoadStore { .. } => {
|
||||
let next_address = ins.addr + 4;
|
||||
// If we already visited the next address, connect the blocks and end
|
||||
if executor.visited(section, next_address) {
|
||||
if executor.visited(section_index, section.address as u32, next_address) {
|
||||
self.blocks.insert(block_start, next_address);
|
||||
self.branches.insert(ins.addr, vec![next_address]);
|
||||
Ok(ExecCbResult::EndBlock)
|
||||
@@ -233,7 +233,7 @@ impl FunctionSlices {
|
||||
if self.add_block_start(addr) {
|
||||
return Ok(ExecCbResult::Jump(addr));
|
||||
}
|
||||
} else if matches!(obj.section_data(ins.addr, ins.addr + 4), Ok((_, data)) if data == [0u8; 4])
|
||||
} else if matches!(section.data_range(ins.addr, ins.addr + 4), Ok(data) if data == [0u8; 4])
|
||||
{
|
||||
// If this branch has zeroed padding after it, assume tail call.
|
||||
self.function_references.insert(addr);
|
||||
@@ -385,8 +385,10 @@ impl FunctionSlices {
|
||||
}
|
||||
|
||||
let end = self.end();
|
||||
match (obj.section_at(end), obj.section_at(end - 4)) {
|
||||
(Ok(section), Ok(other_section)) if section.index == other_section.index => {
|
||||
match (obj.sections.at_address(end), obj.sections.at_address(end - 4)) {
|
||||
(Ok((section_index, section)), Ok((other_section_index, _other_section)))
|
||||
if section_index == other_section_index =>
|
||||
{
|
||||
// FIXME this is real bad
|
||||
if !self.has_conditional_blr {
|
||||
if let Some(ins) = disassemble(section, end - 4) {
|
||||
@@ -453,15 +455,15 @@ impl FunctionSlices {
|
||||
return TailCallResult::Is;
|
||||
}
|
||||
// If the jump target is in a different section, known tail call.
|
||||
let section = match obj.section_at(function_start) {
|
||||
let (_, target_section) = match obj.sections.at_address(addr) {
|
||||
Ok(section) => section,
|
||||
Err(e) => return TailCallResult::Error(e),
|
||||
};
|
||||
if !section.contains(addr) {
|
||||
if !target_section.contains(function_start) {
|
||||
return TailCallResult::Is;
|
||||
}
|
||||
// If the jump target has 0'd padding before it, known tail call.
|
||||
if matches!(obj.section_data(addr - 4, addr), Ok((_, data)) if data == [0u8; 4]) {
|
||||
if matches!(target_section.data_range(addr - 4, addr), Ok(data) if data == [0u8; 4]) {
|
||||
return TailCallResult::Is;
|
||||
}
|
||||
// If we're not sure where the function ends yet, mark as possible tail call.
|
||||
|
||||
@@ -73,8 +73,8 @@ impl Tracker {
|
||||
// Stack ends after all BSS sections
|
||||
obj.sections
|
||||
.iter()
|
||||
.rfind(|s| s.kind == ObjSectionKind::Bss)
|
||||
.map(|s| (s.address + s.size) as u32)
|
||||
.rfind(|&(_, s)| s.kind == ObjSectionKind::Bss)
|
||||
.map(|(_, s)| (s.address + s.size) as u32)
|
||||
}),
|
||||
db_stack_addr: obj.db_stack_addr,
|
||||
arena_lo: obj
|
||||
@@ -92,21 +92,23 @@ impl Tracker {
|
||||
pub fn process(&mut self, obj: &ObjInfo) -> Result<()> {
|
||||
log::debug!("Processing code sections");
|
||||
self.process_code(obj)?;
|
||||
for section in &obj.sections {
|
||||
if matches!(section.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData) {
|
||||
log::debug!("Processing section {}, address {:#X}", section.index, section.address);
|
||||
self.process_data(obj, section)?;
|
||||
}
|
||||
for (section_index, section) in obj
|
||||
.sections
|
||||
.iter()
|
||||
.filter(|(_, s)| matches!(s.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData))
|
||||
{
|
||||
log::debug!("Processing section {}, address {:#X}", section_index, section.address);
|
||||
self.process_data(obj, section)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_code(&mut self, obj: &ObjInfo) -> Result<()> {
|
||||
self.process_function_by_address(obj, obj.entry as u32)?;
|
||||
for section in obj.sections.iter().filter(|s| s.kind == ObjSectionKind::Code) {
|
||||
for (section_index, _) in obj.sections.by_kind(ObjSectionKind::Code) {
|
||||
for (_, symbol) in obj
|
||||
.symbols
|
||||
.for_range(section.address as u32..(section.address + section.size) as u32)
|
||||
.for_section(section_index)
|
||||
.filter(|(_, symbol)| symbol.kind == ObjSymbolKind::Function && symbol.size_known)
|
||||
{
|
||||
let addr = symbol.address as u32;
|
||||
@@ -124,9 +126,10 @@ impl Tracker {
|
||||
return Ok(());
|
||||
}
|
||||
self.processed_functions.insert(addr);
|
||||
let (section_index, _) = obj.sections.at_address(addr)?;
|
||||
if let Some((_, symbol)) = obj
|
||||
.symbols
|
||||
.at_address(addr)
|
||||
.at_section_address(section_index, addr)
|
||||
.find(|(_, symbol)| symbol.kind == ObjSymbolKind::Function && symbol.size_known)
|
||||
{
|
||||
self.process_function(obj, symbol)?;
|
||||
@@ -144,7 +147,8 @@ impl Tracker {
|
||||
function_end: u32,
|
||||
possible_missed_branches: &mut BTreeMap<u32, Box<VM>>,
|
||||
) -> Result<ExecCbResult<()>> {
|
||||
let ExecCbData { executor, vm, result, section: _, ins, block_start: _ } = data;
|
||||
let ExecCbData { executor, vm, result, section_index: _, section: _, ins, block_start: _ } =
|
||||
data;
|
||||
let is_function_addr = |addr: u32| addr >= function_start && addr < function_end;
|
||||
|
||||
match result {
|
||||
@@ -344,11 +348,11 @@ impl Tracker {
|
||||
}
|
||||
let mut added = false;
|
||||
for (addr, vm) in take(&mut possible_missed_branches) {
|
||||
let section = match obj.section_at(addr) {
|
||||
let (section_index, section) = match obj.sections.at_address(addr) {
|
||||
Ok(section) => section,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if !executor.visited(section, addr) {
|
||||
if !executor.visited(section_index, section.address as u32, addr) {
|
||||
executor.push(addr, vm, true);
|
||||
added = true;
|
||||
}
|
||||
@@ -397,7 +401,7 @@ impl Tracker {
|
||||
// if addr > 0x80000000 && addr < 0x80003100 {
|
||||
// return true;
|
||||
// }
|
||||
if let Ok(section) = obj.section_at(addr) {
|
||||
if let Ok((_, section)) = obj.sections.at_address(addr) {
|
||||
// References to code sections will never be unaligned
|
||||
return section.kind != ObjSectionKind::Code || addr & 3 == 0;
|
||||
}
|
||||
@@ -450,7 +454,7 @@ impl Tracker {
|
||||
section.name = new_name;
|
||||
}
|
||||
|
||||
for section in &mut obj.sections {
|
||||
for (_, section) in obj.sections.iter_mut() {
|
||||
if !section.section_known {
|
||||
if section.kind == ObjSectionKind::Code {
|
||||
apply_section_name(section, ".text");
|
||||
@@ -485,7 +489,7 @@ impl Tracker {
|
||||
}
|
||||
|
||||
let mut relocation_maps = Vec::new();
|
||||
for section in &obj.sections {
|
||||
for (_, section) in obj.sections.iter() {
|
||||
relocation_maps.push(section.build_relocation_map()?);
|
||||
}
|
||||
|
||||
@@ -516,7 +520,7 @@ impl Tracker {
|
||||
if let Some(symbol) = self.special_symbol(obj, target, reloc_kind) {
|
||||
(symbol, 0)
|
||||
} else {
|
||||
let target_section = match obj.sections.iter().find(|s| {
|
||||
let (target_section_index, _) = match obj.sections.iter().find(|&(_, s)| {
|
||||
target >= s.address as u32 && target < (s.address + s.size) as u32
|
||||
}) {
|
||||
Some(v) => v,
|
||||
@@ -541,7 +545,7 @@ impl Tracker {
|
||||
name: format!("lbl_{:08X}", target),
|
||||
demangled_name: None,
|
||||
address: target as u64,
|
||||
section: Some(target_section.index),
|
||||
section: Some(target_section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
@@ -552,31 +556,34 @@ impl Tracker {
|
||||
(symbol_idx, 0)
|
||||
}
|
||||
};
|
||||
let reloc = ObjReloc { kind: reloc_kind, address: addr as u64, target_symbol, addend };
|
||||
let section = match obj
|
||||
.sections
|
||||
.iter_mut()
|
||||
.find(|s| addr >= s.address as u32 && addr < (s.address + s.size) as u32)
|
||||
{
|
||||
Some(v) => v,
|
||||
None => bail!(
|
||||
"Failed to locate source section for relocation @ {:#010X} {:#010X?}",
|
||||
addr,
|
||||
reloc
|
||||
),
|
||||
let reloc = ObjReloc {
|
||||
kind: reloc_kind,
|
||||
address: addr as u64,
|
||||
target_symbol,
|
||||
addend,
|
||||
module: None,
|
||||
};
|
||||
let (section_index, section) =
|
||||
match obj.sections.iter_mut().find(|(_, s)| s.contains(addr)) {
|
||||
Some(v) => v,
|
||||
None => bail!(
|
||||
"Failed to locate source section for relocation @ {:#010X} {:#010X?}",
|
||||
addr,
|
||||
reloc
|
||||
),
|
||||
};
|
||||
|
||||
let reloc_map = &mut relocation_maps[section.index];
|
||||
let reloc_map = &mut relocation_maps[section_index];
|
||||
match reloc_map.entry(addr) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(section.relocations.len());
|
||||
section.relocations.push(reloc);
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
let reloc_symbol = obj.symbols.at(reloc.target_symbol);
|
||||
let reloc_symbol = &obj.symbols[reloc.target_symbol];
|
||||
if reloc_symbol.name != "_unresolved" {
|
||||
let v = &mut section.relocations[*e.get()];
|
||||
let iter_symbol = obj.symbols.at(v.target_symbol);
|
||||
let iter_symbol = &obj.symbols[v.target_symbol];
|
||||
if iter_symbol.address as i64 + v.addend
|
||||
!= reloc_symbol.address as i64 + reloc.addend
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user