binaryninja/low_level_il/
instruction.rs

1// Copyright 2021-2025 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
248    Jump(Operation<'func, M, F, operation::Jump>),
249    JumpTo(Operation<'func, M, F, operation::JumpTo>),
250
251    Call(Operation<'func, M, F, operation::Call>),
252    CallSsa(Operation<'func, M, F, operation::CallSsa>),
253    TailCall(Operation<'func, M, F, operation::Call>),
254    TailCallSsa(Operation<'func, M, F, operation::CallSsa>),
255
256    Ret(Operation<'func, M, F, operation::Ret>),
257    NoRet(Operation<'func, M, F, operation::NoArgs>),
258
259    If(Operation<'func, M, F, operation::If>),
260    Goto(Operation<'func, M, F, operation::Goto>),
261
262    Syscall(Operation<'func, M, F, operation::Syscall>),
263    SyscallSsa(Operation<'func, M, F, operation::SyscallSsa>),
264    Intrinsic(Operation<'func, M, F, operation::Intrinsic>),
265    Bp(Operation<'func, M, F, operation::NoArgs>),
266    Trap(Operation<'func, M, F, operation::Trap>),
267    Undef(Operation<'func, M, F, operation::NoArgs>),
268    Assert(Operation<'func, M, F, operation::Assert>),
269    AssertSsa(Operation<'func, M, F, operation::AssertSsa>),
270    ForceVersion(Operation<'func, M, F, operation::ForceVersion>),
271    ForceVersionSsa(Operation<'func, M, F, operation::ForceVersionSsa>),
272
273    RegPhi(Operation<'func, M, F, operation::RegPhi>),
274    FlagPhi(Operation<'func, M, F, operation::FlagPhi>),
275    MemPhi(Operation<'func, M, F, operation::MemPhi>),
276
277    /// The instruction is an expression.
278    Value(LowLevelILExpression<'func, M, F, ValueExpr>),
279}
280
281impl<'func, M, F> LowLevelILInstructionKind<'func, M, F>
282where
283    M: FunctionMutability,
284    F: FunctionForm,
285{
286    pub(crate) unsafe fn from_raw(
287        function: &'func LowLevelILFunction<M, F>,
288        expr_index: LowLevelExpressionIndex,
289        op: BNLowLevelILInstruction,
290    ) -> Self {
291        use binaryninjacore_sys::BNLowLevelILOperation::*;
292
293        match op.operation {
294            LLIL_NOP => LowLevelILInstructionKind::Nop(Operation::new(function, op, expr_index)),
295            LLIL_SET_REG => {
296                LowLevelILInstructionKind::SetReg(Operation::new(function, op, expr_index))
297            }
298            LLIL_SET_REG_SSA => {
299                LowLevelILInstructionKind::SetRegSsa(Operation::new(function, op, expr_index))
300            }
301            LLIL_SET_REG_SSA_PARTIAL => LowLevelILInstructionKind::SetRegPartialSsa(
302                Operation::new(function, op, expr_index),
303            ),
304            LLIL_SET_REG_SPLIT => {
305                LowLevelILInstructionKind::SetRegSplit(Operation::new(function, op, expr_index))
306            }
307            LLIL_SET_REG_SPLIT_SSA => {
308                LowLevelILInstructionKind::SetRegSplitSsa(Operation::new(function, op, expr_index))
309            }
310            LLIL_SET_FLAG => {
311                LowLevelILInstructionKind::SetFlag(Operation::new(function, op, expr_index))
312            }
313            LLIL_SET_FLAG_SSA => {
314                LowLevelILInstructionKind::SetFlagSsa(Operation::new(function, op, expr_index))
315            }
316            LLIL_STORE => {
317                LowLevelILInstructionKind::Store(Operation::new(function, op, expr_index))
318            }
319            LLIL_STORE_SSA => {
320                LowLevelILInstructionKind::StoreSsa(Operation::new(function, op, expr_index))
321            }
322            LLIL_PUSH => LowLevelILInstructionKind::Push(Operation::new(function, op, expr_index)),
323
324            LLIL_REG_STACK_PUSH => {
325                LowLevelILInstructionKind::RegStackPush(Operation::new(function, op, expr_index))
326            }
327
328            LLIL_JUMP => LowLevelILInstructionKind::Jump(Operation::new(function, op, expr_index)),
329            LLIL_JUMP_TO => {
330                LowLevelILInstructionKind::JumpTo(Operation::new(function, op, expr_index))
331            }
332
333            LLIL_CALL | LLIL_CALL_STACK_ADJUST => {
334                LowLevelILInstructionKind::Call(Operation::new(function, op, expr_index))
335            }
336            LLIL_CALL_SSA => {
337                LowLevelILInstructionKind::CallSsa(Operation::new(function, op, expr_index))
338            }
339            LLIL_TAILCALL => {
340                LowLevelILInstructionKind::TailCall(Operation::new(function, op, expr_index))
341            }
342            LLIL_TAILCALL_SSA => {
343                LowLevelILInstructionKind::TailCallSsa(Operation::new(function, op, expr_index))
344            }
345
346            LLIL_RET => LowLevelILInstructionKind::Ret(Operation::new(function, op, expr_index)),
347            LLIL_NORET => {
348                LowLevelILInstructionKind::NoRet(Operation::new(function, op, expr_index))
349            }
350
351            LLIL_IF => LowLevelILInstructionKind::If(Operation::new(function, op, expr_index)),
352            LLIL_GOTO => LowLevelILInstructionKind::Goto(Operation::new(function, op, expr_index)),
353
354            LLIL_SYSCALL => {
355                LowLevelILInstructionKind::Syscall(Operation::new(function, op, expr_index))
356            }
357            LLIL_SYSCALL_SSA => {
358                LowLevelILInstructionKind::SyscallSsa(Operation::new(function, op, expr_index))
359            }
360            LLIL_INTRINSIC | LLIL_INTRINSIC_SSA => {
361                LowLevelILInstructionKind::Intrinsic(Operation::new(function, op, expr_index))
362            }
363            LLIL_BP => LowLevelILInstructionKind::Bp(Operation::new(function, op, expr_index)),
364            LLIL_TRAP => LowLevelILInstructionKind::Trap(Operation::new(function, op, expr_index)),
365            LLIL_UNDEF => {
366                LowLevelILInstructionKind::Undef(Operation::new(function, op, expr_index))
367            }
368            LLIL_ASSERT => {
369                LowLevelILInstructionKind::Assert(Operation::new(function, op, expr_index))
370            }
371            LLIL_ASSERT_SSA => {
372                LowLevelILInstructionKind::AssertSsa(Operation::new(function, op, expr_index))
373            }
374            LLIL_FORCE_VER => {
375                LowLevelILInstructionKind::ForceVersion(Operation::new(function, op, expr_index))
376            }
377            LLIL_FORCE_VER_SSA => {
378                LowLevelILInstructionKind::ForceVersionSsa(Operation::new(function, op, expr_index))
379            }
380            LLIL_REG_PHI => {
381                LowLevelILInstructionKind::RegPhi(Operation::new(function, op, expr_index))
382            }
383            LLIL_MEM_PHI => {
384                LowLevelILInstructionKind::MemPhi(Operation::new(function, op, expr_index))
385            }
386            LLIL_FLAG_PHI => {
387                LowLevelILInstructionKind::FlagPhi(Operation::new(function, op, expr_index))
388            }
389
390            _ => LowLevelILInstructionKind::Value(LowLevelILExpression::new(function, expr_index)),
391        }
392    }
393
394    fn visit_sub_expressions<T>(&self, mut visitor: T) -> VisitorAction
395    where
396        T: FnMut(&LowLevelILExpression<'func, M, F, ValueExpr>) -> VisitorAction,
397    {
398        use LowLevelILInstructionKind::*;
399
400        macro_rules! visit {
401            ($expr:expr) => {
402                if let VisitorAction::Halt = visitor($expr) {
403                    return VisitorAction::Halt;
404                }
405            };
406        }
407
408        match self {
409            SetReg(ref op) => visit!(&op.source_expr()),
410            SetRegSsa(ref op) => visit!(&op.source_expr()),
411            SetRegPartialSsa(ref op) => visit!(&op.source_expr()),
412            SetRegSplit(ref op) => visit!(&op.source_expr()),
413            SetRegSplitSsa(ref op) => visit!(&op.source_expr()),
414            SetFlag(ref op) => visit!(&op.source_expr()),
415            SetFlagSsa(ref op) => visit!(&op.source_expr()),
416            Store(ref op) => {
417                visit!(&op.dest_expr());
418                visit!(&op.source_expr());
419            }
420            StoreSsa(ref op) => {
421                visit!(&op.dest_expr());
422                visit!(&op.source_expr());
423            }
424            Push(ref op) => visit!(&op.operand()),
425            RegStackPush(ref op) => visit!(&op.source_expr()),
426            Jump(ref op) => visit!(&op.target()),
427            JumpTo(ref op) => visit!(&op.target()),
428            SyscallSsa(ref op) => {
429                visit!(&op.output_expr());
430                visit!(&op.param_expr());
431                visit!(&op.stack_expr());
432            }
433            Call(ref op) | TailCall(ref op) => visit!(&op.target()),
434            CallSsa(ref op) | TailCallSsa(ref op) => visit!(&op.target()),
435            Ret(ref op) => visit!(&op.target()),
436            If(ref op) => visit!(&op.condition()),
437            Intrinsic(ref _op) => {
438                // TODO: Visit when we support expression lists
439            }
440            Value(e) => visit!(e),
441            // Do not have any sub expressions.
442            Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) | Assert(_)
443            | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) | RegPhi(_) | FlagPhi(_)
444            | MemPhi(_) => {}
445        }
446
447        VisitorAction::Sibling
448    }
449}