decomp-toolkit/src/analysis/signatures.rs
Luke Street dfb569b883 Add alf support (NVIDIA Shield TV binaries)
- Supports .alf files in all places .dol files are accepted.
- Adds `hash` and `dhash` to symbols config.
2023-10-07 02:03:09 -04:00

471 lines
22 KiB
Rust

use anyhow::{anyhow, Result};
use crate::{
analysis::{
cfa::{AnalyzerState, SectionAddress},
read_address,
},
obj::{
ObjInfo, ObjSectionKind, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
ObjSymbolKind,
},
util::signatures::{apply_signature, check_signatures, check_signatures_str, parse_signatures},
};
const SIGNATURES: &[(&str, &str)] = &[
("__init_registers", include_str!("../../assets/signatures/__init_registers.yml")),
("__init_hardware", include_str!("../../assets/signatures/__init_hardware.yml")),
("__init_data", include_str!("../../assets/signatures/__init_data.yml")),
("__set_debug_bba", include_str!("../../assets/signatures/__set_debug_bba.yml")),
("__OSPSInit", include_str!("../../assets/signatures/__OSPSInit.yml")),
("__OSFPRInit", include_str!("../../assets/signatures/__OSFPRInit.yml")),
("__OSCacheInit", include_str!("../../assets/signatures/__OSCacheInit.yml")),
("DMAErrorHandler", include_str!("../../assets/signatures/DMAErrorHandler.yml")),
("DBInit", include_str!("../../assets/signatures/DBInit.yml")),
("OSInit", include_str!("../../assets/signatures/OSInit.yml")),
("__OSThreadInit", include_str!("../../assets/signatures/__OSThreadInit.yml")),
("__OSInitIPCBuffer", include_str!("../../assets/signatures/__OSInitIPCBuffer.yml")),
("EXIInit", include_str!("../../assets/signatures/EXIInit.yml")),
("EXIGetID", include_str!("../../assets/signatures/EXIGetID.yml")),
("exit", include_str!("../../assets/signatures/exit.yml")),
("_ExitProcess", include_str!("../../assets/signatures/_ExitProcess.yml")),
("__fini_cpp", include_str!("../../assets/signatures/__fini_cpp.yml")),
// ("__destroy_global_chain", include_str!("../../assets/signatures/__destroy_global_chain.yml")),
("InitMetroTRK", include_str!("../../assets/signatures/InitMetroTRK.yml")),
("InitMetroTRKCommTable", include_str!("../../assets/signatures/InitMetroTRKCommTable.yml")),
("OSExceptionInit", include_str!("../../assets/signatures/OSExceptionInit.yml")),
(
"OSDefaultExceptionHandler",
include_str!("../../assets/signatures/OSDefaultExceptionHandler.yml"),
),
("__OSUnhandledException", include_str!("../../assets/signatures/__OSUnhandledException.yml")),
("OSDisableScheduler", include_str!("../../assets/signatures/OSDisableScheduler.yml")),
("__OSReschedule", include_str!("../../assets/signatures/__OSReschedule.yml")),
("__OSInitSystemCall", include_str!("../../assets/signatures/__OSInitSystemCall.yml")),
("OSInitAlarm", include_str!("../../assets/signatures/OSInitAlarm.yml")),
("__OSInitAlarm", include_str!("../../assets/signatures/__OSInitAlarm.yml")),
("__OSEVStart", include_str!("../../assets/signatures/OSExceptionVector.yml")),
("__OSDBINTSTART", include_str!("../../assets/signatures/__OSDBIntegrator.yml")),
("__OSDBJUMPSTART", include_str!("../../assets/signatures/__OSDBJump.yml")),
("SIInit", include_str!("../../assets/signatures/SIInit.yml")),
("SIGetType", include_str!("../../assets/signatures/SIGetType.yml")),
("SISetSamplingRate", include_str!("../../assets/signatures/SISetSamplingRate.yml")),
("SISetXY", include_str!("../../assets/signatures/SISetXY.yml")),
("VIGetTvFormat", include_str!("../../assets/signatures/VIGetTvFormat.yml")),
("DVDInit", include_str!("../../assets/signatures/DVDInit.yml")),
(
"DVDSetAutoFatalMessaging",
include_str!("../../assets/signatures/DVDSetAutoFatalMessaging.yml"),
),
("OSSetArenaLo", include_str!("../../assets/signatures/OSSetArenaLo.yml")),
("OSSetArenaHi", include_str!("../../assets/signatures/OSSetArenaHi.yml")),
("OSSetMEM1ArenaLo", include_str!("../../assets/signatures/OSSetMEM1ArenaLo.yml")),
("OSSetMEM1ArenaHi", include_str!("../../assets/signatures/OSSetMEM1ArenaHi.yml")),
("OSSetMEM2ArenaLo", include_str!("../../assets/signatures/OSSetMEM2ArenaLo.yml")),
("OSSetMEM2ArenaHi", include_str!("../../assets/signatures/OSSetMEM2ArenaHi.yml")),
("__OSInitAudioSystem", include_str!("../../assets/signatures/__OSInitAudioSystem.yml")),
(
"__OSInitMemoryProtection",
include_str!("../../assets/signatures/__OSInitMemoryProtection.yml"),
),
// ("BATConfig", include_str!("../../assets/signatures/BATConfig.yml")), TODO
("ReportOSInfo", include_str!("../../assets/signatures/ReportOSInfo.yml")),
("__check_pad3", include_str!("../../assets/signatures/__check_pad3.yml")),
("OSResetSystem", include_str!("../../assets/signatures/OSResetSystem.yml")),
("OSReturnToMenu", include_str!("../../assets/signatures/OSReturnToMenu.yml")),
("__OSReturnToMenu", include_str!("../../assets/signatures/__OSReturnToMenu.yml")),
("__OSShutdownDevices", include_str!("../../assets/signatures/__OSShutdownDevices.yml")),
("__OSInitSram", include_str!("../../assets/signatures/__OSInitSram.yml")),
("__OSSyncSram", include_str!("../../assets/signatures/__OSSyncSram.yml")),
(
"__OSGetExceptionHandler",
include_str!("../../assets/signatures/__OSGetExceptionHandler.yml"),
),
(
"OSRegisterResetFunction",
include_str!("../../assets/signatures/OSRegisterResetFunction.yml"),
),
(
"OSRegisterShutdownFunction",
include_str!("../../assets/signatures/OSRegisterShutdownFunction.yml"),
),
(
"DecrementerExceptionHandler",
include_str!("../../assets/signatures/DecrementerExceptionHandler.yml"),
),
(
"DecrementerExceptionCallback",
include_str!("../../assets/signatures/DecrementerExceptionCallback.yml"),
),
("__OSInterruptInit", include_str!("../../assets/signatures/__OSInterruptInit.yml")),
("__OSContextInit", include_str!("../../assets/signatures/__OSContextInit.yml")),
("OSSwitchFPUContext", include_str!("../../assets/signatures/OSSwitchFPUContext.yml")),
("OSReport", include_str!("../../assets/signatures/OSReport.yml")),
("TRK_main", include_str!("../../assets/signatures/TRK_main.yml")),
("TRKNubWelcome", include_str!("../../assets/signatures/TRKNubWelcome.yml")),
("TRKInitializeNub", include_str!("../../assets/signatures/TRKInitializeNub.yml")),
(
"TRKInitializeIntDrivenUART",
include_str!("../../assets/signatures/TRKInitializeIntDrivenUART.yml"),
),
("TRKEXICallBack", include_str!("../../assets/signatures/TRKEXICallBack.yml")),
("TRKLoadContext", include_str!("../../assets/signatures/TRKLoadContext.yml")),
("TRKInterruptHandler", include_str!("../../assets/signatures/TRKInterruptHandler.yml")),
("TRKExceptionHandler", include_str!("../../assets/signatures/TRKExceptionHandler.yml")),
("TRKSaveExtended1Block", include_str!("../../assets/signatures/TRKSaveExtended1Block.yml")),
("TRKNubMainLoop", include_str!("../../assets/signatures/TRKNubMainLoop.yml")),
("TRKTargetContinue", include_str!("../../assets/signatures/TRKTargetContinue.yml")),
("TRKSwapAndGo", include_str!("../../assets/signatures/TRKSwapAndGo.yml")),
(
"TRKRestoreExtended1Block",
include_str!("../../assets/signatures/TRKRestoreExtended1Block.yml"),
),
(
"TRKInterruptHandlerEnableInterrupts",
include_str!("../../assets/signatures/TRKInterruptHandlerEnableInterrupts.yml"),
),
("memset", include_str!("../../assets/signatures/memset.yml")),
(
"__msl_runtime_constraint_violation_s",
include_str!("../../assets/signatures/__msl_runtime_constraint_violation_s.yml"),
),
("ClearArena", include_str!("../../assets/signatures/ClearArena.yml")),
("IPCCltInit", include_str!("../../assets/signatures/IPCCltInit.yml")),
("__OSInitSTM", include_str!("../../assets/signatures/__OSInitSTM.yml")),
("IOS_Open", include_str!("../../assets/signatures/IOS_Open.yml")),
("__ios_Ipc2", include_str!("../../assets/signatures/__ios_Ipc2.yml")),
("IPCiProfQueueReq", include_str!("../../assets/signatures/IPCiProfQueueReq.yml")),
("SCInit", include_str!("../../assets/signatures/SCInit.yml")),
("SCReloadConfFileAsync", include_str!("../../assets/signatures/SCReloadConfFileAsync.yml")),
("NANDPrivateOpenAsync", include_str!("../../assets/signatures/NANDPrivateOpenAsync.yml")),
("nandIsInitialized", include_str!("../../assets/signatures/nandIsInitialized.yml")),
("nandOpen", include_str!("../../assets/signatures/nandOpen.yml")),
("nandGenerateAbsPath", include_str!("../../assets/signatures/nandGenerateAbsPath.yml")),
("nandGetHeadToken", include_str!("../../assets/signatures/nandGetHeadToken.yml")),
("ISFS_OpenAsync", include_str!("../../assets/signatures/ISFS_OpenAsync.yml")),
("nandConvertErrorCode", include_str!("../../assets/signatures/nandConvertErrorCode.yml")),
(
"NANDLoggingAddMessageAsync",
include_str!("../../assets/signatures/NANDLoggingAddMessageAsync.yml"),
),
(
"__NANDPrintErrorMessage",
include_str!("../../assets/signatures/__NANDPrintErrorMessage.yml"),
),
("__OSInitNet", include_str!("../../assets/signatures/__OSInitNet.yml")),
("__DVDCheckDevice", include_str!("../../assets/signatures/__DVDCheckDevice.yml")),
("__OSInitPlayTime", include_str!("../../assets/signatures/__OSInitPlayTime.yml")),
("__OSStartPlayRecord", include_str!("../../assets/signatures/__OSStartPlayRecord.yml")),
("NANDInit", include_str!("../../assets/signatures/NANDInit.yml")),
("ISFS_OpenLib", include_str!("../../assets/signatures/ISFS_OpenLib.yml")),
("ESP_GetTitleId", include_str!("../../assets/signatures/ESP_GetTitleId.yml")),
(
"NANDSetAutoErrorMessaging",
include_str!("../../assets/signatures/NANDSetAutoErrorMessaging.yml"),
),
("__DVDFSInit", include_str!("../../assets/signatures/__DVDFSInit.yml")),
("__DVDClearWaitingQueue", include_str!("../../assets/signatures/__DVDClearWaitingQueue.yml")),
("__DVDInitWA", include_str!("../../assets/signatures/__DVDInitWA.yml")),
("__DVDLowSetWAType", include_str!("../../assets/signatures/__DVDLowSetWAType.yml")),
("__fstLoad", include_str!("../../assets/signatures/__fstLoad.yml")),
("DVDReset", include_str!("../../assets/signatures/DVDReset.yml")),
("DVDLowReset", include_str!("../../assets/signatures/DVDLowReset.yml")),
("DVDReadDiskID", include_str!("../../assets/signatures/DVDReadDiskID.yml")),
("stateReady", include_str!("../../assets/signatures/stateReady.yml")),
("DVDLowWaitCoverClose", include_str!("../../assets/signatures/DVDLowWaitCoverClose.yml")),
("__DVDStoreErrorCode", include_str!("../../assets/signatures/__DVDStoreErrorCode.yml")),
("DVDLowStopMotor", include_str!("../../assets/signatures/DVDLowStopMotor.yml")),
("DVDGetDriveStatus", include_str!("../../assets/signatures/DVDGetDriveStatus.yml")),
("printf", include_str!("../../assets/signatures/printf.yml")),
("sprintf", include_str!("../../assets/signatures/sprintf.yml")),
("vprintf", include_str!("../../assets/signatures/vprintf.yml")),
("vsprintf", include_str!("../../assets/signatures/vsprintf.yml")),
("vsnprintf", include_str!("../../assets/signatures/vsnprintf.yml")),
("__pformatter", include_str!("../../assets/signatures/__pformatter.yml")),
("longlong2str", include_str!("../../assets/signatures/longlong2str.yml")),
("__mod2u", include_str!("../../assets/signatures/__mod2u.yml")),
("__FileWrite", include_str!("../../assets/signatures/__FileWrite.yml")),
("fwrite", include_str!("../../assets/signatures/fwrite.yml")),
("__fwrite", include_str!("../../assets/signatures/__fwrite.yml")),
("__stdio_atexit", include_str!("../../assets/signatures/__stdio_atexit.yml")),
("__StringWrite", include_str!("../../assets/signatures/__StringWrite.yml")),
];
const POST_SIGNATURES: &[(&str, &str)] = &[
("RSOStaticLocateObject", include_str!("../../assets/signatures/RSOStaticLocateObject.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(),
address,
section: Some(ctors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
kind: ObjSymbolKind::Object,
..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,
skip: false,
rename: None,
})?;
}
Ok(())
}
fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
let (dtors_section_index, dtors_section) =
if let Some((_, symbol)) = obj.symbols.by_name("_dtors")? {
let section_index =
symbol.section.ok_or_else(|| anyhow!("Missing _dtors symbol section"))?;
(section_index, &obj.sections[section_index])
} else if let Some((section_index, section)) = obj.sections.by_name(".dtors")? {
(section_index, section)
} else {
return Ok(());
};
// __destroy_global_chain_reference + null pointer
if dtors_section.size < 8 {
return Ok(());
}
let address = dtors_section.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(),
address,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
),
kind: ObjSymbolKind::Object,
..Default::default()
},
true,
)?;
found_dgc = true;
} else {
log::debug!("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(),
address: address + 4,
section: Some(dtors_section_index),
size: 4,
size_known: true,
flags: ObjSymbolFlagSet(
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
),
kind: ObjSymbolKind::Object,
..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,
skip: false,
rename: None,
})?;
}
}
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.functions {
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<()> {
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 {
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::debug!("Checking post CFA signatures");
for &(_name, sig_str) in POST_SIGNATURES {
let signatures = parse_signatures(sig_str)?;
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((symbol_index, signature)) = found_signature {
let symbol = &obj.symbols[symbol_index];
let symbol_addr = SectionAddress::new(symbol.section.unwrap(), symbol.address as u32);
apply_signature(obj, symbol_addr, &signature)?;
}
}
Ok(())
}
/// Create _ctors and _dtors symbols if missing
pub fn update_ctors_dtors(obj: &mut ObjInfo) -> Result<()> {
if obj.symbols.by_name("_ctors")?.is_none() {
if let Some((section_index, section)) = obj.sections.by_name(".ctors")? {
obj.symbols.add_direct(ObjSymbol {
name: "_ctors".to_string(),
address: section.address,
section: Some(section_index),
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
..Default::default()
})?;
}
}
if obj.symbols.by_name("_dtors")?.is_none() {
if let Some((section_index, section)) = obj.sections.by_name(".dtors")? {
obj.symbols.add_direct(ObjSymbol {
name: "_dtors".to_string(),
address: section.address,
section: Some(section_index),
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
..Default::default()
})?;
}
}
Ok(())
}