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 296426 : #[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 296426 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
30 296426 : unsafe {
31 296426 : let cmd_ref = ffi_entry.as_ref().unwrap();
32 296426 :
33 296426 : if ffi::MachO_RelocationDyld::classof(cmd_ref) {
34 237224 : let raw = {
35 237224 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
36 237224 : type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
37 237224 : std::mem::transmute::<From, To>(ffi_entry)
38 237224 : };
39 237224 : Relocation::Dyld(Dyld::from_ffi(raw))
40 59202 : } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
41 32812 : let raw = {
42 32812 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
43 32812 : type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
44 32812 : std::mem::transmute::<From, To>(ffi_entry)
45 32812 : };
46 32812 : Relocation::Fixup(Fixup::from_ffi(raw))
47 26390 : } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
48 26390 : let raw = {
49 26390 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
50 26390 : type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
51 26390 : std::mem::transmute::<From, To>(ffi_entry)
52 26390 : };
53 26390 : Relocation::Object(Object::from_ffi(raw))
54 : } else {
55 0 : Relocation::Generic(Generic::from_ffi(ffi_entry))
56 : }
57 : }
58 296426 : }
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 296426 : fn is_pc_relative(&self) -> bool {
72 296426 : self.get_base().is_pc_relative()
73 296426 : }
74 :
75 : /// CPU architecture targeted by this relocation
76 0 : fn architecture(&self) -> u32 {
77 0 : self.get_base().architecture()
78 0 : }
79 :
80 : /// Origin of the relocation
81 0 : fn origin(&self) -> Origin {
82 0 : Origin::from(self.get_base().origin())
83 0 : }
84 :
85 : /// Symbol associated with the relocation (if any)
86 296426 : fn symbol(&self) -> Option<Symbol<'_>> {
87 296426 : into_optional(self.get_base().symbol())
88 296426 : }
89 :
90 : /// Section associated with the section (if any)
91 296426 : fn section(&self) -> Option<Section<'_>> {
92 296426 : into_optional(self.get_base().section())
93 296426 : }
94 :
95 : /// Segment command associated with the relocation (if any)
96 296426 : fn segment(&self) -> Option<Segment<'_>> {
97 296426 : into_optional(self.get_base().segment())
98 296426 : }
99 : }
100 :
101 : /// Origin of a Mach-O relocation
102 : #[allow(non_camel_case_types)]
103 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
104 : pub enum Origin {
105 : UNKNOWN,
106 : DYLDINFO,
107 : RELOC_TABLE,
108 : CHAINED_FIXUPS,
109 : }
110 :
111 : impl From<u32> for Origin {
112 0 : fn from(value: u32) -> Self {
113 0 : match value {
114 0 : 0 => Origin::UNKNOWN,
115 0 : 1 => Origin::DYLDINFO,
116 0 : 2 => Origin::RELOC_TABLE,
117 0 : 3 => Origin::CHAINED_FIXUPS,
118 0 : _ => Origin::UNKNOWN,
119 : }
120 0 : }
121 : }
122 :
123 : impl RelocationBase for Relocation<'_> {
124 0 : fn get_base(&self) -> &ffi::MachO_Relocation {
125 0 : match &self {
126 0 : Relocation::Dyld(reloc) => reloc.get_base(),
127 :
128 0 : Relocation::Fixup(reloc) => reloc.get_base(),
129 :
130 0 : Relocation::Object(reloc) => reloc.get_base(),
131 :
132 0 : Relocation::Generic(reloc) => reloc.get_base(),
133 : }
134 0 : }
135 : }
136 :
137 : impl generic::Relocation for Relocation<'_> {
138 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
139 0 : match &self {
140 0 : Relocation::Dyld(reloc) => reloc.as_generic(),
141 :
142 0 : Relocation::Fixup(reloc) => reloc.as_generic(),
143 :
144 0 : Relocation::Object(reloc) => reloc.as_generic(),
145 :
146 0 : Relocation::Generic(reloc) => reloc.as_generic(),
147 : }
148 0 : }
149 : }
150 :
151 : impl std::fmt::Debug for &dyn RelocationBase {
152 296426 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 296426 : f.debug_struct("Section")
154 296426 : .field("is_pc_relative", &self.is_pc_relative())
155 296426 : .field("symbol", &self.symbol())
156 296426 : .field("section", &self.section())
157 296426 : .field("segment", &self.segment())
158 296426 : .finish()
159 296426 : }
160 : }
161 :
162 : pub struct Generic<'a> {
163 : ptr: cxx::UniquePtr<ffi::MachO_Relocation>,
164 : _owner: PhantomData<&'a ()>,
165 : }
166 :
167 : impl RelocationBase for Generic<'_> {
168 0 : fn get_base(&self) -> &ffi::MachO_Relocation {
169 0 : self.ptr.as_ref().unwrap()
170 0 : }
171 : }
172 :
173 : impl generic::Relocation for Generic<'_> {
174 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
175 0 : self.ptr.as_ref().unwrap().as_ref()
176 0 : }
177 : }
178 :
179 : impl std::fmt::Debug for Generic<'_> {
180 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 0 : let base = self as &dyn RelocationBase;
182 0 : f.debug_struct("Generic").field("base", &base).finish()
183 0 : }
184 : }
185 :
186 : impl FromFFI<ffi::MachO_Relocation> for Generic<'_> {
187 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
188 0 : Self {
189 0 : ptr,
190 0 : _owner: PhantomData,
191 0 : }
192 0 : }
193 : }
194 :
195 : /// Structure that represents a bytecode rebase operation (from `LC_DYLD_INFO`)
196 : pub struct Dyld<'a> {
197 : ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>,
198 : _owner: PhantomData<&'a ()>,
199 : }
200 :
201 : impl FromFFI<ffi::MachO_RelocationDyld> for Dyld<'_> {
202 237224 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
203 237224 : Self {
204 237224 : ptr,
205 237224 : _owner: PhantomData,
206 237224 : }
207 237224 : }
208 : }
209 :
210 : impl RelocationBase for Dyld<'_> {
211 948896 : fn get_base(&self) -> &ffi::MachO_Relocation {
212 948896 : self.ptr.as_ref().unwrap().as_ref()
213 948896 : }
214 : }
215 :
216 : impl generic::Relocation for Dyld<'_> {
217 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
218 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
219 0 : }
220 : }
221 :
222 : impl std::fmt::Debug for Dyld<'_> {
223 237224 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 237224 : let base = self as &dyn RelocationBase;
225 237224 : f.debug_struct("Dyld").field("base", &base).finish()
226 237224 : }
227 : }
228 :
229 : /// Structure that represents a fixup (i.e. relocation) from the `LC_DYLD_CHAINED_FIXUPS`
230 : /// command
231 : pub struct Fixup<'a> {
232 : ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>,
233 : _owner: PhantomData<&'a ()>,
234 : }
235 :
236 : impl Fixup<'_> {
237 : /// The value that should be set at the address pointed by [`crate::Relocation::address`]
238 : /// if the imagebase chosen by the loader is [`crate::generic::Binary::imagebase`].
239 : /// Otherwise: [`Fixup::target`] - [`crate::generic::Binary::imagebase`] + new_imagebase.
240 32812 : pub fn target(&self) -> u64 {
241 32812 : self.ptr.target()
242 32812 : }
243 32812 : pub fn ptr_format(&self) -> u32 {
244 32812 : self.ptr.ptr_format()
245 32812 : }
246 :
247 : /// The address of this relocation is bound to its offset
248 32812 : pub fn offset(&self) -> u32 {
249 32812 : self.ptr.offset()
250 32812 : }
251 :
252 : /// Return the (unscaled) next offset in the chain
253 16406 : pub fn next(&self) -> u32 {
254 16406 : self.ptr.next()
255 16406 : }
256 : }
257 :
258 : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
259 32812 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
260 32812 : Self {
261 32812 : ptr,
262 32812 : _owner: PhantomData,
263 32812 : }
264 32812 : }
265 : }
266 :
267 : impl RelocationBase for Fixup<'_> {
268 131248 : fn get_base(&self) -> &ffi::MachO_Relocation {
269 131248 : self.ptr.as_ref().unwrap().as_ref()
270 131248 : }
271 : }
272 :
273 : impl generic::Relocation for Fixup<'_> {
274 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
275 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
276 0 : }
277 : }
278 :
279 : impl std::fmt::Debug for Fixup<'_> {
280 32812 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 32812 : let base = self as &dyn RelocationBase;
282 32812 : f.debug_struct("Fixup")
283 32812 : .field("base", &base)
284 32812 : .field("target", &self.target())
285 32812 : .field("ptr_format", &self.ptr_format())
286 32812 : .field("offset", &self.offset())
287 32812 : .finish()
288 32812 : }
289 : }
290 :
291 : /// This structure represents a relocation in a Mach-O object file (`.o`)
292 : pub struct Object<'a> {
293 : ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>,
294 : _owner: PhantomData<&'a ()>,
295 : }
296 :
297 : impl FromFFI<ffi::MachO_RelocationObject> for Object<'_> {
298 26390 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
299 26390 : Self {
300 26390 : ptr,
301 26390 : _owner: PhantomData,
302 26390 : }
303 26390 : }
304 : }
305 :
306 : impl RelocationBase for Object<'_> {
307 105560 : fn get_base(&self) -> &ffi::MachO_Relocation {
308 105560 : self.ptr.as_ref().unwrap().as_ref()
309 105560 : }
310 : }
311 :
312 : impl generic::Relocation for Object<'_> {
313 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
314 0 : self.ptr.as_ref().unwrap().as_ref().as_ref()
315 0 : }
316 : }
317 :
318 : impl std::fmt::Debug for Object<'_> {
319 26390 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 26390 : let base = self as &dyn RelocationBase;
321 26390 : f.debug_struct("Object").field("base", &base).finish()
322 26390 : }
323 : }
324 :
325 146432 : declare_iterator!(
326 146432 : Relocations,
327 146432 : Relocation<'a>,
328 146432 : ffi::MachO_Relocation,
329 146432 : ffi::MachO_Binary,
330 146432 : ffi::MachO_Binary_it_relocations
331 146432 : );
|