LCOV - code coverage report
Current view: top level - src/macho - relocation.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 69.6 % 158 110
Test Date: 2025-06-29:00:00:00 Functions: 63.0 % 46 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       249192 : #[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       249192 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
      30       249192 :         unsafe {
      31       249192 :             let cmd_ref = ffi_entry.as_ref().unwrap();
      32       249192 : 
      33       249192 :             if ffi::MachO_RelocationDyld::classof(cmd_ref) {
      34       194544 :                 let raw = {
      35       194544 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      36       194544 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
      37       194544 :                     std::mem::transmute::<From, To>(ffi_entry)
      38       194544 :                 };
      39       194544 :                 Relocation::Dyld(Dyld::from_ffi(raw))
      40        54648 :             } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
      41        30288 :                 let raw = {
      42        30288 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      43        30288 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
      44        30288 :                     std::mem::transmute::<From, To>(ffi_entry)
      45        30288 :                 };
      46        30288 :                 Relocation::Fixup(Fixup::from_ffi(raw))
      47        24360 :             } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
      48        24360 :                 let raw = {
      49        24360 :                     type From = cxx::UniquePtr<ffi::MachO_Relocation>;
      50        24360 :                     type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
      51        24360 :                     std::mem::transmute::<From, To>(ffi_entry)
      52        24360 :                 };
      53        24360 :                 Relocation::Object(Object::from_ffi(raw))
      54              :             } else {
      55            0 :                 Relocation::Generic(Generic::from_ffi(ffi_entry))
      56              :             }
      57              :         }
      58       249192 :     }
      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       249192 :     fn is_pc_relative(&self) -> bool {
      72       249192 :         self.get_base().is_pc_relative()
      73       249192 :     }
      74              : 
      75              :     /// Symbol associated with the relocation (if any)
      76       249192 :     fn symbol(&self) -> Option<Symbol> {
      77       249192 :         into_optional(self.get_base().symbol())
      78       249192 :     }
      79              : 
      80              :     /// Section associated with the section (if any)
      81       249192 :     fn section(&self) -> Option<Section> {
      82       249192 :         into_optional(self.get_base().section())
      83       249192 :     }
      84              : 
      85              :     /// Segment command associated with the relocation (if any)
      86       249192 :     fn segment(&self) -> Option<Segment> {
      87       249192 :         into_optional(self.get_base().segment())
      88       249192 :     }
      89              : }
      90              : 
      91              : impl RelocationBase for Relocation<'_> {
      92            0 :     fn get_base(&self) -> &ffi::MachO_Relocation {
      93            0 :         match &self {
      94            0 :             Relocation::Dyld(reloc) => {
      95            0 :                 reloc.get_base()
      96              :             }
      97              : 
      98            0 :             Relocation::Fixup(reloc) => {
      99            0 :                 reloc.get_base()
     100              :             }
     101              : 
     102            0 :             Relocation::Object(reloc) => {
     103            0 :                 reloc.get_base()
     104              :             }
     105              : 
     106            0 :             Relocation::Generic(reloc) => {
     107            0 :                 reloc.get_base()
     108              :             }
     109              :         }
     110            0 :     }
     111              : }
     112              : 
     113              : impl generic::Relocation for Relocation<'_> {
     114            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     115            0 :         match &self {
     116            0 :             Relocation::Dyld(reloc) => {
     117            0 :                 reloc.as_generic()
     118              :             }
     119              : 
     120            0 :             Relocation::Fixup(reloc) => {
     121            0 :                 reloc.as_generic()
     122              :             }
     123              : 
     124            0 :             Relocation::Object(reloc) => {
     125            0 :                 reloc.as_generic()
     126              :             }
     127              : 
     128            0 :             Relocation::Generic(reloc) => {
     129            0 :                 reloc.as_generic()
     130              :             }
     131              :         }
     132            0 :     }
     133              : }
     134              : 
     135              : 
     136              : impl std::fmt::Debug for &dyn RelocationBase {
     137       249192 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     138       249192 :         f.debug_struct("Section")
     139       249192 :             .field("is_pc_relative", &self.is_pc_relative())
     140       249192 :             .field("symbol", &self.symbol())
     141       249192 :             .field("section", &self.section())
     142       249192 :             .field("segment", &self.segment())
     143       249192 :             .finish()
     144       249192 :     }
     145              : }
     146              : 
     147              : pub struct Generic<'a> {
     148              :     ptr: cxx::UniquePtr<ffi::MachO_Relocation>,
     149              :     _owner: PhantomData<&'a ()>,
     150              : }
     151              : 
     152              : impl RelocationBase for Generic<'_> {
     153            0 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     154            0 :         self.ptr.as_ref().unwrap()
     155            0 :     }
     156              : }
     157              : 
     158              : impl generic::Relocation for Generic<'_> {
     159            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     160            0 :         self.ptr.as_ref().unwrap().as_ref()
     161            0 :     }
     162              : }
     163              : 
     164              : impl std::fmt::Debug for Generic<'_> {
     165            0 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     166            0 :         let base = self as &dyn RelocationBase;
     167            0 :         f.debug_struct("Generic").field("base", &base).finish()
     168            0 :     }
     169              : }
     170              : 
     171              : impl FromFFI<ffi::MachO_Relocation> for Generic<'_> {
     172            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
     173            0 :         Self {
     174            0 :             ptr,
     175            0 :             _owner: PhantomData,
     176            0 :         }
     177            0 :     }
     178              : }
     179              : 
     180              : /// Structure that represents a bytecode rebase operation (from `LC_DYLD_INFO`)
     181              : pub struct Dyld<'a> {
     182              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>,
     183              :     _owner: PhantomData<&'a ()>,
     184              : }
     185              : 
     186              : impl FromFFI<ffi::MachO_RelocationDyld> for Dyld<'_> {
     187       194544 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
     188       194544 :         Self {
     189       194544 :             ptr,
     190       194544 :             _owner: PhantomData,
     191       194544 :         }
     192       194544 :     }
     193              : }
     194              : 
     195              : impl RelocationBase for Dyld<'_> {
     196       778176 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     197       778176 :         self.ptr.as_ref().unwrap().as_ref()
     198       778176 :     }
     199              : }
     200              : 
     201              : 
     202              : impl generic::Relocation for Dyld<'_> {
     203            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     204            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     205            0 :     }
     206              : }
     207              : 
     208              : impl std::fmt::Debug for Dyld<'_> {
     209       194544 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     210       194544 :         let base = self as &dyn RelocationBase;
     211       194544 :         f.debug_struct("Dyld").field("base", &base).finish()
     212       194544 :     }
     213              : }
     214              : 
     215              : /// Structure that represents a fixup (i.e. relocation) from  the recent from `LC_DYLD_CHAINED_FIXUPS`
     216              : /// command
     217              : pub struct Fixup<'a> {
     218              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>,
     219              :     _owner: PhantomData<&'a ()>,
     220              : }
     221              : 
     222              : impl Fixup<'_> {
     223              :     /// The value that should be set at the address pointed by [`crate::Relocation::address`]
     224              :     /// if the imagebase chosen by the loader is [`crate::generic::Binary::imagebase`].
     225              :     /// Otherwise: [`Fixup::target`] - [`crate::generic::Binary::imagebase`] + new_imagebase.
     226        30288 :     pub fn target(&self) -> u64 {
     227        30288 :         self.ptr.target()
     228        30288 :     }
     229        30288 :     pub fn ptr_format(&self) -> u32 {
     230        30288 :         self.ptr.ptr_format()
     231        30288 :     }
     232              : 
     233              :     /// The address of this relocation is bound to its offset
     234        30288 :     pub fn offset(&self) -> u32 {
     235        30288 :         self.ptr.offset()
     236        30288 :     }
     237              : 
     238              :     /// Return the (unscaled) next offset in the chain
     239        15144 :     pub fn next(&self) -> u32 {
     240        15144 :         self.ptr.next()
     241        15144 :     }
     242              : }
     243              : 
     244              : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
     245        30288 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
     246        30288 :         Self {
     247        30288 :             ptr,
     248        30288 :             _owner: PhantomData,
     249        30288 :         }
     250        30288 :     }
     251              : }
     252              : 
     253              : impl RelocationBase for Fixup<'_> {
     254       121152 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     255       121152 :         self.ptr.as_ref().unwrap().as_ref()
     256       121152 :     }
     257              : }
     258              : 
     259              : impl generic::Relocation for Fixup<'_> {
     260            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     261            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     262            0 :     }
     263              : }
     264              : 
     265              : impl std::fmt::Debug for Fixup<'_> {
     266        30288 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     267        30288 :         let base = self as &dyn RelocationBase;
     268        30288 :         f.debug_struct("Fixup")
     269        30288 :             .field("base", &base)
     270        30288 :             .field("target", &self.target())
     271        30288 :             .field("ptr_format", &self.ptr_format())
     272        30288 :             .field("offset", &self.offset())
     273        30288 :             .finish()
     274        30288 :     }
     275              : }
     276              : 
     277              : /// This structure represents a relocation in a Mach-O object file (`.o`)
     278              : pub struct Object<'a> {
     279              :     ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>,
     280              :     _owner: PhantomData<&'a ()>,
     281              : }
     282              : 
     283              : impl FromFFI<ffi::MachO_RelocationObject> for Object<'_> {
     284        24360 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
     285        24360 :         Self {
     286        24360 :             ptr,
     287        24360 :             _owner: PhantomData,
     288        24360 :         }
     289        24360 :     }
     290              : }
     291              : 
     292              : impl RelocationBase for Object<'_> {
     293        97440 :     fn get_base(&self) -> &ffi::MachO_Relocation {
     294        97440 :         self.ptr.as_ref().unwrap().as_ref()
     295        97440 :     }
     296              : }
     297              : 
     298              : impl generic::Relocation for Object<'_> {
     299            0 :     fn as_generic(&self) -> &ffi::AbstractRelocation {
     300            0 :         self.ptr.as_ref().unwrap().as_ref().as_ref()
     301            0 :     }
     302              : }
     303              : 
     304              : impl std::fmt::Debug for Object<'_> {
     305        24360 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     306        24360 :         let base = self as &dyn RelocationBase;
     307        24360 :         f.debug_struct("Object").field("base", &base).finish()
     308        24360 :     }
     309              : }
     310              : 
     311       122952 : declare_iterator!(
     312       122952 :     Relocations,
     313       122952 :     Relocation<'a>,
     314       122952 :     ffi::MachO_Relocation,
     315       122952 :     ffi::MachO_Binary,
     316       122952 :     ffi::MachO_Binary_it_relocations
     317       122952 : );
        

Generated by: LCOV version 2.1-1