1#![no_std]
7
8extern crate alloc;
9use alloc::collections::{BTreeMap, BTreeSet};
10use alloc::string::String;
11use alloc::vec;
12use alloc::vec::Vec;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
20pub enum AddressSpaceId {
21 Register,
23 Ram,
25 Unique,
27 Const,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
36pub struct Varnode {
37 pub space: AddressSpaceId,
38 pub offset: u64,
39 pub size: u32,
41}
42
43impl Varnode {
44 #[inline]
46 pub fn register(offset: u64, size: u32) -> Self {
47 Self {
48 space: AddressSpaceId::Register,
49 offset,
50 size,
51 }
52 }
53
54 #[inline]
56 pub fn unique(offset: u64, size: u32) -> Self {
57 Self {
58 space: AddressSpaceId::Unique,
59 offset,
60 size,
61 }
62 }
63
64 #[inline]
66 pub fn ram(offset: u64, size: u32) -> Self {
67 Self {
68 space: AddressSpaceId::Ram,
69 offset,
70 size,
71 }
72 }
73
74 #[inline]
76 pub fn constant(value: u64, size: u32) -> Self {
77 Self {
78 space: AddressSpaceId::Const,
79 offset: value,
80 size,
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
87pub struct Instruction {
88 pub len: u64,
90 pub disassembly: String,
92 pub ops: Vec<PcodeOp>,
94}
95
96#[derive(Debug, Clone)]
98pub enum DecodeError {
99 UnknownInstruction,
101}
102
103impl core::fmt::Display for DecodeError {
104 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105 match self {
106 DecodeError::UnknownInstruction => write!(f, "unknown instruction encoding"),
107 }
108 }
109}
110
111pub fn offset_unique_varnodes(op: &mut PcodeOp, offset: u64) {
114 if let Some(out) = get_output_mut(op) {
116 if out.space == AddressSpaceId::Unique {
117 out.offset += offset;
118 }
119 }
120 visit_reads_mut(op, &mut |v| {
122 if v.space == AddressSpaceId::Unique {
123 v.offset += offset;
124 }
125 });
126}
127
128pub fn optimize(ops: &mut Vec<PcodeOp>) {
133 for _round in 0..4 {
135 let before = ops.len();
136 optimize_once(ops);
137 if ops.len() == before {
138 break;
139 }
140 }
141}
142
143fn optimize_once(ops: &mut Vec<PcodeOp>) {
144 for op in ops.iter_mut() {
146 match op {
147 PcodeOp::IntZext { out, input } if input.space == AddressSpaceId::Const => {
148 *op = PcodeOp::Copy {
149 out: *out,
150 input: Varnode::constant(input.offset, out.size),
151 };
152 }
153 PcodeOp::IntSext { out, input } if input.space == AddressSpaceId::Const => {
154 let val = input.offset;
156 let in_bits = (input.size as u64) * 8;
157 let extended = if in_bits < 64 && (val >> (in_bits - 1)) & 1 != 0 {
158 val | (!0u64 << in_bits)
159 } else {
160 val
161 };
162 *op = PcodeOp::Copy {
163 out: *out,
164 input: Varnode::constant(extended, out.size),
165 };
166 }
167 PcodeOp::IntLsr { out, left, right }
169 | PcodeOp::IntLsl { out, left, right }
170 | PcodeOp::IntAsr { out, left, right }
171 if right.space == AddressSpaceId::Const && right.offset == 0 =>
172 {
173 *op = PcodeOp::Copy {
174 out: *out,
175 input: *left,
176 };
177 }
178 PcodeOp::IntOr { out, left, right }
180 if right.space == AddressSpaceId::Const && right.offset == 0 =>
181 {
182 *op = PcodeOp::Copy {
183 out: *out,
184 input: *left,
185 };
186 }
187 PcodeOp::IntOr { out, left, right }
188 if left.space == AddressSpaceId::Const && left.offset == 0 =>
189 {
190 *op = PcodeOp::Copy {
191 out: *out,
192 input: *right,
193 };
194 }
195 PcodeOp::IntAnd { out, left, right }
197 if right.space == AddressSpaceId::Const
198 && right.offset == u64::MAX >> (64 - out.size as u64 * 8) =>
199 {
200 *op = PcodeOp::Copy {
201 out: *out,
202 input: *left,
203 };
204 }
205 _ => {}
206 }
207 }
208
209 for op in ops.iter_mut() {
211 if let PcodeOp::Subpiece { out, input, lsb: 0 } = op {
212 if out.size == input.size {
213 *op = PcodeOp::Copy {
214 out: *out,
215 input: *input,
216 };
217 }
218 }
219 }
220
221 let mut analysis = analyze_unique_outputs(ops);
225
226 let mut i = 0;
229 while i + 1 < ops.len() {
230 let collapse = if let PcodeOp::IntAnd {
231 out: out1,
232 left: _,
233 right: mask1,
234 } = &ops[i]
235 {
236 if out1.space == AddressSpaceId::Unique && mask1.space == AddressSpaceId::Const {
237 if let PcodeOp::IntAnd {
238 out: out2,
239 left: in2,
240 right: mask2,
241 } = &ops[i + 1]
242 {
243 if *in2 == *out1 && *mask2 == *mask1 {
244 let total_reads = match analysis.get(i) {
248 Some(Some(info)) => info.future_reads,
249 _ => usize::MAX, };
251 if total_reads == 1 {
252 Some(*out2)
253 } else {
254 None
255 }
256 } else {
257 None
258 }
259 } else {
260 None
261 }
262 } else {
263 None
264 }
265 } else {
266 None
267 };
268
269 if let Some(new_out) = collapse {
270 if let PcodeOp::IntAnd { out, .. } = &mut ops[i] {
271 *out = new_out;
272 }
273 ops.remove(i + 1);
274 analysis = analyze_unique_outputs(ops);
275 continue;
276 }
277 i += 1;
278 }
279
280 let mut i = 0;
285 while i < ops.len() {
286 if let PcodeOp::Copy { out, input } = &ops[i] {
287 if out.space == AddressSpaceId::Unique {
288 let target = *out;
289 let replacement = *input;
290 let entry = analysis.get(i).and_then(|entry| entry.as_ref());
291 if let Some(UniqueOutputInfo {
292 future_reads: 1,
293 next_access: Some(NextAccess::Read(read_idx)),
294 }) = entry
295 {
296 replace_reads(&mut ops[*read_idx], &target, &replacement);
297 ops.remove(i);
298 analysis = analyze_unique_outputs(ops);
299 continue;
300 }
301 }
302 }
303 i += 1;
304 }
305
306 {
313 let mut to_remove = Vec::new();
314 for (i, entry) in analysis.iter().enumerate() {
315 if let Some(info) = entry {
316 if info.future_reads == 0
317 || matches!(info.next_access, Some(NextAccess::Write))
318 {
319 to_remove.push(i);
320 }
321 }
322 }
323 for &idx in to_remove.iter().rev() {
324 ops.remove(idx);
325 }
326 }
327
328 analysis = analyze_unique_outputs(ops);
334 let mut i = 0;
335 while i < ops.len() {
336 let should_sink = match (
337 get_output(&ops[i]),
338 analysis.get(i).and_then(|entry| entry.as_ref()),
339 ) {
340 (
341 Some(out),
342 Some(UniqueOutputInfo {
343 future_reads: 1,
344 next_access: Some(NextAccess::Read(copy_idx)),
345 }),
346 ) if out.space == AddressSpaceId::Unique => {
347 if let PcodeOp::Copy {
348 out: copy_dest,
349 input: copy_src,
350 } = &ops[*copy_idx]
351 {
352 if *copy_src == out {
353 let d = *copy_dest;
354 let safe = (i + 1..*copy_idx)
355 .all(|k| count_reads(&ops[k], &d) == 0 && !writes_to(&ops[k], &d));
356 if safe {
357 Some((*copy_idx, d))
358 } else {
359 None
360 }
361 } else {
362 None
363 }
364 } else {
365 None
366 }
367 }
368 _ => None,
369 };
370
371 if let Some((copy_idx, new_dest)) = should_sink {
372 if let Some(out) = get_output_mut(&mut ops[i]) {
373 *out = new_dest;
374 }
375 ops.remove(copy_idx);
376 analysis = analyze_unique_outputs(ops);
377 continue;
378 }
379 i += 1;
380 }
381}
382
383#[derive(Clone, Copy)]
384struct UniqueOutputInfo {
385 future_reads: usize,
386 next_access: Option<NextAccess>,
387}
388
389#[derive(Clone, Copy)]
390enum NextAccess {
391 Read(usize),
392 Write,
393}
394
395fn analyze_unique_outputs(ops: &[PcodeOp]) -> Vec<Option<UniqueOutputInfo>> {
396 let mut future_reads = BTreeMap::<Varnode, usize>::new();
397 let mut next_access = BTreeMap::<Varnode, NextAccess>::new();
398 let mut result = vec![None; ops.len()];
399
400 let mut cbranch_protected = BTreeSet::<Varnode>::new();
406 {
407 let cbranch_indices: Vec<usize> = ops.iter().enumerate()
409 .filter(|(_, op)| matches!(op, PcodeOp::CBranch { dest, .. } if dest.space == AddressSpaceId::Const))
410 .map(|(i, _)| i)
411 .collect();
412 for &cb_idx in &cbranch_indices {
413 let mut before = BTreeSet::new();
415 let mut after = BTreeSet::new();
416 for (i, op) in ops.iter().enumerate() {
417 if let Some(out) = get_output(op) {
418 if out.space == AddressSpaceId::Unique {
419 if i < cb_idx {
420 before.insert(out);
421 } else if i > cb_idx {
422 after.insert(out);
423 }
424 }
425 }
426 }
427 for v in before.intersection(&after) {
428 cbranch_protected.insert(*v);
429 }
430 }
431 }
432
433 for (idx, op) in ops.iter().enumerate().rev() {
434 if let Some(out) = get_output(op).filter(|out| out.space == AddressSpaceId::Unique) {
435 if cbranch_protected.contains(&out) {
436 result[idx] = None;
439 } else {
440 result[idx] = Some(UniqueOutputInfo {
441 future_reads: future_reads.get(&out).copied().unwrap_or(0),
442 next_access: next_access.get(&out).copied(),
443 });
444 future_reads.remove(&out);
445 next_access.insert(out, NextAccess::Write);
446 }
447 }
448
449 visit_reads(op, &mut |v| {
450 if v.space == AddressSpaceId::Unique {
451 *future_reads.entry(*v).or_insert(0) += 1;
452 next_access.insert(*v, NextAccess::Read(idx));
453 }
454 });
455 }
456
457 result
458}
459
460pub fn get_output(op: &PcodeOp) -> Option<Varnode> {
461 match op {
462 PcodeOp::Copy { out, .. }
463 | PcodeOp::Load { out, .. }
464 | PcodeOp::Subpiece { out, .. }
465 | PcodeOp::IntNeg { out, .. }
466 | PcodeOp::IntNot { out, .. }
467 | PcodeOp::IntZext { out, .. }
468 | PcodeOp::IntSext { out, .. }
469 | PcodeOp::BoolNot { out, .. }
470 | PcodeOp::FloatNeg { out, .. }
471 | PcodeOp::FloatAbs { out, .. }
472 | PcodeOp::FloatSqrt { out, .. }
473 | PcodeOp::FloatNan { out, .. }
474 | PcodeOp::Int2Float { out, .. }
475 | PcodeOp::Float2Float { out, .. }
476 | PcodeOp::Trunc { out, .. }
477 | PcodeOp::FloatCeil { out, .. }
478 | PcodeOp::FloatFloor { out, .. }
479 | PcodeOp::FloatRound { out, .. }
480 | PcodeOp::Popcount { out, .. }
481 | PcodeOp::Lzcount { out, .. }
482 | PcodeOp::IntAdd { out, .. }
483 | PcodeOp::IntSub { out, .. }
484 | PcodeOp::IntMult { out, .. }
485 | PcodeOp::IntDiv { out, .. }
486 | PcodeOp::IntSDiv { out, .. }
487 | PcodeOp::IntRem { out, .. }
488 | PcodeOp::IntSRem { out, .. }
489 | PcodeOp::IntEq { out, .. }
490 | PcodeOp::IntNotEq { out, .. }
491 | PcodeOp::IntLess { out, .. }
492 | PcodeOp::IntLessEq { out, .. }
493 | PcodeOp::IntSLess { out, .. }
494 | PcodeOp::IntSLessEq { out, .. }
495 | PcodeOp::IntAnd { out, .. }
496 | PcodeOp::IntOr { out, .. }
497 | PcodeOp::IntXor { out, .. }
498 | PcodeOp::IntLsl { out, .. }
499 | PcodeOp::IntLsr { out, .. }
500 | PcodeOp::IntAsr { out, .. }
501 | PcodeOp::IntCarry { out, .. }
502 | PcodeOp::IntSCarry { out, .. }
503 | PcodeOp::IntSBorrow { out, .. }
504 | PcodeOp::BoolAnd { out, .. }
505 | PcodeOp::BoolOr { out, .. }
506 | PcodeOp::BoolXor { out, .. }
507 | PcodeOp::FloatAdd { out, .. }
508 | PcodeOp::FloatSub { out, .. }
509 | PcodeOp::FloatMult { out, .. }
510 | PcodeOp::FloatDiv { out, .. }
511 | PcodeOp::FloatEq { out, .. }
512 | PcodeOp::FloatNotEq { out, .. }
513 | PcodeOp::FloatLess { out, .. }
514 | PcodeOp::FloatLessEq { out, .. } => Some(*out),
515 _ => None,
516 }
517}
518
519fn get_output_mut(op: &mut PcodeOp) -> Option<&mut Varnode> {
520 match op {
521 PcodeOp::Copy { out, .. }
522 | PcodeOp::Load { out, .. }
523 | PcodeOp::Subpiece { out, .. }
524 | PcodeOp::IntNeg { out, .. }
525 | PcodeOp::IntNot { out, .. }
526 | PcodeOp::IntZext { out, .. }
527 | PcodeOp::IntSext { out, .. }
528 | PcodeOp::BoolNot { out, .. }
529 | PcodeOp::FloatNeg { out, .. }
530 | PcodeOp::FloatAbs { out, .. }
531 | PcodeOp::FloatSqrt { out, .. }
532 | PcodeOp::FloatNan { out, .. }
533 | PcodeOp::Int2Float { out, .. }
534 | PcodeOp::Float2Float { out, .. }
535 | PcodeOp::Trunc { out, .. }
536 | PcodeOp::FloatCeil { out, .. }
537 | PcodeOp::FloatFloor { out, .. }
538 | PcodeOp::FloatRound { out, .. }
539 | PcodeOp::Popcount { out, .. }
540 | PcodeOp::Lzcount { out, .. }
541 | PcodeOp::IntAdd { out, .. }
542 | PcodeOp::IntSub { out, .. }
543 | PcodeOp::IntMult { out, .. }
544 | PcodeOp::IntDiv { out, .. }
545 | PcodeOp::IntSDiv { out, .. }
546 | PcodeOp::IntRem { out, .. }
547 | PcodeOp::IntSRem { out, .. }
548 | PcodeOp::IntEq { out, .. }
549 | PcodeOp::IntNotEq { out, .. }
550 | PcodeOp::IntLess { out, .. }
551 | PcodeOp::IntLessEq { out, .. }
552 | PcodeOp::IntSLess { out, .. }
553 | PcodeOp::IntSLessEq { out, .. }
554 | PcodeOp::IntAnd { out, .. }
555 | PcodeOp::IntOr { out, .. }
556 | PcodeOp::IntXor { out, .. }
557 | PcodeOp::IntLsl { out, .. }
558 | PcodeOp::IntLsr { out, .. }
559 | PcodeOp::IntAsr { out, .. }
560 | PcodeOp::IntCarry { out, .. }
561 | PcodeOp::IntSCarry { out, .. }
562 | PcodeOp::IntSBorrow { out, .. }
563 | PcodeOp::BoolAnd { out, .. }
564 | PcodeOp::BoolOr { out, .. }
565 | PcodeOp::BoolXor { out, .. }
566 | PcodeOp::FloatAdd { out, .. }
567 | PcodeOp::FloatSub { out, .. }
568 | PcodeOp::FloatMult { out, .. }
569 | PcodeOp::FloatDiv { out, .. }
570 | PcodeOp::FloatEq { out, .. }
571 | PcodeOp::FloatNotEq { out, .. }
572 | PcodeOp::FloatLess { out, .. }
573 | PcodeOp::FloatLessEq { out, .. } => Some(out),
574 _ => None,
575 }
576}
577
578pub fn writes_to(op: &PcodeOp, target: &Varnode) -> bool {
579 match op {
580 PcodeOp::Copy { out, .. }
581 | PcodeOp::Load { out, .. }
582 | PcodeOp::Subpiece { out, .. }
583 | PcodeOp::IntNeg { out, .. }
584 | PcodeOp::IntNot { out, .. }
585 | PcodeOp::IntZext { out, .. }
586 | PcodeOp::IntSext { out, .. }
587 | PcodeOp::BoolNot { out, .. }
588 | PcodeOp::FloatNeg { out, .. }
589 | PcodeOp::FloatAbs { out, .. }
590 | PcodeOp::FloatSqrt { out, .. }
591 | PcodeOp::FloatNan { out, .. }
592 | PcodeOp::Int2Float { out, .. }
593 | PcodeOp::Float2Float { out, .. }
594 | PcodeOp::Trunc { out, .. }
595 | PcodeOp::FloatCeil { out, .. }
596 | PcodeOp::FloatFloor { out, .. }
597 | PcodeOp::FloatRound { out, .. }
598 | PcodeOp::Popcount { out, .. }
599 | PcodeOp::Lzcount { out, .. }
600 | PcodeOp::IntAdd { out, .. }
601 | PcodeOp::IntSub { out, .. }
602 | PcodeOp::IntMult { out, .. }
603 | PcodeOp::IntDiv { out, .. }
604 | PcodeOp::IntSDiv { out, .. }
605 | PcodeOp::IntRem { out, .. }
606 | PcodeOp::IntSRem { out, .. }
607 | PcodeOp::IntEq { out, .. }
608 | PcodeOp::IntNotEq { out, .. }
609 | PcodeOp::IntLess { out, .. }
610 | PcodeOp::IntLessEq { out, .. }
611 | PcodeOp::IntSLess { out, .. }
612 | PcodeOp::IntSLessEq { out, .. }
613 | PcodeOp::IntAnd { out, .. }
614 | PcodeOp::IntOr { out, .. }
615 | PcodeOp::IntXor { out, .. }
616 | PcodeOp::IntLsl { out, .. }
617 | PcodeOp::IntLsr { out, .. }
618 | PcodeOp::IntAsr { out, .. }
619 | PcodeOp::IntCarry { out, .. }
620 | PcodeOp::IntSCarry { out, .. }
621 | PcodeOp::IntSBorrow { out, .. }
622 | PcodeOp::BoolAnd { out, .. }
623 | PcodeOp::BoolOr { out, .. }
624 | PcodeOp::BoolXor { out, .. }
625 | PcodeOp::FloatAdd { out, .. }
626 | PcodeOp::FloatSub { out, .. }
627 | PcodeOp::FloatMult { out, .. }
628 | PcodeOp::FloatDiv { out, .. }
629 | PcodeOp::FloatEq { out, .. }
630 | PcodeOp::FloatNotEq { out, .. }
631 | PcodeOp::FloatLess { out, .. }
632 | PcodeOp::FloatLessEq { out, .. } => out == target,
633 PcodeOp::CallOther { out: Some(out), .. } => out == target,
634 _ => false,
635 }
636}
637
638pub fn reads_varnode(op: &PcodeOp, target: &Varnode) -> bool {
640 count_reads(op, target) > 0
641}
642
643pub fn count_reads(op: &PcodeOp, target: &Varnode) -> usize {
644 let mut n = 0;
645 visit_reads(op, &mut |v| {
646 if v == target {
647 n += 1
648 }
649 });
650 n
651}
652
653fn replace_reads(op: &mut PcodeOp, target: &Varnode, replacement: &Varnode) -> bool {
654 let mut found = false;
655 visit_reads_mut(op, &mut |v| {
656 if v == target {
657 *v = *replacement;
658 found = true;
659 }
660 });
661 found
662}
663
664pub fn visit_reads(op: &PcodeOp, f: &mut impl FnMut(&Varnode)) {
665 match op {
666 PcodeOp::Copy { input, .. } => f(input),
667 PcodeOp::Load { ptr, .. } => f(ptr),
668 PcodeOp::Store { ptr, val, .. } => {
669 f(ptr);
670 f(val);
671 }
672 PcodeOp::Branch { dest }
673 | PcodeOp::BranchInd { dest }
674 | PcodeOp::Call { dest }
675 | PcodeOp::CallInd { dest }
676 | PcodeOp::Return { dest } => f(dest),
677 PcodeOp::CBranch { dest, cond } => {
678 f(dest);
679 f(cond);
680 }
681 PcodeOp::Subpiece { input, .. } => f(input),
682 PcodeOp::IntNeg { input, .. }
683 | PcodeOp::IntNot { input, .. }
684 | PcodeOp::IntZext { input, .. }
685 | PcodeOp::IntSext { input, .. }
686 | PcodeOp::BoolNot { input, .. }
687 | PcodeOp::FloatNeg { input, .. }
688 | PcodeOp::FloatAbs { input, .. }
689 | PcodeOp::FloatSqrt { input, .. }
690 | PcodeOp::FloatNan { input, .. }
691 | PcodeOp::Int2Float { input, .. }
692 | PcodeOp::Float2Float { input, .. }
693 | PcodeOp::Trunc { input, .. }
694 | PcodeOp::FloatCeil { input, .. }
695 | PcodeOp::FloatFloor { input, .. }
696 | PcodeOp::FloatRound { input, .. }
697 | PcodeOp::Popcount { input, .. }
698 | PcodeOp::Lzcount { input, .. } => f(input),
699 PcodeOp::IntAdd { left, right, .. }
700 | PcodeOp::IntSub { left, right, .. }
701 | PcodeOp::IntMult { left, right, .. }
702 | PcodeOp::IntDiv { left, right, .. }
703 | PcodeOp::IntSDiv { left, right, .. }
704 | PcodeOp::IntRem { left, right, .. }
705 | PcodeOp::IntSRem { left, right, .. }
706 | PcodeOp::IntEq { left, right, .. }
707 | PcodeOp::IntNotEq { left, right, .. }
708 | PcodeOp::IntLess { left, right, .. }
709 | PcodeOp::IntLessEq { left, right, .. }
710 | PcodeOp::IntSLess { left, right, .. }
711 | PcodeOp::IntSLessEq { left, right, .. }
712 | PcodeOp::IntAnd { left, right, .. }
713 | PcodeOp::IntOr { left, right, .. }
714 | PcodeOp::IntXor { left, right, .. }
715 | PcodeOp::IntLsl { left, right, .. }
716 | PcodeOp::IntLsr { left, right, .. }
717 | PcodeOp::IntAsr { left, right, .. }
718 | PcodeOp::IntCarry { left, right, .. }
719 | PcodeOp::IntSCarry { left, right, .. }
720 | PcodeOp::IntSBorrow { left, right, .. }
721 | PcodeOp::BoolAnd { left, right, .. }
722 | PcodeOp::BoolOr { left, right, .. }
723 | PcodeOp::BoolXor { left, right, .. }
724 | PcodeOp::FloatAdd { left, right, .. }
725 | PcodeOp::FloatSub { left, right, .. }
726 | PcodeOp::FloatMult { left, right, .. }
727 | PcodeOp::FloatDiv { left, right, .. }
728 | PcodeOp::FloatEq { left, right, .. }
729 | PcodeOp::FloatNotEq { left, right, .. }
730 | PcodeOp::FloatLess { left, right, .. }
731 | PcodeOp::FloatLessEq { left, right, .. } => {
732 f(left);
733 f(right);
734 }
735 PcodeOp::CallOther { inputs, .. } => {
736 for v in inputs {
737 f(v);
738 }
739 }
740 }
741}
742
743fn visit_reads_mut(op: &mut PcodeOp, f: &mut impl FnMut(&mut Varnode)) {
744 match op {
745 PcodeOp::Copy { input, .. } => f(input),
746 PcodeOp::Load { ptr, .. } => f(ptr),
747 PcodeOp::Store { ptr, val, .. } => {
748 f(ptr);
749 f(val);
750 }
751 PcodeOp::Branch { dest }
752 | PcodeOp::BranchInd { dest }
753 | PcodeOp::Call { dest }
754 | PcodeOp::CallInd { dest }
755 | PcodeOp::Return { dest } => f(dest),
756 PcodeOp::CBranch { dest, cond } => {
757 f(dest);
758 f(cond);
759 }
760 PcodeOp::Subpiece { input, .. } => f(input),
761 PcodeOp::IntNeg { input, .. }
762 | PcodeOp::IntNot { input, .. }
763 | PcodeOp::IntZext { input, .. }
764 | PcodeOp::IntSext { input, .. }
765 | PcodeOp::BoolNot { input, .. }
766 | PcodeOp::FloatNeg { input, .. }
767 | PcodeOp::FloatAbs { input, .. }
768 | PcodeOp::FloatSqrt { input, .. }
769 | PcodeOp::FloatNan { input, .. }
770 | PcodeOp::Int2Float { input, .. }
771 | PcodeOp::Float2Float { input, .. }
772 | PcodeOp::Trunc { input, .. }
773 | PcodeOp::FloatCeil { input, .. }
774 | PcodeOp::FloatFloor { input, .. }
775 | PcodeOp::FloatRound { input, .. }
776 | PcodeOp::Popcount { input, .. }
777 | PcodeOp::Lzcount { input, .. } => f(input),
778 PcodeOp::IntAdd { left, right, .. }
779 | PcodeOp::IntSub { left, right, .. }
780 | PcodeOp::IntMult { left, right, .. }
781 | PcodeOp::IntDiv { left, right, .. }
782 | PcodeOp::IntSDiv { left, right, .. }
783 | PcodeOp::IntRem { left, right, .. }
784 | PcodeOp::IntSRem { left, right, .. }
785 | PcodeOp::IntEq { left, right, .. }
786 | PcodeOp::IntNotEq { left, right, .. }
787 | PcodeOp::IntLess { left, right, .. }
788 | PcodeOp::IntLessEq { left, right, .. }
789 | PcodeOp::IntSLess { left, right, .. }
790 | PcodeOp::IntSLessEq { left, right, .. }
791 | PcodeOp::IntAnd { left, right, .. }
792 | PcodeOp::IntOr { left, right, .. }
793 | PcodeOp::IntXor { left, right, .. }
794 | PcodeOp::IntLsl { left, right, .. }
795 | PcodeOp::IntLsr { left, right, .. }
796 | PcodeOp::IntAsr { left, right, .. }
797 | PcodeOp::IntCarry { left, right, .. }
798 | PcodeOp::IntSCarry { left, right, .. }
799 | PcodeOp::IntSBorrow { left, right, .. }
800 | PcodeOp::BoolAnd { left, right, .. }
801 | PcodeOp::BoolOr { left, right, .. }
802 | PcodeOp::BoolXor { left, right, .. }
803 | PcodeOp::FloatAdd { left, right, .. }
804 | PcodeOp::FloatSub { left, right, .. }
805 | PcodeOp::FloatMult { left, right, .. }
806 | PcodeOp::FloatDiv { left, right, .. }
807 | PcodeOp::FloatEq { left, right, .. }
808 | PcodeOp::FloatNotEq { left, right, .. }
809 | PcodeOp::FloatLess { left, right, .. }
810 | PcodeOp::FloatLessEq { left, right, .. } => {
811 f(left);
812 f(right);
813 }
814 PcodeOp::CallOther { inputs, .. } => {
815 for v in inputs {
816 f(v);
817 }
818 }
819 }
820}
821
822#[derive(Debug, Clone, PartialEq, Eq)]
827pub enum PcodeOp {
828 Copy {
830 out: Varnode,
831 input: Varnode,
832 },
833 Load {
834 out: Varnode,
835 space: AddressSpaceId,
836 ptr: Varnode,
837 },
838 Store {
839 space: AddressSpaceId,
840 ptr: Varnode,
841 val: Varnode,
842 },
843
844 Branch {
846 dest: Varnode,
847 },
848 CBranch {
849 dest: Varnode,
850 cond: Varnode,
851 },
852 BranchInd {
853 dest: Varnode,
854 },
855 Call {
856 dest: Varnode,
857 },
858 CallInd {
859 dest: Varnode,
860 },
861 Return {
862 dest: Varnode,
863 },
864
865 IntAdd {
867 out: Varnode,
868 left: Varnode,
869 right: Varnode,
870 },
871 IntSub {
872 out: Varnode,
873 left: Varnode,
874 right: Varnode,
875 },
876 IntMult {
877 out: Varnode,
878 left: Varnode,
879 right: Varnode,
880 },
881 IntDiv {
882 out: Varnode,
883 left: Varnode,
884 right: Varnode,
885 },
886 IntSDiv {
887 out: Varnode,
888 left: Varnode,
889 right: Varnode,
890 },
891 IntRem {
892 out: Varnode,
893 left: Varnode,
894 right: Varnode,
895 },
896 IntSRem {
897 out: Varnode,
898 left: Varnode,
899 right: Varnode,
900 },
901 IntNeg {
902 out: Varnode,
903 input: Varnode,
904 },
905
906 IntEq {
908 out: Varnode,
909 left: Varnode,
910 right: Varnode,
911 },
912 IntNotEq {
913 out: Varnode,
914 left: Varnode,
915 right: Varnode,
916 },
917 IntLess {
918 out: Varnode,
919 left: Varnode,
920 right: Varnode,
921 },
922 IntLessEq {
923 out: Varnode,
924 left: Varnode,
925 right: Varnode,
926 },
927 IntSLess {
928 out: Varnode,
929 left: Varnode,
930 right: Varnode,
931 },
932 IntSLessEq {
933 out: Varnode,
934 left: Varnode,
935 right: Varnode,
936 },
937
938 IntAnd {
940 out: Varnode,
941 left: Varnode,
942 right: Varnode,
943 },
944 IntOr {
945 out: Varnode,
946 left: Varnode,
947 right: Varnode,
948 },
949 IntXor {
950 out: Varnode,
951 left: Varnode,
952 right: Varnode,
953 },
954 IntNot {
955 out: Varnode,
956 input: Varnode,
957 },
958
959 IntLsl {
961 out: Varnode,
962 left: Varnode,
963 right: Varnode,
964 },
965 IntLsr {
966 out: Varnode,
967 left: Varnode,
968 right: Varnode,
969 },
970 IntAsr {
971 out: Varnode,
972 left: Varnode,
973 right: Varnode,
974 },
975
976 IntZext {
978 out: Varnode,
979 input: Varnode,
980 },
981 IntSext {
982 out: Varnode,
983 input: Varnode,
984 },
985 Subpiece {
986 out: Varnode,
987 input: Varnode,
988 lsb: u32,
989 },
990
991 IntCarry {
993 out: Varnode,
994 left: Varnode,
995 right: Varnode,
996 },
997 IntSCarry {
998 out: Varnode,
999 left: Varnode,
1000 right: Varnode,
1001 },
1002 IntSBorrow {
1003 out: Varnode,
1004 left: Varnode,
1005 right: Varnode,
1006 },
1007
1008 BoolAnd {
1010 out: Varnode,
1011 left: Varnode,
1012 right: Varnode,
1013 },
1014 BoolOr {
1015 out: Varnode,
1016 left: Varnode,
1017 right: Varnode,
1018 },
1019 BoolXor {
1020 out: Varnode,
1021 left: Varnode,
1022 right: Varnode,
1023 },
1024 BoolNot {
1025 out: Varnode,
1026 input: Varnode,
1027 },
1028
1029 FloatAdd {
1031 out: Varnode,
1032 left: Varnode,
1033 right: Varnode,
1034 },
1035 FloatSub {
1036 out: Varnode,
1037 left: Varnode,
1038 right: Varnode,
1039 },
1040 FloatMult {
1041 out: Varnode,
1042 left: Varnode,
1043 right: Varnode,
1044 },
1045 FloatDiv {
1046 out: Varnode,
1047 left: Varnode,
1048 right: Varnode,
1049 },
1050 FloatNeg {
1051 out: Varnode,
1052 input: Varnode,
1053 },
1054 FloatAbs {
1055 out: Varnode,
1056 input: Varnode,
1057 },
1058 FloatSqrt {
1059 out: Varnode,
1060 input: Varnode,
1061 },
1062
1063 FloatEq {
1065 out: Varnode,
1066 left: Varnode,
1067 right: Varnode,
1068 },
1069 FloatNotEq {
1070 out: Varnode,
1071 left: Varnode,
1072 right: Varnode,
1073 },
1074 FloatLess {
1075 out: Varnode,
1076 left: Varnode,
1077 right: Varnode,
1078 },
1079 FloatLessEq {
1080 out: Varnode,
1081 left: Varnode,
1082 right: Varnode,
1083 },
1084 FloatNan {
1085 out: Varnode,
1086 input: Varnode,
1087 },
1088
1089 Int2Float {
1091 out: Varnode,
1092 input: Varnode,
1093 },
1094 Float2Float {
1095 out: Varnode,
1096 input: Varnode,
1097 },
1098 Trunc {
1099 out: Varnode,
1100 input: Varnode,
1101 },
1102 FloatCeil {
1103 out: Varnode,
1104 input: Varnode,
1105 },
1106 FloatFloor {
1107 out: Varnode,
1108 input: Varnode,
1109 },
1110 FloatRound {
1111 out: Varnode,
1112 input: Varnode,
1113 },
1114
1115 Popcount {
1117 out: Varnode,
1118 input: Varnode,
1119 },
1120 Lzcount {
1121 out: Varnode,
1122 input: Varnode,
1123 },
1124
1125 CallOther {
1128 out: Option<Varnode>,
1129 func_id: u64,
1130 inputs: Vec<Varnode>,
1131 },
1132}