diff --git a/Cargo.lock b/Cargo.lock index 547b0d7..5f44186 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1526,15 +1526,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -1551,9 +1551,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -1562,21 +1562,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-io", @@ -2861,7 +2861,7 @@ dependencies = [ [[package]] name = "objdiff-cli" -version = "2.3.1" +version = "2.3.2" dependencies = [ "anyhow", "argp", @@ -2883,7 +2883,7 @@ dependencies = [ [[package]] name = "objdiff-core" -version = "2.3.1" +version = "2.3.2" dependencies = [ "anyhow", "arm-attr", @@ -2923,7 +2923,7 @@ dependencies = [ [[package]] name = "objdiff-gui" -version = "2.3.1" +version = "2.3.2" dependencies = [ "anyhow", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 1875927..faae7dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ strip = "debuginfo" codegen-units = 1 [workspace.package] -version = "2.3.1" +version = "2.3.2" authors = ["Luke Street "] edition = "2021" license = "MIT OR Apache-2.0" diff --git a/deny.toml b/deny.toml index 5cb5ccc..49410bd 100644 --- a/deny.toml +++ b/deny.toml @@ -70,7 +70,6 @@ feature-depth = 1 # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - "RUSTSEC-2024-0370", #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, @@ -240,7 +239,7 @@ allow-git = [] [sources.allow-org] # github.com organizations to allow git sources for -github = ["encounter"] +github = ["notify-rs"] # gitlab.com organizations to allow git sources for gitlab = [] # bitbucket.org organizations to allow git sources for diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index aca016d..603aabc 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -83,7 +83,7 @@ impl ObjArch for ObjArchMips { &self, address: u64, code: &[u8], - _section_index: usize, + section_index: usize, relocations: &[ObjReloc], line_info: &BTreeMap, config: &DiffObjConfig, @@ -140,11 +140,18 @@ impl ObjArch for ObjArchMips { | OperandType::cpu_label | OperandType::cpu_branch_target_label => { if let Some(reloc) = reloc { - if matches!(&reloc.target_section, Some(s) if s == ".text") - && reloc.target.address > start_address - && reloc.target.address < end_address + // If the relocation target is within the current function, we can + // convert it into a relative branch target. Note that we check + // target_address > start_address instead of >= so that recursive + // tail calls are not considered branch targets. + let target_address = + reloc.target.address.checked_add_signed(reloc.addend); + if reloc.target.orig_section_index == Some(section_index) + && matches!(target_address, Some(addr) if addr > start_address && addr < end_address) { - args.push(ObjInsArg::BranchDest(reloc.target.address)); + let target_address = target_address.unwrap(); + args.push(ObjInsArg::BranchDest(target_address)); + branch_dest = Some(target_address); } else { push_reloc(&mut args, reloc)?; branch_dest = None; diff --git a/objdiff-core/src/bindings/diff.rs b/objdiff-core/src/bindings/diff.rs index b29105f..ab83560 100644 --- a/objdiff-core/src/bindings/diff.rs +++ b/objdiff-core/src/bindings/diff.rs @@ -70,9 +70,13 @@ impl FunctionDiff { // let (_section, symbol) = object.section_symbol(symbol_ref); // Symbol::from(symbol) // }); - let instructions = symbol_diff.instructions.iter().map(InstructionDiff::from).collect(); + let instructions = symbol_diff + .instructions + .iter() + .map(|ins_diff| InstructionDiff::new(object, ins_diff)) + .collect(); Self { - symbol: Some(Symbol::from(symbol)), + symbol: Some(Symbol::new(symbol)), // diff_symbol, instructions, match_percent: symbol_diff.match_percent, @@ -90,8 +94,8 @@ impl DataDiff { } } -impl<'a> From<&'a ObjSymbol> for Symbol { - fn from(value: &'a ObjSymbol) -> Self { +impl Symbol { + pub fn new(value: &ObjSymbol) -> Self { Self { name: value.name.to_string(), demangled_name: value.demangled_name.clone(), @@ -122,29 +126,29 @@ fn symbol_flags(value: ObjSymbolFlagSet) -> u32 { flags } -impl<'a> From<&'a ObjIns> for Instruction { - fn from(value: &'a ObjIns) -> Self { +impl Instruction { + pub fn new(object: &ObjInfo, instruction: &ObjIns) -> Self { Self { - address: value.address, - size: value.size as u32, - opcode: value.op as u32, - mnemonic: value.mnemonic.clone(), - formatted: value.formatted.clone(), - arguments: value.args.iter().map(Argument::from).collect(), - relocation: value.reloc.as_ref().map(Relocation::from), - branch_dest: value.branch_dest, - line_number: value.line, - original: value.orig.clone(), + address: instruction.address, + size: instruction.size as u32, + opcode: instruction.op as u32, + mnemonic: instruction.mnemonic.clone(), + formatted: instruction.formatted.clone(), + arguments: instruction.args.iter().map(Argument::new).collect(), + relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)), + branch_dest: instruction.branch_dest, + line_number: instruction.line, + original: instruction.orig.clone(), } } } -impl<'a> From<&'a ObjInsArg> for Argument { - fn from(value: &'a ObjInsArg) -> Self { +impl Argument { + pub fn new(value: &ObjInsArg) -> Self { Self { value: Some(match value { ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()), - ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::from(v)), + ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::new(v)), ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}), ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest), }), @@ -152,8 +156,8 @@ impl<'a> From<&'a ObjInsArg> for Argument { } } -impl From<&ObjInsArgValue> for ArgumentValue { - fn from(value: &ObjInsArgValue) -> Self { +impl ArgumentValue { + pub fn new(value: &ObjInsArgValue) -> Self { Self { value: Some(match value { ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v), @@ -164,42 +168,39 @@ impl From<&ObjInsArgValue> for ArgumentValue { } } -impl<'a> From<&'a ObjReloc> for Relocation { - fn from(value: &ObjReloc) -> Self { +impl Relocation { + pub fn new(object: &ObjInfo, reloc: &ObjReloc) -> Self { Self { - r#type: match value.flags { + r#type: match reloc.flags { object::RelocationFlags::Elf { r_type } => r_type, object::RelocationFlags::MachO { r_type, .. } => r_type as u32, object::RelocationFlags::Coff { typ } => typ as u32, object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32, _ => unreachable!(), }, - type_name: String::new(), // TODO - target: Some(RelocationTarget::from(&value.target)), + type_name: object.arch.display_reloc(reloc.flags).into_owned(), + target: Some(RelocationTarget { + symbol: Some(Symbol::new(&reloc.target)), + addend: reloc.addend, + }), } } } -impl<'a> From<&'a ObjSymbol> for RelocationTarget { - fn from(value: &'a ObjSymbol) -> Self { - Self { symbol: Some(Symbol::from(value)), addend: value.addend } - } -} - -impl<'a> From<&'a ObjInsDiff> for InstructionDiff { - fn from(value: &'a ObjInsDiff) -> Self { +impl InstructionDiff { + pub fn new(object: &ObjInfo, instruction_diff: &ObjInsDiff) -> Self { Self { - instruction: value.ins.as_ref().map(Instruction::from), - diff_kind: DiffKind::from(value.kind) as i32, - branch_from: value.branch_from.as_ref().map(InstructionBranchFrom::from), - branch_to: value.branch_to.as_ref().map(InstructionBranchTo::from), - arg_diff: value.arg_diff.iter().map(ArgumentDiff::from).collect(), + instruction: instruction_diff.ins.as_ref().map(|ins| Instruction::new(object, ins)), + diff_kind: DiffKind::from(instruction_diff.kind) as i32, + branch_from: instruction_diff.branch_from.as_ref().map(InstructionBranchFrom::new), + branch_to: instruction_diff.branch_to.as_ref().map(InstructionBranchTo::new), + arg_diff: instruction_diff.arg_diff.iter().map(ArgumentDiff::new).collect(), } } } -impl From<&Option> for ArgumentDiff { - fn from(value: &Option) -> Self { +impl ArgumentDiff { + pub fn new(value: &Option) -> Self { Self { diff_index: value.as_ref().map(|v| v.idx as u32) } } } @@ -228,8 +229,8 @@ impl From for DiffKind { } } -impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom { - fn from(value: &'a ObjInsBranchFrom) -> Self { +impl InstructionBranchFrom { + pub fn new(value: &ObjInsBranchFrom) -> Self { Self { instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(), branch_index: value.branch_idx as u32, @@ -237,8 +238,8 @@ impl<'a> From<&'a ObjInsBranchFrom> for InstructionBranchFrom { } } -impl<'a> From<&'a ObjInsBranchTo> for InstructionBranchTo { - fn from(value: &'a ObjInsBranchTo) -> Self { +impl InstructionBranchTo { + pub fn new(value: &ObjInsBranchTo) -> Self { Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 } } } diff --git a/objdiff-core/src/diff/code.rs b/objdiff-core/src/diff/code.rs index 795c296..c840f85 100644 --- a/objdiff-core/src/diff/code.rs +++ b/objdiff-core/src/diff/code.rs @@ -9,7 +9,7 @@ use crate::{ DiffObjConfig, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind, ObjSymbolDiff, }, - obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbol, ObjSymbolFlags, SymbolRef}, + obj::{ObjInfo, ObjInsArg, ObjReloc, ObjSymbolFlags, SymbolRef}, }; pub fn process_code_symbol( @@ -45,6 +45,8 @@ pub fn no_diff_code(out: &ProcessCodeResult, symbol_ref: SymbolRef) -> Result bool { - left.address as i64 + left.addend == right.address as i64 + right.addend +fn address_eq(left: &ObjReloc, right: &ObjReloc) -> bool { + left.target.address as i64 + left.addend == right.target.address as i64 + right.addend +} + +fn section_name_eq( + left_obj: &ObjInfo, + right_obj: &ObjInfo, + left_orig_section_index: usize, + right_orig_section_index: usize, +) -> bool { + let Some(left_section) = + left_obj.sections.iter().find(|s| s.orig_index == left_orig_section_index) + else { + return false; + }; + let Some(right_section) = + right_obj.sections.iter().find(|s| s.orig_index == right_orig_section_index) + else { + return false; + }; + left_section.name == right_section.name } fn reloc_eq( config: &DiffObjConfig, + left_obj: &ObjInfo, + right_obj: &ObjInfo, left_reloc: Option<&ObjReloc>, right_reloc: Option<&ObjReloc>, ) -> bool { @@ -189,23 +212,26 @@ fn reloc_eq( return true; } - let name_matches = left.target.name == right.target.name; - match (&left.target_section, &right.target_section) { + let symbol_name_matches = left.target.name == right.target.name; + match (&left.target.orig_section_index, &right.target.orig_section_index) { (Some(sl), Some(sr)) => { // Match if section and name or address match - sl == sr && (name_matches || address_eq(&left.target, &right.target)) + section_name_eq(left_obj, right_obj, *sl, *sr) + && (symbol_name_matches || address_eq(left, right)) } (Some(_), None) => false, (None, Some(_)) => { // Match if possibly stripped weak symbol - name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak) + symbol_name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak) } - (None, None) => name_matches, + (None, None) => symbol_name_matches, } } fn arg_eq( config: &DiffObjConfig, + left_obj: &ObjInfo, + right_obj: &ObjInfo, left: &ObjInsArg, right: &ObjInsArg, left_diff: &ObjInsDiff, @@ -227,6 +253,8 @@ fn arg_eq( matches!(right, ObjInsArg::Reloc) && reloc_eq( config, + left_obj, + right_obj, left_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()), right_diff.ins.as_ref().and_then(|i| i.reloc.as_ref()), ) @@ -257,6 +285,8 @@ struct InsDiffResult { fn compare_ins( config: &DiffObjConfig, + left_obj: &ObjInfo, + right_obj: &ObjInfo, left: &ObjInsDiff, right: &ObjInsDiff, state: &mut InsDiffState, @@ -283,7 +313,7 @@ fn compare_ins( state.diff_count += 1; } for (a, b) in left_ins.args.iter().zip(&right_ins.args) { - if arg_eq(config, a, b, left, right) { + if arg_eq(config, left_obj, right_obj, a, b, left, right) { result.left_args_diff.push(None); result.right_args_diff.push(None); } else { diff --git a/objdiff-core/src/diff/display.rs b/objdiff-core/src/diff/display.rs index 3435181..262fb82 100644 --- a/objdiff-core/src/diff/display.rs +++ b/objdiff-core/src/diff/display.rs @@ -94,9 +94,9 @@ fn display_reloc_name( mut cb: impl FnMut(DiffText) -> Result<(), E>, ) -> Result<(), E> { cb(DiffText::Symbol(&reloc.target))?; - match reloc.target.addend.cmp(&0i64) { - Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.target.addend))), - Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.target.addend))), + match reloc.addend.cmp(&0i64) { + Ordering::Greater => cb(DiffText::Basic(&format!("+{:#x}", reloc.addend))), + Ordering::Less => cb(DiffText::Basic(&format!("-{:#x}", -reloc.addend))), _ => Ok(()), } } diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index f9e5783..95ce055 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -411,6 +411,8 @@ pub fn diff_objs( let left_code = process_code_symbol(left_obj, left_symbol_ref, config)?; let right_code = process_code_symbol(right_obj, right_symbol_ref, config)?; let (left_diff, right_diff) = diff_code( + left_obj, + right_obj, &left_code, &right_code, left_symbol_ref, @@ -424,6 +426,8 @@ pub fn diff_objs( let (prev_obj, prev_out) = prev.as_mut().unwrap(); let prev_code = process_code_symbol(prev_obj, prev_symbol_ref, config)?; let (_, prev_diff) = diff_code( + left_obj, + right_obj, &right_code, &prev_code, right_symbol_ref, @@ -592,6 +596,8 @@ fn generate_mapping_symbols( ObjSectionKind::Code => { let target_code = process_code_symbol(target_obj, target_symbol_ref, config)?; let (left_diff, _right_diff) = diff_code( + target_obj, + base_obj, &target_code, base_code.as_ref().unwrap(), target_symbol_ref, diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index 68af116..4b7c29a 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -131,7 +131,7 @@ pub struct ObjSymbol { pub size_known: bool, pub kind: ObjSymbolKind, pub flags: ObjSymbolFlagSet, - pub addend: i64, + pub orig_section_index: Option, /// Original virtual address (from .note.split section) pub virtual_address: Option, /// Original index in object symbol table @@ -155,7 +155,7 @@ pub struct ObjReloc { pub flags: RelocationFlags, pub address: u64, pub target: ObjSymbol, - pub target_section: Option, + pub addend: i64, } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index a1ff44b..2cd7f23 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -13,8 +13,8 @@ use object::{ endian::LittleEndian as LE, pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber}, read::coff::{CoffFile, CoffHeader, ImageSymbol}, - BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex, - SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, + BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, Section, + SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, }; use crate::{ @@ -41,7 +41,6 @@ fn to_obj_symbol( arch: &dyn ObjArch, obj_file: &File<'_>, symbol: &Symbol<'_, '_>, - addend: i64, split_meta: Option<&SplitMeta>, ) -> Result { let mut name = symbol.name().context("Failed to process symbol name")?; @@ -111,7 +110,7 @@ fn to_obj_symbol( size_known: symbol.size() != 0, kind, flags, - addend, + orig_section_index: symbol.section_index().map(|i| i.0), virtual_address, original_index: Some(symbol.index().0), bytes: bytes.to_vec(), @@ -177,7 +176,7 @@ fn symbols_by_section( continue; } } - result.push(to_obj_symbol(arch, obj_file, symbol, 0, split_meta)?); + result.push(to_obj_symbol(arch, obj_file, symbol, split_meta)?); } result.sort_by(|a, b| a.address.cmp(&b.address).then(a.size.cmp(&b.size))); let mut iter = result.iter_mut().peekable(); @@ -217,7 +216,7 @@ fn symbols_by_section( ObjSectionKind::Data | ObjSectionKind::Bss => ObjSymbolKind::Object, }, flags: Default::default(), - addend: 0, + orig_section_index: Some(section.orig_index), virtual_address: None, original_index: None, bytes: Vec::new(), @@ -234,7 +233,7 @@ fn common_symbols( obj_file .symbols() .filter(Symbol::is_common) - .map(|symbol| to_obj_symbol(arch, obj_file, &symbol, 0, split_meta)) + .map(|symbol| to_obj_symbol(arch, obj_file, &symbol, split_meta)) .collect::>>() } @@ -245,10 +244,18 @@ fn best_symbol<'r, 'data, 'file>( symbols: &'r [Symbol<'data, 'file>], address: u64, ) -> Option<&'r Symbol<'data, 'file>> { - let closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) { + let mut closest_symbol_index = match symbols.binary_search_by_key(&address, |s| s.address()) { Ok(index) => Some(index), Err(index) => index.checked_sub(1), }?; + // The binary search may not find the first symbol at the address, so work backwards + let target_address = symbols[closest_symbol_index].address(); + while let Some(prev_index) = closest_symbol_index.checked_sub(1) { + if symbols[prev_index].address() != target_address { + break; + } + closest_symbol_index = prev_index; + } let mut best_symbol: Option<&'r Symbol<'data, 'file>> = None; for symbol in symbols.iter().skip(closest_symbol_index) { if symbol.address() > address { @@ -276,24 +283,15 @@ fn best_symbol<'r, 'data, 'file>( fn find_section_symbol( arch: &dyn ObjArch, obj_file: &File<'_>, + section: &Section, section_symbols: &[Symbol<'_, '_>], - target: &Symbol<'_, '_>, address: u64, split_meta: Option<&SplitMeta>, ) -> Result { if let Some(symbol) = best_symbol(section_symbols, address) { - return to_obj_symbol( - arch, - obj_file, - symbol, - address as i64 - symbol.address() as i64, - split_meta, - ); + return to_obj_symbol(arch, obj_file, symbol, split_meta); } // Fallback to section symbol - let section_index = - target.section_index().ok_or_else(|| anyhow::Error::msg("Unknown section index"))?; - let section = obj_file.section_by_index(section_index)?; Ok(ObjSymbol { name: section.name()?.to_string(), demangled_name: None, @@ -303,7 +301,7 @@ fn find_section_symbol( size_known: false, kind: ObjSymbolKind::Section, flags: Default::default(), - addend: address as i64 - section.address() as i64, + orig_section_index: Some(section.index().0), virtual_address: None, original_index: None, bytes: Vec::new(), @@ -314,7 +312,7 @@ fn relocations_by_section( arch: &dyn ObjArch, obj_file: &File<'_>, section: &ObjSection, - section_symbols: &[Symbol<'_, '_>], + section_symbols: &[Vec>], split_meta: Option<&SplitMeta>, ) -> Result> { let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?; @@ -339,37 +337,36 @@ fn relocations_by_section( _ => bail!("Unhandled relocation target: {:?}", reloc.target()), }; let flags = reloc.flags(); // TODO validate reloc here? - let target_section = match symbol.section() { - SymbolSection::Common => Some(".comm".to_string()), - SymbolSection::Section(idx) => { - obj_file.section_by_index(idx).and_then(|s| s.name().map(|s| s.to_string())).ok() - } - _ => None, - }; - let addend = if reloc.has_implicit_addend() { + let mut addend = if reloc.has_implicit_addend() { arch.implcit_addend(obj_file, section, address, &reloc)? } else { reloc.addend() }; - // println!("Reloc: {reloc:?}, symbol: {symbol:?}, addend: {addend:#x}"); let target = match symbol.kind() { SymbolKind::Text | SymbolKind::Data | SymbolKind::Label | SymbolKind::Unknown => { - to_obj_symbol(arch, obj_file, &symbol, addend, split_meta) + to_obj_symbol(arch, obj_file, &symbol, split_meta)? } SymbolKind::Section => { - ensure!(addend >= 0, "Negative addend in reloc: {addend}"); - find_section_symbol( + ensure!(addend >= 0, "Negative addend in section reloc: {addend}"); + let section_index = symbol + .section_index() + .ok_or_else(|| anyhow!("Section symbol {symbol:?} has no section index"))?; + let section = obj_file.section_by_index(section_index)?; + let symbol = find_section_symbol( arch, obj_file, - section_symbols, - &symbol, + §ion, + §ion_symbols[section_index.0], addend as u64, split_meta, - ) + )?; + // Adjust addend to be relative to the selected symbol + addend = (symbol.address - section.address()) as i64; + symbol } - kind => Err(anyhow!("Unhandled relocation symbol type {kind:?}")), - }?; - relocations.push(ObjReloc { flags, address, target, target_section }); + kind => bail!("Unhandled relocation symbol type {kind:?}"), + }; + relocations.push(ObjReloc { flags, address, target, addend }); } Ok(relocations) } @@ -591,7 +588,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result Result Result { let obj_file = File::parse(data)?; let arch = new_arch(&obj_file)?; let split_meta = split_meta(&obj_file)?; - let mut sections = filter_sections(&obj_file, split_meta.as_ref())?; - let mut name_counts: HashMap = HashMap::new(); - for section in &mut sections { + + // Create sorted symbol list for each section + let mut section_symbols = Vec::with_capacity(obj_file.sections().count()); + for section in obj_file.sections() { let mut symbols = obj_file .symbols() - .filter(|s| s.section_index() == Some(SectionIndex(section.orig_index))) + .filter(|s| s.section_index() == Some(section.index())) .collect::>(); symbols.sort_by_key(|s| s.address()); + let section_index = section.index().0; + if section_index >= section_symbols.len() { + section_symbols.resize_with(section_index + 1, Vec::new); + } + section_symbols[section_index] = symbols; + } + + let mut sections = filter_sections(&obj_file, split_meta.as_ref())?; + let mut section_name_counts: HashMap = HashMap::new(); + for section in &mut sections { section.symbols = symbols_by_section( arch.as_ref(), &obj_file, section, - &symbols, + §ion_symbols[section.orig_index], split_meta.as_ref(), - &mut name_counts, + &mut section_name_counts, )?; section.relocations = relocations_by_section( arch.as_ref(), &obj_file, section, - &symbols, + §ion_symbols, split_meta.as_ref(), )?; } diff --git a/objdiff-gui/src/views/function_diff.rs b/objdiff-gui/src/views/function_diff.rs index d372220..dea683c 100644 --- a/objdiff-gui/src/views/function_diff.rs +++ b/objdiff-gui/src/views/function_diff.rs @@ -3,7 +3,6 @@ use std::default::Default; use egui::{text::LayoutJob, Id, Label, Response, RichText, Sense, Widget}; use egui_extras::TableRow; use objdiff_core::{ - arch::ObjArch, diff::{ display::{display_diff, DiffText, HighlightKind}, ObjDiff, ObjInsDiff, ObjInsDiffKind, @@ -77,7 +76,7 @@ impl FunctionViewState { fn ins_hover_ui( ui: &mut egui::Ui, - arch: &dyn ObjArch, + obj: &ObjInfo, section: &ObjSection, ins: &ObjIns, symbol: &ObjSymbol, @@ -120,10 +119,17 @@ fn ins_hover_ui( } if let Some(reloc) = &ins.reloc { - ui.label(format!("Relocation type: {}", arch.display_reloc(reloc.flags))); + ui.label(format!("Relocation type: {}", obj.arch.display_reloc(reloc.flags))); ui.colored_label(appearance.highlight_color, format!("Name: {}", reloc.target.name)); - if let Some(section) = &reloc.target_section { - ui.colored_label(appearance.highlight_color, format!("Section: {section}")); + if let Some(orig_section_index) = reloc.target.orig_section_index { + if let Some(section) = + obj.sections.iter().find(|s| s.orig_index == orig_section_index) + { + ui.colored_label( + appearance.highlight_color, + format!("Section: {}", section.name), + ); + } ui.colored_label( appearance.highlight_color, format!("Address: {:x}", reloc.target.address), @@ -132,9 +138,10 @@ fn ins_hover_ui( appearance.highlight_color, format!("Size: {:x}", reloc.target.size), ); - if let Some(s) = arch + if let Some(s) = obj + .arch .guess_data_type(ins) - .and_then(|ty| arch.display_data_type(ty, &reloc.target.bytes)) + .and_then(|ty| obj.arch.display_data_type(ty, &reloc.target.bytes)) { ui.colored_label(appearance.highlight_color, s); } @@ -370,7 +377,7 @@ fn asm_col_ui( if let Some(ins) = &ins_diff.ins { response.context_menu(|ui| ins_context_menu(ui, section, ins, symbol)); response.on_hover_ui_at_pointer(|ui| { - ins_hover_ui(ui, ctx.obj.arch.as_ref(), section, ins, symbol, appearance) + ins_hover_ui(ui, ctx.obj, section, ins, symbol, appearance) }) } else { response