diff options
Diffstat (limited to 'fuzz/fuzz_targets/behavior_does_not_panic.rs')
| -rw-r--r-- | fuzz/fuzz_targets/behavior_does_not_panic.rs | 253 |
1 files changed, 247 insertions, 6 deletions
diff --git a/fuzz/fuzz_targets/behavior_does_not_panic.rs b/fuzz/fuzz_targets/behavior_does_not_panic.rs index 1b6ac96..b2c648b 100644 --- a/fuzz/fuzz_targets/behavior_does_not_panic.rs +++ b/fuzz/fuzz_targets/behavior_does_not_panic.rs @@ -9,13 +9,10 @@ fuzz_target!(|data: &[u8]| { let x86_64_decoder = yaxpeax_x86::long_mode::InstDecoder::default(); let x86_32_decoder = yaxpeax_x86::protected_mode::InstDecoder::default(); let x86_16_decoder = yaxpeax_x86::real_mode::InstDecoder::default(); - /* - let inst_32b = x86_32_decoder.decode_slice(data).expect("is ok"); - let inst_16b = x86_16_decoder.decode_slice(data).expect("is ok"); - */ if let Ok(inst_64b) = x86_64_decoder.decode_slice(data) { /* + eprint!("x86_64: "); for b in data { eprint!("{:02x}", b); } @@ -24,7 +21,7 @@ fuzz_target!(|data: &[u8]| { let behavior_64b = inst_64b.behavior(); let _ = behavior_64b.privilege_level(); let _ = behavior_64b.exceptions(); - let _ = behavior_64b.implicit_oplist(); +// let _ = behavior_64b.implicit_oplist(); for i in 0..5 { let _ = behavior_64b.operand_access(i); } @@ -51,7 +48,7 @@ fuzz_target!(|data: &[u8]| { _ => {} } // eprintln!("saw {:?}, {:?}", op, acc); - let mut accs = 0; + let mut accs; if inst_64b.opcode() == b64Opcode::LEA && op.is_memory() { // the access-visiting interface below does not report a memory access for lea // because lea does not access memory. skip it to make the counters line up. @@ -135,4 +132,248 @@ fuzz_target!(|data: &[u8]| { assert_eq!(opcount_64b, acc_seen_64b); } } + + if let Ok(inst_32b) = x86_32_decoder.decode_slice(data) { + /* + eprint!("x86_32: "); + for b in data { + eprint!("{:02x}", b); + } + eprintln!(": {}", inst_32b); + */ + let behavior_32b = inst_32b.behavior(); + let _ = behavior_32b.privilege_level(); + let _ = behavior_32b.exceptions(); +// let _ = behavior_32b.implicit_oplist(); + for i in 0..5 { + let _ = behavior_32b.operand_access(i); + } + + let mut opcount_32b = 0; + use yaxpeax_x86::protected_mode::{Opcode as b32Opcode, Operand as b32Operand}; + + if let Ok(ops) = behavior_32b.all_operands() { + // eprintln!("checking instr {}", inst_32b); + for (op, acc) in ops.iter() { + match op { + b32Operand::ImmediateI8 { .. } | + b32Operand::ImmediateU8 { .. } | + b32Operand::ImmediateI16 { .. } | + b32Operand::ImmediateU16 { .. } | + b32Operand::ImmediateI32 { .. } | + b32Operand::ImmediateU32 { .. } => { + // immediates are not reported as "accessed" below, as they are not really + // architectural state to be "accessed".. so skip them here to make the + // counters line up. + continue; + }, + _ => {} + } +// eprintln!("saw {:?}, {:?}", op, acc); + let mut accs; + if inst_32b.opcode() == b32Opcode::LEA && op.is_memory() { + // the access-visiting interface below does not report a memory access for lea + // because lea does not access memory. skip it to make the counters line up. + continue; + } + match op { + b32Operand::AbsoluteU16 { .. } | + b32Operand::AbsoluteU32 { .. } | + b32Operand::Register { .. } | + b32Operand::MemDeref { .. } | + b32Operand::Disp { .. } | + b32Operand::MemIndexScale { .. } | + b32Operand::MemIndexScaleDisp { .. } | + b32Operand::MemBaseIndexScale { .. } | + b32Operand::MemBaseIndexScaleDisp { .. } => { + accs = 1; + } + b32Operand::RegisterMaskMerge { mask, .. } | + b32Operand::RegisterMaskMergeSae { mask, .. } | + b32Operand::RegisterMaskMergeSaeNoround { mask, .. } | + b32Operand::MemDerefMasked { mask, .. } | + b32Operand::DispMasked { mask, .. } | + b32Operand::MemIndexScaleMasked { mask, .. } | + b32Operand::MemIndexScaleDispMasked { mask, .. } | + b32Operand::MemBaseIndexScaleMasked { mask, .. } | + b32Operand::MemBaseIndexScaleDispMasked { mask, .. } => { + accs = 1; + if mask.num() != 0 { + // the variants producing RegisterMaskMerge* are not sufficiently + // careful.. + accs += 1; + } + } + _ => { + // immediates don't produce a register/memory read/write + accs = 0; + } + } + // read-write accesses are reported as two accesses in the visitor interface below. + // count such cases twice here to make the counters line up. + if acc.is_read() { + opcount_32b += accs; + } + if acc.is_write() { + opcount_32b += accs; + } + } + } + + struct AccessCounter<'ctr> { + counter: &'ctr mut usize, + } + + impl<'ctr> yaxpeax_x86::protected_mode::behavior::AccessVisitor for AccessCounter<'ctr> { + fn register_read(&mut self, _reg: yaxpeax_x86::protected_mode::RegSpec) { +// eprintln!("saw read {:?}", _reg); + *self.counter += 1; + } + fn register_write(&mut self, _reg: yaxpeax_x86::protected_mode::RegSpec) { +// eprintln!("saw write {:?}", _reg); + *self.counter += 1; + } + fn get_register(&mut self, _reg: yaxpeax_x86::protected_mode::RegSpec) -> Option<u32> { None } + fn memory_read(&mut self, _address: Option<u32>, _size: u32) { +// eprintln!("saw read {:?}", _size); + *self.counter += 1; + } + fn memory_write(&mut self, _address: Option<u32>, _size: u32) { +// eprintln!("saw write {:?}", _size); + *self.counter += 1; + } + } + + let mut acc_seen_32b = 0; + let mut visitor = AccessCounter { + counter: &mut acc_seen_32b, + }; + + let visit_res = behavior_32b.visit_accesses(&mut visitor); + if visit_res.is_ok() { + assert_eq!(opcount_32b, acc_seen_32b); + } + } + + if let Ok(inst_16b) = x86_16_decoder.decode_slice(data) { + /* + eprint!("x86_16: "); + for b in data { + eprint!("{:02x}", b); + } + eprintln!(": {}", inst_16b); + */ + let behavior_16b = inst_16b.behavior(); + let _ = behavior_16b.privilege_level(); + let _ = behavior_16b.exceptions(); +// let _ = behavior_16b.implicit_oplist(); + for i in 0..5 { + let _ = behavior_16b.operand_access(i); + } + + let mut opcount_16b = 0; + use yaxpeax_x86::real_mode::{Opcode as b16Opcode, Operand as b16Operand}; + + if let Ok(ops) = behavior_16b.all_operands() { + // eprintln!("checking instr {}", inst_16b); + for (op, acc) in ops.iter() { + match op { + b16Operand::ImmediateI8 { .. } | + b16Operand::ImmediateU8 { .. } | + b16Operand::ImmediateI16 { .. } | + b16Operand::ImmediateU16 { .. } | + b16Operand::ImmediateI32 { .. } | + b16Operand::ImmediateU32 { .. } => { + // immediates are not reported as "accessed" below, as they are not really + // architectural state to be "accessed".. so skip them here to make the + // counters line up. + continue; + }, + _ => {} + } +// eprintln!("saw {:?}, {:?}", op, acc); + let mut accs; + if inst_16b.opcode() == b16Opcode::LEA && op.is_memory() { + // the access-visiting interface below does not report a memory access for lea + // because lea does not access memory. skip it to make the counters line up. + continue; + } + match op { + b16Operand::AbsoluteU16 { .. } | + b16Operand::AbsoluteU32 { .. } | + b16Operand::Register { .. } | + b16Operand::MemDeref { .. } | + b16Operand::MemDisp { .. } | + b16Operand::MemIndexScale { .. } | + b16Operand::MemIndexScaleDisp { .. } | + b16Operand::MemBaseIndexScale { .. } | + b16Operand::MemBaseIndexScaleDisp { .. } => { + accs = 1; + } + b16Operand::RegisterMaskMerge { mask, .. } | + b16Operand::RegisterMaskMergeSae { mask, .. } | + b16Operand::RegisterMaskMergeSaeNoround { mask, .. } | + b16Operand::MemDerefMasked { mask, .. } | + b16Operand::MemDispMasked { mask, .. } | + b16Operand::MemIndexScaleMasked { mask, .. } | + b16Operand::MemIndexScaleDispMasked { mask, .. } | + b16Operand::MemBaseIndexScaleMasked { mask, .. } | + b16Operand::MemBaseIndexScaleDispMasked { mask, .. } => { + accs = 1; + if mask.num() != 0 { + // the variants producing RegisterMaskMerge* are not sufficiently + // careful.. + accs += 1; + } + } + _ => { + // immediates don't produce a register/memory read/write + accs = 0; + } + } + // read-write accesses are reported as two accesses in the visitor interface below. + // count such cases twice here to make the counters line up. + if acc.is_read() { + opcount_16b += accs; + } + if acc.is_write() { + opcount_16b += accs; + } + } + } + + struct AccessCounter<'ctr> { + counter: &'ctr mut usize, + } + + impl<'ctr> yaxpeax_x86::real_mode::behavior::AccessVisitor for AccessCounter<'ctr> { + fn register_read(&mut self, _reg: yaxpeax_x86::real_mode::RegSpec) { +// eprintln!("saw read {:?}", _reg); + *self.counter += 1; + } + fn register_write(&mut self, _reg: yaxpeax_x86::real_mode::RegSpec) { +// eprintln!("saw write {:?}", _reg); + *self.counter += 1; + } + fn get_register(&mut self, _reg: yaxpeax_x86::real_mode::RegSpec) -> Option<u16> { None } + fn memory_read(&mut self, _address: Option<u16>, _size: u32) { +// eprintln!("saw read {:?}", _size); + *self.counter += 1; + } + fn memory_write(&mut self, _address: Option<u16>, _size: u32) { +// eprintln!("saw write {:?}", _size); + *self.counter += 1; + } + } + + let mut acc_seen_16b = 0; + let mut visitor = AccessCounter { + counter: &mut acc_seen_16b, + }; + + let visit_res = behavior_16b.visit_accesses(&mut visitor); + if visit_res.is_ok() { + assert_eq!(opcount_16b, acc_seen_16b); + } + } }); |
