diff --git a/src/cmd/map.rs b/src/cmd/map.rs index ebb5636..2a332fb 100644 --- a/src/cmd/map.rs +++ b/src/cmd/map.rs @@ -1,12 +1,15 @@ -use std::path::PathBuf; +use std::{fs::DirBuilder, path::PathBuf}; use anyhow::{bail, ensure, Result}; use argp::FromArgs; use cwdemangle::{demangle, DemangleOptions}; +use tracing::error; use crate::util::{ + config::{write_splits_file, write_symbols_file}, file::map_file, - map::{process_map, SymbolEntry, SymbolRef}, + map::{create_obj, process_map, SymbolEntry, SymbolRef}, + split::update_splits, }; #[derive(FromArgs, PartialEq, Debug)] @@ -22,6 +25,7 @@ pub struct Args { enum SubCommand { Entries(EntriesArgs), Symbol(SymbolArgs), + Config(ConfigArgs), } #[derive(FromArgs, PartialEq, Eq, Debug)] @@ -48,10 +52,23 @@ pub struct SymbolArgs { symbol: String, } +#[derive(FromArgs, PartialEq, Eq, Debug)] +/// Generates project configuration files from a map. (symbols.txt, splits.txt) +#[argp(subcommand, name = "config")] +pub struct ConfigArgs { + #[argp(positional)] + /// path to input map + map_file: PathBuf, + #[argp(positional)] + /// output directory for symbols.txt and splits.txt + out_dir: PathBuf, +} + pub fn run(args: Args) -> Result<()> { match args.command { SubCommand::Entries(c_args) => entries(c_args), SubCommand::Symbol(c_args) => symbol(c_args), + SubCommand::Config(c_args) => config(c_args), } } @@ -160,3 +177,18 @@ fn symbol(args: SymbolArgs) -> Result<()> { println!("\n"); Ok(()) } + +fn config(args: ConfigArgs) -> Result<()> { + let file = map_file(&args.map_file)?; + log::info!("Processing map..."); + let entries = process_map(&mut file.as_reader(), None, None)?; + let mut obj = create_obj(&entries)?; + if let Err(e) = update_splits(&mut obj, None, false) { + error!("Failed to update splits: {}", e) + } + DirBuilder::new().recursive(true).create(&args.out_dir)?; + write_symbols_file(args.out_dir.join("symbols.txt"), &obj, None)?; + write_splits_file(args.out_dir.join("splits.txt"), &obj, false, None)?; + log::info!("Done!"); + Ok(()) +} diff --git a/src/obj/mod.rs b/src/obj/mod.rs index 2013e16..428f963 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -13,7 +13,7 @@ use std::{ use anyhow::{anyhow, bail, ensure, Result}; use objdiff_core::obj::split_meta::SplitMeta; pub use relocations::{ObjReloc, ObjRelocKind, ObjRelocations}; -pub use sections::{ObjSection, ObjSectionKind, ObjSections}; +pub use sections::{ObjSection, ObjSectionKind, ObjSections, section_kind_for_section}; pub use splits::{ObjSplit, ObjSplits}; pub use symbols::{ best_match_for_reloc, ObjDataKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, diff --git a/src/obj/sections.rs b/src/obj/sections.rs index 61d45c6..b109cc4 100644 --- a/src/obj/sections.rs +++ b/src/obj/sections.rs @@ -218,7 +218,7 @@ impl ObjSection { } } -fn section_kind_for_section(section_name: &str) -> Result { +pub fn section_kind_for_section(section_name: &str) -> Result { Ok(match section_name { ".init" | ".text" | ".dbgtext" | ".vmtext" => ObjSectionKind::Code, ".ctors" | ".dtors" | ".rodata" | ".sdata2" | "extab" | "extabindex" | ".BINARY" => { diff --git a/src/util/map.rs b/src/util/map.rs index a2c2630..f820ada 100644 --- a/src/util/map.rs +++ b/src/util/map.rs @@ -18,8 +18,9 @@ use regex::{Captures, Regex}; use crate::{ obj::{ - ObjInfo, ObjKind, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, - ObjUnit, + section_kind_for_section, ObjArchitecture, ObjInfo, ObjKind, ObjSection, ObjSectionKind, + ObjSections, ObjSplit, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, ObjSymbolKind, + ObjSymbols, ObjUnit, }, util::{file::map_file, nested::NestedVec}, }; @@ -814,6 +815,108 @@ pub fn apply_map(result: &MapInfo, obj: &mut ObjInfo) -> Result<()> { Ok(()) } +pub fn create_obj(result: &MapInfo) -> Result { + let sections = result + .sections + .iter() + .map(|s| { + let name = s.name.clone(); + let address = s.address as u64; + let size = s.size as u64; + let file_offset = s.file_offset as u64; + let kind = section_kind_for_section(&name).unwrap_or(ObjSectionKind::ReadOnlyData); + ObjSection { + name, + kind, + address, + size, + data: vec![], + align: 0, + elf_index: 0, + relocations: Default::default(), + virtual_address: None, + file_offset, + section_known: true, + splits: Default::default(), + } + }) + .collect(); + let mut obj = ObjInfo { + kind: ObjKind::Executable, + architecture: ObjArchitecture::PowerPc, + name: "".to_string(), + symbols: ObjSymbols::new(ObjKind::Executable, vec![]), + sections: ObjSections::new(ObjKind::Executable, sections), + entry: None, // TODO result.entry_point + mw_comment: None, + split_meta: None, + sda2_base: None, + sda_base: None, + stack_address: None, + stack_end: None, + db_stack_addr: None, + arena_lo: None, + arena_hi: None, + link_order: vec![], + blocked_relocation_sources: Default::default(), + blocked_relocation_targets: Default::default(), + known_functions: Default::default(), + module_id: 0, + unresolved_relocations: vec![], + }; + + // Add section symbols + for (section_name, symbol_map) in &result.section_symbols { + let (section_index, _) = obj + .sections + .by_name(section_name)? + .ok_or_else(|| anyhow!("Failed to locate section {section_name} from map"))?; + for symbol_entry in symbol_map.values().flatten() { + add_symbol(&mut obj, symbol_entry, Some(section_index))?; + } + } + + // Add splits + for (section_name, unit_order) in &result.section_units { + let (_, section) = obj + .sections + .iter_mut() + .find(|(_, s)| s.name == *section_name) + .ok_or_else(|| anyhow!("Failed to locate section '{}'", section_name))?; + let mut iter = unit_order.iter().peekable(); + while let Some((addr, unit)) = iter.next() { + let next = iter + .peek() + .map(|(addr, _)| *addr) + .unwrap_or_else(|| (section.address + section.size) as u32); + let common = section_name == ".bss" + && matches!(result.common_bss_start, Some(start) if *addr >= start); + let unit = unit.replace(' ', "/"); + + // Disable mw_comment_version for assembly units + if unit.ends_with(".s") && !obj.link_order.iter().any(|u| u.name == unit) { + obj.link_order.push(ObjUnit { + name: unit.clone(), + autogenerated: false, + comment_version: Some(0), + order: None, + }); + } + + section.splits.push(*addr, ObjSplit { + unit, + end: next, + align: None, + common, + autogenerated: false, + skip: false, + rename: None, + }); + } + } + Ok(obj) +} + fn add_symbol(obj: &mut ObjInfo, symbol_entry: &SymbolEntry, section: Option) -> Result<()> { let demangled_name = demangle(&symbol_entry.name, &DemangleOptions::default()); let mut flags: FlagSet = match symbol_entry.visibility { diff --git a/src/util/split.rs b/src/util/split.rs index 3fca13b..44645af 100644 --- a/src/util/split.rs +++ b/src/util/split.rs @@ -758,26 +758,32 @@ fn trim_linker_generated_symbols(obj: &mut ObjInfo) -> Result<()> { pub fn update_splits(obj: &mut ObjInfo, common_start: Option, fill_gaps: bool) -> Result<()> { // Create splits for extab and extabindex entries if let Some((section_index, section)) = obj.sections.by_name("extabindex")? { - let start = SectionAddress::new(section_index, section.address as u32); - split_extabindex(obj, start)?; + if !section.data.is_empty() { + let start = SectionAddress::new(section_index, section.address as u32); + split_extabindex(obj, start)?; + } } // Create splits for .ctors entries if let Some((section_index, section)) = obj.sections.by_name(".ctors")? { - let start = SectionAddress::new(section_index, section.address as u32); - let end = start + (section.size as u32 - 4); - split_ctors_dtors(obj, start, end)?; + if !section.data.is_empty() { + let start = SectionAddress::new(section_index, section.address as u32); + let end = start + (section.size as u32 - 4); + split_ctors_dtors(obj, start, end)?; + } } // Create splits for .dtors entries if let Some((section_index, section)) = obj.sections.by_name(".dtors")? { - let mut start = SectionAddress::new(section_index, section.address as u32); - let end = start + (section.size as u32 - 4); - if obj.kind == ObjKind::Executable { - // Skip __destroy_global_chain_reference - start += 4; + if !section.data.is_empty() { + let mut start = SectionAddress::new(section_index, section.address as u32); + let end = start + (section.size as u32 - 4); + if obj.kind == ObjKind::Executable { + // Skip __destroy_global_chain_reference + start += 4; + } + split_ctors_dtors(obj, start, end)?; } - split_ctors_dtors(obj, start, end)?; } // Remove linker generated symbols from splits @@ -1352,6 +1358,9 @@ pub fn end_for_section(obj: &ObjInfo, section_index: usize) -> Result