summaryrefslogtreecommitdiff
path: root/rust/src/architecture/intrinsic.rs
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-12-07 15:03:44 -0500
committerMason Reed <35282038+emesare@users.noreply.github.com>2025-12-10 17:35:19 -0500
commit501fe3ec7a63a534fca3926a5fc4267f6886f089 (patch)
tree0e3e64fcef0a3180950f3e8fb3758ebcbf5d02e7 /rust/src/architecture/intrinsic.rs
parent7090d904513c3e80321bb6a8aba9c3b37d809bac (diff)
[Rust] Move architecture module code into more reasonable files
To keep backwards compatibility for commonly referenced code we re-export them within the architecture module. Also does some light refactoring of some newly added APIs to keep them more consistent with other parts of the codebase.
Diffstat (limited to 'rust/src/architecture/intrinsic.rs')
-rw-r--r--rust/src/architecture/intrinsic.rs150
1 files changed, 150 insertions, 0 deletions
diff --git a/rust/src/architecture/intrinsic.rs b/rust/src/architecture/intrinsic.rs
new file mode 100644
index 00000000..4ad5ee2a
--- /dev/null
+++ b/rust/src/architecture/intrinsic.rs
@@ -0,0 +1,150 @@
+use crate::architecture::CoreArchitecture;
+use crate::confidence::Conf;
+use crate::rc::Ref;
+use crate::types::{NameAndType, Type};
+use binaryninjacore_sys::{
+ BNFreeNameAndTypeList, BNFreeOutputTypeList, BNFreeString, BNGetArchitectureIntrinsicClass,
+ BNGetArchitectureIntrinsicInputs, BNGetArchitectureIntrinsicName,
+ BNGetArchitectureIntrinsicOutputs, BNIntrinsicClass,
+};
+use std::borrow::Cow;
+use std::ffi::CStr;
+use std::fmt::{Debug, Formatter};
+
+crate::new_id_type!(IntrinsicId, u32);
+
+pub trait Intrinsic: Debug + Sized + Clone + Copy {
+ fn name(&self) -> Cow<'_, str>;
+
+ /// Unique identifier for this `Intrinsic`.
+ fn id(&self) -> IntrinsicId;
+
+ /// The intrinsic class for this `Intrinsic`.
+ fn class(&self) -> BNIntrinsicClass {
+ BNIntrinsicClass::GeneralIntrinsicClass
+ }
+
+ // TODO: Maybe just return `(String, Conf<Ref<Type>>)`?
+ /// List of the input names and types for this intrinsic.
+ fn inputs(&self) -> Vec<NameAndType>;
+
+ /// List of the output types for this intrinsic.
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>>;
+}
+
+/// Type for architrectures that do not use intrinsics. Will panic if accessed as an intrinsic.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct UnusedIntrinsic;
+
+impl Intrinsic for UnusedIntrinsic {
+ fn name(&self) -> Cow<'_, str> {
+ unreachable!()
+ }
+ fn id(&self) -> IntrinsicId {
+ unreachable!()
+ }
+ fn inputs(&self) -> Vec<NameAndType> {
+ unreachable!()
+ }
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
+ unreachable!()
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct CoreIntrinsic {
+ pub arch: CoreArchitecture,
+ pub id: IntrinsicId,
+}
+
+impl CoreIntrinsic {
+ pub fn new(arch: CoreArchitecture, id: IntrinsicId) -> Option<Self> {
+ let intrinsic = Self { arch, id };
+ intrinsic.is_valid().then_some(intrinsic)
+ }
+
+ fn is_valid(&self) -> bool {
+ // We check the name to see if the intrinsic is actually valid.
+ let name = unsafe { BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into()) };
+ match name.is_null() {
+ true => false,
+ false => {
+ unsafe { BNFreeString(name) };
+ true
+ }
+ }
+ }
+}
+
+impl Intrinsic for CoreIntrinsic {
+ fn name(&self) -> Cow<'_, str> {
+ unsafe {
+ let name = BNGetArchitectureIntrinsicName(self.arch.handle, self.id.into());
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ // TODO: ^ the above assertion nullifies any benefit to passing back Cow tho?
+ let res = CStr::from_ptr(name);
+ let res = res.to_string_lossy().into_owned().into();
+
+ BNFreeString(name);
+
+ res
+ }
+ }
+
+ fn id(&self) -> IntrinsicId {
+ self.id
+ }
+
+ fn class(&self) -> BNIntrinsicClass {
+ unsafe { BNGetArchitectureIntrinsicClass(self.arch.handle, self.id.into()) }
+ }
+
+ fn inputs(&self) -> Vec<NameAndType> {
+ let mut count: usize = 0;
+ unsafe {
+ let inputs =
+ BNGetArchitectureIntrinsicInputs(self.arch.handle, self.id.into(), &mut count);
+
+ let ret = std::slice::from_raw_parts_mut(inputs, count)
+ .iter()
+ .map(NameAndType::from_raw)
+ .collect();
+
+ BNFreeNameAndTypeList(inputs, count);
+
+ ret
+ }
+ }
+
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
+ let mut count: usize = 0;
+ unsafe {
+ let inputs =
+ BNGetArchitectureIntrinsicOutputs(self.arch.handle, self.id.into(), &mut count);
+
+ let ret = std::slice::from_raw_parts_mut(inputs, count)
+ .iter()
+ .map(Conf::<Ref<Type>>::from_raw)
+ .collect();
+
+ BNFreeOutputTypeList(inputs, count);
+
+ ret
+ }
+ }
+}
+
+impl Debug for CoreIntrinsic {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("CoreIntrinsic")
+ .field("id", &self.id)
+ .field("name", &self.name())
+ .field("class", &self.class())
+ .field("inputs", &self.inputs())
+ .field("outputs", &self.outputs())
+ .finish()
+ }
+}