LCOV - code coverage report
Current view: top level - src/macho - binding_info.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 81.4 % 172 140
Test Date: 2026-04-12:00:00:00 Functions: 53.6 % 69 37

            Line data    Source code
       1              : use lief_ffi as ffi;
       2              : 
       3              : use super::commands::dylib::Dylib;
       4              : use super::commands::Segment;
       5              : use super::symbol::Symbol;
       6              : use std::{fmt, marker::PhantomData};
       7              : 
       8              : use crate::common::{into_optional, FromFFI};
       9              : 
      10       383708 : #[derive(Debug)]
      11              : /// This enum exposes all the different types of binding operations that
      12              : /// we can find in a Mach-O binary. [`BindingInfo::Dyld`] exposes the bindings info
      13              : /// wrapped in the `LC_DYLD_INFO` command while [`BindingInfo::Chained`] exposes the new
      14              : /// chained bindings implemented in the `DYLD_CHAINED_FIXUPS` command.
      15              : pub enum BindingInfo<'a> {
      16              :     /// Bindings defined in `LC_DYLD_INFO` command
      17              :     Dyld(Dyld<'a>),
      18              :     /// Bindings defined in `DYLD_CHAINED_FIXUPS` command
      19              :     Chained(Chained<'a>),
      20              :     /// Bindings infered from the indirect symbol table
      21              :     Indirect(Indirect<'a>),
      22              :     /// Fallback item
      23              :     Generic(Generic<'a>),
      24              : }
      25              : 
      26              : /// Generic trait shared by all [`BindingInfo`] items
      27              : pub trait AsGeneric {
      28              :     #[doc(hidden)]
      29              :     fn as_generic(&self) -> &ffi::MachO_BindingInfo;
      30              : 
      31              :     /// Library associated with the binding (if any)
      32        88478 :     fn library(&self) -> Option<Dylib<'_>> {
      33        88478 :         into_optional(self.as_generic().library())
      34        88478 :     }
      35              : 
      36              :     /// Symbol associated with the binding (if any)
      37        88478 :     fn symbol(&self) -> Option<Symbol<'_>> {
      38        88478 :         into_optional(self.as_generic().symbol())
      39        88478 :     }
      40              : 
      41              :     /// Segment associated with the binding (if any)
      42        88478 :     fn segment(&self) -> Option<Segment<'_>> {
      43        88478 :         into_optional(self.as_generic().segment())
      44        88478 :     }
      45              : 
      46              :     /// Address of the binding
      47       384371 :     fn address(&self) -> u64 {
      48       384371 :         self.as_generic().address()
      49       384371 :     }
      50              : 
      51              :     /// Value added to the segment's virtual address when bound
      52       384371 :     fn addend(&self) -> i64 {
      53       384371 :         self.as_generic().addend()
      54       384371 :     }
      55              : 
      56       384371 :     fn library_ordinal(&self) -> i32 {
      57       384371 :         self.as_generic().library_ordinal()
      58       384371 :     }
      59              : }
      60              : 
      61              : impl AsGeneric for BindingInfo<'_> {
      62              :     #[doc(hidden)]
      63            0 :     fn as_generic(&self) -> &ffi::MachO_BindingInfo {
      64            0 :         match &self {
      65            0 :             BindingInfo::Dyld(info) => info.as_generic(),
      66            0 :             BindingInfo::Chained(info) => info.as_generic(),
      67            0 :             BindingInfo::Indirect(info) => info.as_generic(),
      68            0 :             BindingInfo::Generic(info) => info.as_generic(),
      69              :         }
      70            0 :     }
      71              : }
      72              : 
      73              : impl std::fmt::Debug for &dyn AsGeneric {
      74       384371 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      75       384371 :         f.debug_struct("AsGeneric")
      76       384371 :             .field("address", &self.address())
      77       384371 :             .field("addend", &self.addend())
      78       384371 :             .field("library_ordinal", &self.library_ordinal())
      79       384371 :             .finish()
      80       384371 :     }
      81              : }
      82              : 
      83              : impl<'a> FromFFI<ffi::MachO_BindingInfo> for BindingInfo<'a> {
      84       206752 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_BindingInfo>) -> Self {
      85       206752 :         unsafe {
      86       206752 :             let cmd_ref = ffi_entry.as_ref().unwrap();
      87       206752 : 
      88       206752 :             if ffi::MachO_ChainedBindingInfo::classof(cmd_ref) {
      89         1313 :                 let raw = {
      90         1313 :                     type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
      91         1313 :                     type To = cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>;
      92         1313 :                     std::mem::transmute::<From, To>(ffi_entry)
      93         1313 :                 };
      94         1313 :                 BindingInfo::Chained(Chained::from_ffi(raw))
      95       205439 :             } else if ffi::MachO_DyldBindingInfo::classof(cmd_ref) {
      96       204477 :                 let raw = {
      97       204477 :                     type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
      98       204477 :                     type To = cxx::UniquePtr<ffi::MachO_DyldBindingInfo>;
      99       204477 :                     std::mem::transmute::<From, To>(ffi_entry)
     100       204477 :                 };
     101       204477 :                 BindingInfo::Dyld(Dyld::from_ffi(raw))
     102          962 :             } else if ffi::MachO_IndirectBindingInfo::classof(cmd_ref) {
     103          962 :                 let raw = {
     104          962 :                     type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
     105          962 :                     type To = cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>;
     106          962 :                     std::mem::transmute::<From, To>(ffi_entry)
     107          962 :                 };
     108          962 :                 BindingInfo::Indirect(Indirect::from_ffi(raw))
     109              :             } else {
     110            0 :                 BindingInfo::Generic(Generic::from_ffi(ffi_entry))
     111              :             }
     112              :         }
     113       206752 :     }
     114              : }
     115              : 
     116              : pub struct Generic<'a> {
     117              :     ptr: cxx::UniquePtr<ffi::MachO_BindingInfo>,
     118              :     _owner: PhantomData<&'a ()>,
     119              : }
     120              : 
     121              : impl fmt::Debug for Generic<'_> {
     122            0 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     123            0 :         let base = self as &dyn AsGeneric;
     124            0 :         f.debug_struct("Generic").field("base", &base).finish()
     125            0 :     }
     126              : }
     127              : 
     128              : impl<'a> FromFFI<ffi::MachO_BindingInfo> for Generic<'a> {
     129            0 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_BindingInfo>) -> Self {
     130            0 :         Self {
     131            0 :             ptr,
     132            0 :             _owner: PhantomData,
     133            0 :         }
     134            0 :     }
     135              : }
     136              : 
     137              : impl AsGeneric for Generic<'_> {
     138            0 :     fn as_generic(&self) -> &ffi::MachO_BindingInfo {
     139            0 :         self.ptr.as_ref().unwrap()
     140            0 :     }
     141              : }
     142              : 
     143              : /// This structure represents a binding operation coming from binding bytecode
     144              : /// of `LC_DYLD_INFO`
     145              : pub struct Dyld<'a> {
     146              :     ptr: cxx::UniquePtr<ffi::MachO_DyldBindingInfo>,
     147              :     _owner: PhantomData<&'a ()>,
     148              : }
     149              : 
     150              : #[allow(non_camel_case_types)]
     151       381433 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     152              : pub enum BINDING_CLASS {
     153              :     WEAK,
     154              :     LAZY,
     155              :     STANDARD,
     156              :     THREADED,
     157              :     UNKNOWN(u64),
     158              : }
     159              : 
     160              : impl BINDING_CLASS {
     161       381433 :     pub fn from_value(value: u64) -> Self {
     162       381433 :         match value {
     163         2262 :             0x00000001 => BINDING_CLASS::WEAK,
     164       111059 :             0x00000002 => BINDING_CLASS::LAZY,
     165       268112 :             0x00000003 => BINDING_CLASS::STANDARD,
     166            0 :             0x00000064 => BINDING_CLASS::THREADED,
     167            0 :             _ => BINDING_CLASS::UNKNOWN(value),
     168              :         }
     169       381433 :     }
     170              : }
     171              : 
     172              : #[allow(non_camel_case_types)]
     173       381433 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     174              : pub enum BIND_TYPES {
     175              :     POINTER,
     176              :     TEXT_ABSOLUTE32,
     177              :     TEXT_PCREL32,
     178              :     UNKNOWN(u64),
     179              : }
     180              : 
     181              : impl BIND_TYPES {
     182       381433 :     pub fn from_value(value: u64) -> Self {
     183       381433 :         match value {
     184       381433 :             0x00000001 => BIND_TYPES::POINTER,
     185            0 :             0x00000002 => BIND_TYPES::TEXT_ABSOLUTE32,
     186            0 :             0x00000003 => BIND_TYPES::TEXT_PCREL32,
     187            0 :             _ => BIND_TYPES::UNKNOWN(value),
     188              :         }
     189       381433 :     }
     190              : }
     191              : 
     192              : impl Dyld<'_> {
     193              :     /// Class of the binding (weak, lazy, ...)
     194       381433 :     pub fn binding_class(&self) -> BINDING_CLASS {
     195       381433 :         BINDING_CLASS::from_value(self.ptr.binding_class())
     196       381433 :     }
     197              : 
     198              :     /// Type of the binding. Most of the times it should be [`BIND_TYPES::POINTER`]
     199       381433 :     pub fn binding_type(&self) -> BIND_TYPES {
     200       381433 :         BIND_TYPES::from_value(self.ptr.binding_type())
     201       381433 :     }
     202              : 
     203       381433 :     pub fn is_non_weak_definition(&self) -> bool {
     204       381433 :         self.ptr.is_non_weak_definition()
     205       381433 :     }
     206              : 
     207       381433 :     pub fn original_offset(&self) -> u64 {
     208       381433 :         self.ptr.original_offset()
     209       381433 :     }
     210              : }
     211              : 
     212              : impl fmt::Debug for Dyld<'_> {
     213       381433 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     214       381433 :         let base = self as &dyn AsGeneric;
     215       381433 :         f.debug_struct("Dyld")
     216       381433 :             .field("base", &base)
     217       381433 :             .field("binding_class", &self.binding_class())
     218       381433 :             .field("binding_type", &self.binding_type())
     219       381433 :             .field("is_non_weak_definition", &self.is_non_weak_definition())
     220       381433 :             .field("original_offset", &self.original_offset())
     221       381433 :             .finish()
     222       381433 :     }
     223              : }
     224              : 
     225              : impl FromFFI<ffi::MachO_DyldBindingInfo> for Dyld<'_> {
     226       292955 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_DyldBindingInfo>) -> Self {
     227       292955 :         Self {
     228       292955 :             ptr,
     229       292955 :             _owner: PhantomData,
     230       292955 :         }
     231       292955 :     }
     232              : }
     233              : 
     234              : impl AsGeneric for Dyld<'_> {
     235      1409733 :     fn as_generic(&self) -> &ffi::MachO_BindingInfo {
     236      1409733 :         self.ptr.as_ref().unwrap().as_ref()
     237      1409733 :     }
     238              : }
     239              : /// This structure represents a binding operation coming from chained binding command:
     240              : /// `LC_DYLD_CHAINED_FIXUPS`
     241              : pub struct Chained<'a> {
     242              :     ptr: cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>,
     243              :     _owner: PhantomData<&'a ()>,
     244              : }
     245              : 
     246              : #[allow(non_camel_case_types)]
     247         2080 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
     248              : pub enum CHAINED_FORMAT {
     249              :     IMPORT,
     250              :     IMPORT_ADDEND,
     251              :     IMPORT_ADDEND64,
     252              :     UNKNOWN(u32),
     253              : }
     254              : 
     255              : impl CHAINED_FORMAT {
     256         2080 :     pub fn from_value(value: u32) -> Self {
     257         2080 :         match value {
     258         2080 :             0x00000001 => CHAINED_FORMAT::IMPORT,
     259            0 :             0x00000002 => CHAINED_FORMAT::IMPORT_ADDEND,
     260            0 :             0x00000003 => CHAINED_FORMAT::IMPORT_ADDEND64,
     261            0 :             _ => CHAINED_FORMAT::UNKNOWN(value),
     262              :         }
     263         2080 :     }
     264              : }
     265              : 
     266              : impl Chained<'_> {
     267              :     /// Format of the imports
     268         1976 :     pub fn format(&self) -> CHAINED_FORMAT {
     269         1976 :         CHAINED_FORMAT::from_value(self.ptr.format())
     270         1976 :     }
     271              : 
     272              :     /// Format of the pointer
     273         1976 :     pub fn ptr_format(&self) -> u32 {
     274         1976 :         self.ptr.ptr_format()
     275         1976 :     }
     276              : 
     277              :     /// Original offset in the chain of this binding
     278         1976 :     pub fn offset(&self) -> u32 {
     279         1976 :         self.ptr.offset()
     280         1976 :     }
     281              : 
     282              :     /// Sign-extended addend for this chained binding
     283            0 :     pub fn sign_extended_addend(&self) -> u64 {
     284            0 :         self.ptr.sign_extended_addend()
     285            0 :     }
     286              : }
     287              : 
     288              : impl fmt::Debug for Chained<'_> {
     289         1976 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     290         1976 :         let base = self as &dyn AsGeneric;
     291         1976 :         f.debug_struct("Chained")
     292         1976 :             .field("base", &base)
     293         1976 :             .field("format", &self.format())
     294         1976 :             .field("ptr_format", &self.ptr_format())
     295         1976 :             .field("offset", &self.offset())
     296         1976 :             .finish()
     297         1976 :     }
     298              : }
     299              : 
     300              : impl FromFFI<ffi::MachO_ChainedBindingInfo> for Chained<'_> {
     301         1976 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>) -> Self {
     302         1976 :         Self {
     303         1976 :             ptr,
     304         1976 :             _owner: PhantomData,
     305         1976 :         }
     306         1976 :     }
     307              : }
     308              : 
     309              : impl AsGeneric for Chained<'_> {
     310         5928 :     fn as_generic(&self) -> &ffi::MachO_BindingInfo {
     311         5928 :         self.ptr.as_ref().unwrap().as_ref()
     312         5928 :     }
     313              : }
     314              : 
     315              : /// This structure represents a binding operation coming from the indirect symbol table
     316              : pub struct Indirect<'a> {
     317              :     ptr: cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>,
     318              :     _owner: PhantomData<&'a ()>,
     319              : }
     320              : 
     321              : impl fmt::Debug for Indirect<'_> {
     322          962 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     323          962 :         let base = self as &dyn AsGeneric;
     324          962 :         f.debug_struct("Indirect").field("base", &base).finish()
     325          962 :     }
     326              : }
     327              : 
     328              : impl FromFFI<ffi::MachO_IndirectBindingInfo> for Indirect<'_> {
     329          962 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>) -> Self {
     330          962 :         Self {
     331          962 :             ptr,
     332          962 :             _owner: PhantomData,
     333          962 :         }
     334          962 :     }
     335              : }
     336              : 
     337              : impl AsGeneric for Indirect<'_> {
     338         2886 :     fn as_generic(&self) -> &ffi::MachO_BindingInfo {
     339         2886 :         self.ptr.as_ref().unwrap().as_ref()
     340         2886 :     }
     341              : }
        

Generated by: LCOV version 2.1-1