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 333204 : #[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 77340 : fn library(&self) -> Option<Dylib> {
33 77340 : into_optional(self.as_generic().library())
34 77340 : }
35 :
36 : /// Symbol associated with the binding (if any)
37 77340 : fn symbol(&self) -> Option<Symbol> {
38 77340 : into_optional(self.as_generic().symbol())
39 77340 : }
40 :
41 : /// Segment associated with the binding (if any)
42 77340 : fn segment(&self) -> Option<Segment> {
43 77340 : into_optional(self.as_generic().segment())
44 77340 : }
45 :
46 : /// Address of the binding
47 333816 : fn address(&self) -> u64 {
48 333816 : self.as_generic().address()
49 333816 : }
50 :
51 : /// Value added to the segment's virtual address when bound
52 333816 : fn addend(&self) -> i64 {
53 333816 : self.as_generic().addend()
54 333816 : }
55 :
56 333816 : fn library_ordinal(&self) -> i32 {
57 333816 : self.as_generic().library_ordinal()
58 333816 : }
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) => {
66 0 : info.as_generic()
67 : }
68 0 : BindingInfo::Chained(info) => {
69 0 : info.as_generic()
70 : }
71 0 : BindingInfo::Indirect(info) => {
72 0 : info.as_generic()
73 : }
74 0 : BindingInfo::Generic(info) => {
75 0 : info.as_generic()
76 : }
77 : }
78 0 : }
79 : }
80 :
81 : impl std::fmt::Debug for &dyn AsGeneric {
82 333816 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 333816 : f.debug_struct("AsGeneric")
84 333816 : .field("address", &self.address())
85 333816 : .field("addend", &self.addend())
86 333816 : .field("library_ordinal", &self.library_ordinal())
87 333816 : .finish()
88 333816 : }
89 : }
90 :
91 : impl<'a> FromFFI<ffi::MachO_BindingInfo> for BindingInfo<'a> {
92 178524 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_BindingInfo>) -> Self {
93 178524 : unsafe {
94 178524 : let cmd_ref = ffi_entry.as_ref().unwrap();
95 178524 :
96 178524 : if ffi::MachO_ChainedBindingInfo::classof(cmd_ref) {
97 1212 : let raw = {
98 1212 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
99 1212 : type To = cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>;
100 1212 : std::mem::transmute::<From, To>(ffi_entry)
101 1212 : };
102 1212 : BindingInfo::Chained(Chained::from_ffi(raw))
103 177312 : } else if ffi::MachO_DyldBindingInfo::classof(cmd_ref) {
104 176424 : let raw = {
105 176424 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
106 176424 : type To = cxx::UniquePtr<ffi::MachO_DyldBindingInfo>;
107 176424 : std::mem::transmute::<From, To>(ffi_entry)
108 176424 : };
109 176424 : BindingInfo::Dyld(Dyld::from_ffi(raw))
110 888 : } else if ffi::MachO_IndirectBindingInfo::classof(cmd_ref) {
111 888 : let raw = {
112 888 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
113 888 : type To = cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>;
114 888 : std::mem::transmute::<From, To>(ffi_entry)
115 888 : };
116 888 : BindingInfo::Indirect(Indirect::from_ffi(raw))
117 : } else {
118 0 : BindingInfo::Generic(Generic::from_ffi(ffi_entry))
119 : }
120 : }
121 178524 : }
122 : }
123 :
124 : pub struct Generic<'a> {
125 : ptr: cxx::UniquePtr<ffi::MachO_BindingInfo>,
126 : _owner: PhantomData<&'a ()>,
127 : }
128 :
129 : impl fmt::Debug for Generic<'_> {
130 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 0 : let base = self as &dyn AsGeneric;
132 0 : f.debug_struct("Generic").field("base", &base).finish()
133 0 : }
134 : }
135 :
136 : impl<'a> FromFFI<ffi::MachO_BindingInfo> for Generic<'a> {
137 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_BindingInfo>) -> Self {
138 0 : Self {
139 0 : ptr,
140 0 : _owner: PhantomData,
141 0 : }
142 0 : }
143 : }
144 :
145 : impl AsGeneric for Generic<'_> {
146 0 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
147 0 : self.ptr.as_ref().unwrap()
148 0 : }
149 : }
150 :
151 : /// This structure represents a binding operation coming from binding bytecode
152 : /// of `LC_DYLD_INFO`
153 : pub struct Dyld<'a> {
154 : ptr: cxx::UniquePtr<ffi::MachO_DyldBindingInfo>,
155 : _owner: PhantomData<&'a ()>,
156 : }
157 :
158 : #[allow(non_camel_case_types)]
159 331104 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
160 : pub enum BINDING_CLASS {
161 : WEAK,
162 : LAZY,
163 : STANDARD,
164 : THREADED,
165 : UNKNOWN(u64),
166 : }
167 :
168 : impl BINDING_CLASS {
169 331104 : pub fn from_value(value: u64) -> Self {
170 331104 : match value {
171 1656 : 0x00000001 => BINDING_CLASS::WEAK,
172 85752 : 0x00000002 => BINDING_CLASS::LAZY,
173 243696 : 0x00000003 => BINDING_CLASS::STANDARD,
174 0 : 0x00000064 => BINDING_CLASS::THREADED,
175 0 : _ => BINDING_CLASS::UNKNOWN(value),
176 : }
177 331104 : }
178 : }
179 :
180 : #[allow(non_camel_case_types)]
181 331104 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
182 : pub enum BIND_TYPES {
183 : POINTER,
184 : TEXT_ABSOLUTE32,
185 : TEXT_PCREL32,
186 : UNKNOWN(u64),
187 : }
188 :
189 : impl BIND_TYPES {
190 331104 : pub fn from_value(value: u64) -> Self {
191 331104 : match value {
192 331104 : 0x00000001 => BIND_TYPES::POINTER,
193 0 : 0x00000002 => BIND_TYPES::TEXT_ABSOLUTE32,
194 0 : 0x00000003 => BIND_TYPES::TEXT_PCREL32,
195 0 : _ => BIND_TYPES::UNKNOWN(value),
196 : }
197 331104 : }
198 : }
199 :
200 : impl Dyld<'_> {
201 : /// Class of the binding (weak, lazy, ...)
202 331104 : pub fn binding_class(&self) -> BINDING_CLASS {
203 331104 : BINDING_CLASS::from_value(self.ptr.binding_class())
204 331104 : }
205 :
206 : /// Type of the binding. Most of the times it should be [`BIND_TYPES::POINTER`]
207 331104 : pub fn binding_type(&self) -> BIND_TYPES {
208 331104 : BIND_TYPES::from_value(self.ptr.binding_type())
209 331104 : }
210 :
211 331104 : pub fn is_non_weak_definition(&self) -> bool {
212 331104 : self.ptr.is_non_weak_definition()
213 331104 : }
214 :
215 331104 : pub fn original_offset(&self) -> u64 {
216 331104 : self.ptr.original_offset()
217 331104 : }
218 : }
219 :
220 : impl fmt::Debug for Dyld<'_> {
221 331104 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 331104 : let base = self as &dyn AsGeneric;
223 331104 : f.debug_struct("Dyld")
224 331104 : .field("base", &base)
225 331104 : .field("binding_class", &self.binding_class())
226 331104 : .field("binding_type", &self.binding_type())
227 331104 : .field("is_non_weak_definition", &self.is_non_weak_definition())
228 331104 : .field("original_offset", &self.original_offset())
229 331104 : .finish()
230 331104 : }
231 : }
232 :
233 : impl FromFFI<ffi::MachO_DyldBindingInfo> for Dyld<'_> {
234 253764 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_DyldBindingInfo>) -> Self {
235 253764 : Self {
236 253764 : ptr,
237 253764 : _owner: PhantomData,
238 253764 : }
239 253764 : }
240 : }
241 :
242 : impl AsGeneric for Dyld<'_> {
243 1225332 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
244 1225332 : self.ptr.as_ref().unwrap().as_ref()
245 1225332 : }
246 : }
247 : /// This structure represents a binding operation coming from chained binding command:
248 : /// `LC_DYLD_CHAINED_FIXUPS`
249 : pub struct Chained<'a> {
250 : ptr: cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>,
251 : _owner: PhantomData<&'a ()>,
252 : }
253 :
254 : #[allow(non_camel_case_types)]
255 1896 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
256 : pub enum CHAINED_FORMAT {
257 : IMPORT,
258 : IMPORT_ADDEND,
259 : IMPORT_ADDEND64,
260 : UNKNOWN(u32),
261 : }
262 :
263 : impl CHAINED_FORMAT {
264 1896 : pub fn from_value(value: u32) -> Self {
265 1896 : match value {
266 1896 : 0x00000001 => CHAINED_FORMAT::IMPORT,
267 0 : 0x00000002 => CHAINED_FORMAT::IMPORT_ADDEND,
268 0 : 0x00000003 => CHAINED_FORMAT::IMPORT_ADDEND64,
269 0 : _ => CHAINED_FORMAT::UNKNOWN(value),
270 : }
271 1896 : }
272 : }
273 :
274 : impl Chained<'_> {
275 : /// Format of the imports
276 1824 : pub fn format(&self) -> CHAINED_FORMAT {
277 1824 : CHAINED_FORMAT::from_value(self.ptr.format())
278 1824 : }
279 :
280 : /// Format of the pointer
281 1824 : pub fn ptr_format(&self) -> u32 {
282 1824 : self.ptr.ptr_format()
283 1824 : }
284 :
285 : /// Original offset in the chain of this binding
286 1824 : pub fn offset(&self) -> u32 {
287 1824 : self.ptr.offset()
288 1824 : }
289 : }
290 :
291 : impl fmt::Debug for Chained<'_> {
292 1824 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 1824 : let base = self as &dyn AsGeneric;
294 1824 : f.debug_struct("Chained")
295 1824 : .field("base", &base)
296 1824 : .field("format", &self.format())
297 1824 : .field("ptr_format", &self.ptr_format())
298 1824 : .field("offset", &self.offset())
299 1824 : .finish()
300 1824 : }
301 : }
302 :
303 : impl FromFFI<ffi::MachO_ChainedBindingInfo> for Chained<'_> {
304 1824 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>) -> Self {
305 1824 : Self {
306 1824 : ptr,
307 1824 : _owner: PhantomData,
308 1824 : }
309 1824 : }
310 : }
311 :
312 : impl AsGeneric for Chained<'_> {
313 5472 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
314 5472 : self.ptr.as_ref().unwrap().as_ref()
315 5472 : }
316 : }
317 :
318 : /// This structure represents a binding operation coming from the indirect symbol table
319 : pub struct Indirect<'a> {
320 : ptr: cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>,
321 : _owner: PhantomData<&'a ()>,
322 : }
323 :
324 : impl fmt::Debug for Indirect<'_> {
325 888 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 888 : let base = self as &dyn AsGeneric;
327 888 : f.debug_struct("Indirect")
328 888 : .field("base", &base)
329 888 : .finish()
330 888 : }
331 : }
332 :
333 : impl FromFFI<ffi::MachO_IndirectBindingInfo> for Indirect<'_> {
334 888 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>) -> Self {
335 888 : Self {
336 888 : ptr,
337 888 : _owner: PhantomData,
338 888 : }
339 888 : }
340 : }
341 :
342 : impl AsGeneric for Indirect<'_> {
343 2664 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
344 2664 : self.ptr.as_ref().unwrap().as_ref()
345 2664 : }
346 : }
347 :
348 :
|