1use super::opcode::OpcodeMap;
7use super::operand::Operand;
8use super::prefix::DecodedPrefixes;
9use crate::data::instruction_def::{InstructionCategory, IsaSet};
10use crate::isa::{InstructionAttributes, MachineMode, Mnemonic, Register};
11
12pub const MAX_OPERAND_COUNT: usize = 5;
14
15#[derive(Debug, Clone, Copy, Default)]
20pub struct StackPointerInfo {
21 pub sp_offset: i64,
24 pub modifies_sp: bool,
26 pub is_push: bool,
28 pub is_pop: bool,
30 pub is_call: bool,
32 pub is_ret: bool,
34 pub data_size: u8,
36}
37
38impl StackPointerInfo {
39 #[must_use]
41 pub const fn new() -> Self {
42 Self {
43 sp_offset: 0,
44 modifies_sp: false,
45 is_push: false,
46 is_pop: false,
47 is_call: false,
48 is_ret: false,
49 data_size: 0,
50 }
51 }
52
53 #[must_use]
55 pub const fn push(data_size: u8) -> Self {
56 Self {
57 sp_offset: data_size as i64,
58 modifies_sp: true,
59 is_push: true,
60 is_pop: false,
61 is_call: false,
62 is_ret: false,
63 data_size,
64 }
65 }
66
67 #[must_use]
69 pub const fn pop(data_size: u8) -> Self {
70 Self {
71 sp_offset: -(data_size as i64),
72 modifies_sp: true,
73 is_push: false,
74 is_pop: true,
75 is_call: false,
76 is_ret: false,
77 data_size,
78 }
79 }
80
81 #[must_use]
83 pub const fn call(return_address_size: u8) -> Self {
84 Self {
85 sp_offset: return_address_size as i64,
86 modifies_sp: true,
87 is_push: false,
88 is_pop: false,
89 is_call: true,
90 is_ret: false,
91 data_size: return_address_size,
92 }
93 }
94
95 #[must_use]
97 pub const fn ret(return_address_size: u8) -> Self {
98 Self {
99 sp_offset: -(return_address_size as i64),
100 modifies_sp: true,
101 is_push: false,
102 is_pop: false,
103 is_call: false,
104 is_ret: true,
105 data_size: return_address_size,
106 }
107 }
108
109 #[must_use]
112 pub const fn enter(frame_size: u16, nesting_level: u8, stack_width: u8) -> Self {
113 let base_offset = stack_width as i64 + frame_size as i64;
116 let nesting_offset = if nesting_level > 0 {
117 (nesting_level as i64 - 1) * (stack_width as i64)
118 } else {
119 0
120 };
121 Self {
122 sp_offset: base_offset + nesting_offset,
123 modifies_sp: true,
124 is_push: false,
125 is_pop: false,
126 is_call: false,
127 is_ret: false,
128 data_size: stack_width,
129 }
130 }
131
132 #[must_use]
135 pub const fn leave(stack_width: u8) -> Self {
136 Self {
137 sp_offset: -(stack_width as i64),
138 modifies_sp: true,
139 is_push: false,
140 is_pop: true, is_call: false,
142 is_ret: false,
143 data_size: stack_width,
144 }
145 }
146
147 #[must_use]
149 pub const fn offset(&self) -> i64 {
150 self.sp_offset
151 }
152
153 #[must_use]
155 pub const fn is_stack_modifying(&self) -> bool {
156 self.modifies_sp
157 }
158
159 #[must_use]
161 pub const fn is_stack_push(&self) -> bool {
162 self.is_push
163 }
164
165 #[must_use]
167 pub const fn is_stack_pop(&self) -> bool {
168 self.is_pop
169 }
170
171 #[must_use]
173 pub const fn is_call_instruction(&self) -> bool {
174 self.is_call
175 }
176
177 #[must_use]
179 pub const fn is_ret_instruction(&self) -> bool {
180 self.is_ret
181 }
182
183 #[must_use]
185 pub const fn get_data_size(&self) -> u8 {
186 self.data_size
187 }
188}
189
190#[derive(Debug, Clone)]
200pub struct DecodedInstruction {
201 pub mnemonic: Mnemonic,
203
204 pub category: InstructionCategory,
206
207 pub isa_set: IsaSet,
209
210 pub attributes: InstructionAttributes,
212
213 pub operands: [Operand; MAX_OPERAND_COUNT],
215
216 pub operand_count: u8,
218
219 pub bytes: [u8; 15],
221
222 pub length: u8,
224
225 pub address: u64,
227
228 pub prefixes: DecodedPrefixes,
230
231 pub opcode: u8,
233
234 pub opcode_map: OpcodeMap,
236
237 pub modrm: Option<u8>,
239
240 pub sib: Option<u8>,
242
243 pub displacement: i64,
245
246 pub disp_size: u8,
248
249 pub immediate: u64,
251
252 pub imm_size: u8,
254
255 pub machine_mode: MachineMode,
257
258 pub stack_width: u8,
260
261 pub operand_size: u16,
263
264 pub address_size: u16,
266
267 pub cpu_flags: CpuFlags,
269
270 pub stack_pointer_info: StackPointerInfo,
272}
273
274impl DecodedInstruction {
275 #[must_use]
277 pub fn new() -> Self {
278 Self {
279 mnemonic: Mnemonic::Invalid,
280 category: InstructionCategory::Invalid,
281 isa_set: IsaSet::I86,
282 attributes: InstructionAttributes::empty(),
283 operands: [Operand::default(); MAX_OPERAND_COUNT],
284 operand_count: 0,
285 bytes: [0; 15],
286 length: 0,
287 address: 0,
288 prefixes: DecodedPrefixes::default(),
289 opcode: 0,
290 opcode_map: OpcodeMap::Default,
291 modrm: None,
292 sib: None,
293 displacement: 0,
294 disp_size: 0,
295 immediate: 0,
296 imm_size: 0,
297 machine_mode: MachineMode::Long64,
298 stack_width: 64,
299 operand_size: 32,
300 address_size: 64,
301 cpu_flags: CpuFlags::default(),
302 stack_pointer_info: StackPointerInfo::new(),
303 }
304 }
305
306 #[must_use]
308 pub fn raw_bytes(&self) -> &[u8] {
309 &self.bytes[..usize::from(self.length)]
310 }
311
312 #[must_use]
314 pub fn is_valid(&self) -> bool {
315 self.length > 0 && self.mnemonic != Mnemonic::Invalid
316 }
317
318 #[must_use]
320 pub const fn has_modrm(&self) -> bool {
321 self.modrm.is_some()
322 }
323
324 #[must_use]
326 pub const fn has_sib(&self) -> bool {
327 self.sib.is_some()
328 }
329
330 #[must_use]
332 pub const fn has_displacement(&self) -> bool {
333 self.disp_size > 0
334 }
335
336 #[must_use]
338 pub const fn has_immediate(&self) -> bool {
339 self.imm_size > 0
340 }
341
342 #[must_use]
344 pub const fn is_branch(&self) -> bool {
345 self.attributes.contains(InstructionAttributes::IS_BRANCH)
346 }
347
348 #[must_use]
350 pub const fn is_conditional(&self) -> bool {
351 self.attributes
352 .contains(InstructionAttributes::IS_CONDITIONAL)
353 }
354
355 #[must_use]
357 pub const fn is_privileged(&self) -> bool {
358 self.attributes
359 .contains(InstructionAttributes::IS_PRIVILEGED)
360 }
361
362 #[must_use]
364 pub const fn is_stack_modifying(&self) -> bool {
365 self.attributes
366 .contains(InstructionAttributes::IS_STACK_MODIFYING)
367 }
368
369 #[must_use]
371 pub const fn is_relative(&self) -> bool {
372 self.attributes.contains(InstructionAttributes::IS_RELATIVE)
373 }
374
375 #[must_use]
377 pub const fn next_address(&self) -> u64 {
378 self.address.wrapping_add(self.length as u64)
379 }
380
381 #[must_use]
383 pub fn branch_target(&self) -> Option<u64> {
384 if self.is_relative() && self.is_branch() {
385 let target = self.next_address().wrapping_add(self.displacement as u64);
387 Some(target)
388 } else {
389 None
390 }
391 }
392
393 pub fn operands(&self) -> impl Iterator<Item = &Operand> {
395 self.operands[..usize::from(self.operand_count)].iter()
396 }
397
398 #[must_use]
400 pub fn operand(&self, index: usize) -> Option<&Operand> {
401 if index < usize::from(self.operand_count) {
402 Some(&self.operands[index])
403 } else {
404 None
405 }
406 }
407
408 pub fn set_operand(&mut self, index: usize, operand: Operand) {
410 if index < MAX_OPERAND_COUNT {
411 self.operands[index] = operand;
412 if index >= usize::from(self.operand_count) {
413 self.operand_count = (index + 1) as u8;
414 }
415 }
416 }
417
418 #[must_use]
424 pub const fn cpu_flags_read(&self) -> u64 {
425 self.cpu_flags.read
426 }
427
428 #[must_use]
432 pub const fn cpu_flags_written(&self) -> u64 {
433 self.cpu_flags.written
434 }
435
436 #[must_use]
440 pub const fn cpu_flags_modified(&self) -> u64 {
441 self.cpu_flags.modified
442 }
443
444 #[must_use]
448 pub const fn cpu_flags_undefined(&self) -> u64 {
449 self.cpu_flags.undefined
450 }
451
452 #[must_use]
456 pub const fn get_cpu_flags(&self) -> &CpuFlags {
457 &self.cpu_flags
458 }
459
460 #[must_use]
462 pub const fn reads_any_cpu_flag(&self) -> bool {
463 self.cpu_flags.reads_any()
464 }
465
466 #[must_use]
468 pub const fn writes_any_cpu_flag(&self) -> bool {
469 self.cpu_flags.writes_any()
470 }
471
472 #[must_use]
474 pub const fn modifies_any_cpu_flag(&self) -> bool {
475 self.cpu_flags.modifies_any()
476 }
477
478 #[must_use]
480 pub const fn reads_cpu_flag(&self, flag: CPUFlag) -> bool {
481 self.cpu_flags.reads_flag(flag)
482 }
483
484 #[must_use]
486 pub const fn writes_cpu_flag(&self, flag: CPUFlag) -> bool {
487 self.cpu_flags.writes_flag(flag)
488 }
489
490 #[must_use]
492 pub const fn modifies_cpu_flag(&self, flag: CPUFlag) -> bool {
493 self.cpu_flags.modifies_flag(flag)
494 }
495
496 #[must_use]
502 pub const fn get_stack_pointer_info(&self) -> &StackPointerInfo {
503 &self.stack_pointer_info
504 }
505
506 #[must_use]
511 pub const fn stack_pointer_offset(&self) -> i64 {
512 self.stack_pointer_info.sp_offset
513 }
514
515 #[must_use]
517 pub const fn modifies_stack_pointer(&self) -> bool {
518 self.stack_pointer_info.modifies_sp
519 }
520
521 #[must_use]
523 pub const fn is_push(&self) -> bool {
524 self.stack_pointer_info.is_push
525 }
526
527 #[must_use]
529 pub const fn is_pop(&self) -> bool {
530 self.stack_pointer_info.is_pop
531 }
532
533 #[must_use]
535 pub const fn is_call(&self) -> bool {
536 self.stack_pointer_info.is_call
537 }
538
539 #[must_use]
541 pub const fn is_ret(&self) -> bool {
542 self.stack_pointer_info.is_ret
543 }
544
545 pub fn set_stack_pointer_info(&mut self, info: StackPointerInfo) {
547 self.stack_pointer_info = info;
548 }
549
550 #[must_use]
558 pub const fn category(&self) -> InstructionCategory {
559 self.category
560 }
561
562 #[must_use]
567 pub const fn isa_set(&self) -> IsaSet {
568 self.isa_set
569 }
570
571 #[must_use]
575 pub fn branch_type(&self) -> Option<BranchType> {
576 if !self.is_branch() {
577 return None;
578 }
579
580 if self.is_conditional() {
582 if self.disp_size == 1 {
584 Some(BranchType::Short)
585 } else {
586 Some(BranchType::Near)
587 }
588 } else {
589 match self.disp_size {
591 1 => Some(BranchType::Short),
592 2 | 4 => Some(BranchType::Near),
593 _ => {
594 if self
596 .attributes
597 .contains(InstructionAttributes::IS_FAR_BRANCH)
598 {
599 Some(BranchType::Far)
600 } else {
601 Some(BranchType::Near)
602 }
603 }
604 }
605 }
606 }
607
608 #[must_use]
613 pub const fn exception_class(&self) -> ExceptionClass {
614 if self.isa_set.is_avx512() {
616 ExceptionClass::EVEX
617 } else if self.isa_set.is_avx() {
618 ExceptionClass::VEX
619 } else if self.isa_set.is_xop() {
620 ExceptionClass::XOP
621 } else if self.isa_set.is_sse() {
622 ExceptionClass::SSE
623 } else {
624 ExceptionClass::None
625 }
626 }
627
628 #[must_use]
641 pub fn calc_absolute_address(&self, operand_index: usize, rip: u64) -> Option<u64> {
642 let operand = self.operand(operand_index)?;
643
644 match operand.kind {
645 crate::isa::OperandKind::RelativeOffset => {
646 let disp = operand.imm_signed()?;
648 Some(rip.wrapping_add(disp as u64))
650 }
651 crate::isa::OperandKind::Memory => {
652 let mem = operand.mem()?;
654 if mem.base == Register::RIP {
655 Some(rip.wrapping_add(mem.displacement as u64))
657 } else {
658 None
659 }
660 }
661 _ => None,
662 }
663 }
664
665 #[must_use]
670 pub fn condition_code(&self) -> Option<ConditionCode> {
671 if !self.is_conditional() {
672 return None;
673 }
674
675 let opcode = self.opcode;
678
679 match self.mnemonic {
681 Mnemonic::JO
683 | Mnemonic::JNO
684 | Mnemonic::JB
685 | Mnemonic::JNB
686 | Mnemonic::JZ
687 | Mnemonic::JNZ
688 | Mnemonic::JBE
689 | Mnemonic::JA
690 | Mnemonic::JS
691 | Mnemonic::JNS
692 | Mnemonic::JP
693 | Mnemonic::JNP
694 | Mnemonic::JL
695 | Mnemonic::JGE
696 | Mnemonic::JLE
697 | Mnemonic::JG => {
698 let cc = if (0x70..=0x7F).contains(&opcode) {
699 opcode - 0x70
700 } else if opcode == 0x0F {
701 (self.bytes[1].wrapping_sub(0x80)) & 0x0F
704 } else {
705 return None;
706 };
707 ConditionCode::from_u8(cc)
708 }
709 Mnemonic::SETO
711 | Mnemonic::SETNO
712 | Mnemonic::SETB
713 | Mnemonic::SETNB
714 | Mnemonic::SETZ
715 | Mnemonic::SETNZ
716 | Mnemonic::SETBE
717 | Mnemonic::SETNBE
718 | Mnemonic::SETS
719 | Mnemonic::SETNS
720 | Mnemonic::SETP
721 | Mnemonic::SETNP
722 | Mnemonic::SETL
723 | Mnemonic::SETGE
724 | Mnemonic::SETLE
725 | Mnemonic::SETG => {
726 let cc = if self.bytes.len() > 1 && self.bytes[1] >= 0x90 && self.bytes[1] <= 0x9F {
727 (self.bytes[1] - 0x90) & 0x0F
728 } else {
729 return None;
730 };
731 ConditionCode::from_u8(cc)
732 }
733 Mnemonic::CMOVO
735 | Mnemonic::CMOVNO
736 | Mnemonic::CMOVB
737 | Mnemonic::CMOVNB
738 | Mnemonic::CMOVZ
739 | Mnemonic::CMOVNZ
740 | Mnemonic::CMOVBE
741 | Mnemonic::CMOVA
742 | Mnemonic::CMOVS
743 | Mnemonic::CMOVNS
744 | Mnemonic::CMOVP
745 | Mnemonic::CMOVNP
746 | Mnemonic::CMOVL
747 | Mnemonic::CMOVGE
748 | Mnemonic::CMOVLE
749 | Mnemonic::CMOVG => {
750 let cc = if self.bytes.len() > 1 && self.bytes[1] >= 0x40 && self.bytes[1] <= 0x4F {
751 (self.bytes[1] - 0x40) & 0x0F
752 } else {
753 return None;
754 };
755 ConditionCode::from_u8(cc)
756 }
757 _ => None,
758 }
759 }
760}
761
762#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
766#[repr(u8)]
767#[derive(Default)]
768pub enum BranchType {
769 #[default]
771 None,
772 Short,
774 Near,
776 Far,
778}
779
780#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
784#[repr(u8)]
785#[derive(Default)]
786pub enum ExceptionClass {
787 #[default]
789 None,
790 SSE,
792 VEX,
794 EVEX,
796 XOP,
798}
799
800#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
804#[repr(u8)]
805pub enum ConditionCode {
806 O = 0,
808 NO = 1,
810 B = 2,
812 NB = 3,
814 Z = 4,
816 NZ = 5,
818 BE = 6,
820 A = 7,
822 S = 8,
824 NS = 9,
826 P = 10,
828 NP = 11,
830 L = 12,
832 GE = 13,
834 LE = 14,
836 G = 15,
838}
839
840impl ConditionCode {
841 #[must_use]
843 pub const fn from_u8(value: u8) -> Option<Self> {
844 match value {
845 0 => Some(Self::O),
846 1 => Some(Self::NO),
847 2 => Some(Self::B),
848 3 => Some(Self::NB),
849 4 => Some(Self::Z),
850 5 => Some(Self::NZ),
851 6 => Some(Self::BE),
852 7 => Some(Self::A),
853 8 => Some(Self::S),
854 9 => Some(Self::NS),
855 10 => Some(Self::P),
856 11 => Some(Self::NP),
857 12 => Some(Self::L),
858 13 => Some(Self::GE),
859 14 => Some(Self::LE),
860 15 => Some(Self::G),
861 _ => None,
862 }
863 }
864
865 #[must_use]
867 pub const fn name(&self) -> &'static str {
868 match self {
869 Self::O => "O",
870 Self::NO => "NO",
871 Self::B => "B",
872 Self::NB => "NB",
873 Self::Z => "Z",
874 Self::NZ => "NZ",
875 Self::BE => "BE",
876 Self::A => "A",
877 Self::S => "S",
878 Self::NS => "NS",
879 Self::P => "P",
880 Self::NP => "NP",
881 Self::L => "L",
882 Self::GE => "GE",
883 Self::LE => "LE",
884 Self::G => "G",
885 }
886 }
887}
888
889impl Default for DecodedInstruction {
890 fn default() -> Self {
891 Self::new()
892 }
893}
894
895#[derive(Debug, Clone, Copy, Default)]
900pub struct CpuFlags {
901 pub read: u64,
903 pub written: u64,
905 pub modified: u64,
907 pub undefined: u64,
909}
910
911#[derive(Debug, Clone, Copy, PartialEq, Eq)]
913#[repr(u8)]
914pub enum CPUFlag {
915 CF = 0,
917 PF = 2,
919 AF = 4,
921 ZF = 6,
923 SF = 7,
925 TF = 8,
927 IF = 9,
929 DF = 10,
931 OF = 11,
933 IOPL0 = 12,
935 IOPL1 = 13,
937 NT = 14,
939 RF = 16,
941 VM = 17,
943 AC = 18,
945 VIF = 19,
947 VIP = 20,
949 ID = 21,
951}
952
953impl CpuFlags {
954 pub const CF: u64 = 1 << 0;
957 pub const PF: u64 = 1 << 2;
959 pub const AF: u64 = 1 << 4;
961 pub const ZF: u64 = 1 << 6;
963 pub const SF: u64 = 1 << 7;
965 pub const TF: u64 = 1 << 8;
967 pub const IF: u64 = 1 << 9;
969 pub const DF: u64 = 1 << 10;
971 pub const OF: u64 = 1 << 11;
973 pub const IOPL: u64 = (1 << 12) | (1 << 13);
975 pub const NT: u64 = 1 << 14;
977 pub const RF: u64 = 1 << 16;
979 pub const VM: u64 = 1 << 17;
981 pub const AC: u64 = 1 << 18;
983 pub const VIF: u64 = 1 << 19;
985 pub const VIP: u64 = 1 << 20;
987 pub const ID: u64 = 1 << 21;
989
990 #[must_use]
992 pub const fn new(read: u64, written: u64, modified: u64, undefined: u64) -> Self {
993 Self {
994 read,
995 written,
996 modified,
997 undefined,
998 }
999 }
1000
1001 #[must_use]
1003 pub const fn from_read_written(read: u64, written: u64) -> Self {
1004 Self {
1005 read,
1006 written,
1007 modified: read & written, undefined: 0,
1009 }
1010 }
1011
1012 #[must_use]
1014 pub const fn reads_any(&self) -> bool {
1015 self.read != 0
1016 }
1017
1018 #[must_use]
1020 pub const fn writes_any(&self) -> bool {
1021 self.written != 0
1022 }
1023
1024 #[must_use]
1026 pub const fn modifies_any(&self) -> bool {
1027 self.modified != 0
1028 }
1029
1030 #[must_use]
1032 pub const fn has_undefined(&self) -> bool {
1033 self.undefined != 0
1034 }
1035
1036 #[must_use]
1040 pub const fn reads_cf(&self) -> bool {
1041 (self.read & Self::CF) != 0
1042 }
1043
1044 #[must_use]
1046 pub const fn reads_zf(&self) -> bool {
1047 (self.read & Self::ZF) != 0
1048 }
1049
1050 #[must_use]
1052 pub const fn reads_sf(&self) -> bool {
1053 (self.read & Self::SF) != 0
1054 }
1055
1056 #[must_use]
1058 pub const fn reads_of(&self) -> bool {
1059 (self.read & Self::OF) != 0
1060 }
1061
1062 #[must_use]
1064 pub const fn reads_pf(&self) -> bool {
1065 (self.read & Self::PF) != 0
1066 }
1067
1068 #[must_use]
1070 pub const fn reads_af(&self) -> bool {
1071 (self.read & Self::AF) != 0
1072 }
1073
1074 #[must_use]
1076 pub const fn reads_df(&self) -> bool {
1077 (self.read & Self::DF) != 0
1078 }
1079
1080 #[must_use]
1084 pub const fn writes_cf(&self) -> bool {
1085 (self.written & Self::CF) != 0
1086 }
1087
1088 #[must_use]
1090 pub const fn writes_zf(&self) -> bool {
1091 (self.written & Self::ZF) != 0
1092 }
1093
1094 #[must_use]
1096 pub const fn writes_sf(&self) -> bool {
1097 (self.written & Self::SF) != 0
1098 }
1099
1100 #[must_use]
1102 pub const fn writes_of(&self) -> bool {
1103 (self.written & Self::OF) != 0
1104 }
1105
1106 #[must_use]
1108 pub const fn writes_pf(&self) -> bool {
1109 (self.written & Self::PF) != 0
1110 }
1111
1112 #[must_use]
1114 pub const fn writes_af(&self) -> bool {
1115 (self.written & Self::AF) != 0
1116 }
1117
1118 #[must_use]
1120 pub const fn writes_df(&self) -> bool {
1121 (self.written & Self::DF) != 0
1122 }
1123
1124 #[must_use]
1128 pub const fn modifies_cf(&self) -> bool {
1129 (self.modified & Self::CF) != 0
1130 }
1131
1132 #[must_use]
1134 pub const fn modifies_zf(&self) -> bool {
1135 (self.modified & Self::ZF) != 0
1136 }
1137
1138 #[must_use]
1140 pub const fn modifies_sf(&self) -> bool {
1141 (self.modified & Self::SF) != 0
1142 }
1143
1144 #[must_use]
1146 pub const fn modifies_of(&self) -> bool {
1147 (self.modified & Self::OF) != 0
1148 }
1149
1150 #[must_use]
1153 pub const fn undefined_cf(&self) -> bool {
1154 (self.undefined & Self::CF) != 0
1155 }
1156
1157 #[must_use]
1159 pub const fn undefined_zf(&self) -> bool {
1160 (self.undefined & Self::ZF) != 0
1161 }
1162
1163 #[must_use]
1165 pub const fn undefined_sf(&self) -> bool {
1166 (self.undefined & Self::SF) != 0
1167 }
1168
1169 #[must_use]
1171 pub const fn undefined_of(&self) -> bool {
1172 (self.undefined & Self::OF) != 0
1173 }
1174
1175 #[must_use]
1177 pub const fn reads_flag(&self, flag: CPUFlag) -> bool {
1178 (self.read & (1 << flag as u8)) != 0
1179 }
1180
1181 #[must_use]
1183 pub const fn writes_flag(&self, flag: CPUFlag) -> bool {
1184 (self.written & (1 << flag as u8)) != 0
1185 }
1186
1187 #[must_use]
1189 pub const fn modifies_flag(&self, flag: CPUFlag) -> bool {
1190 (self.modified & (1 << flag as u8)) != 0
1191 }
1192
1193 #[must_use]
1195 pub const fn is_undefined(&self, flag: CPUFlag) -> bool {
1196 (self.undefined & (1 << flag as u8)) != 0
1197 }
1198
1199 #[must_use]
1201 pub const fn accessed(&self) -> u64 {
1202 self.read | self.written
1203 }
1204
1205 #[must_use]
1207 pub const fn merge(&self, other: &Self) -> Self {
1208 Self {
1209 read: self.read | other.read,
1210 written: self.written | other.written,
1211 modified: self.modified | other.modified,
1212 undefined: self.undefined | other.undefined,
1213 }
1214 }
1215}
1216
1217#[cfg(test)]
1218mod tests {
1219 use super::*;
1220
1221 #[test]
1222 fn test_decoded_instruction_new() {
1223 let instr = DecodedInstruction::new();
1224 assert_eq!(instr.mnemonic, Mnemonic::Invalid);
1225 assert_eq!(instr.length, 0);
1226 assert!(!instr.is_valid());
1227 }
1228
1229 #[test]
1230 fn test_instruction_operands() {
1231 let mut instr = DecodedInstruction::new();
1232 instr.operand_count = 2;
1233
1234 let count = instr.operands().count();
1235 assert_eq!(count, 2);
1236 }
1237
1238 #[test]
1239 fn test_branch_target() {
1240 let mut instr = DecodedInstruction::new();
1241 instr.mnemonic = Mnemonic::JMP;
1242 instr.attributes = InstructionAttributes::IS_BRANCH | InstructionAttributes::IS_RELATIVE;
1243 instr.length = 5;
1244 instr.address = 0x1000;
1245 instr.displacement = 0x10;
1246
1247 let target = instr.branch_target();
1248 assert_eq!(target, Some(0x1015)); }
1250
1251 #[test]
1252 fn test_cpu_flags() {
1253 let flags = CpuFlags::new(CpuFlags::CF | CpuFlags::ZF, CpuFlags::OF, 0, 0);
1254 assert!(flags.reads_cf());
1255 assert!(flags.reads_zf());
1256 assert!(!flags.reads_sf());
1257 assert!(flags.writes_cf() == false);
1258 assert!(flags.writes_of());
1259 }
1260
1261 #[test]
1262 fn test_cpu_flags_from_read_written() {
1263 let flags =
1264 CpuFlags::from_read_written(CpuFlags::CF | CpuFlags::ZF, CpuFlags::CF | CpuFlags::OF);
1265 assert!(flags.reads_cf());
1266 assert!(flags.reads_zf());
1267 assert!(flags.writes_cf());
1268 assert!(flags.writes_of());
1269 assert!(flags.modifies_cf()); assert!(!flags.modifies_zf()); assert!(!flags.modifies_of()); }
1273
1274 #[test]
1275 fn test_decoded_instruction_cpu_flags() {
1276 let mut instr = DecodedInstruction::new();
1277 instr.cpu_flags = CpuFlags::from_read_written(CpuFlags::CF, CpuFlags::ZF);
1278
1279 assert!(instr.reads_any_cpu_flag());
1280 assert!(instr.writes_any_cpu_flag());
1281 assert!(instr.reads_cpu_flag(CPUFlag::CF));
1282 assert!(instr.writes_cpu_flag(CPUFlag::ZF));
1283 assert!(!instr.reads_cpu_flag(CPUFlag::ZF));
1284 }
1285
1286 #[test]
1287 fn test_stack_pointer_info_push() {
1288 let info = StackPointerInfo::push(8);
1289 assert!(info.is_stack_modifying());
1290 assert!(info.is_stack_push());
1291 assert!(!info.is_stack_pop());
1292 assert_eq!(info.offset(), 8);
1293 assert_eq!(info.get_data_size(), 8);
1294 }
1295
1296 #[test]
1297 fn test_stack_pointer_info_pop() {
1298 let info = StackPointerInfo::pop(8);
1299 assert!(info.is_stack_modifying());
1300 assert!(!info.is_stack_push());
1301 assert!(info.is_stack_pop());
1302 assert_eq!(info.offset(), -8);
1303 assert_eq!(info.get_data_size(), 8);
1304 }
1305
1306 #[test]
1307 fn test_stack_pointer_info_call() {
1308 let info = StackPointerInfo::call(8);
1309 assert!(info.is_stack_modifying());
1310 assert!(info.is_call_instruction());
1311 assert!(!info.is_ret_instruction());
1312 assert_eq!(info.offset(), 8);
1313 }
1314
1315 #[test]
1316 fn test_stack_pointer_info_ret() {
1317 let info = StackPointerInfo::ret(8);
1318 assert!(info.is_stack_modifying());
1319 assert!(!info.is_call_instruction());
1320 assert!(info.is_ret_instruction());
1321 assert_eq!(info.offset(), -8);
1322 }
1323
1324 #[test]
1325 fn test_stack_pointer_info_enter() {
1326 let info = StackPointerInfo::enter(32, 0, 8);
1327 assert!(info.is_stack_modifying());
1328 assert_eq!(info.offset(), 8 + 32);
1330 }
1331
1332 #[test]
1333 fn test_stack_pointer_info_leave() {
1334 let info = StackPointerInfo::leave(8);
1335 assert!(info.is_stack_modifying());
1336 assert!(info.is_stack_pop());
1337 assert_eq!(info.offset(), -8);
1338 }
1339
1340 #[test]
1341 fn test_decoded_instruction_stack_pointer() {
1342 let mut instr = DecodedInstruction::new();
1343 instr.stack_pointer_info = StackPointerInfo::push(8);
1344
1345 assert!(instr.modifies_stack_pointer());
1346 assert!(instr.is_push());
1347 assert!(!instr.is_pop());
1348 assert_eq!(instr.stack_pointer_offset(), 8);
1349 }
1350}