Skip to content

Commit 03c71de

Browse files
committed
Allow upgrading a mutable LowLevelILFunction to a finalized LowLevelILFunction through LowLevelILFunction::finalized in the Rust API
1 parent 2956883 commit 03c71de

File tree

4 files changed

+31
-29
lines changed

4 files changed

+31
-29
lines changed

plugins/lift_check/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use binaryninja::architecture::{CoreArchitecture, Register, RegisterInfo};
22
use binaryninja::logger::Logger;
33
use binaryninja::low_level_il::expression::{ExpressionHandler, LowLevelILExpression, ValueExpr};
44
use binaryninja::low_level_il::expression::LowLevelILExpressionKind::*;
5-
use binaryninja::low_level_il::function::{Finalized, LiftedNonSSA, LowLevelILFunction, NonSSA, RegularNonSSA};
5+
use binaryninja::low_level_il::function::{FunctionMutability, LiftedNonSSA, NonSSA};
66
use binaryninja::low_level_il::instruction::LowLevelILInstructionKind::*;
77
use log::{error, info, LevelFilter};
88
use binaryninja::low_level_il::instruction::{InstructionHandler, LowLevelILInstruction};
@@ -19,7 +19,7 @@ const LIFT_CHECK_ACTIVITY_CONFIG: &str = r#"{
1919
}
2020
}"#;
2121

22-
fn check_expression(expr: &LowLevelILExpression<CoreArchitecture, Finalized, NonSSA<LiftedNonSSA>, ValueExpr>,
22+
fn check_expression<M: FunctionMutability>(expr: &LowLevelILExpression<CoreArchitecture, M, NonSSA<LiftedNonSSA>, ValueExpr>,
2323
required_size: Option<usize>)
2424
{
2525
match expr.kind() {
@@ -325,7 +325,7 @@ fn check_expression(expr: &LowLevelILExpression<CoreArchitecture, Finalized, Non
325325
}
326326
}
327327

328-
fn check_instruction(inst: &LowLevelILInstruction<CoreArchitecture, Finalized, NonSSA<LiftedNonSSA>>) {
328+
fn check_instruction<M: FunctionMutability>(inst: &LowLevelILInstruction<CoreArchitecture, M, NonSSA<LiftedNonSSA>>) {
329329
match inst.kind() {
330330
SetReg(op) => {
331331
let required_expr_size = op.size();

rust/examples/workflow.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,21 @@ fn example_activity(analysis_context: &AnalysisContext) {
2525
);
2626
// If we have llil available, replace that as well.
2727
if let Some(llil) = unsafe { analysis_context.llil_function() } {
28-
for basic_block in &func.basic_blocks() {
28+
for basic_block in &llil.basic_blocks() {
2929
for instr in basic_block.iter() {
30-
if let Some(llil_instr) = llil.instruction_at(instr) {
31-
llil_instr.visit_tree(&mut |expr| {
32-
if let LowLevelILExpressionKind::Const(_op) = expr.kind() {
33-
// Replace all consts with 0x1337.
34-
println!("Replacing llil expression @ 0x{:x} : {}", instr, expr.index);
35-
unsafe {
36-
llil.replace_expression(expr.index, llil.const_int(4, 0x1337))
37-
};
38-
}
39-
VisitorAction::Descend
40-
});
41-
}
30+
instr.visit_tree(&mut |expr| {
31+
if let LowLevelILExpressionKind::Const(_op) = expr.kind() {
32+
// Replace all consts with 0x1337.
33+
println!("Replacing llil expression @ 0x{:x} : {}", instr.address(), expr.index);
34+
unsafe {
35+
llil.replace_expression(expr.index, llil.const_int(4, 0x1337))
36+
};
37+
}
38+
VisitorAction::Descend
39+
});
4240
}
4341
}
44-
analysis_context.set_lifted_il_function(&llil);
42+
analysis_context.set_llil_function(&llil.finalized());
4543
}
4644
}
4745

rust/src/low_level_il/function.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,17 +156,8 @@ where
156156
Function::ref_from_raw(func)
157157
}
158158
}
159-
}
160159

161-
// LLIL basic blocks are not available until the function object
162-
// is finalized, so ensure we can't try requesting basic blocks
163-
// during lifting
164-
impl<A, F> LowLevelILFunction<A, Finalized, F>
165-
where
166-
A: Architecture,
167-
F: FunctionForm,
168-
{
169-
pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<A, Finalized, F>>> {
160+
pub fn basic_blocks(&self) -> Array<BasicBlock<LowLevelILBlock<A, M, F>>> {
170161
use binaryninjacore_sys::BNGetLowLevelILBasicBlockList;
171162

172163
unsafe {
@@ -204,6 +195,15 @@ impl LowLevelILFunction<CoreArchitecture, Mutable, NonSSA<LiftedNonSSA>> {
204195

205196
unsafe { BNGenerateLowLevelILSSAForm(self.handle) };
206197
}
198+
199+
/// Finalizes a mutable [`LowLevelILFunction`].
200+
pub fn finalized(&self) -> Ref<LowLevelILFunction<CoreArchitecture, Finalized, NonSSA<LiftedNonSSA>>> {
201+
use binaryninjacore_sys::BNFinalizeLowLevelILFunction;
202+
unsafe { BNFinalizeLowLevelILFunction(self.handle) };
203+
// We are transferring ownership of the handle to the caller as a finalized function.
204+
// SAFETY: We know that the handle is valid and that the caller is responsible for the new reference.
205+
unsafe { LowLevelILFunction::from_raw(self.arch_handle, self.handle) }.to_owned()
206+
}
207207
}
208208

209209
impl<A, M, F> ToOwned for LowLevelILFunction<A, M, F>

rust/src/workflow.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ impl AnalysisContext {
6767

6868
// TODO: This returns LiftedNonSSA because the lifting code was written before we could patch the IL
6969
// TODO: At some point we need to take the lifting code and make it available to regular IL.
70-
/// [`LowLevelILFunction`] used to represent Low Level IL
70+
/// [`LowLevelILFunction`] used to represent Low Level IL, this is returned as mutable for the
71+
/// user to modify it is required to finalize the function using [`LowLevelILFunction::finalized`]
72+
/// before setting the function using [`LowLevelILFunction::set_llil_function`].
7173
pub unsafe fn llil_function<V: NonSSAVariant>(
7274
&self,
73-
) -> Option<Ref<LowLevelILFunction<CoreArchitecture, Finalized, NonSSA<V>>>> {
75+
) -> Option<Ref<LowLevelILFunction<CoreArchitecture, Mutable, NonSSA<V>>>> {
7476
let result = unsafe { BNAnalysisContextGetLowLevelILFunction(self.handle.as_ptr()) };
7577
let arch = self.function().arch();
7678
unsafe {
@@ -83,6 +85,8 @@ impl AnalysisContext {
8385

8486
// TODO: This returns LiftedNonSSA because the lifting code was written before we could patch the IL
8587
// TODO: At some point we need to take the lifting code and make it available to regular IL.
88+
/// To retrieve the finalized state of the function returned from [`AnalysisContext::llil_function`], use
89+
/// [`LowLevelILFunction::finalized`] which insures that the function is in the correct state.
8690
pub fn set_llil_function<V: NonSSAVariant>(
8791
&self,
8892
value: &LowLevelILFunction<CoreArchitecture, Finalized, NonSSA<V>>,

0 commit comments

Comments
 (0)