1use crate::low_level_il::LowLevelILRegularFunction;
2use crate::rc::Guard;
3use crate::string::IntoCStr;
4use crate::{
5 architecture::CoreArchitecture,
6 binary_view::BinaryView,
7 rc::{CoreArrayProvider, CoreArrayProviderInner, Ref, RefCountable},
8 symbol::Symbol,
9};
10use binaryninjacore_sys::*;
11use std::borrow::Borrow;
12use std::mem::MaybeUninit;
13use std::os::raw::c_void;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
16pub enum RelocationType {
17 ELFGlobalRelocationType,
18 ELFCopyRelocationType,
19 ELFJumpSlotRelocationType,
20 StandardRelocationType,
21 IgnoredRelocation,
22 UnhandledRelocation,
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26pub enum RelocationOperand {
27 Operand(usize),
28 AutocoerceExternPtr,
29 NocoerceExternPtr,
30 Invalid,
31}
32
33impl From<BNRelocationType> for RelocationType {
34 fn from(t: BNRelocationType) -> Self {
35 match t {
36 BNRelocationType::ELFGlobalRelocationType => RelocationType::ELFGlobalRelocationType,
37 BNRelocationType::ELFCopyRelocationType => RelocationType::ELFCopyRelocationType,
38 BNRelocationType::ELFJumpSlotRelocationType => {
39 RelocationType::ELFJumpSlotRelocationType
40 }
41 BNRelocationType::StandardRelocationType => RelocationType::StandardRelocationType,
42 BNRelocationType::IgnoredRelocation => RelocationType::IgnoredRelocation,
43 BNRelocationType::UnhandledRelocation => RelocationType::UnhandledRelocation,
44 }
45 }
46}
47
48impl From<RelocationType> for BNRelocationType {
49 fn from(t: RelocationType) -> Self {
50 match t {
51 RelocationType::ELFGlobalRelocationType => BNRelocationType::ELFGlobalRelocationType,
52 RelocationType::ELFCopyRelocationType => BNRelocationType::ELFCopyRelocationType,
53 RelocationType::ELFJumpSlotRelocationType => {
54 BNRelocationType::ELFJumpSlotRelocationType
55 }
56 RelocationType::StandardRelocationType => BNRelocationType::StandardRelocationType,
57 RelocationType::IgnoredRelocation => BNRelocationType::IgnoredRelocation,
58 RelocationType::UnhandledRelocation => BNRelocationType::UnhandledRelocation,
59 }
60 }
61}
62
63impl From<usize> for RelocationOperand {
64 fn from(operand: usize) -> Self {
65 match operand {
66 0xfffffffd => RelocationOperand::AutocoerceExternPtr,
67 0xfffffffe => RelocationOperand::NocoerceExternPtr,
68 0xffffffff => RelocationOperand::Invalid,
69 _ => RelocationOperand::Operand(operand),
70 }
71 }
72}
73
74impl From<RelocationOperand> for usize {
75 fn from(operand: RelocationOperand) -> Self {
76 match operand {
77 RelocationOperand::Operand(operand) => operand,
78 RelocationOperand::AutocoerceExternPtr => 0xfffffffd,
79 RelocationOperand::NocoerceExternPtr => 0xfffffffe,
80 RelocationOperand::Invalid => 0xffffffff,
81 }
82 }
83}
84
85#[derive(Clone, Debug)]
87pub struct RelocationInfo {
88 pub type_: RelocationType,
89 pub pc_relative: bool,
90 pub base_relative: bool,
91 pub base: u64,
92 pub size: usize,
93 pub truncate_size: usize,
94 pub native_type: u64,
95 pub addend: usize,
96 pub has_sign: bool,
97 pub implicit_addend: bool,
98 pub external: bool,
99 pub symbol_index: usize,
100 pub section_index: usize,
101 pub address: u64,
102 pub target: u64,
103 pub data_relocation: bool,
104 relocation_data_cache: [u8; MAX_RELOCATION_SIZE as usize],
105}
106
107impl RelocationInfo {
108 pub fn new() -> Self {
109 RelocationInfo {
110 type_: RelocationType::UnhandledRelocation,
111 pc_relative: false,
112 base_relative: false,
113 base: 0,
114 size: 0,
115 truncate_size: 0,
116 native_type: 0,
117 addend: 0,
118 has_sign: false,
119 implicit_addend: false,
120 external: false,
121 symbol_index: 0,
122 section_index: 0,
123 address: 0,
124 target: 0,
125 data_relocation: false,
126 relocation_data_cache: [0; MAX_RELOCATION_SIZE as usize],
127 }
128 }
129
130 pub(crate) fn from_raw(reloc: &BNRelocationInfo) -> Self {
131 RelocationInfo {
132 type_: reloc.type_.into(),
133 pc_relative: reloc.pcRelative,
134 base_relative: reloc.baseRelative,
135 base: reloc.base,
136 size: reloc.size,
137 truncate_size: reloc.truncateSize,
138 native_type: reloc.nativeType,
139 addend: reloc.addend,
140 has_sign: reloc.hasSign,
141 implicit_addend: reloc.implicitAddend,
142 external: reloc.external,
143 symbol_index: reloc.symbolIndex,
144 section_index: reloc.sectionIndex,
145 address: reloc.address,
146 target: reloc.target,
147 data_relocation: reloc.dataRelocation,
148 relocation_data_cache: reloc.relocationDataCache,
149 }
150 }
151
152 pub(crate) fn as_raw(&self) -> BNRelocationInfo {
153 BNRelocationInfo {
154 type_: self.type_.into(),
155 pcRelative: self.pc_relative,
156 baseRelative: self.base_relative,
157 base: self.base,
158 size: self.size,
159 truncateSize: self.truncate_size,
160 nativeType: self.native_type,
161 addend: self.addend,
162 hasSign: self.has_sign,
163 implicitAddend: self.implicit_addend,
164 external: self.external,
165 symbolIndex: self.symbol_index,
166 sectionIndex: self.section_index,
167 address: self.address,
168 target: self.target,
169 dataRelocation: self.data_relocation,
170 relocationDataCache: self.relocation_data_cache,
171 prev: core::ptr::null_mut(),
173 next: core::ptr::null_mut(),
174 }
175 }
176}
177
178impl Default for RelocationInfo {
179 fn default() -> Self {
180 Self::new()
181 }
182}
183
184pub struct Relocation(*mut BNRelocation);
188
189impl Relocation {
190 pub(crate) unsafe fn from_raw(reloc: *mut BNRelocation) -> Self {
191 Relocation(reloc)
192 }
193
194 pub fn info(&self) -> RelocationInfo {
195 RelocationInfo::from_raw(unsafe { &BNRelocationGetInfo(self.0) })
196 }
197
198 pub fn architecture(&self) -> Option<CoreArchitecture> {
199 let raw = unsafe { BNRelocationGetArchitecture(self.0) };
200 if raw.is_null() {
201 return None;
202 }
203
204 Some(unsafe { CoreArchitecture::from_raw(raw) })
205 }
206
207 pub fn target(&self) -> u64 {
208 unsafe { BNRelocationGetTarget(self.0) }
209 }
210
211 pub fn address(&self) -> u64 {
212 unsafe { BNRelocationGetReloc(self.0) }
213 }
214
215 pub fn symbol(&self) -> Option<Ref<Symbol>> {
216 let raw = unsafe { BNRelocationGetSymbol(self.0) };
217 if raw.is_null() {
218 return None;
219 }
220
221 Some(unsafe { Symbol::ref_from_raw(raw) })
222 }
223}
224
225impl CoreArrayProvider for Relocation {
226 type Raw = *mut BNRelocation;
227 type Context = ();
228 type Wrapped<'a> = Guard<'a, Relocation>;
229}
230
231unsafe impl CoreArrayProviderInner for Relocation {
232 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
233 BNFreeRelocationList(raw, count);
234 }
235
236 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
237 Guard::new(Relocation(*raw), &())
238 }
239}
240
241pub trait RelocationHandler: 'static + Sized + AsRef<CoreRelocationHandler> {
242 type Handle: Borrow<Self>;
243
244 fn get_relocation_info(
245 &self,
246 _bv: &BinaryView,
247 _arch: &CoreArchitecture,
248 _info: &mut [RelocationInfo],
249 ) -> bool {
250 false
251 }
252
253 fn apply_relocation(
254 &self,
255 bv: &BinaryView,
256 arch: &CoreArchitecture,
257 reloc: &Relocation,
258 dest: &mut [u8],
259 ) -> bool {
260 self.default_apply_relocation(bv, arch, reloc, dest)
261 }
262
263 fn get_operand_for_external_relocation(
264 &self,
265 _data: &[u8],
266 _addr: u64,
267 _il: &LowLevelILRegularFunction,
269 _reloc: &Relocation,
270 ) -> RelocationOperand {
271 RelocationOperand::AutocoerceExternPtr
272 }
273
274 fn handle(&self) -> Self::Handle;
275}
276
277pub trait RelocationHandlerExt: RelocationHandler {
278 fn default_apply_relocation(
279 &self,
280 bv: &BinaryView,
281 arch: &CoreArchitecture,
282 reloc: &Relocation,
283 dest: &mut [u8],
284 ) -> bool {
285 unsafe {
286 BNRelocationHandlerDefaultApplyRelocation(
287 self.as_ref().0,
288 bv.handle,
289 arch.handle,
290 reloc.0,
291 dest.as_mut_ptr(),
292 dest.len(),
293 )
294 }
295 }
296}
297
298impl<T: RelocationHandler> RelocationHandlerExt for T {}
299
300#[derive(Eq, PartialEq, Hash, Debug)]
301pub struct CoreRelocationHandler(*mut BNRelocationHandler);
302
303unsafe impl Send for CoreRelocationHandler {}
304unsafe impl Sync for CoreRelocationHandler {}
305
306impl CoreRelocationHandler {
307 pub(crate) unsafe fn ref_from_raw(raw: *mut BNRelocationHandler) -> Ref<Self> {
308 unsafe { Ref::new(CoreRelocationHandler(raw)) }
309 }
310}
311
312impl AsRef<CoreRelocationHandler> for CoreRelocationHandler {
313 fn as_ref(&self) -> &Self {
314 self
315 }
316}
317
318impl RelocationHandler for CoreRelocationHandler {
319 type Handle = Self;
320
321 fn get_relocation_info(
322 &self,
323 bv: &BinaryView,
324 arch: &CoreArchitecture,
325 info: &mut [RelocationInfo],
326 ) -> bool {
327 let mut raw_info = info.iter().map(|i| i.as_raw()).collect::<Vec<_>>();
328 let res = unsafe {
329 BNRelocationHandlerGetRelocationInfo(
330 self.0,
331 bv.handle,
332 arch.handle,
333 raw_info.as_mut_ptr(),
334 raw_info.len(),
335 )
336 };
337 for (info, raw) in info.iter_mut().zip(raw_info.iter()) {
338 *info = RelocationInfo::from_raw(raw);
339 }
340 res
341 }
342
343 fn apply_relocation(
344 &self,
345 bv: &BinaryView,
346 arch: &CoreArchitecture,
347 reloc: &Relocation,
348 dest: &mut [u8],
349 ) -> bool {
350 unsafe {
351 BNRelocationHandlerApplyRelocation(
352 self.0,
353 bv.handle,
354 arch.handle,
355 reloc.0,
356 dest.as_mut_ptr(),
357 dest.len(),
358 )
359 }
360 }
361
362 fn get_operand_for_external_relocation(
363 &self,
364 data: &[u8],
365 addr: u64,
366 il: &LowLevelILRegularFunction,
367 reloc: &Relocation,
368 ) -> RelocationOperand {
369 unsafe {
370 BNRelocationHandlerGetOperandForExternalRelocation(
371 self.0,
372 data.as_ptr(),
373 addr,
374 data.len(),
375 il.handle,
376 reloc.0,
377 )
378 .into()
379 }
380 }
381
382 fn handle(&self) -> CoreRelocationHandler {
383 CoreRelocationHandler(self.0)
384 }
385}
386
387impl ToOwned for CoreRelocationHandler {
388 type Owned = Ref<Self>;
389
390 fn to_owned(&self) -> Self::Owned {
391 unsafe { RefCountable::inc_ref(self) }
392 }
393}
394
395unsafe impl RefCountable for CoreRelocationHandler {
396 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
397 Ref::new(Self(BNNewRelocationHandlerReference(handle.0)))
398 }
399
400 unsafe fn dec_ref(handle: &Self) {
401 BNFreeRelocationHandler(handle.0);
402 }
403}
404
405pub(crate) fn register_relocation_handler<R, F>(arch: &CoreArchitecture, name: &str, func: F)
406where
407 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync + Sized,
408 F: FnOnce(CustomRelocationHandlerHandle<R>, CoreRelocationHandler) -> R,
409{
410 #[repr(C)]
411 struct RelocationHandlerBuilder<R>
412 where
413 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
414 {
415 handler: R,
416 }
417
418 extern "C" fn cb_free<R>(ctxt: *mut c_void)
419 where
420 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
421 {
422 unsafe {
423 let _handler = Box::from_raw(ctxt as *mut RelocationHandlerBuilder<R>);
424 }
425 }
426
427 extern "C" fn cb_get_relocation_info<R>(
428 ctxt: *mut c_void,
429 bv: *mut BNBinaryView,
430 arch: *mut BNArchitecture,
431 result: *mut BNRelocationInfo,
432 count: usize,
433 ) -> bool
434 where
435 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
436 {
437 let custom_handler = unsafe { &*(ctxt as *mut R) };
438 let bv = unsafe { BinaryView::ref_from_raw(BNNewViewReference(bv)) };
439 let arch = unsafe { CoreArchitecture::from_raw(arch) };
440 let result = unsafe { core::slice::from_raw_parts_mut(result, count) };
441 let mut info = result
442 .iter()
443 .map(RelocationInfo::from_raw)
444 .collect::<Vec<_>>();
445 let ok =
446 custom_handler.get_relocation_info(bv.as_ref(), arch.as_ref(), info.as_mut_slice());
447 for (result, info) in result.iter_mut().zip(info.iter()) {
448 *result = info.as_raw();
449 }
450 ok
451 }
452
453 extern "C" fn cb_apply_relocation<R>(
454 ctxt: *mut c_void,
455 bv: *mut BNBinaryView,
456 arch: *mut BNArchitecture,
457 reloc: *mut BNRelocation,
458 dest: *mut u8,
459 len: usize,
460 ) -> bool
461 where
462 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
463 {
464 let custom_handler = unsafe { &*(ctxt as *mut R) };
465 let bv = unsafe { BinaryView::ref_from_raw(BNNewViewReference(bv)) };
466 let arch = unsafe { CoreArchitecture::from_raw(arch) };
467 let reloc = unsafe { Relocation::from_raw(reloc) };
468 let dest = unsafe { core::slice::from_raw_parts_mut(dest, len) };
469 custom_handler.apply_relocation(bv.as_ref(), arch.as_ref(), &reloc, dest)
470 }
471
472 extern "C" fn cb_get_operand_for_external_relocation<R>(
473 ctxt: *mut c_void,
474 data: *const u8,
475 addr: u64,
476 len: usize,
477 il: *mut BNLowLevelILFunction,
478 reloc: *mut BNRelocation,
479 ) -> usize
480 where
481 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
482 {
483 let custom_handler = unsafe { &*(ctxt as *mut R) };
484 let data = unsafe { core::slice::from_raw_parts(data, len) };
485 let reloc = unsafe { Relocation::from_raw(reloc) };
486
487 let func = unsafe { BNGetLowLevelILOwnerFunction(il) };
488 if func.is_null() {
489 return RelocationOperand::Invalid.into();
490 }
491
492 let arch = unsafe { BNGetFunctionArchitecture(func) };
493 unsafe { BNFreeFunction(func) };
494 if arch.is_null() {
495 return RelocationOperand::Invalid.into();
496 }
497 let arch = unsafe { CoreArchitecture::from_raw(arch) };
498 let il = unsafe { LowLevelILRegularFunction::from_raw_with_arch(il, Some(arch)) };
499
500 custom_handler
501 .get_operand_for_external_relocation(data, addr, &il, &reloc)
502 .into()
503 }
504
505 let name = name.to_cstr();
506
507 let raw = Box::leak(Box::new(
508 MaybeUninit::<RelocationHandlerBuilder<_>>::zeroed(),
509 ));
510 let mut custom_handler = BNCustomRelocationHandler {
511 context: raw.as_mut_ptr() as *mut _,
512 freeObject: Some(cb_free::<R>),
513 getRelocationInfo: Some(cb_get_relocation_info::<R>),
514 applyRelocation: Some(cb_apply_relocation::<R>),
515 getOperandForExternalRelocation: Some(cb_get_operand_for_external_relocation::<R>),
516 };
517
518 let handle_raw = unsafe { BNCreateRelocationHandler(&mut custom_handler) };
519 assert!(!handle_raw.is_null());
520 let handle = CoreRelocationHandler(handle_raw);
521 let custom_handle = CustomRelocationHandlerHandle {
522 handle: raw.as_mut_ptr() as *mut R,
523 };
524 unsafe {
525 raw.write(RelocationHandlerBuilder {
526 handler: func(custom_handle, CoreRelocationHandler(handle.0)),
527 });
528
529 BNArchitectureRegisterRelocationHandler(
530 arch.handle,
531 name.as_ref().as_ptr() as *const _,
532 handle.handle().as_ref().0,
533 );
534 }
535}
536
537pub struct CustomRelocationHandlerHandle<R>
538where
539 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync,
540{
541 handle: *mut R,
542}
543
544unsafe impl<R> Send for CustomRelocationHandlerHandle<R> where
545 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync
546{
547}
548
549unsafe impl<R> Sync for CustomRelocationHandlerHandle<R> where
550 R: 'static + RelocationHandler<Handle = CustomRelocationHandlerHandle<R>> + Send + Sync
551{
552}
553
554impl<R> Clone for CustomRelocationHandlerHandle<R>
555where
556 R: 'static + RelocationHandler<Handle = Self> + Send + Sync,
557{
558 fn clone(&self) -> Self {
559 *self
560 }
561}
562
563impl<R> Copy for CustomRelocationHandlerHandle<R> where
564 R: 'static + RelocationHandler<Handle = Self> + Send + Sync
565{
566}
567
568impl<R> Borrow<R> for CustomRelocationHandlerHandle<R>
569where
570 R: 'static + RelocationHandler<Handle = Self> + Send + Sync,
571{
572 fn borrow(&self) -> &R {
573 unsafe { &*self.handle }
574 }
575}