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