From f6c6e48b0e6e275c4b160e06c7dd34b77f492c68 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 22 Sep 2025 19:21:51 -0400 Subject: [PATCH 1/6] Add source_flag method to Flag operation --- rust/src/low_level_il/operation.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index e74a82401e..4f2bf18e81 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -1013,6 +1013,19 @@ 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, From 891ebd28bcff98e7abef3d969c711f6c74696f6a Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 22 Sep 2025 19:35:27 -0400 Subject: [PATCH 2/6] Update Flag operation debug formatting to include source flag --- rust/src/low_level_il/operation.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 4f2bf18e81..72ada01805 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -1032,7 +1032,9 @@ where 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() } } From 2e600b2dd5def3d985cae8889560d844734c08f1 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 26 Sep 2025 19:05:13 -0400 Subject: [PATCH 3/6] Add method for getting raw operand from llil operation --- rust/src/low_level_il/operation.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 72ada01805..bfc605b597 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> From 846549eab7d75545363159bb02eab429e16fbcea Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 26 Sep 2025 20:15:58 -0400 Subject: [PATCH 4/6] Make llil constructor public --- rust/src/low_level_il/expression.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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, From 4b156be55db1dbe4a1ea35d3f435db18448f6da0 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 26 Sep 2025 22:16:26 -0400 Subject: [PATCH 5/6] Intrinsics don't suck anymore --- rust/src/low_level_il/operation.rs | 71 ++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index bfc605b597..1a0a673cae 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -230,16 +230,87 @@ 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 + } } impl Debug for Operation<'_, M, F, Intrinsic> From ae56250a1420b45e07affa799cf3876a5c234a34 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 26 Sep 2025 22:23:04 -0400 Subject: [PATCH 6/6] Support getting inputs to an intrinsic --- rust/src/low_level_il/operation.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rust/src/low_level_il/operation.rs b/rust/src/low_level_il/operation.rs index 1a0a673cae..245218bbd1 100644 --- a/rust/src/low_level_il/operation.rs +++ b/rust/src/low_level_il/operation.rs @@ -311,6 +311,17 @@ where 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>