#![allow(unused)] use crate::architecture::{Architecture, CoreArchitecture}; use crate::calling_convention::CoreCallingConvention; use crate::rc::{Ref, RefCountable}; use crate::types::{Type, ValueLocation}; use binaryninjacore_sys::{ BNBoolWithConfidence, BNCallingConventionWithConfidence, BNGetCallingConventionArchitecture, BNInlineDuringAnalysis, BNInlineDuringAnalysisWithConfidence, BNOffsetWithConfidence, BNTypeWithConfidence, BNValueLocation, BNValueLocationWithConfidence, }; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::hash::{Hash, Hasher}; /// The minimum allowed confidence of any given [`Type`]. pub const MIN_CONFIDENCE: u8 = u8::MIN; /// The maximum allowed confidence of any given [`Type`]. pub const MAX_CONFIDENCE: u8 = u8::MAX; /// Compatible with the `BNType*WithConfidence` types pub struct Conf { pub contents: T, pub confidence: u8, } pub trait ConfMergeable { type Result; /// Merge two confidence types' values depending on whichever has higher confidence /// In the event of a tie, the LHS (caller's) value is used. fn merge(self, other: O) -> Self::Result; } impl Conf { pub fn new(contents: T, confidence: u8) -> Self { Self { contents, confidence, } } pub fn map(self, f: F) -> Conf where F: FnOnce(T) -> U, { Conf::new(f(self.contents), self.confidence) } pub fn as_ref(&self) -> Conf<&U> where T: AsRef, { Conf::new(self.contents.as_ref(), self.confidence) } } /// Returns best value or LHS on tie /// /// `Conf` + `Conf` → `Conf` impl ConfMergeable> for Conf { type Result = Conf; fn merge(self, other: Conf) -> Conf { if other.confidence > self.confidence { other } else { self } } } /// Returns LHS if RHS is None /// /// `Conf` + `Option>` → `Conf` impl ConfMergeable>> for Conf { type Result = Conf; fn merge(self, other: Option>) -> Conf { match other { Some(c @ Conf { confidence, .. }) if confidence > self.confidence => c, _ => self, } } } /// Returns RHS if LHS is None /// /// `Option>` + `Conf` → `Conf` impl ConfMergeable> for Option> { type Result = Conf; fn merge(self, other: Conf) -> Conf { match self { Some(c @ Conf { confidence, .. }) if confidence >= other.confidence => c, _ => other, } } } /// Returns best non-None value or None /// /// `Option>` + `Option>` → `Option>` impl ConfMergeable>> for Option> { type Result = Option>; fn merge(self, other: Option>) -> Option> { match (self, other) { ( Some( this @ Conf { confidence: this_confidence, .. }, ), Some( other @ Conf { confidence: other_confidence, .. }, ), ) => { if this_confidence >= other_confidence { Some(this) } else { Some(other) } } (None, Some(c)) => Some(c), (Some(c), None) => Some(c), (None, None) => None, } } } impl Debug for Conf { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{:?} ({} confidence)", self.contents, self.confidence) } } impl Display for Conf { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{} ({} confidence)", self.contents, self.confidence) } } impl PartialEq for Conf { fn eq(&self, other: &Self) -> bool { self.contents.eq(&other.contents) } } impl Eq for Conf {} impl Hash for Conf { fn hash(&self, state: &mut H) { self.contents.hash(state); } } impl<'a, T> From<&'a Conf> for Conf<&'a T> { fn from(c: &'a Conf) -> Self { Conf::new(&c.contents, c.confidence) } } impl<'a, T: RefCountable> From<&'a Conf>> for Conf<&'a T> { fn from(c: &'a Conf>) -> Self { Conf::new(c.contents.as_ref(), c.confidence) } } impl<'a, T: RefCountable> From<&'a Ref> for Conf<&'a T> { fn from(r: &'a Ref) -> Self { r.as_ref().into() } } impl Clone for Conf { fn clone(&self) -> Self { Self { contents: self.contents.clone(), confidence: self.confidence, } } } impl Copy for Conf {} impl From for Conf { fn from(contents: T) -> Self { Self::new(contents, MAX_CONFIDENCE) } } impl Conf<&'_ Type> { pub(crate) fn into_raw(value: Self) -> BNTypeWithConfidence { BNTypeWithConfidence { type_: value.contents.handle, confidence: value.confidence, } } } impl Conf> { pub(crate) fn from_raw(value: &BNTypeWithConfidence) -> Self { Self::new( unsafe { Type::from_raw(value.type_) }.to_owned(), value.confidence, ) } pub(crate) fn from_owned_raw(value: BNTypeWithConfidence) -> Self { let owned = Self::from_raw(&value); Self::free_raw(value); owned } pub(crate) fn into_raw(value: Self) -> BNTypeWithConfidence { BNTypeWithConfidence { type_: unsafe { Ref::into_raw(value.contents) }.handle, confidence: value.confidence, } } pub(crate) fn free_raw(value: BNTypeWithConfidence) { let _ = unsafe { Type::ref_from_raw(value.type_) }; } } impl Conf { pub(crate) fn into_rust_raw(value: Self) -> BNValueLocationWithConfidence { BNValueLocationWithConfidence { location: ValueLocation::into_rust_raw(&value.contents), confidence: value.confidence, } } pub(crate) fn free_rust_raw(value: BNValueLocationWithConfidence) { ValueLocation::free_rust_raw(value.location); } } impl Conf> { pub(crate) fn from_raw(value: &BNCallingConventionWithConfidence) -> Self { let arch = unsafe { CoreArchitecture::from_raw(BNGetCallingConventionArchitecture(value.convention)) }; Self::new( unsafe { CoreCallingConvention::from_raw(value.convention, arch).to_owned() }, value.confidence, ) } pub(crate) fn from_owned_raw(value: BNCallingConventionWithConfidence) -> Self { let owned = Self::from_raw(&value); Self::free_raw(value); owned } } impl Conf> { pub(crate) fn into_raw(value: Self) -> BNCallingConventionWithConfidence { BNCallingConventionWithConfidence { convention: unsafe { Ref::into_raw(value.contents) }.handle, confidence: value.confidence, } } pub(crate) fn into_owned_raw(value: &Self) -> BNCallingConventionWithConfidence { BNCallingConventionWithConfidence { convention: value.contents.handle, confidence: value.confidence, } } pub(crate) fn free_raw(value: BNCallingConventionWithConfidence) { let arch = unsafe { CoreArchitecture::from_raw(BNGetCallingConventionArchitecture(value.convention)) }; let _ = unsafe { CoreCallingConvention::ref_from_raw(value.convention, arch) }; } } impl From for Conf { fn from(bool_with_confidence: BNBoolWithConfidence) -> Self { Self::new(bool_with_confidence.value, bool_with_confidence.confidence) } } impl From for Conf { fn from(offset_with_confidence: BNOffsetWithConfidence) -> Self { Self::new( offset_with_confidence.value, offset_with_confidence.confidence, ) } } impl From for Conf { fn from(inline_with_confidence: BNInlineDuringAnalysisWithConfidence) -> Self { Self::new( inline_with_confidence.value, inline_with_confidence.confidence, ) } } impl From> for BNBoolWithConfidence { fn from(conf: Conf) -> Self { Self { value: conf.contents, confidence: conf.confidence, } } } impl From> for BNOffsetWithConfidence { fn from(conf: Conf) -> Self { Self { value: conf.contents, confidence: conf.confidence, } } } impl From> for BNInlineDuringAnalysisWithConfidence { fn from(conf: Conf) -> Self { Self { value: conf.contents, confidence: conf.confidence, } } }