LCOV - code coverage report
Current view: top level - src/macho - binary.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 75.7 % 177 134
Test Date: 2024-10-27:00:00:00 Functions: 85.7 % 49 42

            Line data    Source code
       1              : use std::mem::size_of;
       2              : use num_traits::{Num, cast};
       3              : 
       4              : use crate::Error;
       5              : use super::commands::build_version::{BuildVersion, Platform};
       6              : use super::commands::code_signature::CodeSignature;
       7              : use super::commands::code_signature_dir::CodeSignatureDir;
       8              : use super::commands::data_in_code::DataInCode;
       9              : use super::commands::dyld_chained_fixups::DyldChainedFixups;
      10              : use super::commands::dyld_environment::DyldEnvironment;
      11              : use super::commands::dyld_export_trie::DyldExportsTrie;
      12              : use super::commands::dyldinfo::DyldInfo;
      13              : use super::commands::dylib::Libraries;
      14              : use super::commands::dylinker::Dylinker;
      15              : use super::commands::dynamic_symbol_command::DynamicSymbolCommand;
      16              : use super::commands::encryption_info::EncryptionInfo;
      17              : use super::commands::functionstarts::FunctionStarts;
      18              : use super::commands::linker_opt_hint::LinkerOptHint;
      19              : use super::commands::main_cmd::Main;
      20              : use super::commands::rpath::RPath;
      21              : use super::commands::routine::Routine;
      22              : use super::commands::segment::Segments;
      23              : use super::commands::segment_split_info::SegmentSplitInfo;
      24              : use super::commands::source_version::SourceVersion;
      25              : use super::commands::sub_framework::SubFramework;
      26              : use super::commands::sub_client::SubClients;
      27              : use super::commands::symbol_command::SymbolCommand;
      28              : use super::commands::thread_command::ThreadCommand;
      29              : use super::commands::two_level_hints::TwoLevelHints;
      30              : use super::commands::uuid::UUID;
      31              : use super::commands::version_min::VersionMin;
      32              : use super::commands::CommandsIter;
      33              : use super::header::Header;
      34              : use super::relocation::Relocations;
      35              : use super::section::Sections;
      36              : use super::symbol::Symbols;
      37              : use super::binding_info::BindingInfo;
      38              : use super::stub::Stub;
      39              : use lief_ffi as ffi;
      40              : 
      41              : use crate::common::{into_optional, FromFFI};
      42              : use crate::{generic, declare_fwd_iterator, declare_iterator, to_conv_result};
      43              : use crate::objc::Metadata;
      44              : 
      45              : /// This is the main interface to read and write Mach-O binary attributes.
      46              : ///
      47              : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
      48              : /// functions are exposed
      49              : pub struct Binary {
      50              :     ptr: cxx::UniquePtr<ffi::MachO_Binary>,
      51              : }
      52              : 
      53              : impl std::fmt::Debug for Binary {
      54          112 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
      55          112 :         f.debug_struct("Binary").finish()
      56          112 :     }
      57              : }
      58              : 
      59              : impl FromFFI<ffi::MachO_Binary> for Binary {
      60          112 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Binary>) -> Self {
      61          112 :         Binary { ptr }
      62          112 :     }
      63              : }
      64              : 
      65              : impl Binary {
      66              :     /// Return the main Mach-O header
      67          112 :     pub fn header(&self) -> Header {
      68          112 :         Header::from_ffi(self.ptr.header())
      69          112 :     }
      70              : 
      71              :     /// Return an iterator over the different [`crate::macho::Commands`] used by the
      72              :     /// Mach-O binary
      73          112 :     pub fn commands(&self) -> CommandsIter {
      74          112 :         CommandsIter::new(self.ptr.commands())
      75          112 :     }
      76              : 
      77              :     /// Return an iterator over the different [`crate::macho::Section`] of the binary
      78          112 :     pub fn sections(&self) -> Sections {
      79          112 :         Sections::new(self.ptr.sections())
      80          112 :     }
      81              : 
      82              :     /// Return an iterator over the different [`crate::macho::commands::Segment`] (`LC_SEGMENT/LC_SIGNATURE`)
      83              :     /// of the binary.
      84          112 :     pub fn segments(&self) -> Segments {
      85          112 :         Segments::new(self.ptr.segments())
      86          112 :     }
      87              : 
      88              :     /// Return an iterator over the [`crate::macho::commands::Dylib`] used by this binary
      89          112 :     pub fn libraries(&self) -> Libraries {
      90          112 :         Libraries::new(self.ptr.libraries())
      91          112 :     }
      92              : 
      93              :     /// Return an iterator over the different [`crate::macho::Relocation`] of this binary
      94          112 :     pub fn relocations(&self) -> Relocations {
      95          112 :         Relocations::new(self.ptr.relocations())
      96          112 :     }
      97              : 
      98              :     /// Return an iterator over the different [`crate::macho::Symbol`] of this binary
      99          112 :     pub fn symbols(&self) -> Symbols {
     100          112 :         Symbols::new(self.ptr.symbols())
     101          112 :     }
     102              : 
     103              :     /// Return the `LC_DYLD_INFO/LC_DYLD_INFO_ONLY` command if present
     104          112 :     pub fn dyld_info(&self) -> Option<DyldInfo> {
     105          112 :         into_optional(self.ptr.dyld_info())
     106          112 :     }
     107              : 
     108              :     /// Return the `LC_UUID` command if present
     109          112 :     pub fn uuid(&self) -> Option<UUID> {
     110          112 :         into_optional(self.ptr.uuid())
     111          112 :     }
     112              : 
     113              :     /// Return the `LC_MAIN` command if present
     114          112 :     pub fn main_command(&self) -> Option<Main> {
     115          112 :         into_optional(self.ptr.main_command())
     116          112 :     }
     117              : 
     118              :     /// Return the `LC_LOAD_DYLINKER/LC_ID_DYLINKER` command if present
     119          112 :     pub fn dylinker(&self) -> Option<Dylinker> {
     120          112 :         into_optional(self.ptr.dylinker())
     121          112 :     }
     122              : 
     123              :     /// Return the `LC_FUNCTION_STARTS` command if present
     124          112 :     pub fn function_starts(&self) -> Option<FunctionStarts> {
     125          112 :         into_optional(self.ptr.function_starts())
     126          112 :     }
     127              : 
     128              :     /// Return the `LC_SOURCE_VERSION` command if present
     129          112 :     pub fn source_version(&self) -> Option<SourceVersion> {
     130          112 :         into_optional(self.ptr.source_version())
     131          112 :     }
     132              : 
     133              :     /// Return the `LC_THREAD/LC_UNIXTHREAD` command if present
     134          112 :     pub fn thread_command(&self) -> Option<ThreadCommand> {
     135          112 :         into_optional(self.ptr.thread_command())
     136          112 :     }
     137              : 
     138              :     /// Return the `LC_RPATH` command if present
     139          112 :     pub fn rpath(&self) -> Option<RPath> {
     140          112 :         into_optional(self.ptr.rpath())
     141          112 :     }
     142              : 
     143              :     /// Return the `LC_ROUTINE/LC_ROUTINE64` command if present
     144          112 :     pub fn routine(&self) -> Option<Routine> {
     145          112 :         into_optional(self.ptr.routine_command())
     146          112 :     }
     147              : 
     148              :     /// Return the `LC_SYMTAB` command if present
     149          112 :     pub fn symbol_command(&self) -> Option<SymbolCommand> {
     150          112 :         into_optional(self.ptr.symbol_command())
     151          112 :     }
     152              : 
     153              :     /// Return the `LC_DYSYMTAB` command if present
     154          112 :     pub fn dynamic_symbol(&self) -> Option<DynamicSymbolCommand> {
     155          112 :         into_optional(self.ptr.dynamic_symbol_command())
     156          112 :     }
     157              : 
     158              :     /// Return the `LC_CODE_SIGNATURE` command if present
     159          112 :     pub fn code_signature(&self) -> Option<CodeSignature> {
     160          112 :         into_optional(self.ptr.code_signature())
     161          112 :     }
     162              : 
     163              :     /// Return the `LC_DYLIB_CODE_SIGN_DRS` command if present
     164          112 :     pub fn code_signature_dir(&self) -> Option<CodeSignatureDir> {
     165          112 :         into_optional(self.ptr.code_signature_dir())
     166          112 :     }
     167              : 
     168              :     /// Return the `LC_DATA_IN_CODE` command if present
     169          112 :     pub fn data_in_code(&self) -> Option<DataInCode> {
     170          112 :         into_optional(self.ptr.data_in_code())
     171          112 :     }
     172              : 
     173              :     /// Return the `LC_SEGMENT_SPLIT_INFO` command if present
     174          112 :     pub fn segment_split_info(&self) -> Option<SegmentSplitInfo> {
     175          112 :         into_optional(self.ptr.segment_split_info())
     176          112 :     }
     177              : 
     178              :     /// Return the `LC_ENCRYPTION_INFO/LC_ENCRYPTION_INFO_64` command if present
     179          112 :     pub fn encryption_info(&self) -> Option<EncryptionInfo> {
     180          112 :         into_optional(self.ptr.encryption_info())
     181          112 :     }
     182              : 
     183              :     /// Return the `LC_SUB_FRAMEWORK` command if present
     184          112 :     pub fn sub_framework(&self) -> Option<SubFramework> {
     185          112 :         into_optional(self.ptr.sub_framework())
     186          112 :     }
     187              : 
     188              :     /// Return the `LC_SUBCLIENT` command if present
     189          112 :     pub fn subclients(&self) -> SubClients {
     190          112 :         SubClients::new(self.ptr.subclients())
     191          112 :     }
     192              : 
     193              :     /// Return the `LC_DYLD_ENVIRONMENT` command if present
     194          112 :     pub fn dyld_environment(&self) -> Option<DyldEnvironment> {
     195          112 :         into_optional(self.ptr.dyld_environment())
     196          112 :     }
     197              : 
     198              :     /// Return the `LC_BUILD_VERSION` command if present
     199          112 :     pub fn build_version(&self) -> Option<BuildVersion> {
     200          112 :         into_optional(self.ptr.build_version())
     201          112 :     }
     202              : 
     203              :     /// Return the `LC_DYLD_CHAINED_FIXUPS` command if present
     204          112 :     pub fn dyld_chained_fixups(&self) -> Option<DyldChainedFixups> {
     205          112 :         into_optional(self.ptr.dyld_chained_fixups())
     206          112 :     }
     207              : 
     208              :     /// Return the `LC_DYLD_EXPORTS_TRIE` command if present
     209          112 :     pub fn dyld_exports_trie(&self) -> Option<DyldExportsTrie> {
     210          112 :         into_optional(self.ptr.dyld_exports_trie())
     211          112 :     }
     212              : 
     213              :     /// Return the `LC_TWOLEVEL_HINTS` command if present
     214          112 :     pub fn two_level_hints(&self) -> Option<TwoLevelHints> {
     215          112 :         into_optional(self.ptr.two_level_hints())
     216          112 :     }
     217              : 
     218              :     /// Return the `LC_LINKER_OPTIMIZATION_HINT` command if present
     219          112 :     pub fn linker_opt_hint(&self) -> Option<LinkerOptHint> {
     220          112 :         into_optional(self.ptr.linker_opt_hint())
     221          112 :     }
     222              : 
     223              :     /// Return the `LC_VERSION_MIN_MACOSX/VERSION_MIN_IPHONEOS` command if present
     224          112 :     pub fn version_min(&self) -> Option<VersionMin> {
     225          112 :         into_optional(self.ptr.version_min())
     226          112 :     }
     227              : 
     228              :     /// Check if the binary is supporting ARM64 pointer authentication (arm64e)
     229            0 :     pub fn support_arm64_ptr_auth(&self) -> bool {
     230            0 :         self.ptr.support_arm64_ptr_auth()
     231            0 :     }
     232              : 
     233              :     /// Return an iterator over the bindings located in [`DyldInfo`] or [`DyldChainedFixups`]
     234          112 :     pub fn bindings(&self) -> BindingsInfo {
     235          112 :         BindingsInfo::new(self.ptr.bindings())
     236          112 :     }
     237              : 
     238              :     /// Return an iterator over the symbol stubs.
     239              :     ///
     240              :     /// These stubs are involved when calling an **imported** function and are
     241              :     /// similar to the ELF's plt/got mechanism.
     242              :     ///
     243              :     /// There are located in sections like: `__stubs,__auth_stubs,__symbol_stub,__picsymbolstub4`
     244          112 :     pub fn symbol_stubs(&self) -> Stubs {
     245          112 :         Stubs::new(self.ptr.symbol_stubs())
     246          112 :     }
     247              : 
     248              :     /// Return Objective-C metadata if present
     249            0 :     pub fn objc_metadata(&self) -> Option<Metadata> {
     250            0 :         into_optional(self.ptr.objc_metadata())
     251            0 :     }
     252              : 
     253              :     /// Return the platform for which this Mach-O has been compiled for
     254          112 :     pub fn platform(&self) -> Platform {
     255          112 :         Platform::from(self.ptr.platform())
     256          112 :     }
     257              : 
     258              :     /// True if this binary targets iOS
     259          112 :     pub fn is_ios(&self) -> bool {
     260          112 :         self.ptr.is_ios()
     261          112 :     }
     262              : 
     263              :     /// True if this binary targets macOS
     264          112 :     pub fn is_macos(&self) -> bool {
     265          112 :         self.ptr.is_macos()
     266          112 :     }
     267              : 
     268              : 
     269              :     /// Get the integer value at the given virtual address
     270            0 :     pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
     271            0 :         where T: Num + cast::FromPrimitive + cast::ToPrimitive
     272            0 :     {
     273            0 :         // Can't be in the generic trait because of:
     274            0 :         //   > for a trait to be "object safe" it needs to allow building a vtable to allow the call
     275            0 :         //   > to be resolvable dynamically; for more information visit
     276            0 :         //   > https://doc.rust-lang.org/reference/items/traits.html#object-safety
     277            0 :         if size_of::<T>() == size_of::<u8>() {
     278            0 :             to_conv_result!(ffi::AbstractBinary::get_u8,
     279            0 :                 self.ptr.as_ref().unwrap().as_ref(),
     280            0 :                 |value| { T::from_u8(value).expect(format!("Can't cast value: {}", value).as_str()) },
     281            0 :                 addr);
     282            0 :         }
     283            0 : 
     284            0 :         if size_of::<T>() == size_of::<u16>() {
     285            0 :             to_conv_result!(ffi::AbstractBinary::get_u16,
     286            0 :                 self.ptr.as_ref().unwrap().as_ref(),
     287            0 :                 |value| { T::from_u16(value).expect(format!("Can't cast value: {}", value).as_str()) },
     288            0 :                 addr);
     289            0 :         }
     290            0 : 
     291            0 :         if size_of::<T>() == size_of::<u32>() {
     292            0 :             to_conv_result!(ffi::AbstractBinary::get_u32,
     293            0 :                 self.ptr.as_ref().unwrap().as_ref(),
     294            0 :                 |value| { T::from_u32(value).expect(format!("Can't cast value: {}", value).as_str()) },
     295            0 :                 addr);
     296            0 :         }
     297            0 : 
     298            0 :         if size_of::<T>() == size_of::<u64>() {
     299            0 :             to_conv_result!(ffi::AbstractBinary::get_u64,
     300            0 :                 self.ptr.as_ref().unwrap().as_ref(),
     301            0 :                 |value| { T::from_u64(value).expect(format!("Can't cast value: {}", value).as_str()) },
     302            0 :                 addr);
     303            0 :         }
     304            0 : 
     305            0 :         Err(Error::NotSupported)
     306            0 :     }
     307              : }
     308              : 
     309              : impl generic::Binary for Binary {
     310          112 :     fn as_generic(&self) -> &ffi::AbstractBinary {
     311          112 :         self.ptr.as_ref().unwrap().as_ref()
     312          112 :     }
     313              : }
     314              : 
     315              : 
     316        52552 : declare_fwd_iterator!(
     317        52552 :     BindingsInfo,
     318        52552 :     BindingInfo<'a>,
     319        52552 :     ffi::MachO_BindingInfo,
     320        52552 :     ffi::MachO_Binary,
     321        52552 :     ffi::MachO_Binary_it_bindings_info
     322        52552 : );
     323              : 
     324        12160 : declare_iterator!(
     325        12160 :     Stubs,
     326        12160 :     Stub<'a>,
     327        12160 :     ffi::MachO_Stub,
     328        12160 :     ffi::MachO_Binary,
     329        12160 :     ffi::MachO_Binary_it_stubs
     330        12160 : );
        

Generated by: LCOV version 2.1-1