Add alf support (NVIDIA Shield TV binaries)
- Supports .alf files in all places .dol files are accepted. - Adds `hash` and `dhash` to symbols config.
This commit is contained in:
parent
db506fb927
commit
dfb569b883
|
@ -144,15 +144,12 @@ impl AnalyzerState {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name,
|
name,
|
||||||
demangled_name: None,
|
|
||||||
address: start.address as u64,
|
address: start.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: (end.address - start.address) as u64,
|
size: (end.address - start.address) as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: Default::default(),
|
|
||||||
kind: ObjSymbolKind::Function,
|
kind: ObjSymbolKind::Function,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
@ -188,15 +185,13 @@ impl AnalyzerState {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: format!("jumptable_{}", address_str),
|
name: format!("jumptable_{}", address_str),
|
||||||
demangled_name: None,
|
|
||||||
address: addr.address as u64,
|
address: addr.address as u64,
|
||||||
section: Some(addr.section),
|
section: Some(addr.section),
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local.into()),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -37,28 +37,20 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||||
log::debug!("Found gTRKInterruptVectorTable @ {:#010X}", start);
|
log::debug!("Found gTRKInterruptVectorTable @ {:#010X}", start);
|
||||||
state.known_symbols.insert(start, ObjSymbol {
|
state.known_symbols.insert(start, ObjSymbol {
|
||||||
name: "gTRKInterruptVectorTable".to_string(),
|
name: "gTRKInterruptVectorTable".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: start.address as u64,
|
address: start.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
let end = start + TRK_TABLE_SIZE;
|
let end = start + TRK_TABLE_SIZE;
|
||||||
state.known_symbols.insert(end, ObjSymbol {
|
state.known_symbols.insert(end, ObjSymbol {
|
||||||
name: "gTRKInterruptVectorTableEnd".to_string(),
|
name: "gTRKInterruptVectorTableEnd".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: end.address as u64,
|
address: end.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -96,29 +88,23 @@ impl AnalysisPass for FindSaveRestSleds {
|
||||||
});
|
});
|
||||||
state.known_symbols.insert(start, ObjSymbol {
|
state.known_symbols.insert(start, ObjSymbol {
|
||||||
name: func.to_string(),
|
name: func.to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: start.address as u64,
|
address: start.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: SLED_SIZE as u64,
|
size: SLED_SIZE as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Function,
|
kind: ObjSymbolKind::Function,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
for i in 14..=31 {
|
for i in 14..=31 {
|
||||||
let addr = start + (i - 14) * 4;
|
let addr = start + (i - 14) * 4;
|
||||||
state.known_symbols.insert(addr, ObjSymbol {
|
state.known_symbols.insert(addr, ObjSymbol {
|
||||||
name: format!("{}{}", label, i),
|
name: format!("{}{}", label, i),
|
||||||
demangled_name: None,
|
|
||||||
address: addr.address as u64,
|
address: addr.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,30 +188,20 @@ impl AnalysisPass for FindRelCtorsDtors {
|
||||||
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
||||||
state.known_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
|
state.known_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
|
||||||
name: "_ctors".to_string(),
|
name: "_ctors".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: 0,
|
|
||||||
section: Some(ctors_section_index),
|
section: Some(ctors_section_index),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: Default::default(),
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let dtors_section_index = possible_sections[1].0;
|
let dtors_section_index = possible_sections[1].0;
|
||||||
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
||||||
state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
||||||
name: "_dtors".to_string(),
|
name: "_dtors".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: 0,
|
|
||||||
section: Some(dtors_section_index),
|
section: Some(dtors_section_index),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: Default::default(),
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for duplicate entries in .dtors, indicating __destroy_global_chain_reference
|
// Check for duplicate entries in .dtors, indicating __destroy_global_chain_reference
|
||||||
|
|
|
@ -245,15 +245,13 @@ fn apply_ctors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||||
obj.symbols.add(
|
obj.symbols.add(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "__init_cpp_exceptions_reference".to_string(),
|
name: "__init_cpp_exceptions_reference".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address,
|
address,
|
||||||
section: Some(ctors_section_index),
|
section: Some(ctors_section_index),
|
||||||
size: 4,
|
size: 4,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -303,7 +301,6 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "__destroy_global_chain_reference".to_string(),
|
name: "__destroy_global_chain_reference".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address,
|
address,
|
||||||
section: Some(dtors_section_index),
|
section: Some(dtors_section_index),
|
||||||
size: 4,
|
size: 4,
|
||||||
|
@ -312,8 +309,7 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||||
),
|
),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -334,7 +330,6 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "__fini_cpp_exceptions_reference".to_string(),
|
name: "__fini_cpp_exceptions_reference".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: address + 4,
|
address: address + 4,
|
||||||
section: Some(dtors_section_index),
|
section: Some(dtors_section_index),
|
||||||
size: 4,
|
size: 4,
|
||||||
|
@ -343,8 +338,7 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
||||||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||||
),
|
),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -452,15 +446,11 @@ pub fn update_ctors_dtors(obj: &mut ObjInfo) -> Result<()> {
|
||||||
if let Some((section_index, section)) = obj.sections.by_name(".ctors")? {
|
if let Some((section_index, section)) = obj.sections.by_name(".ctors")? {
|
||||||
obj.symbols.add_direct(ObjSymbol {
|
obj.symbols.add_direct(ObjSymbol {
|
||||||
name: "_ctors".to_string(),
|
name: "_ctors".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: section.address,
|
address: section.address,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,15 +458,11 @@ pub fn update_ctors_dtors(obj: &mut ObjInfo) -> Result<()> {
|
||||||
if let Some((section_index, section)) = obj.sections.by_name(".dtors")? {
|
if let Some((section_index, section)) = obj.sections.by_name(".dtors")? {
|
||||||
obj.symbols.add_direct(ObjSymbol {
|
obj.symbols.add_direct(ObjSymbol {
|
||||||
name: "_dtors".to_string(),
|
name: "_dtors".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: section.address,
|
address: section.address,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: 0,
|
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,15 +710,10 @@ impl Tracker {
|
||||||
};
|
};
|
||||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||||
name,
|
name,
|
||||||
demangled_name: None,
|
|
||||||
address: target.address as u64,
|
address: target.address as u64,
|
||||||
section: Some(target.section),
|
section: Some(target.section),
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: Default::default(),
|
|
||||||
kind: Default::default(),
|
|
||||||
align: None,
|
|
||||||
data_kind,
|
data_kind,
|
||||||
|
..Default::default()
|
||||||
})?;
|
})?;
|
||||||
(symbol_idx, 0)
|
(symbol_idx, 0)
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
use std::{
|
||||||
|
io::{stdout, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use argp::FromArgs;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
cmd,
|
||||||
|
util::{
|
||||||
|
alf::AlfFile,
|
||||||
|
file::{buf_writer, map_file},
|
||||||
|
reader::{Endian, FromReader},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// Commands for processing NVIDIA Shield TV alf files.
|
||||||
|
#[argp(subcommand, name = "alf")]
|
||||||
|
pub struct Args {
|
||||||
|
#[argp(subcommand)]
|
||||||
|
command: SubCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argp(subcommand)]
|
||||||
|
enum SubCommand {
|
||||||
|
Info(InfoArgs),
|
||||||
|
Hashes(HashesArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// Prints information about an alf file. (Same as `dol info`)
|
||||||
|
#[argp(subcommand, name = "info")]
|
||||||
|
pub struct InfoArgs {
|
||||||
|
#[argp(positional)]
|
||||||
|
/// alf file
|
||||||
|
file: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// Extracts symbol hashes from an alf file.
|
||||||
|
#[argp(subcommand, name = "hashes")]
|
||||||
|
pub struct HashesArgs {
|
||||||
|
#[argp(positional)]
|
||||||
|
/// alf file
|
||||||
|
alf_file: PathBuf,
|
||||||
|
#[argp(positional)]
|
||||||
|
/// output file
|
||||||
|
output: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(args: Args) -> Result<()> {
|
||||||
|
match args.command {
|
||||||
|
SubCommand::Info(c_args) => info(c_args),
|
||||||
|
SubCommand::Hashes(c_args) => hashes(c_args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hashes(args: HashesArgs) -> Result<()> {
|
||||||
|
let alf_file = {
|
||||||
|
let file = map_file(&args.alf_file)?;
|
||||||
|
let mut reader = file.as_reader();
|
||||||
|
AlfFile::from_reader(&mut reader, Endian::Little)?
|
||||||
|
};
|
||||||
|
let mut w: Box<dyn Write> = if let Some(output) = args.output {
|
||||||
|
Box::new(buf_writer(output)?)
|
||||||
|
} else {
|
||||||
|
Box::new(stdout())
|
||||||
|
};
|
||||||
|
let mut symbols = alf_file.symbols.clone();
|
||||||
|
symbols.sort_by_key(|s| s.address);
|
||||||
|
for symbol in symbols {
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
"{:#010X} | {} | {:?} | {} | {} | {:#X}",
|
||||||
|
symbol.address,
|
||||||
|
symbol.section,
|
||||||
|
symbol.kind,
|
||||||
|
symbol.name,
|
||||||
|
symbol.demangled_name,
|
||||||
|
symbol.size
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
w.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info(args: InfoArgs) -> Result<()> {
|
||||||
|
cmd::dol::info(cmd::dol::InfoArgs { dol_file: args.file, selfile: None })
|
||||||
|
}
|
|
@ -31,9 +31,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
cmd::shasum::file_sha1_string,
|
cmd::shasum::file_sha1_string,
|
||||||
obj::{
|
obj::{
|
||||||
best_match_for_reloc, ObjDataKind, ObjInfo, ObjKind, ObjReloc, ObjRelocKind,
|
best_match_for_reloc, ObjInfo, ObjKind, ObjReloc, ObjRelocKind, ObjSectionKind, ObjSymbol,
|
||||||
ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, ObjSymbolScope,
|
ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, ObjSymbolScope, SymbolIndex,
|
||||||
SymbolIndex,
|
|
||||||
},
|
},
|
||||||
util::{
|
util::{
|
||||||
asm::write_asm,
|
asm::write_asm,
|
||||||
|
@ -79,10 +78,10 @@ enum SubCommand {
|
||||||
pub struct InfoArgs {
|
pub struct InfoArgs {
|
||||||
#[argp(positional)]
|
#[argp(positional)]
|
||||||
/// DOL file
|
/// DOL file
|
||||||
dol_file: PathBuf,
|
pub dol_file: PathBuf,
|
||||||
#[argp(option, short = 's')]
|
#[argp(option, short = 's')]
|
||||||
/// optional path to selfile.sel
|
/// optional path to selfile.sel
|
||||||
selfile: Option<PathBuf>,
|
pub selfile: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
|
@ -366,6 +365,8 @@ fn apply_selfile(obj: &mut ObjInfo, buf: &[u8]) -> Result<()> {
|
||||||
kind: existing_symbol.kind,
|
kind: existing_symbol.kind,
|
||||||
align: existing_symbol.align,
|
align: existing_symbol.align,
|
||||||
data_kind: existing_symbol.data_kind,
|
data_kind: existing_symbol.data_kind,
|
||||||
|
name_hash: existing_symbol.name_hash,
|
||||||
|
demangled_name_hash: existing_symbol.demangled_name_hash,
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Creating symbol {} at {:#010X}", symbol.name, address);
|
log::debug!("Creating symbol {} at {:#010X}", symbol.name, address);
|
||||||
|
@ -385,7 +386,7 @@ fn apply_selfile(obj: &mut ObjInfo, buf: &[u8]) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info(args: InfoArgs) -> Result<()> {
|
pub fn info(args: InfoArgs) -> Result<()> {
|
||||||
let mut obj = {
|
let mut obj = {
|
||||||
let file = map_file(&args.dol_file)?;
|
let file = map_file(&args.dol_file)?;
|
||||||
process_dol(file.as_slice(), "")?
|
process_dol(file.as_slice(), "")?
|
||||||
|
@ -523,15 +524,10 @@ fn update_symbols(obj: &mut ObjInfo, modules: &ModuleMap<'_>, create_symbols: bo
|
||||||
};
|
};
|
||||||
obj.symbols.add_direct(ObjSymbol {
|
obj.symbols.add_direct(ObjSymbol {
|
||||||
name,
|
name,
|
||||||
demangled_name: None,
|
|
||||||
address: rel_reloc.addend as u64,
|
address: rel_reloc.addend as u64,
|
||||||
section: Some(target_section_index),
|
section: Some(target_section_index),
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::ForceActive.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::ForceActive.into()),
|
||||||
kind: Default::default(),
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: ObjDataKind::Unknown,
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,14 +650,7 @@ fn resolve_external_relocations(
|
||||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||||
name: target_symbol.name.clone(),
|
name: target_symbol.name.clone(),
|
||||||
demangled_name: target_symbol.demangled_name.clone(),
|
demangled_name: target_symbol.demangled_name.clone(),
|
||||||
address: 0,
|
..Default::default()
|
||||||
section: None,
|
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: Default::default(),
|
|
||||||
kind: Default::default(),
|
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
e.insert(symbol_idx);
|
e.insert(symbol_idx);
|
||||||
|
@ -1542,6 +1531,8 @@ fn apply(args: ApplyArgs) -> Result<()> {
|
||||||
kind: linked_sym.kind,
|
kind: linked_sym.kind,
|
||||||
align: linked_sym.align,
|
align: linked_sym.align,
|
||||||
data_kind: linked_sym.data_kind,
|
data_kind: linked_sym.data_kind,
|
||||||
|
name_hash: linked_sym.name_hash,
|
||||||
|
demangled_name_hash: linked_sym.demangled_name_hash,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod alf;
|
||||||
pub mod ar;
|
pub mod ar;
|
||||||
pub mod demangle;
|
pub mod demangle;
|
||||||
pub mod dol;
|
pub mod dol;
|
||||||
|
|
|
@ -471,8 +471,10 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||||
size_known: mod_symbol.size_known,
|
size_known: mod_symbol.size_known,
|
||||||
flags: mod_symbol.flags,
|
flags: mod_symbol.flags,
|
||||||
kind: mod_symbol.kind,
|
kind: mod_symbol.kind,
|
||||||
align: None,
|
align: mod_symbol.align,
|
||||||
data_kind: Default::default(),
|
data_kind: mod_symbol.data_kind,
|
||||||
|
name_hash: mod_symbol.name_hash,
|
||||||
|
demangled_name_hash: mod_symbol.demangled_name_hash,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
offset += align32(mod_section.size as u32);
|
offset += align32(mod_section.size as u32);
|
||||||
|
@ -506,15 +508,9 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||||
// Create a new label
|
// Create a new label
|
||||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
demangled_name: None,
|
|
||||||
address: target_addr as u64,
|
address: target_addr as u64,
|
||||||
section: Some(target_section_index),
|
section: Some(target_section_index),
|
||||||
size: 0,
|
..Default::default()
|
||||||
size_known: false,
|
|
||||||
flags: Default::default(),
|
|
||||||
kind: Default::default(),
|
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
})?;
|
})?;
|
||||||
(symbol_idx, 0)
|
(symbol_idx, 0)
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,6 +74,7 @@ struct TopLevel {
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argp(subcommand)]
|
#[argp(subcommand)]
|
||||||
enum SubCommand {
|
enum SubCommand {
|
||||||
|
Alf(cmd::alf::Args),
|
||||||
Ar(cmd::ar::Args),
|
Ar(cmd::ar::Args),
|
||||||
Demangle(cmd::demangle::Args),
|
Demangle(cmd::demangle::Args),
|
||||||
Dol(cmd::dol::Args),
|
Dol(cmd::dol::Args),
|
||||||
|
@ -122,6 +123,7 @@ fn main() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
result = result.and_then(|_| match args.command {
|
result = result.and_then(|_| match args.command {
|
||||||
|
SubCommand::Alf(c_args) => cmd::alf::run(c_args),
|
||||||
SubCommand::Ar(c_args) => cmd::ar::run(c_args),
|
SubCommand::Ar(c_args) => cmd::ar::run(c_args),
|
||||||
SubCommand::Demangle(c_args) => cmd::demangle::run(c_args),
|
SubCommand::Demangle(c_args) => cmd::demangle::run(c_args),
|
||||||
SubCommand::Dol(c_args) => cmd::dol::run(c_args),
|
SubCommand::Dol(c_args) => cmd::dol::run(c_args),
|
||||||
|
|
|
@ -165,6 +165,9 @@ pub struct ObjSymbol {
|
||||||
pub kind: ObjSymbolKind,
|
pub kind: ObjSymbolKind,
|
||||||
pub align: Option<u32>,
|
pub align: Option<u32>,
|
||||||
pub data_kind: ObjDataKind,
|
pub data_kind: ObjDataKind,
|
||||||
|
/// ALF hashes
|
||||||
|
pub name_hash: Option<u32>,
|
||||||
|
pub demangled_name_hash: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type SymbolIndex = usize;
|
pub type SymbolIndex = usize;
|
||||||
|
@ -263,6 +266,8 @@ impl ObjSymbols {
|
||||||
ObjDataKind::Unknown => existing.data_kind,
|
ObjDataKind::Unknown => existing.data_kind,
|
||||||
kind => kind,
|
kind => kind,
|
||||||
},
|
},
|
||||||
|
name_hash: in_symbol.name_hash.or(existing.name_hash),
|
||||||
|
demangled_name_hash: in_symbol.demangled_name_hash.or(existing.demangled_name_hash),
|
||||||
};
|
};
|
||||||
if existing != &new_symbol {
|
if existing != &new_symbol {
|
||||||
log::debug!("Replacing {:?} with {:?}", existing, new_symbol);
|
log::debug!("Replacing {:?} with {:?}", existing, new_symbol);
|
||||||
|
@ -282,6 +287,8 @@ impl ObjSymbols {
|
||||||
kind: in_symbol.kind,
|
kind: in_symbol.kind,
|
||||||
align: in_symbol.align,
|
align: in_symbol.align,
|
||||||
data_kind: in_symbol.data_kind,
|
data_kind: in_symbol.data_kind,
|
||||||
|
name_hash: in_symbol.name_hash,
|
||||||
|
demangled_name_hash: in_symbol.demangled_name_hash,
|
||||||
})?;
|
})?;
|
||||||
target_symbol_idx
|
target_symbol_idx
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
io::{Read, Seek, SeekFrom},
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use io::{Error, ErrorKind};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
obj::{ObjSymbol, ObjSymbolKind},
|
||||||
|
util::{
|
||||||
|
dol::{DolLike, DolSection, DolSectionKind},
|
||||||
|
reader::{
|
||||||
|
read_string, read_vec, read_vec_args, struct_size, Endian, FromReader, DYNAMIC_SIZE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ALF_MAGIC: [u8; 4] = *b"RBOF";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AlfFile {
|
||||||
|
pub header: AlfHeader,
|
||||||
|
pub sections: Vec<DolSection>,
|
||||||
|
pub symbols: Vec<AlfSymbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfFile {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = DYNAMIC_SIZE;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let header = AlfHeader::from_reader(reader, e)?;
|
||||||
|
if !matches!(header.version, 104 | 105) {
|
||||||
|
return Err(Error::new(
|
||||||
|
ErrorKind::InvalidData,
|
||||||
|
format!("unsupported ALF version: {}", header.version),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let alf_sections: Vec<AlfSection> = read_vec(reader, header.section_count as usize, e)?;
|
||||||
|
let symtab =
|
||||||
|
AlfSymTab::from_reader_args(reader, e, AlfVersionArgs { version: header.version })?;
|
||||||
|
|
||||||
|
// Infer section types from data size and symbol typeFs
|
||||||
|
let mut sections = Vec::with_capacity(alf_sections.len());
|
||||||
|
for section in &alf_sections {
|
||||||
|
let kind =
|
||||||
|
if section.data_size == 0 { DolSectionKind::Bss } else { DolSectionKind::Data };
|
||||||
|
sections.push(DolSection {
|
||||||
|
address: section.address,
|
||||||
|
file_offset: section.file_offset,
|
||||||
|
data_size: section.data_size,
|
||||||
|
size: section.size,
|
||||||
|
kind,
|
||||||
|
index: sections.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for sym in &symtab.symbols {
|
||||||
|
// Section IDs are 1-based
|
||||||
|
if sym.section == 0 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "invalid ALF symbol section"));
|
||||||
|
}
|
||||||
|
if sym.kind == AlfSymbolKind::Function {
|
||||||
|
sections[sym.section as usize - 1].kind = DolSectionKind::Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { header, sections, symbols: symtab.symbols })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DolLike for AlfFile {
|
||||||
|
fn sections(&self) -> &[DolSection] { &self.sections }
|
||||||
|
|
||||||
|
fn symbols(&self) -> &[AlfSymbol] { &self.symbols }
|
||||||
|
|
||||||
|
fn entry_point(&self) -> u32 { self.header.entry }
|
||||||
|
|
||||||
|
fn has_unified_bss(&self) -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AlfHeader {
|
||||||
|
pub version: u32,
|
||||||
|
pub entry: u32,
|
||||||
|
pub section_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfHeader {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = struct_size([
|
||||||
|
4, // magic
|
||||||
|
u32::STATIC_SIZE, // version
|
||||||
|
u32::STATIC_SIZE, // entry
|
||||||
|
u32::STATIC_SIZE, // section_count
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
if <[u8; 4]>::from_reader(reader, e)? != ALF_MAGIC {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "invalid ALF magic"));
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
version: <_>::from_reader(reader, e)?,
|
||||||
|
entry: <_>::from_reader(reader, e)?,
|
||||||
|
section_count: <_>::from_reader(reader, e)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AlfSection {
|
||||||
|
pub address: u32,
|
||||||
|
pub data_size: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub file_offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfSection {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = struct_size([
|
||||||
|
u32::STATIC_SIZE, // address
|
||||||
|
u32::STATIC_SIZE, // data_size
|
||||||
|
u32::STATIC_SIZE, // size
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let result = Self {
|
||||||
|
address: <_>::from_reader(reader, e)?,
|
||||||
|
data_size: <_>::from_reader(reader, e)?,
|
||||||
|
size: <_>::from_reader(reader, e)?,
|
||||||
|
file_offset: reader.stream_position()? as u32,
|
||||||
|
};
|
||||||
|
reader.seek(SeekFrom::Current(result.data_size as i64))?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum AlfSymbolKind {
|
||||||
|
Function,
|
||||||
|
Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfSymbolKind {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = u32::STATIC_SIZE;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
match u32::from_reader(reader, e)? {
|
||||||
|
0 => Ok(Self::Function),
|
||||||
|
1 => Ok(Self::Object),
|
||||||
|
v => Err(Error::new(ErrorKind::InvalidData, format!("invalid ALF symbol kind: {}", v))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AlfSymbol {
|
||||||
|
pub name: String,
|
||||||
|
pub demangled_name: String,
|
||||||
|
pub address: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub kind: AlfSymbolKind,
|
||||||
|
pub section: u32,
|
||||||
|
pub unk: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct AlfVersionArgs {
|
||||||
|
pub version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfSymbol {
|
||||||
|
type Args = AlfVersionArgs;
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = DYNAMIC_SIZE;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
Ok(Self {
|
||||||
|
name: read_string::<u32, _>(reader, e)?,
|
||||||
|
demangled_name: read_string::<u32, _>(reader, e)?,
|
||||||
|
address: <_>::from_reader(reader, e)?,
|
||||||
|
size: <_>::from_reader(reader, e)?,
|
||||||
|
kind: <_>::from_reader(reader, e)?,
|
||||||
|
section: <_>::from_reader(reader, e)?,
|
||||||
|
unk: if args.version >= 105 { <_>::from_reader(reader, e)? } else { 0 },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlfSymbol {
|
||||||
|
pub fn to_obj_symbol(&self) -> Result<ObjSymbol> {
|
||||||
|
let kind = match self.kind {
|
||||||
|
AlfSymbolKind::Function => ObjSymbolKind::Function,
|
||||||
|
AlfSymbolKind::Object => ObjSymbolKind::Object,
|
||||||
|
};
|
||||||
|
let (name, name_hash) = if self.name.starts_with('#') {
|
||||||
|
let hash_str = self.name.trim_start_matches('#');
|
||||||
|
let hash = u32::from_str_radix(hash_str, 16)?;
|
||||||
|
let name = match self.kind {
|
||||||
|
AlfSymbolKind::Function => format!("fn_{:08X}", self.address),
|
||||||
|
AlfSymbolKind::Object => format!("lbl_{:08X}", self.address),
|
||||||
|
};
|
||||||
|
(name, Some(hash))
|
||||||
|
} else {
|
||||||
|
(self.name.clone(), None)
|
||||||
|
};
|
||||||
|
let (demangled_name, demangled_name_hash) = if self.demangled_name.starts_with('#') {
|
||||||
|
let hash_str = self.demangled_name.trim_start_matches('#');
|
||||||
|
let hash = u32::from_str_radix(hash_str, 16)?;
|
||||||
|
(None, Some(hash))
|
||||||
|
} else {
|
||||||
|
(Some(self.demangled_name.clone()), None)
|
||||||
|
};
|
||||||
|
Ok(ObjSymbol {
|
||||||
|
name,
|
||||||
|
demangled_name,
|
||||||
|
address: self.address as u64,
|
||||||
|
section: Some(self.section as usize - 1),
|
||||||
|
size: self.size as u64,
|
||||||
|
size_known: true,
|
||||||
|
flags: Default::default(),
|
||||||
|
kind,
|
||||||
|
align: None,
|
||||||
|
data_kind: Default::default(),
|
||||||
|
name_hash,
|
||||||
|
demangled_name_hash,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AlfSymTab {
|
||||||
|
pub symbols: Vec<AlfSymbol>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for AlfSymTab {
|
||||||
|
type Args = AlfVersionArgs;
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = DYNAMIC_SIZE;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let _size = u32::from_reader(reader, e)?;
|
||||||
|
let count = u32::from_reader(reader, e)? as usize;
|
||||||
|
let symbols = read_vec_args(reader, count, e, args)?;
|
||||||
|
Ok(Self { symbols })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ALF_HASH_SEED: u32 = 0x1505;
|
||||||
|
|
||||||
|
pub fn alf_hash(mut h: u32, s: &str) -> u32 {
|
||||||
|
for c in s.bytes() {
|
||||||
|
h *= 33;
|
||||||
|
h ^= c as u32;
|
||||||
|
}
|
||||||
|
h
|
||||||
|
}
|
|
@ -75,18 +75,8 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result<Option<ObjSymb
|
||||||
bail!("Section {} not found", section_name)
|
bail!("Section {} not found", section_name)
|
||||||
};
|
};
|
||||||
let demangled_name = demangle(&name, &DemangleOptions::default());
|
let demangled_name = demangle(&name, &DemangleOptions::default());
|
||||||
let mut symbol = ObjSymbol {
|
let mut symbol =
|
||||||
name,
|
ObjSymbol { name, demangled_name, address: addr as u64, section, ..Default::default() };
|
||||||
demangled_name,
|
|
||||||
address: addr as u64,
|
|
||||||
section,
|
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: Default::default(),
|
|
||||||
kind: ObjSymbolKind::Unknown,
|
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
};
|
|
||||||
// TODO move somewhere common
|
// TODO move somewhere common
|
||||||
if symbol.name.starts_with("..") {
|
if symbol.name.starts_with("..") {
|
||||||
symbol.flags.0 |= ObjSymbolFlags::ForceActive;
|
symbol.flags.0 |= ObjSymbolFlags::ForceActive;
|
||||||
|
@ -114,6 +104,16 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result<Option<ObjSymb
|
||||||
symbol.data_kind = symbol_data_kind_from_str(value)
|
symbol.data_kind = symbol_data_kind_from_str(value)
|
||||||
.ok_or_else(|| anyhow!("Unknown symbol data type '{}'", value))?;
|
.ok_or_else(|| anyhow!("Unknown symbol data type '{}'", value))?;
|
||||||
}
|
}
|
||||||
|
"hash" => {
|
||||||
|
let hash = parse_hex(value)?;
|
||||||
|
symbol.name_hash = Some(hash);
|
||||||
|
if symbol.demangled_name_hash.is_none() {
|
||||||
|
symbol.demangled_name_hash = Some(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"dhash" => {
|
||||||
|
symbol.demangled_name_hash = Some(parse_hex(value)?);
|
||||||
|
}
|
||||||
_ => bail!("Unknown symbol attribute '{name}'"),
|
_ => bail!("Unknown symbol attribute '{name}'"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,7 +163,9 @@ pub fn is_skip_symbol(symbol: &ObjSymbol) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_auto_symbol(symbol: &ObjSymbol) -> bool {
|
pub fn is_auto_symbol(symbol: &ObjSymbol) -> bool {
|
||||||
symbol.name.starts_with("lbl_") || symbol.name.starts_with("fn_")
|
symbol.name.starts_with("lbl_")
|
||||||
|
|| symbol.name.starts_with("fn_")
|
||||||
|
|| symbol.name.starts_with("jumptable_")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -204,6 +206,14 @@ fn write_symbol<W: Write>(w: &mut W, obj: &ObjInfo, symbol: &ObjSymbol) -> Resul
|
||||||
if let Some(kind) = symbol_data_kind_to_str(symbol.data_kind) {
|
if let Some(kind) = symbol_data_kind_to_str(symbol.data_kind) {
|
||||||
write!(w, " data:{kind}")?;
|
write!(w, " data:{kind}")?;
|
||||||
}
|
}
|
||||||
|
if let Some(hash) = symbol.name_hash {
|
||||||
|
write!(w, " hash:{:#010X}", hash)?;
|
||||||
|
}
|
||||||
|
if let Some(hash) = symbol.demangled_name_hash {
|
||||||
|
if symbol.name_hash != symbol.demangled_name_hash {
|
||||||
|
write!(w, " dhash:{:#010X}", hash)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
if symbol.flags.is_hidden() {
|
if symbol.flags.is_hidden() {
|
||||||
write!(w, " hidden")?;
|
write!(w, " hidden")?;
|
||||||
}
|
}
|
||||||
|
|
424
src/util/dol.rs
424
src/util/dol.rs
|
@ -1,7 +1,10 @@
|
||||||
use std::{collections::BTreeMap, io::Cursor};
|
use std::{
|
||||||
|
collections::BTreeMap,
|
||||||
|
io,
|
||||||
|
io::{Cursor, Read, Seek},
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
use dol::{Dol, DolSection, DolSectionType};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::cfa::{locate_sda_bases, SectionAddress},
|
analysis::cfa::{locate_sda_bases, SectionAddress},
|
||||||
|
@ -9,6 +12,10 @@ use crate::{
|
||||||
ObjArchitecture, ObjInfo, ObjKind, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
ObjArchitecture, ObjInfo, ObjKind, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||||
ObjSymbolFlags, ObjSymbolKind,
|
ObjSymbolFlags, ObjSymbolKind,
|
||||||
},
|
},
|
||||||
|
util::{
|
||||||
|
alf::{AlfFile, AlfSymbol},
|
||||||
|
reader::{skip_bytes, Endian, FromReader},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_TEXT_SECTIONS: usize = 7;
|
const MAX_TEXT_SECTIONS: usize = 7;
|
||||||
|
@ -17,34 +24,188 @@ const MAX_ROM_COPY_INFO_SIZE: usize = (MAX_TEXT_SECTIONS + MAX_DATA_SECTIONS + 1
|
||||||
const MAX_BSS_INIT_INFO_SIZE: usize = (MAX_DATA_SECTIONS + 1) * 2 * 4; // num sections * 2 entries * u32
|
const MAX_BSS_INIT_INFO_SIZE: usize = (MAX_DATA_SECTIONS + 1) * 2 * 4; // num sections * 2 entries * u32
|
||||||
const ETI_INIT_INFO_SIZE: usize = 16; // eti_start, eti_end, code_start, code_size
|
const ETI_INIT_INFO_SIZE: usize = 16; // eti_start, eti_end, code_start, code_size
|
||||||
|
|
||||||
fn read_u32(dol: &Dol, addr: u32) -> Result<u32> {
|
/// Unified trait for DOL and ALF files
|
||||||
Ok(u32::from_be_bytes(dol.virtual_data_at(addr, 4)?.try_into()?))
|
pub trait DolLike {
|
||||||
|
fn sections(&self) -> &[DolSection];
|
||||||
|
|
||||||
|
fn symbols(&self) -> &[AlfSymbol] { &[] }
|
||||||
|
|
||||||
|
fn entry_point(&self) -> u32;
|
||||||
|
|
||||||
|
fn has_unified_bss(&self) -> bool;
|
||||||
|
|
||||||
|
fn section_by_address(&self, addr: u32) -> Option<&DolSection> {
|
||||||
|
self.sections()
|
||||||
|
.iter()
|
||||||
|
.find(|section| addr >= section.address && addr < section.address + section.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn virtual_data_at<'a>(&self, buf: &'a [u8], addr: u32, size: u32) -> Result<&'a [u8]> {
|
||||||
|
let section = self
|
||||||
|
.section_by_address(addr)
|
||||||
|
.ok_or_else(|| anyhow!("Failed to locate section for address {:#010X}", addr))?;
|
||||||
|
let offset = addr - section.address;
|
||||||
|
ensure!(
|
||||||
|
offset + size <= section.size,
|
||||||
|
"Invalid virtual data range {:#010X}-{:#010X} (section: {:#010X}-{:#010X})",
|
||||||
|
addr,
|
||||||
|
addr + size,
|
||||||
|
section.address,
|
||||||
|
section.address + section.size
|
||||||
|
);
|
||||||
|
let offset = section.file_offset as usize + offset as usize;
|
||||||
|
Ok(&buf[offset..offset + size as usize])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum DolSectionKind {
|
||||||
|
Text,
|
||||||
|
Data,
|
||||||
|
Bss,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DolSection {
|
||||||
|
pub address: u32,
|
||||||
|
pub file_offset: u32,
|
||||||
|
pub data_size: u32,
|
||||||
|
pub size: u32,
|
||||||
|
pub kind: DolSectionKind,
|
||||||
|
// TODO remove
|
||||||
|
pub index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DolFile {
|
||||||
|
pub header: DolHeader,
|
||||||
|
pub sections: Vec<DolSection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for DolFile {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = DolHeader::STATIC_SIZE;
|
||||||
|
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let header = DolHeader::from_reader(reader, e)?;
|
||||||
|
let mut sections = Vec::with_capacity(header.text_sizes.len() + header.data_sizes.len());
|
||||||
|
for (idx, &size) in header.text_sizes.iter().enumerate() {
|
||||||
|
if size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sections.push(DolSection {
|
||||||
|
address: header.text_addrs[idx],
|
||||||
|
file_offset: header.text_offs[idx],
|
||||||
|
data_size: size,
|
||||||
|
size,
|
||||||
|
kind: DolSectionKind::Text,
|
||||||
|
index: sections.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (idx, &size) in header.data_sizes.iter().enumerate() {
|
||||||
|
if size == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sections.push(DolSection {
|
||||||
|
address: header.data_addrs[idx],
|
||||||
|
file_offset: header.data_offs[idx],
|
||||||
|
data_size: size,
|
||||||
|
size,
|
||||||
|
kind: DolSectionKind::Data,
|
||||||
|
index: sections.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sections.push(DolSection {
|
||||||
|
address: header.bss_addr,
|
||||||
|
file_offset: 0,
|
||||||
|
data_size: 0,
|
||||||
|
size: header.bss_size,
|
||||||
|
kind: DolSectionKind::Bss,
|
||||||
|
index: sections.len(),
|
||||||
|
});
|
||||||
|
Ok(Self { header, sections })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DolHeader {
|
||||||
|
pub text_offs: [u32; MAX_TEXT_SECTIONS],
|
||||||
|
pub data_offs: [u32; MAX_DATA_SECTIONS],
|
||||||
|
pub text_addrs: [u32; MAX_TEXT_SECTIONS],
|
||||||
|
pub data_addrs: [u32; MAX_DATA_SECTIONS],
|
||||||
|
pub text_sizes: [u32; MAX_TEXT_SECTIONS],
|
||||||
|
pub data_sizes: [u32; MAX_DATA_SECTIONS],
|
||||||
|
pub bss_addr: u32,
|
||||||
|
pub bss_size: u32,
|
||||||
|
pub entry_point: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromReader for DolHeader {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = 0x100;
|
||||||
|
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let result = Self {
|
||||||
|
text_offs: <_>::from_reader(reader, e)?,
|
||||||
|
data_offs: <_>::from_reader(reader, e)?,
|
||||||
|
text_addrs: <_>::from_reader(reader, e)?,
|
||||||
|
data_addrs: <_>::from_reader(reader, e)?,
|
||||||
|
text_sizes: <_>::from_reader(reader, e)?,
|
||||||
|
data_sizes: <_>::from_reader(reader, e)?,
|
||||||
|
bss_addr: <_>::from_reader(reader, e)?,
|
||||||
|
bss_size: <_>::from_reader(reader, e)?,
|
||||||
|
entry_point: <_>::from_reader(reader, e)?,
|
||||||
|
};
|
||||||
|
skip_bytes::<0x1C, _>(reader)?; // padding
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DolLike for DolFile {
|
||||||
|
fn sections(&self) -> &[DolSection] { &self.sections }
|
||||||
|
|
||||||
|
fn entry_point(&self) -> u32 { self.header.entry_point }
|
||||||
|
|
||||||
|
fn has_unified_bss(&self) -> bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(buf: &[u8], dol: &dyn DolLike, addr: u32) -> Result<u32> {
|
||||||
|
Ok(u32::from_be_bytes(dol.virtual_data_at(buf, addr, 4)?.try_into()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
let dol = Dol::read_from(Cursor::new(buf))?;
|
let mut reader = Cursor::new(buf);
|
||||||
|
let dol: Box<dyn DolLike> = if buf.len() > 4 && &buf[0..4] == b"RBOF" {
|
||||||
|
Box::new(AlfFile::from_reader(&mut reader, Endian::Little)?)
|
||||||
|
} else {
|
||||||
|
Box::new(DolFile::from_reader(&mut reader, Endian::Big)?)
|
||||||
|
};
|
||||||
|
|
||||||
// Locate _rom_copy_info
|
// Locate _rom_copy_info
|
||||||
let first_rom_section = dol
|
let first_rom_section = dol
|
||||||
.header
|
.sections()
|
||||||
.sections
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|section| section.kind != DolSectionType::Bss)
|
.find(|section| section.kind != DolSectionKind::Bss)
|
||||||
.ok_or_else(|| anyhow!("Failed to locate first rom section"))?;
|
.ok_or_else(|| anyhow!("Failed to locate first rom section"))?;
|
||||||
let init_section = section_by_address(&dol, dol.header.entry_point)
|
let init_section = dol
|
||||||
|
.section_by_address(dol.entry_point())
|
||||||
.ok_or_else(|| anyhow!("Failed to locate .init section"))?;
|
.ok_or_else(|| anyhow!("Failed to locate .init section"))?;
|
||||||
let rom_copy_info_addr = {
|
let rom_copy_info_addr = {
|
||||||
let mut addr = init_section.target + init_section.size
|
let mut addr = init_section.address + init_section.size
|
||||||
- MAX_ROM_COPY_INFO_SIZE as u32
|
- MAX_ROM_COPY_INFO_SIZE as u32
|
||||||
- MAX_BSS_INIT_INFO_SIZE as u32;
|
- MAX_BSS_INIT_INFO_SIZE as u32;
|
||||||
loop {
|
loop {
|
||||||
let value = read_u32(&dol, addr)?;
|
let value = read_u32(buf, dol.as_ref(), addr)?;
|
||||||
if value == first_rom_section.target {
|
if value == first_rom_section.address {
|
||||||
log::debug!("Found _rom_copy_info @ {addr:#010X}");
|
log::debug!("Found _rom_copy_info @ {addr:#010X}");
|
||||||
break Some(addr);
|
break Some(addr);
|
||||||
}
|
}
|
||||||
addr += 4;
|
addr += 4;
|
||||||
if addr >= init_section.target + init_section.size {
|
if addr >= init_section.address + init_section.size {
|
||||||
log::warn!("Failed to locate _rom_copy_info");
|
log::warn!("Failed to locate _rom_copy_info");
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
|
@ -55,19 +216,19 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
let mut rom_sections = BTreeMap::<u32, u32>::new();
|
let mut rom_sections = BTreeMap::<u32, u32>::new();
|
||||||
let rom_copy_info_end = match rom_copy_info_addr {
|
let rom_copy_info_end = match rom_copy_info_addr {
|
||||||
Some(mut addr) => loop {
|
Some(mut addr) => loop {
|
||||||
let rom = read_u32(&dol, addr)?;
|
let rom = read_u32(buf, dol.as_ref(), addr)?;
|
||||||
let copy = read_u32(&dol, addr + 4)?;
|
let copy = read_u32(buf, dol.as_ref(), addr + 4)?;
|
||||||
ensure!(
|
ensure!(
|
||||||
rom == copy,
|
rom == copy,
|
||||||
"Unsupported section: ROM address {rom:#010X} != copy address {copy:#010X}",
|
"Unsupported section: ROM address {rom:#010X} != copy address {copy:#010X}",
|
||||||
);
|
);
|
||||||
let size = read_u32(&dol, addr + 8)?;
|
let size = read_u32(buf, dol.as_ref(), addr + 8)?;
|
||||||
addr += 12;
|
addr += 12;
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
log::debug!("Found _rom_copy_info end @ {addr:#010X}");
|
log::debug!("Found _rom_copy_info end @ {addr:#010X}");
|
||||||
break Some(addr);
|
break Some(addr);
|
||||||
}
|
}
|
||||||
if addr >= init_section.target + init_section.size {
|
if addr >= init_section.address + init_section.size {
|
||||||
log::warn!("Failed to locate _rom_copy_info end");
|
log::warn!("Failed to locate _rom_copy_info end");
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
|
@ -78,20 +239,19 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
|
|
||||||
// Locate _bss_init_info
|
// Locate _bss_init_info
|
||||||
let bss_section = dol
|
let bss_section = dol
|
||||||
.header
|
.sections()
|
||||||
.sections
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|section| section.kind == DolSectionType::Bss)
|
.find(|section| section.kind == DolSectionKind::Bss)
|
||||||
.ok_or_else(|| anyhow!("Failed to locate BSS section"))?;
|
.ok_or_else(|| anyhow!("Failed to locate BSS section"))?;
|
||||||
let bss_init_info_addr = match rom_copy_info_end {
|
let bss_init_info_addr = match rom_copy_info_end {
|
||||||
Some(mut addr) => loop {
|
Some(mut addr) => loop {
|
||||||
let value = read_u32(&dol, addr)?;
|
let value = read_u32(buf, dol.as_ref(), addr)?;
|
||||||
if value == bss_section.target {
|
if value == bss_section.address {
|
||||||
log::debug!("Found _bss_init_info @ {addr:#010X}");
|
log::debug!("Found _bss_init_info @ {addr:#010X}");
|
||||||
break Some(addr);
|
break Some(addr);
|
||||||
}
|
}
|
||||||
addr += 4;
|
addr += 4;
|
||||||
if addr >= init_section.target + init_section.size {
|
if addr >= init_section.address + init_section.size {
|
||||||
log::warn!("Failed to locate _bss_init_info");
|
log::warn!("Failed to locate _bss_init_info");
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
|
@ -103,14 +263,14 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
let mut bss_sections = BTreeMap::<u32, u32>::new();
|
let mut bss_sections = BTreeMap::<u32, u32>::new();
|
||||||
let bss_init_info_end = match bss_init_info_addr {
|
let bss_init_info_end = match bss_init_info_addr {
|
||||||
Some(mut addr) => loop {
|
Some(mut addr) => loop {
|
||||||
let rom = read_u32(&dol, addr)?;
|
let rom = read_u32(buf, dol.as_ref(), addr)?;
|
||||||
let size = read_u32(&dol, addr + 4)?;
|
let size = read_u32(buf, dol.as_ref(), addr + 4)?;
|
||||||
addr += 8;
|
addr += 8;
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
log::debug!("Found _bss_init_info end @ {addr:#010X}");
|
log::debug!("Found _bss_init_info end @ {addr:#010X}");
|
||||||
break Some(addr);
|
break Some(addr);
|
||||||
}
|
}
|
||||||
if addr >= init_section.target + init_section.size {
|
if addr >= init_section.address + init_section.size {
|
||||||
log::warn!("Failed to locate _bss_init_info end");
|
log::warn!("Failed to locate _bss_init_info end");
|
||||||
break None;
|
break None;
|
||||||
}
|
}
|
||||||
|
@ -121,27 +281,27 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
|
|
||||||
// Locate _eti_init_info
|
// Locate _eti_init_info
|
||||||
let num_text_sections =
|
let num_text_sections =
|
||||||
dol.header.sections.iter().filter(|section| section.kind == DolSectionType::Text).count();
|
dol.sections().iter().filter(|section| section.kind == DolSectionKind::Text).count();
|
||||||
let mut eti_entries: Vec<EtiEntry> = Vec::new();
|
let mut eti_entries: Vec<EtiEntry> = Vec::new();
|
||||||
let mut eti_init_info_range: Option<(u32, u32)> = None;
|
let mut eti_init_info_range: Option<(u32, u32)> = None;
|
||||||
let mut extab_section: Option<usize> = None;
|
let mut extab_section: Option<usize> = None;
|
||||||
let mut extabindex_section: Option<usize> = None;
|
let mut extabindex_section: Option<usize> = None;
|
||||||
'outer: for dol_section in
|
'outer: for dol_section in
|
||||||
dol.header.sections.iter().filter(|section| section.kind == DolSectionType::Data)
|
dol.sections().iter().filter(|section| section.kind == DolSectionKind::Data)
|
||||||
{
|
{
|
||||||
// Use section size from _rom_copy_info
|
// Use section size from _rom_copy_info
|
||||||
let dol_section_size = match rom_sections.get(&dol_section.target) {
|
let dol_section_size = match rom_sections.get(&dol_section.address) {
|
||||||
Some(&size) => size,
|
Some(&size) => size,
|
||||||
None => dol_section.size,
|
None => dol_section.size,
|
||||||
};
|
};
|
||||||
let dol_section_end = dol_section.target + dol_section_size;
|
let dol_section_end = dol_section.address + dol_section_size;
|
||||||
|
|
||||||
let eti_init_info_addr = {
|
let eti_init_info_addr = {
|
||||||
let mut addr = dol_section_end - (ETI_INIT_INFO_SIZE * (num_text_sections + 1)) as u32;
|
let mut addr = dol_section_end - (ETI_INIT_INFO_SIZE * (num_text_sections + 1)) as u32;
|
||||||
loop {
|
loop {
|
||||||
let eti_init_info = read_eti_init_info(&dol, addr)?;
|
let eti_init_info = read_eti_init_info(buf, dol.as_ref(), addr)?;
|
||||||
if validate_eti_init_info(
|
if validate_eti_init_info(
|
||||||
&dol,
|
dol.as_ref(),
|
||||||
&eti_init_info,
|
&eti_init_info,
|
||||||
dol_section,
|
dol_section,
|
||||||
dol_section_end,
|
dol_section_end,
|
||||||
|
@ -160,7 +320,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
let eti_init_info_end = {
|
let eti_init_info_end = {
|
||||||
let mut addr = eti_init_info_addr;
|
let mut addr = eti_init_info_addr;
|
||||||
loop {
|
loop {
|
||||||
let eti_init_info = read_eti_init_info(&dol, addr)?;
|
let eti_init_info = read_eti_init_info(buf, dol.as_ref(), addr)?;
|
||||||
addr += 16;
|
addr += 16;
|
||||||
if eti_init_info.is_zero() {
|
if eti_init_info.is_zero() {
|
||||||
break;
|
break;
|
||||||
|
@ -172,7 +332,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if !validate_eti_init_info(
|
if !validate_eti_init_info(
|
||||||
&dol,
|
dol.as_ref(),
|
||||||
&eti_init_info,
|
&eti_init_info,
|
||||||
dol_section,
|
dol_section,
|
||||||
dol_section_end,
|
dol_section_end,
|
||||||
|
@ -181,9 +341,9 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
bail!("Invalid _eti_init_info entry: {:#010X?}", eti_init_info);
|
bail!("Invalid _eti_init_info entry: {:#010X?}", eti_init_info);
|
||||||
}
|
}
|
||||||
for addr in (eti_init_info.eti_start..eti_init_info.eti_end).step_by(12) {
|
for addr in (eti_init_info.eti_start..eti_init_info.eti_end).step_by(12) {
|
||||||
let eti_entry = read_eti_entry(&dol, addr)?;
|
let eti_entry = read_eti_entry(buf, dol.as_ref(), addr)?;
|
||||||
let entry_section =
|
let entry_section =
|
||||||
section_by_address(&dol, eti_entry.extab_addr).ok_or_else(|| {
|
dol.section_by_address(eti_entry.extab_addr).ok_or_else(|| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to locate section for extab address {:#010X}",
|
"Failed to locate section for extab address {:#010X}",
|
||||||
eti_entry.extab_addr
|
eti_entry.extab_addr
|
||||||
|
@ -216,9 +376,12 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
|
|
||||||
// Add text and data sections
|
// Add text and data sections
|
||||||
let mut sections = vec![];
|
let mut sections = vec![];
|
||||||
for dol_section in
|
for dol_section in dol.sections().iter() {
|
||||||
dol.header.sections.iter().filter(|section| section.kind != DolSectionType::Bss)
|
// We'll split .bss later
|
||||||
{
|
if dol_section.kind == DolSectionKind::Bss && dol.has_unified_bss() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let (name, kind, known) = match dol_section.index {
|
let (name, kind, known) = match dol_section.index {
|
||||||
idx if idx == init_section.index => (".init".to_string(), ObjSectionKind::Code, true),
|
idx if idx == init_section.index => (".init".to_string(), ObjSectionKind::Code, true),
|
||||||
idx if Some(idx) == extab_section => {
|
idx if Some(idx) == extab_section => {
|
||||||
|
@ -227,79 +390,86 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
idx if Some(idx) == extabindex_section => {
|
idx if Some(idx) == extabindex_section => {
|
||||||
("extabindex".to_string(), ObjSectionKind::ReadOnlyData, true)
|
("extabindex".to_string(), ObjSectionKind::ReadOnlyData, true)
|
||||||
}
|
}
|
||||||
_ if num_text_sections == 2 && dol_section.kind == DolSectionType::Text => {
|
_ if num_text_sections == 2 && dol_section.kind == DolSectionKind::Text => {
|
||||||
(".text".to_string(), ObjSectionKind::Code, true)
|
(".text".to_string(), ObjSectionKind::Code, true)
|
||||||
}
|
}
|
||||||
idx => match dol_section.kind {
|
idx => match dol_section.kind {
|
||||||
DolSectionType::Text => (format!(".text{idx}"), ObjSectionKind::Code, false),
|
DolSectionKind::Text => (format!(".text{idx}"), ObjSectionKind::Code, false),
|
||||||
DolSectionType::Data => (format!(".data{idx}"), ObjSectionKind::Data, false),
|
DolSectionKind::Data => (format!(".data{idx}"), ObjSectionKind::Data, false),
|
||||||
DolSectionType::Bss => unreachable!(),
|
DolSectionKind::Bss => (format!(".bss{}", idx), ObjSectionKind::Bss, false),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use section size from _rom_copy_info
|
let (size, data): (u32, &[u8]) = if kind == ObjSectionKind::Bss {
|
||||||
let size = match rom_sections.get(&dol_section.target) {
|
(dol_section.size, &[])
|
||||||
Some(&size) => size,
|
} else {
|
||||||
None => {
|
// Use section size from _rom_copy_info
|
||||||
if !rom_sections.is_empty() {
|
let size = match rom_sections.get(&dol_section.address) {
|
||||||
log::warn!(
|
Some(&size) => size,
|
||||||
"Section {} ({:#010X}) doesn't exist in _rom_copy_info",
|
None => {
|
||||||
dol_section.index,
|
if !rom_sections.is_empty() {
|
||||||
dol_section.target
|
log::warn!(
|
||||||
);
|
"Section {} ({:#010X}) doesn't exist in _rom_copy_info",
|
||||||
|
dol_section.index,
|
||||||
|
dol_section.address
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dol_section.size
|
||||||
}
|
}
|
||||||
dol_section.size
|
};
|
||||||
}
|
(size, dol.virtual_data_at(buf, dol_section.address, size)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
sections.push(ObjSection {
|
sections.push(ObjSection {
|
||||||
name,
|
name,
|
||||||
kind,
|
kind,
|
||||||
address: dol_section.target as u64,
|
address: dol_section.address as u64,
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
data: dol.virtual_data_at(dol_section.target, size)?.to_vec(),
|
data: data.to_vec(),
|
||||||
align: 0,
|
align: 0,
|
||||||
elf_index: 0,
|
elf_index: 0,
|
||||||
relocations: Default::default(),
|
relocations: Default::default(),
|
||||||
original_address: 0,
|
original_address: 0,
|
||||||
file_offset: dol_section.offset as u64,
|
file_offset: dol_section.file_offset as u64,
|
||||||
section_known: known,
|
section_known: known,
|
||||||
splits: Default::default(),
|
splits: Default::default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add BSS sections from _bss_init_info
|
if dol.has_unified_bss() {
|
||||||
for (idx, (&addr, &size)) in bss_sections.iter().enumerate() {
|
// Add BSS sections from _bss_init_info
|
||||||
ensure!(
|
for (idx, (&addr, &size)) in bss_sections.iter().enumerate() {
|
||||||
addr >= bss_section.target
|
ensure!(
|
||||||
&& addr < bss_section.target + bss_section.size
|
addr >= bss_section.address
|
||||||
&& addr + size <= bss_section.target + bss_section.size,
|
&& addr < bss_section.address + bss_section.size
|
||||||
"Invalid BSS range {:#010X}-{:#010X} (DOL BSS: {:#010X}-{:#010X})",
|
&& addr + size <= bss_section.address + bss_section.size,
|
||||||
addr,
|
"Invalid BSS range {:#010X}-{:#010X} (DOL BSS: {:#010X}-{:#010X})",
|
||||||
addr + size,
|
addr,
|
||||||
bss_section.target,
|
addr + size,
|
||||||
bss_section.target + bss_section.size
|
bss_section.address,
|
||||||
);
|
bss_section.address + bss_section.size
|
||||||
|
);
|
||||||
|
|
||||||
sections.push(ObjSection {
|
sections.push(ObjSection {
|
||||||
name: format!(".bss{}", idx),
|
name: format!(".bss{}", idx),
|
||||||
kind: ObjSectionKind::Bss,
|
kind: ObjSectionKind::Bss,
|
||||||
address: addr as u64,
|
address: addr as u64,
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
data: vec![],
|
data: vec![],
|
||||||
align: 0,
|
align: 0,
|
||||||
elf_index: 0,
|
elf_index: 0,
|
||||||
relocations: Default::default(),
|
relocations: Default::default(),
|
||||||
original_address: 0,
|
original_address: 0,
|
||||||
file_offset: 0,
|
file_offset: 0,
|
||||||
section_known: false,
|
section_known: false,
|
||||||
splits: Default::default(),
|
splits: Default::default(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sections by address ascending
|
||||||
|
sections.sort_by_key(|s| s.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort sections by address ascending
|
|
||||||
sections.sort_by_key(|s| s.address);
|
|
||||||
|
|
||||||
// Apply section indices
|
// Apply section indices
|
||||||
let mut init_section_index = None;
|
let mut init_section_index = None;
|
||||||
for (idx, section) in sections.iter_mut().enumerate() {
|
for (idx, section) in sections.iter_mut().enumerate() {
|
||||||
|
@ -328,7 +498,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
vec![],
|
vec![],
|
||||||
sections,
|
sections,
|
||||||
);
|
);
|
||||||
obj.entry = Some(dol.header.entry_point as u64);
|
obj.entry = Some(dol.entry_point() as u64);
|
||||||
|
|
||||||
// Generate _rom_copy_info symbol
|
// Generate _rom_copy_info symbol
|
||||||
if let (Some(rom_copy_info_addr), Some(rom_copy_info_end)) =
|
if let (Some(rom_copy_info_addr), Some(rom_copy_info_end)) =
|
||||||
|
@ -337,15 +507,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "_rom_copy_info".to_string(),
|
name: "_rom_copy_info".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: rom_copy_info_addr as u64,
|
address: rom_copy_info_addr as u64,
|
||||||
section: init_section_index,
|
section: init_section_index,
|
||||||
size: (rom_copy_info_end - rom_copy_info_addr) as u64,
|
size: (rom_copy_info_end - rom_copy_info_addr) as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -358,15 +526,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "_bss_init_info".to_string(),
|
name: "_bss_init_info".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: bss_init_info_addr as u64,
|
address: bss_init_info_addr as u64,
|
||||||
section: init_section_index,
|
section: init_section_index,
|
||||||
size: (bss_init_info_end - bss_init_info_addr) as u64,
|
size: (bss_init_info_end - bss_init_info_addr) as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -377,15 +543,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "_eti_init_info".to_string(),
|
name: "_eti_init_info".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: eti_init_info_addr as u64,
|
address: eti_init_info_addr as u64,
|
||||||
section: extabindex_section,
|
section: extabindex_section,
|
||||||
size: (eti_init_info_end - eti_init_info_addr) as u64,
|
size: (eti_init_info_end - eti_init_info_addr) as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -424,15 +588,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: format!("@eti_{:08X}", entry.address),
|
name: format!("@eti_{:08X}", entry.address),
|
||||||
demangled_name: None,
|
|
||||||
address: entry.address as u64,
|
address: entry.address as u64,
|
||||||
section: Some(extabindex_section_index),
|
section: Some(extabindex_section_index),
|
||||||
size: 12,
|
size: 12,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
@ -451,15 +613,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: format!("@etb_{:08X}", addr),
|
name: format!("@etb_{:08X}", addr),
|
||||||
demangled_name: None,
|
|
||||||
address: addr as u64,
|
address: addr as u64,
|
||||||
section: Some(extab_section_index),
|
section: Some(extab_section_index),
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
||||||
kind: ObjSymbolKind::Object,
|
kind: ObjSymbolKind::Object,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
@ -504,30 +664,20 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "_SDA2_BASE_".to_string(),
|
name: "_SDA2_BASE_".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: sda2_base as u64,
|
address: sda2_base as u64,
|
||||||
section: None,
|
size_known: true,
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
obj.add_symbol(
|
obj.add_symbol(
|
||||||
ObjSymbol {
|
ObjSymbol {
|
||||||
name: "_SDA_BASE_".to_string(),
|
name: "_SDA_BASE_".to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: sda_base as u64,
|
address: sda_base as u64,
|
||||||
section: None,
|
size_known: true,
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Unknown,
|
..Default::default()
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -540,6 +690,11 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply ALF symbols
|
||||||
|
for symbol in dol.symbols() {
|
||||||
|
obj.add_symbol(symbol.to_obj_symbol()?, true)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,35 +721,35 @@ struct EtiEntry {
|
||||||
extab_addr: u32,
|
extab_addr: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_eti_init_info(dol: &Dol, addr: u32) -> Result<EtiInitInfo> {
|
fn read_eti_init_info(buf: &[u8], dol: &dyn DolLike, addr: u32) -> Result<EtiInitInfo> {
|
||||||
let eti_start = read_u32(dol, addr)?;
|
let eti_start = read_u32(buf, dol, addr)?;
|
||||||
let eti_end = read_u32(dol, addr + 4)?;
|
let eti_end = read_u32(buf, dol, addr + 4)?;
|
||||||
let code_start = read_u32(dol, addr + 8)?;
|
let code_start = read_u32(buf, dol, addr + 8)?;
|
||||||
let code_size = read_u32(dol, addr + 12)?;
|
let code_size = read_u32(buf, dol, addr + 12)?;
|
||||||
Ok(EtiInitInfo { eti_start, eti_end, code_start, code_size })
|
Ok(EtiInitInfo { eti_start, eti_end, code_start, code_size })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_eti_entry(dol: &Dol, address: u32) -> Result<EtiEntry> {
|
fn read_eti_entry(buf: &[u8], dol: &dyn DolLike, address: u32) -> Result<EtiEntry> {
|
||||||
let function = read_u32(dol, address)?;
|
let function = read_u32(buf, dol, address)?;
|
||||||
let function_size = read_u32(dol, address + 4)?;
|
let function_size = read_u32(buf, dol, address + 4)?;
|
||||||
let extab_addr = read_u32(dol, address + 8)?;
|
let extab_addr = read_u32(buf, dol, address + 8)?;
|
||||||
Ok(EtiEntry { address, function, function_size, extab_addr })
|
Ok(EtiEntry { address, function, function_size, extab_addr })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_eti_init_info(
|
fn validate_eti_init_info(
|
||||||
dol: &Dol,
|
dol: &dyn DolLike,
|
||||||
eti_init_info: &EtiInitInfo,
|
eti_init_info: &EtiInitInfo,
|
||||||
eti_section: &DolSection,
|
eti_section: &DolSection,
|
||||||
eti_section_end: u32,
|
eti_section_end: u32,
|
||||||
rom_sections: &BTreeMap<u32, u32>,
|
rom_sections: &BTreeMap<u32, u32>,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
if eti_init_info.eti_start >= eti_section.target
|
if eti_init_info.eti_start >= eti_section.address
|
||||||
&& eti_init_info.eti_start < eti_section_end
|
&& eti_init_info.eti_start < eti_section_end
|
||||||
&& eti_init_info.eti_end >= eti_section.target
|
&& eti_init_info.eti_end >= eti_section.address
|
||||||
&& eti_init_info.eti_end < eti_section_end
|
&& eti_init_info.eti_end < eti_section_end
|
||||||
{
|
{
|
||||||
if let Some(code_section) = section_by_address(dol, eti_init_info.code_start) {
|
if let Some(code_section) = dol.section_by_address(eti_init_info.code_start) {
|
||||||
let code_section_size = match rom_sections.get(&code_section.target) {
|
let code_section_size = match rom_sections.get(&code_section.address) {
|
||||||
Some(&size) => size,
|
Some(&size) => size,
|
||||||
None => code_section.size,
|
None => code_section.size,
|
||||||
};
|
};
|
||||||
|
@ -605,10 +760,3 @@ fn validate_eti_init_info(
|
||||||
}
|
}
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn section_by_address(dol: &Dol, addr: u32) -> Option<&DolSection> {
|
|
||||||
dol.header
|
|
||||||
.sections
|
|
||||||
.iter()
|
|
||||||
.find(|section| addr >= section.target && addr < section.target + section.size)
|
|
||||||
}
|
|
||||||
|
|
|
@ -816,7 +816,7 @@ fn to_obj_symbol(
|
||||||
_ => bail!("Unsupported symbol kind: {:?}", symbol),
|
_ => bail!("Unsupported symbol kind: {:?}", symbol),
|
||||||
},
|
},
|
||||||
align,
|
align,
|
||||||
data_kind: Default::default(),
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -688,7 +688,7 @@ fn add_symbol(obj: &mut ObjInfo, symbol_entry: &SymbolEntry, section: Option<usi
|
||||||
SymbolKind::NoType => ObjSymbolKind::Unknown,
|
SymbolKind::NoType => ObjSymbolKind::Unknown,
|
||||||
},
|
},
|
||||||
align: symbol_entry.align,
|
align: symbol_entry.align,
|
||||||
data_kind: Default::default(),
|
..Default::default()
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{borrow::Cow, ops::Deref};
|
use std::{borrow::Cow, ops::Deref};
|
||||||
|
|
||||||
|
pub mod alf;
|
||||||
pub mod asm;
|
pub mod asm;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
@ -12,6 +13,7 @@ pub mod lcf;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod nested;
|
pub mod nested;
|
||||||
pub mod rarc;
|
pub mod rarc;
|
||||||
|
pub mod reader;
|
||||||
pub mod rel;
|
pub mod rel;
|
||||||
pub mod rso;
|
pub mod rso;
|
||||||
pub mod signatures;
|
pub mod signatures;
|
||||||
|
|
|
@ -0,0 +1,249 @@
|
||||||
|
use std::{
|
||||||
|
io,
|
||||||
|
io::{Error, ErrorKind, Read, Seek, SeekFrom},
|
||||||
|
};
|
||||||
|
|
||||||
|
use io::Write;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Endian {
|
||||||
|
Big,
|
||||||
|
Little,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DYNAMIC_SIZE: usize = 0;
|
||||||
|
|
||||||
|
pub const fn struct_size<const N: usize>(fields: [usize; N]) -> usize {
|
||||||
|
let mut result = 0;
|
||||||
|
let mut i = 0;
|
||||||
|
while i < N {
|
||||||
|
let size = fields[i];
|
||||||
|
if size == DYNAMIC_SIZE {
|
||||||
|
// Dynamically sized
|
||||||
|
return DYNAMIC_SIZE;
|
||||||
|
}
|
||||||
|
result += size;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn skip_bytes<const N: usize, R>(reader: &mut R) -> io::Result<()>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
reader.seek(SeekFrom::Current(N as i64))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromReader: Sized {
|
||||||
|
type Args;
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize;
|
||||||
|
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized;
|
||||||
|
|
||||||
|
fn from_reader<R>(reader: &mut R, e: Endian) -> io::Result<Self>
|
||||||
|
where
|
||||||
|
R: Read + Seek + ?Sized,
|
||||||
|
Self::Args: Default,
|
||||||
|
{
|
||||||
|
Self::from_reader_args(reader, e, Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_reader {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl FromReader for $t {
|
||||||
|
const STATIC_SIZE: usize = std::mem::size_of::<Self>();
|
||||||
|
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let mut buf = [0u8; Self::STATIC_SIZE];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
Ok(match e {
|
||||||
|
Endian::Big => Self::from_be_bytes(buf),
|
||||||
|
Endian::Little => Self::from_le_bytes(buf),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_reader!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
|
||||||
|
|
||||||
|
impl<const N: usize> FromReader for [u8; N] {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = N;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, _e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let mut buf = [0u8; N];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> FromReader for [u32; N] {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
const STATIC_SIZE: usize = N * u32::STATIC_SIZE;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_reader_args<R>(reader: &mut R, e: Endian, _args: Self::Args) -> io::Result<Self>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let mut buf = [0u32; N];
|
||||||
|
reader.read_exact(unsafe {
|
||||||
|
std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, Self::STATIC_SIZE)
|
||||||
|
})?;
|
||||||
|
if e == Endian::Big {
|
||||||
|
for x in buf.iter_mut() {
|
||||||
|
*x = u32::from_be(*x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_bytes<R>(reader: &mut R, count: usize) -> io::Result<Vec<u8>>
|
||||||
|
where R: Read + Seek + ?Sized {
|
||||||
|
let mut buf = vec![0u8; count];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_vec<T, R>(reader: &mut R, count: usize, e: Endian) -> io::Result<Vec<T>>
|
||||||
|
where
|
||||||
|
T: FromReader,
|
||||||
|
T::Args: Default,
|
||||||
|
R: Read + Seek + ?Sized,
|
||||||
|
{
|
||||||
|
let mut vec = Vec::with_capacity(count);
|
||||||
|
for _ in 0..count {
|
||||||
|
vec.push(T::from_reader(reader, e)?);
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_vec_args<T, R>(
|
||||||
|
reader: &mut R,
|
||||||
|
count: usize,
|
||||||
|
e: Endian,
|
||||||
|
args: T::Args,
|
||||||
|
) -> io::Result<Vec<T>>
|
||||||
|
where
|
||||||
|
T: FromReader,
|
||||||
|
T::Args: Clone,
|
||||||
|
R: Read + Seek + ?Sized,
|
||||||
|
{
|
||||||
|
let mut vec = Vec::with_capacity(count);
|
||||||
|
for _ in 0..count {
|
||||||
|
vec.push(T::from_reader_args(reader, e, args.clone())?);
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_string<T, R>(reader: &mut R, e: Endian) -> io::Result<String>
|
||||||
|
where
|
||||||
|
T: FromReader + TryInto<usize>,
|
||||||
|
T::Args: Default,
|
||||||
|
R: Read + Seek + ?Sized,
|
||||||
|
{
|
||||||
|
let len = <T>::from_reader(reader, e)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::new(ErrorKind::InvalidData, "invalid string length"))?;
|
||||||
|
let mut buf = vec![0u8; len];
|
||||||
|
reader.read_exact(&mut buf)?;
|
||||||
|
String::from_utf8(buf).map_err(|e| Error::new(ErrorKind::InvalidData, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToWriter: Sized {
|
||||||
|
fn to_writer<W>(&self, writer: &mut W, e: Endian) -> io::Result<()>
|
||||||
|
where W: Write + ?Sized;
|
||||||
|
|
||||||
|
fn to_bytes(&self, e: Endian) -> io::Result<Vec<u8>> {
|
||||||
|
let mut buf = vec![0u8; self.write_size()];
|
||||||
|
self.to_writer(&mut buf.as_mut_slice(), e)?;
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_size(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_to_writer {
|
||||||
|
($($t:ty),*) => {
|
||||||
|
$(
|
||||||
|
impl ToWriter for $t {
|
||||||
|
fn to_writer<W>(&self, writer: &mut W, e: Endian) -> io::Result<()>
|
||||||
|
where W: Write + ?Sized {
|
||||||
|
writer.write_all(&match e {
|
||||||
|
Endian::Big => self.to_be_bytes(),
|
||||||
|
Endian::Little => self.to_le_bytes(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bytes(&self, e: Endian) -> io::Result<Vec<u8>> {
|
||||||
|
Ok(match e {
|
||||||
|
Endian::Big => self.to_be_bytes(),
|
||||||
|
Endian::Little => self.to_le_bytes(),
|
||||||
|
}.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_size(&self) -> usize {
|
||||||
|
std::mem::size_of::<Self>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_to_writer!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
|
||||||
|
|
||||||
|
impl<const N: usize> ToWriter for [u8; N] {
|
||||||
|
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
|
||||||
|
where W: Write + ?Sized {
|
||||||
|
writer.write_all(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_size(&self) -> usize { N }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToWriter for &[u8] {
|
||||||
|
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
|
||||||
|
where W: Write + ?Sized {
|
||||||
|
writer.write_all(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_size(&self) -> usize { self.len() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToWriter for Vec<u8> {
|
||||||
|
fn to_writer<W>(&self, writer: &mut W, _e: Endian) -> io::Result<()>
|
||||||
|
where W: Write + ?Sized {
|
||||||
|
writer.write_all(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_size(&self) -> usize { self.len() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_vec<T, W>(writer: &mut W, vec: &[T], e: Endian) -> io::Result<()>
|
||||||
|
where
|
||||||
|
T: ToWriter,
|
||||||
|
W: Write + ?Sized,
|
||||||
|
{
|
||||||
|
for item in vec {
|
||||||
|
item.to_writer(writer, e)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -232,15 +232,11 @@ pub fn process_rel<R: Read + Seek>(reader: &mut R, name: &str) -> Result<(RelHea
|
||||||
}
|
}
|
||||||
symbols.push(ObjSymbol {
|
symbols.push(ObjSymbol {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: offset as u64,
|
address: offset as u64,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags,
|
flags,
|
||||||
kind: ObjSymbolKind::Function,
|
kind: ObjSymbolKind::Function,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -128,15 +128,11 @@ pub fn process_rso<R: Read + Seek>(reader: &mut R) -> Result<ObjInfo> {
|
||||||
log::debug!("Adding {name} section {rel_section_idx} offset {offset:#X}");
|
log::debug!("Adding {name} section {rel_section_idx} offset {offset:#X}");
|
||||||
symbols.push(ObjSymbol {
|
symbols.push(ObjSymbol {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
demangled_name: None,
|
|
||||||
address: offset as u64,
|
address: offset as u64,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: 0,
|
|
||||||
size_known: false,
|
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Function,
|
kind: ObjSymbolKind::Function,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -196,12 +192,7 @@ pub fn process_rso<R: Read + Seek>(reader: &mut R) -> Result<ObjInfo> {
|
||||||
demangled_name,
|
demangled_name,
|
||||||
address: sym_off as u64,
|
address: sym_off as u64,
|
||||||
section: Some(section),
|
section: Some(section),
|
||||||
size: 0,
|
..Default::default()
|
||||||
size_known: false,
|
|
||||||
flags: Default::default(),
|
|
||||||
kind: Default::default(),
|
|
||||||
align: None,
|
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
reader.seek(SeekFrom::Start(import_table_offset as u64))?;
|
reader.seek(SeekFrom::Start(import_table_offset as u64))?;
|
||||||
|
|
|
@ -142,8 +142,7 @@ pub fn apply_symbol(
|
||||||
size_known: sig_symbol.size > 0 || sig_symbol.kind == ObjSymbolKind::Unknown,
|
size_known: sig_symbol.size > 0 || sig_symbol.kind == ObjSymbolKind::Unknown,
|
||||||
flags: sig_symbol.flags,
|
flags: sig_symbol.flags,
|
||||||
kind: sig_symbol.kind,
|
kind: sig_symbol.kind,
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -554,7 +554,6 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
||||||
log::debug!("Adding padding symbol {} at {:#010X}", symbol_name, addr);
|
log::debug!("Adding padding symbol {} at {:#010X}", symbol_name, addr);
|
||||||
obj.symbols.add_direct(ObjSymbol {
|
obj.symbols.add_direct(ObjSymbol {
|
||||||
name: symbol_name,
|
name: symbol_name,
|
||||||
demangled_name: None,
|
|
||||||
address: addr as u64,
|
address: addr as u64,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: next_symbol_address - addr as u64,
|
size: next_symbol_address - addr as u64,
|
||||||
|
@ -568,8 +567,7 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
||||||
ObjSymbolKind::Object
|
ObjSymbolKind::Object
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,7 +598,6 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
||||||
log::debug!("Adding gap symbol {} at {:#010X}", symbol_name, aligned_end);
|
log::debug!("Adding gap symbol {} at {:#010X}", symbol_name, aligned_end);
|
||||||
to_add.push(ObjSymbol {
|
to_add.push(ObjSymbol {
|
||||||
name: symbol_name,
|
name: symbol_name,
|
||||||
demangled_name: None,
|
|
||||||
address: aligned_end as u64,
|
address: aligned_end as u64,
|
||||||
section: Some(section_index),
|
section: Some(section_index),
|
||||||
size: next_symbol.address - aligned_end as u64,
|
size: next_symbol.address - aligned_end as u64,
|
||||||
|
@ -616,8 +613,7 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
||||||
| ObjSectionKind::ReadOnlyData
|
| ObjSectionKind::ReadOnlyData
|
||||||
| ObjSectionKind::Bss => ObjSymbolKind::Object,
|
| ObjSectionKind::Bss => ObjSymbolKind::Object,
|
||||||
},
|
},
|
||||||
align: None,
|
..Default::default()
|
||||||
data_kind: Default::default(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ordering::Equal => {}
|
Ordering::Equal => {}
|
||||||
|
@ -1048,6 +1044,8 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
|
||||||
kind: symbol.kind,
|
kind: symbol.kind,
|
||||||
align: symbol.align,
|
align: symbol.align,
|
||||||
data_kind: symbol.data_kind,
|
data_kind: symbol.data_kind,
|
||||||
|
name_hash: symbol.name_hash,
|
||||||
|
demangled_name_hash: symbol.demangled_name_hash,
|
||||||
})?);
|
})?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue