LCOV - code coverage report
Current view: top level - src/macho - thread_local_variables.rs (source / functions) Coverage Total Hit
Test: lief.lcov Lines: 66.7 % 78 52
Test Date: 2026-04-12:00:00:00 Functions: 75.0 % 16 12

            Line data    Source code
       1              : use lief_ffi as ffi;
       2              : 
       3              : use crate::common::{into_optional, FromFFI};
       4              : use crate::declare_iterator;
       5              : use crate::generic;
       6              : use crate::macho::section::MachOSection;
       7              : use std::fmt;
       8              : use std::marker::PhantomData;
       9              : use std::pin::Pin;
      10              : 
      11              : /// This class represents a MachO section whose type is
      12              : /// [`crate::macho::section::Type::THREAD_LOCAL_VARIABLES`].
      13              : ///
      14              : /// It contains an array of thread-local variable descriptors ([`Thunk`]) used
      15              : /// by dyld to lazily initialize thread-local storage on first access.
      16              : pub struct ThreadLocalVariables<'a> {
      17              :     ptr: cxx::UniquePtr<ffi::MachO_ThreadLocalVariables>,
      18              :     _owner: PhantomData<&'a ffi::MachO_Binary>,
      19              : }
      20              : 
      21              : impl ThreadLocalVariables<'_> {
      22              :     /// Number of [`Thunk`] descriptors in this section
      23           52 :     pub fn nb_thunks(&self) -> u64 {
      24           52 :         self.ptr.nb_thunks().try_into().unwrap()
      25           52 :     }
      26              : 
      27              :     /// Iterator over the [`Thunk`] descriptors stored in this section
      28           13 :     pub fn thunks(&self) -> Thunks<'_> {
      29           13 :         Thunks::new(self.ptr.thunks())
      30           13 :     }
      31              : 
      32              :     /// Return the [`Thunk`] at the given index, or `None` if out of range.
      33            0 :     pub fn get(&self, idx: u64) -> Option<Thunk<'_>> {
      34            0 :         into_optional(self.ptr.get_thunk(idx))
      35            0 :     }
      36              : 
      37              :     /// Change the [`Thunk`] at the given index.
      38            0 :     pub fn set(&mut self, idx: u64, thunk: &Thunk<'_>) {
      39            0 :         self.ptr
      40            0 :             .pin_mut()
      41            0 :             .set_thunk(idx, thunk.func(), thunk.key(), thunk.offset());
      42            0 :     }
      43              : }
      44              : 
      45              : impl fmt::Debug for ThreadLocalVariables<'_> {
      46           39 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      47           39 :         f.debug_struct("ThreadLocalVariables")
      48           39 :             .field("nb_thunks", &self.nb_thunks())
      49           39 :             .finish()
      50           39 :     }
      51              : }
      52              : 
      53              : impl<'a> FromFFI<ffi::MachO_ThreadLocalVariables> for ThreadLocalVariables<'a> {
      54           39 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_ThreadLocalVariables>) -> Self {
      55           39 :         Self {
      56           39 :             ptr,
      57           39 :             _owner: PhantomData,
      58           39 :         }
      59           39 :     }
      60              : }
      61              : 
      62              : impl generic::Section for ThreadLocalVariables<'_> {
      63           13 :     fn as_generic(&self) -> &ffi::AbstractSection {
      64           13 :         self.as_base().as_ref()
      65           13 :     }
      66              : 
      67            0 :     fn as_generic_mut(&mut self) -> Pin<&mut ffi::AbstractSection> {
      68            0 :         unsafe {
      69            0 :             Pin::new_unchecked({
      70            0 :                 (self.as_generic() as *const ffi::AbstractSection as *mut ffi::AbstractSection)
      71            0 :                     .as_mut()
      72            0 :                     .unwrap()
      73            0 :             })
      74            0 :         }
      75            0 :     }
      76              : }
      77              : 
      78              : impl MachOSection for ThreadLocalVariables<'_> {
      79           78 :     fn as_base(&self) -> &ffi::MachO_Section {
      80           78 :         self.ptr.as_ref().unwrap().as_ref()
      81           78 :     }
      82              : 
      83            0 :     fn as_mut_base(&mut self) -> Pin<&mut ffi::MachO_Section> {
      84            0 :         unsafe {
      85            0 :             Pin::new_unchecked({
      86            0 :                 (self.as_base() as *const ffi::MachO_Section as *mut ffi::MachO_Section)
      87            0 :                     .as_mut()
      88            0 :                     .unwrap()
      89            0 :             })
      90            0 :         }
      91            0 :     }
      92              : }
      93              : 
      94              : /// Descriptor for a single thread-local variable.
      95              : ///
      96              : /// The layout mirrors the `tlv_descriptor` structure from `<mach-o/loader.h>`.
      97              : pub struct Thunk<'a> {
      98              :     ptr: cxx::UniquePtr<ffi::MachO_ThreadLocalVariables_Thunk>,
      99              :     _owner: PhantomData<&'a ffi::MachO_ThreadLocalVariables>,
     100              : }
     101              : 
     102              : impl Thunk<'_> {
     103              :     /// Address of the initializer function (`tlv_thunk`)
     104           26 :     pub fn func(&self) -> u64 {
     105           26 :         self.ptr.func()
     106           26 :     }
     107              : 
     108              :     /// `pthread_key_t` key used by the runtime
     109           26 :     pub fn key(&self) -> u64 {
     110           26 :         self.ptr.key()
     111           26 :     }
     112              : 
     113              :     /// Offset of the variable in the TLS block
     114           52 :     pub fn offset(&self) -> u64 {
     115           52 :         self.ptr.offset()
     116           52 :     }
     117              : }
     118              : 
     119              : impl fmt::Debug for Thunk<'_> {
     120           26 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     121           26 :         f.debug_struct("Thunk")
     122           26 :             .field("func", &format_args!("{:#x}", self.func()))
     123           26 :             .field("key", &format_args!("{:#x}", self.key()))
     124           26 :             .field("offset", &format_args!("{:#x}", self.offset()))
     125           26 :             .finish()
     126           26 :     }
     127              : }
     128              : 
     129              : impl<'a> FromFFI<ffi::MachO_ThreadLocalVariables_Thunk> for Thunk<'a> {
     130           26 :     fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_ThreadLocalVariables_Thunk>) -> Self {
     131           26 :         Self {
     132           26 :             ptr,
     133           26 :             _owner: PhantomData,
     134           26 :         }
     135           26 :     }
     136              : }
     137              : 
     138           26 : declare_iterator!(
     139           26 :     Thunks,
     140           26 :     Thunk<'a>,
     141           26 :     ffi::MachO_ThreadLocalVariables_Thunk,
     142           26 :     ffi::MachO_ThreadLocalVariables,
     143           26 :     ffi::MachO_ThreadLocalVariables_it_thunks
     144           26 : );
        

Generated by: LCOV version 2.1-1