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 166128 : #[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 166128 : fn from_ffi(ffi_entry: cxx::UniquePtr<ffi::MachO_Relocation>) -> Self {
30 166128 : unsafe {
31 166128 : let cmd_ref = ffi_entry.as_ref().unwrap();
32 166128 :
33 166128 : if ffi::MachO_RelocationDyld::classof(cmd_ref) {
34 129696 : let raw = {
35 129696 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
36 129696 : type To = cxx::UniquePtr<ffi::MachO_RelocationDyld>;
37 129696 : std::mem::transmute::<From, To>(ffi_entry)
38 129696 : };
39 129696 : Relocation::Dyld(Dyld::from_ffi(raw))
40 36432 : } else if ffi::MachO_RelocationFixup::classof(cmd_ref) {
41 20192 : let raw = {
42 20192 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
43 20192 : type To = cxx::UniquePtr<ffi::MachO_RelocationFixup>;
44 20192 : std::mem::transmute::<From, To>(ffi_entry)
45 20192 : };
46 20192 : Relocation::Fixup(Fixup::from_ffi(raw))
47 16240 : } else if ffi::MachO_RelocationObject::classof(cmd_ref) {
48 16240 : let raw = {
49 16240 : type From = cxx::UniquePtr<ffi::MachO_Relocation>;
50 16240 : type To = cxx::UniquePtr<ffi::MachO_RelocationObject>;
51 16240 : std::mem::transmute::<From, To>(ffi_entry)
52 16240 : };
53 16240 : Relocation::Object(Object::from_ffi(raw))
54 : } else {
55 0 : Relocation::Generic(Generic::from_ffi(ffi_entry))
56 : }
57 : }
58 166128 : }
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 166128 : fn is_pc_relative(&self) -> bool {
72 166128 : self.get_base().is_pc_relative()
73 166128 : }
74 :
75 : /// Symbol associated with the relocation (if any)
76 166128 : fn symbol(&self) -> Option<Symbol> {
77 166128 : into_optional(self.get_base().symbol())
78 166128 : }
79 :
80 : /// Section associated with the section (if any)
81 166128 : fn section(&self) -> Option<Section> {
82 166128 : into_optional(self.get_base().section())
83 166128 : }
84 :
85 : /// Segment command associated with the relocation (if any)
86 166128 : fn segment(&self) -> Option<Segment> {
87 166128 : into_optional(self.get_base().segment())
88 166128 : }
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 166128 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 166128 : f.debug_struct("Section")
116 166128 : .field("is_pc_relative", &self.is_pc_relative())
117 166128 : .field("symbol", &self.symbol())
118 166128 : .field("section", &self.section())
119 166128 : .field("segment", &self.segment())
120 166128 : .finish()
121 166128 : }
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 129696 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationDyld>) -> Self {
165 129696 : Self {
166 129696 : ptr,
167 129696 : _owner: PhantomData,
168 129696 : }
169 129696 : }
170 : }
171 :
172 : impl RelocationBase for Dyld<'_> {
173 518784 : fn get_base(&self) -> &ffi::MachO_Relocation {
174 518784 : self.ptr.as_ref().unwrap().as_ref()
175 518784 : }
176 : }
177 :
178 : impl std::fmt::Debug for Dyld<'_> {
179 129696 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 129696 : let base = self as &dyn RelocationBase;
181 129696 : f.debug_struct("Dyld").field("base", &base).finish()
182 129696 : }
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 20192 : pub fn target(&self) -> u64 {
197 20192 : self.ptr.target()
198 20192 : }
199 20192 : pub fn ptr_format(&self) -> u32 {
200 20192 : self.ptr.ptr_format()
201 20192 : }
202 :
203 : /// The address of this relocation is bound to its offset
204 20192 : pub fn offset(&self) -> u32 {
205 20192 : self.ptr.offset()
206 20192 : }
207 :
208 : /// Return the (unscaled) next offset in the chain
209 10096 : pub fn next(&self) -> u32 {
210 10096 : self.ptr.next()
211 10096 : }
212 : }
213 :
214 : impl FromFFI<ffi::MachO_RelocationFixup> for Fixup<'_> {
215 20192 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationFixup>) -> Self {
216 20192 : Self {
217 20192 : ptr,
218 20192 : _owner: PhantomData,
219 20192 : }
220 20192 : }
221 : }
222 :
223 : impl RelocationBase for Fixup<'_> {
224 80768 : fn get_base(&self) -> &ffi::MachO_Relocation {
225 80768 : self.ptr.as_ref().unwrap().as_ref()
226 80768 : }
227 : }
228 :
229 : impl std::fmt::Debug for Fixup<'_> {
230 20192 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 20192 : let base = self as &dyn RelocationBase;
232 20192 : f.debug_struct("Fixup")
233 20192 : .field("base", &base)
234 20192 : .field("target", &self.target())
235 20192 : .field("ptr_format", &self.ptr_format())
236 20192 : .field("offset", &self.offset())
237 20192 : .finish()
238 20192 : }
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 16240 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_RelocationObject>) -> Self {
249 16240 : Self {
250 16240 : ptr,
251 16240 : _owner: PhantomData,
252 16240 : }
253 16240 : }
254 : }
255 :
256 : impl RelocationBase for Object<'_> {
257 64960 : fn get_base(&self) -> &ffi::MachO_Relocation {
258 64960 : self.ptr.as_ref().unwrap().as_ref()
259 64960 : }
260 : }
261 :
262 : impl std::fmt::Debug for Object<'_> {
263 16240 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264 16240 : let base = self as &dyn RelocationBase;
265 16240 : f.debug_struct("Object").field("base", &base).finish()
266 16240 : }
267 : }
268 :
269 81968 : declare_iterator!(
270 81968 : Relocations,
271 81968 : Relocation<'a>,
272 81968 : ffi::MachO_Relocation,
273 81968 : ffi::MachO_Binary,
274 81968 : ffi::MachO_Binary_it_relocations
275 81968 : );
|