Compare commits

...

5 Commits

Author SHA1 Message Date
Luke Street a156c3697f Appease clippy 2024-04-03 00:18:16 -06:00
Luke Street 3497d38ea3 Version 0.7.6 2024-04-03 00:13:42 -06:00
Luke Street d0f39f1d82 Support global labels in REL creation (_savegpr, etc) 2024-04-03 00:13:15 -06:00
Luke Street ccfbfd1a5a Fix for jumptable naming in RELs 2024-04-03 00:12:46 -06:00
Luke Street e9a9ed0453 Fixes for switch analysis
- When finalizing a block, restart analysis at
  the first block
- Check for default case in jump table entries
2024-04-03 00:11:58 -06:00
9 changed files with 30 additions and 14 deletions

2
Cargo.lock generated
View File

@ -269,7 +269,7 @@ checksum = "c2e06f9bce634a3c898eb1e5cb949ff63133cbb218af93cc9b38b31d6f3ea285"
[[package]] [[package]]
name = "decomp-toolkit" name = "decomp-toolkit"
version = "0.7.5" version = "0.7.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ar", "ar",

View File

@ -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.7.5" version = "0.7.6"
edition = "2021" edition = "2021"
publish = false publish = false
repository = "https://github.com/encounter/decomp-toolkit" repository = "https://github.com/encounter/decomp-toolkit"

View File

@ -248,8 +248,12 @@ impl AnalyzerState {
} }
if self.functions.iter().any(|(_, i)| i.is_unfinalized()) { if self.functions.iter().any(|(_, i)| i.is_unfinalized()) {
log::error!("Failed to finalize functions:"); log::error!("Failed to finalize functions:");
for (addr, _) in self.functions.iter().filter(|(_, i)| i.is_unfinalized()) { for (addr, info) in self.functions.iter().filter(|(_, i)| i.is_unfinalized()) {
log::error!(" {:#010X}", addr); log::error!(
" {:#010X}: blocks [{:?}]",
addr,
info.slices.as_ref().unwrap().possible_blocks.keys()
);
} }
bail!("Failed to finalize functions"); bail!("Failed to finalize functions");
} }
@ -298,11 +302,15 @@ impl AnalyzerState {
&self.functions, &self.functions,
Some(vm), Some(vm),
)?; )?;
// Start at the beginning of the function again
current = SectionAddress::new(addr.section, 0);
} }
TailCallResult::Is => { TailCallResult::Is => {
log::trace!("Finalized tail call @ {:#010X}", block); log::trace!("Finalized tail call @ {:#010X}", block);
slices.possible_blocks.remove(&block); slices.possible_blocks.remove(&block);
slices.function_references.insert(block); slices.function_references.insert(block);
// Start at the beginning of the function again
current = SectionAddress::new(addr.section, 0);
} }
TailCallResult::Possible => { TailCallResult::Possible => {
if finalize { if finalize {

View File

@ -328,7 +328,7 @@ impl FunctionSlices {
function_end.or_else(|| self.end()), function_end.or_else(|| self.end()),
)?; )?;
log::debug!("-> size {}: {:?}", size, entries); log::debug!("-> size {}: {:?}", size, entries);
if entries.contains(&next_address) if (entries.contains(&next_address) || self.blocks.contains_key(&next_address))
&& !entries.iter().any(|&addr| { && !entries.iter().any(|&addr| {
self.is_known_function(known_functions, addr) self.is_known_function(known_functions, addr)
.is_some_and(|fn_addr| fn_addr != function_start) .is_some_and(|fn_addr| fn_addr != function_start)

View File

@ -295,7 +295,7 @@ fn make(args: MakeArgs) -> Result<()> {
for (module_id, (module, path)) in modules.iter().enumerate() { for (module_id, (module, path)) in modules.iter().enumerate() {
let _span = info_span!("file", path = %path.display()).entered(); let _span = info_span!("file", path = %path.display()).entered();
for symbol in module.symbols() { for symbol in module.symbols() {
if symbol.is_definition() && symbol.scope() == object::SymbolScope::Dynamic { if symbol.scope() == object::SymbolScope::Dynamic {
symbol_map.entry(symbol.name_bytes()?).or_insert((module_id, symbol.index())); symbol_map.entry(symbol.name_bytes()?).or_insert((module_id, symbol.index()));
} }
} }

View File

@ -13,7 +13,11 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::{ use crate::{
analysis::cfa::SectionAddress, analysis::cfa::SectionAddress,
obj::{ObjKind, ObjRelocKind}, obj::{ObjKind, ObjRelocKind},
util::{config::is_auto_symbol, nested::NestedVec, split::is_linker_generated_label}, util::{
config::{is_auto_jump_table, is_auto_label, is_auto_symbol},
nested::NestedVec,
split::is_linker_generated_label,
},
}; };
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default)] #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default)]
@ -242,7 +246,11 @@ impl ObjSymbols {
bail!("ABS symbol in relocatable object: {:?}", in_symbol); bail!("ABS symbol in relocatable object: {:?}", in_symbol);
}; };
let target_symbol_idx = if let Some((symbol_idx, existing)) = opt { let target_symbol_idx = if let Some((symbol_idx, existing)) = opt {
let replace = replace || (is_auto_symbol(existing) && !is_auto_symbol(&in_symbol)); let replace = replace
// Replace auto symbols with known symbols
|| (is_auto_symbol(existing) && !is_auto_symbol(&in_symbol))
// Replace lbl_ with jumptable_
|| (is_auto_label(existing) && is_auto_jump_table(&in_symbol));
let size = let size =
if existing.size_known && in_symbol.size_known && existing.size != in_symbol.size { if existing.size_known && in_symbol.size_known && existing.size != in_symbol.size {
// TODO fix this and restore to warning // TODO fix this and restore to warning

View File

@ -182,6 +182,10 @@ pub fn is_auto_symbol(symbol: &ObjSymbol) -> bool {
|| symbol.name.starts_with("pad_") || symbol.name.starts_with("pad_")
} }
pub fn is_auto_label(symbol: &ObjSymbol) -> bool { symbol.name.starts_with("lbl_") }
pub fn is_auto_jump_table(symbol: &ObjSymbol) -> bool { symbol.name.starts_with("jumptable_") }
fn write_if_unchanged<P, Cb>(path: P, cb: Cb, cached_file: Option<FileReadInfo>) -> Result<()> fn write_if_unchanged<P, Cb>(path: P, cb: Cb, cached_file: Option<FileReadInfo>) -> Result<()>
where where
P: AsRef<Path>, P: AsRef<Path>,

View File

@ -428,7 +428,7 @@ where P: AsRef<Path> {
if path.as_ref().exists() { if path.as_ref().exists() {
set_file_mtime(path, FileTime::now()) set_file_mtime(path, FileTime::now())
} else { } else {
match OpenOptions::new().create(true).write(true).open(path) { match OpenOptions::new().create(true).truncate(true).write(true).open(path) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(e), Err(e) => Err(e),
} }

View File

@ -391,11 +391,7 @@ impl<'parent> Iterator for Nodes<'parent> {
type Item = Node; type Item = Node;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let Some(state) = self.stack.pop() else { match self.stack.pop()? {
return None;
};
match state {
NodeState::Begin(name) => { NodeState::Begin(name) => {
self.stack.push(NodeState::File(name.clone(), 0)); self.stack.push(NodeState::File(name.clone(), 0));
Some(Node::DirectoryBegin { name }) Some(Node::DirectoryBegin { name })