Begin REL analysis & rework lots of code to be section-address aware

This commit is contained in:
2023-08-17 22:09:45 -04:00
parent 347889773d
commit 5843ee021e
27 changed files with 1813 additions and 1227 deletions

View File

@@ -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);

View File

@@ -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)
}
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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()),

View File

@@ -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(&section.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(&section.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(&section.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!");

View File

@@ -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.

View File

@@ -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
{