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 207660 : #[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 207660 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
30 207660 : unsafe {
31 207660 : let cmd_ref = ffi_entry.as_ref().unwrap();
32 207660 :
33 207660 : if ffi::MachO_RelocationDyld::classof(cmd_ref) {
34 162120 : let raw = {
35 162120 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
36 162120 : type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
37 162120 : std::mem::transmute::<From, To>(ffi_entry)
38 162120 : };
39 162120 : Relocation::Dyld(Dyld::from_ffi(raw))
40 45540 : } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
41 25240 : let raw = {
42 25240 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
43 25240 : type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
44 25240 : std::mem::transmute::<From, To>(ffi_entry)
45 25240 : };
46 25240 : Relocation::Fixup(Fixup::from_ffi(raw))
47 20300 : } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
48 20300 : let raw = {
49 20300 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
50 20300 : type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
51 20300 : std::mem::transmute::<From, To>(ffi_entry)
52 20300 : };
53 20300 : Relocation::Object(Object::from_ffi(raw))
54 : } else {
55 0 : Relocation::Generic(Generic::from_ffi(ffi_entry))
56 : }
57 : }
58 207660 : }
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 207660 : fn is_pc_relative(&self) -> bool {
72 207660 : self.get_base().is_pc_relative()
73 207660 : }
74 :
75 : /// Symbol associated with the relocation (if any)
76 207660 : fn symbol(&self) -> Option<Symbol> {
77 207660 : into_optional(self.get_base().symbol())
78 207660 : }
79 :
80 : /// Section associated with the section (if any)
81 207660 : fn section(&self) -> Option<Section> {
82 207660 : into_optional(self.get_base().section())
83 207660 : }
84 :
85 : /// Segment command associated with the relocation (if any)
86 207660 : fn segment(&self) -> Option<Segment> {
87 207660 : into_optional(self.get_base().segment())
88 207660 : }
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 std::fmt::Debug for &dyn RelocationBase {
114 207660 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 207660 : f.debug_struct("Section")
116 207660 : .field("is_pc_relative", &self.is_pc_relative())
117 207660 : .field("symbol", &self.symbol())
118 207660 : .field("section", &self.section())
119 207660 : .field("segment", &self.segment())
120 207660 : .finish()
121 207660 : }
122 : }
123 :
124 : pub struct Generic<'a> {
125 : ptr: cxx::UniquePtr<ffi::MachO_Relocation>,
126 : _owner: PhantomData<&'a ()>,
127 : }
128 :
129 : impl RelocationBase for Generic<'_> {
130 0 : fn get_base(&self) -> &ffi::MachO_Relocation {
131 0 : self.ptr.as_ref().unwrap()
132 0 : }
133 : }
134 :
135 : impl generic::Relocation for Generic<'_> {
136 0 : fn as_generic(&self) -> &ffi::AbstractRelocation {
137 0 : self.ptr.as_ref().unwrap().as_ref()
138 0 : }
139 : }
140 :
141 : impl std::fmt::Debug for Generic<'_> {
142 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 0 : let base = self as &dyn RelocationBase;
144 0 : f.debug_struct("Generic").field("base", &base).finish()
145 0 : }
146 : }
147 :
148 : impl FromFFI<ffi::MachO_Relocation> for Generic<'_> {
149 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
150 0 : Self {
151 0 : ptr,
152 0 : _owner: PhantomData,
153 0 : }
154 0 : }
155 : }
156 :
157 : /// Structure that represents a bytecode rebase operation (from `LC_DYLD_INFO`)
158 : pub struct Dyld<'a> {
159 : ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>,
160 : _owner: PhantomData<&'a ()>,
161 : }
162 :
163 : impl FromFFI<ffi::MachO_RelocationDyld> for Dyld<'_> {
164 162120 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
165 162120 : Self {
166 162120 : ptr,
167 162120 : _owner: PhantomData,
168 162120 : }
169 162120 : }
170 : }
171 :
172 : impl RelocationBase for Dyld<'_> {
173 648480 : fn get_base(&self) -> &ffi::MachO_Relocation {
174 648480 : self.ptr.as_ref().unwrap().as_ref()
175 648480 : }
176 : }
177 :
178 : impl std::fmt::Debug for Dyld<'_> {
179 162120 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 162120 : let base = self as &dyn RelocationBase;
181 162120 : f.debug_struct("Dyld").field("base", &base).finish()
182 162120 : }
183 : }
184 :
185 : /// Structure that represents a fixup (i.e. relocation) from the recent from `LC_DYLD_CHAINED_FIXUPS`
186 : /// command
187 : pub struct Fixup<'a> {
188 : ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>,
189 : _owner: PhantomData<&'a ()>,
190 : }
191 :
192 : impl Fixup<'_> {
193 : /// The value that should be set at the address pointed by [`crate::Relocation::address`]
194 : /// if the imagebase chosen by the loader is [`crate::generic::Binary::imagebase`].
195 : /// Otherwise: [`Fixup::target`] - [`crate::generic::Binary::imagebase`] + new_imagebase.
196 25240 : pub fn target(&self) -> u64 {
197 25240 : self.ptr.target()
198 25240 : }
199 25240 : pub fn ptr_format(&self) -> u32 {
200 25240 : self.ptr.ptr_format()
201 25240 : }
202 :
203 : /// The address of this relocation is bound to its offset
204 25240 : pub fn offset(&self) -> u32 {
205 25240 : self.ptr.offset()
206 25240 : }
207 :
208 : /// Return the (unscaled) next offset in the chain
209 12620 : pub fn next(&self) -> u32 {
210 12620 : self.ptr.next()
211 12620 : }
212 : }
213 :
214 : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
215 25240 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
216 25240 : Self {
217 25240 : ptr,
218 25240 : _owner: PhantomData,
219 25240 : }
220 25240 : }
221 : }
222 :
223 : impl RelocationBase for Fixup<'_> {
224 100960 : fn get_base(&self) -> &ffi::MachO_Relocation {
225 100960 : self.ptr.as_ref().unwrap().as_ref()
226 100960 : }
227 : }
228 :
229 : impl std::fmt::Debug for Fixup<'_> {
230 25240 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 25240 : let base = self as &dyn RelocationBase;
232 25240 : f.debug_struct("Fixup")
233 25240 : .field("base", &base)
234 25240 : .field("target", &self.target())
235 25240 : .field("ptr_format", &self.ptr_format())
236 25240 : .field("offset", &self.offset())
237 25240 : .finish()
238 25240 : }
239 : }
240 :
241 : /// This structure represents a relocation in a Mach-O object file (`.o`)
242 : pub struct Object<'a> {
243 : ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>,
244 : _owner: PhantomData<&'a ()>,
245 : }
246 :
247 : impl FromFFI<ffi::MachO_RelocationObject> for Object<'_> {
248 20300 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
249 20300 : Self {
250 20300 : ptr,
251 20300 : _owner: PhantomData,
252 20300 : }
253 20300 : }
254 : }
255 :
256 : impl RelocationBase for Object<'_> {
257 81200 : fn get_base(&self) -> &ffi::MachO_Relocation {
258 81200 : self.ptr.as_ref().unwrap().as_ref()
259 81200 : }
260 : }
261 :
262 : impl std::fmt::Debug for Object<'_> {
263 20300 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264 20300 : let base = self as &dyn RelocationBase;
265 20300 : f.debug_struct("Object").field("base", &base).finish()
266 20300 : }
267 : }
268 :
269 102460 : declare_iterator!(
270 102460 : Relocations,
271 102460 : Relocation<'a>,
272 102460 : ffi::MachO_Relocation,
273 102460 : ffi::MachO_Binary,
274 102460 : ffi::MachO_Binary_it_relocations
275 102460 : );
|