diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2023-12-19 22:39:11 -0700 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-01-04 11:02:14 -0700 |
| commit | 0748dfe65398f17064ed744a3d198f144d0aa2c5 (patch) | |
| tree | adde2cf25a4b9812c8322ed326f361b23c1681e5 | |
| parent | e9e5c3e3568351e99c5034e49ae21f0b8d12a4c2 (diff) | |
Support intrinsics in Rust architecture plugins
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | rust/src/architecture.rs | 345 | ||||
| -rw-r--r-- | rust/src/llil/expression.rs | 99 | ||||
| -rw-r--r-- | rust/src/llil/instruction.rs | 8 | ||||
| -rw-r--r-- | rust/src/llil/lifting.rs | 97 | ||||
| -rw-r--r-- | rust/src/llil/operation.rs | 17 | ||||
| -rw-r--r-- | rust/src/types.rs | 13 |
7 files changed, 520 insertions, 60 deletions
@@ -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() } |
