mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-14 15:46:18 +00:00
A lot more section-address-aware refactoring
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, ensure, Result};
|
||||
use flagset::FlagSet;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
analysis::cfa::AnalyzerState,
|
||||
obj::{ObjInfo, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind},
|
||||
analysis::cfa::{AnalyzerState, SectionAddress},
|
||||
obj::{
|
||||
ObjInfo, ObjKind, ObjRelocKind, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||
ObjSymbolFlags, ObjSymbolKind,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait AnalysisPass {
|
||||
@@ -20,9 +24,9 @@ pub const TRK_TABLE_SIZE: u32 = 0x1F34; // always?
|
||||
// TRK_MINNOW_DOLPHIN.a __exception.s
|
||||
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_index, section) = obj.sections.at_address(start)?;
|
||||
let data = match section.data_range(start, 0) {
|
||||
for (&start, _) in state.function_bounds.iter().filter(|&(_, &end)| end.is_none()) {
|
||||
let section = &obj.sections[start.section];
|
||||
let data = match section.data_range(start.address, 0) {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => continue,
|
||||
};
|
||||
@@ -33,8 +37,8 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||
state.known_symbols.insert(start, ObjSymbol {
|
||||
name: "gTRKInterruptVectorTable".to_string(),
|
||||
demangled_name: None,
|
||||
address: start as u64,
|
||||
section: Some(section_index),
|
||||
address: start.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
@@ -46,8 +50,8 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||
state.known_symbols.insert(end, ObjSymbol {
|
||||
name: "gTRKInterruptVectorTableEnd".to_string(),
|
||||
demangled_name: None,
|
||||
address: end as u64,
|
||||
section: Some(section_index),
|
||||
address: end.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
@@ -77,10 +81,10 @@ const SLEDS: [([u8; 4], &str, &str); 4] = [
|
||||
impl AnalysisPass for FindSaveRestSleds {
|
||||
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
||||
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_index, section) = obj.sections.at_address(start)?;
|
||||
let data = match section.data_range(start, 0) {
|
||||
let mut clear_ranges: Vec<Range<SectionAddress>> = vec![];
|
||||
for (&start, _) in state.function_bounds.iter().filter(|&(_, &end)| end.is_some()) {
|
||||
let section = &obj.sections[start.section];
|
||||
let data = match section.data_range(start.address, 0) {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => continue,
|
||||
};
|
||||
@@ -91,8 +95,8 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
state.known_symbols.insert(start, ObjSymbol {
|
||||
name: func.to_string(),
|
||||
demangled_name: None,
|
||||
address: start as u64,
|
||||
section: Some(section_index),
|
||||
address: start.address as u64,
|
||||
section: Some(start.section),
|
||||
size: SLED_SIZE as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -105,8 +109,8 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
state.known_symbols.insert(addr, ObjSymbol {
|
||||
name: format!("{}{}", label, i),
|
||||
demangled_name: None,
|
||||
address: addr as u64,
|
||||
section: Some(section_index),
|
||||
address: addr.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
@@ -119,12 +123,163 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||
}
|
||||
}
|
||||
for range in clear_ranges {
|
||||
for addr in range.step_by(4) {
|
||||
let mut addr = range.start;
|
||||
while addr < range.end {
|
||||
state.function_entries.remove(&addr);
|
||||
state.function_bounds.remove(&addr);
|
||||
state.function_slices.remove(&addr);
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FindRelCtorsDtors {}
|
||||
|
||||
impl AnalysisPass for FindRelCtorsDtors {
|
||||
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
||||
ensure!(obj.kind == ObjKind::Relocatable);
|
||||
ensure!(!obj.unresolved_relocations.is_empty());
|
||||
|
||||
match (obj.sections.by_name(".ctors")?, obj.sections.by_name(".dtors")?) {
|
||||
(Some(_), Some(_)) => return Ok(()),
|
||||
(None, None) => {}
|
||||
_ => bail!("Only one of .ctors and .dtors has been found?"),
|
||||
}
|
||||
|
||||
let possible_sections = obj
|
||||
.sections
|
||||
.iter()
|
||||
.filter(|&(_, section)| {
|
||||
if section.section_known
|
||||
|| !matches!(section.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData)
|
||||
|| section.size < 4
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut current_address = section.address as u32;
|
||||
let section_end = current_address + section.size as u32;
|
||||
// Check that each word has a relocation to a function
|
||||
// And the section ends with a null pointer
|
||||
while let Some(reloc) = obj.unresolved_relocations.iter().find(|reloc| {
|
||||
reloc.module_id == obj.module_id
|
||||
&& reloc.section == section.elf_index as u8
|
||||
&& reloc.address == current_address
|
||||
&& reloc.kind == ObjRelocKind::Absolute
|
||||
}) {
|
||||
let Some((target_section_index, target_section)) = obj
|
||||
.sections
|
||||
.iter()
|
||||
.find(|(_, section)| section.elf_index == reloc.target_section as usize)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if target_section.kind != ObjSectionKind::Code
|
||||
|| !state
|
||||
.function_bounds
|
||||
.contains_key(&SectionAddress::new(target_section_index, reloc.addend))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
current_address += 4;
|
||||
if current_address >= section_end {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if current_address + 4 != section_end {
|
||||
return false;
|
||||
}
|
||||
section.data_range(section_end - 4, section_end).ok() == Some(&[0; 4])
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
if possible_sections.len() != 2 {
|
||||
log::warn!("Failed to find .ctors and .dtors");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
log::debug!("Found .ctors and .dtors: {:?}", possible_sections);
|
||||
let ctors_section_index = possible_sections[0].0;
|
||||
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
||||
state.known_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
|
||||
name: "_ctors".to_string(),
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
section: Some(ctors_section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
});
|
||||
|
||||
let dtors_section_index = possible_sections[1].0;
|
||||
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
||||
state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
||||
name: "_dtors".to_string(),
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
section: Some(dtors_section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
});
|
||||
|
||||
// Check for duplicate entries in .dtors, indicating __destroy_global_chain_reference
|
||||
// let mut dtors_entries = vec![];
|
||||
// let mut current_address = obj.sections[dtors_section_index].address as u32;
|
||||
// let section_end = current_address + obj.sections[dtors_section_index].size as u32;
|
||||
// while let Some(reloc) = obj.unresolved_relocations.iter().find(|reloc| {
|
||||
// reloc.module_id == obj.module_id
|
||||
// && reloc.section == obj.sections[dtors_section_index].elf_index as u8
|
||||
// && reloc.address == current_address
|
||||
// && reloc.kind == ObjRelocKind::Absolute
|
||||
// }) {
|
||||
// let Some((target_section_index, target_section)) = obj
|
||||
// .sections
|
||||
// .iter()
|
||||
// .find(|(_, section)| section.elf_index == reloc.target_section as usize)
|
||||
// else {
|
||||
// bail!("Failed to find target section for .dtors entry");
|
||||
// };
|
||||
// if target_section.kind != ObjSectionKind::Code
|
||||
// || !state
|
||||
// .function_bounds
|
||||
// .contains_key(&SectionAddress::new(target_section_index, reloc.addend))
|
||||
// {
|
||||
// bail!("Failed to find target function for .dtors entry");
|
||||
// }
|
||||
// dtors_entries.push(SectionAddress::new(target_section_index, reloc.addend));
|
||||
// current_address += 4;
|
||||
// if current_address >= section_end {
|
||||
// bail!("Failed to find null terminator for .dtors");
|
||||
// }
|
||||
// }
|
||||
// if current_address + 4 != section_end {
|
||||
// bail!("Failed to find null terminator for .dtors");
|
||||
// }
|
||||
// if dtors_entries.len() != dtors_entries.iter().unique().count() {
|
||||
// log::debug!("Found __destroy_global_chain_reference");
|
||||
// state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
||||
// name: "__destroy_global_chain_reference".to_string(),
|
||||
// demangled_name: None,
|
||||
// address: 0,
|
||||
// section: Some(dtors_section_index),
|
||||
// size: 4,
|
||||
// size_known: true,
|
||||
// flags: ObjSymbolFlagSet(ObjSymbolFlags::Local.into()),
|
||||
// kind: ObjSymbolKind::Object,
|
||||
// align: None,
|
||||
// data_kind: Default::default(),
|
||||
// });
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user