diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index 8df8dfe0cf..93638fafa8 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -280,6 +280,8 @@ where FcmpO(Operation<'func, M, F, operation::Condition>), FcmpUO(Operation<'func, M, F, operation::Condition>), + SeparateParamListSsa(Operation<'func, M, F, operation::SeparateParamListSsa>), + // TODO ADD_OVERFLOW Unimpl(Operation<'func, M, F, operation::NoArgs>), UnimplMem(Operation<'func, M, F, operation::UnimplMem>), @@ -428,6 +430,12 @@ where LLIL_FCMP_O => LowLevelILExpressionKind::FcmpO(Operation::new(function, op, index)), LLIL_FCMP_UO => LowLevelILExpressionKind::FcmpUO(Operation::new(function, op, index)), + LLIL_SEPARATE_PARAM_LIST_SSA => { + LowLevelILExpressionKind::SeparateParamListSsa(Operation::new(function, op, index)) + } + + LLIL_UNDEF => LowLevelILExpressionKind::Undef(Operation::new(function, op, index)), + LLIL_UNIMPL => LowLevelILExpressionKind::Unimpl(Operation::new(function, op, index)), LLIL_UNIMPL_MEM => { LowLevelILExpressionKind::UnimplMem(Operation::new(function, op, index)) @@ -598,6 +606,11 @@ where visit!(param_expr); } } + SeparateParamListSsa(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(_) @@ -668,6 +681,8 @@ where | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => &op.op, + SeparateParamListSsa(ref op) => &op.op, + UnimplMem(ref op) => &op.op, //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO } @@ -738,6 +753,8 @@ impl LowLevelILExpressionKind<'_, Mutable, NonSSA> { | FloatToInt(ref op) | IntToFloat(ref op) | FloatConv(ref op) | RoundToInt(ref op) | Floor(ref op) | Ceil(ref op) | Ftrunc(ref op) => op.flag_write(), + SeparateParamListSsa(ref op) => op.flag_write(), + UnimplMem(ref op) => op.flag_write(), //TestBit(Operation<'func, M, F, operation::TestBit>), // TODO } diff --git a/rust/src/low_level_il/instruction.rs b/rust/src/low_level_il/instruction.rs index ef546412ed..e76f4f9c73 100644 --- a/rust/src/low_level_il/instruction.rs +++ b/rust/src/low_level_il/instruction.rs @@ -214,6 +214,10 @@ where ForceVersion(Operation<'func, M, F, operation::ForceVersion>), ForceVersionSsa(Operation<'func, M, F, operation::ForceVersionSsa>), + RegPhi(Operation<'func, M, F, operation::RegPhi>), + FlagPhi(Operation<'func, M, F, operation::FlagPhi>), + MemPhi(Operation<'func, M, F, operation::MemPhi>), + /// The instruction is an expression. Value(LowLevelILExpression<'func, M, F, ValueExpr>), } @@ -317,6 +321,16 @@ where LLIL_FORCE_VER_SSA => { LowLevelILInstructionKind::ForceVersionSsa(Operation::new(function, op, expr_index)) } + LLIL_REG_PHI => { + LowLevelILInstructionKind::RegPhi(Operation::new(function, op, expr_index)) + } + LLIL_MEM_PHI => { + LowLevelILInstructionKind::MemPhi(Operation::new(function, op, expr_index)) + } + LLIL_FLAG_PHI => { + LowLevelILInstructionKind::FlagPhi(Operation::new(function, op, expr_index)) + } + _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)), } } @@ -370,7 +384,8 @@ where Value(e) => visit!(e), // Do not have any sub expressions. Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) | Assert(_) - | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) => {} + | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) | RegPhi(_) | FlagPhi(_) + | MemPhi(_) => {} } VisitorAction::Sibling diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 6e0dda9150..bc8e579e61 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -1475,6 +1475,35 @@ where // LLIL_REG_PHI pub struct RegPhi; +impl Operation<'_, M, F, RegPhi> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_reg(&self) -> LowLevelILSSARegisterKind { + 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_regs(&self) -> Vec> { + let operand_list = self.get_operand_list(2); + let arch = self.function.arch(); + operand_list + .chunks_exact(2) + .map(|chunk| { + let (register, version) = (chunk[0], chunk[1]); + LowLevelILSSARegisterKind::new_full( + LowLevelILRegisterKind::from_raw(&arch, RegisterId(register as u32)) + .expect("Bad register ID"), + version as u32, + ) + }) + .collect() + } +} impl Debug for Operation<'_, M, F, RegPhi> where @@ -1482,33 +1511,89 @@ where F: FunctionForm, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("RegPhi").finish() + f.debug_struct("RegPhi") + .field("dest_reg", &self.dest_reg()) + .field("source_regs", &self.source_regs()) + .finish() } } // LLIL_FLAG_PHI pub struct FlagPhi; +impl Operation<'_, M, F, FlagPhi> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_flag(&self) -> LowLevelILSSAFlag { + 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_flags(&self) -> Vec> { + let operand_list = self.get_operand_list(2); + operand_list + .chunks_exact(2) + .map(|chunk| { + let (flag, version) = (chunk[0], chunk[1]); + let flag = self + .function + .arch() + .flag_from_id(FlagId(flag as u32)) + .expect("Bad flag ID"); + LowLevelILSSAFlag::new(flag, version as u32) + }) + .collect() + } +} + impl Debug for Operation<'_, M, F, FlagPhi> where M: FunctionMutability, F: FunctionForm, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("FlagPhi").finish() + f.debug_struct("FlagPhi") + .field("dest_flag", &self.dest_flag()) + .field("source_flags", &self.source_flags()) + .finish() } } // LLIL_MEM_PHI pub struct MemPhi; +impl Operation<'_, M, F, MemPhi> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn dest_memory_version(&self) -> usize { + self.op.operands[0] as usize + } + + pub fn source_memory_versions(&self) -> Vec { + let operand_list = self.get_operand_list(1); + operand_list.into_iter().map(|op| op as usize).collect() + } +} + impl Debug for Operation<'_, M, F, MemPhi> where M: FunctionMutability, F: FunctionForm, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("MemPhi").finish() + f.debug_struct("MemPhi") + .field("dest_memory_version", &self.dest_memory_version()) + .field("source_memory_versions", &self.source_memory_versions()) + .finish() } } @@ -2026,6 +2111,35 @@ where } } +// LLIL_SEPARATE_PARAM_LIST_SSA +pub struct SeparateParamListSsa; + +impl<'func, M, F> Operation<'func, M, F, SeparateParamListSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn param_exprs(&self) -> Vec> { + self.get_operand_list(0) + .into_iter() + .map(|val| LowLevelExpressionIndex(val as usize)) + .map(|expr_idx| LowLevelILExpression::new(self.function, expr_idx)) + .collect() + } +} + +impl Debug for Operation<'_, M, F, SeparateParamListSsa> +where + M: FunctionMutability, + F: FunctionForm, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("SeparateParamListSsa") + .field("param_exprs", &self.param_exprs()) + .finish() + } +} + // TODO TEST_BIT pub trait OperationArguments: 'static {} @@ -2083,3 +2197,4 @@ impl OperationArguments for Assert {} impl OperationArguments for AssertSsa {} impl OperationArguments for ForceVersion {} impl OperationArguments for ForceVersionSsa {} +impl OperationArguments for SeparateParamListSsa {}