binaryninja/
references.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#![allow(dead_code)]
use crate::architecture::CoreArchitecture;
use crate::function::Function;
use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
use binaryninjacore_sys::{BNFreeCodeReferences, BNFreeDataReferences, BNReferenceSource};

/// A struct representing a single code cross-reference.
#[derive(Debug)]
pub struct CodeReference {
    pub arch: Option<CoreArchitecture>,
    pub func: Option<Ref<Function>>,
    pub address: u64,
}

impl CodeReference {
    pub(crate) fn from_raw(value: &BNReferenceSource) -> Self {
        Self {
            func: match value.func.is_null() {
                false => Some(unsafe { Function::from_raw(value.func) }.to_owned()),
                true => None,
            },
            arch: match value.func.is_null() {
                false => Some(unsafe { CoreArchitecture::from_raw(value.arch) }),
                true => None,
            },
            address: value.addr,
        }
    }

    pub(crate) fn from_owned_raw(value: BNReferenceSource) -> Self {
        let owned = Self::from_raw(&value);
        Self::free_raw(value);
        owned
    }

    pub(crate) fn into_raw(value: Self) -> BNReferenceSource {
        BNReferenceSource {
            func: match value.func {
                Some(func) => unsafe { Ref::into_raw(func) }.handle,
                None => std::ptr::null_mut(),
            },
            arch: value.arch.map(|a| a.handle).unwrap_or(std::ptr::null_mut()),
            addr: value.address,
        }
    }

    pub(crate) fn into_owned_raw(value: &Self) -> BNReferenceSource {
        BNReferenceSource {
            func: match &value.func {
                Some(func) => func.handle,
                None => std::ptr::null_mut(),
            },
            arch: value.arch.map(|a| a.handle).unwrap_or(std::ptr::null_mut()),
            addr: value.address,
        }
    }

    pub(crate) fn free_raw(value: BNReferenceSource) {
        let _ = unsafe { Function::ref_from_raw(value.func) };
    }

    pub fn new(address: u64, func: Option<Ref<Function>>, arch: Option<CoreArchitecture>) -> Self {
        Self {
            func,
            arch,
            address,
        }
    }
}

// Code Reference Array<T> boilerplate

impl CoreArrayProvider for CodeReference {
    type Raw = BNReferenceSource;
    type Context = ();
    type Wrapped<'a> = Self;
}

unsafe impl CoreArrayProviderInner for CodeReference {
    unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
        BNFreeCodeReferences(raw, count)
    }

    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
        CodeReference::from_raw(raw)
    }
}

// TODO: This only exists so that Array can free.
// TODO: Is there any way we can have this instead be Array<Location> of some sort?
/// A struct representing a single data cross-reference.
/// Data references have no associated metadata, so this object has only
/// a single [`DataReference::address`] attribute.
pub struct DataReference {
    pub address: u64,
}

impl CoreArrayProvider for DataReference {
    type Raw = u64;
    type Context = ();
    type Wrapped<'a> = DataReference;
}

unsafe impl CoreArrayProviderInner for DataReference {
    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
        BNFreeDataReferences(raw)
    }

    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
        DataReference { address: *raw }
    }
}