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(
|
||||
ObjSymbol {
|
||||
name,
|
||||
demangled_name: None,
|
||||
address: start.address as u64,
|
||||
section: Some(start.section),
|
||||
size: (end.address - start.address) as u64,
|
||||
size_known: true,
|
||||
flags: Default::default(),
|
||||
kind: ObjSymbolKind::Function,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
|
@ -188,15 +185,13 @@ impl AnalyzerState {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("jumptable_{}", address_str),
|
||||
demangled_name: None,
|
||||
address: addr.address as u64,
|
||||
section: Some(addr.section),
|
||||
size: size as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
|
|
|
@ -37,28 +37,20 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
|||
log::debug!("Found gTRKInterruptVectorTable @ {:#010X}", start);
|
||||
state.known_symbols.insert(start, ObjSymbol {
|
||||
name: "gTRKInterruptVectorTable".to_string(),
|
||||
demangled_name: None,
|
||||
address: start.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
let end = start + TRK_TABLE_SIZE;
|
||||
state.known_symbols.insert(end, ObjSymbol {
|
||||
name: "gTRKInterruptVectorTableEnd".to_string(),
|
||||
demangled_name: None,
|
||||
address: end.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(FlagSet::from(ObjSymbolFlags::Global)),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
|
@ -96,29 +88,23 @@ impl AnalysisPass for FindSaveRestSleds {
|
|||
});
|
||||
state.known_symbols.insert(start, ObjSymbol {
|
||||
name: func.to_string(),
|
||||
demangled_name: None,
|
||||
address: start.address as u64,
|
||||
section: Some(start.section),
|
||||
size: SLED_SIZE as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Function,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
for i in 14..=31 {
|
||||
let addr = start + (i - 14) * 4;
|
||||
state.known_symbols.insert(addr, ObjSymbol {
|
||||
name: format!("{}{}", label, i),
|
||||
demangled_name: None,
|
||||
address: addr.address as u64,
|
||||
section: Some(start.section),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -202,30 +188,20 @@ impl AnalysisPass for FindRelCtorsDtors {
|
|||
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
||||
state.known_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
|
||||
name: "_ctors".to_string(),
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
section: Some(ctors_section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let dtors_section_index = possible_sections[1].0;
|
||||
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
||||
state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
||||
name: "_dtors".to_string(),
|
||||
demangled_name: None,
|
||||
address: 0,
|
||||
section: Some(dtors_section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// 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(
|
||||
ObjSymbol {
|
||||
name: "__init_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(ctors_section_index),
|
||||
size: 4,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
@ -303,7 +301,6 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__destroy_global_chain_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address,
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
|
@ -312,8 +309,7 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
|||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||
),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
@ -334,7 +330,6 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "__fini_cpp_exceptions_reference".to_string(),
|
||||
demangled_name: None,
|
||||
address: address + 4,
|
||||
section: Some(dtors_section_index),
|
||||
size: 4,
|
||||
|
@ -343,8 +338,7 @@ fn apply_dtors_signatures(obj: &mut ObjInfo) -> Result<()> {
|
|||
ObjSymbolFlags::Global | ObjSymbolFlags::RelocationIgnore,
|
||||
),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
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")? {
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: "_ctors".to_string(),
|
||||
demangled_name: None,
|
||||
address: section.address,
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..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")? {
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: "_dtors".to_string(),
|
||||
demangled_name: None,
|
||||
address: section.address,
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -710,15 +710,10 @@ impl Tracker {
|
|||
};
|
||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||
name,
|
||||
demangled_name: None,
|
||||
address: target.address as u64,
|
||||
section: Some(target.section),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind,
|
||||
..Default::default()
|
||||
})?;
|
||||
(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,
|
||||
obj::{
|
||||
best_match_for_reloc, ObjDataKind, ObjInfo, ObjKind, ObjReloc, ObjRelocKind,
|
||||
ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, ObjSymbolScope,
|
||||
SymbolIndex,
|
||||
best_match_for_reloc, ObjInfo, ObjKind, ObjReloc, ObjRelocKind, ObjSectionKind, ObjSymbol,
|
||||
ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, ObjSymbolScope, SymbolIndex,
|
||||
},
|
||||
util::{
|
||||
asm::write_asm,
|
||||
|
@ -79,10 +78,10 @@ enum SubCommand {
|
|||
pub struct InfoArgs {
|
||||
#[argp(positional)]
|
||||
/// DOL file
|
||||
dol_file: PathBuf,
|
||||
pub dol_file: PathBuf,
|
||||
#[argp(option, short = 's')]
|
||||
/// optional path to selfile.sel
|
||||
selfile: Option<PathBuf>,
|
||||
pub selfile: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||
|
@ -366,6 +365,8 @@ fn apply_selfile(obj: &mut ObjInfo, buf: &[u8]) -> Result<()> {
|
|||
kind: existing_symbol.kind,
|
||||
align: existing_symbol.align,
|
||||
data_kind: existing_symbol.data_kind,
|
||||
name_hash: existing_symbol.name_hash,
|
||||
demangled_name_hash: existing_symbol.demangled_name_hash,
|
||||
})?;
|
||||
} else {
|
||||
log::debug!("Creating symbol {} at {:#010X}", symbol.name, address);
|
||||
|
@ -385,7 +386,7 @@ fn apply_selfile(obj: &mut ObjInfo, buf: &[u8]) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn info(args: InfoArgs) -> Result<()> {
|
||||
pub fn info(args: InfoArgs) -> Result<()> {
|
||||
let mut obj = {
|
||||
let file = map_file(&args.dol_file)?;
|
||||
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 {
|
||||
name,
|
||||
demangled_name: None,
|
||||
address: rel_reloc.addend as u64,
|
||||
section: Some(target_section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::ForceActive.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: ObjDataKind::Unknown,
|
||||
..Default::default()
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
@ -654,14 +650,7 @@ fn resolve_external_relocations(
|
|||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||
name: target_symbol.name.clone(),
|
||||
demangled_name: target_symbol.demangled_name.clone(),
|
||||
address: 0,
|
||||
section: None,
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
})?;
|
||||
|
||||
e.insert(symbol_idx);
|
||||
|
@ -1542,6 +1531,8 @@ fn apply(args: ApplyArgs) -> Result<()> {
|
|||
kind: linked_sym.kind,
|
||||
align: linked_sym.align,
|
||||
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 demangle;
|
||||
pub mod dol;
|
||||
|
|
|
@ -471,8 +471,10 @@ fn merge(args: MergeArgs) -> Result<()> {
|
|||
size_known: mod_symbol.size_known,
|
||||
flags: mod_symbol.flags,
|
||||
kind: mod_symbol.kind,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
align: mod_symbol.align,
|
||||
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);
|
||||
|
@ -506,15 +508,9 @@ fn merge(args: MergeArgs) -> Result<()> {
|
|||
// Create a new label
|
||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||
name: String::new(),
|
||||
demangled_name: None,
|
||||
address: target_addr as u64,
|
||||
section: Some(target_section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
})?;
|
||||
(symbol_idx, 0)
|
||||
};
|
||||
|
|
|
@ -74,6 +74,7 @@ struct TopLevel {
|
|||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argp(subcommand)]
|
||||
enum SubCommand {
|
||||
Alf(cmd::alf::Args),
|
||||
Ar(cmd::ar::Args),
|
||||
Demangle(cmd::demangle::Args),
|
||||
Dol(cmd::dol::Args),
|
||||
|
@ -122,6 +123,7 @@ fn main() {
|
|||
});
|
||||
}
|
||||
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::Demangle(c_args) => cmd::demangle::run(c_args),
|
||||
SubCommand::Dol(c_args) => cmd::dol::run(c_args),
|
||||
|
|
|
@ -165,6 +165,9 @@ pub struct ObjSymbol {
|
|||
pub kind: ObjSymbolKind,
|
||||
pub align: Option<u32>,
|
||||
pub data_kind: ObjDataKind,
|
||||
/// ALF hashes
|
||||
pub name_hash: Option<u32>,
|
||||
pub demangled_name_hash: Option<u32>,
|
||||
}
|
||||
|
||||
pub type SymbolIndex = usize;
|
||||
|
@ -263,6 +266,8 @@ impl ObjSymbols {
|
|||
ObjDataKind::Unknown => existing.data_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 {
|
||||
log::debug!("Replacing {:?} with {:?}", existing, new_symbol);
|
||||
|
@ -282,6 +287,8 @@ impl ObjSymbols {
|
|||
kind: in_symbol.kind,
|
||||
align: in_symbol.align,
|
||||
data_kind: in_symbol.data_kind,
|
||||
name_hash: in_symbol.name_hash,
|
||||
demangled_name_hash: in_symbol.demangled_name_hash,
|
||||
})?;
|
||||
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)
|
||||
};
|
||||
let demangled_name = demangle(&name, &DemangleOptions::default());
|
||||
let mut symbol = ObjSymbol {
|
||||
name,
|
||||
demangled_name,
|
||||
address: addr as u64,
|
||||
section,
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
};
|
||||
let mut symbol =
|
||||
ObjSymbol { name, demangled_name, address: addr as u64, section, ..Default::default() };
|
||||
// TODO move somewhere common
|
||||
if symbol.name.starts_with("..") {
|
||||
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)
|
||||
.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}'"),
|
||||
}
|
||||
} else {
|
||||
|
@ -163,7 +163,9 @@ pub fn is_skip_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]
|
||||
|
@ -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) {
|
||||
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() {
|
||||
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 dol::{Dol, DolSection, DolSectionType};
|
||||
|
||||
use crate::{
|
||||
analysis::cfa::{locate_sda_bases, SectionAddress},
|
||||
|
@ -9,6 +12,10 @@ use crate::{
|
|||
ObjArchitecture, ObjInfo, ObjKind, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||
ObjSymbolFlags, ObjSymbolKind,
|
||||
},
|
||||
util::{
|
||||
alf::{AlfFile, AlfSymbol},
|
||||
reader::{skip_bytes, Endian, FromReader},
|
||||
},
|
||||
};
|
||||
|
||||
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 ETI_INIT_INFO_SIZE: usize = 16; // eti_start, eti_end, code_start, code_size
|
||||
|
||||
fn read_u32(dol: &Dol, addr: u32) -> Result<u32> {
|
||||
Ok(u32::from_be_bytes(dol.virtual_data_at(addr, 4)?.try_into()?))
|
||||
/// Unified trait for DOL and ALF files
|
||||
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> {
|
||||
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
|
||||
let first_rom_section = dol
|
||||
.header
|
||||
.sections
|
||||
.sections()
|
||||
.iter()
|
||||
.find(|section| section.kind != DolSectionType::Bss)
|
||||
.find(|section| section.kind != DolSectionKind::Bss)
|
||||
.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"))?;
|
||||
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_BSS_INIT_INFO_SIZE as u32;
|
||||
loop {
|
||||
let value = read_u32(&dol, addr)?;
|
||||
if value == first_rom_section.target {
|
||||
let value = read_u32(buf, dol.as_ref(), addr)?;
|
||||
if value == first_rom_section.address {
|
||||
log::debug!("Found _rom_copy_info @ {addr:#010X}");
|
||||
break Some(addr);
|
||||
}
|
||||
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");
|
||||
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 rom_copy_info_end = match rom_copy_info_addr {
|
||||
Some(mut addr) => loop {
|
||||
let rom = read_u32(&dol, addr)?;
|
||||
let copy = read_u32(&dol, addr + 4)?;
|
||||
let rom = read_u32(buf, dol.as_ref(), addr)?;
|
||||
let copy = read_u32(buf, dol.as_ref(), addr + 4)?;
|
||||
ensure!(
|
||||
rom == copy,
|
||||
"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;
|
||||
if size == 0 {
|
||||
log::debug!("Found _rom_copy_info end @ {addr:#010X}");
|
||||
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");
|
||||
break None;
|
||||
}
|
||||
|
@ -78,20 +239,19 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
|
||||
// Locate _bss_init_info
|
||||
let bss_section = dol
|
||||
.header
|
||||
.sections
|
||||
.sections()
|
||||
.iter()
|
||||
.find(|section| section.kind == DolSectionType::Bss)
|
||||
.find(|section| section.kind == DolSectionKind::Bss)
|
||||
.ok_or_else(|| anyhow!("Failed to locate BSS section"))?;
|
||||
let bss_init_info_addr = match rom_copy_info_end {
|
||||
Some(mut addr) => loop {
|
||||
let value = read_u32(&dol, addr)?;
|
||||
if value == bss_section.target {
|
||||
let value = read_u32(buf, dol.as_ref(), addr)?;
|
||||
if value == bss_section.address {
|
||||
log::debug!("Found _bss_init_info @ {addr:#010X}");
|
||||
break Some(addr);
|
||||
}
|
||||
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");
|
||||
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 bss_init_info_end = match bss_init_info_addr {
|
||||
Some(mut addr) => loop {
|
||||
let rom = read_u32(&dol, addr)?;
|
||||
let size = read_u32(&dol, addr + 4)?;
|
||||
let rom = read_u32(buf, dol.as_ref(), addr)?;
|
||||
let size = read_u32(buf, dol.as_ref(), addr + 4)?;
|
||||
addr += 8;
|
||||
if size == 0 {
|
||||
log::debug!("Found _bss_init_info end @ {addr:#010X}");
|
||||
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");
|
||||
break None;
|
||||
}
|
||||
|
@ -121,27 +281,27 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
|
||||
// Locate _eti_init_info
|
||||
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_init_info_range: Option<(u32, u32)> = None;
|
||||
let mut extab_section: Option<usize> = None;
|
||||
let mut extabindex_section: Option<usize> = None;
|
||||
'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
|
||||
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,
|
||||
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 mut addr = dol_section_end - (ETI_INIT_INFO_SIZE * (num_text_sections + 1)) as u32;
|
||||
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(
|
||||
&dol,
|
||||
dol.as_ref(),
|
||||
&eti_init_info,
|
||||
dol_section,
|
||||
dol_section_end,
|
||||
|
@ -160,7 +320,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
let eti_init_info_end = {
|
||||
let mut addr = eti_init_info_addr;
|
||||
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;
|
||||
if eti_init_info.is_zero() {
|
||||
break;
|
||||
|
@ -172,7 +332,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
);
|
||||
}
|
||||
if !validate_eti_init_info(
|
||||
&dol,
|
||||
dol.as_ref(),
|
||||
&eti_init_info,
|
||||
dol_section,
|
||||
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);
|
||||
}
|
||||
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 =
|
||||
section_by_address(&dol, eti_entry.extab_addr).ok_or_else(|| {
|
||||
dol.section_by_address(eti_entry.extab_addr).ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to locate section for extab address {:#010X}",
|
||||
eti_entry.extab_addr
|
||||
|
@ -216,9 +376,12 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
|
||||
// Add text and data sections
|
||||
let mut sections = vec![];
|
||||
for dol_section in
|
||||
dol.header.sections.iter().filter(|section| section.kind != DolSectionType::Bss)
|
||||
{
|
||||
for dol_section in dol.sections().iter() {
|
||||
// We'll split .bss later
|
||||
if dol_section.kind == DolSectionKind::Bss && dol.has_unified_bss() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (name, kind, known) = match dol_section.index {
|
||||
idx if idx == init_section.index => (".init".to_string(), ObjSectionKind::Code, true),
|
||||
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 => {
|
||||
("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)
|
||||
}
|
||||
idx => match dol_section.kind {
|
||||
DolSectionType::Text => (format!(".text{idx}"), ObjSectionKind::Code, false),
|
||||
DolSectionType::Data => (format!(".data{idx}"), ObjSectionKind::Data, false),
|
||||
DolSectionType::Bss => unreachable!(),
|
||||
DolSectionKind::Text => (format!(".text{idx}"), ObjSectionKind::Code, false),
|
||||
DolSectionKind::Data => (format!(".data{idx}"), ObjSectionKind::Data, false),
|
||||
DolSectionKind::Bss => (format!(".bss{}", idx), ObjSectionKind::Bss, false),
|
||||
},
|
||||
};
|
||||
|
||||
// Use section size from _rom_copy_info
|
||||
let size = match rom_sections.get(&dol_section.target) {
|
||||
Some(&size) => size,
|
||||
None => {
|
||||
if !rom_sections.is_empty() {
|
||||
log::warn!(
|
||||
"Section {} ({:#010X}) doesn't exist in _rom_copy_info",
|
||||
dol_section.index,
|
||||
dol_section.target
|
||||
);
|
||||
let (size, data): (u32, &[u8]) = if kind == ObjSectionKind::Bss {
|
||||
(dol_section.size, &[])
|
||||
} else {
|
||||
// Use section size from _rom_copy_info
|
||||
let size = match rom_sections.get(&dol_section.address) {
|
||||
Some(&size) => size,
|
||||
None => {
|
||||
if !rom_sections.is_empty() {
|
||||
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 {
|
||||
name,
|
||||
kind,
|
||||
address: dol_section.target as u64,
|
||||
address: dol_section.address as u64,
|
||||
size: size as u64,
|
||||
data: dol.virtual_data_at(dol_section.target, size)?.to_vec(),
|
||||
data: data.to_vec(),
|
||||
align: 0,
|
||||
elf_index: 0,
|
||||
relocations: Default::default(),
|
||||
original_address: 0,
|
||||
file_offset: dol_section.offset as u64,
|
||||
file_offset: dol_section.file_offset as u64,
|
||||
section_known: known,
|
||||
splits: Default::default(),
|
||||
});
|
||||
}
|
||||
|
||||
// Add BSS sections from _bss_init_info
|
||||
for (idx, (&addr, &size)) in bss_sections.iter().enumerate() {
|
||||
ensure!(
|
||||
addr >= bss_section.target
|
||||
&& addr < bss_section.target + bss_section.size
|
||||
&& addr + size <= bss_section.target + bss_section.size,
|
||||
"Invalid BSS range {:#010X}-{:#010X} (DOL BSS: {:#010X}-{:#010X})",
|
||||
addr,
|
||||
addr + size,
|
||||
bss_section.target,
|
||||
bss_section.target + bss_section.size
|
||||
);
|
||||
if dol.has_unified_bss() {
|
||||
// Add BSS sections from _bss_init_info
|
||||
for (idx, (&addr, &size)) in bss_sections.iter().enumerate() {
|
||||
ensure!(
|
||||
addr >= bss_section.address
|
||||
&& addr < bss_section.address + bss_section.size
|
||||
&& addr + size <= bss_section.address + bss_section.size,
|
||||
"Invalid BSS range {:#010X}-{:#010X} (DOL BSS: {:#010X}-{:#010X})",
|
||||
addr,
|
||||
addr + size,
|
||||
bss_section.address,
|
||||
bss_section.address + bss_section.size
|
||||
);
|
||||
|
||||
sections.push(ObjSection {
|
||||
name: format!(".bss{}", idx),
|
||||
kind: ObjSectionKind::Bss,
|
||||
address: addr as u64,
|
||||
size: size as u64,
|
||||
data: vec![],
|
||||
align: 0,
|
||||
elf_index: 0,
|
||||
relocations: Default::default(),
|
||||
original_address: 0,
|
||||
file_offset: 0,
|
||||
section_known: false,
|
||||
splits: Default::default(),
|
||||
});
|
||||
sections.push(ObjSection {
|
||||
name: format!(".bss{}", idx),
|
||||
kind: ObjSectionKind::Bss,
|
||||
address: addr as u64,
|
||||
size: size as u64,
|
||||
data: vec![],
|
||||
align: 0,
|
||||
elf_index: 0,
|
||||
relocations: Default::default(),
|
||||
original_address: 0,
|
||||
file_offset: 0,
|
||||
section_known: false,
|
||||
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
|
||||
let mut init_section_index = None;
|
||||
for (idx, section) in sections.iter_mut().enumerate() {
|
||||
|
@ -328,7 +498,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
vec![],
|
||||
sections,
|
||||
);
|
||||
obj.entry = Some(dol.header.entry_point as u64);
|
||||
obj.entry = Some(dol.entry_point() as u64);
|
||||
|
||||
// Generate _rom_copy_info symbol
|
||||
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(
|
||||
ObjSymbol {
|
||||
name: "_rom_copy_info".to_string(),
|
||||
demangled_name: None,
|
||||
address: rom_copy_info_addr as u64,
|
||||
section: init_section_index,
|
||||
size: (rom_copy_info_end - rom_copy_info_addr) as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
@ -358,15 +526,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "_bss_init_info".to_string(),
|
||||
demangled_name: None,
|
||||
address: bss_init_info_addr as u64,
|
||||
section: init_section_index,
|
||||
size: (bss_init_info_end - bss_init_info_addr) as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
@ -377,15 +543,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "_eti_init_info".to_string(),
|
||||
demangled_name: None,
|
||||
address: eti_init_info_addr as u64,
|
||||
section: extabindex_section,
|
||||
size: (eti_init_info_end - eti_init_info_addr) as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
@ -424,15 +588,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("@eti_{:08X}", entry.address),
|
||||
demangled_name: None,
|
||||
address: entry.address as u64,
|
||||
section: Some(extabindex_section_index),
|
||||
size: 12,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
|
@ -451,15 +613,13 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("@etb_{:08X}", addr),
|
||||
demangled_name: None,
|
||||
address: addr as u64,
|
||||
section: Some(extab_section_index),
|
||||
size: size as u64,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Local | ObjSymbolFlags::Hidden),
|
||||
kind: ObjSymbolKind::Object,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
|
@ -504,30 +664,20 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
|
|||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "_SDA2_BASE_".to_string(),
|
||||
demangled_name: None,
|
||||
address: sda2_base as u64,
|
||||
section: None,
|
||||
size: 0,
|
||||
size_known: false,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: "_SDA_BASE_".to_string(),
|
||||
demangled_name: None,
|
||||
address: sda_base as u64,
|
||||
section: None,
|
||||
size: 0,
|
||||
size_known: false,
|
||||
size_known: true,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Unknown,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -566,35 +721,35 @@ struct EtiEntry {
|
|||
extab_addr: u32,
|
||||
}
|
||||
|
||||
fn read_eti_init_info(dol: &Dol, addr: u32) -> Result<EtiInitInfo> {
|
||||
let eti_start = read_u32(dol, addr)?;
|
||||
let eti_end = read_u32(dol, addr + 4)?;
|
||||
let code_start = read_u32(dol, addr + 8)?;
|
||||
let code_size = read_u32(dol, addr + 12)?;
|
||||
fn read_eti_init_info(buf: &[u8], dol: &dyn DolLike, addr: u32) -> Result<EtiInitInfo> {
|
||||
let eti_start = read_u32(buf, dol, addr)?;
|
||||
let eti_end = read_u32(buf, dol, addr + 4)?;
|
||||
let code_start = read_u32(buf, dol, addr + 8)?;
|
||||
let code_size = read_u32(buf, dol, addr + 12)?;
|
||||
Ok(EtiInitInfo { eti_start, eti_end, code_start, code_size })
|
||||
}
|
||||
|
||||
fn read_eti_entry(dol: &Dol, address: u32) -> Result<EtiEntry> {
|
||||
let function = read_u32(dol, address)?;
|
||||
let function_size = read_u32(dol, address + 4)?;
|
||||
let extab_addr = read_u32(dol, address + 8)?;
|
||||
fn read_eti_entry(buf: &[u8], dol: &dyn DolLike, address: u32) -> Result<EtiEntry> {
|
||||
let function = read_u32(buf, dol, address)?;
|
||||
let function_size = read_u32(buf, dol, address + 4)?;
|
||||
let extab_addr = read_u32(buf, dol, address + 8)?;
|
||||
Ok(EtiEntry { address, function, function_size, extab_addr })
|
||||
}
|
||||
|
||||
fn validate_eti_init_info(
|
||||
dol: &Dol,
|
||||
dol: &dyn DolLike,
|
||||
eti_init_info: &EtiInitInfo,
|
||||
eti_section: &DolSection,
|
||||
eti_section_end: u32,
|
||||
rom_sections: &BTreeMap<u32, u32>,
|
||||
) -> 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_end >= eti_section.target
|
||||
&& eti_init_info.eti_end >= eti_section.address
|
||||
&& eti_init_info.eti_end < eti_section_end
|
||||
{
|
||||
if let Some(code_section) = section_by_address(dol, eti_init_info.code_start) {
|
||||
let code_section_size = match rom_sections.get(&code_section.target) {
|
||||
if let Some(code_section) = dol.section_by_address(eti_init_info.code_start) {
|
||||
let code_section_size = match rom_sections.get(&code_section.address) {
|
||||
Some(&size) => size,
|
||||
None => code_section.size,
|
||||
};
|
||||
|
@ -605,10 +760,3 @@ fn validate_eti_init_info(
|
|||
}
|
||||
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),
|
||||
},
|
||||
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,
|
||||
},
|
||||
align: symbol_entry.align,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{borrow::Cow, ops::Deref};
|
||||
|
||||
pub mod alf;
|
||||
pub mod asm;
|
||||
pub mod comment;
|
||||
pub mod config;
|
||||
|
@ -12,6 +13,7 @@ pub mod lcf;
|
|||
pub mod map;
|
||||
pub mod nested;
|
||||
pub mod rarc;
|
||||
pub mod reader;
|
||||
pub mod rel;
|
||||
pub mod rso;
|
||||
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 {
|
||||
name: name.to_string(),
|
||||
demangled_name: None,
|
||||
address: offset as u64,
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags,
|
||||
kind: ObjSymbolKind::Function,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
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}");
|
||||
symbols.push(ObjSymbol {
|
||||
name: name.to_string(),
|
||||
demangled_name: None,
|
||||
address: offset as u64,
|
||||
section: Some(section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||
kind: ObjSymbolKind::Function,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
|
@ -196,12 +192,7 @@ pub fn process_rso<R: Read + Seek>(reader: &mut R) -> Result<ObjInfo> {
|
|||
demangled_name,
|
||||
address: sym_off as u64,
|
||||
section: Some(section),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
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,
|
||||
flags: sig_symbol.flags,
|
||||
kind: sig_symbol.kind,
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
|
|
|
@ -554,7 +554,6 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
|||
log::debug!("Adding padding symbol {} at {:#010X}", symbol_name, addr);
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: symbol_name,
|
||||
demangled_name: None,
|
||||
address: addr as u64,
|
||||
section: Some(section_index),
|
||||
size: next_symbol_address - addr as u64,
|
||||
|
@ -568,8 +567,7 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
|||
ObjSymbolKind::Object
|
||||
}
|
||||
},
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..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);
|
||||
to_add.push(ObjSymbol {
|
||||
name: symbol_name,
|
||||
demangled_name: None,
|
||||
address: aligned_end as u64,
|
||||
section: Some(section_index),
|
||||
size: next_symbol.address - aligned_end as u64,
|
||||
|
@ -616,8 +613,7 @@ fn add_padding_symbols(obj: &mut ObjInfo) -> Result<()> {
|
|||
| ObjSectionKind::ReadOnlyData
|
||||
| ObjSectionKind::Bss => ObjSymbolKind::Object,
|
||||
},
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
Ordering::Equal => {}
|
||||
|
@ -1048,6 +1044,8 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
|
|||
kind: symbol.kind,
|
||||
align: symbol.align,
|
||||
data_kind: symbol.data_kind,
|
||||
name_hash: symbol.name_hash,
|
||||
demangled_name_hash: symbol.demangled_name_hash,
|
||||
})?);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue