summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2023-12-19 22:39:11 -0700
committerRusty Wagner <rusty.wagner@gmail.com>2024-01-04 11:02:14 -0700
commit0748dfe65398f17064ed744a3d198f144d0aa2c5 (patch)
treeadde2cf25a4b9812c8322ed326f361b23c1681e5
parente9e5c3e3568351e99c5034e49ae21f0b8d12a4c2 (diff)
Support intrinsics in Rust architecture plugins
-rw-r--r--.gitignore1
-rw-r--r--rust/src/architecture.rs345
-rw-r--r--rust/src/llil/expression.rs99
-rw-r--r--rust/src/llil/instruction.rs8
-rw-r--r--rust/src/llil/lifting.rs97
-rw-r--r--rust/src/llil/operation.rs17
-rw-r--r--rust/src/types.rs13
7 files changed, 520 insertions, 60 deletions
diff --git a/.gitignore b/.gitignore
index be6cf3df..b8280223 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ python/generator.exe
python/generator.log
python/generator.tlog
.cache/
+target/
# Unit Tests
suite/unit.py
diff --git a/rust/src/architecture.rs b/rust/src/architecture.rs
index 1bf22423..006dc839 100644
--- a/rust/src/architecture.rs
+++ b/rust/src/architecture.rs
@@ -37,6 +37,7 @@ use crate::{
rc::*,
string::BnStrCompatible,
string::*,
+ types::{Conf, NameAndType, Type},
{BranchType, Endianness},
};
@@ -273,6 +274,19 @@ pub trait FlagGroup: Sized + Clone + Copy {
fn flag_conditions(&self) -> HashMap<Self::FlagClass, FlagCondition>;
}
+pub trait Intrinsic: Sized + Clone + Copy {
+ fn name(&self) -> Cow<str>;
+
+ /// Unique identifier for this `Intrinsic`.
+ fn id(&self) -> u32;
+
+ /// Reeturns the list of the input names and types for this intrinsic.
+ fn inputs(&self) -> Vec<NameAndType<String>>;
+
+ /// Returns the list of the output types for this intrinsic.
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>>;
+}
+
pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
type Handle: Borrow<Self> + Clone;
@@ -284,6 +298,8 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
type FlagClass: FlagClass;
type FlagGroup: FlagGroup<FlagType = Self::Flag, FlagClass = Self::FlagClass>;
+ type Intrinsic: Intrinsic;
+
fn endianness(&self) -> Endianness;
fn address_size(&self) -> usize;
fn default_integer_size(&self) -> usize;
@@ -333,9 +349,11 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
/// 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>;
+ _condition: FlagCondition,
+ _class: Option<Self::FlagClass>,
+ ) -> Vec<Self::Flag> {
+ Vec::new()
+ }
/// This function *MUST NOT* append instructions that have side effects.
///
@@ -368,32 +386,143 @@ pub trait Architecture: 'static + Sized + AsRef<CoreArchitecture> {
/// `flags_required` method.
fn flag_group_llil<'a>(
&self,
- group: Self::FlagGroup,
- il: &'a mut Lifter<Self>,
- ) -> Option<LiftedExpr<'a, Self>>;
+ _group: Self::FlagGroup,
+ _il: &'a mut Lifter<Self>,
+ ) -> Option<LiftedExpr<'a, Self>> {
+ None
+ }
fn registers_all(&self) -> Vec<Self::Register>;
fn registers_full_width(&self) -> Vec<Self::Register>;
- fn registers_global(&self) -> Vec<Self::Register>;
- fn registers_system(&self) -> Vec<Self::Register>;
+ fn registers_global(&self) -> Vec<Self::Register> {
+ Vec::new()
+ }
+ fn registers_system(&self) -> Vec<Self::Register> {
+ Vec::new()
+ }
- 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 flags(&self) -> Vec<Self::Flag> {
+ Vec::new()
+ }
+ fn flag_write_types(&self) -> Vec<Self::FlagWrite> {
+ Vec::new()
+ }
+ fn flag_classes(&self) -> Vec<Self::FlagClass> {
+ Vec::new()
+ }
+ fn flag_groups(&self) -> Vec<Self::FlagGroup> {
+ Vec::new()
+ }
fn stack_pointer_reg(&self) -> Option<Self::Register>;
- fn link_reg(&self) -> Option<Self::Register>;
+ fn link_reg(&self) -> Option<Self::Register> {
+ None
+ }
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 flag_from_id(&self, _id: u32) -> Option<Self::Flag> {
+ None
+ }
+ fn flag_write_from_id(&self, _id: u32) -> Option<Self::FlagWrite> {
+ None
+ }
+ fn flag_class_from_id(&self, _id: u32) -> Option<Self::FlagClass> {
+ None
+ }
+ fn flag_group_from_id(&self, _id: u32) -> Option<Self::FlagGroup> {
+ None
+ }
+
+ fn intrinsics(&self) -> Vec<Self::Intrinsic> {
+ Vec::new()
+ }
+ fn intrinsic_from_id(&self, _id: u32) -> Option<Self::Intrinsic> {
+ None
+ }
fn handle(&self) -> Self::Handle;
}
+/// Type for architrectures that do not use flags. Will panic if accessed as a flag.
+#[derive(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) -> u32 {
+ 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) -> u32 {
+ unreachable!()
+ }
+ fn flags_written(&self) -> Vec<Self::FlagType> {
+ unreachable!()
+ }
+}
+
+impl FlagClass for UnusedFlag {
+ fn name(&self) -> Cow<str> {
+ unreachable!()
+ }
+ fn id(&self) -> u32 {
+ unreachable!()
+ }
+}
+
+impl FlagGroup for UnusedFlag {
+ type FlagType = Self;
+ type FlagClass = Self;
+ fn name(&self) -> Cow<str> {
+ unreachable!()
+ }
+ fn id(&self) -> u32 {
+ unreachable!()
+ }
+ fn flags_required(&self) -> Vec<Self::FlagType> {
+ unreachable!()
+ }
+ fn flag_conditions(&self) -> HashMap<Self, FlagCondition> {
+ unreachable!()
+ }
+}
+
+/// Type for architrectures that do not use intrinsics. Will panic if accessed as an intrinsic.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct UnusedIntrinsic;
+
+impl Intrinsic for UnusedIntrinsic {
+ fn name(&self) -> Cow<str> {
+ unreachable!()
+ }
+ fn id(&self) -> u32 {
+ unreachable!()
+ }
+ fn inputs(&self) -> Vec<NameAndType<String>> {
+ unreachable!()
+ }
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
+ unreachable!()
+ }
+}
+
pub struct CoreRegisterInfo(*mut BNArchitecture, u32, BNRegisterInfo);
impl RegisterInfo for CoreRegisterInfo {
type RegType = CoreRegister;
@@ -639,6 +768,65 @@ impl FlagGroup for CoreFlagGroup {
}
}
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub struct CoreIntrinsic(*mut BNArchitecture, u32);
+
+impl Intrinsic for crate::architecture::CoreIntrinsic {
+ fn name(&self) -> Cow<str> {
+ unsafe {
+ let name = BNGetArchitectureIntrinsicName(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 inputs(&self) -> Vec<NameAndType<String>> {
+ let mut count: usize = 0;
+
+ unsafe {
+ let inputs = BNGetArchitectureIntrinsicInputs(self.0, self.1, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(inputs, count)
+ .iter()
+ .map(|input| NameAndType::from_raw(input))
+ .collect();
+
+ BNFreeNameAndTypeList(inputs, count);
+
+ ret
+ }
+ }
+
+ fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
+ let mut count: usize = 0;
+
+ unsafe {
+ let inputs = BNGetArchitectureIntrinsicOutputs(self.0, self.1, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(inputs, count)
+ .iter()
+ .map(|input| (*input).into())
+ .collect();
+
+ BNFreeOutputTypeList(inputs, count);
+
+ ret
+ }
+ }
+}
+
pub struct CoreArchitectureList(*mut *mut BNArchitecture, usize);
impl ops::Deref for CoreArchitectureList {
type Target = [CoreArchitecture];
@@ -703,6 +891,7 @@ impl Architecture for CoreArchitecture {
type FlagWrite = CoreFlagWrite;
type FlagClass = CoreFlagClass;
type FlagGroup = CoreFlagGroup;
+ type Intrinsic = CoreIntrinsic;
fn endianness(&self) -> Endianness {
unsafe { BNGetArchitectureEndianness(self.0) }
@@ -1012,6 +1201,27 @@ impl Architecture for CoreArchitecture {
Some(CoreFlagGroup(self.0, id))
}
+ fn intrinsics(&self) -> Vec<CoreIntrinsic> {
+ unsafe {
+ let mut count: usize = 0;
+ let intrinsics = BNGetAllArchitectureIntrinsics(self.0, &mut count as *mut _);
+
+ let ret = slice::from_raw_parts_mut(intrinsics, count)
+ .iter()
+ .map(|reg| CoreIntrinsic(self.0, *reg))
+ .collect();
+
+ BNFreeRegisterList(intrinsics);
+
+ ret
+ }
+ }
+
+ fn intrinsic_from_id(&self, id: u32) -> Option<CoreIntrinsic> {
+ // TODO validate in debug builds
+ Some(CoreIntrinsic(self.0, id))
+ }
+
fn handle(&self) -> CoreArchitecture {
*self
}
@@ -1791,76 +2001,125 @@ where
let _custom_arch = unsafe { &*(ctxt as *mut A) };
}
- extern "C" fn cb_intrinsic_name<A>(ctxt: *mut c_void, _intrinsic: u32) -> *mut c_char
+ 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()
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ match custom_arch.intrinsic_from_id(intrinsic) {
+ Some(intrinsic) => BnString::new(intrinsic.name().as_ref()).into_raw(),
+ None => BnString::new("invalid_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()
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
+ let intrinsics = custom_arch.intrinsics();
+ alloc_register_list(intrinsics.iter().map(|i| i.id()), unsafe { &mut *count })
}
extern "C" fn cb_intrinsic_inputs<A>(
ctxt: *mut c_void,
- _intrinsic: u32,
+ intrinsic: u32,
count: *mut usize,
) -> *mut BNNameAndType
where
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
{
- let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
- unsafe {
- *count = 0;
+ if let Some(intrinsic) = custom_arch.intrinsic_from_id(intrinsic) {
+ let inputs = intrinsic.inputs();
+ let mut res = Vec::with_capacity(inputs.len());
+ for input in inputs {
+ res.push(input.into_raw());
+ }
+
+ unsafe {
+ *count = res.len();
+ if res.len() == 0 {
+ ptr::null_mut()
+ } else {
+ let raw = res.as_mut_ptr();
+ mem::forget(res);
+ raw
+ }
+ }
+ } else {
+ unsafe {
+ *count = 0;
+ }
+ ptr::null_mut()
}
- ptr::null_mut()
}
- extern "C" fn cb_free_name_and_types<A>(
- ctxt: *mut c_void,
- _nt: *mut BNNameAndType,
- _count: usize,
- ) where
+ 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) };
+
+ if !nt.is_null() {
+ unsafe {
+ let list = Vec::from_raw_parts(nt, count, count);
+ for nt in list {
+ BnString::from_raw(nt.name);
+ }
+ }
+ }
}
extern "C" fn cb_intrinsic_outputs<A>(
ctxt: *mut c_void,
- _intrinsic: u32,
+ intrinsic: u32,
count: *mut usize,
) -> *mut BNTypeWithConfidence
where
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
{
- let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ let custom_arch = unsafe { &*(ctxt as *mut A) };
- unsafe {
- *count = 0;
+ if let Some(intrinsic) = custom_arch.intrinsic_from_id(intrinsic) {
+ let inputs = intrinsic.outputs();
+ let mut res = Vec::with_capacity(inputs.len());
+ for input in inputs {
+ res.push(input.into());
+ }
+
+ unsafe {
+ *count = res.len();
+ if res.len() == 0 {
+ ptr::null_mut()
+ } else {
+ let raw = res.as_mut_ptr();
+ mem::forget(res);
+ raw
+ }
+ }
+ } else {
+ unsafe {
+ *count = 0;
+ }
+ ptr::null_mut()
}
- ptr::null_mut()
}
extern "C" fn cb_free_type_list<A>(
ctxt: *mut c_void,
- _tl: *mut BNTypeWithConfidence,
- _count: usize,
+ tl: *mut BNTypeWithConfidence,
+ count: usize,
) where
A: 'static + Architecture<Handle = CustomArchitectureHandle<A>> + Send + Sync,
{
let _custom_arch = unsafe { &*(ctxt as *mut A) };
+ if !tl.is_null() {
+ unsafe {
+ let _list = Vec::from_raw_parts(tl, count, count);
+ }
+ }
}
// TODO : I have no idea what I'm doing and this is likely wrong!
diff --git a/rust/src/llil/expression.rs b/rust/src/llil/expression.rs
index 2898d89f..60d13521 100644
--- a/rust/src/llil/expression.rs
+++ b/rust/src/llil/expression.rs
@@ -149,6 +149,31 @@ where
LLIL_BOOL_TO_INT => ExprInfo::BoolToInt(Operation::new(function, op)),
+ LLIL_FADD => ExprInfo::Fadd(Operation::new(function, op)),
+ LLIL_FSUB => ExprInfo::Fsub(Operation::new(function, op)),
+ LLIL_FMUL => ExprInfo::Fmul(Operation::new(function, op)),
+ LLIL_FDIV => ExprInfo::Fdiv(Operation::new(function, op)),
+
+ LLIL_FSQRT => ExprInfo::Fsqrt(Operation::new(function, op)),
+ LLIL_FNEG => ExprInfo::Fneg(Operation::new(function, op)),
+ LLIL_FABS => ExprInfo::Fabs(Operation::new(function, op)),
+ LLIL_FLOAT_TO_INT => ExprInfo::FloatToInt(Operation::new(function, op)),
+ LLIL_INT_TO_FLOAT => ExprInfo::IntToFloat(Operation::new(function, op)),
+ LLIL_FLOAT_CONV => ExprInfo::FloatConv(Operation::new(function, op)),
+ LLIL_ROUND_TO_INT => ExprInfo::RoundToInt(Operation::new(function, op)),
+ LLIL_FLOOR => ExprInfo::Floor(Operation::new(function, op)),
+ LLIL_CEIL => ExprInfo::Ceil(Operation::new(function, op)),
+ LLIL_FTRUNC => ExprInfo::Ftrunc(Operation::new(function, op)),
+
+ LLIL_FCMP_E => ExprInfo::FcmpE(Operation::new(function, op)),
+ LLIL_FCMP_NE => ExprInfo::FcmpNE(Operation::new(function, op)),
+ LLIL_FCMP_LT => ExprInfo::FcmpLT(Operation::new(function, op)),
+ LLIL_FCMP_LE => ExprInfo::FcmpLE(Operation::new(function, op)),
+ LLIL_FCMP_GT => ExprInfo::FcmpGT(Operation::new(function, op)),
+ LLIL_FCMP_GE => ExprInfo::FcmpGE(Operation::new(function, op)),
+ LLIL_FCMP_O => ExprInfo::FcmpO(Operation::new(function, op)),
+ LLIL_FCMP_UO => ExprInfo::FcmpUO(Operation::new(function, op)),
+
LLIL_UNIMPL => ExprInfo::Unimpl(Operation::new(function, op)),
LLIL_UNIMPL_MEM => ExprInfo::UnimplMem(Operation::new(function, op)),
@@ -188,7 +213,9 @@ where
match *info {
CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
- | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) | CmpUgt(ref op) => {
+ | CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op) | CmpUgt(ref op)
+ | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op) | FcmpGE(ref op)
+ | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => {
visit!(f, &op.left());
visit!(f, &op.right());
}
@@ -201,7 +228,8 @@ where
Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
| Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op) | MulsDp(ref op)
- | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) | Mods(ref op) => {
+ | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op) | Mods(ref op)
+ | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => {
visit!(f, &op.left());
visit!(f, &op.right());
}
@@ -213,7 +241,9 @@ where
}
Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
- | BoolToInt(ref op) => {
+ | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op) | FloatToInt(ref op)
+ | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) | Floor(ref op)
+ | Ceil(ref op) | Ftrunc(ref op) => {
visit!(f, &op.operand());
}
@@ -412,6 +442,30 @@ where
//TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO
BoolToInt(Operation<'func, A, M, F, operation::UnaryOp>),
+ Fadd(Operation<'func, A, M, F, operation::BinaryOp>),
+ Fsub(Operation<'func, A, M, F, operation::BinaryOp>),
+ Fmul(Operation<'func, A, M, F, operation::BinaryOp>),
+ Fdiv(Operation<'func, A, M, F, operation::BinaryOp>),
+ Fsqrt(Operation<'func, A, M, F, operation::UnaryOp>),
+ Fneg(Operation<'func, A, M, F, operation::UnaryOp>),
+ Fabs(Operation<'func, A, M, F, operation::UnaryOp>),
+ FloatToInt(Operation<'func, A, M, F, operation::UnaryOp>),
+ IntToFloat(Operation<'func, A, M, F, operation::UnaryOp>),
+ FloatConv(Operation<'func, A, M, F, operation::UnaryOp>),
+ RoundToInt(Operation<'func, A, M, F, operation::UnaryOp>),
+ Floor(Operation<'func, A, M, F, operation::UnaryOp>),
+ Ceil(Operation<'func, A, M, F, operation::UnaryOp>),
+ Ftrunc(Operation<'func, A, M, F, operation::UnaryOp>),
+
+ FcmpE(Operation<'func, A, M, F, operation::Condition>),
+ FcmpNE(Operation<'func, A, M, F, operation::Condition>),
+ FcmpLT(Operation<'func, A, M, F, operation::Condition>),
+ FcmpLE(Operation<'func, A, M, F, operation::Condition>),
+ FcmpGE(Operation<'func, A, M, F, operation::Condition>),
+ FcmpGT(Operation<'func, A, M, F, operation::Condition>),
+ FcmpO(Operation<'func, A, M, F, operation::Condition>),
+ FcmpUO(Operation<'func, A, M, F, operation::Condition>),
+
// TODO ADD_OVERFLOW
Unimpl(Operation<'func, A, M, F, operation::NoArgs>),
UnimplMem(Operation<'func, A, M, F, operation::UnimplMem>),
@@ -467,7 +521,8 @@ where
match *self {
CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
| CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
- | CmpUgt(ref op) => Some(op),
+ | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
+ | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => Some(op),
_ => None,
}
}
@@ -479,7 +534,7 @@ where
Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
| Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
| MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
- | Mods(ref op) => Some(op),
+ | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => Some(op),
_ => None,
}
}
@@ -511,7 +566,9 @@ where
match *self {
Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
- | BoolToInt(ref op) => Some(op),
+ | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
+ | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
+ | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => Some(op),
_ => None,
}
}
@@ -529,7 +586,8 @@ where
CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
| CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
- | CmpUgt(ref op) => &op.op,
+ | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
+ | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => &op.op,
Load(ref op) => &op.op,
@@ -548,12 +606,14 @@ where
Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
| Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
| MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
- | Mods(ref op) => &op.op,
+ | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => &op.op,
DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => &op.op,
Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
- | BoolToInt(ref op) => &op.op,
+ | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
+ | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
+ | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op,
UnimplMem(ref op) => &op.op,
//TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO
@@ -578,7 +638,9 @@ where
CmpE(ref _op) | CmpNe(ref _op) | CmpSlt(ref _op) | CmpUlt(ref _op)
| CmpSle(ref _op) | CmpUle(ref _op) | CmpSge(ref _op) | CmpUge(ref _op)
- | CmpSgt(ref _op) | CmpUgt(ref _op) => None,
+ | CmpSgt(ref _op) | CmpUgt(ref _op) | FcmpE(ref _op) | FcmpNE(ref _op)
+ | FcmpLT(ref _op) | FcmpLE(ref _op) | FcmpGE(ref _op) | FcmpGT(ref _op)
+ | FcmpO(ref _op) | FcmpUO(ref _op) => None,
Load(ref op) => op.flag_write(),
@@ -597,12 +659,16 @@ where
Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
| Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
| MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
- | Mods(ref op) => op.flag_write(),
+ | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => {
+ op.flag_write()
+ }
DivuDp(ref op) | DivsDp(ref op) | ModuDp(ref op) | ModsDp(ref op) => op.flag_write(),
Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
- | BoolToInt(ref op) => op.flag_write(),
+ | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
+ | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
+ | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(),
UnimplMem(ref op) => op.flag_write(),
//TestBit(Operation<'func, A, M, F, operation::TestBit>), // TODO
@@ -629,7 +695,8 @@ where
CmpE(ref op) | CmpNe(ref op) | CmpSlt(ref op) | CmpUlt(ref op) | CmpSle(ref op)
| CmpUle(ref op) | CmpSge(ref op) | CmpUge(ref op) | CmpSgt(ref op)
- | CmpUgt(ref op) => {
+ | CmpUgt(ref op) | FcmpE(ref op) | FcmpNE(ref op) | FcmpLT(ref op) | FcmpLE(ref op)
+ | FcmpGE(ref op) | FcmpGT(ref op) | FcmpO(ref op) | FcmpUO(ref op) => {
let left = op.left();
let right = op.right();
@@ -693,7 +760,7 @@ where
Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op)
| Lsr(ref op) | Asr(ref op) | Rol(ref op) | Ror(ref op) | Mul(ref op)
| MulsDp(ref op) | MuluDp(ref op) | Divu(ref op) | Divs(ref op) | Modu(ref op)
- | Mods(ref op) => {
+ | Mods(ref op) | Fadd(ref op) | Fsub(ref op) | Fmul(ref op) | Fdiv(ref op) => {
let left = op.left();
let right = op.right();
@@ -724,7 +791,9 @@ where
}
Neg(ref op) | Not(ref op) | Sx(ref op) | Zx(ref op) | LowPart(ref op)
- | BoolToInt(ref op) => write!(
+ | BoolToInt(ref op) | Fsqrt(ref op) | Fneg(ref op) | Fabs(ref op)
+ | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op)
+ | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => write!(
f,
"{:?}({}, {:?})",
op.op.operation,
diff --git a/rust/src/llil/instruction.rs b/rust/src/llil/instruction.rs
index e5ae508b..c9817dbf 100644
--- a/rust/src/llil/instruction.rs
+++ b/rust/src/llil/instruction.rs
@@ -112,6 +112,7 @@ where
InstrInfo::Call(Operation::new(self.function, op))
}
LLIL_SYSCALL => InstrInfo::Syscall(Operation::new(self.function, op)),
+ LLIL_INTRINSIC => InstrInfo::Intrinsic(Operation::new(self.function, op)),
_ => {
common_info(self.function, op).unwrap_or({
// Hopefully this is a bare value. If it isn't (expression
@@ -149,6 +150,12 @@ where
}
Push(ref op) => visit!(fb, &op.operand()),
Call(ref op) => visit!(fb, &op.target()),
+ Intrinsic(ref _op) => {
+ // TODO: Use this when we support expression lists
+ // for expr in op.source_exprs() {
+ // visit!(fb, expr);
+ // }
+ }
_ => visit!(common_visit, &info, fb),
}
@@ -181,6 +188,7 @@ where
Goto(Operation<'func, A, M, F, operation::Goto>),
Syscall(Operation<'func, A, M, F, operation::Syscall>),
+ Intrinsic(Operation<'func, A, M, F, operation::Intrinsic>),
Bp(Operation<'func, A, M, F, operation::NoArgs>),
Trap(Operation<'func, A, M, F, operation::Trap>),
Undef(Operation<'func, A, M, F, operation::NoArgs>),
diff --git a/rust/src/llil/lifting.rs b/rust/src/llil/lifting.rs
index eb7b36fd..bd023933 100644
--- a/rust/src/llil/lifting.rs
+++ b/rust/src/llil/lifting.rs
@@ -17,7 +17,9 @@ use std::mem;
use crate::architecture::Architecture;
use crate::architecture::Register as ArchReg;
-use crate::architecture::{Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite};
+use crate::architecture::{
+ Flag, FlagClass, FlagCondition, FlagGroup, FlagRole, FlagWrite, Intrinsic,
+};
use super::*;
@@ -866,6 +868,9 @@ impl<A> Function<A, Mutable, NonSSA<LiftedNonSSA>>
where
A: Architecture,
{
+ pub const NO_INPUTS: [ExpressionBuilder<'static, A, ValueExpr>; 0] = [];
+ pub const NO_OUTPUTS: [Register<A::Register>; 0] = [];
+
pub fn expression<'a, E: Liftable<'a, A>>(
&'a self,
expr: E,
@@ -1215,6 +1220,73 @@ where
}
}
+ pub fn intrinsic<'a, O, OL, I, P, PL>(
+ &'a self,
+ outputs: OL,
+ intrinsic: I,
+ inputs: PL,
+ ) -> ExpressionBuilder<'a, A, VoidExpr>
+ where
+ O: Into<Register<A::Register>>,
+ OL: IntoIterator<Item = O>,
+ I: Into<A::Intrinsic>,
+ P: Liftable<'a, A, Result = ValueExpr>,
+ PL: IntoIterator<Item = P>,
+ {
+ use binaryninjacore_sys::BNLowLevelILOperation::{LLIL_CALL_PARAM, LLIL_INTRINSIC};
+ use binaryninjacore_sys::{BNLowLevelILAddExpr, BNLowLevelILAddOperandList};
+
+ let mut outputs: Vec<u64> = outputs
+ .into_iter()
+ .map(|output| {
+ // TODO verify valid id
+ let output = match output.into() {
+ Register::ArchReg(r) => r.id(),
+ Register::Temp(r) => 0x8000_0000 | r,
+ };
+ output as u64
+ })
+ .collect();
+ let output_expr_idx =
+ unsafe { BNLowLevelILAddOperandList(self.handle, outputs.as_mut_ptr(), outputs.len()) };
+
+ let intrinsic: A::Intrinsic = intrinsic.into();
+
+ let mut inputs: Vec<u64> = inputs
+ .into_iter()
+ .map(|input| {
+ let input = P::lift(self, input);
+ input.expr_idx as u64
+ })
+ .collect();
+ let input_list_expr_idx =
+ unsafe { BNLowLevelILAddOperandList(self.handle, inputs.as_mut_ptr(), inputs.len()) };
+ let input_expr_idx = unsafe {
+ BNLowLevelILAddExpr(
+ self.handle,
+ LLIL_CALL_PARAM,
+ 0,
+ 0,
+ inputs.len() as u64,
+ input_list_expr_idx as u64,
+ 0,
+ 0,
+ )
+ };
+
+ ExpressionBuilder {
+ function: self,
+ op: LLIL_INTRINSIC,
+ size: 0,
+ flags: 0,
+ op1: outputs.len() as u64,
+ op2: output_expr_idx as u64,
+ op3: intrinsic.id() as u64,
+ op4: input_expr_idx as u64,
+ _ty: PhantomData,
+ }
+ }
+
sized_unary_op_lifter!(push, LLIL_PUSH, VoidExpr);
sized_no_arg_lifter!(pop, LLIL_POP, ValueExpr);
@@ -1276,6 +1348,29 @@ where
// TODO no flags
size_changing_unary_op_lifter!(bool_to_int, LLIL_BOOL_TO_INT, ValueExpr);
+ binary_op_lifter!(fadd, LLIL_FADD);
+ binary_op_lifter!(fsub, LLIL_FSUB);
+ binary_op_lifter!(fmul, LLIL_FMUL);
+ binary_op_lifter!(fdiv, LLIL_FDIV);
+ sized_unary_op_lifter!(fsqrt, LLIL_FSQRT, ValueExpr);
+ sized_unary_op_lifter!(fneg, LLIL_FNEG, ValueExpr);
+ sized_unary_op_lifter!(fabs, LLIL_FABS, ValueExpr);
+ sized_unary_op_lifter!(float_to_int, LLIL_FLOAT_TO_INT, ValueExpr);
+ sized_unary_op_lifter!(int_to_float, LLIL_INT_TO_FLOAT, ValueExpr);
+ sized_unary_op_lifter!(float_conv, LLIL_FLOAT_CONV, ValueExpr);
+ sized_unary_op_lifter!(round_to_int, LLIL_ROUND_TO_INT, ValueExpr);
+ sized_unary_op_lifter!(floor, LLIL_FLOOR, ValueExpr);
+ sized_unary_op_lifter!(ceil, LLIL_CEIL, ValueExpr);
+ sized_unary_op_lifter!(ftrunc, LLIL_FTRUNC, ValueExpr);
+ binary_op_lifter!(fcmp_e, LLIL_FCMP_E);
+ binary_op_lifter!(fcmp_ne, LLIL_FCMP_NE);
+ binary_op_lifter!(fcmp_lt, LLIL_FCMP_LT);
+ binary_op_lifter!(fcmp_le, LLIL_FCMP_LE);
+ binary_op_lifter!(fcmp_ge, LLIL_FCMP_GE);
+ binary_op_lifter!(fcmp_gt, LLIL_FCMP_GT);
+ binary_op_lifter!(fcmp_o, LLIL_FCMP_O);
+ binary_op_lifter!(fcmp_uo, LLIL_FCMP_UO);
+
pub fn current_address(&self) -> u64 {
use binaryninjacore_sys::BNLowLevelILGetCurrentAddress;
unsafe { BNLowLevelILGetCurrentAddress(self.handle) }
diff --git a/rust/src/llil/operation.rs b/rust/src/llil/operation.rs
index b998cce3..4daa7cb2 100644
--- a/rust/src/llil/operation.rs
+++ b/rust/src/llil/operation.rs
@@ -85,6 +85,22 @@ where
// LLIL_SYSCALL, LLIL_SYSCALL_SSA
pub struct Syscall;
+// LLIL_INTRINSIC, LLIL_INTRINSIC_SSA
+pub struct Intrinsic;
+
+impl<'func, A, M, V> Operation<'func, A, M, NonSSA<V>, Intrinsic>
+ where
+ A: 'func + Architecture,
+ M: FunctionMutability,
+ V: NonSSAVariant,
+{
+ // TODO: Support register and expression lists
+ pub fn intrinsic(&self) -> Option<A::Intrinsic> {
+ let raw_id = self.op.operands[2] as u32;
+ self.function.arch().intrinsic_from_id(raw_id)
+ }
+}
+
// LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA
pub struct SetReg;
@@ -617,6 +633,7 @@ pub trait OperationArguments: 'static {}
impl OperationArguments for NoArgs {}
impl OperationArguments for Pop {}
impl OperationArguments for Syscall {}
+impl OperationArguments for Intrinsic {}
impl OperationArguments for SetReg {}
impl OperationArguments for SetRegSplit {}
impl OperationArguments for SetFlag {}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index d86ffc82..04cb93fc 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -2446,7 +2446,7 @@ unsafe impl<'a> CoreArrayWrapper<'a> for QualifiedNameTypeAndId {
pub struct NameAndType<S: BnStrCompatible> {
pub name: S,
- t: Conf<Ref<Type>>,
+ pub t: Conf<Ref<Type>>,
}
impl NameAndType<String> {
@@ -2467,6 +2467,17 @@ impl<S: BnStrCompatible> NameAndType<S> {
}
}
+ pub(crate) fn into_raw(self) -> BNNameAndType {
+ let t = self.t.clone();
+ let res = BNNameAndType {
+ name: BnString::new(self.name).into_raw(),
+ type_: t.contents.handle,
+ typeConfidence: self.t.confidence,
+ };
+ mem::forget(t);
+ res
+ }
+
pub fn type_with_confidence(&self) -> Conf<Ref<Type>> {
self.t.clone()
}