LCOV - code coverage report
Current view: top level - src/macho - relocation.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 66.7 % 165 110
Test Date: 2026-04-12:00:00:00 Functions: 47.5 % 61 29

            Line data    Source code
       1              : use std::marker::PhantomData;
       2              : 
       3              : use super::commands::segment::Segment;
       4              : use super::section::Section;
       5              : use super::symbol::Symbol;
       6              : use crate::common::{into_optional, FromFFI};
       7              : use crate::declare_iterator;
       8              : use crate::generic;
       9              : use lief_ffi as ffi;
      10              : 
      11       296426 : #[derive(Debug)]
      12              : /// Enum that represents the different to encode/represent a relocation
      13              : /// in a Mach-O file
      14              : pub enum Relocation<'a> {
      15              :     /// Relocation encoded in the rebase bytecode of `LC_DYLD_INFO`
      16              :     Dyld(Dyld<'a>),
      17              : 
      18              :     /// Relocation encoded in chained fixup `LC_DYLD_CHAINED_FIXUPS`
      19              :     Fixup(Fixup<'a>),
      20              : 
      21              :     /// Relocation of Mach-O object files (`.o`) wrapped by the sections
      22              :     Object(Object<'a>),
      23              : 
      24              :     /// Fallback structure
      25              :     Generic(Generic<'a>),
      26              : }
      27              : 
      28              : impl<'a> FromFFI<ffi::MachO_Relocation> for Relocation<'a> {
      29       296426 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
      30       296426 :         unsafe {
      31       296426 :             let cmd_ref = ffi_entry.as_ref().unwrap();
      32       296426 : 
      33       296426 :             if ffi::MachO_RelocationDyld::classof(cmd_ref) {
      34       237224 :                 let raw = {
      35       237224 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      36       237224 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
      37       237224 :                     std::mem::transmute::<From, To>(ffi_entry)
      38       237224 :                 };
      39       237224 :                 Relocation::Dyld(Dyld::from_ffi(raw))
      40        59202 :             } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
      41        32812 :                 let raw = {
      42        32812 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      43        32812 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
      44        32812 :                     std::mem::transmute::<From, To>(ffi_entry)
      45        32812 :                 };
      46        32812 :                 Relocation::Fixup(Fixup::from_ffi(raw))
      47        26390 :             } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
      48        26390 :                 let raw = {
      49        26390 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      50        26390 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
      51        26390 :                     std::mem::transmute::<From, To>(ffi_entry)
      52        26390 :                 };
      53        26390 :                 Relocation::Object(Object::from_ffi(raw))
      54              :             } else {
      55            0 :                 Relocation::Generic(Generic::from_ffi(ffi_entry))
      56              :             }
      57              :         }
      58       296426 :     }
      59              : }
      60              : 
      61              : /// Trait shared by **all** the relocations defined in [`Relocation`]
      62              : pub trait RelocationBase {
      63              :     #[doc(hidden)]
      64              :     fn get_base(&self) -> &ffi::MachO_Relocation;
      65              : 
      66              :     /// Indicates whether the item containing the address to be
      67              :     /// relocated is part of a CPU instruction that uses PC-relative addressing.
      68              :     ///
      69              :     /// For addresses contained in PC-relative instructions, the CPU adds the address of
      70              :     /// the instruction to the address contained in the instruction.
      71       296426 :     fn is_pc_relative(&self) -> bool {
      72       296426 :         self.get_base().is_pc_relative()
      73       296426 :     }
      74              : 
      75              :     /// CPU architecture targeted by this relocation
      76            0 :     fn architecture(&self) -> u32 {
      77            0 :         self.get_base().architecture()
      78            0 :     }
      79              : 
      80              :     /// Origin of the relocation
      81            0 :     fn origin(&self) -> Origin {
      82            0 :         Origin::from(self.get_base().origin())
      83            0 :     }
      84              : 
      85              :     /// Symbol associated with the relocation (if any)
      86       296426 :     fn symbol(&self) -> Option<Symbol<'_>> {
      87       296426 :         into_optional(self.get_base().symbol())
      88       296426 :     }
      89              : 
      90              :     /// Section associated with the section (if any)
      91       296426 :     fn section(&self) -> Option<Section<'_>> {
      92       296426 :         into_optional(self.get_base().section())
      93       296426 :     }
      94              : 
      95              :     /// Segment command associated with the relocation (if any)
      96       296426 :     fn segment(&self) -> Option<Segment<'_>> {
      97       296426 :         into_optional(self.get_base().segment())
      98       296426 :     }
      99              : }
     100              : 
     101              : /// Origin of a Mach-O relocation
     102              : #[allow(non_camel_case_types)]
     103            0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     104              : pub enum Origin {
     105              :     UNKNOWN,
     106              :     DYLDINFO,
     107              :     RELOC_TABLE,
     108              :     CHAINED_FIXUPS,
     109              : }
     110              : 
     111              : impl From<u32> for Origin {
     112            0 :     fn from(value: u32) -> Self {
     113            0 :         match value {
     114            0 :             0 => Origin::UNKNOWN,
     115            0 :             1 => Origin::DYLDINFO,
     116            0 :             2 => Origin::RELOC_TABLE,
     117            0 :             3 => Origin::CHAINED_FIXUPS,
     118            0 :             _ => Origin::UNKNOWN,
     119              :         }
     120            0 :     }
     121              : }
     122              : 
     123              : impl RelocationBase for Relocation<'_> {
     124            0 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     125            0 :         match &self {
     126            0 :             Relocation::Dyld(reloc) => reloc.get_base(),
     127              : 
     128            0 :             Relocation::Fixup(reloc) => reloc.get_base(),
     129              : 
     130            0 :             Relocation::Object(reloc) => reloc.get_base(),
     131              : 
     132            0 :             Relocation::Generic(reloc) => reloc.get_base(),
     133              :         }
     134            0 :     }
     135              : }
     136              : 
     137              : impl generic::Relocation for Relocation<'_> {
     138            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     139            0 :         match &self {
     140            0 :             Relocation::Dyld(reloc) => reloc.as_generic(),
     141              : 
     142            0 :             Relocation::Fixup(reloc) => reloc.as_generic(),
     143              : 
     144            0 :             Relocation::Object(reloc) => reloc.as_generic(),
     145              : 
     146            0 :             Relocation::Generic(reloc) => reloc.as_generic(),
     147              :         }
     148            0 :     }
     149              : }
     150              : 
     151              : impl std::fmt::Debug for &dyn RelocationBase {
     152       296426 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     153       296426 :         f.debug_struct("Section")
     154       296426 :             .field("is_pc_relative", &self.is_pc_relative())
     155       296426 :             .field("symbol", &self.symbol())
     156       296426 :             .field("section", &self.section())
     157       296426 :             .field("segment", &self.segment())
     158       296426 :             .finish()
     159       296426 :     }
     160              : }
     161              : 
     162              : pub struct Generic<'a> {
     163              :     ptr: cxx::UniquePtr<ffi::MachO_Relocation>,
     164              :     _owner: PhantomData<&'a ()>,
     165              : }
     166              : 
     167              : impl RelocationBase for Generic<'_> {
     168            0 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     169            0 :         self.ptr.as_ref().unwrap()
     170            0 :     }
     171              : }
     172              : 
     173              : impl generic::Relocation for Generic<'_> {
     174            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     175            0 :         self.ptr.as_ref().unwrap().as_ref()
     176            0 :     }
     177              : }
     178              : 
     179              : impl std::fmt::Debug for Generic<'_> {
     180            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     181            0 :         let base = self as &dyn RelocationBase;
     182            0 :         f.debug_struct("Generic").field("base", &base).finish()
     183            0 :     }
     184              : }
     185              : 
     186              : impl FromFFI<ffi::MachO_Relocation> for Generic<'_> {
     187            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
     188            0 :         Self {
     189            0 :             ptr,
     190            0 :             _owner: PhantomData,
     191            0 :         }
     192            0 :     }
     193              : }
     194              : 
     195              : /// Structure that represents a bytecode rebase operation (from `LC_DYLD_INFO`)
     196              : pub struct Dyld<'a> {
     197              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>,
     198              :     _owner: PhantomData<&'a ()>,
     199              : }
     200              : 
     201              : impl FromFFI<ffi::MachO_RelocationDyld> for Dyld<'_> {
     202       237224 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
     203       237224 :         Self {
     204       237224 :             ptr,
     205       237224 :             _owner: PhantomData,
     206       237224 :         }
     207       237224 :     }
     208              : }
     209              : 
     210              : impl RelocationBase for Dyld<'_> {
     211       948896 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     212       948896 :         self.ptr.as_ref().unwrap().as_ref()
     213       948896 :     }
     214              : }
     215              : 
     216              : impl generic::Relocation for Dyld<'_> {
     217            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     218            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     219            0 :     }
     220              : }
     221              : 
     222              : impl std::fmt::Debug for Dyld<'_> {
     223       237224 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     224       237224 :         let base = self as &dyn RelocationBase;
     225       237224 :         f.debug_struct("Dyld").field("base", &base).finish()
     226       237224 :     }
     227              : }
     228              : 
     229              : /// Structure that represents a fixup (i.e. relocation) from the `LC_DYLD_CHAINED_FIXUPS`
     230              : /// command
     231              : pub struct Fixup<'a> {
     232              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>,
     233              :     _owner: PhantomData<&'a ()>,
     234              : }
     235              : 
     236              : impl Fixup<'_> {
     237              :     /// The value that should be set at the address pointed by [`crate::Relocation::address`]
     238              :     /// if the imagebase chosen by the loader is [`crate::generic::Binary::imagebase`].
     239              :     /// Otherwise: [`Fixup::target`] - [`crate::generic::Binary::imagebase`] + new_imagebase.
     240        32812 :     pub fn target(&self) -> u64 {
     241        32812 :         self.ptr.target()
     242        32812 :     }
     243        32812 :     pub fn ptr_format(&self) -> u32 {
     244        32812 :         self.ptr.ptr_format()
     245        32812 :     }
     246              : 
     247              :     /// The address of this relocation is bound to its offset
     248        32812 :     pub fn offset(&self) -> u32 {
     249        32812 :         self.ptr.offset()
     250        32812 :     }
     251              : 
     252              :     /// Return the (unscaled) next offset in the chain
     253        16406 :     pub fn next(&self) -> u32 {
     254        16406 :         self.ptr.next()
     255        16406 :     }
     256              : }
     257              : 
     258              : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
     259        32812 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
     260        32812 :         Self {
     261        32812 :             ptr,
     262        32812 :             _owner: PhantomData,
     263        32812 :         }
     264        32812 :     }
     265              : }
     266              : 
     267              : impl RelocationBase for Fixup<'_> {
     268       131248 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     269       131248 :         self.ptr.as_ref().unwrap().as_ref()
     270       131248 :     }
     271              : }
     272              : 
     273              : impl generic::Relocation for Fixup<'_> {
     274            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     275            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     276            0 :     }
     277              : }
     278              : 
     279              : impl std::fmt::Debug for Fixup<'_> {
     280        32812 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     281        32812 :         let base = self as &dyn RelocationBase;
     282        32812 :         f.debug_struct("Fixup")
     283        32812 :             .field("base", &base)
     284        32812 :             .field("target", &self.target())
     285        32812 :             .field("ptr_format", &self.ptr_format())
     286        32812 :             .field("offset", &self.offset())
     287        32812 :             .finish()
     288        32812 :     }
     289              : }
     290              : 
     291              : /// This structure represents a relocation in a Mach-O object file (`.o`)
     292              : pub struct Object<'a> {
     293              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>,
     294              :     _owner: PhantomData<&'a ()>,
     295              : }
     296              : 
     297              : impl FromFFI<ffi::MachO_RelocationObject> for Object<'_> {
     298        26390 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
     299        26390 :         Self {
     300        26390 :             ptr,
     301        26390 :             _owner: PhantomData,
     302        26390 :         }
     303        26390 :     }
     304              : }
     305              : 
     306              : impl RelocationBase for Object<'_> {
     307       105560 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     308       105560 :         self.ptr.as_ref().unwrap().as_ref()
     309       105560 :     }
     310              : }
     311              : 
     312              : impl generic::Relocation for Object<'_> {
     313            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     314            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     315            0 :     }
     316              : }
     317              : 
     318              : impl std::fmt::Debug for Object<'_> {
     319        26390 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     320        26390 :         let base = self as &dyn RelocationBase;
     321        26390 :         f.debug_struct("Object").field("base", &base).finish()
     322        26390 :     }
     323              : }
     324              : 
     325       146432 : declare_iterator!(
     326       146432 :     Relocations,
     327       146432 :     Relocation<'a>,
     328       146432 :     ffi::MachO_Relocation,
     329       146432 :     ffi::MachO_Binary,
     330       146432 :     ffi::MachO_Binary_it_relocations
     331       146432 : );
        

Generated by: LCOV version 2.1-1