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 : );
|