Skip to main content

binaryninja/low_level_il/
instruction.rs

1// Copyright 2021-2026 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::basic_block::BasicBlock;
16use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
17
18use super::block::LowLevelILBlock;
19use super::operation;
20use super::operation::Operation;
21use super::VisitorAction;
22use super::*;
23use binaryninjacore_sys::BNGetLowLevelILIndexForInstruction;
24use binaryninjacore_sys::BNLowLevelILInstruction;
25use binaryninjacore_sys::{BNFreeILInstructionList, BNGetLowLevelILByIndex};
26use std::fmt::{Debug, Display, Formatter};
27
28#[repr(transparent)]
29#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct LowLevelInstructionIndex(pub usize);
31
32impl LowLevelInstructionIndex {
33    pub fn next(&self) -> Self {
34        Self(self.0 + 1)
35    }
36}
37
38impl From<usize> for LowLevelInstructionIndex {
39    fn from(index: usize) -> Self {
40        Self(index)
41    }
42}
43
44impl From<u64> for LowLevelInstructionIndex {
45    fn from(index: u64) -> Self {
46        Self(index as usize)
47    }
48}
49
50impl Display for LowLevelInstructionIndex {
51    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
52        f.write_fmt(format_args!("{}", self.0))
53    }
54}
55
56impl CoreArrayProvider for LowLevelInstructionIndex {
57    type Raw = usize;
58    type Context = ();
59    type Wrapped<'a> = Self;
60}
61
62unsafe impl CoreArrayProviderInner for LowLevelInstructionIndex {
63    unsafe fn free(raw: *mut Self::Raw, _count: usize, _context: &Self::Context) {
64        BNFreeILInstructionList(raw)
65    }
66
67    unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
68        Self::from(*raw)
69    }
70}
71
72// TODO: Probably want to rename this with a LowLevelIL prefix to avoid collisions when we add handlers for other ILs
73pub trait InstructionHandler<'func, M, F>
74where
75    M: FunctionMutability,
76    F: FunctionForm,
77{
78    fn kind(&self) -> LowLevelILInstructionKind<'func, M, F>;
79
80    /// Visit the sub expressions of this instruction.
81    ///
82    /// NOTE: This does not visit the root expression, i.e. the instruction.
83    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
84    where
85        T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction;
86}
87
88#[derive(Copy, Clone)]
89pub struct LowLevelILInstruction<'func, M, F>
90where
91    M: FunctionMutability,
92    F: FunctionForm,
93{
94    pub(crate) function: &'func LowLevelILFunction<M, F>,
95    pub index: LowLevelInstructionIndex,
96}
97
98impl<'func, M, F> LowLevelILInstruction<'func, M, F>
99where
100    M: FunctionMutability,
101    F: FunctionForm,
102{
103    // TODO: Should we check the instruction count here with BNGetLowLevelILInstructionCount?
104    // TODO: If we _can_ then this should become an Option<Self> methinks
105    pub fn new(function: &'func LowLevelILFunction<M, F>, index: LowLevelInstructionIndex) -> Self {
106        Self { function, index }
107    }
108
109    pub fn address(&self) -> u64 {
110        self.into_raw().address
111    }
112
113    // TODO: Document the difference between the self.index and the expr_idx.
114    pub fn expr_idx(&self) -> LowLevelExpressionIndex {
115        let idx = unsafe { BNGetLowLevelILIndexForInstruction(self.function.handle, self.index.0) };
116        LowLevelExpressionIndex(idx)
117    }
118
119    pub fn into_raw(&self) -> BNLowLevelILInstruction {
120        unsafe { BNGetLowLevelILByIndex(self.function.handle, self.expr_idx().0) }
121    }
122
123    /// Returns the [`BasicBlock`] containing the given [`LowLevelILInstruction`].
124    pub fn basic_block(&self) -> Option<Ref<BasicBlock<LowLevelILBlock<'func, M, F>>>> {
125        // TODO: We might be able to .expect this if we guarantee that self.index is valid.
126        self.function.basic_block_containing_index(self.index)
127    }
128}
129
130impl<'func, M> LowLevelILInstruction<'func, M, NonSSA>
131where
132    M: FunctionMutability,
133{
134    pub fn ssa_form(
135        &self,
136        ssa: &'func LowLevelILFunction<M, SSA>,
137    ) -> LowLevelILInstruction<'func, M, SSA> {
138        use binaryninjacore_sys::BNGetLowLevelILSSAInstructionIndex;
139        let idx = unsafe { BNGetLowLevelILSSAInstructionIndex(self.function.handle, self.index.0) };
140        LowLevelILInstruction::new(ssa, LowLevelInstructionIndex(idx))
141    }
142}
143
144impl<'func, M> LowLevelILInstruction<'func, M, SSA>
145where
146    M: FunctionMutability,
147{
148    pub fn non_ssa_form(
149        &self,
150        non_ssa: &'func LowLevelILFunction<M, NonSSA>,
151    ) -> LowLevelILInstruction<'func, M, NonSSA> {
152        use binaryninjacore_sys::BNGetLowLevelILNonSSAInstructionIndex;
153        let idx =
154            unsafe { BNGetLowLevelILNonSSAInstructionIndex(self.function.handle, self.index.0) };
155        LowLevelILInstruction::new(non_ssa, LowLevelInstructionIndex(idx))
156    }
157}
158
159impl<M, F> Debug for LowLevelILInstruction<'_, M, F>
160where
161    M: FunctionMutability,
162    F: FunctionForm,
163{
164    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
165        f.debug_struct("Instruction")
166            .field("index", &self.index)
167            .field("expr_idx", &self.expr_idx())
168            .field("address", &self.address())
169            .finish()
170    }
171}
172
173impl<'func, M> InstructionHandler<'func, M, SSA> for LowLevelILInstruction<'func, M, SSA>
174where
175    M: FunctionMutability,
176{
177    fn kind(&self) -> LowLevelILInstructionKind<'func, M, SSA> {
178        #[allow(unused_imports)]
179        use binaryninjacore_sys::BNLowLevelILOperation::*;
180        let raw_op = self.into_raw();
181        #[allow(clippy::match_single_binding)]
182        match raw_op.operation {
183            // Any invalid ops for Non-Lifted IL will be checked here.
184            // SAFETY: We have checked for illegal operations.
185            _ => unsafe {
186                LowLevelILInstructionKind::from_raw(self.function, self.expr_idx(), raw_op)
187            },
188        }
189    }
190
191    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
192    where
193        T: FnMut(&LowLevelILExpression<'func, M, SSA, ValueExpr>) -> VisitorAction,
194    {
195        // Recursively visit sub expressions.
196        self.kind().visit_sub_expressions(|e| e.visit_tree(f))
197    }
198}
199
200impl<'func, M> InstructionHandler<'func, M, NonSSA> for LowLevelILInstruction<'func, M, NonSSA>
201where
202    M: FunctionMutability,
203{
204    fn kind(&self) -> LowLevelILInstructionKind<'func, M, NonSSA> {
205        #[allow(unused_imports)]
206        use binaryninjacore_sys::BNLowLevelILOperation::*;
207        let raw_op = self.into_raw();
208        #[allow(clippy::match_single_binding)]
209        match raw_op.operation {
210            // Any invalid ops for Non-Lifted IL will be checked here.
211            // SAFETY: We have checked for illegal operations.
212            _ => unsafe {
213                LowLevelILInstructionKind::from_raw(self.function, self.expr_idx(), raw_op)
214            },
215        }
216    }
217
218    fn visit_tree<T>(&self, f: &mut T) -> VisitorAction
219    where
220        T: FnMut(&LowLevelILExpression<'func, M, NonSSA, ValueExpr>) -> VisitorAction,
221    {
222        // Recursively visit sub expressions.
223        self.kind().visit_sub_expressions(|e| e.visit_tree(f))
224    }
225}
226
227#[derive(Debug)]
228pub enum LowLevelILInstructionKind<'func, M, F>
229where
230    M: FunctionMutability,
231    F: FunctionForm,
232{
233    Nop(Operation<'func, M, F, operation::NoArgs>),
234    SetReg(Operation<'func, M, F, operation::SetReg>),
235    SetRegSsa(Operation<'func, M, F, operation::SetRegSsa>),
236    SetRegPartialSsa(Operation<'func, M, F, operation::SetRegPartialSsa>),
237    SetRegSplit(Operation<'func, M, F, operation::SetRegSplit>),
238    SetRegSplitSsa(Operation<'func, M, F, operation::SetRegSplitSsa>),
239    SetFlag(Operation<'func, M, F, operation::SetFlag>),
240    SetFlagSsa(Operation<'func, M, F, operation::SetFlagSsa>),
241    Store(Operation<'func, M, F, operation::Store>),
242    StoreSsa(Operation<'func, M, F, operation::StoreSsa>),
243    // TODO needs a real op
244    Push(Operation<'func, M, F, operation::UnaryOp>),
245
246    RegStackPush(Operation<'func, M, F, operation::RegStackPush>),
247    RegStackFreeReg(Operation<'func, M, F, operation::RegStackFreeReg>),
248
249    Jump(Operation<'func, M, F, operation::Jump>),
250    JumpTo(Operation<'func, M, F, operation::JumpTo>),
251
252    Call(Operation<'func, M, F, operation::Call>),
253    CallSsa(Operation<'func, M, F, operation::CallSsa>),
254    TailCall(Operation<'func, M, F, operation::Call>),
255    TailCallSsa(Operation<'func, M, F, operation::CallSsa>),
256
257    Ret(Operation<'func, M, F, operation::Ret>),
258    NoRet(Operation<'func, M, F, operation::NoArgs>),
259
260    If(Operation<'func, M, F, operation::If>),
261    Goto(Operation<'func, M, F, operation::Goto>),
262
263    Syscall(Operation<'func, M, F, operation::Syscall>),
264    SyscallSsa(Operation<'func, M, F, operation::SyscallSsa>),
265    Intrinsic(Operation<'func, M, F, operation::Intrinsic>),
266    Bp(Operation<'func, M, F, operation::NoArgs>),
267    Trap(Operation<'func, M, F, operation::Trap>),
268    Undef(Operation<'func, M, F, operation::NoArgs>),
269    Assert(Operation<'func, M, F, operation::Assert>),
270    AssertSsa(Operation<'func, M, F, operation::AssertSsa>),
271    ForceVersion(Operation<'func, M, F, operation::ForceVersion>),
272    ForceVersionSsa(Operation<'func, M, F, operation::ForceVersionSsa>),
273
274    RegPhi(Operation<'func, M, F, operation::RegPhi>),
275    FlagPhi(Operation<'func, M, F, operation::FlagPhi>),
276    MemPhi(Operation<'func, M, F, operation::MemPhi>),
277
278    /// The instruction is an expression.
279    Value(LowLevelILExpression<'func, M, F, ValueExpr>),
280}
281
282impl<'func, M, F> LowLevelILInstructionKind<'func, M, F>
283where
284    M: FunctionMutability,
285    F: FunctionForm,
286{
287    pub(crate) unsafe fn from_raw(
288        function: &'func LowLevelILFunction<M, F>,
289        expr_index: LowLevelExpressionIndex,
290        op: BNLowLevelILInstruction,
291    ) -> Self {
292        use binaryninjacore_sys::BNLowLevelILOperation::*;
293
294        match op.operation {
295            LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op, expr_index)),
296            LLIL_SET_REG => {
297                LowLevelILInstructionKind::SetReg(Operation::new(function, op, expr_index))
298            }
299            LLIL_SET_REG_SSA => {
300                LowLevelILInstructionKind::SetRegSsa(Operation::new(function, op, expr_index))
301            }
302            LLIL_SET_REG_SSA_PARTIAL => LowLevelILInstructionKind::SetRegPartialSsa(
303                Operation::new(function, op, expr_index),
304            ),
305            LLIL_SET_REG_SPLIT => {
306                LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op, expr_index))
307            }
308            LLIL_SET_REG_SPLIT_SSA => {
309                LowLevelILInstructionKind::SetRegSplitSsa(Operation::new(function, op, expr_index))
310            }
311            LLIL_SET_FLAG => {
312                LowLevelILInstructionKind::SetFlag(Operation::new(function, op, expr_index))
313            }
314            LLIL_SET_FLAG_SSA => {
315                LowLevelILInstructionKind::SetFlagSsa(Operation::new(function, op, expr_index))
316            }
317            LLIL_STORE => {
318                LowLevelILInstructionKind::Store(Operation::new(function, op, expr_index))
319            }
320            LLIL_STORE_SSA => {
321                LowLevelILInstructionKind::StoreSsa(Operation::new(function, op, expr_index))
322            }
323            LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op, expr_index)),
324
325            LLIL_REG_STACK_PUSH => {
326                LowLevelILInstructionKind::RegStackPush(Operation::new(function, op, expr_index))
327            }
328            LLIL_REG_STACK_FREE_REG => {
329                LowLevelILInstructionKind::RegStackFreeReg(Operation::new(function, op, expr_index))
330            }
331
332            LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op, expr_index)),
333            LLIL_JUMP_TO => {
334                LowLevelILInstructionKind::JumpTo(Operation::new(function, op, expr_index))
335            }
336
337            LLIL_CALL | LLIL_CALL_STACK_ADJUST => {
338                LowLevelILInstructionKind::Call(Operation::new(function, op, expr_index))
339            }
340            LLIL_CALL_SSA => {
341                LowLevelILInstructionKind::CallSsa(Operation::new(function, op, expr_index))
342            }
343            LLIL_TAILCALL => {
344                LowLevelILInstructionKind::TailCall(Operation::new(function, op, expr_index))
345            }
346            LLIL_TAILCALL_SSA => {
347                LowLevelILInstructionKind::TailCallSsa(Operation::new(function, op, expr_index))
348            }
349
350            LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op, expr_index)),
351            LLIL_NORET => {
352                LowLevelILInstructionKind::NoRet(Operation::new(function, op, expr_index))
353            }
354
355            LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op, expr_index)),
356            LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op, expr_index)),
357
358            LLIL_SYSCALL => {
359                LowLevelILInstructionKind::Syscall(Operation::new(function, op, expr_index))
360            }
361            LLIL_SYSCALL_SSA => {
362                LowLevelILInstructionKind::SyscallSsa(Operation::new(function, op, expr_index))
363            }
364            LLIL_INTRINSIC | LLIL_INTRINSIC_SSA => {
365                LowLevelILInstructionKind::Intrinsic(Operation::new(function, op, expr_index))
366            }
367            LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op, expr_index)),
368            LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op, expr_index)),
369            LLIL_UNDEF => {
370                LowLevelILInstructionKind::Undef(Operation::new(function, op, expr_index))
371            }
372            LLIL_ASSERT => {
373                LowLevelILInstructionKind::Assert(Operation::new(function, op, expr_index))
374            }
375            LLIL_ASSERT_SSA => {
376                LowLevelILInstructionKind::AssertSsa(Operation::new(function, op, expr_index))
377            }
378            LLIL_FORCE_VER => {
379                LowLevelILInstructionKind::ForceVersion(Operation::new(function, op, expr_index))
380            }
381            LLIL_FORCE_VER_SSA => {
382                LowLevelILInstructionKind::ForceVersionSsa(Operation::new(function, op, expr_index))
383            }
384            LLIL_REG_PHI => {
385                LowLevelILInstructionKind::RegPhi(Operation::new(function, op, expr_index))
386            }
387            LLIL_MEM_PHI => {
388                LowLevelILInstructionKind::MemPhi(Operation::new(function, op, expr_index))
389            }
390            LLIL_FLAG_PHI => {
391                LowLevelILInstructionKind::FlagPhi(Operation::new(function, op, expr_index))
392            }
393
394            _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)),
395        }
396    }
397
398    fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction
399    where
400        T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction,
401    {
402        use LowLevelILInstructionKind::*;
403
404        macro_rules! visit {
405            ($expr:expr) => {
406                if let VisitorAction::Halt = visitor($expr) {
407                    return VisitorAction::Halt;
408                }
409            };
410        }
411
412        match self {
413            SetReg(ref op) => visit!(&op.source_expr()),
414            SetRegSsa(ref op) => visit!(&op.source_expr()),
415            SetRegPartialSsa(ref op) => visit!(&op.source_expr()),
416            SetRegSplit(ref op) => visit!(&op.source_expr()),
417            SetRegSplitSsa(ref op) => {
418                visit!(&op.dest_expr_high());
419                visit!(&op.dest_expr_low());
420                visit!(&op.source_expr());
421            }
422            SetFlag(ref op) => visit!(&op.source_expr()),
423            SetFlagSsa(ref op) => visit!(&op.source_expr()),
424            Store(ref op) => {
425                visit!(&op.dest_expr());
426                visit!(&op.source_expr());
427            }
428            StoreSsa(ref op) => {
429                visit!(&op.dest_expr());
430                visit!(&op.source_expr());
431            }
432            Push(ref op) => visit!(&op.operand()),
433            RegStackPush(ref op) => visit!(&op.source_expr()),
434            Jump(ref op) => visit!(&op.target()),
435            JumpTo(ref op) => visit!(&op.target()),
436            SyscallSsa(ref op) => {
437                visit!(&op.output_expr());
438                visit!(&op.stack_expr());
439                visit!(&op.param_expr());
440            }
441            Call(ref op) | TailCall(ref op) => visit!(&op.target()),
442            CallSsa(ref op) | TailCallSsa(ref op) => {
443                visit!(&op.output_expr());
444                visit!(&op.target());
445                visit!(&op.stack_expr());
446                visit!(&op.param_expr());
447            }
448            Ret(ref op) => visit!(&op.target()),
449            If(ref op) => visit!(&op.condition()),
450            Intrinsic(ref op) => visit!(&op.inputs()),
451            Value(e) => visit!(e),
452            // Do not have any sub expressions.
453            Nop(_) | RegStackFreeReg(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_)
454            | Undef(_) | Assert(_) | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_)
455            | RegPhi(_) | FlagPhi(_) | MemPhi(_) => {}
456        }
457
458        VisitorAction::Sibling
459    }
460}