1use 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
72pub trait InstructionHandler<'func, M, F>
74where
75 M: FunctionMutability,
76 F: FunctionForm,
77{
78 fn kind(&self) -> LowLevelILInstructionKind<'func, M, F>;
79
80 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 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 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 pub fn basic_block(&self) -> Option<Ref<BasicBlock<LowLevelILBlock<'func, M, F>>>> {
125 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 _ => 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 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 _ => 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 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 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 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 }
440 Value(e) => visit!(e),
441 Nop(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_) | Undef(_) | Assert(_)
443 | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_) | RegPhi(_) | FlagPhi(_)
444 | MemPhi(_) => {}
445 }
446
447 VisitorAction::Sibling
448 }
449}