LCOV - code coverage report
Current view: top level - src/macho - section.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 67.0 % 188 126
Test Date: 2026-04-12:00:00:00 Functions: 50.9 % 57 29

            Line data    Source code
       1              : use super::commands::segment::Segment;
       2              : use super::thread_local_variables::ThreadLocalVariables;
       3              : use super::Relocation;
       4              : use lief_ffi as ffi;
       5              : use std::fmt;
       6              : use std::marker::PhantomData;
       7              : use std::pin::Pin;
       8              : 
       9              : use crate::common::{into_optional, FromFFI};
      10              : use crate::declare_iterator;
      11              : use crate::generic;
      12              : 
      13              : use bitflags::bitflags;
      14              : 
      15              : /// Enum that wraps all the Mach-O section types, dispatching to the
      16              : /// appropriate concrete type when extra semantics are available.
      17       304681 : #[derive(Debug)]
      18              : pub enum Section<'a> {
      19              :     /// A section without additional specialization.
      20              :     Generic(Generic<'a>),
      21              : 
      22              :     /// A section whose type is [`Type::THREAD_LOCAL_VARIABLES`], providing access
      23              :     /// to thread-local variable descriptors.
      24              :     ThreadLocalVariables(ThreadLocalVariables<'a>),
      25              : }
      26              : 
      27              : pub struct Generic<'a> {
      28              :     ptr: cxx::UniquePtr<ffi::MachO_Section>,
      29              :     _owner: PhantomData<&'a ()>,
      30              : }
      31              : 
      32              : #[allow(non_camel_case_types)]
      33       304642 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
      34              : pub enum Type {
      35              :     /// Regular section.
      36              :     REGULAR,
      37              :     /// Zero fill on demand section.
      38              :     ZEROFILL,
      39              :     /// Section with literal C strings.
      40              :     CSTRING_LITERALS,
      41              :     /// Section with 4 byte literals.
      42              :     S_4BYTE_LITERALS,
      43              :     /// Section with 8 byte literals.
      44              :     S_8BYTE_LITERALS,
      45              :     /// Section with pointers to literals.
      46              :     LITERAL_POINTERS,
      47              :     /// Section with non-lazy symbol pointers.
      48              :     NON_LAZY_SYMBOL_POINTERS,
      49              :     /// Section with lazy symbol pointers.
      50              :     LAZY_SYMBOL_POINTERS,
      51              :     /// Section with symbol stubs, byte size of stub in the Reserved2 field.
      52              :     SYMBOL_STUBS,
      53              :     /// Section with only function pointers for initialization.
      54              :     MOD_INIT_FUNC_POINTERS,
      55              :     /// Section with only function pointers for termination.
      56              :     MOD_TERM_FUNC_POINTERS,
      57              :     /// Section contains symbols that are to be coalesced.
      58              :     COALESCED,
      59              :     /// Zero fill on demand section (that can be larger than 4 gigabytes).
      60              :     GB_ZEROFILL,
      61              :     /// Section with only pairs of function pointers for interposing.
      62              :     INTERPOSING,
      63              :     /// Section with only 16 byte literals.
      64              :     S_16BYTE_LITERALS,
      65              :     /// Section contains DTrace Object Format.
      66              :     DTRACE_DOF,
      67              :     /// Section with lazy symbol pointers to lazy loaded dylibs.
      68              :     LAZY_DYLIB_SYMBOL_POINTERS,
      69              :     /// Thread local data section.
      70              :     THREAD_LOCAL_REGULAR,
      71              :     /// Thread local zerofill section.
      72              :     THREAD_LOCAL_ZEROFILL,
      73              :     /// Section with thread local variable structure data.
      74              :     THREAD_LOCAL_VARIABLES,
      75              :     /// Section with pointers to thread local structures.
      76              :     THREAD_LOCAL_VARIABLE_POINTERS,
      77              :     /// Section with thread local variable initialization pointers to functions.
      78              :     THREAD_LOCAL_INIT_FUNCTION_POINTERS,
      79              :     /// Section with 32-bit offsets to initializer functions
      80              :     INIT_FUNC_OFFSETS,
      81              :     UNKNOWN(u64),
      82              : }
      83              : 
      84              : impl From<u64> for Type {
      85       304837 :     fn from(value: u64) -> Self {
      86       304837 :         match value {
      87       252785 :             0x00000000 => Type::REGULAR,
      88          702 :             0x00000001 => Type::ZEROFILL,
      89          637 :             0x00000002 => Type::CSTRING_LITERALS,
      90            0 :             0x00000003 => Type::S_4BYTE_LITERALS,
      91            0 :             0x00000004 => Type::S_8BYTE_LITERALS,
      92           78 :             0x00000005 => Type::LITERAL_POINTERS,
      93        21879 :             0x00000006 => Type::NON_LAZY_SYMBOL_POINTERS,
      94        17381 :             0x00000007 => Type::LAZY_SYMBOL_POINTERS,
      95         3081 :             0x00000008 => Type::SYMBOL_STUBS,
      96          325 :             0x00000009 => Type::MOD_INIT_FUNC_POINTERS,
      97            0 :             0x0000000a => Type::MOD_TERM_FUNC_POINTERS,
      98         7813 :             0x0000000b => Type::COALESCED,
      99            0 :             0x0000000c => Type::GB_ZEROFILL,
     100            0 :             0x0000000d => Type::INTERPOSING,
     101           26 :             0x0000000e => Type::S_16BYTE_LITERALS,
     102           52 :             0x0000000f => Type::DTRACE_DOF,
     103            0 :             0x00000010 => Type::LAZY_DYLIB_SYMBOL_POINTERS,
     104            0 :             0x00000011 => Type::THREAD_LOCAL_REGULAR,
     105           26 :             0x00000012 => Type::THREAD_LOCAL_ZEROFILL,
     106           26 :             0x00000013 => Type::THREAD_LOCAL_VARIABLES,
     107            0 :             0x00000014 => Type::THREAD_LOCAL_VARIABLE_POINTERS,
     108            0 :             0x00000015 => Type::THREAD_LOCAL_INIT_FUNCTION_POINTERS,
     109           26 :             0x00000016 => Type::INIT_FUNC_OFFSETS,
     110            0 :             _ => Type::UNKNOWN(value),
     111              :         }
     112       304837 :     }
     113              : }
     114              : 
     115            0 : bitflags! {
     116       304642 :     #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
     117            0 :     pub struct Flags: u64 {
     118            0 :         const PURE_INSTRUCTIONS = 0x80000000;
     119            0 :         const NO_TOC = 0x40000000;
     120            0 :         const STRIP_STATIC_SYMS = 0x20000000;
     121            0 :         const NO_DEAD_STRIP = 0x10000000;
     122            0 :         const LIVE_SUPPORT = 0x8000000;
     123            0 :         const SELF_MODIFYING_CODE = 0x4000000;
     124            0 :         const DEBUG_INFO = 0x2000000;
     125            0 :         const SOME_INSTRUCTIONS = 0x400;
     126            0 :         const EXT_RELOC = 0x200;
     127            0 :         const LOC_RELOC = 0x100;
     128            0 :     }
     129            0 : }
     130              : 
     131              : impl From<u64> for Flags {
     132            0 :     fn from(value: u64) -> Self {
     133            0 :         Flags::from_bits_truncate(value)
     134            0 :     }
     135              : }
     136              : impl From<Flags> for u64 {
     137            0 :     fn from(value: Flags) -> Self {
     138            0 :         value.bits()
     139            0 :     }
     140              : }
     141              : impl std::fmt::Display for Flags {
     142            0 :     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
     143            0 :         bitflags::parser::to_writer(self, f)
     144            0 :     }
     145              : }
     146              : 
     147              : /// Trait shared by **all** Mach-O section types in the [`Section`] enum.
     148              : pub trait MachOSection {
     149              :     #[doc(hidden)]
     150              :     fn as_base(&self) -> &ffi::MachO_Section;
     151              : 
     152              :     #[doc(hidden)]
     153              :     fn as_mut_base(&mut self) -> Pin<&mut ffi::MachO_Section>;
     154              : 
     155              :     /// Name of the segment that owns this section
     156       304643 :     fn segment_name(&self) -> String {
     157       304643 :         self.as_base().segment_name().to_string()
     158       304643 :     }
     159              : 
     160              :     /// Virtual base address of this section
     161       304642 :     fn address(&self) -> u64 {
     162       304642 :         self.as_base().address()
     163       304642 :     }
     164              : 
     165              :     /// Section alignment as a power of 2
     166       304642 :     fn alignment(&self) -> u32 {
     167       304642 :         self.as_base().alignment()
     168       304642 :     }
     169              : 
     170              :     /// Offset of the relocation table. This value should be 0
     171              :     /// for executable and libraries as the relocations are managed by
     172              :     /// [`crate::macho::Relocation::Dyld`] or [`crate::macho::Relocation::Fixup`]
     173              :     ///
     174              :     /// On the other hand, for object files (`.o`) this value should not be 0 (c.f. [`crate::macho::Relocation::Object`])
     175       304642 :     fn relocation_offset(&self) -> u32 {
     176       304642 :         self.as_base().relocation_offset()
     177       304642 :     }
     178              : 
     179              :     /// Number of relocations associated with this section
     180       304642 :     fn numberof_relocations(&self) -> u32 {
     181       304642 :         self.as_base().numberof_relocations()
     182       304642 :     }
     183              : 
     184       304642 :     fn raw_flags(&self) -> u32 {
     185       304642 :         self.as_base().raw_flags()
     186       304642 :     }
     187              : 
     188              :     /// Section's flags masked with `SECTION_FLAGS_MASK`
     189       304642 :     fn flags(&self) -> Flags {
     190       304642 :         Flags::from_bits_truncate(self.as_base().flags())
     191       304642 :     }
     192              : 
     193              :     /// Type of the section. This value can help to determine the purpose of the section
     194       304657 :     fn section_type(&self) -> Type {
     195       304657 :         Type::from(self.as_base().section_type())
     196       304657 :     }
     197              : 
     198              :     /// According to the official `loader.h` file, this value is reserved
     199              :     /// for *offset* or *index*
     200       304642 :     fn reserved1(&self) -> u32 {
     201       304642 :         self.as_base().reserved1()
     202       304642 :     }
     203              : 
     204              :     /// According to the official `loader.h` file, this value is reserved
     205              :     /// for *count* or *sizeof*
     206       304642 :     fn reserved2(&self) -> u32 {
     207       304642 :         self.as_base().reserved2()
     208       304642 :     }
     209              : 
     210              :     /// This value is only present for 64 bits Mach-O files. In that case,
     211              :     /// the value is *reserved*.
     212       304642 :     fn reserved3(&self) -> u32 {
     213       304642 :         self.as_base().reserved3()
     214       304642 :     }
     215              : 
     216              :     /// Segment bound to this section
     217          317 :     fn segment(&self) -> Option<Segment<'_>> {
     218          317 :         into_optional(self.as_base().segment())
     219          317 :     }
     220              : 
     221              :     /// Iterator over the [`crate::macho::Relocation`] associated with this section
     222          317 :     fn relocations(&self) -> Relocations<'_> {
     223          317 :         Relocations::new(self.as_base().relocations())
     224          317 :     }
     225              : }
     226              : 
     227              : impl MachOSection for Generic<'_> {
     228      4578015 :     fn as_base(&self) -> &ffi::MachO_Section {
     229      4578015 :         self.ptr.as_ref().unwrap()
     230      4578015 :     }
     231              : 
     232            0 :     fn as_mut_base(&mut self) -> Pin<&mut ffi::MachO_Section> {
     233            0 :         unsafe {
     234            0 :             Pin::new_unchecked({
     235            0 :                 (self.ptr.as_ref().unwrap() as *const ffi::MachO_Section as *mut ffi::MachO_Section)
     236            0 :                     .as_mut()
     237            0 :                     .unwrap()
     238            0 :             })
     239            0 :         }
     240            0 :     }
     241              : }
     242              : 
     243              : impl MachOSection for Section<'_> {
     244         8450 :     fn as_base(&self) -> &ffi::MachO_Section {
     245         8450 :         match self {
     246         8385 :             Section::Generic(s) => s.as_base(),
     247           65 :             Section::ThreadLocalVariables(s) => s.as_base(),
     248              :         }
     249         8450 :     }
     250              : 
     251            0 :     fn as_mut_base(&mut self) -> Pin<&mut ffi::MachO_Section> {
     252            0 :         match self {
     253            0 :             Section::Generic(s) => s.as_mut_base(),
     254            0 :             Section::ThreadLocalVariables(s) => s.as_mut_base(),
     255              :         }
     256            0 :     }
     257              : }
     258              : 
     259              : impl fmt::Debug for Generic<'_> {
     260       304642 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     261       304642 :         let base = self as &dyn generic::Section;
     262       304642 :         f.debug_struct("Generic")
     263       304642 :             .field("base", &base)
     264       304642 :             .field("segment_name", &MachOSection::segment_name(self))
     265       304642 :             .field("address", &MachOSection::address(self))
     266       304642 :             .field("alignment", &MachOSection::alignment(self))
     267       304642 :             .field("relocation_offset", &MachOSection::relocation_offset(self))
     268       304642 :             .field(
     269       304642 :                 "numberof_relocations",
     270       304642 :                 &MachOSection::numberof_relocations(self),
     271       304642 :             )
     272       304642 :             .field("raw_flags", &MachOSection::raw_flags(self))
     273       304642 :             .field("flags", &MachOSection::flags(self))
     274       304642 :             .field("type", &MachOSection::section_type(self))
     275       304642 :             .field("reserved1", &MachOSection::reserved1(self))
     276       304642 :             .field("reserved2", &MachOSection::reserved2(self))
     277       304642 :             .field("reserved3", &MachOSection::reserved3(self))
     278       304642 :             .finish()
     279       304642 :     }
     280              : }
     281              : 
     282              : impl<'a> FromFFI<ffi::MachO_Section> for Generic<'a> {
     283       304811 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Section>) -> Self {
     284       304811 :         Self {
     285       304811 :             ptr,
     286       304811 :             _owner: PhantomData,
     287       304811 :         }
     288       304811 :     }
     289              : }
     290              : 
     291              : impl<'a> FromFFI<ffi::MachO_Section> for Section<'a> {
     292       304850 :     fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Section>) -> Self {
     293       304850 :         unsafe {
     294       304850 :             let sec_ref = ffi_entry.as_ref().unwrap();
     295       304850 :             if ffi::MachO_ThreadLocalVariables::classof(sec_ref) {
     296           39 :                 let raw = {
     297           39 :                     type From = cxx::UniquePtr<ffi::MachO_Section>;
     298           39 :                     type To = cxx::UniquePtr<ffi::MachO_ThreadLocalVariables>;
     299           39 :                     std::mem::transmute::<From, To>(ffi_entry)
     300           39 :                 };
     301           39 :                 Section::ThreadLocalVariables(ThreadLocalVariables::from_ffi(raw))
     302              :             } else {
     303       304811 :                 Section::Generic(Generic::from_ffi(ffi_entry))
     304              :             }
     305              :         }
     306       304850 :     }
     307              : }
     308              : 
     309              : impl generic::Section for Generic<'_> {
     310      1218568 :     fn as_generic(&self) -> &ffi::AbstractSection {
     311      1218568 :         self.as_base().as_ref()
     312      1218568 :     }
     313              : 
     314            0 :     fn as_generic_mut(&mut self) -> Pin<&mut ffi::AbstractSection> {
     315            0 :         unsafe {
     316            0 :             Pin::new_unchecked({
     317            0 :                 (self.as_generic() as *const ffi::AbstractSection as *mut ffi::AbstractSection)
     318            0 :                     .as_mut()
     319            0 :                     .unwrap()
     320            0 :             })
     321            0 :         }
     322            0 :     }
     323              : }
     324              : 
     325              : impl generic::Section for Section<'_> {
     326           13 :     fn as_generic(&self) -> &ffi::AbstractSection {
     327           13 :         match self {
     328            0 :             Section::Generic(s) => s.as_generic(),
     329           13 :             Section::ThreadLocalVariables(s) => s.as_generic(),
     330              :         }
     331           13 :     }
     332              : 
     333            0 :     fn as_generic_mut(&mut self) -> Pin<&mut ffi::AbstractSection> {
     334            0 :         match self {
     335            0 :             Section::Generic(s) => s.as_generic_mut(),
     336            0 :             Section::ThreadLocalVariables(s) => s.as_generic_mut(),
     337              :         }
     338            0 :     }
     339              : }
     340              : 
     341         4303 : declare_iterator!(
     342         4303 :     Sections,
     343         4303 :     Section<'a>,
     344         4303 :     ffi::MachO_Section,
     345         4303 :     ffi::MachO_Binary,
     346         4303 :     ffi::MachO_Binary_it_sections
     347         4303 : );
     348        14976 : declare_iterator!(
     349        14976 :     Relocations,
     350        14976 :     Relocation<'a>,
     351        14976 :     ffi::MachO_Relocation,
     352        14976 :     ffi::MachO_Section,
     353        14976 :     ffi::MachO_Section_it_relocations
     354        14976 : );
        

Generated by: LCOV version 2.1-1