binaryninja/architecture/
flag.rsuse crate::architecture::CoreArchitecture;
use binaryninjacore_sys::*;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::CStr;
use std::fmt::Debug;
use std::hash::Hash;
pub use binaryninjacore_sys::BNFlagRole as FlagRole;
pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition;
crate::new_id_type!(FlagId, u32);
crate::new_id_type!(FlagWriteId, u32);
crate::new_id_type!(FlagClassId, u32);
crate::new_id_type!(FlagGroupId, u32);
pub trait Flag: Debug + Sized + Clone + Copy + Hash + Eq {
type FlagClass: FlagClass;
fn name(&self) -> Cow<'_, str>;
fn role(&self, class: Option<Self::FlagClass>) -> FlagRole;
fn id(&self) -> FlagId;
}
pub trait FlagWrite: Sized + Clone + Copy {
type FlagType: Flag;
type FlagClass: FlagClass;
fn name(&self) -> Cow<'_, str>;
fn class(&self) -> Option<Self::FlagClass>;
fn id(&self) -> FlagWriteId;
fn flags_written(&self) -> Vec<Self::FlagType>;
}
pub trait FlagClass: Sized + Clone + Copy + Hash + Eq {
fn name(&self) -> Cow<'_, str>;
fn id(&self) -> FlagClassId;
}
pub trait FlagGroup: Debug + Sized + Clone + Copy {
type FlagType: Flag;
type FlagClass: FlagClass;
fn name(&self) -> Cow<'_, str>;
fn id(&self) -> FlagGroupId;
fn flags_required(&self) -> Vec<Self::FlagType>;
fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UnusedFlag;
impl Flag for UnusedFlag {
type FlagClass = Self;
fn name(&self) -> Cow<'_, str> {
unreachable!()
}
fn role(&self, _class: Option<Self::FlagClass>) -> FlagRole {
unreachable!()
}
fn id(&self) -> FlagId {
unreachable!()
}
}
impl FlagWrite for UnusedFlag {
type FlagType = Self;
type FlagClass = Self;
fn name(&self) -> Cow<'_, str> {
unreachable!()
}
fn class(&self) -> Option<Self> {
unreachable!()
}
fn id(&self) -> FlagWriteId {
unreachable!()
}
fn flags_written(&self) -> Vec<Self::FlagType> {
unreachable!()
}
}
impl FlagClass for UnusedFlag {
fn name(&self) -> Cow<'_, str> {
unreachable!()
}
fn id(&self) -> FlagClassId {
unreachable!()
}
}
impl FlagGroup for UnusedFlag {
type FlagType = Self;
type FlagClass = Self;
fn name(&self) -> Cow<'_, str> {
unreachable!()
}
fn id(&self) -> FlagGroupId {
unreachable!()
}
fn flags_required(&self) -> Vec<Self::FlagType> {
unreachable!()
}
fn flag_conditions(&self) -> HashMap<Self, FlagCondition> {
unreachable!()
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct CoreFlag {
arch: CoreArchitecture,
id: FlagId,
}
impl CoreFlag {
pub fn new(arch: CoreArchitecture, id: FlagId) -> Option<Self> {
let flag = Self { arch, id };
flag.is_valid().then_some(flag)
}
fn is_valid(&self) -> bool {
let name = unsafe { BNGetArchitectureFlagName(self.arch.handle, self.id.into()) };
match name.is_null() {
true => false,
false => {
unsafe { BNFreeString(name) };
true
}
}
}
}
impl Flag for CoreFlag {
type FlagClass = CoreFlagClass;
fn name(&self) -> Cow<'_, str> {
unsafe {
let name = BNGetArchitectureFlagName(self.arch.handle, self.id.into());
let res = CStr::from_ptr(name);
let res = res.to_string_lossy().into_owned().into();
BNFreeString(name);
res
}
}
fn role(&self, class: Option<CoreFlagClass>) -> FlagRole {
unsafe {
BNGetArchitectureFlagRole(
self.arch.handle,
self.id.into(),
class.map(|c| c.id.0).unwrap_or(0),
)
}
}
fn id(&self) -> FlagId {
self.id
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct CoreFlagWrite {
arch: CoreArchitecture,
id: FlagWriteId,
}
impl CoreFlagWrite {
pub fn new(arch: CoreArchitecture, id: FlagWriteId) -> Option<Self> {
let flag_write = Self { arch, id };
flag_write.is_valid().then_some(flag_write)
}
fn is_valid(&self) -> bool {
let name = unsafe { BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into()) };
match name.is_null() {
true => false,
false => {
unsafe { BNFreeString(name) };
true
}
}
}
}
impl FlagWrite for CoreFlagWrite {
type FlagType = CoreFlag;
type FlagClass = CoreFlagClass;
fn name(&self) -> Cow<'_, str> {
unsafe {
let name = BNGetArchitectureFlagWriteTypeName(self.arch.handle, self.id.into());
let res = CStr::from_ptr(name);
let res = res.to_string_lossy().into_owned().into();
BNFreeString(name);
res
}
}
fn class(&self) -> Option<CoreFlagClass> {
let class = unsafe {
BNGetArchitectureSemanticClassForFlagWriteType(self.arch.handle, self.id.into())
};
match class {
0 => None,
class_id => Some(CoreFlagClass::new(self.arch, class_id.into())?),
}
}
fn id(&self) -> FlagWriteId {
self.id
}
fn flags_written(&self) -> Vec<CoreFlag> {
let mut count: usize = 0;
let regs: *mut u32 = unsafe {
BNGetArchitectureFlagsWrittenByFlagWriteType(
self.arch.handle,
self.id.into(),
&mut count,
)
};
let ret = unsafe {
std::slice::from_raw_parts(regs, count)
.iter()
.map(|id| FlagId::from(*id))
.filter_map(|reg| CoreFlag::new(self.arch, reg))
.collect()
};
unsafe {
BNFreeRegisterList(regs);
}
ret
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct CoreFlagClass {
arch: CoreArchitecture,
id: FlagClassId,
}
impl CoreFlagClass {
pub fn new(arch: CoreArchitecture, id: FlagClassId) -> Option<Self> {
let flag = Self { arch, id };
flag.is_valid().then_some(flag)
}
fn is_valid(&self) -> bool {
let name =
unsafe { BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into()) };
match name.is_null() {
true => false,
false => {
unsafe { BNFreeString(name) };
true
}
}
}
}
impl FlagClass for CoreFlagClass {
fn name(&self) -> Cow<'_, str> {
unsafe {
let name = BNGetArchitectureSemanticFlagClassName(self.arch.handle, self.id.into());
let res = CStr::from_ptr(name);
let res = res.to_string_lossy().into_owned().into();
BNFreeString(name);
res
}
}
fn id(&self) -> FlagClassId {
self.id
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct CoreFlagGroup {
arch: CoreArchitecture,
id: FlagGroupId,
}
impl CoreFlagGroup {
pub fn new(arch: CoreArchitecture, id: FlagGroupId) -> Option<Self> {
let flag_group = Self { arch, id };
flag_group.is_valid().then_some(flag_group)
}
fn is_valid(&self) -> bool {
let name =
unsafe { BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into()) };
match name.is_null() {
true => false,
false => {
unsafe { BNFreeString(name) };
true
}
}
}
}
impl FlagGroup for CoreFlagGroup {
type FlagType = CoreFlag;
type FlagClass = CoreFlagClass;
fn name(&self) -> Cow<'_, str> {
unsafe {
let name = BNGetArchitectureSemanticFlagGroupName(self.arch.handle, self.id.into());
let res = CStr::from_ptr(name);
let res = res.to_string_lossy().into_owned().into();
BNFreeString(name);
res
}
}
fn id(&self) -> FlagGroupId {
self.id
}
fn flags_required(&self) -> Vec<CoreFlag> {
let mut count: usize = 0;
let regs: *mut u32 = unsafe {
BNGetArchitectureFlagsRequiredForSemanticFlagGroup(
self.arch.handle,
self.id.into(),
&mut count,
)
};
let ret = unsafe {
std::slice::from_raw_parts(regs, count)
.iter()
.map(|id| FlagId::from(*id))
.filter_map(|reg| CoreFlag::new(self.arch, reg))
.collect()
};
unsafe {
BNFreeRegisterList(regs);
}
ret
}
fn flag_conditions(&self) -> HashMap<CoreFlagClass, FlagCondition> {
let mut count: usize = 0;
unsafe {
let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup(
self.arch.handle,
self.id.into(),
&mut count,
);
let ret = std::slice::from_raw_parts_mut(flag_conds, count)
.iter()
.filter_map(|class_cond| {
Some((
CoreFlagClass::new(self.arch, class_cond.semanticClass.into())?,
class_cond.condition,
))
})
.collect();
BNFreeFlagConditionsForSemanticFlagGroup(flag_conds);
ret
}
}
}