Validate splits don't overlap symbols (or each other)
Use DoubleEndedIterator::next_back instead of Iterator::last to avoid unnecessary iteration.
This commit is contained in:
parent
d272b5dce8
commit
2c2ee8bf08
|
@ -214,7 +214,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "decomp-toolkit"
|
name = "decomp-toolkit"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ar",
|
"ar",
|
||||||
|
|
|
@ -3,7 +3,7 @@ name = "decomp-toolkit"
|
||||||
description = "Yet another GameCube/Wii decompilation toolkit."
|
description = "Yet another GameCube/Wii decompilation toolkit."
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
|
@ -80,7 +80,7 @@ impl FunctionSlices {
|
||||||
|
|
||||||
pub fn add_block_start(&mut self, addr: u32) -> bool {
|
pub fn add_block_start(&mut self, addr: u32) -> bool {
|
||||||
// Slice previous block.
|
// Slice previous block.
|
||||||
if let Some((_, end)) = self.blocks.range_mut(..addr).last() {
|
if let Some((_, end)) = self.blocks.range_mut(..addr).next_back() {
|
||||||
let last_end = *end;
|
let last_end = *end;
|
||||||
if last_end > addr {
|
if last_end > addr {
|
||||||
*end = addr;
|
*end = addr;
|
||||||
|
|
|
@ -376,7 +376,7 @@ impl Tracker {
|
||||||
if self.ignore_addresses.contains(&addr) {
|
if self.ignore_addresses.contains(&addr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let Some((&start, &end)) = obj.blocked_ranges.range(..=from).last() {
|
if let Some((&start, &end)) = obj.blocked_ranges.range(..=from).next_back() {
|
||||||
if from >= start && from < end {
|
if from >= start && from < end {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,7 +509,7 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !real_functions.contains_key(&start) {
|
if !real_functions.contains_key(&start) {
|
||||||
let (real_addr, real_name) = real_functions.range(..start).last().unwrap();
|
let (real_addr, real_name) = real_functions.range(..start).next_back().unwrap();
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Function {:#010X} not real (actually a part of {} @ {:#010X})",
|
"Function {:#010X} not real (actually a part of {} @ {:#010X})",
|
||||||
start,
|
start,
|
||||||
|
|
|
@ -478,7 +478,10 @@ impl ObjSymbols {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn by_kind(&self, kind: ObjSymbolKind) -> impl Iterator<Item = (SymbolIndex, &ObjSymbol)> {
|
pub fn by_kind(
|
||||||
|
&self,
|
||||||
|
kind: ObjSymbolKind,
|
||||||
|
) -> impl DoubleEndedIterator<Item = (SymbolIndex, &ObjSymbol)> {
|
||||||
self.symbols.iter().enumerate().filter(move |(_, sym)| sym.kind == kind)
|
self.symbols.iter().enumerate().filter(move |(_, sym)| sym.kind == kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,15 +664,20 @@ impl ObjInfo {
|
||||||
|
|
||||||
/// Locate an existing split for the given address.
|
/// Locate an existing split for the given address.
|
||||||
pub fn split_for(&self, address: u32) -> Option<(u32, &ObjSplit)> {
|
pub fn split_for(&self, address: u32) -> Option<(u32, &ObjSplit)> {
|
||||||
match self.splits_for_range(..=address).last() {
|
match self.splits_for_range(..=address).next_back() {
|
||||||
Some((addr, split)) if split.end == 0 || split.end > address => Some((addr, split)),
|
Some((addr, split)) if split.end == 0 || split.end > address => Some((addr, split)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locate existing splits within the given address range.
|
/// Locate existing splits within the given address range.
|
||||||
pub fn splits_for_range<R>(&self, range: R) -> impl Iterator<Item = (u32, &ObjSplit)>
|
pub fn splits_for_range<R>(
|
||||||
where R: RangeBounds<u32> {
|
&self,
|
||||||
|
range: R,
|
||||||
|
) -> impl DoubleEndedIterator<Item = (u32, &ObjSplit)>
|
||||||
|
where
|
||||||
|
R: RangeBounds<u32>,
|
||||||
|
{
|
||||||
self.splits.range(range).flat_map(|(addr, v)| v.iter().map(move |u| (*addr, u)))
|
self.splits.range(range).flat_map(|(addr, v)| v.iter().map(move |u| (*addr, u)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -386,6 +386,67 @@ fn update_common_splits(obj: &mut ObjInfo) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Final validation of splits.
|
||||||
|
fn validate_splits(obj: &ObjInfo) -> Result<()> {
|
||||||
|
let mut last_split_end = 0;
|
||||||
|
for (addr, split) in obj.splits_for_range(..) {
|
||||||
|
let section = obj.section_at(addr)?;
|
||||||
|
ensure!(
|
||||||
|
addr >= last_split_end,
|
||||||
|
"Split {} {} {:#010X}..{:#010X} overlaps with previous split",
|
||||||
|
split.unit,
|
||||||
|
section.name,
|
||||||
|
addr,
|
||||||
|
split.end
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
split.end > 0 && split.end > addr,
|
||||||
|
"Invalid split end {} {} {:#010X}..{:#010X}",
|
||||||
|
split.unit,
|
||||||
|
section.name,
|
||||||
|
addr,
|
||||||
|
split.end
|
||||||
|
);
|
||||||
|
last_split_end = split.end;
|
||||||
|
|
||||||
|
if let Some((_, symbol)) =
|
||||||
|
obj.symbols.for_range(..addr).filter(|&(_, s)| s.size_known && s.size > 0).next_back()
|
||||||
|
{
|
||||||
|
ensure!(
|
||||||
|
addr >= symbol.address as u32 + symbol.size as u32,
|
||||||
|
"Split {} {} {:#010X}..{:#010X} overlaps symbol '{}' {:#010X}..{:#010X}",
|
||||||
|
split.unit,
|
||||||
|
section.name,
|
||||||
|
addr,
|
||||||
|
split.end,
|
||||||
|
symbol.name,
|
||||||
|
symbol.address,
|
||||||
|
symbol.address + symbol.size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, symbol)) = obj
|
||||||
|
.symbols
|
||||||
|
.for_range(..split.end)
|
||||||
|
.filter(|&(_, s)| s.size_known && s.size > 0)
|
||||||
|
.next_back()
|
||||||
|
{
|
||||||
|
ensure!(
|
||||||
|
split.end >= symbol.address as u32 + symbol.size as u32,
|
||||||
|
"Split {} {} ({:#010X}..{:#010X}) ends within symbol '{}' ({:#010X}..{:#010X})",
|
||||||
|
split.unit,
|
||||||
|
section.name,
|
||||||
|
addr,
|
||||||
|
split.end,
|
||||||
|
symbol.name,
|
||||||
|
symbol.address,
|
||||||
|
symbol.address + symbol.size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform any necessary adjustments to allow relinking.
|
/// Perform any necessary adjustments to allow relinking.
|
||||||
/// This includes:
|
/// This includes:
|
||||||
/// - Ensuring .ctors & .dtors entries are split with their associated function
|
/// - Ensuring .ctors & .dtors entries are split with their associated function
|
||||||
|
@ -418,6 +479,9 @@ pub fn update_splits(obj: &mut ObjInfo) -> Result<()> {
|
||||||
// Update common BSS splits
|
// Update common BSS splits
|
||||||
update_common_splits(obj)?;
|
update_common_splits(obj)?;
|
||||||
|
|
||||||
|
// Ensure splits don't overlap symbols or each other
|
||||||
|
validate_splits(obj)?;
|
||||||
|
|
||||||
// Resolve link order
|
// Resolve link order
|
||||||
obj.link_order = resolve_link_order(obj)?;
|
obj.link_order = resolve_link_order(obj)?;
|
||||||
|
|
||||||
|
@ -908,7 +972,7 @@ pub fn end_for_section(obj: &ObjInfo, section_index: usize) -> Result<u32> {
|
||||||
.symbols
|
.symbols
|
||||||
.for_range(section_start..section_end)
|
.for_range(section_start..section_end)
|
||||||
.filter(|(_, s)| s.kind == ObjSymbolKind::Object && s.size_known && s.size > 0)
|
.filter(|(_, s)| s.kind == ObjSymbolKind::Object && s.size_known && s.size > 0)
|
||||||
.last();
|
.next_back();
|
||||||
match last_symbol {
|
match last_symbol {
|
||||||
Some((_, symbol)) if is_linker_generated_object(&symbol.name) => {
|
Some((_, symbol)) if is_linker_generated_object(&symbol.name) => {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
|
|
Loading…
Reference in New Issue