Line data Source code
1 : use std::marker::PhantomData;
2 :
3 : use super::commands::segment::Segment;
4 : use super::section::Section;
5 : use super::symbol::Symbol;
6 : use crate::common::{into_optional, FromFFI};
7 : use crate::declare_iterator;
8 : use crate::generic;
9 : use lief_ffi as ffi;
10 :
11 249192 : #[derive(Debug)]
12 : /// Enum that represents the different to encode/represent a relocation
13 : /// in a Mach-O file
14 : pub enum Relocation<'a> {
15 : /// Relocation encoded in the rebase bytecode of `LC_DYLD_INFO`
16 : Dyld(Dyld<'a>),
17 :
18 : /// Relocation encoded in chained fixup `LC_DYLD_CHAINED_FIXUPS`
19 : Fixup(Fixup<'a>),
20 :
21 : /// Relocation of Mach-O object files (`.o`) wrapped by the sections
22 : Object(Object<'a>),
23 :
24 : /// Fallback structure
25 : Generic(Generic<'a>),
26 : }
27 :
28 : impl<'a> FromFFI<ffi::MachO_Relocation> for Relocation<'a> {
29 249192 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
30 249192 : unsafe {
31 249192 : let cmd_ref = ffi_entry.as_ref().unwrap();
32 249192 :
33 249192 : if ffi::MachO_RelocationDyld::classof(cmd_ref) {
34 194544 : let raw = {
35 194544 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
36 194544 : type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
37 194544 : std::mem::transmute::<From, To>(ffi_entry)
38 194544 : };
39 194544 : Relocation::Dyld(Dyld::from_ffi(raw))
40 54648 : } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
41 30288 : let raw = {
42 30288 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
43 30288 : type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
44 30288 : std::mem::transmute::<From, To>(ffi_entry)
45 30288 : };
46 30288 : Relocation::Fixup(Fixup::from_ffi(raw))
47 24360 : } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
48 24360 : let raw = {
49 24360 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
50 24360 : type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
51 24360 : std::mem::transmute::<From, To>(ffi_entry)
52 24360 : };
53 24360 : Relocation::Object(Object::from_ffi(raw))
54 : } else {
55 0 : Relocation::Generic(Generic::from_ffi(ffi_entry))
56 : }
57 : }
58 249192 : }
59 : }
60 :
61 : /// Trait shared by **all** the relocations defined in [`Relocation`]
62 : pub trait RelocationBase {
63 : #[doc(hidden)]
64 : fn get_base(&self) -> &ffi::MachO_Relocation;
65 :
66 : /// Indicates whether the item containing the address to be
67 : /// relocated is part of a CPU instruction that uses PC-relative addressing.
68 : ///
69 : /// For addresses contained in PC-relative instructions, the CPU adds the address of
70 : /// the instruction to the address contained in the instruction.
71 249192 : fn is_pc_relative(&self) -> bool {
72 249192 : self.get_base().is_pc_relative()
73 249192 : }
74 :
75 : /// Symbol associated with the relocation (if any)
76 249192 : fn symbol(&self) -> Option<Symbol> {
77 249192 : into_optional(self.get_base().symbol())
78 249192 : }
79 :
80 : /// Section associated with the section (if any)
81 249192 : fn section(&self) -> Option<Section> {
82 249192 : into_optional(self.get_base().section())
83 249192 : }
84 :
85 : /// Segment command associated with the relocation (if any)
86 249192 : fn segment(&self) -> Option<Segment> {
87 249192 : into_optional(self.get_base().segment())
88 249192 : }
89 : }
90 :
91 : impl RelocationBase for Relocation<'_> {
92 0 : fn get_base(&self) -> &ffi::MachO_Relocation {
93 0 : match &self {
94 0 : Relocation::Dyld(reloc) => {
95 0 : reloc.get_base()
96 : }
97 :
98 0 : Relocation::Fixup(reloc) => {
99 0 : reloc.get_base()
100 : }
101 :
102 0 : Relocation::Object(reloc) => {
103 0 : reloc.get_base()
104 : }
105 :
106 0 : Relocation::Generic(reloc) => {
107 0 : reloc.get_base()
108 : }
109 : }
110 0 : }
111 : }
112 :
113 : impl generic::Relocation for Relocation<'_> {
114 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
115 0 : match &self {
116 0 : Relocation::Dyld(reloc) => {
117 0 : reloc.as_generic()
118 : }
119 :
120 0 : Relocation::Fixup(reloc) => {
121 0 : reloc.as_generic()
122 : }
123 :
124 0 : Relocation::Object(reloc) => {
125 0 : reloc.as_generic()
126 : }
127 :
128 0 : Relocation::Generic(reloc) => {
129 0 : reloc.as_generic()
130 : }
131 : }
132 0 : }
133 : }
134 :
135 :
136 : impl std::fmt::Debug for &dyn RelocationBase {
137 249192 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 249192 : f.debug_struct("Section")
139 249192 : .field("is_pc_relative", &self.is_pc_relative())
140 249192 : .field("symbol", &self.symbol())
141 249192 : .field("section", &self.section())
142 249192 : .field("segment", &self.segment())
143 249192 : .finish()
144 249192 : }
145 : }
146 :
147 : pub struct Generic<'a> {
148 : ptr: cxx::UniquePtr<ffi::MachO_Relocation>,
149 : _owner: PhantomData<&'a ()>,
150 : }
151 :
152 : impl RelocationBase for Generic<'_> {
153 0 : fn get_base(&self) -> &ffi::MachO_Relocation {
154 0 : self.ptr.as_ref().unwrap()
155 0 : }
156 : }
157 :
158 : impl generic::Relocation for Generic<'_> {
159 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
160 0 : self.ptr.as_ref().unwrap().as_ref()
161 0 : }
162 : }
163 :
164 : impl std::fmt::Debug for Generic<'_> {
165 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 0 : let base = self as &dyn RelocationBase;
167 0 : f.debug_struct("Generic").field("base", &base).finish()
168 0 : }
169 : }
170 :
171 : impl FromFFI<ffi::MachO_Relocation> for Generic<'_> {
172 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
173 0 : Self {
174 0 : ptr,
175 0 : _owner: PhantomData,
176 0 : }
177 0 : }
178 : }
179 :
180 : /// Structure that represents a bytecode rebase operation (from `LC_DYLD_INFO`)
181 : pub struct Dyld<'a> {
182 : ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>,
183 : _owner: PhantomData<&'a ()>,
184 : }
185 :
186 : impl FromFFI<ffi::MachO_RelocationDyld> for Dyld<'_> {
187 194544 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
188 194544 : Self {
189 194544 : ptr,
190 194544 : _owner: PhantomData,
191 194544 : }
192 194544 : }
193 : }
194 :
195 : impl RelocationBase for Dyld<'_> {
196 778176 : fn get_base(&self) -> &ffi::MachO_Relocation {
197 778176 : self.ptr.as_ref().unwrap().as_ref()
198 778176 : }
199 : }
200 :
201 :
202 : impl generic::Relocation for Dyld<'_> {
203 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
204 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
205 0 : }
206 : }
207 :
208 : impl std::fmt::Debug for Dyld<'_> {
209 194544 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 194544 : let base = self as &dyn RelocationBase;
211 194544 : f.debug_struct("Dyld").field("base", &base).finish()
212 194544 : }
213 : }
214 :
215 : /// Structure that represents a fixup (i.e. relocation) from the recent from `LC_DYLD_CHAINED_FIXUPS`
216 : /// command
217 : pub struct Fixup<'a> {
218 : ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>,
219 : _owner: PhantomData<&'a ()>,
220 : }
221 :
222 : impl Fixup<'_> {
223 : /// The value that should be set at the address pointed by [`crate::Relocation::address`]
224 : /// if the imagebase chosen by the loader is [`crate::generic::Binary::imagebase`].
225 : /// Otherwise: [`Fixup::target`] - [`crate::generic::Binary::imagebase`] + new_imagebase.
226 30288 : pub fn target(&self) -> u64 {
227 30288 : self.ptr.target()
228 30288 : }
229 30288 : pub fn ptr_format(&self) -> u32 {
230 30288 : self.ptr.ptr_format()
231 30288 : }
232 :
233 : /// The address of this relocation is bound to its offset
234 30288 : pub fn offset(&self) -> u32 {
235 30288 : self.ptr.offset()
236 30288 : }
237 :
238 : /// Return the (unscaled) next offset in the chain
239 15144 : pub fn next(&self) -> u32 {
240 15144 : self.ptr.next()
241 15144 : }
242 : }
243 :
244 : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
245 30288 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
246 30288 : Self {
247 30288 : ptr,
248 30288 : _owner: PhantomData,
249 30288 : }
250 30288 : }
251 : }
252 :
253 : impl RelocationBase for Fixup<'_> {
254 121152 : fn get_base(&self) -> &ffi::MachO_Relocation {
255 121152 : self.ptr.as_ref().unwrap().as_ref()
256 121152 : }
257 : }
258 :
259 : impl generic::Relocation for Fixup<'_> {
260 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
261 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
262 0 : }
263 : }
264 :
265 : impl std::fmt::Debug for Fixup<'_> {
266 30288 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 30288 : let base = self as &dyn RelocationBase;
268 30288 : f.debug_struct("Fixup")
269 30288 : .field("base", &base)
270 30288 : .field("target", &self.target())
271 30288 : .field("ptr_format", &self.ptr_format())
272 30288 : .field("offset", &self.offset())
273 30288 : .finish()
274 30288 : }
275 : }
276 :
277 : /// This structure represents a relocation in a Mach-O object file (`.o`)
278 : pub struct Object<'a> {
279 : ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>,
280 : _owner: PhantomData<&'a ()>,
281 : }
282 :
283 : impl FromFFI<ffi::MachO_RelocationObject> for Object<'_> {
284 24360 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
285 24360 : Self {
286 24360 : ptr,
287 24360 : _owner: PhantomData,
288 24360 : }
289 24360 : }
290 : }
291 :
292 : impl RelocationBase for Object<'_> {
293 97440 : fn get_base(&self) -> &ffi::MachO_Relocation {
294 97440 : self.ptr.as_ref().unwrap().as_ref()
295 97440 : }
296 : }
297 :
298 : impl generic::Relocation for Object<'_> {
299 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
300 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
301 0 : }
302 : }
303 :
304 : impl std::fmt::Debug for Object<'_> {
305 24360 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 24360 : let base = self as &dyn RelocationBase;
307 24360 : f.debug_struct("Object").field("base", &base).finish()
308 24360 : }
309 : }
310 :
311 122952 : declare_iterator!(
312 122952 : Relocations,
313 122952 : Relocation<'a>,
314 122952 : ffi::MachO_Relocation,
315 122952 : ffi::MachO_Binary,
316 122952 : ffi::MachO_Binary_it_relocations
317 122952 : );
|