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