summaryrefslogtreecommitdiff
path: root/rust/src/high_level_il
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/high_level_il')
-rw-r--r--rust/src/high_level_il/block.rs62
-rw-r--r--rust/src/high_level_il/function.rs293
-rw-r--r--rust/src/high_level_il/instruction.rs1124
-rw-r--r--rust/src/high_level_il/lift.rs462
-rw-r--r--rust/src/high_level_il/operation.rs550
5 files changed, 2491 insertions, 0 deletions
diff --git a/rust/src/high_level_il/block.rs b/rust/src/high_level_il/block.rs
new file mode 100644
index 00000000..e7f83425
--- /dev/null
+++ b/rust/src/high_level_il/block.rs
@@ -0,0 +1,62 @@
+use std::ops::Range;
+
+use crate::basic_block::{BasicBlock, BlockContext};
+use crate::rc::Ref;
+
+use super::{HighLevelILFunction, HighLevelILInstruction, HighLevelInstructionIndex};
+
+pub struct HighLevelILBlockIter {
+ function: Ref<HighLevelILFunction>,
+ range: Range<usize>,
+}
+
+impl Iterator for HighLevelILBlockIter {
+ type Item = HighLevelILInstruction;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.range
+ .next()
+ .map(HighLevelInstructionIndex)
+ // TODO: Is this already MAPPED>!>?!? If so we map twice that is BAD!!!!
+ .and_then(|i| self.function.instruction_from_index(i))
+ }
+}
+
+pub struct HighLevelILBlock {
+ pub(crate) function: Ref<HighLevelILFunction>,
+}
+
+impl core::fmt::Debug for HighLevelILBlock {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ // TODO: Actual basic block please
+ write!(f, "mlil_bb {:?}", self.function)
+ }
+}
+
+impl BlockContext for HighLevelILBlock {
+ type Instruction = HighLevelILInstruction;
+ type InstructionIndex = HighLevelInstructionIndex;
+ type Iter = HighLevelILBlockIter;
+
+ fn start(&self, block: &BasicBlock<Self>) -> HighLevelILInstruction {
+ // TODO: Is this start index already mappedd?????
+ self.function
+ .instruction_from_index(block.start_index())
+ .unwrap()
+ }
+
+ fn iter(&self, block: &BasicBlock<Self>) -> HighLevelILBlockIter {
+ HighLevelILBlockIter {
+ function: self.function.to_owned(),
+ range: block.start_index().0..block.end_index().0,
+ }
+ }
+}
+
+impl Clone for HighLevelILBlock {
+ fn clone(&self) -> Self {
+ HighLevelILBlock {
+ function: self.function.to_owned(),
+ }
+ }
+}
diff --git a/rust/src/high_level_il/function.rs b/rust/src/high_level_il/function.rs
new file mode 100644
index 00000000..aad16e14
--- /dev/null
+++ b/rust/src/high_level_il/function.rs
@@ -0,0 +1,293 @@
+use std::fmt::{Debug, Formatter};
+use std::hash::{Hash, Hasher};
+
+use binaryninjacore_sys::*;
+
+use super::{HighLevelILBlock, HighLevelILInstruction, HighLevelInstructionIndex};
+use crate::basic_block::BasicBlock;
+use crate::function::{Function, Location};
+use crate::rc::{Array, Ref, RefCountable};
+use crate::variable::{SSAVariable, Variable};
+
+pub struct HighLevelILFunction {
+ pub(crate) full_ast: bool,
+ pub(crate) handle: *mut BNHighLevelILFunction,
+}
+
+impl HighLevelILFunction {
+ pub(crate) unsafe fn ref_from_raw(
+ handle: *mut BNHighLevelILFunction,
+ full_ast: bool,
+ ) -> Ref<Self> {
+ debug_assert!(!handle.is_null());
+ Self { handle, full_ast }.to_owned()
+ }
+
+ pub fn instruction_from_index(
+ &self,
+ index: HighLevelInstructionIndex,
+ ) -> Option<HighLevelILInstruction> {
+ if index.0 >= self.instruction_count() {
+ None
+ } else {
+ Some(HighLevelILInstruction::new(self.to_owned(), index))
+ }
+ }
+
+ pub fn instruction_from_expr_index(
+ &self,
+ expr_index: HighLevelInstructionIndex,
+ ) -> Option<HighLevelILInstruction> {
+ if expr_index.0 >= self.expression_count() {
+ None
+ } else {
+ Some(HighLevelILInstruction::new_expr(
+ self.to_owned(),
+ expr_index,
+ ))
+ }
+ }
+
+ // TODO: This returns an expression index!
+ pub fn root_instruction_index(&self) -> HighLevelInstructionIndex {
+ HighLevelInstructionIndex(unsafe { BNGetHighLevelILRootExpr(self.handle) })
+ }
+
+ pub fn root(&self) -> HighLevelILInstruction {
+ HighLevelILInstruction::new_expr(self.as_ast(), self.root_instruction_index())
+ }
+
+ pub fn set_root(&self, new_root: &HighLevelILInstruction) {
+ unsafe { BNSetHighLevelILRootExpr(self.handle, new_root.expr_index.0) }
+ }
+
+ pub fn instruction_count(&self) -> usize {
+ unsafe { BNGetHighLevelILInstructionCount(self.handle) }
+ }
+
+ pub fn expression_count(&self) -> usize {
+ unsafe { BNGetHighLevelILExprCount(self.handle) }
+ }
+
+ pub fn ssa_form(&self) -> HighLevelILFunction {
+ let ssa = unsafe { BNGetHighLevelILSSAForm(self.handle) };
+ assert!(!ssa.is_null());
+ HighLevelILFunction {
+ handle: ssa,
+ full_ast: self.full_ast,
+ }
+ }
+
+ pub fn function(&self) -> Ref<Function> {
+ unsafe {
+ let func = BNGetHighLevelILOwnerFunction(self.handle);
+ Function::ref_from_raw(func)
+ }
+ }
+
+ pub fn basic_blocks(&self) -> Array<BasicBlock<HighLevelILBlock>> {
+ let mut count = 0;
+ let blocks = unsafe { BNGetHighLevelILBasicBlockList(self.handle, &mut count) };
+ let context = HighLevelILBlock {
+ function: self.to_owned(),
+ };
+ unsafe { Array::new(blocks, count, context) }
+ }
+
+ pub fn as_ast(&self) -> Ref<HighLevelILFunction> {
+ Self {
+ handle: self.handle,
+ full_ast: true,
+ }
+ .to_owned()
+ }
+
+ pub fn as_non_ast(&self) -> Ref<HighLevelILFunction> {
+ Self {
+ handle: self.handle,
+ full_ast: false,
+ }
+ .to_owned()
+ }
+
+ // TODO: Rename to `current_location`?
+ pub fn current_address(&self) -> Location {
+ let addr = unsafe { BNHighLevelILGetCurrentAddress(self.handle) };
+ Location::from(addr)
+ }
+
+ // TODO: Rename to `set_current_location`?
+ pub fn set_current_address(&self, location: impl Into<Location>) {
+ let location = location.into();
+ let arch = location
+ .arch
+ .map(|a| a.handle)
+ .unwrap_or_else(std::ptr::null_mut);
+ unsafe { BNHighLevelILSetCurrentAddress(self.handle, arch, location.addr) }
+ }
+
+ /// Gets the instruction that contains the given SSA variable's definition.
+ ///
+ /// Since SSA variables can only be defined once, this will return the single instruction where that occurs.
+ /// For SSA variable version 0s, which don't have definitions, this will return None instead.
+ pub fn ssa_variable_definition(&self, variable: SSAVariable) -> Option<HighLevelILInstruction> {
+ let index = unsafe {
+ BNGetHighLevelILSSAVarDefinition(
+ self.handle,
+ &variable.variable.into(),
+ variable.version,
+ )
+ };
+ self.instruction_from_index(HighLevelInstructionIndex(index))
+ }
+
+ pub fn ssa_memory_definition(&self, version: usize) -> Option<HighLevelILInstruction> {
+ let index = unsafe { BNGetHighLevelILSSAMemoryDefinition(self.handle, version) };
+ self.instruction_from_index(HighLevelInstructionIndex(index))
+ }
+
+ /// Gets all the instructions that use the given SSA variable.
+ pub fn ssa_variable_uses(&self, variable: SSAVariable) -> Array<HighLevelILInstruction> {
+ let mut count = 0;
+ let instrs = unsafe {
+ BNGetHighLevelILSSAVarUses(
+ self.handle,
+ &variable.variable.into(),
+ variable.version,
+ &mut count,
+ )
+ };
+ assert!(!instrs.is_null());
+ unsafe { Array::new(instrs, count, self.to_owned()) }
+ }
+
+ pub fn ssa_memory_uses(&self, version: usize) -> Array<HighLevelILInstruction> {
+ let mut count = 0;
+ let instrs = unsafe { BNGetHighLevelILSSAMemoryUses(self.handle, version, &mut count) };
+ assert!(!instrs.is_null());
+ unsafe { Array::new(instrs, count, self.to_owned()) }
+ }
+
+ /// Determines if `variable` is live at any point in the function
+ pub fn is_ssa_variable_live(&self, variable: SSAVariable) -> bool {
+ unsafe {
+ BNIsHighLevelILSSAVarLive(self.handle, &variable.variable.into(), variable.version)
+ }
+ }
+
+ /// Determines if `variable` is live at a given point in the function
+ pub fn is_ssa_variable_live_at(
+ &self,
+ variable: SSAVariable,
+ instr: &HighLevelILInstruction,
+ ) -> bool {
+ unsafe {
+ BNIsHighLevelILSSAVarLiveAt(
+ self.handle,
+ &variable.variable.into(),
+ variable.version,
+ instr.expr_index.0,
+ )
+ }
+ }
+
+ pub fn variable_definitions(&self, variable: Variable) -> Array<HighLevelILInstruction> {
+ let mut count = 0;
+ let defs = unsafe {
+ BNGetHighLevelILVariableDefinitions(self.handle, &variable.into(), &mut count)
+ };
+ assert!(!defs.is_null());
+ unsafe { Array::new(defs, count, self.to_owned()) }
+ }
+
+ pub fn variable_uses(&self, variable: Variable) -> Array<HighLevelILInstruction> {
+ let mut count = 0;
+ let instrs =
+ unsafe { BNGetHighLevelILVariableUses(self.handle, &variable.into(), &mut count) };
+ assert!(!instrs.is_null());
+ unsafe { Array::new(instrs, count, self.to_owned()) }
+ }
+
+ /// Determines if `variable` is live at a given point in the function
+ pub fn is_variable_live_at(&self, variable: Variable, instr: &HighLevelILInstruction) -> bool {
+ unsafe { BNIsHighLevelILVarLiveAt(self.handle, &variable.into(), instr.expr_index.0) }
+ }
+
+ /// This gets just the HLIL variables - you may be interested in the union
+ /// of [`Function::parameter_variables`] and [`HighLevelILFunction::aliased_variables`] as well for all the
+ /// variables used in the function
+ pub fn variables(&self) -> Array<Variable> {
+ let mut count = 0;
+ let variables = unsafe { BNGetHighLevelILVariables(self.handle, &mut count) };
+ assert!(!variables.is_null());
+ unsafe { Array::new(variables, count, ()) }
+ }
+
+ /// This returns a list of Variables that are taken reference to and used
+ /// elsewhere. You may also wish to consider [`HighLevelILFunction::variables`]
+ /// and [`Function::parameter_variables`]
+ pub fn aliased_variables(&self) -> Array<Variable> {
+ let mut count = 0;
+ let variables = unsafe { BNGetHighLevelILAliasedVariables(self.handle, &mut count) };
+ assert!(!variables.is_null());
+ unsafe { Array::new(variables, count, ()) }
+ }
+
+ /// This gets the HLIL SSA variables for a given [`Variable`].
+ pub fn ssa_variables(&self, variable: &Variable) -> Array<SSAVariable> {
+ let mut count = 0;
+ let raw_variable = BNVariable::from(variable);
+ let variables =
+ unsafe { BNGetHighLevelILVariableSSAVersions(self.handle, &raw_variable, &mut count) };
+ unsafe { Array::new(variables, count, *variable) }
+ }
+}
+
+impl Debug for HighLevelILFunction {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("HighLevelILFunction")
+ .field("arch", &self.function().arch())
+ .field("instruction_count", &self.instruction_count())
+ .field("expression_count", &self.expression_count())
+ .field("root", &self.root())
+ .field("root", &self.root())
+ .finish()
+ }
+}
+
+unsafe impl Send for HighLevelILFunction {}
+unsafe impl Sync for HighLevelILFunction {}
+
+impl Eq for HighLevelILFunction {}
+impl PartialEq for HighLevelILFunction {
+ fn eq(&self, rhs: &Self) -> bool {
+ self.function().eq(&rhs.function())
+ }
+}
+
+impl Hash for HighLevelILFunction {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.function().hash(state)
+ }
+}
+
+impl ToOwned for HighLevelILFunction {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+unsafe impl RefCountable for HighLevelILFunction {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
+ Ref::new(Self {
+ handle: BNNewHighLevelILFunctionReference(handle.handle),
+ full_ast: handle.full_ast,
+ })
+ }
+
+ unsafe fn dec_ref(handle: &Self) {
+ BNFreeHighLevelILFunction(handle.handle);
+ }
+}
diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs
new file mode 100644
index 00000000..40ac164b
--- /dev/null
+++ b/rust/src/high_level_il/instruction.rs
@@ -0,0 +1,1124 @@
+use binaryninjacore_sys::*;
+use std::fmt;
+use std::fmt::{Debug, Display, Formatter};
+
+use super::operation::*;
+use super::{HighLevelILFunction, HighLevelILLiftedInstruction, HighLevelILLiftedInstructionKind};
+use crate::architecture::{CoreIntrinsic, IntrinsicId};
+use crate::confidence::Conf;
+use crate::disassembly::DisassemblyTextLine;
+use crate::operand_iter::OperandIter;
+use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref};
+use crate::types::Type;
+use crate::variable::{ConstantData, RegisterValue, SSAVariable, Variable};
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct HighLevelInstructionIndex(pub usize);
+
+impl HighLevelInstructionIndex {
+ pub fn next(&self) -> Self {
+ Self(self.0 + 1)
+ }
+}
+
+impl From<usize> for HighLevelInstructionIndex {
+ fn from(index: usize) -> Self {
+ Self(index)
+ }
+}
+
+impl From<u64> for HighLevelInstructionIndex {
+ fn from(index: u64) -> Self {
+ Self(index as usize)
+ }
+}
+
+impl Display for HighLevelInstructionIndex {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.write_fmt(format_args!("{}", self.0))
+ }
+}
+
+#[derive(Clone)]
+pub struct HighLevelILInstruction {
+ pub function: Ref<HighLevelILFunction>,
+ pub address: u64,
+ pub expr_index: HighLevelInstructionIndex,
+ pub size: usize,
+ pub kind: HighLevelILInstructionKind,
+}
+
+impl HighLevelILInstruction {
+ pub(crate) fn new(
+ function: Ref<HighLevelILFunction>,
+ index: HighLevelInstructionIndex,
+ ) -> Self {
+ let expr_index = unsafe { BNGetHighLevelILIndexForInstruction(function.handle, index.0) };
+ Self::new_expr(function, HighLevelInstructionIndex(expr_index))
+ }
+
+ // TODO: I need HighLevelILExpression YESTERDAY!!!!
+ pub(crate) fn new_expr(
+ function: Ref<HighLevelILFunction>,
+ expr_index: HighLevelInstructionIndex,
+ ) -> Self {
+ let op =
+ unsafe { BNGetHighLevelILByIndex(function.handle, expr_index.0, function.full_ast) };
+ use BNHighLevelILOperation::*;
+ use HighLevelILInstructionKind as Op;
+ let kind = match op.operation {
+ HLIL_NOP => Op::Nop,
+ HLIL_BREAK => Op::Break,
+ HLIL_CONTINUE => Op::Continue,
+ HLIL_NORET => Op::Noret,
+ HLIL_UNREACHABLE => Op::Unreachable,
+ HLIL_BP => Op::Bp,
+ HLIL_UNDEF => Op::Undef,
+ HLIL_UNIMPL => Op::Unimpl,
+ HLIL_ADC => Op::Adc(BinaryOpCarry {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ carry: op.operands[2] as usize,
+ }),
+ HLIL_SBB => Op::Sbb(BinaryOpCarry {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ carry: op.operands[2] as usize,
+ }),
+ HLIL_RLC => Op::Rlc(BinaryOpCarry {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ carry: op.operands[2] as usize,
+ }),
+ HLIL_RRC => Op::Rrc(BinaryOpCarry {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ carry: op.operands[2] as usize,
+ }),
+ HLIL_ADD => Op::Add(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_SUB => Op::Sub(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_AND => Op::And(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_OR => Op::Or(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_XOR => Op::Xor(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_LSL => Op::Lsl(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_LSR => Op::Lsr(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_ASR => Op::Asr(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_ROL => Op::Rol(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_ROR => Op::Ror(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MUL => Op::Mul(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MULU_DP => Op::MuluDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MULS_DP => Op::MulsDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_DIVU => Op::Divu(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_DIVU_DP => Op::DivuDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_DIVS => Op::Divs(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_DIVS_DP => Op::DivsDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MODU => Op::Modu(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MODU_DP => Op::ModuDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MODS => Op::Mods(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_MODS_DP => Op::ModsDp(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_E => Op::CmpE(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_NE => Op::CmpNe(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_SLT => Op::CmpSlt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_ULT => Op::CmpUlt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_SLE => Op::CmpSle(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_ULE => Op::CmpUle(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_SGE => Op::CmpSge(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_UGE => Op::CmpUge(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_SGT => Op::CmpSgt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_CMP_UGT => Op::CmpUgt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_TEST_BIT => Op::TestBit(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FADD => Op::Fadd(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FSUB => Op::Fsub(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FMUL => Op::Fmul(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FDIV => Op::Fdiv(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_E => Op::FcmpE(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_NE => Op::FcmpNe(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_LT => Op::FcmpLt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_LE => Op::FcmpLe(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_GE => Op::FcmpGe(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_GT => Op::FcmpGt(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_O => Op::FcmpO(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_FCMP_UO => Op::FcmpUo(BinaryOp {
+ left: op.operands[0] as usize,
+ right: op.operands[1] as usize,
+ }),
+ HLIL_ARRAY_INDEX => Op::ArrayIndex(ArrayIndex {
+ src: op.operands[0] as usize,
+ index: op.operands[1] as usize,
+ }),
+ HLIL_ARRAY_INDEX_SSA => Op::ArrayIndexSsa(ArrayIndexSsa {
+ src: op.operands[0] as usize,
+ src_memory: op.operands[1],
+ index: op.operands[2] as usize,
+ }),
+ HLIL_ASSIGN => Op::Assign(Assign {
+ dest: op.operands[0] as usize,
+ src: op.operands[1] as usize,
+ }),
+ HLIL_ASSIGN_MEM_SSA => Op::AssignMemSsa(AssignMemSsa {
+ dest: op.operands[0] as usize,
+ dest_memory: op.operands[1],
+ src: op.operands[2] as usize,
+ src_memory: op.operands[3],
+ }),
+ HLIL_ASSIGN_UNPACK => Op::AssignUnpack(AssignUnpack {
+ num_dests: op.operands[0] as usize,
+ first_dest: op.operands[1] as usize,
+ src: op.operands[2] as usize,
+ }),
+ HLIL_ASSIGN_UNPACK_MEM_SSA => Op::AssignUnpackMemSsa(AssignUnpackMemSsa {
+ num_dests: op.operands[0] as usize,
+ first_dest: op.operands[1] as usize,
+ dest_memory: op.operands[2],
+ src: op.operands[3] as usize,
+ src_memory: op.operands[4],
+ }),
+ HLIL_BLOCK => Op::Block(Block {
+ num_params: op.operands[0] as usize,
+ first_param: op.operands[1] as usize,
+ }),
+ HLIL_CALL => Op::Call(Call {
+ dest: op.operands[0] as usize,
+ num_params: op.operands[1] as usize,
+ first_param: op.operands[2] as usize,
+ }),
+ HLIL_TAILCALL => Op::Tailcall(Call {
+ dest: op.operands[0] as usize,
+ num_params: op.operands[1] as usize,
+ first_param: op.operands[2] as usize,
+ }),
+ HLIL_CALL_SSA => Op::CallSsa(CallSsa {
+ dest: op.operands[0] as usize,
+ num_params: op.operands[1] as usize,
+ first_param: op.operands[2] as usize,
+ dest_memory: op.operands[3],
+ src_memory: op.operands[4],
+ }),
+ HLIL_CASE => Op::Case(Case {
+ num_values: op.operands[0] as usize,
+ first_value: op.operands[1] as usize,
+ body: op.operands[2] as usize,
+ }),
+ HLIL_CONST => Op::Const(Const {
+ constant: op.operands[0],
+ }),
+ HLIL_CONST_PTR => Op::ConstPtr(Const {
+ constant: op.operands[0],
+ }),
+ HLIL_IMPORT => Op::Import(Const {
+ constant: op.operands[0],
+ }),
+ HLIL_CONST_DATA => Op::ConstData(ConstData {
+ constant_data_kind: op.operands[0] as u32,
+ constant_data_value: op.operands[1] as i64,
+ size: op.size,
+ }),
+ HLIL_DEREF => Op::Deref(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_ADDRESS_OF => Op::AddressOf(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_NEG => Op::Neg(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_NOT => Op::Not(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_SX => Op::Sx(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_ZX => Op::Zx(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_LOW_PART => Op::LowPart(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FSQRT => Op::Fsqrt(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FNEG => Op::Fneg(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FABS => Op::Fabs(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FLOAT_CONV => Op::FloatConv(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FLOOR => Op::Floor(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_CEIL => Op::Ceil(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_FTRUNC => Op::Ftrunc(UnaryOp {
+ src: op.operands[0] as usize,
+ }),
+ HLIL_DEREF_FIELD_SSA => Op::DerefFieldSsa(DerefFieldSsa {
+ src: op.operands[0] as usize,
+ src_memory: op.operands[1],
+ offset: op.operands[2],
+ member_index: get_member_index(op.operands[3]),
+ }),
+ HLIL_DEREF_SSA => Op::DerefSsa(DerefSsa {
+ src: op.operands[0] as usize,
+ src_memory: op.operands[1],
+ }),
+ HLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr {
+ constant: op.operands[0],
+ offset: op.operands[1],
+ }),
+ HLIL_FLOAT_CONST => Op::FloatConst(FloatConst {
+ constant: get_float(op.operands[0], op.size),
+ }),
+ HLIL_FOR => Op::For(ForLoop {
+ init: op.operands[0] as usize,
+ condition: op.operands[1] as usize,
+ update: op.operands[2] as usize,
+ body: op.operands[3] as usize,
+ }),
+ HLIL_FOR_SSA => Op::ForSsa(ForLoopSsa {
+ init: op.operands[0] as usize,
+ condition_phi: op.operands[1] as usize,
+ condition: op.operands[2] as usize,
+ update: op.operands[3] as usize,
+ body: op.operands[4] as usize,
+ }),
+ HLIL_GOTO => Op::Goto(Label {
+ target: op.operands[0],
+ }),
+ HLIL_LABEL => Op::Label(Label {
+ target: op.operands[0],
+ }),
+ HLIL_IF => Op::If(If {
+ condition: op.operands[0] as usize,
+ cond_true: op.operands[1] as usize,
+ cond_false: op.operands[2] as usize,
+ }),
+ HLIL_INTRINSIC => Op::Intrinsic(Intrinsic {
+ intrinsic: op.operands[0] as u32,
+ num_params: op.operands[1] as usize,
+ first_param: op.operands[2] as usize,
+ }),
+ HLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa {
+ intrinsic: op.operands[0] as u32,
+ num_params: op.operands[1] as usize,
+ first_param: op.operands[2] as usize,
+ dest_memory: op.operands[3],
+ src_memory: op.operands[4],
+ }),
+ HLIL_JUMP => Op::Jump(Jump {
+ dest: op.operands[0] as usize,
+ }),
+ HLIL_MEM_PHI => Op::MemPhi(MemPhi {
+ dest: op.operands[0],
+ num_srcs: op.operands[1] as usize,
+ first_src: op.operands[2] as usize,
+ }),
+ HLIL_RET => Op::Ret(Ret {
+ num_srcs: op.operands[0] as usize,
+ first_src: op.operands[1] as usize,
+ }),
+ HLIL_SPLIT => Op::Split(Split {
+ high: op.operands[0] as usize,
+ low: op.operands[1] as usize,
+ }),
+ HLIL_STRUCT_FIELD => Op::StructField(StructField {
+ src: op.operands[0] as usize,
+ offset: op.operands[1],
+ member_index: get_member_index(op.operands[2]),
+ }),
+ HLIL_DEREF_FIELD => Op::DerefField(StructField {
+ src: op.operands[0] as usize,
+ offset: op.operands[1],
+ member_index: get_member_index(op.operands[2]),
+ }),
+ HLIL_SWITCH => Op::Switch(Switch {
+ condition: op.operands[0] as usize,
+ default: op.operands[1] as usize,
+ num_cases: op.operands[2] as usize,
+ first_case: op.operands[3] as usize,
+ }),
+ HLIL_SYSCALL => Op::Syscall(Syscall {
+ num_params: op.operands[0] as usize,
+ first_param: op.operands[1] as usize,
+ }),
+ HLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa {
+ num_params: op.operands[0] as usize,
+ first_param: op.operands[1] as usize,
+ dest_memory: op.operands[2],
+ src_memory: op.operands[3],
+ }),
+ HLIL_TRAP => Op::Trap(Trap {
+ vector: op.operands[0],
+ }),
+ HLIL_VAR_DECLARE => Op::VarDeclare(Var {
+ var: get_var(op.operands[0]),
+ }),
+ HLIL_VAR => Op::Var(Var {
+ var: get_var(op.operands[0]),
+ }),
+ HLIL_VAR_INIT => Op::VarInit(VarInit {
+ dest: get_var(op.operands[0]),
+ src: op.operands[1] as usize,
+ }),
+ HLIL_VAR_INIT_SSA => Op::VarInitSsa(VarInitSsa {
+ dest: get_var_ssa((op.operands[0], op.operands[1] as usize)),
+ src: op.operands[2] as usize,
+ }),
+ HLIL_VAR_PHI => Op::VarPhi(VarPhi {
+ dest: get_var_ssa((op.operands[0], op.operands[1] as usize)),
+ num_srcs: op.operands[2] as usize,
+ first_src: op.operands[3] as usize,
+ }),
+ HLIL_VAR_SSA => Op::VarSsa(VarSsa {
+ var: get_var_ssa((op.operands[0], op.operands[1] as usize)),
+ }),
+ HLIL_WHILE => Op::While(While {
+ condition: op.operands[0] as usize,
+ body: op.operands[1] as usize,
+ }),
+ HLIL_DO_WHILE => Op::DoWhile(While {
+ body: op.operands[0] as usize,
+ condition: op.operands[1] as usize,
+ }),
+ HLIL_WHILE_SSA => Op::WhileSsa(WhileSsa {
+ condition_phi: op.operands[0] as usize,
+ condition: op.operands[1] as usize,
+ body: op.operands[2] as usize,
+ }),
+ HLIL_DO_WHILE_SSA => Op::DoWhileSsa(WhileSsa {
+ condition_phi: op.operands[0] as usize,
+ condition: op.operands[1] as usize,
+ body: op.operands[2] as usize,
+ }),
+ };
+ Self {
+ function,
+ address: op.address,
+ expr_index,
+ size: op.size,
+ kind,
+ }
+ }
+
+ pub fn lift(&self) -> HighLevelILLiftedInstruction {
+ use HighLevelILInstructionKind::*;
+ use HighLevelILLiftedInstructionKind as Lifted;
+ let kind = match self.kind {
+ Nop => Lifted::Nop,
+ Break => Lifted::Break,
+ Continue => Lifted::Continue,
+ Noret => Lifted::Noret,
+ Unreachable => Lifted::Unreachable,
+ Bp => Lifted::Bp,
+ Undef => Lifted::Undef,
+ Unimpl => Lifted::Unimpl,
+
+ Adc(op) => Lifted::Adc(self.lift_binary_op_carry(op)),
+ Sbb(op) => Lifted::Sbb(self.lift_binary_op_carry(op)),
+ Rlc(op) => Lifted::Rlc(self.lift_binary_op_carry(op)),
+ Rrc(op) => Lifted::Rrc(self.lift_binary_op_carry(op)),
+
+ Add(op) => Lifted::Add(self.lift_binary_op(op)),
+ Sub(op) => Lifted::Sub(self.lift_binary_op(op)),
+ And(op) => Lifted::And(self.lift_binary_op(op)),
+ Or(op) => Lifted::Or(self.lift_binary_op(op)),
+ Xor(op) => Lifted::Xor(self.lift_binary_op(op)),
+ Lsl(op) => Lifted::Lsl(self.lift_binary_op(op)),
+ Lsr(op) => Lifted::Lsr(self.lift_binary_op(op)),
+ Asr(op) => Lifted::Asr(self.lift_binary_op(op)),
+ Rol(op) => Lifted::Rol(self.lift_binary_op(op)),
+ Ror(op) => Lifted::Ror(self.lift_binary_op(op)),
+ Mul(op) => Lifted::Mul(self.lift_binary_op(op)),
+ MuluDp(op) => Lifted::MuluDp(self.lift_binary_op(op)),
+ MulsDp(op) => Lifted::MulsDp(self.lift_binary_op(op)),
+ Divu(op) => Lifted::Divu(self.lift_binary_op(op)),
+ DivuDp(op) => Lifted::DivuDp(self.lift_binary_op(op)),
+ Divs(op) => Lifted::Divs(self.lift_binary_op(op)),
+ DivsDp(op) => Lifted::DivsDp(self.lift_binary_op(op)),
+ Modu(op) => Lifted::Modu(self.lift_binary_op(op)),
+ ModuDp(op) => Lifted::ModuDp(self.lift_binary_op(op)),
+ Mods(op) => Lifted::Mods(self.lift_binary_op(op)),
+ ModsDp(op) => Lifted::ModsDp(self.lift_binary_op(op)),
+ CmpE(op) => Lifted::CmpE(self.lift_binary_op(op)),
+ CmpNe(op) => Lifted::CmpNe(self.lift_binary_op(op)),
+ CmpSlt(op) => Lifted::CmpSlt(self.lift_binary_op(op)),
+ CmpUlt(op) => Lifted::CmpUlt(self.lift_binary_op(op)),
+ CmpSle(op) => Lifted::CmpSle(self.lift_binary_op(op)),
+ CmpUle(op) => Lifted::CmpUle(self.lift_binary_op(op)),
+ CmpSge(op) => Lifted::CmpSge(self.lift_binary_op(op)),
+ CmpUge(op) => Lifted::CmpUge(self.lift_binary_op(op)),
+ CmpSgt(op) => Lifted::CmpSgt(self.lift_binary_op(op)),
+ CmpUgt(op) => Lifted::CmpUgt(self.lift_binary_op(op)),
+ TestBit(op) => Lifted::TestBit(self.lift_binary_op(op)),
+ AddOverflow(op) => Lifted::AddOverflow(self.lift_binary_op(op)),
+ Fadd(op) => Lifted::Fadd(self.lift_binary_op(op)),
+ Fsub(op) => Lifted::Fsub(self.lift_binary_op(op)),
+ Fmul(op) => Lifted::Fmul(self.lift_binary_op(op)),
+ Fdiv(op) => Lifted::Fdiv(self.lift_binary_op(op)),
+ FcmpE(op) => Lifted::FcmpE(self.lift_binary_op(op)),
+ FcmpNe(op) => Lifted::FcmpNe(self.lift_binary_op(op)),
+ FcmpLt(op) => Lifted::FcmpLt(self.lift_binary_op(op)),
+ FcmpLe(op) => Lifted::FcmpLe(self.lift_binary_op(op)),
+ FcmpGe(op) => Lifted::FcmpGe(self.lift_binary_op(op)),
+ FcmpGt(op) => Lifted::FcmpGt(self.lift_binary_op(op)),
+ FcmpO(op) => Lifted::FcmpO(self.lift_binary_op(op)),
+ FcmpUo(op) => Lifted::FcmpUo(self.lift_binary_op(op)),
+
+ ArrayIndex(op) => Lifted::ArrayIndex(LiftedArrayIndex {
+ src: self.lift_operand(op.src),
+ index: self.lift_operand(op.index),
+ }),
+ ArrayIndexSsa(op) => Lifted::ArrayIndexSsa(LiftedArrayIndexSsa {
+ src: self.lift_operand(op.src),
+ src_memory: op.src_memory,
+ index: self.lift_operand(op.index),
+ }),
+ Assign(op) => Lifted::Assign(LiftedAssign {
+ dest: self.lift_operand(op.dest),
+ src: self.lift_operand(op.src),
+ }),
+ AssignUnpack(op) => Lifted::AssignUnpack(LiftedAssignUnpack {
+ dest: self.lift_instruction_list(op.first_dest, op.num_dests),
+ src: self.lift_operand(op.src),
+ }),
+ AssignMemSsa(op) => Lifted::AssignMemSsa(LiftedAssignMemSsa {
+ dest: self.lift_operand(op.dest),
+ dest_memory: op.dest_memory,
+ src: self.lift_operand(op.src),
+ src_memory: op.src_memory,
+ }),
+ AssignUnpackMemSsa(op) => Lifted::AssignUnpackMemSsa(LiftedAssignUnpackMemSsa {
+ dest: self.lift_instruction_list(op.first_dest, op.num_dests),
+ dest_memory: op.dest_memory,
+ src: self.lift_operand(op.src),
+ src_memory: op.src_memory,
+ }),
+ Block(op) => Lifted::Block(LiftedBlock {
+ body: self.lift_instruction_list(op.first_param, op.num_params),
+ }),
+
+ Call(op) => Lifted::Call(self.lift_call(op)),
+ Tailcall(op) => Lifted::Tailcall(self.lift_call(op)),
+ CallSsa(op) => Lifted::CallSsa(LiftedCallSsa {
+ dest: self.lift_operand(op.dest),
+ params: self.lift_instruction_list(op.first_param, op.num_params),
+ dest_memory: op.dest_memory,
+ src_memory: op.src_memory,
+ }),
+
+ Case(op) => Lifted::Case(LiftedCase {
+ values: self.lift_instruction_list(op.first_value, op.num_values),
+ body: self.lift_operand(op.body),
+ }),
+ Const(op) => Lifted::Const(op),
+ ConstPtr(op) => Lifted::ConstPtr(op),
+ Import(op) => Lifted::Import(op),
+ ConstData(op) => Lifted::ConstData(LiftedConstData {
+ constant_data: ConstantData::new(
+ self.function.function(),
+ RegisterValue {
+ // TODO: Replace with a From<u32> for RegisterValueType.
+ // TODO: We might also want to change the type of `op.constant_data_kind`
+ // TODO: To RegisterValueType and do the conversion when creating instruction.
+ state: unsafe {
+ std::mem::transmute::<u32, BNRegisterValueType>(op.constant_data_kind)
+ },
+ value: op.constant_data_value,
+ offset: 0,
+ size: op.size,
+ },
+ ),
+ }),
+
+ Deref(op) => Lifted::Deref(self.lift_unary_op(op)),
+ AddressOf(op) => Lifted::AddressOf(self.lift_unary_op(op)),
+ Neg(op) => Lifted::Neg(self.lift_unary_op(op)),
+ Not(op) => Lifted::Not(self.lift_unary_op(op)),
+ Sx(op) => Lifted::Sx(self.lift_unary_op(op)),
+ Zx(op) => Lifted::Zx(self.lift_unary_op(op)),
+ LowPart(op) => Lifted::LowPart(self.lift_unary_op(op)),
+ BoolToInt(op) => Lifted::BoolToInt(self.lift_unary_op(op)),
+ UnimplMem(op) => Lifted::UnimplMem(self.lift_unary_op(op)),
+ Fsqrt(op) => Lifted::Fsqrt(self.lift_unary_op(op)),
+ Fneg(op) => Lifted::Fneg(self.lift_unary_op(op)),
+ Fabs(op) => Lifted::Fabs(self.lift_unary_op(op)),
+ FloatToInt(op) => Lifted::FloatToInt(self.lift_unary_op(op)),
+ IntToFloat(op) => Lifted::IntToFloat(self.lift_unary_op(op)),
+ FloatConv(op) => Lifted::FloatConv(self.lift_unary_op(op)),
+ RoundToInt(op) => Lifted::RoundToInt(self.lift_unary_op(op)),
+ Floor(op) => Lifted::Floor(self.lift_unary_op(op)),
+ Ceil(op) => Lifted::Ceil(self.lift_unary_op(op)),
+ Ftrunc(op) => Lifted::Ftrunc(self.lift_unary_op(op)),
+
+ DerefFieldSsa(op) => Lifted::DerefFieldSsa(LiftedDerefFieldSsa {
+ src: self.lift_operand(op.src),
+ src_memory: op.src_memory,
+ offset: op.offset,
+ member_index: op.member_index,
+ }),
+ DerefSsa(op) => Lifted::DerefSsa(LiftedDerefSsa {
+ src: self.lift_operand(op.src),
+ src_memory: op.src_memory,
+ }),
+ ExternPtr(op) => Lifted::ExternPtr(op),
+ FloatConst(op) => Lifted::FloatConst(op),
+ For(op) => Lifted::For(LiftedForLoop {
+ init: self.lift_operand(op.init),
+ condition: self.lift_operand(op.condition),
+ update: self.lift_operand(op.update),
+ body: self.lift_operand(op.body),
+ }),
+ Goto(op) => Lifted::Goto(self.lift_label(op)),
+ Label(op) => Lifted::Label(self.lift_label(op)),
+ ForSsa(op) => Lifted::ForSsa(LiftedForLoopSsa {
+ init: self.lift_operand(op.init),
+ condition_phi: self.lift_operand(op.condition_phi),
+ condition: self.lift_operand(op.condition),
+ update: self.lift_operand(op.update),
+ body: self.lift_operand(op.body),
+ }),
+ If(op) => Lifted::If(LiftedIf {
+ condition: self.lift_operand(op.condition),
+ cond_true: self.lift_operand(op.cond_true),
+ cond_false: self.lift_operand(op.cond_false),
+ }),
+ Intrinsic(op) => Lifted::Intrinsic(LiftedIntrinsic {
+ intrinsic: CoreIntrinsic::new(
+ self.function.function().arch(),
+ IntrinsicId(op.intrinsic),
+ )
+ .expect("Invalid intrinsic"),
+ params: self.lift_instruction_list(op.first_param, op.num_params),
+ }),
+ IntrinsicSsa(op) => Lifted::IntrinsicSsa(LiftedIntrinsicSsa {
+ intrinsic: CoreIntrinsic::new(
+ self.function.function().arch(),
+ IntrinsicId(op.intrinsic),
+ )
+ .expect("Invalid intrinsic"),
+ params: self.lift_instruction_list(op.first_param, op.num_params),
+ dest_memory: op.dest_memory,
+ src_memory: op.src_memory,
+ }),
+ Jump(op) => Lifted::Jump(LiftedJump {
+ dest: self.lift_operand(op.dest),
+ }),
+ MemPhi(op) => Lifted::MemPhi(LiftedMemPhi {
+ dest: op.dest,
+ src: OperandIter::new(&*self.function, op.first_src, op.num_srcs).collect(),
+ }),
+ Ret(op) => Lifted::Ret(LiftedRet {
+ src: self.lift_instruction_list(op.first_src, op.num_srcs),
+ }),
+ Split(op) => Lifted::Split(LiftedSplit {
+ high: self.lift_operand(op.high),
+ low: self.lift_operand(op.low),
+ }),
+ StructField(op) => Lifted::StructField(self.lift_struct_field(op)),
+ DerefField(op) => Lifted::DerefField(self.lift_struct_field(op)),
+ Switch(op) => Lifted::Switch(LiftedSwitch {
+ condition: self.lift_operand(op.condition),
+ default: self.lift_operand(op.default),
+ cases: self.lift_instruction_list(op.first_case, op.num_cases),
+ }),
+ Syscall(op) => Lifted::Syscall(LiftedSyscall {
+ params: self.lift_instruction_list(op.first_param, op.num_params),
+ }),
+ SyscallSsa(op) => Lifted::SyscallSsa(LiftedSyscallSsa {
+ params: self.lift_instruction_list(op.first_param, op.num_params),
+ dest_memory: op.dest_memory,
+ src_memory: op.src_memory,
+ }),
+ Trap(op) => Lifted::Trap(op),
+ VarDeclare(op) => Lifted::VarDeclare(op),
+ Var(op) => Lifted::Var(op),
+ VarInit(op) => Lifted::VarInit(LiftedVarInit {
+ dest: op.dest,
+ src: self.lift_operand(op.src),
+ }),
+ VarInitSsa(op) => Lifted::VarInitSsa(LiftedVarInitSsa {
+ dest: op.dest,
+ src: self.lift_operand(op.src),
+ }),
+ VarPhi(op) => Lifted::VarPhi(LiftedVarPhi {
+ dest: op.dest,
+ src: OperandIter::new(&*self.function, op.first_src, op.num_srcs)
+ .ssa_vars()
+ .collect(),
+ }),
+ VarSsa(op) => Lifted::VarSsa(op),
+
+ While(op) => Lifted::While(self.lift_while(op)),
+ DoWhile(op) => Lifted::DoWhile(self.lift_while(op)),
+
+ WhileSsa(op) => Lifted::WhileSsa(self.lift_while_ssa(op)),
+ DoWhileSsa(op) => Lifted::DoWhileSsa(self.lift_while_ssa(op)),
+ };
+ HighLevelILLiftedInstruction {
+ function: self.function.clone(),
+ address: self.address,
+ expr_index: self.expr_index,
+ size: self.size,
+ kind,
+ }
+ }
+
+ /// HLIL text lines
+ pub fn lines(&self) -> Array<DisassemblyTextLine> {
+ let mut count = 0;
+ let lines = unsafe {
+ BNGetHighLevelILExprText(
+ self.function.handle,
+ self.expr_index.0,
+ self.function.full_ast,
+ &mut count,
+ core::ptr::null_mut(),
+ )
+ };
+ unsafe { Array::new(lines, count, ()) }
+ }
+
+ /// Type of expression
+ pub fn expr_type(&self) -> Option<Conf<Ref<Type>>> {
+ let result = unsafe { BNGetHighLevelILExprType(self.function.handle, self.expr_index.0) };
+ (!result.type_.is_null()).then(|| {
+ Conf::new(
+ unsafe { Type::ref_from_raw(result.type_) },
+ result.confidence,
+ )
+ })
+ }
+
+ /// Version of active memory contents in SSA form for this instruction
+ pub fn ssa_memory_version(&self) -> usize {
+ unsafe {
+ BNGetHighLevelILSSAMemoryVersionAtILInstruction(self.function.handle, self.expr_index.0)
+ }
+ }
+
+ pub fn ssa_variable_version(&self, variable: Variable) -> SSAVariable {
+ let version = unsafe {
+ BNGetHighLevelILSSAVarVersionAtILInstruction(
+ self.function.handle,
+ &variable.into(),
+ self.expr_index.0,
+ )
+ };
+ SSAVariable::new(variable, version)
+ }
+
+ fn lift_operand(&self, expr_idx: usize) -> Box<HighLevelILLiftedInstruction> {
+ // TODO: UGH, if your gonna call it expr_idx, call the instruction and expression!!!!!
+ // TODO: We dont even need to say instruction in the type!
+ // TODO: IF you want to have an instruction type, there needs to be a separate expression type
+ // TODO: See the lowlevelil module.
+ let expr_idx_is_really_instr_idx = HighLevelInstructionIndex(expr_idx);
+ // TODO: Ugh, this is so dumb..... i want HighLevelILLiftedExpression yesterday!!!
+ let operand_instr = self
+ .function
+ .instruction_from_expr_index(expr_idx_is_really_instr_idx)
+ .unwrap();
+ // TODO: Why box it here??!?!?! insane.
+ Box::new(operand_instr.lift())
+ }
+
+ fn lift_binary_op(&self, op: BinaryOp) -> LiftedBinaryOp {
+ LiftedBinaryOp {
+ left: self.lift_operand(op.left),
+ right: self.lift_operand(op.right),
+ }
+ }
+
+ fn lift_binary_op_carry(&self, op: BinaryOpCarry) -> LiftedBinaryOpCarry {
+ LiftedBinaryOpCarry {
+ left: self.lift_operand(op.left),
+ right: self.lift_operand(op.right),
+ carry: self.lift_operand(op.carry),
+ }
+ }
+
+ fn lift_unary_op(&self, op: UnaryOp) -> LiftedUnaryOp {
+ LiftedUnaryOp {
+ src: self.lift_operand(op.src),
+ }
+ }
+
+ fn lift_label(&self, op: Label) -> LiftedLabel {
+ LiftedLabel {
+ target: GotoLabel {
+ function: self.function.function(),
+ target: op.target,
+ },
+ }
+ }
+
+ fn lift_call(&self, op: Call) -> LiftedCall {
+ LiftedCall {
+ dest: self.lift_operand(op.dest),
+ params: OperandIter::new(&*self.function, op.first_param, op.num_params)
+ .exprs()
+ .map(|expr| expr.lift())
+ .collect(),
+ }
+ }
+
+ fn lift_while(&self, op: While) -> LiftedWhile {
+ LiftedWhile {
+ condition: self.lift_operand(op.condition),
+ body: self.lift_operand(op.body),
+ }
+ }
+
+ fn lift_while_ssa(&self, op: WhileSsa) -> LiftedWhileSsa {
+ LiftedWhileSsa {
+ condition_phi: self.lift_operand(op.condition_phi),
+ condition: self.lift_operand(op.condition),
+ body: self.lift_operand(op.body),
+ }
+ }
+
+ fn lift_struct_field(&self, op: StructField) -> LiftedStructField {
+ LiftedStructField {
+ src: self.lift_operand(op.src),
+ offset: op.offset,
+ member_index: op.member_index,
+ }
+ }
+
+ fn lift_instruction_list(
+ &self,
+ first_instruction: usize,
+ num_instructions: usize,
+ ) -> Vec<HighLevelILLiftedInstruction> {
+ OperandIter::new(&*self.function, first_instruction, num_instructions)
+ .exprs()
+ .map(|expr| expr.lift())
+ .collect()
+ }
+}
+
+impl CoreArrayProvider for HighLevelILInstruction {
+ type Raw = usize;
+ type Context = Ref<HighLevelILFunction>;
+ type Wrapped<'a> = Self;
+}
+
+unsafe impl CoreArrayProviderInner for HighLevelILInstruction {
+ unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
+ unsafe { BNFreeILInstructionList(raw) }
+ }
+
+ unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
+ Self::new(context.clone(), HighLevelInstructionIndex(*raw))
+ }
+}
+
+impl Debug for HighLevelILInstruction {
+ fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
+ // TODO: Actual debug impl please!
+ write!(
+ f,
+ "<{} at 0x{:08}>",
+ core::any::type_name::<Self>(),
+ self.address,
+ )
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum HighLevelILInstructionKind {
+ Nop,
+ Break,
+ Continue,
+ Noret,
+ Unreachable,
+ Bp,
+ Undef,
+ Unimpl,
+ Adc(BinaryOpCarry),
+ Sbb(BinaryOpCarry),
+ Rlc(BinaryOpCarry),
+ Rrc(BinaryOpCarry),
+ Add(BinaryOp),
+ Sub(BinaryOp),
+ And(BinaryOp),
+ Or(BinaryOp),
+ Xor(BinaryOp),
+ Lsl(BinaryOp),
+ Lsr(BinaryOp),
+ Asr(BinaryOp),
+ Rol(BinaryOp),
+ Ror(BinaryOp),
+ Mul(BinaryOp),
+ MuluDp(BinaryOp),
+ MulsDp(BinaryOp),
+ Divu(BinaryOp),
+ DivuDp(BinaryOp),
+ Divs(BinaryOp),
+ DivsDp(BinaryOp),
+ Modu(BinaryOp),
+ ModuDp(BinaryOp),
+ Mods(BinaryOp),
+ ModsDp(BinaryOp),
+ CmpE(BinaryOp),
+ CmpNe(BinaryOp),
+ CmpSlt(BinaryOp),
+ CmpUlt(BinaryOp),
+ CmpSle(BinaryOp),
+ CmpUle(BinaryOp),
+ CmpSge(BinaryOp),
+ CmpUge(BinaryOp),
+ CmpSgt(BinaryOp),
+ CmpUgt(BinaryOp),
+ TestBit(BinaryOp),
+ AddOverflow(BinaryOp),
+ Fadd(BinaryOp),
+ Fsub(BinaryOp),
+ Fmul(BinaryOp),
+ Fdiv(BinaryOp),
+ FcmpE(BinaryOp),
+ FcmpNe(BinaryOp),
+ FcmpLt(BinaryOp),
+ FcmpLe(BinaryOp),
+ FcmpGe(BinaryOp),
+ FcmpGt(BinaryOp),
+ FcmpO(BinaryOp),
+ FcmpUo(BinaryOp),
+ ArrayIndex(ArrayIndex),
+ ArrayIndexSsa(ArrayIndexSsa),
+ Assign(Assign),
+ AssignMemSsa(AssignMemSsa),
+ AssignUnpack(AssignUnpack),
+ AssignUnpackMemSsa(AssignUnpackMemSsa),
+ Block(Block),
+ Call(Call),
+ Tailcall(Call),
+ CallSsa(CallSsa),
+ Case(Case),
+ Const(Const),
+ ConstPtr(Const),
+ Import(Const),
+ ConstData(ConstData),
+ Deref(UnaryOp),
+ AddressOf(UnaryOp),
+ Neg(UnaryOp),
+ Not(UnaryOp),
+ Sx(UnaryOp),
+ Zx(UnaryOp),
+ LowPart(UnaryOp),
+ BoolToInt(UnaryOp),
+ UnimplMem(UnaryOp),
+ Fsqrt(UnaryOp),
+ Fneg(UnaryOp),
+ Fabs(UnaryOp),
+ FloatToInt(UnaryOp),
+ IntToFloat(UnaryOp),
+ FloatConv(UnaryOp),
+ RoundToInt(UnaryOp),
+ Floor(UnaryOp),
+ Ceil(UnaryOp),
+ Ftrunc(UnaryOp),
+ DerefFieldSsa(DerefFieldSsa),
+ DerefSsa(DerefSsa),
+ ExternPtr(ExternPtr),
+ FloatConst(FloatConst),
+ For(ForLoop),
+ ForSsa(ForLoopSsa),
+ Goto(Label),
+ Label(Label),
+ If(If),
+ Intrinsic(Intrinsic),
+ IntrinsicSsa(IntrinsicSsa),
+ Jump(Jump),
+ MemPhi(MemPhi),
+ Ret(Ret),
+ Split(Split),
+ StructField(StructField),
+ DerefField(StructField),
+ Switch(Switch),
+ Syscall(Syscall),
+ SyscallSsa(SyscallSsa),
+ Trap(Trap),
+ VarDeclare(Var),
+ Var(Var),
+ VarInit(VarInit),
+ VarInitSsa(VarInitSsa),
+ VarPhi(VarPhi),
+ VarSsa(VarSsa),
+ While(While),
+ DoWhile(While),
+ WhileSsa(WhileSsa),
+ DoWhileSsa(WhileSsa),
+}
+
+fn get_float(value: u64, size: usize) -> f64 {
+ match size {
+ 4 => f32::from_bits(value as u32) as f64,
+ 8 => f64::from_bits(value),
+ // TODO how to handle this value?
+ size => todo!("float size {}", size),
+ }
+}
+
+fn get_var(id: u64) -> Variable {
+ Variable::from_identifier(id)
+}
+
+fn get_member_index(idx: u64) -> Option<usize> {
+ (idx as i64 > 0).then_some(idx as usize)
+}
+
+fn get_var_ssa(input: (u64, usize)) -> SSAVariable {
+ SSAVariable::new(get_var(input.0), input.1)
+}
diff --git a/rust/src/high_level_il/lift.rs b/rust/src/high_level_il/lift.rs
new file mode 100644
index 00000000..0c7c2983
--- /dev/null
+++ b/rust/src/high_level_il/lift.rs
@@ -0,0 +1,462 @@
+use super::operation::*;
+use super::{HighLevelILFunction, HighLevelInstructionIndex};
+
+use crate::architecture::CoreIntrinsic;
+use crate::rc::Ref;
+use crate::variable::{ConstantData, SSAVariable, Variable};
+
+#[derive(Clone)]
+pub enum HighLevelILLiftedOperand {
+ ConstantData(ConstantData),
+ Expr(HighLevelILLiftedInstruction),
+ ExprList(Vec<HighLevelILLiftedInstruction>),
+ Float(f64),
+ Int(u64),
+ IntList(Vec<u64>),
+ Intrinsic(CoreIntrinsic),
+ Label(GotoLabel),
+ MemberIndex(Option<usize>),
+ Var(Variable),
+ VarSsa(SSAVariable),
+ VarSsaList(Vec<SSAVariable>),
+}
+
+// TODO: UGH, if your gonna call it expr_idx, call the instruction and expression!!!!!
+// TODO: We dont even need to say instruction in the type!
+// TODO: IF you want to have an instruction type, there needs to be a separate expression type
+// TODO: See the lowlevelil module.
+#[derive(Clone, Debug, PartialEq)]
+pub struct HighLevelILLiftedInstruction {
+ pub function: Ref<HighLevelILFunction>,
+ pub address: u64,
+ // TODO: Please i need expression
+ pub expr_index: HighLevelInstructionIndex,
+ pub size: usize,
+ pub kind: HighLevelILLiftedInstructionKind,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum HighLevelILLiftedInstructionKind {
+ Nop,
+ Break,
+ Continue,
+ Noret,
+ Unreachable,
+ Bp,
+ Undef,
+ Unimpl,
+ Adc(LiftedBinaryOpCarry),
+ Sbb(LiftedBinaryOpCarry),
+ Rlc(LiftedBinaryOpCarry),
+ Rrc(LiftedBinaryOpCarry),
+ Add(LiftedBinaryOp),
+ Sub(LiftedBinaryOp),
+ And(LiftedBinaryOp),
+ Or(LiftedBinaryOp),
+ Xor(LiftedBinaryOp),
+ Lsl(LiftedBinaryOp),
+ Lsr(LiftedBinaryOp),
+ Asr(LiftedBinaryOp),
+ Rol(LiftedBinaryOp),
+ Ror(LiftedBinaryOp),
+ Mul(LiftedBinaryOp),
+ MuluDp(LiftedBinaryOp),
+ MulsDp(LiftedBinaryOp),
+ Divu(LiftedBinaryOp),
+ DivuDp(LiftedBinaryOp),
+ Divs(LiftedBinaryOp),
+ DivsDp(LiftedBinaryOp),
+ Modu(LiftedBinaryOp),
+ ModuDp(LiftedBinaryOp),
+ Mods(LiftedBinaryOp),
+ ModsDp(LiftedBinaryOp),
+ CmpE(LiftedBinaryOp),
+ CmpNe(LiftedBinaryOp),
+ CmpSlt(LiftedBinaryOp),
+ CmpUlt(LiftedBinaryOp),
+ CmpSle(LiftedBinaryOp),
+ CmpUle(LiftedBinaryOp),
+ CmpSge(LiftedBinaryOp),
+ CmpUge(LiftedBinaryOp),
+ CmpSgt(LiftedBinaryOp),
+ CmpUgt(LiftedBinaryOp),
+ TestBit(LiftedBinaryOp),
+ AddOverflow(LiftedBinaryOp),
+ Fadd(LiftedBinaryOp),
+ Fsub(LiftedBinaryOp),
+ Fmul(LiftedBinaryOp),
+ Fdiv(LiftedBinaryOp),
+ FcmpE(LiftedBinaryOp),
+ FcmpNe(LiftedBinaryOp),
+ FcmpLt(LiftedBinaryOp),
+ FcmpLe(LiftedBinaryOp),
+ FcmpGe(LiftedBinaryOp),
+ FcmpGt(LiftedBinaryOp),
+ FcmpO(LiftedBinaryOp),
+ FcmpUo(LiftedBinaryOp),
+ ArrayIndex(LiftedArrayIndex),
+ ArrayIndexSsa(LiftedArrayIndexSsa),
+ Assign(LiftedAssign),
+ AssignMemSsa(LiftedAssignMemSsa),
+ AssignUnpack(LiftedAssignUnpack),
+ AssignUnpackMemSsa(LiftedAssignUnpackMemSsa),
+ Block(LiftedBlock),
+ Call(LiftedCall),
+ Tailcall(LiftedCall),
+ CallSsa(LiftedCallSsa),
+ Case(LiftedCase),
+ Const(Const),
+ ConstPtr(Const),
+ Import(Const),
+ ConstData(LiftedConstData),
+ Deref(LiftedUnaryOp),
+ AddressOf(LiftedUnaryOp),
+ Neg(LiftedUnaryOp),
+ Not(LiftedUnaryOp),
+ Sx(LiftedUnaryOp),
+ Zx(LiftedUnaryOp),
+ LowPart(LiftedUnaryOp),
+ BoolToInt(LiftedUnaryOp),
+ UnimplMem(LiftedUnaryOp),
+ Fsqrt(LiftedUnaryOp),
+ Fneg(LiftedUnaryOp),
+ Fabs(LiftedUnaryOp),
+ FloatToInt(LiftedUnaryOp),
+ IntToFloat(LiftedUnaryOp),
+ FloatConv(LiftedUnaryOp),
+ RoundToInt(LiftedUnaryOp),
+ Floor(LiftedUnaryOp),
+ Ceil(LiftedUnaryOp),
+ Ftrunc(LiftedUnaryOp),
+ DerefFieldSsa(LiftedDerefFieldSsa),
+ DerefSsa(LiftedDerefSsa),
+ ExternPtr(ExternPtr),
+ FloatConst(FloatConst),
+ For(LiftedForLoop),
+ ForSsa(LiftedForLoopSsa),
+ Goto(LiftedLabel),
+ Label(LiftedLabel),
+ If(LiftedIf),
+ Intrinsic(LiftedIntrinsic),
+ IntrinsicSsa(LiftedIntrinsicSsa),
+ Jump(LiftedJump),
+ MemPhi(LiftedMemPhi),
+ Ret(LiftedRet),
+ Split(LiftedSplit),
+ StructField(LiftedStructField),
+ DerefField(LiftedStructField),
+ Switch(LiftedSwitch),
+ Syscall(LiftedSyscall),
+ SyscallSsa(LiftedSyscallSsa),
+ Trap(Trap),
+ VarDeclare(Var),
+ Var(Var),
+ VarInit(LiftedVarInit),
+ VarInitSsa(LiftedVarInitSsa),
+ VarPhi(LiftedVarPhi),
+ VarSsa(VarSsa),
+ While(LiftedWhile),
+ DoWhile(LiftedWhile),
+ WhileSsa(LiftedWhileSsa),
+ DoWhileSsa(LiftedWhileSsa),
+}
+
+impl HighLevelILLiftedInstruction {
+ pub fn name(&self) -> &'static str {
+ use HighLevelILLiftedInstructionKind::*;
+ match self.kind {
+ Nop => "Nop",
+ Break => "Break",
+ Continue => "Continue",
+ Noret => "Noret",
+ Unreachable => "Unreachable",
+ Bp => "Bp",
+ Undef => "Undef",
+ Unimpl => "Unimpl",
+ Adc(_) => "Adc",
+ Sbb(_) => "Sbb",
+ Rlc(_) => "Rlc",
+ Rrc(_) => "Rrc",
+ Add(_) => "Add",
+ Sub(_) => "Sub",
+ And(_) => "And",
+ Or(_) => "Or",
+ Xor(_) => "Xor",
+ Lsl(_) => "Lsl",
+ Lsr(_) => "Lsr",
+ Asr(_) => "Asr",
+ Rol(_) => "Rol",
+ Ror(_) => "Ror",
+ Mul(_) => "Mul",
+ MuluDp(_) => "MuluDp",
+ MulsDp(_) => "MulsDp",
+ Divu(_) => "Divu",
+ DivuDp(_) => "DivuDp",
+ Divs(_) => "Divs",
+ DivsDp(_) => "DivsDp",
+ Modu(_) => "Modu",
+ ModuDp(_) => "ModuDp",
+ Mods(_) => "Mods",
+ ModsDp(_) => "ModsDp",
+ CmpE(_) => "CmpE",
+ CmpNe(_) => "CmpNe",
+ CmpSlt(_) => "CmpSlt",
+ CmpUlt(_) => "CmpUlt",
+ CmpSle(_) => "CmpSle",
+ CmpUle(_) => "CmpUle",
+ CmpSge(_) => "CmpSge",
+ CmpUge(_) => "CmpUge",
+ CmpSgt(_) => "CmpSgt",
+ CmpUgt(_) => "CmpUgt",
+ TestBit(_) => "TestBit",
+ AddOverflow(_) => "AddOverflow",
+ Fadd(_) => "Fadd",
+ Fsub(_) => "Fsub",
+ Fmul(_) => "Fmul",
+ Fdiv(_) => "Fdiv",
+ FcmpE(_) => "FcmpE",
+ FcmpNe(_) => "FcmpNe",
+ FcmpLt(_) => "FcmpLt",
+ FcmpLe(_) => "FcmpLe",
+ FcmpGe(_) => "FcmpGe",
+ FcmpGt(_) => "FcmpGt",
+ FcmpO(_) => "FcmpO",
+ FcmpUo(_) => "FcmpUo",
+ ArrayIndex(_) => "ArrayIndex",
+ ArrayIndexSsa(_) => "ArrayIndexSsa",
+ Assign(_) => "Assign",
+ AssignMemSsa(_) => "AssignMemSsa",
+ AssignUnpack(_) => "AssignUnpack",
+ AssignUnpackMemSsa(_) => "AssignUnpackMemSsa",
+ Block(_) => "Block",
+ Call(_) => "Call",
+ Tailcall(_) => "Tailcall",
+ CallSsa(_) => "CallSsa",
+ Case(_) => "Case",
+ Const(_) => "Const",
+ ConstPtr(_) => "ConstPtr",
+ Import(_) => "Import",
+ ConstData(_) => "ConstData",
+ Deref(_) => "Deref",
+ AddressOf(_) => "AddressOf",
+ Neg(_) => "Neg",
+ Not(_) => "Not",
+ Sx(_) => "Sx",
+ Zx(_) => "Zx",
+ LowPart(_) => "LowPart",
+ BoolToInt(_) => "BoolToInt",
+ UnimplMem(_) => "UnimplMem",
+ Fsqrt(_) => "Fsqrt",
+ Fneg(_) => "Fneg",
+ Fabs(_) => "Fabs",
+ FloatToInt(_) => "FloatToInt",
+ IntToFloat(_) => "IntToFloat",
+ FloatConv(_) => "FloatConv",
+ RoundToInt(_) => "RoundToInt",
+ Floor(_) => "Floor",
+ Ceil(_) => "Ceil",
+ Ftrunc(_) => "Ftrunc",
+ DerefFieldSsa(_) => "DerefFieldSsa",
+ DerefSsa(_) => "DerefSsa",
+ ExternPtr(_) => "ExternPtr",
+ FloatConst(_) => "FloatConst",
+ For(_) => "For",
+ ForSsa(_) => "ForSsa",
+ Goto(_) => "Goto",
+ Label(_) => "Label",
+ If(_) => "If",
+ Intrinsic(_) => "Intrinsic",
+ IntrinsicSsa(_) => "IntrinsicSsa",
+ Jump(_) => "Jump",
+ MemPhi(_) => "MemPhi",
+ Ret(_) => "Ret",
+ Split(_) => "Split",
+ StructField(_) => "StructField",
+ DerefField(_) => "DerefField",
+ Switch(_) => "Switch",
+ Syscall(_) => "Syscall",
+ SyscallSsa(_) => "SyscallSsa",
+ Trap(_) => "Trap",
+ VarDeclare(_) => "VarDeclare",
+ Var(_) => "Var",
+ VarInit(_) => "VarInit",
+ VarInitSsa(_) => "VarInitSsa",
+ VarPhi(_) => "VarPhi",
+ VarSsa(_) => "VarSsa",
+ While(_) => "While",
+ DoWhile(_) => "DoWhile",
+ WhileSsa(_) => "WhileSsa",
+ DoWhileSsa(_) => "DoWhileSsa",
+ }
+ }
+
+ pub fn operands(&self) -> Vec<(&'static str, HighLevelILLiftedOperand)> {
+ use HighLevelILLiftedInstructionKind::*;
+ use HighLevelILLiftedOperand as Operand;
+ match &self.kind {
+ Nop | Break | Continue | Noret | Unreachable | Bp | Undef | Unimpl => vec![],
+ Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => vec![
+ ("left", Operand::Expr(*op.left.clone())),
+ ("right", Operand::Expr(*op.right.clone())),
+ ("carry", Operand::Expr(*op.carry.clone())),
+ ],
+ Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op)
+ | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op)
+ | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op)
+ | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op)
+ | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | Fadd(op)
+ | Fsub(op) | Fmul(op) | Fdiv(op) | FcmpE(op) | FcmpNe(op) | FcmpLt(op) | FcmpLe(op)
+ | FcmpGe(op) | FcmpGt(op) | FcmpO(op) | FcmpUo(op) => vec![
+ ("left", Operand::Expr(*op.left.clone())),
+ ("right", Operand::Expr(*op.right.clone())),
+ ],
+ ArrayIndex(op) => vec![
+ ("src", Operand::Expr(*op.src.clone())),
+ ("index", Operand::Expr(*op.index.clone())),
+ ],
+ ArrayIndexSsa(op) => vec![
+ ("src", Operand::Expr(*op.src.clone())),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ("index", Operand::Expr(*op.index.clone())),
+ ],
+ Assign(op) => vec![
+ ("dest", Operand::Expr(*op.dest.clone())),
+ ("src", Operand::Expr(*op.src.clone())),
+ ],
+ AssignMemSsa(op) => vec![
+ ("dest", Operand::Expr(*op.dest.clone())),
+ ("dest_memory", Operand::Int(op.dest_memory)),
+ ("src", Operand::Expr(*op.src.clone())),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ AssignUnpack(op) => vec![
+ ("dest", Operand::ExprList(op.dest.clone())),
+ ("src", Operand::Expr(*op.src.clone())),
+ ],
+ AssignUnpackMemSsa(op) => vec![
+ ("dest", Operand::ExprList(op.dest.clone())),
+ ("dest_memory", Operand::Int(op.dest_memory)),
+ ("src", Operand::Expr(*op.src.clone())),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ Block(op) => vec![("body", Operand::ExprList(op.body.clone()))],
+ Call(op) | Tailcall(op) => vec![
+ ("dest", Operand::Expr(*op.dest.clone())),
+ ("params", Operand::ExprList(op.params.clone())),
+ ],
+ CallSsa(op) => vec![
+ ("dest", Operand::Expr(*op.dest.clone())),
+ ("params", Operand::ExprList(op.params.clone())),
+ ("dest_memory", Operand::Int(op.dest_memory)),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ Case(op) => vec![
+ ("values", Operand::ExprList(op.values.clone())),
+ ("body", Operand::Expr(*op.body.clone())),
+ ],
+ Const(op) | ConstPtr(op) | Import(op) => vec![("constant", Operand::Int(op.constant))],
+ ConstData(op) => vec![(
+ "constant_data",
+ Operand::ConstantData(op.constant_data.clone()),
+ )],
+ Deref(op) | AddressOf(op) | Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op)
+ | BoolToInt(op) | UnimplMem(op) | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op)
+ | IntToFloat(op) | FloatConv(op) | RoundToInt(op) | Floor(op) | Ceil(op)
+ | Ftrunc(op) => vec![("src", Operand::Expr(*op.src.clone()))],
+ DerefFieldSsa(op) => vec![
+ ("src", Operand::Expr(*op.src.clone())),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ("offset", Operand::Int(op.offset)),
+ ("member_index", Operand::MemberIndex(op.member_index)),
+ ],
+ DerefSsa(op) => vec![
+ ("src", Operand::Expr(*op.src.clone())),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ ExternPtr(op) => vec![
+ ("constant", Operand::Int(op.constant)),
+ ("offset", Operand::Int(op.offset)),
+ ],
+ FloatConst(op) => vec![("constant", Operand::Float(op.constant))],
+ For(op) => vec![
+ ("init", Operand::Expr(*op.init.clone())),
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("update", Operand::Expr(*op.update.clone())),
+ ("body", Operand::Expr(*op.body.clone())),
+ ],
+ ForSsa(op) => vec![
+ ("init", Operand::Expr(*op.init.clone())),
+ ("condition_phi", Operand::Expr(*op.condition_phi.clone())),
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("update", Operand::Expr(*op.update.clone())),
+ ("body", Operand::Expr(*op.body.clone())),
+ ],
+ Goto(op) | Label(op) => vec![("target", Operand::Label(op.target.clone()))],
+ If(op) => vec![
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("cond_true", Operand::Expr(*op.cond_true.clone())),
+ ("cond_false", Operand::Expr(*op.cond_false.clone())),
+ ],
+ Intrinsic(op) => vec![
+ ("intrinsic", Operand::Intrinsic(op.intrinsic)),
+ ("params", Operand::ExprList(op.params.clone())),
+ ],
+ IntrinsicSsa(op) => vec![
+ ("intrinsic", Operand::Intrinsic(op.intrinsic)),
+ ("params", Operand::ExprList(op.params.clone())),
+ ("dest_memory", Operand::Int(op.dest_memory)),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ Jump(op) => vec![("dest", Operand::Expr(*op.dest.clone()))],
+ MemPhi(op) => vec![
+ ("dest", Operand::Int(op.dest)),
+ ("src", Operand::IntList(op.src.clone())),
+ ],
+ Ret(op) => vec![("src", Operand::ExprList(op.src.clone()))],
+ Split(op) => vec![
+ ("high", Operand::Expr(*op.high.clone())),
+ ("low", Operand::Expr(*op.low.clone())),
+ ],
+ StructField(op) | DerefField(op) => vec![
+ ("src", Operand::Expr(*op.src.clone())),
+ ("offset", Operand::Int(op.offset)),
+ ("member_index", Operand::MemberIndex(op.member_index)),
+ ],
+ Switch(op) => vec![
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("default", Operand::Expr(*op.default.clone())),
+ ("cases", Operand::ExprList(op.cases.clone())),
+ ],
+ Syscall(op) => vec![("params", Operand::ExprList(op.params.clone()))],
+ SyscallSsa(op) => vec![
+ ("params", Operand::ExprList(op.params.clone())),
+ ("dest_memory", Operand::Int(op.dest_memory)),
+ ("src_memory", Operand::Int(op.src_memory)),
+ ],
+ Trap(op) => vec![("vector", Operand::Int(op.vector))],
+ VarDeclare(op) | Var(op) => vec![("var", Operand::Var(op.var))],
+ VarInit(op) => vec![
+ ("dest", Operand::Var(op.dest)),
+ ("src", Operand::Expr(*op.src.clone())),
+ ],
+ VarInitSsa(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("src", Operand::Expr(*op.src.clone())),
+ ],
+ VarPhi(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("src", Operand::VarSsaList(op.src.clone())),
+ ],
+ VarSsa(op) => vec![("var", Operand::VarSsa(op.var))],
+ While(op) | DoWhile(op) => vec![
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("body", Operand::Expr(*op.body.clone())),
+ ],
+ WhileSsa(op) | DoWhileSsa(op) => vec![
+ ("condition_phi", Operand::Expr(*op.condition_phi.clone())),
+ ("condition", Operand::Expr(*op.condition.clone())),
+ ("body", Operand::Expr(*op.body.clone())),
+ ],
+ }
+ }
+}
diff --git a/rust/src/high_level_il/operation.rs b/rust/src/high_level_il/operation.rs
new file mode 100644
index 00000000..58accce0
--- /dev/null
+++ b/rust/src/high_level_il/operation.rs
@@ -0,0 +1,550 @@
+use core::ffi;
+
+use binaryninjacore_sys::*;
+
+use super::HighLevelILLiftedInstruction;
+use crate::architecture::CoreIntrinsic;
+use crate::function::Function;
+use crate::rc::Ref;
+use crate::string::{BnStrCompatible, BnString};
+use crate::variable::{ConstantData, SSAVariable, Variable};
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct GotoLabel {
+ pub(crate) function: Ref<Function>,
+ pub target: u64,
+}
+
+impl GotoLabel {
+ pub fn name(&self) -> BnString {
+ unsafe { BnString::from_raw(BNGetGotoLabelName(self.function.handle, self.target)) }
+ }
+
+ fn set_name<S: BnStrCompatible>(&self, name: S) {
+ let raw = name.into_bytes_with_nul();
+ unsafe {
+ BNSetUserGotoLabelName(
+ self.function.handle,
+ self.target,
+ raw.as_ref().as_ptr() as *const ffi::c_char,
+ )
+ }
+ }
+}
+
+// ADC, SBB, RLC, RRC
+#[derive(Debug, Copy, Clone)]
+pub struct BinaryOpCarry {
+ pub left: usize,
+ pub right: usize,
+ pub carry: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBinaryOpCarry {
+ pub left: Box<HighLevelILLiftedInstruction>,
+ pub right: Box<HighLevelILLiftedInstruction>,
+ pub carry: Box<HighLevelILLiftedInstruction>,
+}
+
+// ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FADD, FSUB, FMUL, FDIV, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO
+#[derive(Debug, Copy, Clone)]
+pub struct BinaryOp {
+ pub left: usize,
+ pub right: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBinaryOp {
+ pub left: Box<HighLevelILLiftedInstruction>,
+ pub right: Box<HighLevelILLiftedInstruction>,
+}
+
+// ARRAY_INDEX
+#[derive(Debug, Copy, Clone)]
+pub struct ArrayIndex {
+ pub src: usize,
+ pub index: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedArrayIndex {
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub index: Box<HighLevelILLiftedInstruction>,
+}
+
+// ARRAY_INDEX_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct ArrayIndexSsa {
+ pub src: usize,
+ pub src_memory: u64,
+ pub index: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedArrayIndexSsa {
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub src_memory: u64,
+ pub index: Box<HighLevelILLiftedInstruction>,
+}
+
+// ASSIGN
+#[derive(Debug, Copy, Clone)]
+pub struct Assign {
+ pub dest: usize,
+ pub src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedAssign {
+ pub dest: Box<HighLevelILLiftedInstruction>,
+ pub src: Box<HighLevelILLiftedInstruction>,
+}
+
+// ASSIGN_MEM_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct AssignMemSsa {
+ pub dest: usize,
+ pub dest_memory: u64,
+ pub src: usize,
+ pub src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedAssignMemSsa {
+ pub dest: Box<HighLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+
+// ASSIGN_UNPACK
+#[derive(Debug, Copy, Clone)]
+pub struct AssignUnpack {
+ pub first_dest: usize,
+ pub num_dests: usize,
+ pub src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedAssignUnpack {
+ pub dest: Vec<HighLevelILLiftedInstruction>,
+ pub src: Box<HighLevelILLiftedInstruction>,
+}
+
+// ASSIGN_UNPACK_MEM_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct AssignUnpackMemSsa {
+ pub first_dest: usize,
+ pub num_dests: usize,
+ pub dest_memory: u64,
+ pub src: usize,
+ pub src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedAssignUnpackMemSsa {
+ pub dest: Vec<HighLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+
+// BLOCK
+#[derive(Debug, Copy, Clone)]
+pub struct Block {
+ pub first_param: usize,
+ pub num_params: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBlock {
+ pub body: Vec<HighLevelILLiftedInstruction>,
+}
+
+// CALL, TAILCALL
+#[derive(Debug, Copy, Clone)]
+pub struct Call {
+ pub dest: usize,
+ pub first_param: usize,
+ pub num_params: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCall {
+ pub dest: Box<HighLevelILLiftedInstruction>,
+ pub params: Vec<HighLevelILLiftedInstruction>,
+}
+
+// CALL_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct CallSsa {
+ pub dest: usize,
+ pub first_param: usize,
+ pub num_params: usize,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCallSsa {
+ pub dest: Box<HighLevelILLiftedInstruction>,
+ pub params: Vec<HighLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+
+// CASE
+#[derive(Debug, Copy, Clone)]
+pub struct Case {
+ pub first_value: usize,
+ pub num_values: usize,
+ pub body: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCase {
+ pub values: Vec<HighLevelILLiftedInstruction>,
+ pub body: Box<HighLevelILLiftedInstruction>,
+}
+
+// CONST, CONST_PTR, IMPORT
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Const {
+ pub constant: u64,
+}
+
+// CONST_DATA
+#[derive(Debug, Copy, Clone)]
+pub struct ConstData {
+ pub constant_data_kind: u32,
+ pub constant_data_value: i64,
+ pub size: usize,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedConstData {
+ pub constant_data: ConstantData,
+}
+
+// DEREF, ADDRESS_OF, NEG, NOT, SX, ZX, LOW_PART, BOOL_TO_INT, UNIMPL_MEM, FSQRT, FNEG, FABS, FLOAT_TO_INT, INT_TO_FLOAT, FLOAT_CONV, ROUND_TO_INT, FLOOR, CEIL, FTRUNC
+#[derive(Debug, Copy, Clone)]
+pub struct UnaryOp {
+ pub src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedUnaryOp {
+ pub src: Box<HighLevelILLiftedInstruction>,
+}
+
+// DEREF_FIELD_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct DerefFieldSsa {
+ pub src: usize,
+ pub src_memory: u64,
+ pub offset: u64,
+ pub member_index: Option<usize>,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedDerefFieldSsa {
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub src_memory: u64,
+ pub offset: u64,
+ pub member_index: Option<usize>,
+}
+
+// DEREF_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct DerefSsa {
+ pub src: usize,
+ pub src_memory: u64,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedDerefSsa {
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+
+// EXTERN_PTR
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ExternPtr {
+ pub constant: u64,
+ pub offset: u64,
+}
+
+// FLOAT_CONST
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct FloatConst {
+ pub constant: f64,
+}
+
+// FOR
+#[derive(Debug, Copy, Clone)]
+pub struct ForLoop {
+ pub init: usize,
+ pub condition: usize,
+ pub update: usize,
+ pub body: usize,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedForLoop {
+ pub init: Box<HighLevelILLiftedInstruction>,
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub update: Box<HighLevelILLiftedInstruction>,
+ pub body: Box<HighLevelILLiftedInstruction>,
+}
+
+// FOR_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct ForLoopSsa {
+ pub init: usize,
+ pub condition_phi: usize,
+ pub condition: usize,
+ pub update: usize,
+ pub body: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedForLoopSsa {
+ pub init: Box<HighLevelILLiftedInstruction>,
+ pub condition_phi: Box<HighLevelILLiftedInstruction>,
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub update: Box<HighLevelILLiftedInstruction>,
+ pub body: Box<HighLevelILLiftedInstruction>,
+}
+
+// GOTO, LABEL
+#[derive(Debug, Copy, Clone)]
+pub struct Label {
+ pub target: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedLabel {
+ pub target: GotoLabel,
+}
+
+impl LiftedLabel {
+ pub fn name(&self) -> BnString {
+ self.target.name()
+ }
+
+ pub fn set_name<S: BnStrCompatible>(&self, name: S) {
+ self.target.set_name(name)
+ }
+}
+
+// IF
+#[derive(Debug, Copy, Clone)]
+pub struct If {
+ pub condition: usize,
+ pub cond_true: usize,
+ pub cond_false: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedIf {
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub cond_true: Box<HighLevelILLiftedInstruction>,
+ pub cond_false: Box<HighLevelILLiftedInstruction>,
+}
+
+// INTRINSIC
+#[derive(Debug, Copy, Clone)]
+pub struct Intrinsic {
+ pub intrinsic: u32,
+ pub first_param: usize,
+ pub num_params: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedIntrinsic {
+ pub intrinsic: CoreIntrinsic,
+ pub params: Vec<HighLevelILLiftedInstruction>,
+}
+
+// INTRINSIC_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct IntrinsicSsa {
+ pub intrinsic: u32,
+ pub first_param: usize,
+ pub num_params: usize,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedIntrinsicSsa {
+ pub intrinsic: CoreIntrinsic,
+ pub params: Vec<HighLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+
+// JUMP
+#[derive(Debug, Copy, Clone)]
+pub struct Jump {
+ pub dest: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedJump {
+ pub dest: Box<HighLevelILLiftedInstruction>,
+}
+
+// MEM_PHI
+#[derive(Debug, Copy, Clone)]
+pub struct MemPhi {
+ pub dest: u64,
+ pub first_src: usize,
+ pub num_srcs: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedMemPhi {
+ pub dest: u64,
+ pub src: Vec<u64>,
+}
+
+// RET
+#[derive(Debug, Copy, Clone)]
+pub struct Ret {
+ pub first_src: usize,
+ pub num_srcs: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedRet {
+ pub src: Vec<HighLevelILLiftedInstruction>,
+}
+
+// SPLIT
+#[derive(Debug, Copy, Clone)]
+pub struct Split {
+ pub high: usize,
+ pub low: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSplit {
+ pub high: Box<HighLevelILLiftedInstruction>,
+ pub low: Box<HighLevelILLiftedInstruction>,
+}
+
+// STRUCT_FIELD, DEREF_FIELD
+#[derive(Debug, Copy, Clone)]
+pub struct StructField {
+ pub src: usize,
+ pub offset: u64,
+ pub member_index: Option<usize>,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStructField {
+ pub src: Box<HighLevelILLiftedInstruction>,
+ pub offset: u64,
+ pub member_index: Option<usize>,
+}
+
+// SWITCH
+#[derive(Debug, Copy, Clone)]
+pub struct Switch {
+ pub condition: usize,
+ pub default: usize,
+ pub first_case: usize,
+ pub num_cases: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSwitch {
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub default: Box<HighLevelILLiftedInstruction>,
+ pub cases: Vec<HighLevelILLiftedInstruction>,
+}
+
+// SYSCALL
+#[derive(Debug, Copy, Clone)]
+pub struct Syscall {
+ pub first_param: usize,
+ pub num_params: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSyscall {
+ pub params: Vec<HighLevelILLiftedInstruction>,
+}
+
+// SYSCALL_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct SyscallSsa {
+ pub first_param: usize,
+ pub num_params: usize,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSyscallSsa {
+ pub params: Vec<HighLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+}
+
+// TRAP
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Trap {
+ pub vector: u64,
+}
+
+// VAR_DECLARE, VAR
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Var {
+ pub var: Variable,
+}
+
+// VAR_INIT
+#[derive(Debug, Copy, Clone)]
+pub struct VarInit {
+ pub dest: Variable,
+ pub src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedVarInit {
+ pub dest: Variable,
+ pub src: Box<HighLevelILLiftedInstruction>,
+}
+
+// VAR_INIT_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct VarInitSsa {
+ pub dest: SSAVariable,
+ pub src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedVarInitSsa {
+ pub dest: SSAVariable,
+ pub src: Box<HighLevelILLiftedInstruction>,
+}
+
+// VAR_PHI
+#[derive(Debug, Copy, Clone)]
+pub struct VarPhi {
+ pub dest: SSAVariable,
+ pub first_src: usize,
+ pub num_srcs: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedVarPhi {
+ pub dest: SSAVariable,
+ pub src: Vec<SSAVariable>,
+}
+
+// VAR_SSA
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct VarSsa {
+ pub var: SSAVariable,
+}
+
+// WHILE, DO_WHILE
+#[derive(Debug, Copy, Clone)]
+pub struct While {
+ pub condition: usize,
+ pub body: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedWhile {
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub body: Box<HighLevelILLiftedInstruction>,
+}
+
+// WHILE_SSA, DO_WHILE_SSA
+#[derive(Debug, Copy, Clone)]
+pub struct WhileSsa {
+ pub condition_phi: usize,
+ pub condition: usize,
+ pub body: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedWhileSsa {
+ pub condition_phi: Box<HighLevelILLiftedInstruction>,
+ pub condition: Box<HighLevelILLiftedInstruction>,
+ pub body: Box<HighLevelILLiftedInstruction>,
+}