mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-15 16:16:20 +00:00
A lot more section-address-aware refactoring
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
|
||||
use crate::{
|
||||
analysis::{cfa::AnalyzerState, read_u32},
|
||||
analysis::{
|
||||
cfa::{AnalyzerState, SectionAddress},
|
||||
read_address,
|
||||
},
|
||||
obj::{
|
||||
ObjInfo, ObjSectionKind, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
|
||||
ObjSymbolKind,
|
||||
@@ -189,189 +192,230 @@ const SIGNATURES: &[(&str, &str)] = &[
|
||||
];
|
||||
const POST_SIGNATURES: &[(&str, &str)] = &[
|
||||
("RSOStaticLocateObject", include_str!("../../assets/signatures/RSOStaticLocateObject.yml")),
|
||||
// ("GXInit", include_str!("../../assets/signatures/GXInit.yml")),
|
||||
("GXInit", include_str!("../../assets/signatures/GXInit.yml")),
|
||||
("__register_fragment", include_str!("../../assets/signatures/__register_fragment.yml")),
|
||||
("__unregister_fragment", include_str!("../../assets/signatures/__unregister_fragment.yml")),
|
||||
("__register_atexit", include_str!("../../assets/signatures/__register_atexit.yml")),
|
||||
(
|
||||
"__register_global_object",
|
||||
include_str!("../../assets/signatures/__register_global_object.yml"),
|
||||
),
|
||||
];
|
||||
|
||||
fn apply_signature_for_symbol(obj: &mut ObjInfo, name: &str, sig_str: &str) -> Result<()> {
|
||||
let Some((_, symbol)) = obj.symbols.by_name(name)? else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(section_index) = symbol.section else {
|
||||
return Ok(());
|
||||
};
|
||||
let addr = symbol.address as u32;
|
||||
let section = &obj.sections[section_index];
|
||||
if let Some(signature) = check_signatures_str(section, addr, sig_str)? {
|
||||
apply_signature(obj, SectionAddress::new(section_index, addr), &signature)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_ctors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let Some((_, symbol)) = obj.symbols.by_name("_ctors")? else {
|
||||
return Ok(());
|
||||
};
|
||||
// First entry of ctors is __init_cpp_exceptions
|
||||
let ctors_section_index =
|
||||
symbol.section.ok_or_else(|| anyhow!("Missing _ctors symbol section"))?;
|
||||
let ctors_section = &obj.sections[ctors_section_index];
|
||||
// __init_cpp_exceptions_reference + null pointer
|
||||
if ctors_section.size < 8 {
|
||||
return Ok(());
|
||||
}
|
||||
let Some(target) = read_address(obj, ctors_section, symbol.address as u32).ok() else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(signature) = check_signatures_str(
|
||||
&obj.sections[target.section],
|
||||
target.address,
|
||||
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
|
||||
)?
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
let address = symbol.address;
|
||||
apply_signature(obj, target, &signature)?;
|
||||
obj.symbols.add(
|
||||
ObjSymbol {
|
||||
name: "__init_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(ctors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
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,
|
||||
common: false,
|
||||
autogenerated: true,
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let Some((_, symbol)) = obj.symbols.by_name("_dtors")? else {
|
||||
for symbol in obj.symbols.iter() {
|
||||
println!("{:?} {:#010X} {}", symbol.section, symbol.address, symbol.name);
|
||||
}
|
||||
bail!("Missing _dtors symbol");
|
||||
// return Ok(());
|
||||
};
|
||||
let dtors_section_index =
|
||||
symbol.section.ok_or_else(|| anyhow!("Missing _dtors symbol section"))?;
|
||||
let dtors_section = &obj.sections[dtors_section_index];
|
||||
// __destroy_global_chain_reference + null pointer
|
||||
if dtors_section.size < 8 {
|
||||
return Ok(());
|
||||
}
|
||||
let address = symbol.address;
|
||||
let dgc_target = read_address(obj, dtors_section, address as u32).ok();
|
||||
let fce_target = read_address(obj, dtors_section, address as u32 + 4).ok();
|
||||
let mut found_dgc = false;
|
||||
let mut found_fce = false;
|
||||
|
||||
// First entry of dtors is __destroy_global_chain
|
||||
if let Some(dgc_target) = dgc_target {
|
||||
if let Some(signature) = check_signatures_str(
|
||||
&obj.sections[dgc_target.section],
|
||||
dgc_target.address,
|
||||
include_str!("../../assets/signatures/__destroy_global_chain.yml"),
|
||||
)? {
|
||||
apply_signature(obj, dgc_target, &signature)?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__destroy_global_chain_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(
|
||||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||
),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
found_dgc = true;
|
||||
} else {
|
||||
log::warn!("Failed to match __destroy_global_chain signature ({:#010X})", dgc_target);
|
||||
}
|
||||
}
|
||||
|
||||
// Second entry of dtors is __fini_cpp_exceptions
|
||||
if let Some(fce_target) = fce_target {
|
||||
if let Some(signature) = check_signatures_str(
|
||||
&obj.sections[fce_target.section],
|
||||
fce_target.address,
|
||||
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
|
||||
)? {
|
||||
apply_signature(obj, fce_target, &signature)?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__fini_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address: address + 4,
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(
|
||||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||
),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
found_fce = true;
|
||||
}
|
||||
}
|
||||
|
||||
if found_dgc {
|
||||
let mut end = address as u32 + 4;
|
||||
if found_fce {
|
||||
end += 4;
|
||||
}
|
||||
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,
|
||||
common: false,
|
||||
autogenerated: true,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_init_user_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let Some((_, symbol)) = obj.symbols.by_name("__init_user")? else {
|
||||
return Ok(());
|
||||
};
|
||||
let Some(section_index) = symbol.section else {
|
||||
return Ok(());
|
||||
};
|
||||
// __init_user can be overridden, but we can still look for __init_cpp from it
|
||||
let mut analyzer = AnalyzerState::default();
|
||||
analyzer.process_function_at(obj, SectionAddress::new(section_index, symbol.address as u32))?;
|
||||
for addr in analyzer.function_entries {
|
||||
let section = &obj.sections[addr.section];
|
||||
if let Some(signature) = check_signatures_str(
|
||||
section,
|
||||
addr.address,
|
||||
include_str!("../../assets/signatures/__init_cpp.yml"),
|
||||
)? {
|
||||
apply_signature(obj, SectionAddress::new(section_index, addr.address), &signature)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||
let entry = obj.entry as u32;
|
||||
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)?;
|
||||
if let Some(entry) = obj.entry.map(|n| n as u32) {
|
||||
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, SectionAddress::new(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;
|
||||
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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, symbol)) = obj.symbols.by_name("__init_user")? {
|
||||
// __init_user can be overridden, but we can still look for __init_cpp from it
|
||||
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(
|
||||
section,
|
||||
addr,
|
||||
include_str!("../../assets/signatures/__init_cpp.yml"),
|
||||
)? {
|
||||
apply_signature(obj, section_index, addr, &signature)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, symbol)) = obj.symbols.by_name("_ctors")? {
|
||||
// First entry of ctors is __init_cpp_exceptions
|
||||
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(
|
||||
target_section,
|
||||
target,
|
||||
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
|
||||
)? {
|
||||
let address = symbol.address;
|
||||
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(ctors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
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,
|
||||
common: false,
|
||||
autogenerated: true,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((_, symbol)) = obj.symbols.by_name("_dtors")? {
|
||||
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 = dtors_section.address;
|
||||
// First entry of dtors is __destroy_global_chain
|
||||
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(&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(
|
||||
target_section,
|
||||
dgc_target,
|
||||
include_str!("../../assets/signatures/__destroy_global_chain.yml"),
|
||||
)? {
|
||||
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(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
found_dgc = true;
|
||||
} else {
|
||||
log::warn!(
|
||||
"Failed to match __destroy_global_chain signature ({:#010X})",
|
||||
dgc_target
|
||||
);
|
||||
}
|
||||
}
|
||||
// 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(
|
||||
target_section,
|
||||
fce_target,
|
||||
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
|
||||
)? {
|
||||
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(dtors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
found_fce = true;
|
||||
}
|
||||
}
|
||||
|
||||
if found_dgc {
|
||||
let mut end = address as u32 + 4;
|
||||
if found_fce {
|
||||
end += 4;
|
||||
}
|
||||
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,
|
||||
common: false,
|
||||
autogenerated: true,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
apply_signature_for_symbol(obj, name, sig_str)?
|
||||
}
|
||||
|
||||
apply_init_user_signatures(obj)?;
|
||||
apply_ctors_signatures(obj)?;
|
||||
apply_dtors_signatures(obj)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_signatures_post(obj: &mut ObjInfo) -> Result<()> {
|
||||
log::info!("Checking post CFA signatures...");
|
||||
log::debug!("Checking post CFA signatures");
|
||||
for &(_name, sig_str) in POST_SIGNATURES {
|
||||
let signatures = parse_signatures(sig_str)?;
|
||||
let mut found_signature = None;
|
||||
@@ -391,13 +435,10 @@ pub fn apply_signatures_post(obj: &mut ObjInfo) -> Result<()> {
|
||||
}
|
||||
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)?;
|
||||
let symbol_addr = SectionAddress::new(symbol.section.unwrap(), symbol.address as u32);
|
||||
apply_signature(obj, symbol_addr, &signature)?;
|
||||
}
|
||||
}
|
||||
log::info!("Done!");
|
||||
log::debug!("Done!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user