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 277650 : #[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 64450 : fn library(&self) -> Option<Dylib> {
33 64450 : into_optional(self.as_generic().library())
34 64450 : }
35 :
36 : /// Symbol associated with the binding (if any)
37 64450 : fn symbol(&self) -> Option<Symbol> {
38 64450 : into_optional(self.as_generic().symbol())
39 64450 : }
40 :
41 : /// Segment associated with the binding (if any)
42 64450 : fn segment(&self) -> Option<Segment> {
43 64450 : into_optional(self.as_generic().segment())
44 64450 : }
45 :
46 : /// Address of the binding
47 278150 : fn address(&self) -> u64 {
48 278150 : self.as_generic().address()
49 278150 : }
50 :
51 : /// Value added to the segment's virtual address when bound
52 278150 : fn addend(&self) -> i64 {
53 278150 : self.as_generic().addend()
54 278150 : }
55 :
56 278150 : fn library_ordinal(&self) -> i32 {
57 278150 : self.as_generic().library_ordinal()
58 278150 : }
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 278150 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 278150 : f.debug_struct("AsGeneric")
84 278150 : .field("address", &self.address())
85 278150 : .field("addend", &self.addend())
86 278150 : .field("library_ordinal", &self.library_ordinal())
87 278150 : .finish()
88 278150 : }
89 : }
90 :
91 : impl<'a> FromFFI<ffi::MachO_BindingInfo> for BindingInfo<'a> {
92 148750 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_BindingInfo>) -> Self {
93 148750 : unsafe {
94 148750 : let cmd_ref = ffi_entry.as_ref().unwrap();
95 148750 :
96 148750 : if ffi::MachO_ChainedBindingInfo::classof(cmd_ref) {
97 990 : let raw = {
98 990 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
99 990 : type To = cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>;
100 990 : std::mem::transmute::<From, To>(ffi_entry)
101 990 : };
102 990 : BindingInfo::Chained(Chained::from_ffi(raw))
103 147760 : } else if ffi::MachO_DyldBindingInfo::classof(cmd_ref) {
104 147020 : let raw = {
105 147020 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
106 147020 : type To = cxx::UniquePtr<ffi::MachO_DyldBindingInfo>;
107 147020 : std::mem::transmute::<From, To>(ffi_entry)
108 147020 : };
109 147020 : BindingInfo::Dyld(Dyld::from_ffi(raw))
110 740 : } else if ffi::MachO_IndirectBindingInfo::classof(cmd_ref) {
111 740 : let raw = {
112 740 : type From = cxx::UniquePtr<ffi::MachO_BindingInfo>;
113 740 : type To = cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>;
114 740 : std::mem::transmute::<From, To>(ffi_entry)
115 740 : };
116 740 : BindingInfo::Indirect(Indirect::from_ffi(raw))
117 : } else {
118 0 : BindingInfo::Generic(Generic::from_ffi(ffi_entry))
119 : }
120 : }
121 148750 : }
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 275920 : #[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 275920 : pub fn from_value(value: u64) -> Self {
170 275920 : match value {
171 1380 : 0x00000001 => BINDING_CLASS::WEAK,
172 71460 : 0x00000002 => BINDING_CLASS::LAZY,
173 203080 : 0x00000003 => BINDING_CLASS::STANDARD,
174 0 : 0x00000064 => BINDING_CLASS::THREADED,
175 0 : _ => BINDING_CLASS::UNKNOWN(value),
176 : }
177 275920 : }
178 : }
179 :
180 : #[allow(non_camel_case_types)]
181 275920 : #[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 275920 : pub fn from_value(value: u64) -> Self {
191 275920 : match value {
192 275920 : 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 275920 : }
198 : }
199 :
200 : impl Dyld<'_> {
201 : /// Class of the binding (weak, lazy, ...)
202 275920 : pub fn binding_class(&self) -> BINDING_CLASS {
203 275920 : BINDING_CLASS::from_value(self.ptr.binding_class())
204 275920 : }
205 :
206 : /// Type of the binding. Most of the times it should be [`BIND_TYPES::POINTER`]
207 275920 : pub fn binding_type(&self) -> BIND_TYPES {
208 275920 : BIND_TYPES::from_value(self.ptr.binding_type())
209 275920 : }
210 :
211 275920 : pub fn is_non_weak_definition(&self) -> bool {
212 275920 : self.ptr.is_non_weak_definition()
213 275920 : }
214 :
215 275920 : pub fn original_offset(&self) -> u64 {
216 275920 : self.ptr.original_offset()
217 275920 : }
218 : }
219 :
220 : impl fmt::Debug for Dyld<'_> {
221 275920 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 275920 : let base = self as &dyn AsGeneric;
223 275920 : f.debug_struct("Dyld")
224 275920 : .field("base", &base)
225 275920 : .field("binding_class", &self.binding_class())
226 275920 : .field("binding_type", &self.binding_type())
227 275920 : .field("is_non_weak_definition", &self.is_non_weak_definition())
228 275920 : .field("original_offset", &self.original_offset())
229 275920 : .finish()
230 275920 : }
231 : }
232 :
233 : impl FromFFI<ffi::MachO_DyldBindingInfo> for Dyld<'_> {
234 211470 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_DyldBindingInfo>) -> Self {
235 211470 : Self {
236 211470 : ptr,
237 211470 : _owner: PhantomData,
238 211470 : }
239 211470 : }
240 : }
241 :
242 : impl AsGeneric for Dyld<'_> {
243 1021110 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
244 1021110 : self.ptr.as_ref().unwrap().as_ref()
245 1021110 : }
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 1530 : #[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 1530 : pub fn from_value(value: u32) -> Self {
265 1530 : match value {
266 1530 : 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 1530 : }
272 : }
273 :
274 : impl Chained<'_> {
275 : /// Format of the imports
276 1490 : pub fn format(&self) -> CHAINED_FORMAT {
277 1490 : CHAINED_FORMAT::from_value(self.ptr.format())
278 1490 : }
279 :
280 : /// Format of the pointer
281 1490 : pub fn ptr_format(&self) -> u32 {
282 1490 : self.ptr.ptr_format()
283 1490 : }
284 :
285 : /// Original offset in the chain of this binding
286 1490 : pub fn offset(&self) -> u32 {
287 1490 : self.ptr.offset()
288 1490 : }
289 : }
290 :
291 : impl fmt::Debug for Chained<'_> {
292 1490 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 1490 : let base = self as &dyn AsGeneric;
294 1490 : f.debug_struct("Chained")
295 1490 : .field("base", &base)
296 1490 : .field("format", &self.format())
297 1490 : .field("ptr_format", &self.ptr_format())
298 1490 : .field("offset", &self.offset())
299 1490 : .finish()
300 1490 : }
301 : }
302 :
303 : impl FromFFI<ffi::MachO_ChainedBindingInfo> for Chained<'_> {
304 1490 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_ChainedBindingInfo>) -> Self {
305 1490 : Self {
306 1490 : ptr,
307 1490 : _owner: PhantomData,
308 1490 : }
309 1490 : }
310 : }
311 :
312 : impl AsGeneric for Chained<'_> {
313 4470 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
314 4470 : self.ptr.as_ref().unwrap().as_ref()
315 4470 : }
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 740 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 740 : let base = self as &dyn AsGeneric;
327 740 : f.debug_struct("Indirect")
328 740 : .field("base", &base)
329 740 : .finish()
330 740 : }
331 : }
332 :
333 : impl FromFFI<ffi::MachO_IndirectBindingInfo> for Indirect<'_> {
334 740 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_IndirectBindingInfo>) -> Self {
335 740 : Self {
336 740 : ptr,
337 740 : _owner: PhantomData,
338 740 : }
339 740 : }
340 : }
341 :
342 : impl AsGeneric for Indirect<'_> {
343 2220 : fn as_generic(&self) -> &ffi::MachO_BindingInfo {
344 2220 : self.ptr.as_ref().unwrap().as_ref()
345 2220 : }
346 : }
347 :
348 :
|