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 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 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 Nop(_) | RegStackFreeReg(_) | NoRet(_) | Goto(_) | Syscall(_) | Bp(_) | Trap(_)
454 | Undef(_) | Assert(_) | AssertSsa(_) | ForceVersion(_) | ForceVersionSsa(_)
455 | RegPhi(_) | FlagPhi(_) | MemPhi(_) => {}
456 }
457
458 VisitorAction::Sibling
459 }
460}