summaryrefslogtreecommitdiff
path: root/rust/src/architecture.rs
diff options
context:
space:
mode:
authorRyan Snyder <ryan@vector35.com>2021-01-21 18:27:48 +0000
committerKyleMiles <krm504@nyu.edu>2021-01-21 19:06:55 +0000
commitd3140edec185f47235b9e4642bdd56d6c585a341 (patch)
treea61859c29e4e3539daea2b761bb1439d942beaf4 /rust/src/architecture.rs
parentc0ddbf0c76d3f1bb7a2b2024f749afc8b9482575 (diff)
This is a combination of 23 commits, the work of Ryan Snyder:
Initial fresh repo Add support for recent calling convention API updates and folds the binaryninjacore-sys crate directly into this one. Add support for auto function analysis suppression Finish moving binaryninjacore-sys back into this crate Update for Symbol/Segment core API changes Update for Symbol API cleanup api: advance submodule reference, support Token changes arch/lifting: support for flags in custom architectures arch/lifting: support default flag write behaviors, handle more ops build: enable headless binary support on MacOS via evil hack bv: add BinaryView wrapper support, remove wrong comment api: update to latest binja dev branch support deps: bump dep versions rust: bump to 2018 edition api: bump to avoid cargo submodule brokenness build: improve binaryninja path detection; enable linux linkhack bv: stub for bv load settings arch: fix flag related crash, minor llil update api: update for recent changes macos: disable linkhack briefly
Diffstat (limited to 'rust/src/architecture.rs')
-rw-r--r--rust/src/architecture.rs1885
1 files changed, 1885 insertions, 0 deletions
diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs
new file mode 100644
index 00000000..fc56140c
--- /dev/null
+++ b/rust/src/architecture.rs
@@ -0,0 +1,1885 @@
+// container abstraction to avoid Vec<> (want CoreArchFlagList, CoreArchRegList)
+// RegisterInfo purge
+use binaryninjacore_sys::*;
+
+use std::ffi::{CString, CStr};
+use std::ptr;
+use std::ops::Drop;
+use std::borrow::{Borrow, Cow};
+use std::slice;
+use std::ops;
+use std::mem::zeroed;
+use std::hash::Hash;
+use std::collections::HashMap;
+
+use crate::{BranchType, Endianness};
+use crate::callingconvention::CallingConvention;
+use crate::platform::Platform;
+
+use crate::llil::{Lifter, LiftedExpr, FlagWriteOp};
+use crate::llil::{get_default_flag_write_llil, get_default_flag_cond_llil};
+
+use crate::string::*;
+use crate::rc::*;
+
+pub enum BranchInfo {
+ Unconditional(u64),
+ False(u64),
+ True(u64),
+ Call(u64),
+ FunctionReturn,
+ SystemCall,
+ Indirect,
+ Exception,
+ Unresolved,
+}
+
+pub struct BranchIter<'a>(&'a InstructionInfo, ops::Range<usize>);
+impl<'a> Iterator for BranchIter<'a> {
+ type Item = (BranchInfo, Option<CoreArchitecture>);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use crate::BranchType::*;
+
+ match self.1.next() {
+ Some(i) => {
+ let target = (self.0).0.branchTarget[i];
+ let arch = (self.0).0.branchArch[i];
+ let arch = if arch.is_null() { None } else { Some(CoreArchitecture(arch)) };
+
+ let res = match (self.0).0.branchType[i] {
+ UnconditionalBranch => BranchInfo::Unconditional(target),
+ FalseBranch => BranchInfo::False(target),
+ TrueBranch => BranchInfo::True(target),
+ CallDestination => BranchInfo::Call(target),
+ FunctionReturn => BranchInfo::FunctionReturn,
+ SystemCall => BranchInfo::SystemCall,
+ IndirectBranch => BranchInfo::Indirect,
+ ExceptionBranch => BranchInfo::Exception,
+ UnresolvedBranch => BranchInfo::Unresolved,
+ };
+
+ Some((res, arch))
+ }
+ _ => None,
+ }
+ }
+}
+
+#[repr(C)]
+pub struct InstructionInfo(BNInstructionInfo);
+impl InstructionInfo {
+ pub fn new(len: usize, branch_delay: bool) -> Self {
+ InstructionInfo (
+ BNInstructionInfo {
+ length: len,
+ archTransitionByTargetAddr: false,
+ branchDelay: branch_delay,
+ branchCount: 0usize,
+ branchType: [BranchType::UnresolvedBranch; 3],
+ branchTarget: [0u64; 3],
+ branchArch: [ptr::null_mut(); 3],
+ }
+ )
+ }
+
+ pub fn len(&self) -> usize { self.0.length }
+ pub fn branch_count(&self) -> usize { self.0.branchCount }
+ pub fn branch_delay(&self) -> bool { self.0.branchDelay }
+ pub fn branches(&self) -> BranchIter { BranchIter(self, 0 .. self.branch_count()) }
+
+ pub fn allow_arch_transition_by_target_addr(&mut self, transition: bool) {
+ self.0.archTransitionByTargetAddr = transition;
+ }
+
+ pub fn add_branch(&mut self, branch: BranchInfo, arch: Option<CoreArchitecture>) {
+ if self.0.branchCount < self.0.branchType.len() {
+ let idx = self.0.branchCount;
+
+ let ty = match branch {
+ BranchInfo::Unconditional(t) => {
+ self.0.branchTarget[idx] = t;
+ BranchType::UnconditionalBranch
+ }
+ BranchInfo::False(t) => {
+ self.0.branchTarget[idx] = t;
+ BranchType::FalseBranch
+ }
+ BranchInfo::True(t) => {
+ self.0.branchTarget[idx] = t;
+ BranchType::TrueBranch
+ }
+ BranchInfo::Call(t) => {
+ self.0.branchTarget[idx] = t;
+ BranchType::CallDestination
+ }
+ BranchInfo::FunctionReturn => BranchType::FunctionReturn,
+ BranchInfo::SystemCall => BranchType::SystemCall,
+ BranchInfo::Indirect => BranchType::IndirectBranch,
+ BranchInfo::Exception => BranchType::ExceptionBranch,
+ BranchInfo::Unresolved => BranchType::UnresolvedBranch,
+ };
+
+ self.0.branchType[idx] = ty;
+ self.0.branchArch[idx] = match arch {
+ Some(a) => a.0,
+ _ => ptr::null_mut(),
+ };
+
+ self.0.branchCount += 1;
+ } else {
+ error!("Attempt to branch to instruction with no additional branch space!");
+ }
+ }
+}
+
+pub enum InstructionTextTokenContents {
+ Text,
+ Instruction,
+ OperandSeparator,
+ Register,
+ Integer(u64), // TODO size?
+ PossibleAddress(u64), // TODO size?
+ BeginMemoryOperand,
+ EndMemoryOperand,
+ FloatingPoint,
+ CodeRelativeAddress(u64),
+}
+
+pub use binaryninjacore_sys::BNInstructionTextTokenContext as InstructionTextTokenContext;
+
+#[repr(C)]
+pub struct InstructionTextToken(BNInstructionTextToken);
+impl InstructionTextToken {
+ pub fn new<T: Into<Vec<u8>>>(contents: InstructionTextTokenContents, text: T) -> Self {
+ use self::BNInstructionTextTokenType::*;
+ use self::InstructionTextTokenContents::*;
+
+ let mut res: BNInstructionTextToken = unsafe { zeroed() };
+
+ res.context = InstructionTextTokenContext::NoTokenContext;
+ res.address = 0;
+ res.size = 0; // TODO supply? x86 seems to, others don't...
+ res.operand = 0xffff_ffff;
+ res.confidence = 0xff;
+
+ match contents {
+ Integer(v) => res.value = v,
+ PossibleAddress(v) |
+ CodeRelativeAddress(v) => {
+ res.value = v;
+ res.address = v;
+ }
+ _ => {},
+ }
+
+ res.type_ = match contents {
+
+ Text => TextToken,
+ Instruction => InstructionToken,
+ OperandSeparator => OperandSeparatorToken,
+ Register => RegisterToken,
+ Integer(_) => IntegerToken,
+ PossibleAddress(_) => PossibleAddressToken,
+ BeginMemoryOperand => BeginMemoryOperandToken,
+ EndMemoryOperand => EndMemoryOperandToken,
+ FloatingPoint => FloatingPointToken,
+ CodeRelativeAddress(_) => CodeRelativeAddressToken,
+ };
+
+ res.text = CString::new(text).unwrap().into_raw();
+
+ InstructionTextToken(res)
+ }
+
+ pub fn text(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.0.text) }
+ }
+
+ pub fn contents(&self) -> InstructionTextTokenContents {
+ use self::BNInstructionTextTokenType::*;
+ use self::InstructionTextTokenContents::*;
+
+ match self.0.type_ {
+ TextToken => Text,
+ InstructionToken => Instruction,
+ OperandSeparatorToken => OperandSeparator,
+ RegisterToken => Register,
+ IntegerToken => Integer(self.0.value),
+ PossibleAddressToken => PossibleAddress(self.0.value),
+ BeginMemoryOperandToken => BeginMemoryOperand,
+ EndMemoryOperandToken => EndMemoryOperand,
+ FloatingPointToken => FloatingPoint,
+ CodeRelativeAddressToken => CodeRelativeAddress(self.0.value),
+ _ => unimplemented!("woops"),
+ }
+ }
+
+ pub fn context(&self) -> InstructionTextTokenContext {
+ self.0.context
+ }
+
+ pub fn size(&self) -> usize {
+ self.0.size
+ }
+
+ pub fn operand(&self) -> usize {
+ self.0.operand
+ }
+
+ pub fn address(&self) -> u64 {
+ self.0.address
+ }
+}
+
+impl Clone for InstructionTextToken {
+ fn clone(&self) -> Self {
+ InstructionTextToken (
+ BNInstructionTextToken {
+ type_: self.0.type_,
+ context: self.0.context,
+ address: self.0.address,
+ size: self.0.size,
+ operand: self.0.operand,
+ value: self.0.value,
+ width: 0,
+ text: self.text().to_owned().into_raw(),
+ confidence: 0xff,
+ typeNames: ptr::null_mut(),
+ namesCount: 0,
+ }
+ )
+ }
+}
+
+impl Drop for InstructionTextToken {
+ fn drop(&mut self) {
+ let _owned = unsafe { CString::from_raw(self.0.text) };
+ }
+}
+
+pub use binaryninjacore_sys::BNImplicitRegisterExtend as ImplicitRegisterExtend;
+pub use binaryninjacore_sys::BNLowLevelILFlagCondition as FlagCondition;
+pub use binaryninjacore_sys::BNFlagRole as FlagRole;
+
+pub trait RegisterInfo: Sized {
+ type RegType: Register<InfoType=Self>;
+
+ fn parent(&self) -> Option<Self::RegType>;
+ fn size(&self) -> usize;
+ fn offset(&self) -> usize;
+ fn implicit_extend(&self) -> ImplicitRegisterExtend;
+}
+
+pub trait Register: Sized + Clone + Copy {
+ type InfoType: RegisterInfo<RegType=Self>;
+
+ fn name(&self) -> Cow<str>;
+ fn info(&self) -> Self::InfoType;
+
+ /// Unique identifier for this `Register`.
+ ///
+ /// *MUST* be in the range [0, 0x7fff_ffff]
+ fn id(&self) -> u32;
+}
+
+pub trait Flag: Sized + Clone + Copy {
+ type FlagClass: FlagClass;
+
+ fn name(&self) -> Cow<str>;
+ fn role(&self, class: Option<Self::FlagClass>) -> FlagRole;
+
+ /// Unique identifier for this `Flag`.
+ ///
+ /// *MUST* be in the range [0, 0x7fff_ffff]
+ fn id(&self) -> u32;
+}
+
+pub trait FlagWrite: Sized + Clone + Copy {
+ type FlagType: Flag;
+ type FlagClass: FlagClass;
+
+ fn name(&self) -> Cow<str>;
+ fn class(&self) -> Option<Self::FlagClass>;
+
+ /// Unique identifier for this `FlagWrite`.
+ ///
+ /// *MUST NOT* be 0.
+ /// *MUST* be in the range [1, 0x7fff_ffff]
+ fn id(&self) -> u32;
+
+ fn flags_written(&self) -> Vec<Self::FlagType>;
+}
+
+pub trait FlagClass: Sized + Clone + Copy + Hash + Eq {
+ fn name(&self) -> Cow<str>;
+
+ /// Unique identifier for this `FlagClass`.
+ ///
+ /// *MUST NOT* be 0.
+ /// *MUST* be in the range [1, 0x7fff_ffff]
+ fn id(&self) -> u32;
+}
+
+pub trait FlagGroup: Sized + Clone + Copy {
+ type FlagType: Flag;
+ type FlagClass: FlagClass;
+
+ fn name(&self) -> Cow<str>;
+
+ /// Unique identifier for this `FlagGroup`.
+ ///
+ /// *MUST* be in the range [0, 0x7fff_ffff]
+ fn id(&self) -> u32;
+
+ /// Returns the list of flags that need to be resolved in order
+ /// to take the clean flag resolution path -- at time of writing,
+ /// all required flags must have been set by the same instruction,
+ /// and the 'querying' instruction must be reachable from *one*
+ /// instruction that sets all of these flags.
+ fn flags_required(&self) -> Vec<Self::FlagType>;
+
+ /// Returns the mapping of Semantic Flag Classes to Flag Conditions,
+ /// in the context of this Flag Group.
+ ///
+ /// Example:
+ ///
+ /// If we have a group representing `cr1_lt` (as in PowerPC), we would
+ /// have multiple Semantic Flag Classes used by the different Flag Write
+ /// Types to represent the different comparisons, so for `cr1_lt` we
+ /// would return a mapping along the lines of:
+ ///
+ /// ```
+ /// cr1_signed -> LLFC_SLT,
+ /// cr1_unsigned -> LLFC_ULT,
+ /// ```
+ ///
+ /// This allows the core to recover the semantics of the comparison and
+ /// inline it into conditional branches when appropriate.
+ fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>;
+}
+
+pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
+ type Handle: Borrow<Self> + Clone;
+
+ type RegisterInfo: RegisterInfo<RegType=Self::Register>;
+ type Register: Register<InfoType=Self::RegisterInfo>;
+
+ type Flag: Flag<FlagClass=Self::FlagClass>;
+ type FlagWrite: FlagWrite<FlagType=Self::Flag, FlagClass=Self::FlagClass>;
+ type FlagClass: FlagClass;
+ type FlagGroup: FlagGroup<FlagType=Self::Flag, FlagClass=Self::FlagClass>;
+
+ type InstructionTextContainer: Into<Vec<InstructionTextToken>>;
+
+ fn endianness(&self) -> Endianness;
+ fn address_size(&self) -> usize;
+ fn default_integer_size(&self) -> usize;
+ fn instruction_alignment(&self) -> usize;
+ fn max_instr_len(&self) -> usize;
+ fn opcode_display_len(&self) -> usize;
+
+ fn associated_arch_by_addr(&self, addr: &mut u64) -> CoreArchitecture;
+
+ fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo>;
+ fn instruction_text(&self, data: &[u8], addr: u64) -> Option<(usize, Self::InstructionTextContainer)>;
+ fn instruction_llil(&self, data: &[u8], addr: u64, il: &mut Lifter<Self>) -> Option<(usize, bool)>;
+
+ /// Fallback flag value calculation path. This method is invoked when the core is unable to
+ /// recover flag use semantics, and resorts to emitting instructions that explicitly set each
+ /// observed flag to the value of an expression returned by this function.
+ ///
+ /// This function *MUST NOT* append instructions that have side effects.
+ ///
+ /// This function *MUST NOT* observe the values of other flags.
+ ///
+ /// This function *MUST* return `None` or an expression representing a boolean value.
+ fn flag_write_llil<'a>(&self, flag: Self::Flag, flag_write_type: Self::FlagWrite, op: FlagWriteOp<Self::Register>, il: &'a mut Lifter<Self>)
+ -> Option<LiftedExpr<'a, Self>>
+ {
+ let role = flag.role(flag_write_type.class());
+ Some(get_default_flag_write_llil(self, role, op, il))
+ }
+
+ /// Determines what flags need to be examined in order to attempt automatic recovery of the
+ /// semantics of this flag use.
+ ///
+ /// If automatic recovery is not possible, the `flag_cond_llil` method will be invoked to give
+ /// this `Architecture` implementation arbitrary control over the expression to be evaluated.
+ fn flags_required_for_flag_condition(&self, condition: FlagCondition, class: Option<Self::FlagClass>) -> Vec<Self::Flag>;
+
+ /// This function *MUST NOT* append instructions that have side effects.
+ ///
+ /// This function *MUST NOT* observe the values of flags not returned by
+ /// `flags_required_for_flag_condition`.
+ ///
+ /// This function *MUST* return `None` or an expression representing a boolean value.
+ fn flag_cond_llil<'a>(&self, cond: FlagCondition, class: Option<Self::FlagClass>, il: &'a mut Lifter<Self>)
+ -> Option<LiftedExpr<'a, Self>>
+ {
+ Some(get_default_flag_cond_llil(self, cond, class, il))
+ }
+
+ /// Performs fallback resolution when the core was unable to recover the semantics of a
+ /// `LLIL_FLAG_GROUP` expression. This occurs when multiple instructions may have set the flags
+ /// at the flag group query, or when the `FlagGroup::flag_conditions()` map doesn't have an entry
+ /// for the `FlagClass` associated with the `FlagWrite` type of the expression that last set
+ /// the flags required by the `FlagGroup` `group`.
+ ///
+ /// In this fallback path, the `Architecture` must generate the boolean expression in terms of
+ /// the values of that flags returned by `group`'s `flags_required` method.
+ ///
+ /// This function must return an expression representing a boolean (as in, size of `0`) value.
+ /// It is not allowed to add any instructions that can cause side effects.
+ ///
+ /// This function must not observe the values of any flag not returned by `group`'s
+ /// `flags_required` method.
+ fn flag_group_llil<'a>(&self, group: Self::FlagGroup, il: &'a mut Lifter<Self>) -> Option<LiftedExpr<'a, Self>>;
+
+ fn registers_all(&self) -> Vec<Self::Register>;
+ fn registers_full_width(&self) -> Vec<Self::Register>;
+ fn registers_global(&self) -> Vec<Self::Register>;
+
+ fn flags(&self) -> Vec<Self::Flag>;
+ fn flag_write_types(&self) -> Vec<Self::FlagWrite>;
+ fn flag_classes(&self) -> Vec<Self::FlagClass>;
+ fn flag_groups(&self) -> Vec<Self::FlagGroup>;
+
+
+ fn stack_pointer_reg(&self) -> Option<Self::Register>;
+ fn link_reg(&self) -> Option<Self::Register>;
+
+ fn register_from_id(&self, id: u32) -> Option<Self::Register>;
+ fn flag_from_id(&self, id: u32) -> Option<Self::Flag>;
+ fn flag_write_from_id(&self, id: u32) -> Option<Self::FlagWrite>;
+ fn flag_class_from_id(&self, id: u32) -> Option<Self::FlagClass>;
+ fn flag_group_from_id(&self, id: u32) -> Option<Self::FlagGroup>;
+
+ fn handle(&self) -> Self::Handle;
+}
+
+pub struct CoreRegisterInfo(*mut BNArchitecture, u32, BNRegisterInfo);
+impl RegisterInfo for CoreRegisterInfo {
+ type RegType = CoreRegister;
+
+ fn parent(&self) -> Option<CoreRegister> {
+ if self.1 != self.2.fullWidthRegister {
+ Some(CoreRegister(self.0, self.2.fullWidthRegister))
+ } else {
+ None
+ }
+ }
+
+ fn size(&self) -> usize {
+ self.2.size
+ }
+
+ fn offset(&self) -> usize {
+ self.2.offset
+ }
+
+ fn implicit_extend(&self) -> ImplicitRegisterExtend {
+ self.2.extend
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct CoreRegister(*mut BNArchitecture, u32);
+impl Register for CoreRegister {
+ type InfoType = CoreRegisterInfo;
+
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureRegisterName(self.0, self.1);
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ let res = CStr::from_ptr(name);
+ let res = res.to_string_lossy().into_owned().into();
+
+ BNFreeString(name);
+
+ res
+ }
+ }
+
+ fn info(&self) -> CoreRegisterInfo {
+ CoreRegisterInfo(self.0, self.1, unsafe {
+ BNGetArchitectureRegisterInfo(self.0, self.1)
+ })
+ }
+
+ fn id(&self) -> u32 {
+ self.1
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct CoreFlag(*mut BNArchitecture, u32);
+impl Flag for CoreFlag {
+ type FlagClass = CoreFlagClass;
+
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureFlagName(self.0, self.1);
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ 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 {
+ let class_id = match class {
+ Some(class) => class.1,
+ _ => 0
+ };
+
+ unsafe { BNGetArchitectureFlagRole(self.0, self.1, class_id) }
+ }
+
+ fn id(&self) -> u32 {
+ self.1
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct CoreFlagWrite(*mut BNArchitecture, u32);
+impl FlagWrite for CoreFlagWrite {
+ type FlagType = CoreFlag;
+ type FlagClass = CoreFlagClass;
+
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureFlagWriteTypeName(self.0, self.1);
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ let res = CStr::from_ptr(name);
+ let res = res.to_string_lossy().into_owned().into();
+
+ BNFreeString(name);
+
+ res
+ }
+ }
+
+ fn id(&self) -> u32 {
+ self.1
+ }
+
+ fn flags_written(&self) -> Vec<CoreFlag> {
+ let mut count: usize = 0;
+ let regs: *mut u32 = unsafe {
+ BNGetArchitectureFlagsWrittenByFlagWriteType(self.0, self.1, &mut count as *mut _)
+ };
+
+ let ret = unsafe {
+ slice::from_raw_parts_mut(regs, count).iter().map(|reg| CoreFlag(self.0, *reg)).collect()
+ };
+
+ unsafe { BNFreeRegisterList(regs); }
+
+ ret
+ }
+
+ fn class(&self) -> Option<CoreFlagClass> {
+ let class = unsafe { BNGetArchitectureSemanticClassForFlagWriteType(self.0, self.1) };
+
+ match class {
+ 0 => None,
+ id => Some(CoreFlagClass(self.0, id)),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct CoreFlagClass(*mut BNArchitecture, u32);
+impl FlagClass for CoreFlagClass {
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureSemanticFlagClassName(self.0, self.1);
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ let res = CStr::from_ptr(name);
+ let res = res.to_string_lossy().into_owned().into();
+
+ BNFreeString(name);
+
+ res
+ }
+ }
+
+ fn id(&self) -> u32 {
+ self.1
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct CoreFlagGroup(*mut BNArchitecture, u32);
+impl FlagGroup for CoreFlagGroup {
+ type FlagType = CoreFlag;
+ type FlagClass = CoreFlagClass;
+
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureSemanticFlagGroupName(self.0, self.1);
+
+ // We need to guarantee ownership, as if we're still
+ // a Borrowed variant we're about to free the underlying
+ // memory.
+ let res = CStr::from_ptr(name);
+ let res = res.to_string_lossy().into_owned().into();
+
+ BNFreeString(name);
+
+ res
+ }
+ }
+
+ fn id(&self) -> u32 {
+ self.1
+ }
+
+ fn flags_required(&self) -> Vec<CoreFlag> {
+ let mut count: usize = 0;
+ let regs: *mut u32 = unsafe {
+ BNGetArchitectureFlagsRequiredForSemanticFlagGroup(self.0, self.1, &mut count as *mut _)
+ };
+
+ let ret = unsafe {
+ slice::from_raw_parts_mut(regs, count).iter().map(|reg| CoreFlag(self.0, *reg)).collect()
+ };
+
+ unsafe { BNFreeRegisterList(regs); }
+
+ ret
+ }
+
+ fn flag_conditions(&self) -> HashMap<CoreFlagClass, FlagCondition> {
+ let mut count: usize = 0;
+
+ unsafe {
+ let flag_conds = BNGetArchitectureFlagConditionsForSemanticFlagGroup(self.0, self.1, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(flag_conds, count).iter().map(|class_cond| {
+ (CoreFlagClass(self.0, class_cond.semanticClass), class_cond.condition)
+ }).collect();
+
+ BNFreeFlagConditionsForSemanticFlagGroup(flag_conds);
+
+ ret
+ }
+ }
+}
+
+pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize);
+impl ops::Deref for CoreArchitectureList {
+ type Target = [CoreArchitecture];
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { slice::from_raw_parts_mut(self.0 as *mut CoreArchitecture, self.1) }
+ }
+}
+
+impl Drop for CoreArchitectureList {
+ fn drop(&mut self) {
+ unsafe { BNFreeArchitectureList(self.0); }
+ }
+}
+
+pub struct InstructionTextTokenList(*mut BNInstructionTextToken, usize);
+
+impl ops::Deref for InstructionTextTokenList {
+ type Target = [InstructionTextToken];
+
+ fn deref(&self) -> &Self::Target {
+ unsafe { slice::from_raw_parts(&*(self.0 as *const InstructionTextToken), self.1) }
+ }
+}
+
+impl Drop for InstructionTextTokenList {
+ fn drop(&mut self) {
+ unsafe { BNFreeInstructionText(self.0, self.1) }
+ }
+}
+
+impl Into<Vec<InstructionTextToken>> for InstructionTextTokenList {
+ fn into(self) -> Vec<InstructionTextToken> {
+ self.to_vec()
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+pub struct CoreArchitecture(pub(crate) *mut BNArchitecture);
+
+unsafe impl Send for CoreArchitecture {}
+unsafe impl Sync for CoreArchitecture {}
+
+impl CoreArchitecture {
+ pub(crate) unsafe fn from_raw(raw: *mut BNArchitecture) -> Self {
+ CoreArchitecture(raw)
+ }
+
+ pub fn list_all() -> CoreArchitectureList {
+ let mut count: usize = 0;
+ let archs = unsafe { BNGetArchitectureList(&mut count as *mut _) };
+
+ CoreArchitectureList(archs, count)
+ }
+
+ pub fn by_name<N: Into<Vec<u8>>>(name: N) -> Option<Self> {
+ let name = match CString::new(name) {
+ Ok(s) => s,
+ _ => return None,
+ };
+
+ let res = unsafe { BNGetArchitectureByName(name.as_ptr()) };
+
+ match res.is_null() {
+ false => Some(CoreArchitecture(res)),
+ true => None,
+ }
+ }
+
+ pub fn name(&self) -> BnString {
+ unsafe {
+ BnString::from_raw(BNGetArchitectureName(self.0))
+ }
+ }
+}
+
+impl AsRef<CoreArchitecture> for CoreArchitecture {
+ fn as_ref(&self) -> &Self {
+ self
+ }
+}
+
+impl Architecture for CoreArchitecture {
+ type Handle = Self;
+
+ type RegisterInfo = CoreRegisterInfo;
+ type Register = CoreRegister;
+ type Flag = CoreFlag;
+ type FlagWrite = CoreFlagWrite;
+ type FlagClass = CoreFlagClass;
+ type FlagGroup = CoreFlagGroup;
+
+ type InstructionTextContainer = InstructionTextTokenList;
+
+ fn endianness(&self) -> Endianness {
+ unsafe { BNGetArchitectureEndianness(self.0) }
+ }
+
+ fn address_size(&self) -> usize {
+ unsafe { BNGetArchitectureAddressSize(self.0) }
+ }
+
+ fn default_integer_size(&self) -> usize {
+ unsafe { BNGetArchitectureDefaultIntegerSize(self.0) }
+ }
+
+ fn instruction_alignment(&self) -> usize {
+ unsafe { BNGetArchitectureInstructionAlignment(self.0) }
+ }
+
+ fn max_instr_len(&self) -> usize {
+ unsafe { BNGetArchitectureMaxInstructionLength(self.0) }
+ }
+
+ fn opcode_display_len(&self) -> usize {
+ unsafe { BNGetArchitectureOpcodeDisplayLength(self.0) }
+ }
+
+ fn associated_arch_by_addr(&self, addr: &mut u64) -> CoreArchitecture {
+ let arch = unsafe { BNGetAssociatedArchitectureByAddress(self.0, addr as *mut _) };
+
+ CoreArchitecture(arch)
+ }
+
+ fn instruction_info(&self, data: &[u8], addr: u64) -> Option<InstructionInfo> {
+ let mut info = unsafe { zeroed::<InstructionInfo>() };
+ let success = unsafe { BNGetInstructionInfo(self.0, data.as_ptr(), addr, data.len(), &mut (info.0) as *mut _) };
+
+ if success {
+ Some(info)
+ } else {
+ None
+ }
+ }
+
+ fn instruction_text(&self, data: &[u8], addr: u64) -> Option<(usize, InstructionTextTokenList)> {
+ let mut consumed = data.len();
+ let mut count: usize = 0;
+ let mut result: *mut BNInstructionTextToken = ptr::null_mut();
+
+ unsafe {
+ if BNGetInstructionText(self.0, data.as_ptr(), addr, &mut consumed as *mut _, &mut result as *mut _,
+ &mut count as *mut _) {
+ Some((consumed, InstructionTextTokenList(result, count)))
+ } else {
+ None
+ }
+ }
+ }
+
+ fn instruction_llil(&self, _data: &[u8], _addr: u64, _il: &mut Lifter<Self>) -> Option<(usize, bool)> {
+ None
+ }
+
+ fn flag_write_llil<'a>(&self, _flag: Self::Flag, _flag_write: Self::FlagWrite, _op: FlagWriteOp<Self::Register>, _il: &'a mut Lifter<Self>)
+ -> Option<LiftedExpr<'a, Self>>
+ {
+ None
+ }
+
+ fn flag_cond_llil<'a>(&self, _cond: FlagCondition, _class: Option<Self::FlagClass>, _il: &'a mut Lifter<Self>)
+ -> Option<LiftedExpr<'a, Self>>
+ {
+ None
+ }
+
+ fn flag_group_llil<'a>(&self, _group: Self::FlagGroup, _il: &'a mut Lifter<Self>)
+ -> Option<LiftedExpr<'a, Self>>
+ {
+ None
+ }
+
+
+ fn registers_all(&self) -> Vec<CoreRegister> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetAllArchitectureRegisters(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreRegister(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn registers_full_width(&self) -> Vec<CoreRegister> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetFullWidthArchitectureRegisters(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreRegister(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn registers_global(&self) -> Vec<CoreRegister> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetArchitectureGlobalRegisters(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreRegister(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn flags(&self) -> Vec<CoreFlag> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetAllArchitectureFlags(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreFlag(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn flag_write_types(&self) -> Vec<CoreFlagWrite> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetAllArchitectureFlagWriteTypes(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreFlagWrite(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn flag_classes(&self) -> Vec<CoreFlagClass> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetAllArchitectureSemanticFlagClasses(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreFlagClass(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn flag_groups(&self) -> Vec<CoreFlagGroup> {
+ unsafe {
+ let mut count: usize = 0;
+ let regs = BNGetAllArchitectureSemanticFlagGroups(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(regs, count)
+ .iter()
+ .map(|reg| CoreFlagGroup(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(regs);
+
+ ret
+ }
+ }
+
+ fn flags_required_for_flag_condition(&self, condition: FlagCondition, class: Option<Self::FlagClass>) -> Vec<Self::Flag> {
+ let class_id = class.map(|c| c.id()).unwrap_or(0);
+
+ unsafe {
+ let mut count: usize = 0;
+ let flags = BNGetArchitectureFlagsRequiredForFlagCondition(self.0, condition, class_id, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(flags, count)
+ .iter()
+ .map(|flag| CoreFlag(self.0, *flag))
+ .collect();
+
+ BNFreeRegisterList(flags);
+
+ ret
+ }
+ }
+
+ fn stack_pointer_reg(&self) -> Option<CoreRegister> {
+ match unsafe { BNGetArchitectureStackPointerRegister(self.0) } {
+ 0xffff_ffff => None,
+ reg => Some(CoreRegister(self.0, reg))
+ }
+ }
+
+ fn link_reg(&self) -> Option<CoreRegister> {
+ match unsafe { BNGetArchitectureLinkRegister(self.0) } {
+ 0xffff_ffff => None,
+ reg => Some(CoreRegister(self.0, reg))
+ }
+ }
+
+ fn register_from_id(&self, id: u32) -> Option<CoreRegister> {
+ // TODO validate in debug builds
+ Some(CoreRegister(self.0, id))
+ }
+
+ fn flag_from_id(&self, id: u32) -> Option<CoreFlag> {
+ // TODO validate in debug builds
+ Some(CoreFlag(self.0, id))
+ }
+
+ fn flag_write_from_id(&self, id: u32) -> Option<CoreFlagWrite> {
+ // TODO validate in debug builds
+ Some(CoreFlagWrite(self.0, id))
+ }
+
+ fn flag_class_from_id(&self, id: u32) -> Option<CoreFlagClass> {
+ // TODO validate in debug builds
+ Some(CoreFlagClass(self.0, id))
+ }
+
+ fn flag_group_from_id(&self, id: u32) -> Option<CoreFlagGroup> {
+ // TODO validate in debug builds
+ Some(CoreFlagGroup(self.0, id))
+ }
+
+ fn handle(&self) -> CoreArchitecture {
+ *self
+ }
+}
+
+macro_rules! cc_func {
+ ($get_name:ident, $get_api:ident, $set_name:ident, $set_api:ident) => {
+ fn $get_name(&self) -> Option<Ref<CallingConvention<Self>>> {
+ let handle = self.as_ref();
+
+ unsafe {
+ let cc = $get_api(handle.0);
+
+ if cc.is_null() {
+ None
+ } else {
+ Some(Ref::new(CallingConvention::from_raw(cc, self.handle())))
+ }
+ }
+ }
+
+ fn $set_name(&self, cc: &CallingConvention<Self>) {
+ let handle = self.as_ref();
+
+ assert!(cc.arch_handle.borrow().as_ref().0 == handle.0, "use of calling convention with non-matching architecture!");
+
+ unsafe {
+ $set_api(handle.0, cc.handle);
+ }
+ }
+ }
+}
+
+/// Contains helper methods for all types implementing 'Architecture'
+pub trait ArchitectureExt: Architecture {
+ fn register_by_name<S: BnStrCompatible>(&self, name: S) -> Option<Self::Register> {
+ let name = name.as_bytes_with_nul();
+
+ match unsafe { BNGetArchitectureRegisterByName(self.as_ref().0, name.as_ref().as_ptr() as *mut _) } {
+ 0xffff_ffff => None,
+ reg => self.register_from_id(reg)
+ }
+ }
+
+ cc_func!(get_default_calling_convention, BNGetArchitectureDefaultCallingConvention,
+ set_default_calling_convention, BNSetArchitectureDefaultCallingConvention);
+
+ cc_func!(get_cdecl_calling_convention, BNGetArchitectureCdeclCallingConvention,
+ set_cdecl_calling_convention, BNSetArchitectureCdeclCallingConvention);
+
+ cc_func!(get_stdcall_calling_convention, BNGetArchitectureStdcallCallingConvention,
+ set_stdcall_calling_convention, BNSetArchitectureStdcallCallingConvention);
+
+ cc_func!(get_fastcall_calling_convention, BNGetArchitectureFastcallCallingConvention,
+ set_fastcall_calling_convention, BNSetArchitectureFastcallCallingConvention);
+
+ fn standalone_platform(&self) -> Option<Ref<Platform>> {
+ unsafe {
+ let handle = BNGetArchitectureStandalonePlatform(self.as_ref().0);
+
+ if handle.is_null() {
+ return None;
+ }
+
+ Some(Ref::new(Platform::from_raw(handle)))
+ }
+ }
+}
+
+impl<T: Architecture> ArchitectureExt for T { }
+
+pub fn register_architecture<S, A, F>(name: S, func: F) -> &'static A
+where
+ S: BnStrCompatible,
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync + Sized,
+ F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
+{
+ use std::os::raw::{c_void, c_char};
+ use std::mem;
+
+ #[repr(C)]
+ struct ArchitectureBuilder<A, F>
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
+ {
+ arch: A,
+ func: F,
+ }
+
+ extern "C" fn cb_init<A, F>(ctxt: *mut c_void, obj: *mut BNArchitecture)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ F: FnOnce(CustomArchitectureHandle<A>, CoreArchitecture) -> A,
+ {
+ unsafe {
+ let custom_arch = &mut *(ctxt as *mut ArchitectureBuilder<A, F>);
+ let custom_arch_handle = CustomArchitectureHandle {
+ handle: ctxt as *mut A
+ };
+
+ let create = ptr::read(&custom_arch.func);
+ ptr::write(&mut custom_arch.arch, create(custom_arch_handle, CoreArchitecture(obj)));
+ }
+ }
+
+ extern "C" fn cb_endianness<A>(ctxt: *mut c_void) -> BNEndianness
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.endianness()
+ }
+
+ extern "C" fn cb_address_size<A>(ctxt: *mut c_void) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.address_size()
+ }
+
+ extern "C" fn cb_default_integer_size<A>(ctxt: *mut c_void) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.default_integer_size()
+ }
+
+ extern "C" fn cb_instruction_alignment<A>(ctxt: *mut c_void) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.instruction_alignment()
+ }
+
+ extern "C" fn cb_max_instr_len<A>(ctxt: *mut c_void) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.max_instr_len()
+ }
+
+ extern "C" fn cb_opcode_display_len<A>(ctxt: *mut c_void) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.opcode_display_len()
+ }
+
+ extern "C" fn cb_associated_arch_by_addr<A>(ctxt: *mut c_void, addr: *mut u64) -> *mut BNArchitecture
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let addr = unsafe { &mut *(addr) };
+
+ custom_arch.associated_arch_by_addr(addr).0
+ }
+
+ extern "C" fn cb_instruction_info<A>(ctxt: *mut c_void, data: *const u8, addr: u64,
+ len: usize, result: *mut BNInstructionInfo) -> bool
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let data = unsafe { slice::from_raw_parts(data, len) };
+ let result = unsafe { &mut *(result as *mut InstructionInfo) };
+
+ match custom_arch.instruction_info(data, addr) {
+ Some(info) => {
+ result.0 = info.0;
+ true
+ }
+ None => false,
+ }
+ }
+
+ extern "C" fn cb_get_instruction_text<A>(ctxt: *mut c_void, data: *const u8, addr: u64, len: *mut usize,
+ result: *mut *mut BNInstructionTextToken, count: *mut usize) -> bool
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let data = unsafe { slice::from_raw_parts(data, *len) };
+ let result = unsafe { &mut *result };
+
+ match custom_arch.instruction_text(data, addr) {
+ Some((res_size, res_tokens)) => {
+ unsafe {
+ let mut res_tokens = res_tokens.into();
+ res_tokens.shrink_to_fit();
+ assert!(res_tokens.capacity() == res_tokens.len());
+
+ *len = res_size;
+ *count = res_tokens.len();
+
+ *result = res_tokens.as_mut_ptr() as *mut _;
+ mem::forget(res_tokens);
+ }
+ true
+ }
+ None => false,
+ }
+ }
+
+ extern "C" fn cb_free_instruction_text(tokens: *mut BNInstructionTextToken, count: usize) {
+ let _tokens = unsafe { Vec::from_raw_parts(tokens as *mut InstructionTextToken, count, count) };
+ }
+
+ extern "C" fn cb_instruction_llil<A>(ctxt: *mut c_void, data: *const u8, addr: u64, len: *mut usize,
+ il: *mut BNLowLevelILFunction) -> bool
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch_handle = CustomArchitectureHandle {
+ handle: ctxt as *mut A
+ };
+
+ let data = unsafe { slice::from_raw_parts(data, *len) };
+ let mut lifter = unsafe { Lifter::from_raw(custom_arch_handle, il) };
+
+ match custom_arch.instruction_llil(data, addr, &mut lifter) {
+ Some((res_len, res_value)) => {
+ unsafe { *len = res_len };
+ res_value
+ }
+ None => false,
+ }
+ }
+
+ extern "C" fn cb_reg_name<A>(ctxt: *mut c_void, reg: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ match custom_arch.register_from_id(reg) {
+ Some(reg) => BnString::new(reg.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_reg").into_raw(),
+ }
+ }
+
+ extern "C" fn cb_flag_name<A>(ctxt: *mut c_void, flag: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ match custom_arch.flag_from_id(flag) {
+ Some(flag) => BnString::new(flag.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_flag").into_raw(),
+ }
+ }
+
+ extern "C" fn cb_flag_write_name<A>(ctxt: *mut c_void, flag_write: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ match custom_arch.flag_write_from_id(flag_write) {
+ Some(flag_write) => BnString::new(flag_write.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_flag_write").into_raw(),
+ }
+ }
+
+ extern "C" fn cb_semantic_flag_class_name<A>(ctxt: *mut c_void, class: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ match custom_arch.flag_class_from_id(class) {
+ Some(class) => BnString::new(class.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_flag_class").into_raw(),
+ }
+ }
+
+ extern "C" fn cb_semantic_flag_group_name<A>(ctxt: *mut c_void, group: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ match custom_arch.flag_group_from_id(group) {
+ Some(group) => BnString::new(group.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_flag_group").into_raw(),
+ }
+ }
+
+ fn alloc_register_list<I: Iterator<Item=u32> + ExactSizeIterator>(items: I, count: &mut usize) -> *mut u32 {
+ let len = items.len();
+ *count = len;
+
+ if len == 0 {
+ ptr::null_mut()
+ } else {
+ let mut res = Vec::with_capacity(len + 1);
+
+ res.push(len as u32);
+
+ for i in items {
+ res.push(i.clone().into());
+ }
+
+ assert!(res.len() == len + 1);
+
+ let raw = res.as_mut_ptr();
+ mem::forget(res);
+
+ unsafe { raw.offset(1) }
+ }
+ }
+
+ extern "C" fn cb_registers_full_width<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let regs = custom_arch.registers_full_width();
+
+ alloc_register_list(regs.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_registers_all<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let regs = custom_arch.registers_all();
+
+ alloc_register_list(regs.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_registers_global<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let regs = custom_arch.registers_global();
+
+ alloc_register_list(regs.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_flags<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let flags = custom_arch.flags();
+
+ alloc_register_list(flags.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_flag_write_types<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let flag_writes = custom_arch.flag_write_types();
+
+ alloc_register_list(flag_writes.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_semantic_flag_classes<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let flag_classes = custom_arch.flag_classes();
+
+ alloc_register_list(flag_classes.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_semantic_flag_groups<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let flag_groups = custom_arch.flag_groups();
+
+ alloc_register_list(flag_groups.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_flag_role<A>(ctxt: *mut c_void, flag: u32, class: u32) -> BNFlagRole
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let (Some(flag), class) = (custom_arch.flag_from_id(flag), custom_arch.flag_class_from_id(class)) {
+ flag.role(class)
+ } else {
+ FlagRole::SpecialFlagRole
+ }
+ }
+
+ extern "C" fn cb_flags_required_for_flag_cond<A>(ctxt: *mut c_void, cond: BNLowLevelILFlagCondition, class: u32,
+ count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let class = custom_arch.flag_class_from_id(class);
+ let flags = custom_arch.flags_required_for_flag_condition(cond, class);
+
+ alloc_register_list(flags.iter().map(|r| r.id()), unsafe { &mut *count })
+ }
+
+ extern "C" fn cb_flags_required_for_semantic_flag_group<A>(ctxt: *mut c_void, group: u32, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let Some(group) = custom_arch.flag_group_from_id(group) {
+ let flags = group.flags_required();
+ alloc_register_list(flags.iter().map(|r| r.id()), unsafe { &mut *count })
+ } else {
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+ }
+
+ extern "C" fn cb_flag_conditions_for_semantic_flag_group<A>(ctxt: *mut c_void, group: u32, count: *mut usize)
+ -> *mut BNFlagConditionForSemanticClass
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let Some(group) = custom_arch.flag_group_from_id(group) {
+ let flag_conditions = group.flag_conditions();
+
+ unsafe {
+ let allocation_size = mem::size_of::<BNFlagConditionForSemanticClass>() * flag_conditions.len();
+ let result = libc::malloc(allocation_size) as *mut BNFlagConditionForSemanticClass;
+ let out_slice = slice::from_raw_parts_mut(result, flag_conditions.len());
+
+ for (i, (class, cond)) in flag_conditions.iter().enumerate() {
+ let out = out_slice.get_unchecked_mut(i);
+
+ out.semanticClass = class.id();
+ out.condition = *cond;
+ }
+
+ *count = flag_conditions.len();
+ result
+ }
+ } else {
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+ }
+
+ extern "C" fn cb_free_flag_conditions_for_semantic_flag_group<A>(_ctxt: *mut c_void, conds: *mut BNFlagConditionForSemanticClass)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ unsafe { libc::free(conds as *mut _); }
+ }
+
+ extern "C" fn cb_flags_written_by_write_type<A>(ctxt: *mut c_void, write_type: u32, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let Some(write_type) = custom_arch.flag_write_from_id(write_type) {
+ let written = write_type.flags_written();
+ alloc_register_list(written.iter().map(|f| f.id()), unsafe { &mut *count })
+ } else {
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+ }
+
+ extern "C" fn cb_semantic_class_for_flag_write_type<A>(ctxt: *mut c_void, write_type: u32) -> u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ custom_arch.flag_write_from_id(write_type).map(|w| w.id()).unwrap_or(0)
+ }
+
+ extern "C" fn cb_flag_write_llil<A>(ctxt: *mut c_void, op: BNLowLevelILOperation, size: usize, flag_write: u32,
+ flag: u32, operands_raw: *mut BNRegisterOrConstant, operand_count: usize,
+ il: *mut BNLowLevelILFunction) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch_handle = CustomArchitectureHandle {
+ handle: ctxt as *mut A
+ };
+
+ let flag_write = custom_arch.flag_write_from_id(flag_write);
+ let flag = custom_arch.flag_from_id(flag);
+ let operands = unsafe { slice::from_raw_parts(operands_raw, operand_count) };
+ let mut lifter = unsafe { Lifter::from_raw(custom_arch_handle, il) };
+
+ if let (Some(flag_write), Some(flag)) = (flag_write, flag) {
+ if let Some(op) = FlagWriteOp::from_op(custom_arch, size, op, operands) {
+ if let Some(expr) = custom_arch.flag_write_llil(flag, flag_write, op, &mut lifter) {
+ // TODO verify that returned expr is a bool value
+ return expr.expr_idx;
+ }
+ } else {
+ warn!("unable to unpack flag write op: {:?} with {} operands", op, operands.len());
+ }
+
+ let role = flag.role(flag_write.class());
+
+ unsafe {
+ BNGetDefaultArchitectureFlagWriteLowLevelIL(custom_arch.as_ref().0, op, size,
+ role, operands_raw, operand_count, il)
+ }
+ } else {
+ // TODO this should be impossible; requires bad flag/flag_write ids passed in;
+ // explode more violently
+ lifter.unimplemented().expr_idx
+ }
+ }
+
+ extern "C" fn cb_flag_cond_llil<A>(ctxt: *mut c_void, cond: FlagCondition, class: u32,
+ il: *mut BNLowLevelILFunction) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch_handle = CustomArchitectureHandle {
+ handle: ctxt as *mut A
+ };
+
+ let class = custom_arch.flag_class_from_id(class);
+
+ let mut lifter = unsafe { Lifter::from_raw(custom_arch_handle, il) };
+ if let Some(expr) = custom_arch.flag_cond_llil(cond, class, &mut lifter) {
+ // TODO verify that returned expr is a bool value
+ return expr.expr_idx;
+ }
+
+ lifter.unimplemented().expr_idx
+ }
+
+ extern "C" fn cb_flag_group_llil<A>(ctxt: *mut c_void, group: u32,
+ il: *mut BNLowLevelILFunction) -> usize
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch_handle = CustomArchitectureHandle {
+ handle: ctxt as *mut A
+ };
+
+ let mut lifter = unsafe { Lifter::from_raw(custom_arch_handle, il) };
+
+ if let Some(group) = custom_arch.flag_group_from_id(group) {
+ if let Some(expr) = custom_arch.flag_group_llil(group, &mut lifter) {
+ // TODO verify that returned expr is a bool value
+ return expr.expr_idx;
+ }
+ }
+
+ lifter.unimplemented().expr_idx
+ }
+
+ extern "C" fn cb_free_register_list(_ctxt: *mut c_void, regs: *mut u32) {
+ if regs.is_null() {
+ return;
+ }
+
+ unsafe {
+ let actual_start = regs.offset(-1);
+ let len = *actual_start + 1;
+ let _regs = Vec::from_raw_parts(actual_start, len as usize, len as usize);
+ }
+ }
+
+ extern "C" fn cb_register_info<A>(ctxt: *mut c_void, reg: u32, result: *mut BNRegisterInfo)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let result = unsafe { &mut *result };
+
+ if let Some(reg) = custom_arch.register_from_id(reg) {
+ let info = reg.info();
+
+ result.fullWidthRegister = match info.parent() {
+ Some(p) => p.id(),
+ None => reg.id(),
+ };
+
+ result.offset = info.offset();
+ result.size = info.size();
+ result.extend = info.implicit_extend();
+ }
+ }
+
+ extern "C" fn cb_stack_pointer<A>(ctxt: *mut c_void) -> u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let Some(reg) = custom_arch.stack_pointer_reg() {
+ reg.id()
+ } else {
+ 0xffff_ffff
+ }
+ }
+
+ extern "C" fn cb_link_reg<A>(ctxt: *mut c_void) -> u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ if let Some(reg) = custom_arch.link_reg() {
+ reg.id()
+ } else {
+ 0xffff_ffff
+ }
+ }
+
+ extern "C" fn cb_reg_stack_name<A>(ctxt: *mut c_void, _stack: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ BnString::new("reg_stack").into_raw()
+ }
+
+ extern "C" fn cb_reg_stacks<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+
+ extern "C" fn cb_reg_stack_info<A>(ctxt: *mut c_void, _stack: u32, _info: *mut BNRegisterStackInfo)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ }
+
+ extern "C" fn cb_intrinsic_name<A>(ctxt: *mut c_void, _intrinsic: u32) -> *mut c_char
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ BnString::new("intrinsic").into_raw()
+ }
+
+ extern "C" fn cb_intrinsics<A>(ctxt: *mut c_void, count: *mut usize) -> *mut u32
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+
+ extern "C" fn cb_intrinsic_inputs<A>(ctxt: *mut c_void, _intrinsic: u32, count: *mut usize) -> *mut BNNameAndType
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+
+ extern "C" fn cb_free_name_and_types<A>(ctxt: *mut c_void, _nt: *mut BNNameAndType, _count: usize)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ }
+
+ extern "C" fn cb_intrinsic_outputs<A>(ctxt: *mut c_void, _intrinsic: u32, count: *mut usize) -> *mut BNTypeWithConfidence
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+
+ unsafe { *count = 0; }
+ ptr::null_mut()
+ }
+
+ extern "C" fn cb_free_type_list<A>(ctxt: *mut c_void, _tl: *mut BNTypeWithConfidence, _count: usize)
+ where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync,
+ {
+ let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ }
+
+ extern "C" fn cb_assemble(_ctxt: *mut c_void, _code: *const c_char, _addr: u64,
+ _result: *mut BNDataBuffer, errors: *mut *mut c_char) -> bool
+ {
+ unsafe { *errors = ptr::null_mut(); }
+ false
+ }
+
+ extern "C" fn cb_patch_unavailable(_ctxt: *mut c_void, _data: *const u8, _addr: u64, _len: usize) -> bool {
+ false
+ }
+
+ extern "C" fn cb_do_patch_unavailable(_ctxt: *mut c_void, _data: *mut u8, _addr: u64, _len: usize) -> bool {
+ false
+ }
+
+ extern "C" fn cb_skip_patch_unavailable(_ctxt: *mut c_void, _data: *mut u8, _addr: u64, _len: usize, _val: u64) -> bool {
+ false
+ }
+
+ let name = name.as_bytes_with_nul();
+
+ let uninit_arch = ArchitectureBuilder {
+ arch: unsafe { mem::uninitialized() },
+ func: func,
+ };
+
+ let raw = Box::into_raw(Box::new(uninit_arch));
+ let mut custom_arch = BNCustomArchitecture {
+ context: raw as *mut _,
+ init: Some(cb_init::<A, F>),
+ getEndianness: Some(cb_endianness::<A>),
+ getAddressSize: Some(cb_address_size::<A>),
+ getDefaultIntegerSize: Some(cb_default_integer_size::<A>),
+ getInstructionAlignment: Some(cb_instruction_alignment::<A>),
+ getMaxInstructionLength: Some(cb_max_instr_len::<A>),
+ getOpcodeDisplayLength: Some(cb_opcode_display_len::<A>),
+ getAssociatedArchitectureByAddress: Some(cb_associated_arch_by_addr::<A>),
+ getInstructionInfo: Some(cb_instruction_info::<A>),
+ getInstructionText: Some(cb_get_instruction_text::<A>),
+ freeInstructionText: Some(cb_free_instruction_text),
+ getInstructionLowLevelIL: Some(cb_instruction_llil::<A>),
+
+ getRegisterName: Some(cb_reg_name::<A>),
+ getFlagName: Some(cb_flag_name::<A>),
+ getFlagWriteTypeName: Some(cb_flag_write_name::<A>),
+ getSemanticFlagClassName: Some(cb_semantic_flag_class_name::<A>),
+ getSemanticFlagGroupName: Some(cb_semantic_flag_group_name::<A>),
+
+ getFullWidthRegisters: Some(cb_registers_full_width::<A>),
+ getAllRegisters: Some(cb_registers_all::<A>),
+ getAllFlags: Some(cb_flags::<A>),
+ getAllFlagWriteTypes: Some(cb_flag_write_types::<A>),
+ getAllSemanticFlagClasses: Some(cb_semantic_flag_classes::<A>),
+ getAllSemanticFlagGroups: Some(cb_semantic_flag_groups::<A>),
+
+ getFlagRole: Some(cb_flag_role::<A>),
+ getFlagsRequiredForFlagCondition: Some(cb_flags_required_for_flag_cond::<A>),
+
+ getFlagsRequiredForSemanticFlagGroup: Some(cb_flags_required_for_semantic_flag_group::<A>),
+ getFlagConditionsForSemanticFlagGroup: Some(cb_flag_conditions_for_semantic_flag_group::<A>),
+ freeFlagConditionsForSemanticFlagGroup: Some(cb_free_flag_conditions_for_semantic_flag_group::<A>),
+
+ getFlagsWrittenByFlagWriteType: Some(cb_flags_written_by_write_type::<A>),
+ getSemanticClassForFlagWriteType: Some(cb_semantic_class_for_flag_write_type::<A>),
+
+ getFlagWriteLowLevelIL: Some(cb_flag_write_llil::<A>),
+ getFlagConditionLowLevelIL: Some(cb_flag_cond_llil::<A>),
+ getSemanticFlagGroupLowLevelIL: Some(cb_flag_group_llil::<A>),
+
+ freeRegisterList: Some(cb_free_register_list),
+ getRegisterInfo: Some(cb_register_info::<A>),
+ getStackPointerRegister: Some(cb_stack_pointer::<A>),
+ getLinkRegister: Some(cb_link_reg::<A>),
+ getGlobalRegisters: Some(cb_registers_global::<A>),
+
+ getRegisterStackName: Some(cb_reg_stack_name::<A>),
+ getAllRegisterStacks: Some(cb_reg_stacks::<A>),
+ getRegisterStackInfo: Some(cb_reg_stack_info::<A>),
+
+ getIntrinsicName: Some(cb_intrinsic_name::<A>),
+ getAllIntrinsics: Some(cb_intrinsics::<A>),
+ getIntrinsicInputs: Some(cb_intrinsic_inputs::<A>),
+ freeNameAndTypeList: Some(cb_free_name_and_types::<A>),
+ getIntrinsicOutputs: Some(cb_intrinsic_outputs::<A>),
+ freeTypeList: Some(cb_free_type_list::<A>),
+
+ assemble: Some(cb_assemble),
+
+ isNeverBranchPatchAvailable: Some(cb_patch_unavailable),
+ isAlwaysBranchPatchAvailable: Some(cb_patch_unavailable),
+ isInvertBranchPatchAvailable: Some(cb_patch_unavailable),
+ isSkipAndReturnZeroPatchAvailable: Some(cb_patch_unavailable),
+ isSkipAndReturnValuePatchAvailable: Some(cb_patch_unavailable),
+
+ convertToNop: Some(cb_do_patch_unavailable),
+ alwaysBranch: Some(cb_do_patch_unavailable),
+ invertBranch: Some(cb_do_patch_unavailable),
+ skipAndReturnValue: Some(cb_skip_patch_unavailable),
+ };
+
+ unsafe {
+ let res = BNRegisterArchitecture(name.as_ref().as_ptr() as *mut _, &mut custom_arch as *mut _);
+
+ assert!(!res.is_null());
+
+ &(*raw).arch
+ }
+}
+
+pub struct CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync
+{
+ handle: *mut A
+}
+
+unsafe impl<A> Send for CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync
+{}
+
+unsafe impl<A> Sync for CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=CustomArchitectureHandle<A>> + Send + Sync
+{}
+
+impl<A> Clone for CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=Self> + Send + Sync
+{
+ fn clone(&self) -> Self {
+ Self { handle: self.handle }
+ }
+}
+
+impl<A> Copy for CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=Self> + Send + Sync
+{
+}
+
+impl<A> Borrow<A> for CustomArchitectureHandle<A>
+where
+ A: 'static + Architecture<Handle=Self> + Send + Sync
+{
+ fn borrow(&self) -> &A {
+ unsafe { &*self.handle }
+ }
+}