binaryninja/architecture/
intrinsic.rs

1use crate::architecture::CoreArchitecture;
2use crate::confidence::Conf;
3use crate::rc::Ref;
4use crate::types::{NameAndType, Type};
5use binaryninjacore_sys::{
6    BNFreeNameAndTypeList, BNFreeOutputTypeList, BNFreeString, BNGetArchitectureIntrinsicClass,
7    BNGetArchitectureIntrinsicInputs, BNGetArchitectureIntrinsicName,
8    BNGetArchitectureIntrinsicOutputs, BNIntrinsicClass,
9};
10use std::borrow::Cow;
11use std::ffi::CStr;
12use std::fmt::{Debug, Formatter};
13
14new_id_type!(IntrinsicId, u32);
15
16pub trait Intrinsic: Debug + Sized + Clone + Copy {
17    fn name(&self) -> Cow<'_, str>;
18
19    /// Unique identifier for this `Intrinsic`.
20    fn id(&self) -> IntrinsicId;
21
22    /// The intrinsic class for this `Intrinsic`.
23    fn class(&self) -> BNIntrinsicClass {
24        BNIntrinsicClass::GeneralIntrinsicClass
25    }
26
27    // TODO: Maybe just return `(String, Conf<Ref<Type>>)`?
28    /// List of the input names and types for this intrinsic.
29    fn inputs(&self) -> Vec<NameAndType>;
30
31    /// List of the output types for this intrinsic.
32    fn outputs(&self) -> Vec<Conf<Ref<Type>>>;
33}
34
35/// Type for architectures that do not use intrinsics. Will panic if accessed as an intrinsic.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub struct UnusedIntrinsic;
38
39impl Intrinsic for UnusedIntrinsic {
40    fn name(&self) -> Cow<'_, str> {
41        unreachable!()
42    }
43    fn id(&self) -> IntrinsicId {
44        unreachable!()
45    }
46    fn inputs(&self) -> Vec<NameAndType> {
47        unreachable!()
48    }
49    fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
50        unreachable!()
51    }
52}
53
54#[derive(Copy, Clone, Eq, PartialEq)]
55pub struct CoreIntrinsic {
56    pub arch: CoreArchitecture,
57    pub id: IntrinsicId,
58}
59
60impl CoreIntrinsic {
61    pub fn new(arch: CoreArchitecture, id: IntrinsicId) -> Option<Self> {
62        let intrinsic = Self { arch, id };
63        intrinsic.is_valid().then_some(intrinsic)
64    }
65
66    fn is_valid(&self) -> bool {
67        // We check the name to see if the intrinsic is actually valid.
68        let name = unsafe { BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()) };
69        match name.is_null() {
70            true => false,
71            false => {
72                unsafe { BNFreeString(name) };
73                true
74            }
75        }
76    }
77}
78
79impl Intrinsic for CoreIntrinsic {
80    fn name(&self) -> Cow<'_, str> {
81        unsafe {
82            let name = BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into());
83
84            // We need to guarantee ownership, as if we're still
85            // a Borrowed variant we're about to free the underlying
86            // memory.
87            // TODO: ^ the above assertion nullifies any benefit to passing back Cow tho?
88            let res = CStr::from_ptr(name);
89            let res = res.to_string_lossy().into_owned().into();
90
91            BNFreeString(name);
92
93            res
94        }
95    }
96
97    fn id(&self) -> IntrinsicId {
98        self.id
99    }
100
101    fn class(&self) -> BNIntrinsicClass {
102        unsafe { BNGetArchitectureIntrinsicClass(self.arch.handle, self.id.into()) }
103    }
104
105    fn inputs(&self) -> Vec<NameAndType> {
106        let mut count: usize = 0;
107        unsafe {
108            let inputs =
109                BNGetArchitectureIntrinsicInputs(self.arch.handle, self.id.into(), &mut count);
110
111            let ret = std::slice::from_raw_parts_mut(inputs, count)
112                .iter()
113                .map(NameAndType::from_raw)
114                .collect();
115
116            BNFreeNameAndTypeList(inputs, count);
117
118            ret
119        }
120    }
121
122    fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
123        let mut count: usize = 0;
124        unsafe {
125            let inputs =
126                BNGetArchitectureIntrinsicOutputs(self.arch.handle, self.id.into(), &mut count);
127
128            let ret = std::slice::from_raw_parts_mut(inputs, count)
129                .iter()
130                .map(Conf::<Ref<Type>>::from_raw)
131                .collect();
132
133            BNFreeOutputTypeList(inputs, count);
134
135            ret
136        }
137    }
138}
139
140impl Debug for CoreIntrinsic {
141    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
142        f.debug_struct("CoreIntrinsic")
143            .field("id", &self.id)
144            .field("name", &self.name())
145            .field("class", &self.class())
146            .field("inputs", &self.inputs())
147            .field("outputs", &self.outputs())
148            .finish()
149    }
150}