From 5ba4ee0d90aab0a712185f7ad99743a703402276 Mon Sep 17 00:00:00 2001 From: Haydn Trigg Date: Sun, 14 Jun 2026 00:22:43 +0930 Subject: [PATCH 1/2] Mach-O Object Support --- objdiff-core/Cargo.toml | 2 +- objdiff-core/src/arch/ppc/mod.rs | 2 ++ objdiff-core/src/arch/x86.rs | 19 +++++++++++++++++++ objdiff-core/src/bindings/diff.rs | 1 + objdiff-core/src/obj/mod.rs | 1 + objdiff-core/src/obj/read.rs | 11 ++++++++--- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/objdiff-core/Cargo.toml b/objdiff-core/Cargo.toml index a0f4602e..8e5604bb 100644 --- a/objdiff-core/Cargo.toml +++ b/objdiff-core/Cargo.toml @@ -132,7 +132,7 @@ itertools = { version = "0.15", default-features = false, features = ["use_alloc log = { version = "0.4", default-features = false, optional = true } memmap2 = { version = "0.9", optional = true } num-traits = { version = "0.2", default-features = false, optional = true } -object = { version = "0.39.1", default-features = false, features = ["read_core", "elf", "coff"] } +object = { version = "0.39.1", default-features = false, features = ["read_core", "elf", "coff", "macho"] } pbjson = { version = "0.9", default-features = false, optional = true } prost = { version = "0.14", default-features = false, features = ["derive"], optional = true } regex = { version = "1.12", default-features = false, features = [], optional = true } diff --git a/objdiff-core/src/arch/ppc/mod.rs b/objdiff-core/src/arch/ppc/mod.rs index be6a6a1a..f888efdd 100644 --- a/objdiff-core/src/arch/ppc/mod.rs +++ b/objdiff-core/src/arch/ppc/mod.rs @@ -332,6 +332,7 @@ impl Arch for ArchPpc { pe::IMAGE_REL_PPC_PAIR => Some("IMAGE_REL_PPC_PAIR"), _ => None, }, + RelocationFlags::MachO { .. } => None, } } @@ -346,6 +347,7 @@ impl Arch for ArchPpc { pe::IMAGE_REL_PPC_ADDR32 => 4, _ => 1, }, + RelocationFlags::MachO { .. } => 1, } } diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index b02bd0ee..6c43638c 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -77,6 +77,7 @@ impl ArchX86 { elf::R_386_16 => Some(2), _ => None, }, + RelocationFlags::MachO { r_length, .. } => Some(1 << r_length as usize), }, Architecture::X86_64 => match flags { RelocationFlags::Coff(typ) => match typ { @@ -96,6 +97,7 @@ impl ArchX86 { elf::R_X86_64_64 => Some(8), _ => None, }, + RelocationFlags::MachO { .. } => None, }, } } @@ -303,6 +305,22 @@ impl Arch for ArchX86 { section.data()?[address as usize..address as usize + 4].try_into()?; self.endianness.read_i32(data) as i64 } + object::RelocationFlags::MachO { r_length, .. } => { + let size = 1usize << r_length as usize; + match size { + 4 => { + let data = section.data()?[address as usize..address as usize + 4] + .try_into()?; + self.endianness.read_i32(data) as i64 + } + 8 => { + let data = section.data()?[address as usize..address as usize + 8] + .try_into()?; + self.endianness.read_i64(data) + } + _ => bail!("Unsupported MachO x86 implicit relocation length: {r_length}"), + } + } flags => bail!("Unsupported x86 implicit relocation {flags:?}"), }, Architecture::X86_64 => match relocation.flags() { @@ -352,6 +370,7 @@ impl Arch for ArchX86 { elf::R_386_16 => Some("R_386_16"), _ => None, }, + RelocationFlags::MachO { .. } => None, }, Architecture::X86_64 => match flags { RelocationFlags::Coff(typ) => match typ { diff --git a/objdiff-core/src/bindings/diff.rs b/objdiff-core/src/bindings/diff.rs index a6a4e7af..40389d64 100644 --- a/objdiff-core/src/bindings/diff.rs +++ b/objdiff-core/src/bindings/diff.rs @@ -294,6 +294,7 @@ fn relocation_type(flags: obj::RelocationFlags) -> u32 { match flags { obj::RelocationFlags::Elf(r_type) => r_type, obj::RelocationFlags::Coff(typ) => typ as u32, + obj::RelocationFlags::MachO { r_type, .. } => r_type as u32, } } diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index 29e57b4e..177de277 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -375,6 +375,7 @@ pub struct Relocation { pub enum RelocationFlags { Elf(u32), Coff(u16), + MachO { r_type: u8, r_pcrel: bool, r_length: u8 }, } #[derive(Debug, Copy, Clone)] diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index 49ec2c3d..d543d46e 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -142,7 +142,7 @@ fn map_symbol( if symbol.is_weak() { flags |= SymbolFlag::Weak; } - if file.format() == object::BinaryFormat::Elf + if matches!(file.format(), object::BinaryFormat::Elf | object::BinaryFormat::MachO) && symbol.scope() == object::SymbolScope::Linkage && (file.architecture() != Architecture::Arm || !symbol.is_global()) { @@ -285,6 +285,7 @@ fn add_section_symbols(sections: &[Section], symbols: &mut Vec) { // `section.size` can include extra padding, so instead prefer using the address that the // last symbol ends at when there are any symbols in the section. + // Compute size as a section-relative offset (important for non-zero section.address, e.g. Mach-O). let size = symbols .iter() .filter(|s| { @@ -292,13 +293,14 @@ fn add_section_symbols(sections: &[Section], symbols: &mut Vec) { }) .map(|s| s.address + s.size) .max() - .unwrap_or(section.size); + .unwrap_or(section.address + section.size) + .saturating_sub(section.address); symbols.push(Symbol { name, demangled_name: None, normalized_name: None, - address: 0, + address: section.address, size, kind: SymbolKind::Section, section: Some(section_idx), @@ -620,6 +622,9 @@ fn map_section_relocations( let flags = match reloc.flags() { object::RelocationFlags::Elf { r_type } => RelocationFlags::Elf(r_type), object::RelocationFlags::Coff { typ } => RelocationFlags::Coff(typ), + object::RelocationFlags::MachO { r_type, r_pcrel, r_length } => { + RelocationFlags::MachO { r_type, r_pcrel, r_length } + } flags => bail!("Unhandled relocation flags: {:?}", flags), }; let target_symbol = match symbol_indices.get(symbol_index.0).copied() { From 2380b2832cf6e6fbc8b9454862af959622f9f4e3 Mon Sep 17 00:00:00 2001 From: Haydn Trigg Date: Tue, 8 Sep 2026 10:47:44 +0930 Subject: [PATCH 2/2] Mach-O Tests --- objdiff-core/src/arch/arm.rs | 134 ++++- objdiff-core/src/arch/arm64.rs | 135 ++++- objdiff-core/src/arch/mod.rs | 33 +- objdiff-core/src/arch/x86.rs | 94 +++- .../tests/data/macho/fibonacci_arm64.o | Bin 0 -> 1032 bytes .../tests/data/macho/fibonacci_arm64_32.o | Bin 0 -> 916 bytes .../tests/data/macho/fibonacci_armv6.o | Bin 0 -> 716 bytes .../tests/data/macho/fibonacci_armv6_thumb.o | Bin 0 -> 648 bytes .../tests/data/macho/fibonacci_armv7.o | Bin 0 -> 660 bytes .../tests/data/macho/fibonacci_i386.o | Bin 0 -> 972 bytes .../tests/data/macho/fibonacci_x86_64.o | Bin 0 -> 1024 bytes objdiff-core/tests/macho.rs | 58 +++ .../tests/snapshots/arch_arm__read_arm.snap | 1 + .../tests/snapshots/arch_arm__read_thumb.snap | 1 + .../snapshots/macho__arm64_32_display.snap | 28 + .../macho__arm64_32_instructions.snap | 356 +++++++++++++ .../snapshots/macho__arm64_32_object.snap | 276 ++++++++++ .../tests/snapshots/macho__arm64_display.snap | 27 + .../snapshots/macho__arm64_instructions.snap | 342 +++++++++++++ .../tests/snapshots/macho__arm64_object.snap | 276 ++++++++++ .../tests/snapshots/macho__armv6_display.snap | 26 + .../snapshots/macho__armv6_instructions.snap | 328 ++++++++++++ .../tests/snapshots/macho__armv6_object.snap | 176 +++++++ .../snapshots/macho__armv6_thumb_display.snap | 28 + .../macho__armv6_thumb_instructions.snap | 356 +++++++++++++ .../snapshots/macho__armv6_thumb_object.snap | 176 +++++++ .../tests/snapshots/macho__armv7_object.snap | 176 +++++++ .../tests/snapshots/macho__i386_display.snap | 36 ++ .../snapshots/macho__i386_instructions.snap | 482 ++++++++++++++++++ .../tests/snapshots/macho__i386_object.snap | 200 ++++++++ .../snapshots/macho__x86_64_display.snap | 28 + .../snapshots/macho__x86_64_instructions.snap | 356 +++++++++++++ .../tests/snapshots/macho__x86_64_object.snap | 200 ++++++++ 33 files changed, 4289 insertions(+), 40 deletions(-) create mode 100644 objdiff-core/tests/data/macho/fibonacci_arm64.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_arm64_32.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_armv6.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_armv6_thumb.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_armv7.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_i386.o create mode 100644 objdiff-core/tests/data/macho/fibonacci_x86_64.o create mode 100644 objdiff-core/tests/macho.rs create mode 100644 objdiff-core/tests/snapshots/macho__arm64_32_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__arm64_32_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__arm64_32_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__arm64_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__arm64_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__arm64_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_thumb_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_thumb_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv6_thumb_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__armv7_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__i386_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__i386_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__i386_object.snap create mode 100644 objdiff-core/tests/snapshots/macho__x86_64_display.snap create mode 100644 objdiff-core/tests/snapshots/macho__x86_64_instructions.snap create mode 100644 objdiff-core/tests/snapshots/macho__x86_64_object.snap diff --git a/objdiff-core/src/arch/arm.rs b/objdiff-core/src/arch/arm.rs index 4838ed28..1a3ebbb5 100644 --- a/objdiff-core/src/arch/arm.rs +++ b/objdiff-core/src/arch/arm.rs @@ -3,11 +3,14 @@ use core::fmt::Write; use anyhow::{Result, bail}; use arm_attr::{BuildAttrs, enums::CpuArch, tag::Tag}; -use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, elf}; +use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, elf, macho}; use unarm::FormatValue as _; use crate::{ - arch::{Arch, OPCODE_DATA, OPCODE_INVALID, RelocationOverride, RelocationOverrideTarget}, + arch::{ + Arch, OPCODE_DATA, OPCODE_INVALID, RelocationOverride, RelocationOverrideTarget, + macho_implicit_addend, + }, diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart}, obj::{ InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, Section, SectionKind, @@ -21,6 +24,9 @@ pub struct ArchArm { disasm_modes: BTreeMap>, detected_version: Option, endianness: object::Endianness, + /// Mach-O objects have no mapping symbols. Thumb functions are flagged in the symbol table + /// instead, so their disasm modes are collected up front and matched to sections in post_init. + macho_disasm_modes: Option>, } impl ArchArm { @@ -31,12 +37,67 @@ impl ArchArm { // The disasm_modes mapping is populated later in the post_init step so that we have access to merged sections. let disasm_modes = BTreeMap::new(); let detected_version = Self::elf_detect_arm_version(file)?; - Ok(Self { disasm_modes, detected_version, endianness }) + Ok(Self { disasm_modes, detected_version, endianness, macho_disasm_modes: None }) } + object::File::MachO32(_) => Ok(Self { + disasm_modes: BTreeMap::new(), + // Mach-O objects have no equivalent of the ARM build attributes, so the version is + // left to the user's configuration. + detected_version: None, + endianness, + macho_disasm_modes: Some(Self::macho_disasm_modes(file)), + }), _ => bail!("Unsupported file format {:?}", file.format()), } } + /// Collects the disassembly mode of every function in a Mach-O object, which is Thumb when the + /// symbol has the `N_ARM_THUMB_DEF` flag set and ARM otherwise. + fn macho_disasm_modes(file: &object::File) -> Vec { + let mut modes = file + .symbols() + .filter(|s| s.kind() == object::SymbolKind::Text) + .map(|s| { + let thumb = matches!( + s.flags(), + object::SymbolFlags::MachO { n_desc } if n_desc & macho::N_ARM_THUMB_DEF != 0 + ); + let mapping = if thumb { unarm::ParseMode::Thumb } else { unarm::ParseMode::Arm }; + DisasmMode { address: s.address() as u32, mapping } + }) + .collect::>(); + modes.sort_unstable_by_key(|x| x.address); + modes + } + + /// Matches the Mach-O disassembly modes collected in [`Self::macho_disasm_modes`] to the + /// section that each function ended up in. + fn macho_mapping_symbols( + sections: &[Section], + symbols: &[Symbol], + modes: &[DisasmMode], + ) -> BTreeMap> { + sections + .iter() + .enumerate() + .filter(|(_, section)| section.kind == SectionKind::Code) + .map(|(index, _)| { + let mut mapping_symbols: Vec<_> = symbols + .iter() + .filter(|s| s.section == Some(index) && s.kind == SymbolKind::Function) + .filter_map(|s| { + modes + .binary_search_by_key(&(s.address as u32), |m| m.address) + .ok() + .map(|i| modes[i]) + }) + .collect(); + mapping_symbols.sort_unstable_by_key(|x| x.address); + (index, mapping_symbols) + }) + .collect() + } + fn elf_detect_arm_version(file: &object::File) -> Result> { // Check ARM attributes if let Some(arm_attrs) = file.sections().find(|s| { @@ -163,7 +224,10 @@ impl ArchArm { impl Arch for ArchArm { fn post_init(&mut self, sections: &[Section], symbols: &[Symbol], _symbol_indices: &[usize]) { - self.disasm_modes = Self::get_mapping_symbols(sections, symbols); + self.disasm_modes = match &self.macho_disasm_modes { + Some(modes) => Self::macho_mapping_symbols(sections, symbols, modes), + None => Self::get_mapping_symbols(sections, symbols), + }; } fn scan_instructions_internal( @@ -334,7 +398,7 @@ impl Arch for ArchArm { fn relocation_override( &self, - _file: &object::File<'_>, + file: &object::File<'_>, section: &object::Section, address: u64, relocation: &object::Relocation, @@ -409,6 +473,54 @@ impl Arch for ArchArm { Ok(None) } } + // Handle Mach-O implicit relocations + object::RelocationFlags::MachO { r_type, r_pcrel, r_length } + if relocation.has_implicit_addend() => + { + let section_data = section.data()?; + let offset = address as usize; + let (field, pc) = match r_type { + macho::ARM_RELOC_VANILLA => { + let field = match 1usize << r_length as usize { + 1 => section_data[offset] as i8 as i64, + 2 => { + let data = section_data[offset..offset + 2].try_into()?; + self.endianness.read_i16(data) as i64 + } + 4 => { + let data = section_data[offset..offset + 4].try_into()?; + self.endianness.read_i32(data) as i64 + } + _ => bail!("Unsupported Mach-O ARM relocation length: {r_length}"), + }; + (field, 0) + } + macho::ARM_RELOC_BR24 => { + let data = section_data[offset..offset + 4].try_into()?; + let imm24 = self.endianness.read_i32(data) & 0xffffff; + // The ARM program counter is two instructions ahead of the branch. + ((((imm24 << 8) >> 8) << 2) as i64, section.address() + address + 8) + } + macho::ARM_THUMB_RELOC_BR22 => { + let data = section_data[offset..offset + 2].try_into()?; + let high = self.endianness.read_i16(data) as i32; + let data = section_data[offset + 2..offset + 4].try_into()?; + let low = self.endianness.read_i16(data) as i32; + let imm22 = ((high & 0x7ff) << 11) | (low & 0x7ff); + // The Thumb program counter is one instruction ahead of the branch. + ((((imm22 << 1) << 9) >> 9) as i64, section.address() + address + 4) + } + _ => bail!("Unsupported Mach-O ARM relocation type: {r_type}"), + }; + let addend = macho_implicit_addend( + file, + relocation, + field, + if r_pcrel { pc } else { 0 }, + false, + )?; + Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend })) + } _ => Ok(None), } } @@ -562,7 +674,11 @@ impl unarm::FormatIns for ArgsFormatter<'_> { fn write_uimm(&mut self, uimm: u32) -> core::fmt::Result { if let Some(resolved) = self.resolved.relocation - && let RelocationFlags::Elf(elf::R_ARM_ABS32) = resolved.relocation.flags + && matches!( + resolved.relocation.flags, + RelocationFlags::Elf(elf::R_ARM_ABS32) + | RelocationFlags::MachO { r_type: macho::ARM_RELOC_VANILLA, .. } + ) { return self.write(InstructionPart::reloc()); } @@ -582,7 +698,11 @@ impl unarm::FormatIns for ArgsFormatter<'_> { | RelocationFlags::Elf(elf::R_ARM_XPC25) | RelocationFlags::Elf(elf::R_ARM_CALL) | RelocationFlags::Elf(elf::R_ARM_THM_PC11) - | RelocationFlags::Elf(elf::R_ARM_THM_PC9) => { + | RelocationFlags::Elf(elf::R_ARM_THM_PC9) + | RelocationFlags::MachO { + r_type: macho::ARM_RELOC_BR24 | macho::ARM_THUMB_RELOC_BR22, + .. + } => { return self.write(InstructionPart::reloc()); } _ => {} diff --git a/objdiff-core/src/arch/arm64.rs b/objdiff-core/src/arch/arm64.rs index 891a105c..a0e4f68a 100644 --- a/objdiff-core/src/arch/arm64.rs +++ b/objdiff-core/src/arch/arm64.rs @@ -1,8 +1,8 @@ use alloc::{format, string::ToString, vec::Vec}; use core::cmp::Ordering; -use anyhow::Result; -use object::elf; +use anyhow::{Result, bail}; +use object::{Endian as _, ObjectSection as _, elf, macho}; use yaxpeax_arch::{Arch as YaxpeaxArch, Decoder, Reader, U8Reader}; use yaxpeax_arm::armv8::a64::{ ARMv8, DecodeError, InstDecoder, Instruction, Opcode, Operand, SIMDSizeCode, ShiftStyle, @@ -10,7 +10,9 @@ use yaxpeax_arm::armv8::a64::{ }; use crate::{ - arch::{Arch, OPCODE_INVALID}, + arch::{ + Arch, OPCODE_INVALID, RelocationOverride, RelocationOverrideTarget, macho_implicit_addend, + }, diff::{DiffObjConfig, display::InstructionPart}, obj::{ InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation, @@ -22,8 +24,65 @@ pub struct ArchArm64 {} impl ArchArm64 { pub fn new(_file: &object::File) -> Result { Ok(Self {}) } + + /// Decodes the implicit addend of a Mach-O relocation. + fn macho_addend( + &self, + file: &object::File<'_>, + section: &object::Section, + address: u64, + relocation: &object::Relocation, + r_type: u8, + r_pcrel: bool, + r_length: u8, + ) -> Result { + let offset = address as usize; + let data = section.data()?; + // arm64 relocations are always little endian. + let endian = object::LittleEndian; + let (field, pc) = match r_type { + macho::ARM64_RELOC_UNSIGNED | macho::ARM64_RELOC_SUBTRACTOR => { + let field = match 1usize << r_length as usize { + 4 => endian.read_i32(data[offset..offset + 4].try_into()?) as i64, + 8 => endian.read_i64(data[offset..offset + 8].try_into()?), + _ => bail!("Unsupported Mach-O arm64 relocation length: {r_length}"), + }; + (field, 0) + } + _ => { + let ins = endian.read_u32(data[offset..offset + 4].try_into()?); + let pc = section.address() + address; + match r_type { + macho::ARM64_RELOC_BRANCH26 => { + (sign_extend(((ins & 0x03ff_ffff) << 2) as i64, 28), pc) + } + macho::ARM64_RELOC_PAGE21 + | macho::ARM64_RELOC_GOT_LOAD_PAGE21 + | macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => { + let imm = (((ins >> 5) & 0x0007_ffff) << 2) | ((ins >> 29) & 0x3); + // The addend of a section relocation can only be recovered to page + // granularity, since the low 12 bits live in the paired PAGEOFF12. + (sign_extend((imm as i64) << 12, 33), pc & !0xfff) + } + macho::ARM64_RELOC_PAGEOFF12 + | macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 + | macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { + let imm12 = ((ins >> 10) & 0xfff) as i64; + // Load/store instructions scale the immediate by the access size. + let is_load_store = ins & 0x3b00_0000 == 0x3900_0000; + (if is_load_store { imm12 << (ins >> 30) } else { imm12 }, 0) + } + _ => bail!("Unsupported Mach-O arm64 relocation type: {r_type}"), + } + } + }; + // arm64 relocations against a symbol store the addend in the relocation field directly. + macho_implicit_addend(file, relocation, field, if r_pcrel { pc } else { 0 }, true) + } } +fn sign_extend(value: i64, bits: u32) -> i64 { (value << (64 - bits)) >> (64 - bits) } + impl Arch for ArchArm64 { fn scan_instructions_internal( &self, @@ -104,8 +163,41 @@ impl Arch for ArchArm64 { Ok(()) } + fn relocation_override( + &self, + file: &object::File<'_>, + section: &object::Section, + address: u64, + relocation: &object::Relocation, + ) -> Result> { + if !relocation.has_implicit_addend() { + return Ok(None); + } + let object::RelocationFlags::MachO { r_type, r_pcrel, r_length } = relocation.flags() + else { + return Ok(None); + }; + let addend = + self.macho_addend(file, section, address, relocation, r_type, r_pcrel, r_length)?; + Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend })) + } + fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> { match flags { + RelocationFlags::MachO { r_type, .. } => match r_type { + macho::ARM64_RELOC_UNSIGNED => Some("ARM64_RELOC_UNSIGNED"), + macho::ARM64_RELOC_SUBTRACTOR => Some("ARM64_RELOC_SUBTRACTOR"), + macho::ARM64_RELOC_BRANCH26 => Some("ARM64_RELOC_BRANCH26"), + macho::ARM64_RELOC_PAGE21 => Some("ARM64_RELOC_PAGE21"), + macho::ARM64_RELOC_PAGEOFF12 => Some("ARM64_RELOC_PAGEOFF12"), + macho::ARM64_RELOC_GOT_LOAD_PAGE21 => Some("ARM64_RELOC_GOT_LOAD_PAGE21"), + macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 => Some("ARM64_RELOC_GOT_LOAD_PAGEOFF12"), + macho::ARM64_RELOC_POINTER_TO_GOT => Some("ARM64_RELOC_POINTER_TO_GOT"), + macho::ARM64_RELOC_TLVP_LOAD_PAGE21 => Some("ARM64_RELOC_TLVP_LOAD_PAGE21"), + macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => Some("ARM64_RELOC_TLVP_LOAD_PAGEOFF12"), + macho::ARM64_RELOC_ADDEND => Some("ARM64_RELOC_ADDEND"), + _ => None, + }, RelocationFlags::Elf(r_type) => match r_type { elf::R_AARCH64_NONE => Some("R_AARCH64_NONE"), elf::R_AARCH64_ABS64 => Some("R_AARCH64_ABS64"), @@ -129,6 +221,9 @@ impl Arch for ArchArm64 { fn data_reloc_size(&self, flags: RelocationFlags) -> usize { match flags { + RelocationFlags::MachO { r_type: macho::ARM64_RELOC_UNSIGNED, r_length, .. } => { + 1 << r_length as usize + } RelocationFlags::Elf(r_type) => match r_type { elf::R_AARCH64_ABS64 => 8, elf::R_AARCH64_ABS32 => 4, @@ -2075,12 +2170,21 @@ where Cb: FnMut(InstructionPart<'static>) { /// Relocations that appear in Operand::PCOffset. fn is_pc_offset_reloc(reloc: Option) -> Option { if let Some(resolved) = reloc - && let RelocationFlags::Elf( - elf::R_AARCH64_ADR_PREL_PG_HI21 - | elf::R_AARCH64_JUMP26 - | elf::R_AARCH64_CALL26 - | elf::R_AARCH64_ADR_GOT_PAGE, - ) = resolved.relocation.flags + && matches!( + resolved.relocation.flags, + RelocationFlags::Elf( + elf::R_AARCH64_ADR_PREL_PG_HI21 + | elf::R_AARCH64_JUMP26 + | elf::R_AARCH64_CALL26 + | elf::R_AARCH64_ADR_GOT_PAGE, + ) | RelocationFlags::MachO { + r_type: macho::ARM64_RELOC_BRANCH26 + | macho::ARM64_RELOC_PAGE21 + | macho::ARM64_RELOC_GOT_LOAD_PAGE21 + | macho::ARM64_RELOC_TLVP_LOAD_PAGE21, + .. + } + ) { return Some(resolved); } @@ -2090,7 +2194,11 @@ fn is_pc_offset_reloc(reloc: Option) -> Option) -> bool { resolved.is_some_and(|r| { - matches!(r.relocation.flags, RelocationFlags::Elf(elf::R_AARCH64_ADD_ABS_LO12_NC)) + matches!( + r.relocation.flags, + RelocationFlags::Elf(elf::R_AARCH64_ADD_ABS_LO12_NC) + | RelocationFlags::MachO { r_type: macho::ARM64_RELOC_PAGEOFF12, .. } + ) }) } @@ -2101,7 +2209,12 @@ fn is_reg_index_reloc(resolved: Option) -> bool { r.relocation.flags, RelocationFlags::Elf( elf::R_AARCH64_LDST32_ABS_LO12_NC | elf::R_AARCH64_LD64_GOT_LO12_NC - ) + ) | RelocationFlags::MachO { + r_type: macho::ARM64_RELOC_PAGEOFF12 + | macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12 + | macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12, + .. + } ) }) } diff --git a/objdiff-core/src/arch/mod.rs b/objdiff-core/src/arch/mod.rs index fa41a744..9bde8c9f 100644 --- a/objdiff-core/src/arch/mod.rs +++ b/objdiff-core/src/arch/mod.rs @@ -505,6 +505,35 @@ pub trait Arch: Any + Debug + Send + Sync { } } +/// Resolves the addend of a Mach-O relocation, which has no explicit addend field. +/// +/// Instead, the relocation field holds the value that the assembler computed for the target, so +/// the addend has to be recovered from it. PC-relative relocations are biased by the program +/// counter, and relocations against a section hold the target's address rather than its offset, +/// which is what the relocation target resolution expects for Mach-O. Newer Mach-O formats +/// (x86-64 and arm64) instead store the addend directly when the relocation targets a symbol. +/// +/// `field` is the value decoded from the relocation field and `pc` is the program counter that +/// the relocation is relative to, or 0 if it isn't PC-relative. +#[allow(dead_code)] // Only used by architectures that support Mach-O +pub(crate) fn macho_implicit_addend( + file: &object::File<'_>, + relocation: &object::Relocation, + field: i64, + pc: u64, + symbol_field_is_addend: bool, +) -> Result { + use object::{Object as _, ObjectSymbol as _}; + match relocation.target() { + object::RelocationTarget::Symbol(index) if !symbol_field_is_addend => { + let symbol_address = file.symbol_by_index(index)?.address(); + Ok(field + pc as i64 - symbol_address as i64) + } + object::RelocationTarget::Section(_) => Ok(field + pc as i64), + _ => Ok(field), + } +} + pub fn new_arch(object: &object::File, diff_side: DiffSide) -> Result> { use object::Object as _; // Avoid unused warnings on non-mips builds @@ -524,7 +553,9 @@ pub fn new_arch(object: &object::File, diff_side: DiffSide) -> Result Box::new(arm::ArchArm::new(object)?), #[cfg(feature = "arm64")] - object::Architecture::Aarch64 => Box::new(arm64::ArchArm64::new(object)?), + object::Architecture::Aarch64 | object::Architecture::Aarch64_Ilp32 => { + Box::new(arm64::ArchArm64::new(object)?) + } #[cfg(feature = "superh")] object::Architecture::SuperH => Box::new(superh::ArchSuperH::new(object)?), arch => bail!("Unsupported architecture: {arch:?}"), diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index 6c43638c..6cd072b0 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -6,10 +6,12 @@ use iced_x86::{ Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter, Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, Register, }; -use object::{Endian as _, Object as _, ObjectSection as _, elf, pe}; +use object::{Endian as _, Object as _, ObjectSection as _, elf, macho, pe}; use crate::{ - arch::{Arch, OPCODE_DATA, RelocationOverride, RelocationOverrideTarget}, + arch::{ + Arch, OPCODE_DATA, RelocationOverride, RelocationOverrideTarget, macho_implicit_addend, + }, diff::{DiffObjConfig, X86Formatter, display::InstructionPart}, obj::{InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, Section, Symbol}, }; @@ -97,10 +99,50 @@ impl ArchX86 { elf::R_X86_64_64 => Some(8), _ => None, }, - RelocationFlags::MachO { .. } => None, + RelocationFlags::MachO { r_length, .. } => Some(1 << r_length as usize), }, } } + + /// Decodes the implicit addend of a Mach-O relocation. + fn macho_addend( + &self, + file: &object::File<'_>, + section: &object::Section, + address: u64, + relocation: &object::Relocation, + r_type: u8, + r_pcrel: bool, + r_length: u8, + ) -> Result { + let offset = address as usize; + let size = 1usize << r_length as usize; + let data = section.data()?; + let field = match size { + 1 => data[offset] as i8 as i64, + 2 => self.endianness.read_i16(data[offset..offset + 2].try_into()?) as i64, + 4 => self.endianness.read_i32(data[offset..offset + 4].try_into()?) as i64, + 8 => self.endianness.read_i64(data[offset..offset + 8].try_into()?), + _ => bail!("Unsupported Mach-O x86 relocation length: {r_length}"), + }; + let pc = if r_pcrel { + // PC-relative relocations are relative to the end of the instruction, which for the + // SIGNED_N types is N bytes past the end of the relocation field. + let extra = match (&self.arch, r_type) { + (Architecture::X86_64, macho::X86_64_RELOC_SIGNED_1) => 1, + (Architecture::X86_64, macho::X86_64_RELOC_SIGNED_2) => 2, + (Architecture::X86_64, macho::X86_64_RELOC_SIGNED_4) => 4, + _ => 0, + }; + section.address() + address + size as u64 + extra + } else { + 0 + }; + // Unlike the generic (i386) relocations, x86-64 relocations against a symbol store the + // addend in the relocation field directly. + let symbol_field_is_addend = matches!(self.arch, Architecture::X86_64); + macho_implicit_addend(file, relocation, field, pc, symbol_field_is_addend) + } } impl Arch for ArchX86 { @@ -279,7 +321,7 @@ impl Arch for ArchX86 { fn relocation_override( &self, - _file: &object::File<'_>, + file: &object::File<'_>, section: &object::Section, address: u64, relocation: &object::Relocation, @@ -287,6 +329,11 @@ impl Arch for ArchX86 { if !relocation.has_implicit_addend() { return Ok(None); } + if let object::RelocationFlags::MachO { r_type, r_pcrel, r_length } = relocation.flags() { + let addend = + self.macho_addend(file, section, address, relocation, r_type, r_pcrel, r_length)?; + return Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend })); + } let addend = match self.arch { Architecture::X86 => match relocation.flags() { object::RelocationFlags::Coff { @@ -305,22 +352,6 @@ impl Arch for ArchX86 { section.data()?[address as usize..address as usize + 4].try_into()?; self.endianness.read_i32(data) as i64 } - object::RelocationFlags::MachO { r_length, .. } => { - let size = 1usize << r_length as usize; - match size { - 4 => { - let data = section.data()?[address as usize..address as usize + 4] - .try_into()?; - self.endianness.read_i32(data) as i64 - } - 8 => { - let data = section.data()?[address as usize..address as usize + 8] - .try_into()?; - self.endianness.read_i64(data) - } - _ => bail!("Unsupported MachO x86 implicit relocation length: {r_length}"), - } - } flags => bail!("Unsupported x86 implicit relocation {flags:?}"), }, Architecture::X86_64 => match relocation.flags() { @@ -370,7 +401,15 @@ impl Arch for ArchX86 { elf::R_386_16 => Some("R_386_16"), _ => None, }, - RelocationFlags::MachO { .. } => None, + RelocationFlags::MachO { r_type, .. } => match r_type { + macho::GENERIC_RELOC_VANILLA => Some("GENERIC_RELOC_VANILLA"), + macho::GENERIC_RELOC_PAIR => Some("GENERIC_RELOC_PAIR"), + macho::GENERIC_RELOC_SECTDIFF => Some("GENERIC_RELOC_SECTDIFF"), + macho::GENERIC_RELOC_LOCAL_SECTDIFF => Some("GENERIC_RELOC_LOCAL_SECTDIFF"), + macho::GENERIC_RELOC_PB_LA_PTR => Some("GENERIC_RELOC_PB_LA_PTR"), + macho::GENERIC_RELOC_TLV => Some("GENERIC_RELOC_TLV"), + _ => None, + }, }, Architecture::X86_64 => match flags { RelocationFlags::Coff(typ) => match typ { @@ -385,6 +424,19 @@ impl Arch for ArchX86 { pe::IMAGE_REL_AMD64_SECREL => Some("IMAGE_REL_AMD64_SECREL"), _ => None, }, + RelocationFlags::MachO { r_type, .. } => match r_type { + macho::X86_64_RELOC_UNSIGNED => Some("X86_64_RELOC_UNSIGNED"), + macho::X86_64_RELOC_SIGNED => Some("X86_64_RELOC_SIGNED"), + macho::X86_64_RELOC_BRANCH => Some("X86_64_RELOC_BRANCH"), + macho::X86_64_RELOC_GOT_LOAD => Some("X86_64_RELOC_GOT_LOAD"), + macho::X86_64_RELOC_GOT => Some("X86_64_RELOC_GOT"), + macho::X86_64_RELOC_SUBTRACTOR => Some("X86_64_RELOC_SUBTRACTOR"), + macho::X86_64_RELOC_SIGNED_1 => Some("X86_64_RELOC_SIGNED_1"), + macho::X86_64_RELOC_SIGNED_2 => Some("X86_64_RELOC_SIGNED_2"), + macho::X86_64_RELOC_SIGNED_4 => Some("X86_64_RELOC_SIGNED_4"), + macho::X86_64_RELOC_TLV => Some("X86_64_RELOC_TLV"), + _ => None, + }, _ => None, }, } diff --git a/objdiff-core/tests/data/macho/fibonacci_arm64.o b/objdiff-core/tests/data/macho/fibonacci_arm64.o new file mode 100644 index 0000000000000000000000000000000000000000..8179062fe719dda6d6740d12d48499ec6cbae484 GIT binary patch literal 1032 zcma)5K}#D^5T4z&Nwn1}@nA2q7KA8GP!Z8XXq5^%ELbFmP=sf?QQ5NDM6*Fbp@ANI zX&^tqgO|-O@F;lkCic*Cdb0;l^&mnTzuCN{YrJ$|-Z$UOyzlMK+r7NM`TK%MAs8>u z;1?X|aM&yOqF?ptljTlku4PZaqsX&svMz+Xb>K<@5F)#p%l_j*)Q|z|sfb%xScm$k z#t@hgX2spJoE@3y)eCgSW&Mc7Le@j^JZ7m_&YP~NI{TJW5W;vLYNu04-bp-$0KeN9 z7OC|}a*k{8?pU77T|_BF!|(+5#elqt`)0uVfoH%Bkav85v+0(LvzmK2*K-SE}Qz z?{LOO99pB`4VCIGE#BnZAC0`0HtNTf2#tJMq1_2+6MEZ+E8gwevIosNpR;X!N=#O# z^t3){+tmTeY}t0{jlN&nvkMat3)^CsJb87Qrw!CG>%Q~Y&ELi|zhDq*&h>`1J znrDoANE$%wH+c5IwBE%CfO#aU<~E{g#&`=pghXI`A43p4k%T=s$f literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/data/macho/fibonacci_arm64_32.o b/objdiff-core/tests/data/macho/fibonacci_arm64_32.o new file mode 100644 index 0000000000000000000000000000000000000000..761b2513b0c6dc89e3477d868851f9918032f52c GIT binary patch literal 916 zcmb7Cze^i&6n}S@nrK^p5C^A{3PLJPs3M|65XC}<153#eitsf}{Bh-SiROZWg8@eu z0~!1iOeROW6}ogPv_t85Ztc*iE-j?#=aW0r6kL4pxzFdly!W~9y?j6Z{_*F5h^~nU zaSv!v#QZ!&eM@+#UEnuzIDi3WDCKS*xW4xD%=2vKUru!fa9#(W;z17yNsYu%DqnH; zEN9zKk^k?(`A0yS27S?=!lP6y=kl(qI{TJWP|95GYn4kRabO2SocjuW{rJUFx0@ zZL#Ks<=0O`-g?G(H?IuH*wKpYYVa5Iw+~mE*K5m7_}2NZE$elBs`@0BicQ&ebx6{i zwq1G}+b`|eg~u>tEcn#>Y~~vPu7ST^XkHuaCQ$%mSBZ5n2F$F_Dee;cPMBcKncOir zh4c4(=oi+r>tQ`@E}=e*0)smrhS@oIKG0|2XMK8_8vorTI0}pevkwE!Gfx6Rxyv_N zRJrO_#8$YuqKY}o!L@z0h}D#wTt08TK?AO|yCt?;EYEhIGiXnuKM8>%k0O5o_Vj~% literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/data/macho/fibonacci_armv6.o b/objdiff-core/tests/data/macho/fibonacci_armv6.o new file mode 100644 index 0000000000000000000000000000000000000000..24625362e8a6477e37192161a5e8131516102e35 GIT binary patch literal 716 zcma)4JxIe)5WY02|6<1?A`vWDQ0(BKgOEk&n4yD+5^C#DCAOtav112Use_}?S0@LN z4z5B6X9qVINg4_jaddGoe%Gd0(7}T*-+lM)?!CNwkDu>f6GSuwNI(#Xv!nKO6YgL3 zgkTzZ%)>qcexhMmdu7WPAj3#(Y$kp*dv^fWbImF~+=CRVFtHg%s%RB5*@K?^)r0G2 zfpC9QKW|V*5DRtV{8vO#fOQ^8BVf)A17$c0_!>M99tU(_&^Wh`!TA4t-6aw-g@ioo zElUk;>2)N3)}p3xrI>KZ22|n7+NB-PZ*7V6mV7RpKu9=p6Ko4di3umD3g^S~rW@LQ zXOx74UQWN4MzuCk)pkAajWpq|=(ToGui6UoUO0wY?BxWZ74&^ZOwvwUAxgO16X$aq zmHQ5lX$9EN>@Gw~QFUF7m}Y5=;(MlvBI+B|}`T>Eo30l=3 za5gRje?erlXchf|Krj$mG@Y9c3AO0LnRCv2_df32d;jtFIZZ_4fCP*I2^R9ew;}(E z3mj&V$2>8FW0kY0C z08gkL4Z8mi259 z_d3xn&ku2vz~>0Q&JLd6NCEiQlN~U|n~Q;+@W{j5B$@%wN<6{A-dL|e`vH3$%(f=A dR5dE3o}{$`7P-HU28)GsCZiqW3QIQf^aWo(T~`1A literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/data/macho/fibonacci_armv7.o b/objdiff-core/tests/data/macho/fibonacci_armv7.o new file mode 100644 index 0000000000000000000000000000000000000000..158c015dfaf5785b84651cda689132fa1b378c34 GIT binary patch literal 660 zcma)4JxfAi6h8N=eQ9M|h{QD$EF2q5C?xF7$s#1ePM1MRhF7tfes)@nMNi&@@aj0sds29@NCtKjrB&Z%>zLQzGoi11m?YWfzjaJAx886(q8$A6msRas}J(s&Ij2f zH^v!Sbhb?9NK3Xz{%bKOZp4*vixtsn)SA^`SoHgY?Eux=MCFjteKTk&*mhXpEoUJ` z7~O^;3#;%77xarEt=fH^1}W8ADt+knl$Mos#iMDZDGDbwE$35Ca|P|lg+r(M_sPV- z_+-gFqDTIQ4x;;gaD?cVJ)*)s448;Ao9MfM4xmqfH_*o(QDHv~%t{mNd;bAz^pX=8 jJ`M9wlbSE-MN%{IbQX^qTf@O~*?1z6K0yf&uBYf5A0uUW literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/data/macho/fibonacci_i386.o b/objdiff-core/tests/data/macho/fibonacci_i386.o new file mode 100644 index 0000000000000000000000000000000000000000..29aa0ac249966891d8463a7330fe6f5b96943880 GIT binary patch literal 972 zcma)5&ui0Q82;L(T4uXe@Zdpgg%u{Kn4_QvhZ$28%Iw;?v3;vux@Dwk=@K_YVba+e z%D{_%fZ)NShn=;s;_%`@J$MiVaS*UVPdiL$eBLCjRXq5@llOU__s91m$=ieP-NTHr z0N?`zph+a*#uLQGbcI*fv1@)N>w-Q$KHEAZT4h#93~IhWVDp{*&}BInny3|4MZyPPC(O+=Q=VzCZfIG}@+NnfE*9f%&>2 zS?1@f#@@H#U8zlL>`EPS4XNFj>Qr0dc|JS06OC_>i22!!MT}#St@;dD%BtD6U2Vn0 z{jFEmAQTGcqVY{CVkpX3OKy5HmC0JOE+4OUW5yS;InU>I3d-%#q;WcNDUnoFV~9=2 zs#-deSSwZ3#Z%4{#%{sOEI?;*YynUDypqh{*N!@}g;n1dkEFz58f_0%9pxi}Z1Y4t-{rp%>sN+37g@pGJc><4d!3T^z+on3CR`9q3 zpe#~`-Xhi0X+NkJNFX19kAjfVw@-Wlp4Rtd$M-nnWkX+OyqHro{0uV}a8V^Km(MFJ KNa07(3+xwx$EI=s literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/data/macho/fibonacci_x86_64.o b/objdiff-core/tests/data/macho/fibonacci_x86_64.o new file mode 100644 index 0000000000000000000000000000000000000000..7c2ead8b3817765fa01a9944ef5ab7d37b0c9f0e GIT binary patch literal 1024 zcma)5O>5Lp6umQ!w$#?iqJo08DOhO15womNZ0J-T;zG2FDC2XS4;#s3$~2*at3pwl zMWxI6DY_dR5OHC_g>=`I;HC>VRa|sDH@U$$MexGSx#xbI_ww?x`|IFnh$wS{@POyw zl!cod5S@o_ap51fAT^U`UK)l%GCx4Eze=;QTCVsy@YWr#s`ag6(#zNpvLN^d0(@p$ zc!<_tl3LeRbiGw>)Z&4`{q2d)ir`Pt6H2Fvl2Vkqgr~vL=t#tQv2*Ya*5`BD1I_?3 zN4Mc=iIv#1+7jb(o)|V)!FYhWo|vP=)WTZp7{WdwcW92==Y+Bl~fwS9hMy zOb4^(ygBWozZ&>&=#1onlq7*%*)A(5q5cz$wZetB*@P^WqL=+D6709U9(2 z7oYP5_;5cq(I>Lc7_YL6W2a<}`-*Tw`gonllD@^w+-rQ3Dv~(+f?V~&jhLUk4n(AI{-Gn_jt6ah{`uAIGml Gf#^4!RfHM< literal 0 HcmV?d00001 diff --git a/objdiff-core/tests/macho.rs b/objdiff-core/tests/macho.rs new file mode 100644 index 00000000..cee3c7b1 --- /dev/null +++ b/objdiff-core/tests/macho.rs @@ -0,0 +1,58 @@ +use objdiff_core::{diff, obj}; + +mod common; + +fn parse(data: &[u8]) -> (obj::Object, diff::DiffObjConfig) { + let diff_config = diff::DiffObjConfig::default(); + let obj = obj::read::parse(data, &diff_config, diff::DiffSide::Base).unwrap(); + (obj, diff_config) +} + +/// Snapshots the parsed object, then the disassembly of `_main`, which holds every relocation +/// kind that the compiler emits for the test source. +fn read_macho(arch: &str, data: &[u8]) { + let (obj, diff_config) = parse(data); + insta::assert_debug_snapshot!(format!("{arch}_object"), obj); + let symbol_idx = obj.symbols.iter().position(|s| s.name == "_main").unwrap(); + let diff = diff::code::no_diff_code(&obj, symbol_idx, &diff_config).unwrap(); + insta::assert_debug_snapshot!(format!("{arch}_instructions"), diff.instruction_rows); + let output = common::display_diff(&obj, &diff, symbol_idx, &diff_config); + insta::assert_snapshot!(format!("{arch}_display"), output); +} + +#[test] +#[cfg(feature = "x86")] +fn read_macho_x86_64() { read_macho("x86_64", include_object!("data/macho/fibonacci_x86_64.o")); } + +#[test] +#[cfg(feature = "x86")] +fn read_macho_i386() { read_macho("i386", include_object!("data/macho/fibonacci_i386.o")); } + +#[test] +#[cfg(feature = "arm64")] +fn read_macho_arm64() { read_macho("arm64", include_object!("data/macho/fibonacci_arm64.o")); } + +#[test] +#[cfg(feature = "arm64")] +fn read_macho_arm64_32() { + read_macho("arm64_32", include_object!("data/macho/fibonacci_arm64_32.o")); +} + +#[test] +#[cfg(feature = "arm")] +fn read_macho_arm() { read_macho("armv6", include_object!("data/macho/fibonacci_armv6.o")); } + +/// Thumb functions are marked in the Mach-O symbol table rather than by mapping symbols. +#[test] +#[cfg(feature = "arm")] +fn read_macho_arm_thumb() { + read_macho("armv6_thumb", include_object!("data/macho/fibonacci_armv6_thumb.o")); +} + +/// unarm only disassembles up to ARMv6K, so only the parsed object is snapshotted for ARMv7. +#[test] +#[cfg(feature = "arm")] +fn read_macho_armv7() { + let (obj, _) = parse(include_object!("data/macho/fibonacci_armv7.o")); + insta::assert_debug_snapshot!("armv7_object", obj); +} diff --git a/objdiff-core/tests/snapshots/arch_arm__read_arm.snap b/objdiff-core/tests/snapshots/arch_arm__read_arm.snap index 927858c6..32fcff0e 100644 --- a/objdiff-core/tests/snapshots/arch_arm__read_arm.snap +++ b/objdiff-core/tests/snapshots/arch_arm__read_arm.snap @@ -142,6 +142,7 @@ Object { }, detected_version: None, endianness: Little, + macho_disasm_modes: None, }, endianness: Little, symbols: [ diff --git a/objdiff-core/tests/snapshots/arch_arm__read_thumb.snap b/objdiff-core/tests/snapshots/arch_arm__read_thumb.snap index 6aca4f86..740be4fb 100644 --- a/objdiff-core/tests/snapshots/arch_arm__read_thumb.snap +++ b/objdiff-core/tests/snapshots/arch_arm__read_thumb.snap @@ -18,6 +18,7 @@ Object { }, detected_version: None, endianness: Little, + macho_disasm_modes: None, }, endianness: Little, symbols: [ diff --git a/objdiff-core/tests/snapshots/macho__arm64_32_display.snap b/objdiff-core/tests/snapshots/macho__arm64_32_display.snap new file mode 100644 index 00000000..bc290b95 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_32_display.snap @@ -0,0 +1,28 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("sub", 19), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(48)), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stp", 70), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(16)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stp", 70), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x30")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(32)), Normal, 0), (Eol, Normal, 0)] +[(Address(16), Dim, 5), (Spacing(4), Normal, 0), (Opcode("adrp", 24), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_str", demangled_name: None, normalized_name: None, address: 168, size: 14, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_str", demangled_name: None, normalized_name: None, address: 168, size: 14, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(24), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(28), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 3), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(32), Dim, 5), (Spacing(4), Normal, 0), (Opcode("adrp", 24), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_.str.1", demangled_name: None, normalized_name: None, address: 152, size: 16, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(36), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_.str.1", demangled_name: None, normalized_name: None, address: 152, size: 16, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(40), Dim, 5), (BranchArrow(18), Rotating(0), 0), (Opcode("mov", 9), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Eol, Normal, 0)] +[(Address(44), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 56, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(48), Dim, 5), (Spacing(4), Normal, 0), (Opcode("str", 71), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(8)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(52), Dim, 5), (Spacing(4), Normal, 0), (Opcode("str", 71), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(56), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 9), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x20")), Normal, 0), (Eol, Normal, 0)] +[(Address(60), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(64), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(1)), Normal, 0), (Eol, Normal, 0)] +[(Address(68), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 18), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(72), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b.ne", 91), Normal, 10), (Basic("$"), Normal, 0), (BranchDest(40), Normal, 0), (BranchArrow(10), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(76), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 3), Normal, 10), (Argument(Opaque("w0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(80), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldp", 36), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x30")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(84), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldp", 36), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(16)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(88), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(48)), Normal, 0), (Eol, Normal, 0)] +[(Address(92), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ret", 102), Normal, 10), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__arm64_32_instructions.snap b/objdiff-core/tests/snapshots/macho__arm64_32_instructions.snap new file mode 100644 index 00000000..14d779eb --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_32_instructions.snap @@ -0,0 +1,356 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 56, + size: 4, + opcode: 19, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 60, + size: 4, + opcode: 70, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 64, + size: 4, + opcode: 70, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 68, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 72, + size: 4, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 76, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 80, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 84, + size: 4, + opcode: 3, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 88, + size: 4, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 92, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 96, + size: 4, + opcode: 9, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 18, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 100, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 104, + size: 4, + opcode: 71, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 108, + size: 4, + opcode: 71, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 112, + size: 4, + opcode: 9, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 116, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 120, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 124, + size: 4, + opcode: 18, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 128, + size: 4, + opcode: 91, + branch_dest: Some( + 96, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 10, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 132, + size: 4, + opcode: 3, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 136, + size: 4, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 140, + size: 4, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 144, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 148, + size: 4, + opcode: 102, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__arm64_32_object.snap b/objdiff-core/tests/snapshots/macho__arm64_32_object.snap new file mode 100644 index 00000000..5ef8cab0 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_32_object.snap @@ -0,0 +1,276 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchArm64, + endianness: Little, + symbols: [ + Symbol { + name: "[__text]", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Section, + section: Some( + 0, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 56, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 56, + size: 96, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring]", + demangled_name: None, + normalized_name: None, + address: 152, + size: 0, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "l_.str.1", + demangled_name: None, + normalized_name: None, + address: 152, + size: 16, + kind: Object, + section: Some( + 1, + ), + flags: FlagSet(Local | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "l_str", + demangled_name: None, + normalized_name: None, + address: 168, + size: 14, + kind: Object, + section: Some( + 1, + ), + flags: FlagSet(Local | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__compact_unwind]", + demangled_name: None, + normalized_name: None, + address: 184, + size: 40, + kind: Section, + section: Some( + 2, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 152, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 152, + kind: Code, + data: SectionData( + 152, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 3, + r_pcrel: true, + r_length: 2, + }, + address: 72, + target_symbol: 5, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 4, + r_pcrel: false, + r_length: 2, + }, + address: 76, + target_symbol: 5, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 80, + target_symbol: 8, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 3, + r_pcrel: true, + r_length: 2, + }, + address: 88, + target_symbol: 4, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 4, + r_pcrel: false, + r_length: 2, + }, + address: 92, + target_symbol: 4, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 100, + target_symbol: 1, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 116, + target_symbol: 7, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 152, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__compact_unwind-0", + name: "__compact_unwind", + address: 184, + size: 40, + kind: Unknown, + data: SectionData( + 0, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__arm64_display.snap b/objdiff-core/tests/snapshots/macho__arm64_display.snap new file mode 100644 index 00000000..49a4018e --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_display.snap @@ -0,0 +1,27 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("sub", 19), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(48)), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stp", 70), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(16)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stp", 70), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x30")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(32)), Normal, 0), (Eol, Normal, 0)] +[(Address(16), Dim, 5), (Spacing(4), Normal, 0), (Opcode("adrp", 24), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_str", demangled_name: None, normalized_name: None, address: 164, size: 14, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_str", demangled_name: None, normalized_name: None, address: 164, size: 14, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(24), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(28), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 3), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(32), Dim, 5), (Spacing(4), Normal, 0), (Opcode("adrp", 24), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_.str.1", demangled_name: None, normalized_name: None, address: 148, size: 16, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(36), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Symbol(Symbol { name: "l_.str.1", demangled_name: None, normalized_name: None, address: 148, size: 16, kind: Object, section: Some(1), flags: FlagSet(Local | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(40), Dim, 5), (BranchArrow(17), Rotating(0), 0), (Opcode("mov", 9), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Eol, Normal, 0)] +[(Address(44), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 56, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(48), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stp", 70), Normal, 10), (Argument(Opaque("x19")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(52), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 9), Normal, 10), (Argument(Opaque("x0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x20")), Normal, 0), (Eol, Normal, 0)] +[(Address(56), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 92), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(60), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(1)), Normal, 0), (Eol, Normal, 0)] +[(Address(64), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 18), Normal, 10), (Argument(Opaque("w19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(68), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b.ne", 91), Normal, 10), (Basic("$"), Normal, 0), (BranchDest(40), Normal, 0), (BranchArrow(10), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(72), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 3), Normal, 10), (Argument(Opaque("w0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(76), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldp", 36), Normal, 10), (Argument(Opaque("x29")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x30")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(32)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(80), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldp", 36), Normal, 10), (Argument(Opaque("x20")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("x19")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(16)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(84), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 17), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(48)), Normal, 0), (Eol, Normal, 0)] +[(Address(88), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ret", 102), Normal, 10), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__arm64_instructions.snap b/objdiff-core/tests/snapshots/macho__arm64_instructions.snap new file mode 100644 index 00000000..e52d9fe9 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_instructions.snap @@ -0,0 +1,342 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 56, + size: 4, + opcode: 19, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 60, + size: 4, + opcode: 70, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 64, + size: 4, + opcode: 70, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 68, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 72, + size: 4, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 76, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 80, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 84, + size: 4, + opcode: 3, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 88, + size: 4, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 92, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 96, + size: 4, + opcode: 9, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 17, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 100, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 104, + size: 4, + opcode: 70, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 108, + size: 4, + opcode: 9, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 112, + size: 4, + opcode: 92, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 116, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 120, + size: 4, + opcode: 18, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 124, + size: 4, + opcode: 91, + branch_dest: Some( + 96, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 10, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 128, + size: 4, + opcode: 3, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 132, + size: 4, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 136, + size: 4, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 140, + size: 4, + opcode: 17, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 144, + size: 4, + opcode: 102, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__arm64_object.snap b/objdiff-core/tests/snapshots/macho__arm64_object.snap new file mode 100644 index 00000000..84ac7f29 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__arm64_object.snap @@ -0,0 +1,276 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchArm64, + endianness: Little, + symbols: [ + Symbol { + name: "[__text]", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Section, + section: Some( + 0, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 56, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 56, + size: 92, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring]", + demangled_name: None, + normalized_name: None, + address: 148, + size: 0, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "l_.str.1", + demangled_name: None, + normalized_name: None, + address: 148, + size: 16, + kind: Object, + section: Some( + 1, + ), + flags: FlagSet(Local | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "l_str", + demangled_name: None, + normalized_name: None, + address: 164, + size: 14, + kind: Object, + section: Some( + 1, + ), + flags: FlagSet(Local | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__compact_unwind]", + demangled_name: None, + normalized_name: None, + address: 184, + size: 64, + kind: Section, + section: Some( + 2, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 148, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 148, + kind: Code, + data: SectionData( + 148, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 3, + r_pcrel: true, + r_length: 2, + }, + address: 72, + target_symbol: 5, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 4, + r_pcrel: false, + r_length: 2, + }, + address: 76, + target_symbol: 5, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 80, + target_symbol: 8, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 3, + r_pcrel: true, + r_length: 2, + }, + address: 88, + target_symbol: 4, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 4, + r_pcrel: false, + r_length: 2, + }, + address: 92, + target_symbol: 4, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 100, + target_symbol: 1, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 112, + target_symbol: 7, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 148, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__compact_unwind-0", + name: "__compact_unwind", + address: 184, + size: 64, + kind: Unknown, + data: SectionData( + 0, + ), + flags: FlagSet(), + align: Some( + 8, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__armv6_display.snap b/objdiff-core/tests/snapshots/macho__armv6_display.snap new file mode 100644 index 00000000..bd57e2e3 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_display.snap @@ -0,0 +1,26 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stmdb", 32883), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic("!"), Normal, 0), (Basic(", "), Normal, 0), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("lr")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 32769), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(8)), Normal, 0), (Eol, Normal, 0)] +[(Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(64)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(80), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)] +[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 32769), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)] +[(Address(16), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(24), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(52)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(84), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)] +[(Address(28), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 32769), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)] +[(Address(32), Dim, 5), (BranchArrow(17), Rotating(0), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)] +[(Address(36), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 92, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(40), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r2")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)] +[(Address(44), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Eol, Normal, 0)] +[(Address(48), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)] +[(Address(52), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)] +[(Address(56), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(60), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 32769), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(1)), Normal, 0), (Eol, Normal, 0)] +[(Address(64), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(68), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bne", 32772), Normal, 10), (BranchDest(32), Normal, 0), (BranchArrow(8), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(72), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(76), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldmia", 32791), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic("!"), Normal, 0), (Basic(", "), Normal, 0), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)] +[(Address(80), Dim, 5), (Spacing(4), Normal, 0), (Opcode("andeq", 32770), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("asr")), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)] +[(Address(84), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".hword", 65534), Normal, 10), (Argument(Unsigned(52)), Normal, 0), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__armv6_instructions.snap b/objdiff-core/tests/snapshots/macho__armv6_instructions.snap new file mode 100644 index 00000000..c6c64089 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_instructions.snap @@ -0,0 +1,328 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 92, + size: 4, + opcode: 32883, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 96, + size: 4, + opcode: 32769, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 100, + size: 4, + opcode: 32792, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 104, + size: 4, + opcode: 32769, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 108, + size: 4, + opcode: 32775, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 112, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 116, + size: 4, + opcode: 32792, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 120, + size: 4, + opcode: 32769, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 124, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 17, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 128, + size: 4, + opcode: 32775, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 132, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 136, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 140, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 144, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 148, + size: 4, + opcode: 32775, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 152, + size: 4, + opcode: 32769, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 156, + size: 4, + opcode: 32784, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 160, + size: 4, + opcode: 32772, + branch_dest: Some( + 124, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 8, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 164, + size: 4, + opcode: 32811, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 168, + size: 4, + opcode: 32791, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 172, + size: 4, + opcode: 32770, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 176, + size: 2, + opcode: 65534, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__armv6_object.snap b/objdiff-core/tests/snapshots/macho__armv6_object.snap new file mode 100644 index 00000000..07317dbb --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_object.snap @@ -0,0 +1,176 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchArm { + disasm_modes: { + 0: [ + DisasmMode { + address: 0, + mapping: Arm, + }, + DisasmMode { + address: 92, + mapping: Arm, + }, + ], + }, + detected_version: None, + endianness: Little, + macho_disasm_modes: Some( + [ + DisasmMode { + address: 0, + mapping: Arm, + }, + DisasmMode { + address: 92, + mapping: Arm, + }, + ], + ), + }, + endianness: Little, + symbols: [ + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 92, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 92, + size: 86, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 180, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 180, + kind: Code, + data: SectionData( + 180, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 5, + r_pcrel: true, + r_length: 2, + }, + address: 108, + target_symbol: 3, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 5, + r_pcrel: true, + r_length: 2, + }, + address: 128, + target_symbol: 0, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 5, + r_pcrel: true, + r_length: 2, + }, + address: 148, + target_symbol: 2, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 180, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__armv6_thumb_display.snap b/objdiff-core/tests/snapshots/macho__armv6_thumb_display.snap new file mode 100644 index 00000000..60fd7cde --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_thumb_display.snap @@ -0,0 +1,28 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 59), Normal, 10), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("lr")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)] +[(Address(2), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 1), Normal, 10), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("sp")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(8)), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 24), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(40)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(48), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)] +[(Address(6), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 1), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Eol, Normal, 0)] +[(Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 7), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(14), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 24), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(36)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(52), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)] +[(Address(16), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 1), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Eol, Normal, 0)] +[(Address(18), Dim, 5), (BranchArrow(17), Rotating(0), 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)] +[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 7), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 56, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(24), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r2")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)] +[(Address(26), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r3")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Eol, Normal, 0)] +[(Address(28), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)] +[(Address(30), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)] +[(Address(32), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 7), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(36), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 1), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(1)), Normal, 0), (Eol, Normal, 0)] +[(Address(38), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 16), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(40), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bne", 4), Normal, 10), (BranchDest(18), Normal, 0), (BranchArrow(8), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(42), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(44), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 58), Normal, 10), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)] +[(Address(46), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 43), Normal, 10), (Argument(Opaque("r8")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r8")), Normal, 0), (Eol, Normal, 0)] +[(Address(48), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lsl", 36), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r7")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(50), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lsl", 36), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] +[(Address(52), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lsl", 36), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__armv6_thumb_instructions.snap b/objdiff-core/tests/snapshots/macho__armv6_thumb_instructions.snap new file mode 100644 index 00000000..685124af --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_thumb_instructions.snap @@ -0,0 +1,356 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 56, + size: 2, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 58, + size: 2, + opcode: 1, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 60, + size: 2, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 62, + size: 2, + opcode: 1, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 64, + size: 4, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 68, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 70, + size: 2, + opcode: 24, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 72, + size: 2, + opcode: 1, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 74, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 17, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 76, + size: 4, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 80, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 82, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 84, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 86, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 88, + size: 4, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 92, + size: 2, + opcode: 1, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 94, + size: 2, + opcode: 16, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 96, + size: 2, + opcode: 4, + branch_dest: Some( + 74, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 8, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 98, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 100, + size: 2, + opcode: 58, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 102, + size: 2, + opcode: 43, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 104, + size: 2, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 106, + size: 2, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 108, + size: 2, + opcode: 36, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__armv6_thumb_object.snap b/objdiff-core/tests/snapshots/macho__armv6_thumb_object.snap new file mode 100644 index 00000000..5b29c113 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv6_thumb_object.snap @@ -0,0 +1,176 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchArm { + disasm_modes: { + 0: [ + DisasmMode { + address: 0, + mapping: Thumb, + }, + DisasmMode { + address: 56, + mapping: Thumb, + }, + ], + }, + detected_version: None, + endianness: Little, + macho_disasm_modes: Some( + [ + DisasmMode { + address: 0, + mapping: Thumb, + }, + DisasmMode { + address: 56, + mapping: Thumb, + }, + ], + ), + }, + endianness: Little, + symbols: [ + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 56, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 56, + size: 54, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 112, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 112, + kind: Code, + data: SectionData( + 112, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 64, + target_symbol: 3, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 76, + target_symbol: 0, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 88, + target_symbol: 2, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 112, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__armv7_object.snap b/objdiff-core/tests/snapshots/macho__armv7_object.snap new file mode 100644 index 00000000..36e0bf8d --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__armv7_object.snap @@ -0,0 +1,176 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchArm { + disasm_modes: { + 0: [ + DisasmMode { + address: 0, + mapping: Thumb, + }, + DisasmMode { + address: 58, + mapping: Thumb, + }, + ], + }, + detected_version: None, + endianness: Little, + macho_disasm_modes: Some( + [ + DisasmMode { + address: 0, + mapping: Thumb, + }, + DisasmMode { + address: 58, + mapping: Thumb, + }, + ], + ), + }, + endianness: Little, + symbols: [ + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 58, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 58, + size: 58, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 116, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 116, + kind: Code, + data: SectionData( + 116, + ), + flags: FlagSet(), + align: Some( + 2, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 72, + target_symbol: 3, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 90, + target_symbol: 0, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 6, + r_pcrel: true, + r_length: 2, + }, + address: 102, + target_symbol: 2, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 116, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__i386_display.snap b/objdiff-core/tests/snapshots/macho__i386_display.snap new file mode 100644 index 00000000..8d631c0f --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__i386_display.snap @@ -0,0 +1,36 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Eol, Normal, 0)] +[(Address(1), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("esp")), Normal, 0), (Eol, Normal, 0)] +[(Address(3), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(5), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (BranchDest(10), Normal, 0), (BranchArrow(5), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(10), Dim, 5), (BranchArrow(4), Rotating(0), 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Eol, Normal, 0)] +[(Address(11), Dim, 5), (Spacing(4), Normal, 0), (Opcode("sub", 740), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(12)), Normal, 0), (Eol, Normal, 0)] +[(Address(14), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lea", 374), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("edi")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(90)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Eol, Normal, 0)] +[(Address(21), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(26), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 7), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(29), Dim, 5), (Spacing(4), Normal, 0), (Opcode("xor", 1518), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(31), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lea", 374), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("edi")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Signed(74)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(37), Dim, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Argument(Opaque("cs")), Normal, 0), (Basic(":"), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("eax")), Normal, 0), (Argument(Opaque("+")), Normal, 0), (Argument(Opaque("eax")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(48), Dim, 5), (BranchArrow(26), Rotating(1), 0), (Opcode("sub", 740), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(12)), Normal, 0), (Eol, Normal, 0)] +[(Address(51), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(52), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 89, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(57), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 7), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(60), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("edx")), Normal, 0), (Eol, Normal, 0)] +[(Address(61), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Eol, Normal, 0)] +[(Address(62), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(63), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Eol, Normal, 0)] +[(Address(64), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(69), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 7), Normal, 10), (Argument(Opaque("esp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(72), Dim, 5), (Spacing(4), Normal, 0), (Opcode("inc", 279), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(73), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 93), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(76), Dim, 5), (Spacing(4), Normal, 0), (Opcode("jne", 310), Normal, 10), (Argument(Opaque("short")), Normal, 0), (Spacing(1), Normal, 0), (BranchDest(48), Normal, 0), (BranchArrow(14), Rotating(1), 0), (Eol, Normal, 0)] +[(Address(78), Dim, 5), (Spacing(4), Normal, 0), (Opcode("xor", 1518), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("eax")), Normal, 0), (Eol, Normal, 0)] +[(Address(80), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Eol, Normal, 0)] +[(Address(81), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Eol, Normal, 0)] +[(Address(82), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("ebp")), Normal, 0), (Eol, Normal, 0)] +[(Address(83), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ret", 662), Normal, 10), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__i386_instructions.snap b/objdiff-core/tests/snapshots/macho__i386_instructions.snap new file mode 100644 index 00000000..ac390bc8 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__i386_instructions.snap @@ -0,0 +1,482 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 96, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 97, + size: 2, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 99, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 100, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 101, + size: 5, + opcode: 59, + branch_dest: Some( + 106, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 5, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 106, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 4, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 107, + size: 3, + opcode: 740, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 110, + size: 6, + opcode: 374, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 116, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 117, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 122, + size: 3, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 125, + size: 2, + opcode: 1518, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 127, + size: 6, + opcode: 374, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 133, + size: 11, + opcode: 465, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 144, + size: 3, + opcode: 740, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 26, + ], + branch_idx: 1, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 147, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 148, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 153, + size: 3, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 156, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 157, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 158, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 159, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 160, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 165, + size: 3, + opcode: 7, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 168, + size: 1, + opcode: 279, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 169, + size: 3, + opcode: 93, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 172, + size: 2, + opcode: 310, + branch_dest: Some( + 144, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 14, + branch_idx: 1, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 174, + size: 2, + opcode: 1518, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 176, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 177, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 178, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 179, + size: 1, + opcode: 662, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__i386_object.snap b/objdiff-core/tests/snapshots/macho__i386_object.snap new file mode 100644 index 00000000..113efd4d --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__i386_object.snap @@ -0,0 +1,200 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchX86 { + arch: X86, + endianness: Little, + }, + endianness: Little, + symbols: [ + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 89, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 96, + size: 84, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 180, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__eh_frame-0]", + demangled_name: None, + normalized_name: None, + address: 252, + size: 88, + kind: Section, + section: Some( + 3, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 180, + kind: Code, + data: SectionData( + 180, + ), + flags: FlagSet(), + align: Some( + 16, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 0, + r_pcrel: true, + r_length: 2, + }, + address: 118, + target_symbol: 3, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 0, + r_pcrel: true, + r_length: 2, + }, + address: 149, + target_symbol: 0, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 0, + r_pcrel: true, + r_length: 2, + }, + address: 161, + target_symbol: 2, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 180, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__compact_unwind-0", + name: "__compact_unwind", + address: 212, + size: 40, + kind: Unknown, + data: SectionData( + 0, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__eh_frame-0", + name: "__eh_frame", + address: 252, + size: 88, + kind: Data, + data: SectionData( + 88, + ), + flags: FlagSet(), + align: Some( + 4, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +} diff --git a/objdiff-core/tests/snapshots/macho__x86_64_display.snap b/objdiff-core/tests/snapshots/macho__x86_64_display.snap new file mode 100644 index 00000000..2ed1eb17 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__x86_64_display.snap @@ -0,0 +1,28 @@ +--- +source: objdiff-core/tests/macho.rs +expression: output +--- +[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("rbp")), Normal, 0), (Eol, Normal, 0)] +[(Address(1), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rbp")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("rsp")), Normal, 0), (Eol, Normal, 0)] +[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("r14")), Normal, 0), (Eol, Normal, 0)] +[(Address(6), Dim, 5), (Spacing(4), Normal, 0), (Opcode("push", 640), Normal, 10), (Argument(Opaque("rbx")), Normal, 0), (Eol, Normal, 0)] +[(Address(7), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lea", 374), Normal, 10), (Argument(Opaque("rdi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Unsigned(136)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(14), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "_puts", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(19), Dim, 5), (Spacing(4), Normal, 0), (Opcode("lea", 374), Normal, 10), (Argument(Opaque("rbx")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Basic("["), Normal, 0), (Argument(Unsigned(120)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(26), Dim, 5), (Spacing(4), Normal, 0), (Opcode("xor", 1518), Normal, 10), (Argument(Opaque("r14d")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("r14d")), Normal, 0), (Eol, Normal, 0)] +[(Address(29), Dim, 5), (Spacing(4), Normal, 0), (Opcode("nop", 465), Normal, 10), (Basic("["), Normal, 0), (Argument(Opaque("rax")), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)] +[(Address(32), Dim, 5), (BranchArrow(18), Rotating(0), 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("edi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("r14d")), Normal, 0), (Eol, Normal, 0)] +[(Address(35), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "__Z9fibonaccij", demangled_name: Some("fibonacci(unsigned int)"), normalized_name: None, address: 0, size: 41, kind: Function, section: Some(0), flags: FlagSet(Global | SizeInferred), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(40), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rdi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("rbx")), Normal, 0), (Eol, Normal, 0)] +[(Address(43), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("esi")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("r14d")), Normal, 0), (Eol, Normal, 0)] +[(Address(46), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 414), Normal, 10), (Argument(Opaque("rdx")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("rax")), Normal, 0), (Eol, Normal, 0)] +[(Address(49), Dim, 5), (Spacing(4), Normal, 0), (Opcode("xor", 1518), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("eax")), Normal, 0), (Eol, Normal, 0)] +[(Address(51), Dim, 5), (Spacing(4), Normal, 0), (Opcode("call", 59), Normal, 10), (Symbol(Symbol { name: "_printf", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)] +[(Address(56), Dim, 5), (Spacing(4), Normal, 0), (Opcode("inc", 279), Normal, 10), (Argument(Opaque("r14d")), Normal, 0), (Eol, Normal, 0)] +[(Address(59), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 93), Normal, 10), (Argument(Opaque("r14d")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Unsigned(16)), Normal, 0), (Eol, Normal, 0)] +[(Address(63), Dim, 5), (Spacing(4), Normal, 0), (Opcode("jne", 310), Normal, 10), (Argument(Opaque("short")), Normal, 0), (Spacing(1), Normal, 0), (BranchDest(32), Normal, 0), (BranchArrow(9), Rotating(0), 0), (Eol, Normal, 0)] +[(Address(65), Dim, 5), (Spacing(4), Normal, 0), (Opcode("xor", 1518), Normal, 10), (Argument(Opaque("eax")), Normal, 0), (Basic(","), Normal, 0), (Spacing(1), Normal, 0), (Argument(Opaque("eax")), Normal, 0), (Eol, Normal, 0)] +[(Address(67), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("rbx")), Normal, 0), (Eol, Normal, 0)] +[(Address(68), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("r14")), Normal, 0), (Eol, Normal, 0)] +[(Address(70), Dim, 5), (Spacing(4), Normal, 0), (Opcode("pop", 590), Normal, 10), (Argument(Opaque("rbp")), Normal, 0), (Eol, Normal, 0)] +[(Address(71), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ret", 662), Normal, 10), (Eol, Normal, 0)] diff --git a/objdiff-core/tests/snapshots/macho__x86_64_instructions.snap b/objdiff-core/tests/snapshots/macho__x86_64_instructions.snap new file mode 100644 index 00000000..29bc7777 --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__x86_64_instructions.snap @@ -0,0 +1,356 @@ +--- +source: objdiff-core/tests/macho.rs +expression: diff.instruction_rows +--- +[ + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 48, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 49, + size: 3, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 52, + size: 2, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 54, + size: 1, + opcode: 640, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 55, + size: 7, + opcode: 374, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 62, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 67, + size: 7, + opcode: 374, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 74, + size: 3, + opcode: 1518, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 77, + size: 3, + opcode: 465, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 80, + size: 3, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: Some( + InstructionBranchFrom { + ins_idx: [ + 18, + ], + branch_idx: 0, + }, + ), + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 83, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 88, + size: 3, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 91, + size: 3, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 94, + size: 3, + opcode: 414, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 97, + size: 2, + opcode: 1518, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 99, + size: 5, + opcode: 59, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 104, + size: 3, + opcode: 279, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 107, + size: 4, + opcode: 93, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 111, + size: 2, + opcode: 310, + branch_dest: Some( + 80, + ), + }, + ), + kind: None, + branch_from: None, + branch_to: Some( + InstructionBranchTo { + ins_idx: 9, + branch_idx: 0, + }, + ), + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 113, + size: 2, + opcode: 1518, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 115, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 116, + size: 2, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 118, + size: 1, + opcode: 590, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, + InstructionDiffRow { + ins_ref: Some( + InstructionRef { + address: 119, + size: 1, + opcode: 662, + branch_dest: None, + }, + ), + kind: None, + branch_from: None, + branch_to: None, + arg_diff: [], + }, +] diff --git a/objdiff-core/tests/snapshots/macho__x86_64_object.snap b/objdiff-core/tests/snapshots/macho__x86_64_object.snap new file mode 100644 index 00000000..369b09bf --- /dev/null +++ b/objdiff-core/tests/snapshots/macho__x86_64_object.snap @@ -0,0 +1,200 @@ +--- +source: objdiff-core/tests/macho.rs +expression: obj +--- +Object { + arch: ArchX86 { + arch: X86_64, + endianness: Little, + }, + endianness: Little, + symbols: [ + Symbol { + name: "__Z9fibonaccij", + demangled_name: Some( + "fibonacci(unsigned int)", + ), + normalized_name: None, + address: 0, + size: 41, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_main", + demangled_name: None, + normalized_name: None, + address: 48, + size: 72, + kind: Function, + section: Some( + 0, + ), + flags: FlagSet(Global | SizeInferred), + align: None, + virtual_address: None, + }, + Symbol { + name: "_printf", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "_puts", + demangled_name: None, + normalized_name: None, + address: 0, + size: 0, + kind: Unknown, + section: None, + flags: FlagSet(Global), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__cstring-0]", + demangled_name: None, + normalized_name: None, + address: 120, + size: 30, + kind: Section, + section: Some( + 1, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + Symbol { + name: "[__eh_frame-0]", + demangled_name: None, + normalized_name: None, + address: 216, + size: 104, + kind: Section, + section: Some( + 3, + ), + flags: FlagSet(Local), + align: None, + virtual_address: None, + }, + ], + sections: [ + Section { + id: "__text-0", + name: "__text", + address: 0, + size: 120, + kind: Code, + data: SectionData( + 120, + ), + flags: FlagSet(), + align: Some( + 16, + ), + relocations: [ + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 63, + target_symbol: 3, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 84, + target_symbol: 0, + addend: 0, + }, + Relocation { + flags: MachO { + r_type: 2, + r_pcrel: true, + r_length: 2, + }, + address: 100, + target_symbol: 2, + addend: 0, + }, + ], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__cstring-0", + name: "__cstring", + address: 120, + size: 30, + kind: Data, + data: SectionData( + 30, + ), + flags: FlagSet(), + align: Some( + 1, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__compact_unwind-0", + name: "__compact_unwind", + address: 152, + size: 64, + kind: Unknown, + data: SectionData( + 0, + ), + flags: FlagSet(), + align: Some( + 8, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + Section { + id: "__eh_frame-0", + name: "__eh_frame", + address: 216, + size: 104, + kind: Data, + data: SectionData( + 104, + ), + flags: FlagSet(), + align: Some( + 8, + ), + relocations: [], + line_info: {}, + virtual_address: None, + }, + ], + split_meta: None, + path: None, + timestamp: None, + flow_analysis_results: {}, +}