diff --git a/rust/src/low_level_il/expression.rs b/rust/src/low_level_il/expression.rs index ecd850f939..de69e1120e 100644 --- a/rust/src/low_level_il/expression.rs +++ b/rust/src/low_level_il/expression.rs @@ -98,10 +98,7 @@ where F: FunctionForm, R: ExpressionResultType, { - pub(crate) fn new( - function: &'func LowLevelILFunction, - index: LowLevelExpressionIndex, - ) -> Self { + pub fn new(function: &'func LowLevelILFunction, index: LowLevelExpressionIndex) -> Self { // TODO: Validate expression here? Self { function, diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index e74a82401e..245218bbd1 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -88,6 +88,22 @@ where }; PossibleValueSet::from_owned_core_raw(raw_pvs) } + + /// Get the raw operand from the operand list. + /// + /// This has no type information associated with it. It's up to the caller to know what the correct type of the + /// underlying u64 should be. + /// + /// # Panic + /// `idx` must be less than 4. This is to protect against an out of bounds access. + /// + /// # Safety + /// Even if `idx` is valid, it may index to an unitialized or unused value. Make sure you index into an operand that + /// you know should be initialized properly. + pub unsafe fn get_operand(&self, idx: usize) -> u64 { + assert!(idx < 4); + self.op.operands[idx] + } } impl Operation<'_, M, NonSSA, O> @@ -214,16 +230,98 @@ where // LLIL_INTRINSIC, LLIL_INTRINSIC_SSA pub struct Intrinsic; +#[derive(Debug, Clone, Copy)] +pub enum RegOrFlag { + Reg(CoreRegister), + Flag(CoreFlag), +} + +impl From for RegOrFlag { + fn from(value: CoreRegister) -> Self { + Self::Reg(value) + } +} + +impl From for RegOrFlag { + fn from(value: CoreFlag) -> Self { + Self::Flag(value) + } +} + impl Operation<'_, M, F, Intrinsic> where M: FunctionMutability, F: FunctionForm, { + // Order of operands for this operation: + // 1. Number of outputs in the reg or flag list + // 2. Reg or flag list + // 3. Intrinsic id + // 4. Operand list + // TODO: Support register and expression lists pub fn intrinsic(&self) -> Option { let raw_id = self.op.operands[2] as u32; self.function.arch().intrinsic_from_id(IntrinsicId(raw_id)) } + + /// Number of outputs the intrinsic has. + #[inline] + pub fn output_count(&self) -> usize { + self.op.operands[0] as usize + } + + /// Get the output list. + pub fn outputs(&self) -> Vec { + let mut outputs = Vec::new(); + let mut output_size = self.op.operands[0] as usize; + if output_size == 0 { + return outputs; + } + let out_list = unsafe { + BNLowLevelILGetOperandList( + self.function.handle, + self.expr_idx.0, + 0, + &mut output_size as *mut _, + ) + }; + let out_list = unsafe { std::slice::from_raw_parts_mut(out_list, output_size) }; + for val in out_list.iter() { + if *val & (1 << 32) != 0 { + outputs.push( + self.function + .arch() + .flag_from_id(FlagId((*val & 0xffffffff) as u32)) + .expect("Invalid core flag ID") + .into(), + ); + } else { + outputs.push( + self.function + .arch() + .register_from_id(RegisterId((*val & 0xffffffff) as u32)) + .expect("Invalid register ID") + .into(), + ); + } + } + // Need to drop the list at the end. This will get leaked if there's a panic anywhere. + // TODO: Make a new type for this that implements drop so it can't be leaked. + unsafe { BNLowLevelILFreeOperandList(out_list.as_mut_ptr()) }; + outputs + } + + /// Get the input list for the intrinsic. + /// + /// This will just be a CallParamSsa expression. + #[inline] + pub fn inputs(&self) -> LowLevelILExpression<'_, M, F, ValueExpr> { + LowLevelILExpression::new( + self.function, + LowLevelExpressionIndex(self.op.operands[3] as usize), + ) + } } impl Debug for Operation<'_, M, F, Intrinsic> @@ -1013,13 +1111,28 @@ where // LLIL_FLAG, LLIL_FLAG_SSA pub struct Flag; +impl Operation<'_, M, F, Flag> +where + M: FunctionMutability, + F: FunctionForm, +{ + pub fn source_flag(&self) -> CoreFlag { + self.function + .arch() + .flag_from_id(FlagId(self.op.operands[0] as u32)) + .expect("Bad flag ID") + } +} + impl Debug for Operation<'_, M, F, Flag> where M: FunctionMutability, F: FunctionForm, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Flag").finish() + f.debug_struct("Flag") + .field("source_flag", &self.source_flag()) + .finish() } }