1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate yaxpeax_x86;
fuzz_target!(|data: &[u8]| {
if data.len() > 15 {
return;
}
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) {
/*
for b in data {
eprint!("{:02x}", b);
}
eprintln!(": {}", inst_64b);
*/
let behavior_64b = inst_64b.behavior();
let _ = behavior_64b.privilege_level();
let _ = behavior_64b.exceptions();
let _ = behavior_64b.implicit_oplist();
for i in 0..5 {
let _ = behavior_64b.operand_access(i);
}
let mut opcount_64b = 0;
use yaxpeax_x86::long_mode::{Opcode as b64Opcode, Operand as b64Operand};
if let Ok(ops) = behavior_64b.all_operands() {
// eprintln!("checking instr {}", inst_64b);
for (op, acc) in ops.iter() {
match op {
b64Operand::ImmediateI8 { .. } |
b64Operand::ImmediateU8 { .. } |
b64Operand::ImmediateI16 { .. } |
b64Operand::ImmediateU16 { .. } |
b64Operand::ImmediateI32 { .. } |
b64Operand::ImmediateU32 { .. } |
b64Operand::ImmediateI64 { .. } => {
// 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 = 0;
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.
continue;
}
match op {
b64Operand::AbsoluteU32 { .. } |
b64Operand::AbsoluteU64 { .. } |
b64Operand::Register { .. } |
b64Operand::MemDeref { .. } |
b64Operand::Disp { .. } |
b64Operand::MemIndexScale { .. } |
b64Operand::MemIndexScaleDisp { .. } |
b64Operand::MemBaseIndexScale { .. } |
b64Operand::MemBaseIndexScaleDisp { .. } => {
accs = 1;
}
b64Operand::RegisterMaskMerge { mask, .. } |
b64Operand::RegisterMaskMergeSae { mask, .. } |
b64Operand::RegisterMaskMergeSaeNoround { mask, .. } |
b64Operand::MemDerefMasked { mask, .. } |
b64Operand::DispMasked { mask, .. } |
b64Operand::MemIndexScaleMasked { mask, .. } |
b64Operand::MemIndexScaleDispMasked { mask, .. } |
b64Operand::MemBaseIndexScaleMasked { mask, .. } |
b64Operand::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_64b += accs;
}
if acc.is_write() {
opcount_64b += accs;
}
}
}
struct AccessCounter<'ctr> {
counter: &'ctr mut usize,
}
impl<'ctr> yaxpeax_x86::long_mode::behavior::AccessVisitor for AccessCounter<'ctr> {
fn register_read(&mut self, _reg: yaxpeax_x86::long_mode::RegSpec) {
// eprintln!("saw read {:?}", _reg);
*self.counter += 1;
}
fn register_write(&mut self, _reg: yaxpeax_x86::long_mode::RegSpec) {
// eprintln!("saw write {:?}", _reg);
*self.counter += 1;
}
fn get_register(&mut self, _reg: yaxpeax_x86::long_mode::RegSpec) -> Option<u64> { None }
fn memory_read(&mut self, _address: Option<u64>, _size: u32) {
// eprintln!("saw read {:?}", _size);
*self.counter += 1;
}
fn memory_write(&mut self, _address: Option<u64>, _size: u32) {
// eprintln!("saw write {:?}", _size);
*self.counter += 1;
}
}
let mut acc_seen_64b = 0;
let mut visitor = AccessCounter {
counter: &mut acc_seen_64b,
};
let visit_res = behavior_64b.visit_accesses(&mut visitor);
if visit_res.is_ok() {
assert_eq!(opcount_64b, acc_seen_64b);
}
}
});
|