Reorganize files; start RSO support; config & split updates

This commit is contained in:
2023-01-27 23:15:52 -05:00
parent 827e0806be
commit 830f7b172f
171 changed files with 2926 additions and 1010 deletions

View File

@@ -1,14 +1,16 @@
use std::{
collections::{btree_map::Entry, BTreeMap},
fs::File,
io::{BufRead, BufReader, BufWriter, Write},
io::{BufRead, BufWriter, Write},
path::PathBuf,
};
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{anyhow, bail, Result};
use argh::FromArgs;
use object::{Object, ObjectSymbol, SymbolScope};
use crate::util::file::{buf_reader, map_file};
#[derive(FromArgs, PartialEq, Debug)]
/// Commands for processing static libraries.
#[argh(subcommand, name = "ar")]
@@ -49,10 +51,7 @@ fn create(args: CreateArgs) -> Result<()> {
path.to_str().ok_or_else(|| anyhow!("'{}' is not valid UTF-8", path.display()))?;
match path_str.strip_prefix('@') {
Some(rsp_file) => {
let reader = BufReader::new(
File::open(rsp_file)
.with_context(|| format!("Failed to open file '{rsp_file}'"))?,
);
let reader = buf_reader(rsp_file)?;
for result in reader.lines() {
let line = result?;
if !line.is_empty() {
@@ -79,11 +78,8 @@ fn create(args: CreateArgs) -> Result<()> {
Entry::Vacant(e) => e.insert(Vec::new()),
Entry::Occupied(_) => bail!("Duplicate file name '{path_str}'"),
};
let object_file = File::open(path)
.with_context(|| format!("Failed to open object file '{}'", path.display()))?;
let map = unsafe { memmap2::MmapOptions::new().map(&object_file) }
.with_context(|| format!("Failed to mmap object file: '{}'", path.display()))?;
let obj = object::File::parse(map.as_ref())?;
let mmap = map_file(path)?;
let obj = object::File::parse(&*mmap)?;
for symbol in obj.symbols() {
if symbol.scope() == SymbolScope::Dynamic {
entries.push(symbol.name_bytes()?.to_vec());
@@ -93,8 +89,13 @@ fn create(args: CreateArgs) -> Result<()> {
// Write archive
let out = BufWriter::new(File::create(&args.out)?);
let mut builder =
ar::GnuBuilder::new(out, identifiers, ar::GnuSymbolTableFormat::Size32, symbol_table)?;
let mut builder = ar::GnuBuilder::new_with_symbol_table(
out,
true,
identifiers,
ar::GnuSymbolTableFormat::Size32,
symbol_table,
)?;
for path in files {
let path_str =
path.to_str().ok_or_else(|| anyhow!("'{}' is not valid UTF-8", path.display()))?;

View File

@@ -1,30 +1,37 @@
use std::{
collections::BTreeMap,
fs::File,
io::{BufRead, BufReader, BufWriter},
fs,
fs::{DirBuilder, File},
io::{BufRead, BufWriter, Write},
path::{Path, PathBuf},
};
use std::collections::{hash_map, HashMap};
use anyhow::{anyhow, bail, Context, Result};
use argh::FromArgs;
use crate::util::{
cfa::{
locate_sda_bases, AnalysisPass, AnalyzerState, FindSaveRestSleds,
FindTRKInterruptVectorTable,
use crate::{
analysis::{
cfa::AnalyzerState,
pass::{AnalysisPass, FindSaveRestSleds, FindTRKInterruptVectorTable},
read_u32,
tracker::Tracker,
},
config::{parse_symbol_line, write_symbols},
dol::process_dol,
elf::process_elf,
executor::read_u32,
map::process_map,
obj::{
ObjInfo, ObjRelocKind, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
ObjSymbolKind,
signatures::{apply_signature, check_signatures, check_signatures_str, parse_signatures},
split::split_obj,
ObjInfo, ObjRelocKind, ObjSectionKind, ObjSymbolKind,
},
util::{
asm::write_asm,
config::{apply_splits, parse_symbol_line, write_symbols},
dol::process_dol,
elf::process_elf,
file::{map_file, map_reader},
map::process_map,
},
sigs::check_signatures,
tracker::Tracker,
};
use crate::util::elf::write_elf;
#[derive(FromArgs, PartialEq, Debug)]
/// Commands for processing DOL files.
@@ -42,7 +49,7 @@ enum SubCommand {
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
/// Disassembles a DOL file.
/// disassembles a DOL file
#[argh(subcommand, name = "disasm")]
pub struct DisasmArgs {
#[argh(option, short = 'm')]
@@ -51,12 +58,18 @@ pub struct DisasmArgs {
#[argh(option, short = 's')]
/// path to symbols file
symbols_file: Option<PathBuf>,
#[argh(option, short = 'p')]
/// path to splits file
splits_file: Option<PathBuf>,
#[argh(option, short = 'e')]
/// ELF file to validate against (debugging only)
elf_file: Option<PathBuf>,
#[argh(positional)]
/// DOL file
dol_file: PathBuf,
#[argh(option, short = 'o')]
/// output file (or directory, if splitting)
out: PathBuf,
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
@@ -76,152 +89,201 @@ pub fn run(args: Args) -> Result<()> {
}
const SIGNATURES: &[(&str, &str)] = &[
("__init_registers", include_str!("../../assets/__init_registers.yml")),
("__init_hardware", include_str!("../../assets/__init_hardware.yml")),
("__init_data", include_str!("../../assets/__init_data.yml")),
("__set_debug_bba", include_str!("../../assets/__set_debug_bba.yml")),
("__OSPSInit", include_str!("../../assets/__OSPSInit.yml")),
("__OSFPRInit", include_str!("../../assets/__OSFPRInit.yml")),
("__OSCacheInit", include_str!("../../assets/__OSCacheInit.yml")),
("DMAErrorHandler", include_str!("../../assets/DMAErrorHandler.yml")),
("DBInit", include_str!("../../assets/DBInit.yml")),
("OSInit", include_str!("../../assets/OSInit.yml")),
("__OSThreadInit", include_str!("../../assets/__OSThreadInit.yml")),
("__OSInitIPCBuffer", include_str!("../../assets/__OSInitIPCBuffer.yml")),
("EXIInit", include_str!("../../assets/EXIInit.yml")),
("EXIGetID", include_str!("../../assets/EXIGetID.yml")),
("exit", include_str!("../../assets/exit.yml")),
("_ExitProcess", include_str!("../../assets/_ExitProcess.yml")),
("__fini_cpp", include_str!("../../assets/__fini_cpp.yml")),
("__destroy_global_chain", include_str!("../../assets/__destroy_global_chain.yml")),
("InitMetroTRK", include_str!("../../assets/InitMetroTRK.yml")),
("InitMetroTRKCommTable", include_str!("../../assets/InitMetroTRKCommTable.yml")),
("OSExceptionInit", include_str!("../../assets/OSExceptionInit.yml")),
("OSDefaultExceptionHandler", include_str!("../../assets/OSDefaultExceptionHandler.yml")),
("__OSUnhandledException", include_str!("../../assets/__OSUnhandledException.yml")),
("OSDisableScheduler", include_str!("../../assets/OSDisableScheduler.yml")),
("__OSReschedule", include_str!("../../assets/__OSReschedule.yml")),
("__OSInitSystemCall", include_str!("../../assets/__OSInitSystemCall.yml")),
("OSInitAlarm", include_str!("../../assets/OSInitAlarm.yml")),
("__OSInitAlarm", include_str!("../../assets/__OSInitAlarm.yml")),
("__OSEVStart", include_str!("../../assets/OSExceptionVector.yml")),
("__OSDBINTSTART", include_str!("../../assets/__OSDBIntegrator.yml")),
("__OSDBJUMPSTART", include_str!("../../assets/__OSDBJump.yml")),
("SIInit", include_str!("../../assets/SIInit.yml")),
("SIGetType", include_str!("../../assets/SIGetType.yml")),
("SISetSamplingRate", include_str!("../../assets/SISetSamplingRate.yml")),
("SISetXY", include_str!("../../assets/SISetXY.yml")),
("VIGetTvFormat", include_str!("../../assets/VIGetTvFormat.yml")),
("DVDInit", include_str!("../../assets/DVDInit.yml")),
("DVDSetAutoFatalMessaging", include_str!("../../assets/DVDSetAutoFatalMessaging.yml")),
("OSSetArenaLo", include_str!("../../assets/OSSetArenaLo.yml")),
("OSSetArenaHi", include_str!("../../assets/OSSetArenaHi.yml")),
("OSSetMEM1ArenaLo", include_str!("../../assets/OSSetMEM1ArenaLo.yml")),
("OSSetMEM1ArenaHi", include_str!("../../assets/OSSetMEM1ArenaHi.yml")),
("OSSetMEM2ArenaLo", include_str!("../../assets/OSSetMEM2ArenaLo.yml")),
("OSSetMEM2ArenaHi", include_str!("../../assets/OSSetMEM2ArenaHi.yml")),
("__OSInitAudioSystem", include_str!("../../assets/__OSInitAudioSystem.yml")),
("__OSInitMemoryProtection", include_str!("../../assets/__OSInitMemoryProtection.yml")),
// ("BATConfig", include_str!("../../assets/BATConfig.yml")), TODO
("ReportOSInfo", include_str!("../../assets/ReportOSInfo.yml")),
("__check_pad3", include_str!("../../assets/__check_pad3.yml")),
("OSResetSystem", include_str!("../../assets/OSResetSystem.yml")),
("OSReturnToMenu", include_str!("../../assets/OSReturnToMenu.yml")),
("__OSReturnToMenu", include_str!("../../assets/__OSReturnToMenu.yml")),
("__OSShutdownDevices", include_str!("../../assets/__OSShutdownDevices.yml")),
("__OSInitSram", include_str!("../../assets/__OSInitSram.yml")),
("__OSSyncSram", include_str!("../../assets/__OSSyncSram.yml")),
("__OSGetExceptionHandler", include_str!("../../assets/__OSGetExceptionHandler.yml")),
("OSRegisterResetFunction", include_str!("../../assets/OSRegisterResetFunction.yml")),
("OSRegisterShutdownFunction", include_str!("../../assets/OSRegisterShutdownFunction.yml")),
("DecrementerExceptionHandler", include_str!("../../assets/DecrementerExceptionHandler.yml")),
("DecrementerExceptionCallback", include_str!("../../assets/DecrementerExceptionCallback.yml")),
("__OSInterruptInit", include_str!("../../assets/__OSInterruptInit.yml")),
("__OSContextInit", include_str!("../../assets/__OSContextInit.yml")),
("OSSwitchFPUContext", include_str!("../../assets/OSSwitchFPUContext.yml")),
("OSReport", include_str!("../../assets/OSReport.yml")),
("TRK_main", include_str!("../../assets/TRK_main.yml")),
("TRKNubWelcome", include_str!("../../assets/TRKNubWelcome.yml")),
("TRKInitializeNub", include_str!("../../assets/TRKInitializeNub.yml")),
("TRKInitializeIntDrivenUART", include_str!("../../assets/TRKInitializeIntDrivenUART.yml")),
("TRKEXICallBack", include_str!("../../assets/TRKEXICallBack.yml")),
("TRKLoadContext", include_str!("../../assets/TRKLoadContext.yml")),
("TRKInterruptHandler", include_str!("../../assets/TRKInterruptHandler.yml")),
("TRKExceptionHandler", include_str!("../../assets/TRKExceptionHandler.yml")),
("TRKSaveExtended1Block", include_str!("../../assets/TRKSaveExtended1Block.yml")),
("TRKNubMainLoop", include_str!("../../assets/TRKNubMainLoop.yml")),
("TRKTargetContinue", include_str!("../../assets/TRKTargetContinue.yml")),
("TRKSwapAndGo", include_str!("../../assets/TRKSwapAndGo.yml")),
("TRKRestoreExtended1Block", include_str!("../../assets/TRKRestoreExtended1Block.yml")),
("__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/TRKInterruptHandlerEnableInterrupts.yml"),
include_str!("../../assets/signatures/TRKInterruptHandlerEnableInterrupts.yml"),
),
("memset", include_str!("../../assets/memset.yml")),
("memset", include_str!("../../assets/signatures/memset.yml")),
(
"__msl_runtime_constraint_violation_s",
include_str!("../../assets/__msl_runtime_constraint_violation_s.yml"),
include_str!("../../assets/signatures/__msl_runtime_constraint_violation_s.yml"),
),
("ClearArena", include_str!("../../assets/ClearArena.yml")),
("IPCCltInit", include_str!("../../assets/IPCCltInit.yml")),
("__OSInitSTM", include_str!("../../assets/__OSInitSTM.yml")),
("IOS_Open", include_str!("../../assets/IOS_Open.yml")),
("__ios_Ipc2", include_str!("../../assets/__ios_Ipc2.yml")),
("IPCiProfQueueReq", include_str!("../../assets/IPCiProfQueueReq.yml")),
("SCInit", include_str!("../../assets/SCInit.yml")),
("SCReloadConfFileAsync", include_str!("../../assets/SCReloadConfFileAsync.yml")),
("NANDPrivateOpenAsync", include_str!("../../assets/NANDPrivateOpenAsync.yml")),
("nandIsInitialized", include_str!("../../assets/nandIsInitialized.yml")),
("nandOpen", include_str!("../../assets/nandOpen.yml")),
("nandGenerateAbsPath", include_str!("../../assets/nandGenerateAbsPath.yml")),
("nandGetHeadToken", include_str!("../../assets/nandGetHeadToken.yml")),
("ISFS_OpenAsync", include_str!("../../assets/ISFS_OpenAsync.yml")),
("nandConvertErrorCode", include_str!("../../assets/nandConvertErrorCode.yml")),
("NANDLoggingAddMessageAsync", include_str!("../../assets/NANDLoggingAddMessageAsync.yml")),
("__NANDPrintErrorMessage", include_str!("../../assets/__NANDPrintErrorMessage.yml")),
("__OSInitNet", include_str!("../../assets/__OSInitNet.yml")),
("__DVDCheckDevice", include_str!("../../assets/__DVDCheckDevice.yml")),
("__OSInitPlayTime", include_str!("../../assets/__OSInitPlayTime.yml")),
("__OSStartPlayRecord", include_str!("../../assets/__OSStartPlayRecord.yml")),
("NANDInit", include_str!("../../assets/NANDInit.yml")),
("ISFS_OpenLib", include_str!("../../assets/ISFS_OpenLib.yml")),
("ESP_GetTitleId", include_str!("../../assets/ESP_GetTitleId.yml")),
("NANDSetAutoErrorMessaging", include_str!("../../assets/NANDSetAutoErrorMessaging.yml")),
("__DVDFSInit", include_str!("../../assets/__DVDFSInit.yml")),
("__DVDClearWaitingQueue", include_str!("../../assets/__DVDClearWaitingQueue.yml")),
("__DVDInitWA", include_str!("../../assets/__DVDInitWA.yml")),
("__DVDLowSetWAType", include_str!("../../assets/__DVDLowSetWAType.yml")),
("__fstLoad", include_str!("../../assets/__fstLoad.yml")),
("DVDReset", include_str!("../../assets/DVDReset.yml")),
("DVDLowReset", include_str!("../../assets/DVDLowReset.yml")),
("DVDReadDiskID", include_str!("../../assets/DVDReadDiskID.yml")),
("stateReady", include_str!("../../assets/stateReady.yml")),
("DVDLowWaitCoverClose", include_str!("../../assets/DVDLowWaitCoverClose.yml")),
("__DVDStoreErrorCode", include_str!("../../assets/__DVDStoreErrorCode.yml")),
("DVDLowStopMotor", include_str!("../../assets/DVDLowStopMotor.yml")),
("DVDGetDriveStatus", include_str!("../../assets/DVDGetDriveStatus.yml")),
("printf", include_str!("../../assets/printf.yml")),
("sprintf", include_str!("../../assets/sprintf.yml")),
("vprintf", include_str!("../../assets/vprintf.yml")),
("vsprintf", include_str!("../../assets/vsprintf.yml")),
("vsnprintf", include_str!("../../assets/vsnprintf.yml")),
("__pformatter", include_str!("../../assets/__pformatter.yml")),
("longlong2str", include_str!("../../assets/longlong2str.yml")),
("__mod2u", include_str!("../../assets/__mod2u.yml")),
("__FileWrite", include_str!("../../assets/__FileWrite.yml")),
("fwrite", include_str!("../../assets/fwrite.yml")),
("__fwrite", include_str!("../../assets/__fwrite.yml")),
("__stdio_atexit", include_str!("../../assets/__stdio_atexit.yml")),
("__StringWrite", include_str!("../../assets/__StringWrite.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")),
];
pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
let entry = obj.entry as u32;
check_signatures(obj, entry, include_str!("../../assets/__start.yml"))?;
if let Some(signature) =
check_signatures_str(obj, entry, include_str!("../../assets/signatures/__start.yml"))?
{
apply_signature(obj, entry, &signature)?;
}
for &(name, sig_str) in SIGNATURES {
if let Some(symbol) = obj.symbols.iter().find(|symbol| symbol.name == name) {
let addr = symbol.address as u32;
check_signatures(obj, addr, sig_str)?;
if let Some(signature) = check_signatures_str(obj, addr, sig_str)? {
apply_signature(obj, addr, &signature)?;
}
}
}
if let Some(symbol) = obj.symbols.iter().find(|symbol| symbol.name == "__init_user") {
@@ -229,7 +291,12 @@ 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 {
if check_signatures(obj, addr, include_str!("../../assets/__init_cpp.yml"))? {
if let Some(signature) = check_signatures_str(
obj,
addr,
include_str!("../../assets/signatures/__init_cpp.yml"),
)? {
apply_signature(obj, addr, &signature)?;
break;
}
}
@@ -240,7 +307,13 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
let target = read_u32(&section.data, symbol.address as u32, section.address as u32)
.ok_or_else(|| anyhow!("Failed to read _ctors data"))?;
if target != 0 {
check_signatures(obj, target, include_str!("../../assets/__init_cpp_exceptions.yml"))?;
if let Some(signature) = check_signatures_str(
obj,
target,
include_str!("../../assets/signatures/__init_cpp_exceptions.yml"),
)? {
apply_signature(obj, target, &signature)?;
}
}
}
if let Some(symbol) = obj.symbols.iter().find(|symbol| symbol.name == "_dtors") {
@@ -249,12 +322,34 @@ pub fn apply_signatures(obj: &mut ObjInfo) -> Result<()> {
let target = read_u32(&section.data, symbol.address as u32 + 4, section.address as u32)
.ok_or_else(|| anyhow!("Failed to read _dtors data"))?;
if target != 0 {
check_signatures(obj, target, include_str!("../../assets/__fini_cpp_exceptions.yml"))?;
if let Some(signature) = check_signatures_str(
obj,
target,
include_str!("../../assets/signatures/__fini_cpp_exceptions.yml"),
)? {
apply_signature(obj, target, &signature)?;
}
}
}
Ok(())
}
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)?;
for symbol in obj.symbols.iter().filter(|symbol| symbol.kind == ObjSymbolKind::Function) {
let addr = symbol.address as u32;
if let Some(signature) = check_signatures(obj, addr, &signatures)? {
apply_signature(obj, addr, &signature)?;
break;
}
}
}
log::info!("Done!");
Ok(())
}
fn info(args: InfoArgs) -> Result<()> {
let mut obj = process_dol(&args.dol_file)?;
apply_signatures(&mut obj)?;
@@ -288,6 +383,8 @@ fn info(args: InfoArgs) -> Result<()> {
FindSaveRestSleds::execute(&mut state, &obj)?;
state.apply(&mut obj)?;
apply_signatures_post(&mut obj)?;
println!("{}:", obj.name);
println!("Entry point: {:#010X}", obj.entry);
println!("\nSections:");
@@ -329,20 +426,20 @@ fn disasm(args: DisasmArgs) -> Result<()> {
// }
if let Some(map) = &args.map_file {
let mut reader = BufReader::new(
File::open(map)
.with_context(|| format!("Failed to open map file '{}'", map.display()))?,
);
let _entries = process_map(&mut reader)?;
let mmap = map_file(map)?;
let _entries = process_map(map_reader(&mmap))?;
}
if let Some(splits_file) = &args.splits_file {
let map = map_file(splits_file)?;
apply_splits(map_reader(&map), &mut obj)?;
}
let mut state = AnalyzerState::default();
if let Some(symbols_path) = &args.symbols_file {
let mut reader = BufReader::new(File::open(symbols_path).with_context(|| {
format!("Failed to open symbols file '{}'", symbols_path.display())
})?);
for result in reader.lines() {
let map = map_file(symbols_path)?;
for result in map_reader(&map).lines() {
let line = match result {
Ok(line) => line,
Err(e) => bail!("Failed to process symbols file: {e:?}"),
@@ -407,10 +504,66 @@ fn disasm(args: DisasmArgs) -> Result<()> {
log::info!("Applying relocations");
tracker.apply(&mut obj, false)?;
//
// log::info!("Writing disassembly");
// let mut w = BufWriter::new(File::create("out.s")?);
// write_asm(&mut w, &obj)?;
if args.splits_file.is_some() {
log::info!("Splitting {} objects", obj.link_order.len());
let split_objs = split_obj(&obj)?;
// Create out dirs
let asm_dir = args.out.join("asm");
let include_dir = args.out.join("include");
let obj_dir = args.out.join("expected");
DirBuilder::new().recursive(true).create(&include_dir)?;
fs::write(include_dir.join("macros.inc"), include_bytes!("../../assets/macros.inc"))?;
log::info!("Writing object files");
let mut file_map = HashMap::<String, Vec<u8>>::new();
for (unit, split_obj) in obj.link_order.iter().zip(&split_objs) {
let out_obj = write_elf(split_obj)?;
match file_map.entry(unit.clone()) {
hash_map::Entry::Vacant(e) => e.insert(out_obj),
hash_map::Entry::Occupied(_) => bail!("Duplicate file {unit}"),
};
}
let mut rsp_file = BufWriter::new(File::create("rsp")?);
for unit in &obj.link_order {
let object = file_map
.get(unit)
.ok_or_else(|| anyhow!("Failed to find object file for unit '{unit}'"))?;
let out_path = obj_dir.join(unit);
writeln!(rsp_file, "{}", out_path.display())?;
if let Some(parent) = out_path.parent() {
DirBuilder::new().recursive(true).create(parent)?;
}
let mut file = File::create(&out_path)
.with_context(|| format!("Failed to create '{}'", out_path.display()))?;
file.write_all(object)?;
file.flush()?;
}
rsp_file.flush()?;
log::info!("Writing disassembly");
let mut files_out = File::create(args.out.join("link_order.txt"))?;
for (unit, split_obj) in obj.link_order.iter().zip(&split_objs) {
let out_path = asm_dir.join(format!("{}.s", unit.trim_end_matches(".o")));
if let Some(parent) = out_path.parent() {
DirBuilder::new().recursive(true).create(parent)?;
}
let mut w = BufWriter::new(File::create(out_path)?);
write_asm(&mut w, split_obj)?;
w.flush()?;
writeln!(files_out, "{}", unit)?;
}
files_out.flush()?;
} else {
log::info!("Writing disassembly");
let mut w = BufWriter::new(File::create("out.s")?);
write_asm(&mut w, &obj)?;
}
if let Some(symbols_path) = &args.symbols_file {
let mut symbols_writer = BufWriter::new(
@@ -500,6 +653,7 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
);
}
}
return Ok(()); // TODO
for real_section in &real_obj.sections {
let obj_section = match obj.sections.get(real_section.index) {
Some(v) => v,
@@ -562,20 +716,17 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
}
for (&obj_addr, obj_reloc) in &obj_map {
let obj_symbol = &obj.symbols[obj_reloc.target_symbol];
let real_reloc = match real_map.get(&obj_addr) {
Some(v) => v,
None => {
log::warn!(
"Relocation not real @ {:#010X} {:?} to {:#010X}+{:X} ({})",
obj_addr,
obj_reloc.kind,
obj_symbol.address,
obj_reloc.addend,
obj_symbol.demangled_name.as_ref().unwrap_or(&obj_symbol.name)
);
continue;
}
};
if !real_map.contains_key(&obj_addr) {
log::warn!(
"Relocation not real @ {:#010X} {:?} to {:#010X}+{:X} ({})",
obj_addr,
obj_reloc.kind,
obj_symbol.address,
obj_reloc.addend,
obj_symbol.demangled_name.as_ref().unwrap_or(&obj_symbol.name)
);
continue;
}
}
}
Ok(())

View File

@@ -1,9 +1,9 @@
use std::{
collections::{btree_map, btree_map::Entry, hash_map, BTreeMap, HashMap, HashSet},
collections::{btree_map, hash_map, BTreeMap, HashMap},
fs,
fs::{DirBuilder, File},
io::{BufRead, BufReader, BufWriter, Write},
path::{Path, PathBuf},
path::PathBuf,
};
use anyhow::{anyhow, bail, ensure, Context, Result};
@@ -13,18 +13,19 @@ use object::{
Object, ObjectSection, ObjectSymbol, RelocationKind, RelocationTarget, SectionFlags,
SectionIndex, SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection,
};
use ppc750cl::Ins;
use serde::{Deserialize, Serialize};
use sha1::{Digest, Sha1};
use crate::util::{
asm::write_asm,
config::write_symbols,
elf::{process_elf, write_elf},
obj::{ObjKind, ObjReloc, ObjRelocKind, ObjSymbolFlagSet, ObjSymbolKind},
sigs::{check_signature, compare_signature, generate_signature, FunctionSignature},
split::split_obj,
tracker::Tracker,
use crate::{
obj::{
signatures::{compare_signature, generate_signature, FunctionSignature},
split::split_obj,
ObjKind,
},
util::{
asm::write_asm,
config::{write_splits, write_symbols},
elf::{process_elf, write_elf},
file::buf_reader,
},
};
#[derive(FromArgs, PartialEq, Debug)]
@@ -91,6 +92,9 @@ pub struct ConfigArgs {
#[argh(positional)]
/// output directory
out_dir: PathBuf,
#[argh(option, short = 'm')]
/// path to obj_files.mk
obj_files: Option<PathBuf>,
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
@@ -120,15 +124,43 @@ pub fn run(args: Args) -> Result<()> {
fn config(args: ConfigArgs) -> Result<()> {
log::info!("Loading {}", args.in_file.display());
let mut obj = process_elf(&args.in_file)?;
let obj = process_elf(&args.in_file)?;
DirBuilder::new().recursive(true).create(&args.out_dir)?;
let symbols_path = args.out_dir.join("symbols.txt");
let mut symbols_writer = BufWriter::new(
File::create(&symbols_path)
.with_context(|| format!("Failed to create '{}'", symbols_path.display()))?,
);
write_symbols(&mut symbols_writer, &obj)?;
{
let symbols_path = args.out_dir.join("symbols.txt");
let mut symbols_writer = BufWriter::new(
File::create(&symbols_path)
.with_context(|| format!("Failed to create '{}'", symbols_path.display()))?,
);
write_symbols(&mut symbols_writer, &obj)?;
}
{
let obj_files = if let Some(path) = &args.obj_files {
Some(
BufReader::new(
File::open(path)
.with_context(|| format!("Failed to open '{}'", path.display()))?,
)
.lines()
.filter(|line| match line {
Ok(line) => line.contains(".o"),
Err(_) => false,
})
.map(|result| result.unwrap())
.collect::<Vec<String>>(),
)
} else {
None
};
let splits_path = args.out_dir.join("splits.txt");
let mut splits_writer = BufWriter::new(
File::create(&splits_path)
.with_context(|| format!("Failed to create '{}'", splits_path.display()))?,
);
write_splits(&mut splits_writer, &obj, obj_files)?;
}
Ok(())
}
@@ -449,10 +481,7 @@ fn signatures(args: SignaturesArgs) -> Result<()> {
path.to_str().ok_or_else(|| anyhow!("'{}' is not valid UTF-8", path.display()))?;
match path_str.strip_prefix('@') {
Some(rsp_file) => {
let reader = BufReader::new(
File::open(rsp_file)
.with_context(|| format!("Failed to open file '{rsp_file}'"))?,
);
let reader = buf_reader(rsp_file)?;
for result in reader.lines() {
let line = result?;
if !line.is_empty() {
@@ -466,10 +495,10 @@ fn signatures(args: SignaturesArgs) -> Result<()> {
}
}
let mut signatures: HashMap<Vec<u8>, FunctionSignature> = HashMap::new();
let mut signatures: HashMap<String, FunctionSignature> = HashMap::new();
for path in files {
log::info!("Processing {}", path.display());
let (data, signature) = match generate_signature(&path, &args.symbol) {
let signature = match generate_signature(&path, &args.symbol) {
Ok(Some(signature)) => signature,
Ok(None) => continue,
Err(e) => {
@@ -478,13 +507,13 @@ fn signatures(args: SignaturesArgs) -> Result<()> {
}
};
log::info!("Comparing hash {}", signature.hash);
if let Some((_, existing)) = signatures.iter_mut().find(|(a, b)| *a == &data) {
if let Some(existing) = signatures.get_mut(&signature.hash) {
compare_signature(existing, &signature)?;
} else {
signatures.insert(data, signature);
signatures.insert(signature.hash.clone(), signature);
}
}
let mut signatures = signatures.into_iter().map(|(a, b)| b).collect::<Vec<FunctionSignature>>();
let mut signatures = signatures.into_values().collect::<Vec<FunctionSignature>>();
log::info!("{} unique signatures", signatures.len());
signatures.sort_by_key(|s| s.signature.len());
let out =

View File

@@ -1,23 +1,25 @@
use std::{
fs::File,
io::{BufWriter, Seek, SeekFrom, Write},
path::PathBuf,
};
use anyhow::{anyhow, bail, ensure, Context, Result};
use argh::FromArgs;
use memmap2::MmapOptions;
use object::{Architecture, Endianness, Object, ObjectKind, ObjectSection, SectionKind};
use crate::util::file::map_file;
#[derive(FromArgs, PartialEq, Eq, Debug)]
/// Converts an ELF file to a DOL file.
#[argh(subcommand, name = "elf2dol")]
pub struct Args {
#[argh(positional)]
/// path to input ELF
elf_file: String,
elf_file: PathBuf,
#[argh(positional)]
/// path to output DOL
dol_file: String,
dol_file: PathBuf,
}
#[derive(Debug, Clone, Default)]
@@ -42,10 +44,7 @@ const MAX_TEXT_SECTIONS: usize = 7;
const MAX_DATA_SECTIONS: usize = 11;
pub fn run(args: Args) -> Result<()> {
let elf_file = File::open(&args.elf_file)
.with_context(|| format!("Failed to open ELF file '{}'", args.elf_file))?;
let map = unsafe { MmapOptions::new().map(&elf_file) }
.with_context(|| format!("Failed to mmap ELF file: '{}'", args.elf_file))?;
let map = map_file(&args.elf_file)?;
let obj_file = object::read::File::parse(&*map)?;
match obj_file.architecture() {
Architecture::PowerPc => {}
@@ -61,7 +60,7 @@ pub fn run(args: Args) -> Result<()> {
let mut offset = 0x100u32;
let mut out = BufWriter::new(
File::create(&args.dol_file)
.with_context(|| format!("Failed to create DOL file '{}'", args.dol_file))?,
.with_context(|| format!("Failed to create DOL file '{}'", args.dol_file.display()))?,
);
out.seek(SeekFrom::Start(offset as u64))?;

View File

@@ -1,9 +1,12 @@
use std::{fs::File, io::BufReader};
use std::path::PathBuf;
use anyhow::{bail, ensure, Context, Result};
use anyhow::{bail, ensure, Result};
use argh::FromArgs;
use crate::util::map::{process_map, resolve_link_order, SymbolEntry, SymbolRef};
use crate::util::{
file::{map_file, map_reader},
map::{process_map, resolve_link_order, SymbolEntry, SymbolRef},
};
#[derive(FromArgs, PartialEq, Debug)]
/// Commands for processing CodeWarrior maps.
@@ -29,7 +32,7 @@ enum SubCommand {
pub struct EntriesArgs {
#[argh(positional)]
/// path to input map
map_file: String,
map_file: PathBuf,
#[argh(positional)]
/// TU to display entries for
unit: String,
@@ -41,7 +44,7 @@ pub struct EntriesArgs {
pub struct SymbolArgs {
#[argh(positional)]
/// path to input map
map_file: String,
map_file: PathBuf,
#[argh(positional)]
/// symbol to display references for
symbol: String,
@@ -53,7 +56,7 @@ pub struct SymbolArgs {
pub struct OrderArgs {
#[argh(positional)]
/// path to input map
map_file: String,
map_file: PathBuf,
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
@@ -62,7 +65,7 @@ pub struct OrderArgs {
pub struct SlicesArgs {
#[argh(positional)]
/// path to input map
map_file: String,
map_file: PathBuf,
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
@@ -71,7 +74,7 @@ pub struct SlicesArgs {
pub struct SymbolsArgs {
#[argh(positional)]
/// path to input map
map_file: String,
map_file: PathBuf,
}
pub fn run(args: Args) -> Result<()> {
@@ -85,11 +88,8 @@ pub fn run(args: Args) -> Result<()> {
}
fn entries(args: EntriesArgs) -> Result<()> {
let reader = BufReader::new(
File::open(&args.map_file)
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
);
let entries = process_map(reader)?;
let map = map_file(&args.map_file)?;
let entries = process_map(map_reader(&map))?;
match entries.unit_entries.get_vec(&args.unit) {
Some(vec) => {
for symbol_ref in vec {
@@ -109,11 +109,8 @@ fn entries(args: EntriesArgs) -> Result<()> {
}
fn symbol(args: SymbolArgs) -> Result<()> {
let reader = BufReader::new(
File::open(&args.map_file)
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
);
let entries = process_map(reader)?;
let map = map_file(&args.map_file)?;
let entries = process_map(map_reader(&map))?;
let mut opt_ref: Option<(SymbolRef, SymbolEntry)> = None;
for (symbol_ref, entry) in &entries.symbols {
if symbol_ref.name == args.symbol {
@@ -164,11 +161,8 @@ fn symbol(args: SymbolArgs) -> Result<()> {
}
fn order(args: OrderArgs) -> Result<()> {
let reader = BufReader::new(
File::open(&args.map_file)
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
);
let entries = process_map(reader)?;
let map = map_file(&args.map_file)?;
let entries = process_map(map_reader(&map))?;
let order = resolve_link_order(&entries.unit_order)?;
for unit in order {
println!("{unit}");
@@ -177,11 +171,8 @@ fn order(args: OrderArgs) -> Result<()> {
}
fn slices(args: SlicesArgs) -> Result<()> {
let reader = BufReader::new(
File::open(&args.map_file)
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
);
let entries = process_map(reader)?;
let map = map_file(&args.map_file)?;
let entries = process_map(map_reader(&map))?;
let order = resolve_link_order(&entries.unit_order)?;
for unit in order {
let unit_path = if let Some((lib, name)) = unit.split_once(' ') {
@@ -210,11 +201,8 @@ fn slices(args: SlicesArgs) -> Result<()> {
}
fn symbols(args: SymbolsArgs) -> Result<()> {
let reader = BufReader::new(
File::open(&args.map_file)
.with_context(|| format!("Failed to open file '{}'", args.map_file))?,
);
let _entries = process_map(reader)?;
let map = map_file(&args.map_file)?;
let _entries = process_map(map_reader(&map))?;
// for (address, symbol) in entries.address_to_symbol {
// if symbol.name.starts_with('@') {
// continue;

View File

@@ -1,3 +1,5 @@
use std::path::PathBuf;
use anyhow::{bail, ensure, Context, Result};
use argh::FromArgs;
use memchr::memmem;
@@ -9,18 +11,19 @@ use memmap2::MmapOptions;
pub struct Args {
#[argh(positional)]
/// path to source binary
binary: String,
binary: PathBuf,
#[argh(positional)]
/// path to build info string
build_info: String,
build_info: PathBuf,
}
const BUILD_STRING_MAX: usize = 35;
const BUILD_STRING_TAG: &str = "!#$MetroidBuildInfo!#$";
pub fn run(args: Args) -> Result<()> {
let build_string = std::fs::read_to_string(&args.build_info)
.with_context(|| format!("Failed to read build info string from '{}'", args.build_info))?;
let build_string = std::fs::read_to_string(&args.build_info).with_context(|| {
format!("Failed to read build info string from '{}'", args.build_info.display())
})?;
let build_string_trim = build_string.trim_end();
let build_string_bytes = build_string_trim.as_bytes();
ensure!(
@@ -28,13 +31,12 @@ pub fn run(args: Args) -> Result<()> {
"Build string '{build_string_trim}' is greater than maximum size of {BUILD_STRING_MAX}"
);
let binary_file = std::fs::File::options()
.read(true)
.write(true)
.open(&args.binary)
.with_context(|| format!("Failed to open binary for writing: '{}'", args.binary))?;
let binary_file =
std::fs::File::options().read(true).write(true).open(&args.binary).with_context(|| {
format!("Failed to open binary for writing: '{}'", args.binary.display())
})?;
let mut map = unsafe { MmapOptions::new().map_mut(&binary_file) }
.with_context(|| format!("Failed to mmap binary: '{}'", args.binary))?;
.with_context(|| format!("Failed to mmap binary: '{}'", args.binary.display()))?;
let start = match memmem::find(&map, BUILD_STRING_TAG.as_bytes()) {
Some(idx) => idx + BUILD_STRING_TAG.as_bytes().len(),
None => bail!("Failed to find build string tag in binary"),

View File

@@ -1,9 +1,10 @@
pub(crate) mod ar;
pub(crate) mod demangle;
pub(crate) mod dol;
pub(crate) mod elf;
pub(crate) mod elf2dol;
pub(crate) mod map;
pub(crate) mod metroidbuildinfo;
pub(crate) mod rel;
pub(crate) mod shasum;
pub mod ar;
pub mod demangle;
pub mod dol;
pub mod elf;
pub mod elf2dol;
pub mod map;
pub mod metroidbuildinfo;
pub mod rel;
pub mod rso;
pub mod shasum;

View File

@@ -1,25 +1,28 @@
use std::{
collections::{btree_map, BTreeMap},
fs::File,
io::{BufWriter, Write},
io::Write,
path::PathBuf,
};
use anyhow::{anyhow, bail, ensure, Context, Result};
use anyhow::{bail, ensure, Context, Result};
use argh::FromArgs;
use crate::{
analysis::{
cfa::AnalyzerState,
pass::{AnalysisPass, FindSaveRestSleds, FindTRKInterruptVectorTable},
tracker::Tracker,
},
cmd::dol::apply_signatures,
obj::{ObjInfo, ObjReloc, ObjRelocKind, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolKind},
util::{
dol::process_dol,
elf::write_elf,
obj::{ObjInfo, ObjSection, ObjSymbol},
nested::{NestedMap, NestedVec},
rel::process_rel,
},
};
use crate::util::cfa::{AnalysisPass, AnalyzerState, FindSaveRestSleds, FindTRKInterruptVectorTable};
use crate::util::obj::{nested_push, ObjReloc, ObjRelocKind, ObjSectionKind, ObjSymbolKind};
use crate::util::tracker::Tracker;
#[derive(FromArgs, PartialEq, Debug)]
/// Commands for processing REL files.
@@ -111,12 +114,7 @@ fn merge(args: MergeArgs) -> Result<()> {
file_offset: mod_section.file_offset,
section_known: mod_section.section_known,
});
nested_try_insert(
&mut section_map,
module.module_id,
mod_section.elf_index as u32,
offset,
)?;
section_map.nested_insert(module.module_id, mod_section.elf_index as u32, offset)?;
let symbols = module.symbols_for_section(mod_section.index);
for (_, mod_symbol) in symbols {
obj.symbols.push(ObjSymbol {
@@ -159,7 +157,7 @@ fn merge(args: MergeArgs) -> Result<()> {
let sym_map = &mut symbol_maps[target_section_index];
let target_symbol = {
let mut result = None;
for (&addr, symbol_idxs) in sym_map.range(..=target_addr).rev() {
for (_addr, symbol_idxs) in sym_map.range(..=target_addr).rev() {
let symbol_idx = if symbol_idxs.len() == 1 {
symbol_idxs.first().cloned().unwrap()
} else {
@@ -183,10 +181,10 @@ fn merge(args: MergeArgs) -> Result<()> {
ObjRelocKind::PpcAddr16Hi
| ObjRelocKind::PpcAddr16Ha
| ObjRelocKind::PpcAddr16Lo
if !symbol.name.starts_with("..") =>
{
3
}
if !symbol.name.starts_with("..") =>
{
3
}
_ => 1,
},
ObjSymbolKind::Section => -1,
@@ -231,7 +229,7 @@ fn merge(args: MergeArgs) -> Result<()> {
flags: Default::default(),
kind: Default::default(),
});
nested_push(sym_map, target_addr, symbol_idx);
sym_map.nested_push(target_addr, symbol_idx);
(symbol_idx, 0)
};
obj.sections[target_section_index].relocations.push(ObjReloc {
@@ -288,25 +286,3 @@ fn merge(args: MergeArgs) -> Result<()> {
file.flush()?;
Ok(())
}
#[inline]
fn nested_try_insert<T1, T2, T3>(
map: &mut BTreeMap<T1, BTreeMap<T2, T3>>,
v1: T1,
v2: T2,
v3: T3,
) -> Result<()>
where
T1: Eq + Ord,
T2: Eq + Ord,
{
let map = match map.entry(v1) {
btree_map::Entry::Occupied(entry) => entry.into_mut(),
btree_map::Entry::Vacant(entry) => entry.insert(Default::default()),
};
match map.entry(v2) {
btree_map::Entry::Occupied(_) => bail!("Entry already exists"),
btree_map::Entry::Vacant(entry) => entry.insert(v3),
};
Ok(())
}

41
src/cmd/rso.rs Normal file
View File

@@ -0,0 +1,41 @@
use std::path::PathBuf;
use anyhow::Result;
use argh::FromArgs;
use crate::util::rso::process_rso;
#[derive(FromArgs, PartialEq, Debug)]
/// Commands for processing RSO files.
#[argh(subcommand, name = "rso")]
pub struct Args {
#[argh(subcommand)]
command: SubCommand,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum SubCommand {
Info(InfoArgs),
}
#[derive(FromArgs, PartialEq, Eq, Debug)]
/// Views RSO file information.
#[argh(subcommand, name = "info")]
pub struct InfoArgs {
#[argh(positional)]
/// RSO file
rso_file: PathBuf,
}
pub fn run(args: Args) -> Result<()> {
match args.command {
SubCommand::Info(c_args) => info(c_args),
}
}
fn info(args: InfoArgs) -> Result<()> {
let rso = process_rso(&args.rso_file)?;
println!("Read RSO module {}", rso.name);
Ok(())
}

View File

@@ -1,7 +1,7 @@
use std::{
fs::{File, OpenOptions},
io::{BufRead, BufReader, Read},
path::Path,
path::{Path, PathBuf},
};
use anyhow::{anyhow, bail, Context, Result};
@@ -18,17 +18,17 @@ pub struct Args {
check: bool,
#[argh(positional)]
/// path to file
file: String,
file: PathBuf,
#[argh(option, short = 'o')]
/// touch output file on successful check
output: Option<String>,
output: Option<PathBuf>,
}
const DEFAULT_BUF_SIZE: usize = 8192;
pub fn run(args: Args) -> Result<()> {
let file =
File::open(&args.file).with_context(|| format!("Failed to open file '{}'", args.file))?;
let file = File::open(&args.file)
.with_context(|| format!("Failed to open file '{}'", args.file.display()))?;
if args.check {
check(args, file)
} else {
@@ -69,7 +69,8 @@ fn check(args: Args, file: File) -> Result<()> {
std::process::exit(1);
}
if let Some(out_path) = args.output {
touch(&out_path).with_context(|| format!("Failed to touch output file '{out_path}'"))?;
touch(&out_path)
.with_context(|| format!("Failed to touch output file '{}'", out_path.display()))?;
}
Ok(())
}
@@ -79,7 +80,7 @@ fn hash(args: Args, file: File) -> Result<()> {
let mut hash_buf = [0u8; 40];
let hash_str = base16ct::lower::encode_str(&hash, &mut hash_buf)
.map_err(|e| anyhow!("Failed to encode hash: {e}"))?;
println!("{} {}", hash_str, args.file);
println!("{} {}", hash_str, args.file.display());
Ok(())
}