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/low_level_il/operation.rs | |
| parent | 6617b0afa09f549d0a5c9c53063f3ad8ab82b7e4 (diff) | |
[Rust] Support SSA form properly in low level IL
Diffstat (limited to 'rust/src/low_level_il/operation.rs')
| -rw-r--r-- | rust/src/low_level_il/operation.rs | 669 |
1 files changed, 652 insertions, 17 deletions
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 {} |
