diff options
| author | Mason Reed <mason@vector35.com> | 2025-05-09 14:00:38 -0400 |
|---|---|---|
| committer | Mason Reed <35282038+emesare@users.noreply.github.com> | 2025-05-12 17:45:24 -0400 |
| commit | 2a9beeec15d3f32312a0c4f8ad5ddbcfcbc97a89 (patch) | |
| tree | 5562dd4acafb32f6e9826a4247f910507cec4c8d /rust/src | |
| parent | 6617b0afa09f549d0a5c9c53063f3ad8ab82b7e4 (diff) | |
[Rust] Support SSA form properly in low level IL
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/low_level_il.rs | 54 | ||||
| -rw-r--r-- | rust/src/low_level_il/expression.rs | 250 | ||||
| -rw-r--r-- | rust/src/low_level_il/function.rs | 26 | ||||
| -rw-r--r-- | rust/src/low_level_il/instruction.rs | 108 | ||||
| -rw-r--r-- | rust/src/low_level_il/operation.rs | 669 |
5 files changed, 953 insertions, 154 deletions
diff --git a/rust/src/low_level_il.rs b/rust/src/low_level_il.rs index 453e0546..4c52e313 100644 --- a/rust/src/low_level_il.rs +++ b/rust/src/low_level_il.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::borrow::Cow; use std::fmt; // TODO : provide some way to forbid emitting register reads for certain registers @@ -20,7 +21,7 @@ use std::fmt; // requirements on load/store memory address sizes? // can reg/set_reg be used with sizes that differ from what is in BNRegisterInfo? -use crate::architecture::{Architecture, RegisterId}; +use crate::architecture::{Architecture, Flag, RegisterId}; use crate::architecture::{CoreRegister, Register as ArchReg}; use crate::function::Location; @@ -125,12 +126,19 @@ impl<R: ArchReg> LowLevelILRegisterKind<R> { LowLevelILRegisterKind::Temp(temp.into()) } - fn id(&self) -> RegisterId { + pub fn id(&self) -> RegisterId { match *self { LowLevelILRegisterKind::Arch(ref r) => r.id(), LowLevelILRegisterKind::Temp(temp) => temp.id(), } } + + pub fn name(&self) -> Cow<str> { + match *self { + LowLevelILRegisterKind::Arch(ref r) => r.name(), + LowLevelILRegisterKind::Temp(temp) => Cow::Owned(format!("temp{}", temp.temp_id)), + } + } } impl<R: ArchReg> fmt::Debug for LowLevelILRegisterKind<R> { @@ -149,19 +157,51 @@ impl From<LowLevelILTempRegister> for LowLevelILRegisterKind<CoreRegister> { } #[derive(Copy, Clone, Debug)] -pub enum LowLevelILSSARegister<R: ArchReg> { - Full(LowLevelILRegisterKind<R>, u32), // no such thing as partial access to a temp register, I think - Partial(R, u32, R), // partial accesses only possible for arch registers, I think +pub enum LowLevelILSSARegisterKind<R: ArchReg> { + Full { + kind: LowLevelILRegisterKind<R>, + version: u32, + }, + Partial { + full_reg: CoreRegister, + partial_reg: CoreRegister, + version: u32, + }, } -impl<R: ArchReg> LowLevelILSSARegister<R> { +impl<R: ArchReg> LowLevelILSSARegisterKind<R> { + pub fn new_full(kind: LowLevelILRegisterKind<R>, version: u32) -> Self { + Self::Full { kind, version } + } + + pub fn new_partial(full_reg: CoreRegister, partial_reg: CoreRegister, version: u32) -> Self { + Self::Partial { + full_reg, + partial_reg, + version, + } + } + pub fn version(&self) -> u32 { match *self { - LowLevelILSSARegister::Full(_, ver) | LowLevelILSSARegister::Partial(_, ver, _) => ver, + LowLevelILSSARegisterKind::Full { version, .. } + | LowLevelILSSARegisterKind::Partial { version, .. } => version, } } } +#[derive(Copy, Clone, Debug)] +pub struct LowLevelILSSAFlag<F: Flag> { + pub flag: F, + pub version: u32, +} + +impl<F: Flag> LowLevelILSSAFlag<F> { + pub fn new(flag: F, version: u32) -> Self { + Self { flag, version } + } +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum VisitorAction { Descend, diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 6addb7e1..73bec38d 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -99,8 +99,7 @@ where { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let op = unsafe { BNGetLowLevelILByIndex(self.function.handle, self.index.0) }; - // SAFETY: This is safe we are not exposing the expression kind to the caller. - let kind = unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }; + let kind = LowLevelILExpressionKind::from_raw(self.function, op, self.index); kind.fmt(f) } } @@ -117,7 +116,7 @@ where match op.operation { // Any invalid ops for SSA will be checked here. // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -149,7 +148,7 @@ where match op.operation { // Any invalid ops for Lifted IL will be checked here. // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -181,7 +180,7 @@ where LLIL_FLAG_COND => unreachable!("LLIL_FLAG_COND is only valid in Lifted IL"), LLIL_FLAG_GROUP => unreachable!("LLIL_FLAG_GROUP is only valid in Lifted IL"), // SAFETY: We have checked for illegal operations. - _ => unsafe { LowLevelILExpressionKind::from_raw(self.function, op) }, + _ => LowLevelILExpressionKind::from_raw(self.function, op, self.index), } } @@ -216,9 +215,13 @@ where F: FunctionForm, { Load(Operation<'func, M, F, operation::Load>), + LoadSsa(Operation<'func, M, F, operation::LoadSsa>), Pop(Operation<'func, M, F, operation::Pop>), Reg(Operation<'func, M, F, operation::Reg>), + RegSsa(Operation<'func, M, F, operation::RegSsa>), + RegPartialSsa(Operation<'func, M, F, operation::RegPartialSsa>), RegSplit(Operation<'func, M, F, operation::RegSplit>), + RegSplitSsa(Operation<'func, M, F, operation::RegSplitSsa>), Const(Operation<'func, M, F, operation::Const>), ConstPtr(Operation<'func, M, F, operation::Const>), Flag(Operation<'func, M, F, operation::Flag>), @@ -227,6 +230,10 @@ where RegStackPop(Operation<'func, M, F, operation::RegStackPop>), + CallOutputSsa(Operation<'func, M, F, operation::CallOutputSsa>), + CallParamSsa(Operation<'func, M, F, operation::CallParamSsa>), + CallStackSsa(Operation<'func, M, F, operation::CallStackSsa>), + Add(Operation<'func, M, F, operation::BinaryOp>), Adc(Operation<'func, M, F, operation::BinaryOpCarry>), Sub(Operation<'func, M, F, operation::BinaryOp>), @@ -319,116 +326,146 @@ where M: FunctionMutability, F: FunctionForm, { - // TODO: Document what "unchecked" means and how to consume this safely. - pub(crate) unsafe fn from_raw( + pub(crate) fn from_raw( function: &'func LowLevelILFunction<M, F>, op: BNLowLevelILInstruction, + index: LowLevelExpressionIndex, ) -> Self { use binaryninjacore_sys::BNLowLevelILOperation::*; match op.operation { - LLIL_LOAD | LLIL_LOAD_SSA => { - LowLevelILExpressionKind::Load(Operation::new(function, op)) + LLIL_LOAD => LowLevelILExpressionKind::Load(Operation::new(function, op, index)), + LLIL_LOAD_SSA => LowLevelILExpressionKind::LoadSsa(Operation::new(function, op, index)), + LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op, index)), + LLIL_REG => LowLevelILExpressionKind::Reg(Operation::new(function, op, index)), + LLIL_REG_SSA => LowLevelILExpressionKind::RegSsa(Operation::new(function, op, index)), + LLIL_REG_SSA_PARTIAL => { + LowLevelILExpressionKind::RegPartialSsa(Operation::new(function, op, index)) } - LLIL_POP => LowLevelILExpressionKind::Pop(Operation::new(function, op)), - LLIL_REG | LLIL_REG_SSA | LLIL_REG_SSA_PARTIAL => { - LowLevelILExpressionKind::Reg(Operation::new(function, op)) + LLIL_REG_SPLIT => { + LowLevelILExpressionKind::RegSplit(Operation::new(function, op, index)) } - LLIL_REG_SPLIT | LLIL_REG_SPLIT_SSA => { - LowLevelILExpressionKind::RegSplit(Operation::new(function, op)) + LLIL_REG_SPLIT_SSA => { + LowLevelILExpressionKind::RegSplitSsa(Operation::new(function, op, index)) + } + LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op, index)), + LLIL_CONST_PTR => { + LowLevelILExpressionKind::ConstPtr(Operation::new(function, op, index)) } - LLIL_CONST => LowLevelILExpressionKind::Const(Operation::new(function, op)), - LLIL_CONST_PTR => LowLevelILExpressionKind::ConstPtr(Operation::new(function, op)), LLIL_FLAG | LLIL_FLAG_SSA => { - LowLevelILExpressionKind::Flag(Operation::new(function, op)) + LowLevelILExpressionKind::Flag(Operation::new(function, op, index)) } LLIL_FLAG_BIT | LLIL_FLAG_BIT_SSA => { - LowLevelILExpressionKind::FlagBit(Operation::new(function, op)) + LowLevelILExpressionKind::FlagBit(Operation::new(function, op, index)) + } + LLIL_EXTERN_PTR => { + LowLevelILExpressionKind::ExternPtr(Operation::new(function, op, index)) } - LLIL_EXTERN_PTR => LowLevelILExpressionKind::ExternPtr(Operation::new(function, op)), LLIL_REG_STACK_POP => { - LowLevelILExpressionKind::RegStackPop(Operation::new(function, op)) + LowLevelILExpressionKind::RegStackPop(Operation::new(function, op, index)) + } + + LLIL_CALL_OUTPUT_SSA => { + LowLevelILExpressionKind::CallOutputSsa(Operation::new(function, op, index)) + } + LLIL_CALL_PARAM => { + LowLevelILExpressionKind::CallParamSsa(Operation::new(function, op, index)) + } + LLIL_CALL_STACK_SSA => { + LowLevelILExpressionKind::CallStackSsa(Operation::new(function, op, index)) } - LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op)), - LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op)), - LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op)), - LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op)), - LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op)), - LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op)), - LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op)), - LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op)), - LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op)), - LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op)), - LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op)), - LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op)), - LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op)), - LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op)), - LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op)), + LLIL_ADD => LowLevelILExpressionKind::Add(Operation::new(function, op, index)), + LLIL_ADC => LowLevelILExpressionKind::Adc(Operation::new(function, op, index)), + LLIL_SUB => LowLevelILExpressionKind::Sub(Operation::new(function, op, index)), + LLIL_SBB => LowLevelILExpressionKind::Sbb(Operation::new(function, op, index)), + LLIL_AND => LowLevelILExpressionKind::And(Operation::new(function, op, index)), + LLIL_OR => LowLevelILExpressionKind::Or(Operation::new(function, op, index)), + LLIL_XOR => LowLevelILExpressionKind::Xor(Operation::new(function, op, index)), + LLIL_LSL => LowLevelILExpressionKind::Lsl(Operation::new(function, op, index)), + LLIL_LSR => LowLevelILExpressionKind::Lsr(Operation::new(function, op, index)), + LLIL_ASR => LowLevelILExpressionKind::Asr(Operation::new(function, op, index)), + LLIL_ROL => LowLevelILExpressionKind::Rol(Operation::new(function, op, index)), + LLIL_RLC => LowLevelILExpressionKind::Rlc(Operation::new(function, op, index)), + LLIL_ROR => LowLevelILExpressionKind::Ror(Operation::new(function, op, index)), + LLIL_RRC => LowLevelILExpressionKind::Rrc(Operation::new(function, op, index)), + LLIL_MUL => LowLevelILExpressionKind::Mul(Operation::new(function, op, index)), - LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op)), - LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op)), + LLIL_MULU_DP => LowLevelILExpressionKind::MuluDp(Operation::new(function, op, index)), + LLIL_MULS_DP => LowLevelILExpressionKind::MulsDp(Operation::new(function, op, index)), - LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op)), - LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op)), + LLIL_DIVU => LowLevelILExpressionKind::Divu(Operation::new(function, op, index)), + LLIL_DIVS => LowLevelILExpressionKind::Divs(Operation::new(function, op, index)), - LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op)), - LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op)), + LLIL_DIVU_DP => LowLevelILExpressionKind::DivuDp(Operation::new(function, op, index)), + LLIL_DIVS_DP => LowLevelILExpressionKind::DivsDp(Operation::new(function, op, index)), - LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op)), - LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op)), + LLIL_MODU => LowLevelILExpressionKind::Modu(Operation::new(function, op, index)), + LLIL_MODS => LowLevelILExpressionKind::Mods(Operation::new(function, op, index)), - LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op)), - LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op)), + LLIL_MODU_DP => LowLevelILExpressionKind::ModuDp(Operation::new(function, op, index)), + LLIL_MODS_DP => LowLevelILExpressionKind::ModsDp(Operation::new(function, op, index)), - LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op)), - LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op)), + LLIL_NEG => LowLevelILExpressionKind::Neg(Operation::new(function, op, index)), + LLIL_NOT => LowLevelILExpressionKind::Not(Operation::new(function, op, index)), - LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op)), - LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op)), - LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op)), + LLIL_SX => LowLevelILExpressionKind::Sx(Operation::new(function, op, index)), + LLIL_ZX => LowLevelILExpressionKind::Zx(Operation::new(function, op, index)), + LLIL_LOW_PART => LowLevelILExpressionKind::LowPart(Operation::new(function, op, index)), - LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op)), - LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op)), - LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op)), - LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op)), - LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op)), - LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op)), - LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op)), - LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op)), - LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op)), - LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op)), + LLIL_CMP_E => LowLevelILExpressionKind::CmpE(Operation::new(function, op, index)), + LLIL_CMP_NE => LowLevelILExpressionKind::CmpNe(Operation::new(function, op, index)), + LLIL_CMP_SLT => LowLevelILExpressionKind::CmpSlt(Operation::new(function, op, index)), + LLIL_CMP_ULT => LowLevelILExpressionKind::CmpUlt(Operation::new(function, op, index)), + LLIL_CMP_SLE => LowLevelILExpressionKind::CmpSle(Operation::new(function, op, index)), + LLIL_CMP_ULE => LowLevelILExpressionKind::CmpUle(Operation::new(function, op, index)), + LLIL_CMP_SGE => LowLevelILExpressionKind::CmpSge(Operation::new(function, op, index)), + LLIL_CMP_UGE => LowLevelILExpressionKind::CmpUge(Operation::new(function, op, index)), + LLIL_CMP_SGT => LowLevelILExpressionKind::CmpSgt(Operation::new(function, op, index)), + LLIL_CMP_UGT => LowLevelILExpressionKind::CmpUgt(Operation::new(function, op, index)), - LLIL_BOOL_TO_INT => LowLevelILExpressionKind::BoolToInt(Operation::new(function, op)), + LLIL_BOOL_TO_INT => { + LowLevelILExpressionKind::BoolToInt(Operation::new(function, op, index)) + } - LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op)), - LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op)), - LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op)), - LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op)), + LLIL_FADD => LowLevelILExpressionKind::Fadd(Operation::new(function, op, index)), + LLIL_FSUB => LowLevelILExpressionKind::Fsub(Operation::new(function, op, index)), + LLIL_FMUL => LowLevelILExpressionKind::Fmul(Operation::new(function, op, index)), + LLIL_FDIV => LowLevelILExpressionKind::Fdiv(Operation::new(function, op, index)), - LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op)), - LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op)), - LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op)), - LLIL_FLOAT_TO_INT => LowLevelILExpressionKind::FloatToInt(Operation::new(function, op)), - LLIL_INT_TO_FLOAT => LowLevelILExpressionKind::IntToFloat(Operation::new(function, op)), - LLIL_FLOAT_CONV => LowLevelILExpressionKind::FloatConv(Operation::new(function, op)), - LLIL_ROUND_TO_INT => LowLevelILExpressionKind::RoundToInt(Operation::new(function, op)), - LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op)), - LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op)), - LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op)), + LLIL_FSQRT => LowLevelILExpressionKind::Fsqrt(Operation::new(function, op, index)), + LLIL_FNEG => LowLevelILExpressionKind::Fneg(Operation::new(function, op, index)), + LLIL_FABS => LowLevelILExpressionKind::Fabs(Operation::new(function, op, index)), + LLIL_FLOAT_TO_INT => { + LowLevelILExpressionKind::FloatToInt(Operation::new(function, op, index)) + } + LLIL_INT_TO_FLOAT => { + LowLevelILExpressionKind::IntToFloat(Operation::new(function, op, index)) + } + LLIL_FLOAT_CONV => { + LowLevelILExpressionKind::FloatConv(Operation::new(function, op, index)) + } + LLIL_ROUND_TO_INT => { + LowLevelILExpressionKind::RoundToInt(Operation::new(function, op, index)) + } + LLIL_FLOOR => LowLevelILExpressionKind::Floor(Operation::new(function, op, index)), + LLIL_CEIL => LowLevelILExpressionKind::Ceil(Operation::new(function, op, index)), + LLIL_FTRUNC => LowLevelILExpressionKind::Ftrunc(Operation::new(function, op, index)), - LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op)), - LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op)), - LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op)), - LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op)), - LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op)), - LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op)), - LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op)), - LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op)), + LLIL_FCMP_E => LowLevelILExpressionKind::FcmpE(Operation::new(function, op, index)), + LLIL_FCMP_NE => LowLevelILExpressionKind::FcmpNE(Operation::new(function, op, index)), + LLIL_FCMP_LT => LowLevelILExpressionKind::FcmpLT(Operation::new(function, op, index)), + LLIL_FCMP_LE => LowLevelILExpressionKind::FcmpLE(Operation::new(function, op, index)), + LLIL_FCMP_GT => LowLevelILExpressionKind::FcmpGT(Operation::new(function, op, index)), + LLIL_FCMP_GE => LowLevelILExpressionKind::FcmpGE(Operation::new(function, op, index)), + LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op, index)), + LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op, index)), - LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op)), - LLIL_UNIMPL_MEM => LowLevelILExpressionKind::UnimplMem(Operation::new(function, op)), + LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op, index)), + LLIL_UNIMPL_MEM => { + LowLevelILExpressionKind::UnimplMem(Operation::new(function, op, index)) + } // TODO TEST_BIT ADD_OVERFLOW LLIL_REG_STACK_PUSH LLIL_REG_STACK_POP _ => { @@ -439,7 +476,7 @@ where op.address ); - LowLevelILExpressionKind::Undef(Operation::new(function, op)) + LowLevelILExpressionKind::Undef(Operation::new(function, op, index)) } } } @@ -585,12 +622,21 @@ where visit!(op.mem_expr()); } Load(ref op) => { - visit!(op.source_mem_expr()); + visit!(op.source_expr()); } - // Do not have any sub expressions. - Pop(_) | Reg(_) | RegSplit(_) | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) - | ExternPtr(_) | FlagCond(_) | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) => { + LoadSsa(ref op) => { + visit!(op.source_expr()); + } + CallParamSsa(ref op) => { + for param_expr in op.param_exprs() { + visit!(param_expr); + } } + // Do not have any sub expressions. + Pop(_) | Reg(_) | RegSsa(_) | RegPartialSsa(_) | RegSplit(_) | RegSplitSsa(_) + | Const(_) | ConstPtr(_) | Flag(_) | FlagBit(_) | ExternPtr(_) | FlagCond(_) + | FlagGroup(_) | Unimpl(_) | Undef(_) | RegStackPop(_) | CallOutputSsa(_) + | CallStackSsa(_) => {} } VisitorAction::Sibling @@ -614,12 +660,20 @@ where Load(ref op) => &op.op, + LoadSsa(ref op) => &op.op, + Pop(ref op) => &op.op, Reg(ref op) => &op.op, + RegSsa(ref op) => &op.op, + + RegPartialSsa(ref op) => &op.op, + RegSplit(ref op) => &op.op, + RegSplitSsa(ref op) => &op.op, + Flag(ref op) => &op.op, FlagBit(ref op) => &op.op, @@ -630,6 +684,10 @@ where RegStackPop(ref op) => &op.op, + CallOutputSsa(ref op) => &op.op, + CallParamSsa(ref op) => &op.op, + CallStackSsa(ref op) => &op.op, + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => &op.op, Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) @@ -670,12 +728,20 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA<LiftedNonSSA>> { Load(ref op) => op.flag_write(), + LoadSsa(ref op) => op.flag_write(), + Pop(ref op) => op.flag_write(), Reg(ref op) => op.flag_write(), + RegSsa(ref op) => op.flag_write(), + + RegPartialSsa(ref op) => op.flag_write(), + RegSplit(ref op) => op.flag_write(), + RegSplitSsa(ref op) => op.flag_write(), + Flag(ref op) => op.flag_write(), FlagBit(ref op) => op.flag_write(), @@ -686,6 +752,10 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA<LiftedNonSSA>> { RegStackPop(ref op) => op.flag_write(), + CallOutputSsa(ref op) => op.flag_write(), + CallParamSsa(ref op) => op.flag_write(), + CallStackSsa(ref op) => op.flag_write(), + Adc(ref op) | Sbb(ref op) | Rlc(ref op) | Rrc(ref op) => op.flag_write(), Add(ref op) | Sub(ref op) | And(ref op) | Or(ref op) | Xor(ref op) | Lsl(ref op) diff --git a/rust/src/low_level_il/function.rs b/rust/src/low_level_il/function.rs index 21eebc3c..62811b1d 100644 --- a/rust/src/low_level_il/function.rs +++ b/rust/src/low_level_il/function.rs @@ -12,15 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use binaryninjacore_sys::BNFreeLowLevelILFunction; -use binaryninjacore_sys::BNGetLowLevelILOwnerFunction; -use binaryninjacore_sys::BNLowLevelILFunction; -use binaryninjacore_sys::BNNewLowLevelILFunctionReference; - use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use binaryninjacore_sys::*; + use crate::architecture::CoreArchitecture; use crate::basic_block::BasicBlock; use crate::function::Function; @@ -160,13 +157,8 @@ where Function::ref_from_raw(func) } } -} -// LLIL basic blocks are not available until the function object -// is finalized, so ensure we can't try requesting basic blocks -// during lifting -impl<F: FunctionForm> LowLevelILFunction<Finalized, F> { - pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<Finalized, F>>> { + pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<M, F>>> { use binaryninjacore_sys::BNGetLowLevelILBasicBlockList; unsafe { @@ -178,6 +170,17 @@ impl<F: FunctionForm> LowLevelILFunction<Finalized, F> { } } +impl<M: FunctionMutability, V: NonSSAVariant> LowLevelILFunction<M, NonSSA<V>> { + /// Retrieve the SSA form of the function. + pub fn ssa_form(&self) -> Option<Ref<LowLevelILFunction<M, SSA>>> { + let handle = unsafe { BNGetLowLevelILSSAForm(self.handle) }; + if handle.is_null() { + return None; + } + Some(unsafe { LowLevelILFunction::ref_from_raw(handle) }) + } +} + // Allow instantiating Lifted IL functions for querying Lifted IL from Architectures impl LowLevelILFunction<Mutable, NonSSA<LiftedNonSSA>> { // TODO: Document what happens when you pass None for `source_func`. @@ -201,7 +204,6 @@ impl LowLevelILFunction<Mutable, NonSSA<LiftedNonSSA>> { pub fn generate_ssa_form(&self) { use binaryninjacore_sys::BNGenerateLowLevelILSSAForm; - unsafe { BNGenerateLowLevelILSSAForm(self.handle) }; } } diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index ded9c6f3..90d2f1d8 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -207,9 +207,14 @@ where { Nop(Operation<'func, M, F, operation::NoArgs>), SetReg(Operation<'func, M, F, operation::SetReg>), + SetRegSsa(Operation<'func, M, F, operation::SetRegSsa>), + SetRegPartialSsa(Operation<'func, M, F, operation::SetRegPartialSsa>), SetRegSplit(Operation<'func, M, F, operation::SetRegSplit>), + SetRegSplitSsa(Operation<'func, M, F, operation::SetRegSplitSsa>), SetFlag(Operation<'func, M, F, operation::SetFlag>), + SetFlagSsa(Operation<'func, M, F, operation::SetFlagSsa>), Store(Operation<'func, M, F, operation::Store>), + StoreSsa(Operation<'func, M, F, operation::StoreSsa>), // TODO needs a real op Push(Operation<'func, M, F, operation::UnaryOp>), @@ -219,7 +224,9 @@ where JumpTo(Operation<'func, M, F, operation::JumpTo>), Call(Operation<'func, M, F, operation::Call>), + CallSsa(Operation<'func, M, F, operation::CallSsa>), TailCall(Operation<'func, M, F, operation::Call>), + TailCallSsa(Operation<'func, M, F, operation::CallSsa>), Ret(Operation<'func, M, F, operation::Ret>), NoRet(Operation<'func, M, F, operation::NoArgs>), @@ -228,6 +235,7 @@ where Goto(Operation<'func, M, F, operation::Goto>), Syscall(Operation<'func, M, F, operation::Syscall>), + SyscallSsa(Operation<'func, M, F, operation::SyscallSsa>), Intrinsic(Operation<'func, M, F, operation::Intrinsic>), Bp(Operation<'func, M, F, operation::NoArgs>), Trap(Operation<'func, M, F, operation::Trap>), @@ -250,50 +258,80 @@ where use binaryninjacore_sys::BNLowLevelILOperation::*; match op.operation { - LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op)), - LLIL_SET_REG | LLIL_SET_REG_SSA => { - LowLevelILInstructionKind::SetReg(Operation::new(function, op)) + LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op, expr_index)), + LLIL_SET_REG => { + LowLevelILInstructionKind::SetReg(Operation::new(function, op, expr_index)) } - LLIL_SET_REG_SPLIT | LLIL_SET_REG_SPLIT_SSA => { - LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op)) + LLIL_SET_REG_SSA => { + LowLevelILInstructionKind::SetRegSsa(Operation::new(function, op, expr_index)) } - LLIL_SET_FLAG | LLIL_SET_FLAG_SSA => { - LowLevelILInstructionKind::SetFlag(Operation::new(function, op)) + LLIL_SET_REG_SSA_PARTIAL => LowLevelILInstructionKind::SetRegPartialSsa( + Operation::new(function, op, expr_index), + ), + LLIL_SET_REG_SPLIT => { + LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op, expr_index)) } - LLIL_STORE | LLIL_STORE_SSA => { - LowLevelILInstructionKind::Store(Operation::new(function, op)) + LLIL_SET_REG_SPLIT_SSA => { + LowLevelILInstructionKind::SetRegSplitSsa(Operation::new(function, op, expr_index)) } - LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op)), + LLIL_SET_FLAG => { + LowLevelILInstructionKind::SetFlag(Operation::new(function, op, expr_index)) + } + LLIL_SET_FLAG_SSA => { + LowLevelILInstructionKind::SetFlagSsa(Operation::new(function, op, expr_index)) + } + LLIL_STORE => { + LowLevelILInstructionKind::Store(Operation::new(function, op, expr_index)) + } + LLIL_STORE_SSA => { + LowLevelILInstructionKind::StoreSsa(Operation::new(function, op, expr_index)) + } + LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op, expr_index)), LLIL_REG_STACK_PUSH => { - LowLevelILInstructionKind::RegStackPush(Operation::new(function, op)) + LowLevelILInstructionKind::RegStackPush(Operation::new(function, op, expr_index)) } - LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op)), - LLIL_JUMP_TO => LowLevelILInstructionKind::JumpTo(Operation::new(function, op)), + LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op, expr_index)), + LLIL_JUMP_TO => { + LowLevelILInstructionKind::JumpTo(Operation::new(function, op, expr_index)) + } - LLIL_CALL | LLIL_CALL_STACK_ADJUST | LLIL_CALL_SSA => { - LowLevelILInstructionKind::Call(Operation::new(function, op)) + LLIL_CALL | LLIL_CALL_STACK_ADJUST => { + LowLevelILInstructionKind::Call(Operation::new(function, op, expr_index)) + } + LLIL_CALL_SSA => { + LowLevelILInstructionKind::CallSsa(Operation::new(function, op, expr_index)) + } + LLIL_TAILCALL => { + LowLevelILInstructionKind::TailCall(Operation::new(function, op, expr_index)) } - LLIL_TAILCALL | LLIL_TAILCALL_SSA => { - LowLevelILInstructionKind::TailCall(Operation::new(function, op)) + LLIL_TAILCALL_SSA => { + LowLevelILInstructionKind::TailCallSsa(Operation::new(function, op, expr_index)) } - LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op)), - LLIL_NORET => LowLevelILInstructionKind::NoRet(Operation::new(function, op)), + LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op, expr_index)), + LLIL_NORET => { + LowLevelILInstructionKind::NoRet(Operation::new(function, op, expr_index)) + } - LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op)), - LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op)), + LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op, expr_index)), + LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op, expr_index)), - LLIL_SYSCALL | LLIL_SYSCALL_SSA => { - LowLevelILInstructionKind::Syscall(Operation::new(function, op)) + LLIL_SYSCALL => { + LowLevelILInstructionKind::Syscall(Operation::new(function, op, expr_index)) + } + LLIL_SYSCALL_SSA => { + LowLevelILInstructionKind::SyscallSsa(Operation::new(function, op, expr_index)) } LLIL_INTRINSIC | LLIL_INTRINSIC_SSA => { - LowLevelILInstructionKind::Intrinsic(Operation::new(function, op)) + LowLevelILInstructionKind::Intrinsic(Operation::new(function, op, expr_index)) + } + LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op, expr_index)), + LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op, expr_index)), + LLIL_UNDEF => { + LowLevelILInstructionKind::Undef(Operation::new(function, op, expr_index)) } - LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op)), - LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op)), - LLIL_UNDEF => LowLevelILInstructionKind::Undef(Operation::new(function, op)), _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)), } } @@ -314,17 +352,31 @@ where match self { SetReg(ref op) => visit!(&op.source_expr()), + SetRegSsa(ref op) => visit!(&op.source_expr()), + SetRegPartialSsa(ref op) => visit!(&op.source_expr()), SetRegSplit(ref op) => visit!(&op.source_expr()), + SetRegSplitSsa(ref op) => visit!(&op.source_expr()), SetFlag(ref op) => visit!(&op.source_expr()), + SetFlagSsa(ref op) => visit!(&op.source_expr()), Store(ref op) => { - visit!(&op.dest_mem_expr()); + visit!(&op.dest_expr()); + visit!(&op.source_expr()); + } + StoreSsa(ref op) => { + visit!(&op.dest_expr()); visit!(&op.source_expr()); } Push(ref op) => visit!(&op.operand()), RegStackPush(ref op) => visit!(&op.source_expr()), Jump(ref op) => visit!(&op.target()), JumpTo(ref op) => visit!(&op.target()), + SyscallSsa(ref op) => { + visit!(&op.output_expr()); + visit!(&op.param_expr()); + visit!(&op.stack_expr()); + } Call(ref op) | TailCall(ref op) => visit!(&op.target()), + CallSsa(ref op) | TailCallSsa(ref op) => visit!(&op.target()), Ret(ref op) => visit!(&op.target()), If(ref op) => visit!(&op.condition()), Intrinsic(ref _op) => { diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index bd68bbb1..7f31f62b 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use binaryninjacore_sys::{BNGetLowLevelILByIndex, BNLowLevelILInstruction}; +use binaryninjacore_sys::{ + BNGetLowLevelILByIndex, BNLowLevelILFreeOperandList, BNLowLevelILGetOperandList, + BNLowLevelILInstruction, +}; use super::*; use crate::architecture::{ @@ -32,6 +35,7 @@ where { pub(crate) function: &'func LowLevelILFunction<M, F>, pub(crate) op: BNLowLevelILInstruction, + pub(crate) expr_idx: LowLevelExpressionIndex, _args: PhantomData<O>, } @@ -44,10 +48,12 @@ where pub(crate) fn new( function: &'func LowLevelILFunction<M, F>, op: BNLowLevelILInstruction, + expr_idx: LowLevelExpressionIndex, ) -> Self { Self { function, op, + expr_idx, _args: PhantomData, } } @@ -55,6 +61,22 @@ where pub fn address(&self) -> u64 { self.op.address } + + pub fn get_operand_list(&self, operand_idx: usize) -> Vec<u64> { + let mut count = 0; + let raw_list_ptr = unsafe { + BNLowLevelILGetOperandList( + self.function.handle, + self.expr_idx.0, + operand_idx, + &mut count, + ) + }; + assert!(!raw_list_ptr.is_null()); + let list = unsafe { std::slice::from_raw_parts(raw_list_ptr, count).to_vec() }; + unsafe { BNLowLevelILFreeOperandList(raw_list_ptr) }; + list + } } impl<M, O> Operation<'_, M, NonSSA<LiftedNonSSA>, O> @@ -109,7 +131,7 @@ where } } -// LLIL_SYSCALL, LLIL_SYSCALL_SSA +// LLIL_SYSCALL pub struct Syscall; impl<M, F> Debug for Operation<'_, M, F, Syscall> @@ -122,6 +144,59 @@ where } } +// LLIL_SYSCALL_SSA +pub struct SyscallSsa; + +impl<'func, M, F> Operation<'func, M, F, SyscallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + /// Get the output expression of the call. + /// + /// NOTE: This is currently always [`CallOutputSsa`]. + pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Get the parameter expression of the call. + /// + /// NOTE: This is currently always [`CallParamSsa`]. + pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } + + /// Get the stack expression of the call. + /// + /// NOTE: This is currently always [`CallStackSsa`]. + pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, SyscallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SyscallSsa") + .field("output_expr", &self.output_expr()) + .field("param_expr", &self.param_expr()) + .field("stack_expr", &self.stack_expr()) + .finish() + } +} + // LLIL_INTRINSIC, LLIL_INTRINSIC_SSA pub struct Intrinsic; @@ -150,7 +225,7 @@ where } } -// LLIL_SET_REG, LLIL_SET_REG_SSA, LLIL_SET_REG_PARTIAL_SSA +// LLIL_SET_REG pub struct SetReg; impl<'func, M, F> Operation<'func, M, F, SetReg> @@ -190,7 +265,96 @@ where } } -// LLIL_SET_REG_SPLIT, LLIL_SET_REG_SPLIT_SSA +// LLIL_SET_REG_SSA +pub struct SetRegSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, SetRegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_REG_PARTIAL_SSA +pub struct SetRegPartialSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let full_raw_id = RegisterId(self.op.operands[0] as u32); + let version = self.op.operands[1] as u32; + let partial_raw_id = RegisterId(self.op.operands[2] as u32); + let full_reg = + CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID"); + let partial_reg = + CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, SetRegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegPartialSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_reg", &self.dest_reg()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_REG_SPLIT pub struct SetRegSplit; impl<'func, M, F> Operation<'func, M, F, SetRegSplit> @@ -236,7 +400,63 @@ where } } -// LLIL_SET_FLAG, LLIL_SET_FLAG_SSA +// LLIL_SET_REG_SPLIT_SSA +pub struct SetRegSplitSsa; + +impl<'func, M, F> Operation<'func, M, F, SetRegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + /// Because of the fixed operand list size we use another expression for the dest high register. + /// + /// NOTE: This should always be an expression of [`RegSsa`]. + pub fn dest_expr_high(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Because of the fixed operand list size we use another expression for the dest low register. + /// + /// NOTE: This should always be an expression of [`RegSsa`]. + pub fn dest_expr_low(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, SetRegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetRegSplitSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_expr_high", &self.dest_expr_high()) + .field("dest_expr_low", &self.dest_expr_low()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_SET_FLAG pub struct SetFlag; impl<'func, M, F> Operation<'func, M, F, SetFlag> @@ -245,12 +465,10 @@ where F: FunctionForm, { pub fn dest_flag(&self) -> CoreFlag { - // TODO: Error handling? - // TODO: Test this. self.function .arch() .flag_from_id(FlagId(self.op.operands[0] as u32)) - .unwrap() + .expect("Bad flag ID") } pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { @@ -275,7 +493,46 @@ where } } -// LLIL_LOAD, LLIL_LOAD_SSA +// LLIL_SET_FLAG_SSA +pub struct SetFlagSsa; + +impl<'func, M, F> Operation<'func, M, F, SetFlagSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_flag(&self) -> LowLevelILSSAFlag<CoreFlag> { + let flag = self + .function + .arch() + .flag_from_id(FlagId(self.op.operands[0] as u32)) + .expect("Bad flag ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSAFlag::new(flag, version) + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, SetFlagSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SetFlagSsa") + .field("address", &self.address()) + .field("dest_flag", &self.dest_flag()) + .field("source_expr", &self.source_expr()) + .finish() + } +} +// LLIL_LOAD pub struct Load; impl<'func, M, F> Operation<'func, M, F, Load> @@ -287,7 +544,7 @@ where self.op.size } - pub fn source_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -304,12 +561,50 @@ where f.debug_struct("Load") .field("address", &self.address()) .field("size", &self.size()) - .field("source_mem_expr", &self.source_mem_expr()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_LOAD_SSA +pub struct LoadSsa; + +impl<'func, M, F> Operation<'func, M, F, LoadSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + pub fn source_memory_version(&self) -> u64 { + self.op.operands[1] + } +} + +impl<M, F> Debug for Operation<'_, M, F, LoadSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("LoadSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_expr", &self.source_expr()) .finish() } } -// LLIL_STORE, LLIL_STORE_SSA +// LLIL_STORE pub struct Store; impl<'func, M, F> Operation<'func, M, F, Store> @@ -321,7 +616,7 @@ where self.op.size } - pub fn dest_mem_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { LowLevelILExpression::new( self.function, LowLevelExpressionIndex(self.op.operands[0] as usize), @@ -345,13 +640,63 @@ where f.debug_struct("Store") .field("address", &self.address()) .field("size", &self.size()) - .field("dest_mem_expr", &self.dest_mem_expr()) + .field("dest_expr", &self.dest_expr()) + .field("source_expr", &self.source_expr()) + .finish() + } +} + +// LLIL_STORE_SSA +pub struct StoreSsa; + +impl<'func, M, F> Operation<'func, M, F, StoreSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn dest_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + pub fn dest_memory_version(&self) -> u64 { + self.op.operands[1] + } + + pub fn source_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } + + pub fn source_memory_version(&self) -> u64 { + self.op.operands[2] + } +} + +impl<M, F> Debug for Operation<'_, M, F, StoreSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("StoreSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("dest_expr", &self.dest_expr()) .field("source_expr", &self.source_expr()) .finish() } } -// LLIL_REG, LLIL_REG_SSLLIL_REG_SSA_PARTIAL +// LLIL_REG pub struct Reg; impl<M, F> Operation<'_, M, F, Reg> @@ -383,7 +728,80 @@ where } } -// LLIL_REG_SPLIT, LLIL_REG_SPLIT_SSA +// LLIL_REG_SSA +pub struct RegSsa; + +impl<M, F> Operation<'_, M, F, RegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl<M, F> Debug for Operation<'_, M, F, RegSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .finish() + } +} + +// LLIL_REG_SSA_PARTIAL +pub struct RegPartialSsa; + +impl<M, F> Operation<'_, M, F, RegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let full_raw_id = RegisterId(self.op.operands[0] as u32); + let version = self.op.operands[1] as u32; + let partial_raw_id = RegisterId(self.op.operands[2] as u32); + let full_reg = + CoreRegister::new(self.function.arch(), full_raw_id).expect("Bad register ID"); + let partial_reg = + CoreRegister::new(self.function.arch(), partial_raw_id).expect("Bad register ID"); + LowLevelILSSARegisterKind::new_partial(full_reg, partial_reg, version) + } +} + +impl<M, F> Debug for Operation<'_, M, F, RegPartialSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegPartialSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("source_reg", &self.source_reg()) + .finish() + } +} + +// LLIL_REG_SPLIT pub struct RegSplit; impl<M, F> Operation<'_, M, F, RegSplit> @@ -421,6 +839,50 @@ where } } +// LLIL_REG_SPLIT_SSA +pub struct RegSplitSsa; + +impl<M, F> Operation<'_, M, F, RegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn size(&self) -> usize { + self.op.size + } + + pub fn low_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } + + pub fn high_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let raw_id = RegisterId(self.op.operands[2] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[3] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl<M, F> Debug for Operation<'_, M, F, RegSplitSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("RegSplitSsa") + .field("address", &self.address()) + .field("size", &self.size()) + .field("low_reg", &self.low_reg()) + .field("high_reg", &self.high_reg()) + .finish() + } +} + // LLIL_REG_STACK_PUSH pub struct RegStackPush; @@ -630,7 +1092,7 @@ where } } -// LLIL_CALL, LLIL_CALL_SSA +// LLIL_CALL, LLIL_CALL_STACK_ADJUST pub struct Call; impl<'func, M, F> Operation<'func, M, F, Call> @@ -669,6 +1131,165 @@ where } } +// LLIL_CALL_SSA +pub struct CallSsa; + +impl<'func, M, F> Operation<'func, M, F, CallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn target(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[1] as usize), + ) + } + + /// Get the output expression of the call. + /// + /// NOTE: This is currently always [`CallOutputSsa`]. + pub fn output_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[0] as usize), + ) + } + + /// Get the parameter expression of the call. + /// + /// NOTE: This is currently always [`CallParamSsa`]. + pub fn param_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } + + /// Get the stack expression of the call. + /// + /// NOTE: This is currently always [`CallStackSsa`]. + pub fn stack_expr(&self) -> LowLevelILExpression<'func, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[2] as usize), + ) + } +} + +impl<M, F> Debug for Operation<'_, M, F, CallSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallSsa") + .field("target", &self.target()) + .field("output_expr", &self.output_expr()) + .field("param_expr", &self.param_expr()) + .field("stack_expr", &self.stack_expr()) + .finish() + } +} + +// LLIL_CALL_OUTPUT_SSA +pub struct CallOutputSsa; + +impl<M, F> Operation<'_, M, F, CallOutputSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_regs(&self) -> Vec<LowLevelILSSARegisterKind<CoreRegister>> { + let operand_list = self.get_operand_list(1); + + // The operand list contains a list of ([0: reg, 1: version], ...). + let paired_ssa_reg = |paired: &[u64]| { + let raw_id = RegisterId(paired[0] as u32); + let version = paired[1] as u32; + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + LowLevelILSSARegisterKind::new_full(reg_kind, version) + }; + + operand_list.chunks_exact(2).map(paired_ssa_reg).collect() + } + + pub fn dest_memory_version(&self) -> u64 { + self.op.operands[0] + } +} + +impl<M, F> Debug for Operation<'_, M, F, CallOutputSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallOutputSsa") + .field("dest_regs", &self.dest_regs()) + .finish() + } +} + +// LLIL_CALL_PARAM_SSA +pub struct CallParamSsa; + +impl<'func, M, F> Operation<'func, M, F, CallParamSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn param_exprs(&self) -> Vec<LowLevelILExpression<'func, M, F, ValueExpr>> { + self.get_operand_list(0) + .into_iter() + .map(|val| LowLevelExpressionIndex(val as usize)) + .map(|expr_idx| LowLevelILExpression::new(self.function, expr_idx)) + .collect() + } +} + +impl<M, F> Debug for Operation<'_, M, F, CallParamSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallParamSsa") + .field("param_exprs", &self.param_exprs()) + .finish() + } +} + +// LLIL_CALL_STACK_SSA +pub struct CallStackSsa; + +impl<M, F> Operation<'_, M, F, CallStackSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn source_reg(&self) -> LowLevelILSSARegisterKind<CoreRegister> { + let raw_id = RegisterId(self.op.operands[0] as u32); + let reg_kind = LowLevelILRegisterKind::from_raw(&self.function.arch(), raw_id) + .expect("Bad register ID"); + let version = self.op.operands[1] as u32; + LowLevelILSSARegisterKind::new_full(reg_kind, version) + } +} + +impl<M, F> Debug for Operation<'_, M, F, CallStackSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("CallStackSsa") + .field("source_reg", &self.source_reg()) + .finish() + } +} + // LLIL_RET pub struct Ret; @@ -1256,14 +1877,24 @@ pub trait OperationArguments: 'static {} impl OperationArguments for NoArgs {} impl OperationArguments for Pop {} impl OperationArguments for Syscall {} +impl OperationArguments for SyscallSsa {} impl OperationArguments for Intrinsic {} impl OperationArguments for SetReg {} +impl OperationArguments for SetRegSsa {} +impl OperationArguments for SetRegPartialSsa {} impl OperationArguments for SetRegSplit {} +impl OperationArguments for SetRegSplitSsa {} impl OperationArguments for SetFlag {} +impl OperationArguments for SetFlagSsa {} impl OperationArguments for Load {} +impl OperationArguments for LoadSsa {} impl OperationArguments for Store {} +impl OperationArguments for StoreSsa {} impl OperationArguments for Reg {} +impl OperationArguments for RegSsa {} +impl OperationArguments for RegPartialSsa {} impl OperationArguments for RegSplit {} +impl OperationArguments for RegSplitSsa {} impl OperationArguments for RegStackPush {} impl OperationArguments for RegStackPop {} impl OperationArguments for Flag {} @@ -1271,6 +1902,10 @@ impl OperationArguments for FlagBit {} impl OperationArguments for Jump {} impl OperationArguments for JumpTo {} impl OperationArguments for Call {} +impl OperationArguments for CallSsa {} +impl OperationArguments for CallOutputSsa {} +impl OperationArguments for CallParamSsa {} +impl OperationArguments for CallStackSsa {} impl OperationArguments for Ret {} impl OperationArguments for If {} impl OperationArguments for Goto {} |
