1use std::{ffi::CStr, mem::size_of, slice::from_raw_parts};
7
8use super::ArchitectureOperations;
9use crate::{
10 tracer::{CmpExpr, CmpType, CmpValue, TraceEntry},
11 traits::TracerDisassembler,
12 CLASS_NAME,
13};
14use anyhow::{anyhow, bail, Error, Result};
15use libafl::prelude::CmpValues;
16use raw_cstr::AsRawCstr;
17use simics::{
18 api::{
19 get_interface, get_object, read_phys_memory, sys::instruction_handle_t, Access, ConfObject,
20 CpuInstructionQueryInterface, CpuInstrumentationSubscribeInterface, CycleInterface,
21 IntRegisterInterface, ProcessorInfoV2Interface,
22 },
23 trace,
24};
25use yaxpeax_x86::protected_mode::{ConditionCode, InstDecoder, Instruction, Opcode, Operand};
26
27pub(crate) struct X86ArchitectureOperations {
28 cpu: *mut ConfObject,
29 disassembler: Disassembler,
30 int_register: IntRegisterInterface,
31 processor_info_v2: ProcessorInfoV2Interface,
32 cpu_instruction_query: CpuInstructionQueryInterface,
33 cpu_instrumentation_subscribe: CpuInstrumentationSubscribeInterface,
34 cycle: CycleInterface,
35}
36
37impl ArchitectureOperations for X86ArchitectureOperations {
38 const INDEX_SELECTOR_REGISTER: &'static str = "edi";
39 const ARGUMENT_REGISTER_0: &'static str = "esi";
40 const ARGUMENT_REGISTER_1: &'static str = "edx";
41 const ARGUMENT_REGISTER_2: &'static str = "ecx";
42 const POINTER_WIDTH_OVERRIDE: Option<i32> = Some(4);
43
44 fn new(cpu: *mut ConfObject) -> Result<Self> {
45 let mut processor_info_v2: ProcessorInfoV2Interface = get_interface(cpu)?;
46
47 let arch = unsafe { CStr::from_ptr(processor_info_v2.architecture()?) }
48 .to_str()?
49 .to_string();
50
51 trace!(
52 get_object(CLASS_NAME)?,
53 "Checking whether cpu with architecutre {arch} is i386"
54 );
55
56 if arch == "x86-64" {
57 let mut int_register: IntRegisterInterface = get_interface(cpu)?;
60 let regs: Vec<u32> = int_register.all_registers()?.try_into()?;
61 let reg_names: Vec<String> = regs
62 .iter()
63 .map(|r| {
64 int_register
65 .get_name(*r as i32)
66 .map_err(|e| anyhow!("Failed to get register name: {e}"))
67 .and_then(|n| {
68 unsafe { CStr::from_ptr(n) }
69 .to_str()
70 .map(|s| s.to_string())
71 .map_err(|e| anyhow!("Failed to convert string: {e}"))
72 })
73 })
74 .collect::<Result<Vec<_>>>()?;
75
76 if reg_names.iter().any(|n| {
77 [
78 "rax", "rbx", "rcx", "rdx", "rdi", "rsi", "rip", "rsp", "rbp", "r8", "r9",
79 "r10", "r11", "r12", "r14", "r15",
80 ]
81 .contains(&n.to_ascii_lowercase().as_str())
82 }) {
83 bail!("Architecture is x86-64")
84 } else if reg_names.iter().all(|n| {
85 ![
86 "rax", "rbx", "rcx", "rdx", "rdi", "rsi", "rip", "rsp", "rbp", "r8", "r9",
87 "r10", "r11", "r12", "r14", "r15",
88 ]
89 .contains(&n.to_ascii_lowercase().as_str())
90 }) {
91 trace!(
92 get_object(CLASS_NAME)?,
93 "Architecture name is x86-64, but no 'r' registers found. Assuming i386"
94 );
95 Ok(Self {
96 cpu,
97 disassembler: Disassembler::new(),
98 int_register,
99 processor_info_v2,
100 cpu_instruction_query: get_interface(cpu)?,
101 cpu_instrumentation_subscribe: get_interface(cpu)?,
102 cycle: get_interface(cpu)?,
103 })
104 } else {
105 unreachable!("Register set must either contain a 64-bit register or no registers may be 64-bit");
106 }
107 } else if ["i386", "i486", "i586", "i686", "x86", "ia-32"]
108 .contains(&arch.to_ascii_lowercase().as_str())
109 {
110 trace!(get_object(CLASS_NAME)?, "Architecture is i386");
112 Ok(Self {
113 cpu,
114 disassembler: Disassembler::new(),
115 int_register: get_interface(cpu)?,
116 processor_info_v2,
117 cpu_instruction_query: get_interface(cpu)?,
118 cpu_instrumentation_subscribe: get_interface(cpu)?,
119 cycle: get_interface(cpu)?,
120 })
121 } else {
122 bail!("Unsupported architecture {arch}");
123 }
124 }
125
126 fn new_unchecked(cpu: *mut ConfObject) -> Result<Self>
127 where
128 Self: Sized,
129 {
130 Ok(Self {
131 cpu,
132 disassembler: Disassembler::new(),
133 int_register: get_interface(cpu)?,
134 processor_info_v2: get_interface(cpu)?,
135 cpu_instruction_query: get_interface(cpu)?,
136 cpu_instrumentation_subscribe: get_interface(cpu)?,
137 cycle: get_interface(cpu)?,
138 })
139 }
140
141 fn cpu(&self) -> *mut ConfObject {
142 self.cpu
143 }
144
145 fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
146 &mut self.disassembler
147 }
148
149 fn int_register(&mut self) -> &mut IntRegisterInterface {
150 &mut self.int_register
151 }
152
153 fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
154 &mut self.processor_info_v2
155 }
156
157 fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
158 &mut self.cpu_instruction_query
159 }
160
161 fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
162 &mut self.cpu_instrumentation_subscribe
163 }
164
165 fn cycle(&mut self) -> &mut CycleInterface {
166 &mut self.cycle
167 }
168
169 fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
170 let instruction_bytes = self
171 .cpu_instruction_query
172 .get_instruction_bytes(instruction_query)?;
173 self.disassembler.disassemble(unsafe {
174 from_raw_parts(instruction_bytes.data, instruction_bytes.size)
175 })?;
176 if self.disassembler.last_was_call()
177 || self.disassembler.last_was_control_flow()
178 || self.disassembler.last_was_ret()
179 {
180 Ok(TraceEntry::builder()
181 .edge(self.processor_info_v2.get_program_counter()?)
182 .build())
183 } else {
184 Ok(TraceEntry::default())
185 }
186 }
187
188 fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
189 let instruction_bytes = self
190 .cpu_instruction_query
191 .get_instruction_bytes(instruction_query)?;
192 self.disassembler.disassemble(unsafe {
193 from_raw_parts(instruction_bytes.data, instruction_bytes.size)
194 })?;
195 if self.disassembler.last_was_cmp() {
196 let pc = self.processor_info_v2.get_program_counter()?;
197 let mut cmp_values = Vec::new();
198
199 for expr in self.disassembler.cmp() {
200 if let Ok(value) = self.simplify(&expr) {
201 cmp_values.push(value);
202 }
203 }
204
205 let cmp_value = if let (Some(l), Some(r)) = (cmp_values.first(), cmp_values.get(1)) {
206 match (l, r) {
207 (CmpValue::U8(l), CmpValue::U8(r)) => Some(CmpValues::U8((*l, *r))),
208 (CmpValue::I8(l), CmpValue::I8(r)) => Some(CmpValues::U8((
209 u8::from_le_bytes(l.to_le_bytes()),
210 u8::from_le_bytes(r.to_le_bytes()),
211 ))),
212 (CmpValue::U16(l), CmpValue::U16(r)) => Some(CmpValues::U16((*l, *r))),
213 (CmpValue::I16(l), CmpValue::I16(r)) => Some(CmpValues::U16((
214 u16::from_le_bytes(l.to_le_bytes()),
215 u16::from_le_bytes(r.to_le_bytes()),
216 ))),
217 (CmpValue::U32(l), CmpValue::U32(r)) => Some(CmpValues::U32((*l, *r))),
218 (CmpValue::I32(l), CmpValue::I32(r)) => Some(CmpValues::U32((
219 u32::from_le_bytes(l.to_le_bytes()),
220 u32::from_le_bytes(r.to_le_bytes()),
221 ))),
222 (CmpValue::U64(l), CmpValue::U64(r)) => Some(CmpValues::U64((*l, *r))),
223 (CmpValue::I64(l), CmpValue::I64(r)) => Some(CmpValues::U64((
224 u64::from_le_bytes(l.to_le_bytes()),
225 u64::from_le_bytes(r.to_le_bytes()),
226 ))),
227 (CmpValue::Expr(_), CmpValue::Expr(_)) => None,
228 _ => None,
229 }
230 } else {
231 None
232 };
233
234 Ok(TraceEntry::builder()
235 .cmp((
236 pc,
237 self.disassembler.cmp_type(),
238 cmp_value.ok_or_else(|| anyhow!("No cmp value available"))?,
239 ))
240 .build())
241 } else {
242 Ok(TraceEntry::default())
243 }
244 }
245}
246impl X86ArchitectureOperations {
247 fn simplify(&mut self, expr: &CmpExpr) -> Result<CmpValue> {
248 match expr {
249 CmpExpr::Deref((expr, width)) => {
250 let v = self.simplify(expr)?;
251
252 match v {
253 CmpValue::U64(a) => {
254 let address = self
255 .processor_info_v2
256 .logical_to_physical(a, Access::Sim_Access_Read)?;
257 let casted = match width {
258 Some(1) => CmpValue::U8(
259 read_phys_memory(self.cpu, address.address, size_of::<u8>() as i32)
260 .map_err(|e| {
261 anyhow!("Error reading bytes from {:#x}: {}", a, e)
262 })?
263 .to_le_bytes()[0],
264 ),
265 Some(2) => CmpValue::U16(u16::from_le_bytes(
266 read_phys_memory(
267 self.cpu,
268 address.address,
269 size_of::<u16>() as i32,
270 )
271 .map_err(|e| anyhow!("Error reading bytes from {:#x}: {}", a, e))?
272 .to_le_bytes()[0..size_of::<u16>()]
273 .try_into()?,
274 )),
275 Some(4) => CmpValue::U32(u32::from_le_bytes(
276 read_phys_memory(
277 self.cpu,
278 address.address,
279 size_of::<u32>() as i32,
280 )
281 .map_err(|e| anyhow!("Error reading bytes from {:#x}: {}", a, e))?
282 .to_le_bytes()[0..size_of::<u32>()]
283 .try_into()?,
284 )),
285 Some(8) => CmpValue::U64(u64::from_le_bytes(
286 read_phys_memory(
287 self.cpu,
288 address.address,
289 size_of::<u64>() as i32,
290 )
291 .map_err(|e| anyhow!("Error reading bytes from {:#x}: {}", a, e))?
292 .to_le_bytes(),
293 )),
294 _ => bail!("Can't cast to non-power-of-2 width {:?}", width),
295 };
296 Ok(casted)
297 }
298 _ => bail!("Can't dereference non-address"),
299 }
300 }
301 CmpExpr::Reg((name, width)) => {
302 let reg_number = self.int_register.get_number(name.as_raw_cstr()?)?;
303 let value = self.int_register.read(reg_number).map_err(|e| {
304 anyhow!("Couldn't read register value for register {}: {}", name, e)
305 })?;
306
307 let casted = match width {
308 1 => CmpValue::U8(value.to_le_bytes()[0]),
309 2 => CmpValue::U16(u16::from_le_bytes(
310 value.to_le_bytes()[..size_of::<u16>()]
311 .try_into()
312 .map_err(|e| anyhow!("Error converting to u32 bytes: {}", e))?,
313 )),
314 4 => CmpValue::U32(u32::from_le_bytes(
315 value.to_le_bytes()[..size_of::<u32>()]
316 .try_into()
317 .map_err(|e| anyhow!("Error converting to u32 bytes: {}", e))?,
318 )),
319 8 => CmpValue::U64(u64::from_le_bytes(value.to_le_bytes())),
320 _ => bail!("Can't cast to non-power-of-2 width {}", width),
321 };
322 Ok(casted)
323 }
324 CmpExpr::Mul((l, r)) => {
325 let lv = self.simplify(l)?;
326 let rv = self.simplify(r)?;
327
328 match (lv, rv) {
329 (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_mul(ru))),
330 (CmpValue::U8(lu), CmpValue::I8(ru)) => {
331 Ok(CmpValue::U8((lu as i32).wrapping_mul(ru as i32) as u8))
332 }
333 (CmpValue::U8(lu), CmpValue::U16(ru)) => {
334 Ok(CmpValue::U8((lu as u16).wrapping_mul(ru) as u8))
335 }
336 (CmpValue::U8(lu), CmpValue::I16(ru)) => {
337 Ok(CmpValue::U8((lu as i32).wrapping_mul(ru as i32) as u8))
338 }
339 (CmpValue::U8(lu), CmpValue::U32(ru)) => {
340 Ok(CmpValue::U8((lu as u32).wrapping_mul(ru) as u8))
341 }
342 (CmpValue::U8(lu), CmpValue::I32(ru)) => {
343 Ok(CmpValue::U8((lu as i32).wrapping_mul(ru) as u8))
344 }
345 (CmpValue::U8(lu), CmpValue::U64(ru)) => {
346 Ok(CmpValue::U8((lu as u64).wrapping_mul(ru) as u8))
347 }
348 (CmpValue::U8(lu), CmpValue::I64(ru)) => {
349 Ok(CmpValue::U8((lu as i64).wrapping_mul(ru) as u8))
350 }
351 (CmpValue::I8(lu), CmpValue::U8(ru)) => {
352 Ok(CmpValue::I8((lu as i16).wrapping_mul(ru as i16) as i8))
353 }
354 (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_mul(ru))),
355 (CmpValue::I8(lu), CmpValue::U16(ru)) => {
356 Ok(CmpValue::I8((lu as i32).wrapping_mul(ru as i32) as i8))
357 }
358 (CmpValue::I8(lu), CmpValue::I16(ru)) => {
359 Ok(CmpValue::I8((lu as i16).wrapping_mul(ru) as i8))
360 }
361 (CmpValue::I8(lu), CmpValue::U32(ru)) => {
362 Ok(CmpValue::I8((lu as i64).wrapping_mul(ru as i64) as i8))
363 }
364 (CmpValue::I8(lu), CmpValue::I32(ru)) => {
365 Ok(CmpValue::I8((lu as i64).wrapping_mul(ru as i64) as i8))
366 }
367 (CmpValue::I8(lu), CmpValue::U64(ru)) => {
368 Ok(CmpValue::I8((lu as i64).wrapping_mul(ru as i64) as i8))
369 }
370 (CmpValue::I8(lu), CmpValue::I64(ru)) => {
371 Ok(CmpValue::I8((lu as i64).wrapping_mul(ru) as i8))
372 }
373 (CmpValue::U16(lu), CmpValue::U8(ru)) => {
374 Ok(CmpValue::U16(lu.wrapping_mul(ru as u16)))
375 }
376 (CmpValue::U16(lu), CmpValue::I8(ru)) => {
377 Ok(CmpValue::U16((lu as i32).wrapping_mul(ru as i32) as u16))
378 }
379 (CmpValue::U16(lu), CmpValue::U16(ru)) => {
380 Ok(CmpValue::U16(lu.wrapping_mul(ru)))
381 }
382 (CmpValue::U16(lu), CmpValue::I16(ru)) => {
383 Ok(CmpValue::U16((lu as i32).wrapping_mul(ru as i32) as u16))
384 }
385 (CmpValue::U16(lu), CmpValue::U32(ru)) => {
386 Ok(CmpValue::U16((lu as u32).wrapping_mul(ru) as u16))
387 }
388 (CmpValue::U16(lu), CmpValue::I32(ru)) => {
389 Ok(CmpValue::U16((lu as i32).wrapping_mul(ru) as u16))
390 }
391 (CmpValue::U16(lu), CmpValue::U64(ru)) => {
392 Ok(CmpValue::U16((lu as u64).wrapping_mul(ru) as u16))
393 }
394 (CmpValue::U16(lu), CmpValue::I64(ru)) => {
395 Ok(CmpValue::U16((lu as i64).wrapping_mul(ru) as u16))
396 }
397 (CmpValue::I16(lu), CmpValue::U8(ru)) => {
398 Ok(CmpValue::I16(lu.wrapping_mul(ru as i16)))
399 }
400 (CmpValue::I16(lu), CmpValue::I8(ru)) => {
401 Ok(CmpValue::I16(lu.wrapping_mul(ru as i16)))
402 }
403 (CmpValue::I16(lu), CmpValue::U16(ru)) => {
404 Ok(CmpValue::I16((lu as i32).wrapping_mul(ru as i32) as i16))
405 }
406 (CmpValue::I16(lu), CmpValue::I16(ru)) => {
407 Ok(CmpValue::I16(lu.wrapping_mul(ru)))
408 }
409 (CmpValue::I16(lu), CmpValue::U32(ru)) => {
410 Ok(CmpValue::I16((lu as i64).wrapping_mul(ru as i64) as i16))
411 }
412 (CmpValue::I16(lu), CmpValue::I32(ru)) => {
413 Ok(CmpValue::I16((lu as i32).wrapping_mul(ru) as i16))
414 }
415 (CmpValue::I16(lu), CmpValue::U64(ru)) => {
416 Ok(CmpValue::I16((lu as i64).wrapping_mul(ru as i64) as i16))
417 }
418 (CmpValue::I16(lu), CmpValue::I64(ru)) => {
419 Ok(CmpValue::I16((lu as i64).wrapping_mul(ru) as i16))
420 }
421 (CmpValue::U32(lu), CmpValue::U8(ru)) => {
422 Ok(CmpValue::U32(lu.wrapping_mul(ru as u32)))
423 }
424 (CmpValue::U32(lu), CmpValue::I8(ru)) => {
425 Ok(CmpValue::U32((lu as i64).wrapping_mul(ru as i64) as u32))
426 }
427 (CmpValue::U32(lu), CmpValue::U16(ru)) => {
428 Ok(CmpValue::U32(lu.wrapping_mul(ru as u32)))
429 }
430 (CmpValue::U32(lu), CmpValue::I16(ru)) => {
431 Ok(CmpValue::U32((lu as i64).wrapping_mul(ru as i64) as u32))
432 }
433 (CmpValue::U32(lu), CmpValue::U32(ru)) => {
434 Ok(CmpValue::U32(lu.wrapping_mul(ru)))
435 }
436 (CmpValue::U32(lu), CmpValue::I32(ru)) => {
437 Ok(CmpValue::U32((lu as i64).wrapping_mul(ru as i64) as u32))
438 }
439 (CmpValue::U32(lu), CmpValue::U64(ru)) => {
440 Ok(CmpValue::U32((lu as u64).wrapping_mul(ru) as u32))
441 }
442 (CmpValue::U32(lu), CmpValue::I64(ru)) => {
443 Ok(CmpValue::U32((lu as i64).wrapping_mul(ru) as u32))
444 }
445 (CmpValue::I32(lu), CmpValue::U8(ru)) => {
446 Ok(CmpValue::I32(lu.wrapping_mul(ru as i32)))
447 }
448 (CmpValue::I32(lu), CmpValue::I8(ru)) => {
449 Ok(CmpValue::I32(lu.wrapping_mul(ru as i32)))
450 }
451 (CmpValue::I32(lu), CmpValue::U16(ru)) => {
452 Ok(CmpValue::I32(lu.wrapping_mul(ru as i32)))
453 }
454 (CmpValue::I32(lu), CmpValue::I16(ru)) => {
455 Ok(CmpValue::I32(lu.wrapping_mul(ru as i32)))
456 }
457 (CmpValue::I32(lu), CmpValue::U32(ru)) => {
458 Ok(CmpValue::I32((lu as i64).wrapping_mul(ru as i64) as i32))
459 }
460 (CmpValue::I32(lu), CmpValue::I32(ru)) => {
461 Ok(CmpValue::I32(lu.wrapping_mul(ru)))
462 }
463 (CmpValue::I32(lu), CmpValue::U64(ru)) => {
464 Ok(CmpValue::I32((lu as i64).wrapping_mul(ru as i64) as i32))
465 }
466 (CmpValue::I32(lu), CmpValue::I64(ru)) => {
467 Ok(CmpValue::I32((lu as i64).wrapping_mul(ru) as i32))
468 }
469 (CmpValue::U64(lu), CmpValue::U8(ru)) => {
470 Ok(CmpValue::U64(lu.wrapping_mul(ru as u64)))
471 }
472 (CmpValue::U64(lu), CmpValue::I8(ru)) => {
473 Ok(CmpValue::U64((lu as i64).wrapping_mul(ru as i64) as u64))
474 }
475 (CmpValue::U64(lu), CmpValue::U16(ru)) => {
476 Ok(CmpValue::U64(lu.wrapping_mul(ru as u64)))
477 }
478 (CmpValue::U64(lu), CmpValue::I16(ru)) => {
479 Ok(CmpValue::U64((lu as i64).wrapping_mul(ru as i64) as u64))
480 }
481 (CmpValue::U64(lu), CmpValue::U32(ru)) => {
482 Ok(CmpValue::U64(lu.wrapping_mul(ru as u64)))
483 }
484 (CmpValue::U64(lu), CmpValue::I32(ru)) => {
485 Ok(CmpValue::U64((lu as i64).wrapping_mul(ru as i64) as u64))
486 }
487 (CmpValue::U64(lu), CmpValue::U64(ru)) => {
488 Ok(CmpValue::U64(lu.wrapping_mul(ru)))
489 }
490 (CmpValue::U64(lu), CmpValue::I64(ru)) => {
491 Ok(CmpValue::U64((lu as i64).wrapping_mul(ru) as u64))
492 }
493 (CmpValue::I64(lu), CmpValue::U8(ru)) => {
494 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
495 }
496 (CmpValue::I64(lu), CmpValue::I8(ru)) => {
497 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
498 }
499 (CmpValue::I64(lu), CmpValue::U16(ru)) => {
500 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
501 }
502 (CmpValue::I64(lu), CmpValue::I16(ru)) => {
503 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
504 }
505 (CmpValue::I64(lu), CmpValue::U32(ru)) => {
506 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
507 }
508 (CmpValue::I64(lu), CmpValue::I32(ru)) => {
509 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
510 }
511 (CmpValue::I64(lu), CmpValue::U64(ru)) => {
512 Ok(CmpValue::I64(lu.wrapping_mul(ru as i64)))
513 }
514 (CmpValue::I64(lu), CmpValue::I64(ru)) => {
515 Ok(CmpValue::I64(lu.wrapping_mul(ru)))
516 }
517 _ => bail!("Cannot multiply non-integral types"),
518 }
519 }
520 CmpExpr::Add((l, r)) => {
521 let lv = self.simplify(l)?;
522 let rv = self.simplify(r)?;
523
524 match (lv, rv) {
525 (CmpValue::U8(lu), CmpValue::U8(ru)) => Ok(CmpValue::U8(lu.wrapping_add(ru))),
526 (CmpValue::U8(lu), CmpValue::I8(ru)) => {
527 Ok(CmpValue::U8(lu.wrapping_add_signed(ru)))
528 }
529 (CmpValue::U8(lu), CmpValue::U16(ru)) => {
530 Ok(CmpValue::U8((lu as u16).wrapping_add(ru) as u8))
531 }
532 (CmpValue::U8(lu), CmpValue::I16(ru)) => {
533 Ok(CmpValue::U8((lu as u16).wrapping_add_signed(ru) as u8))
534 }
535 (CmpValue::U8(lu), CmpValue::U32(ru)) => {
536 Ok(CmpValue::U8((lu as u32).wrapping_add(ru) as u8))
537 }
538 (CmpValue::U8(lu), CmpValue::I32(ru)) => {
539 Ok(CmpValue::U8((lu as u32).wrapping_add_signed(ru) as u8))
540 }
541 (CmpValue::U8(lu), CmpValue::U64(ru)) => {
542 Ok(CmpValue::U8((lu as u64).wrapping_add(ru) as u8))
543 }
544 (CmpValue::U8(lu), CmpValue::I64(ru)) => {
545 Ok(CmpValue::U8((lu as u64).wrapping_add_signed(ru) as u8))
546 }
547 (CmpValue::I8(lu), CmpValue::U8(ru)) => {
548 Ok(CmpValue::I8(lu.wrapping_add_unsigned(ru)))
549 }
550 (CmpValue::I8(lu), CmpValue::I8(ru)) => Ok(CmpValue::I8(lu.wrapping_add(ru))),
551 (CmpValue::I8(lu), CmpValue::U16(ru)) => {
552 Ok(CmpValue::I8((lu as i16).wrapping_add_unsigned(ru) as i8))
553 }
554 (CmpValue::I8(lu), CmpValue::I16(ru)) => {
555 Ok(CmpValue::I8((lu as i16).wrapping_add(ru) as i8))
556 }
557 (CmpValue::I8(lu), CmpValue::U32(ru)) => {
558 Ok(CmpValue::I8((lu as i32).wrapping_add_unsigned(ru) as i8))
559 }
560 (CmpValue::I8(lu), CmpValue::I32(ru)) => {
561 Ok(CmpValue::I8((lu as i32).wrapping_add(ru) as i8))
562 }
563 (CmpValue::I8(lu), CmpValue::U64(ru)) => {
564 Ok(CmpValue::I8((lu as i64).wrapping_add_unsigned(ru) as i8))
565 }
566 (CmpValue::I8(lu), CmpValue::I64(ru)) => {
567 Ok(CmpValue::I8((lu as i64).wrapping_add(ru) as i8))
568 }
569 (CmpValue::U16(lu), CmpValue::U8(ru)) => {
570 Ok(CmpValue::U16(lu.wrapping_add(ru as u16)))
571 }
572 (CmpValue::U16(lu), CmpValue::I8(ru)) => {
573 Ok(CmpValue::U16(lu.wrapping_add_signed(ru as i16)))
574 }
575 (CmpValue::U16(lu), CmpValue::U16(ru)) => {
576 Ok(CmpValue::U16(lu.wrapping_add(ru)))
577 }
578 (CmpValue::U16(lu), CmpValue::I16(ru)) => {
579 Ok(CmpValue::U16(lu.wrapping_add_signed(ru)))
580 }
581 (CmpValue::U16(lu), CmpValue::U32(ru)) => {
582 Ok(CmpValue::U16((lu as u32).wrapping_add(ru) as u16))
583 }
584 (CmpValue::U16(lu), CmpValue::I32(ru)) => {
585 Ok(CmpValue::U16((lu as u32).wrapping_add_signed(ru) as u16))
586 }
587 (CmpValue::U16(lu), CmpValue::U64(ru)) => {
588 Ok(CmpValue::U16((lu as u64).wrapping_add(ru) as u16))
589 }
590 (CmpValue::U16(lu), CmpValue::I64(ru)) => {
591 Ok(CmpValue::U16((lu as u64).wrapping_add_signed(ru) as u16))
592 }
593 (CmpValue::I16(lu), CmpValue::U8(ru)) => {
594 Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru as u16)))
595 }
596 (CmpValue::I16(lu), CmpValue::I8(ru)) => {
597 Ok(CmpValue::I16(lu.wrapping_add(ru as i16)))
598 }
599 (CmpValue::I16(lu), CmpValue::U16(ru)) => {
600 Ok(CmpValue::I16(lu.wrapping_add_unsigned(ru)))
601 }
602 (CmpValue::I16(lu), CmpValue::I16(ru)) => {
603 Ok(CmpValue::I16(lu.wrapping_add(ru)))
604 }
605 (CmpValue::I16(lu), CmpValue::U32(ru)) => {
606 Ok(CmpValue::I16((lu as i32).wrapping_add_unsigned(ru) as i16))
607 }
608 (CmpValue::I16(lu), CmpValue::I32(ru)) => {
609 Ok(CmpValue::I16((lu as i32).wrapping_add(ru) as i16))
610 }
611 (CmpValue::I16(lu), CmpValue::U64(ru)) => {
612 Ok(CmpValue::I16((lu as i64).wrapping_add_unsigned(ru) as i16))
613 }
614 (CmpValue::I16(lu), CmpValue::I64(ru)) => {
615 Ok(CmpValue::I16((lu as i64).wrapping_add(ru) as i16))
616 }
617 (CmpValue::U32(lu), CmpValue::U8(ru)) => {
618 Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
619 }
620 (CmpValue::U32(lu), CmpValue::I8(ru)) => {
621 Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
622 }
623 (CmpValue::U32(lu), CmpValue::U16(ru)) => {
624 Ok(CmpValue::U32(lu.wrapping_add(ru as u32)))
625 }
626 (CmpValue::U32(lu), CmpValue::I16(ru)) => {
627 Ok(CmpValue::U32(lu.wrapping_add_signed(ru as i32)))
628 }
629 (CmpValue::U32(lu), CmpValue::U32(ru)) => {
630 Ok(CmpValue::U32(lu.wrapping_add(ru)))
631 }
632 (CmpValue::U32(lu), CmpValue::I32(ru)) => {
633 Ok(CmpValue::U32(lu.wrapping_add_signed(ru)))
634 }
635 (CmpValue::U32(lu), CmpValue::U64(ru)) => {
636 Ok(CmpValue::U32((lu as u64).wrapping_add(ru) as u32))
637 }
638 (CmpValue::U32(lu), CmpValue::I64(ru)) => {
639 Ok(CmpValue::U32((lu as u64).wrapping_add_signed(ru) as u32))
640 }
641 (CmpValue::I32(lu), CmpValue::U8(ru)) => {
642 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
643 }
644 (CmpValue::I32(lu), CmpValue::I8(ru)) => {
645 Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
646 }
647 (CmpValue::I32(lu), CmpValue::U16(ru)) => {
648 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru as u32)))
649 }
650 (CmpValue::I32(lu), CmpValue::I16(ru)) => {
651 Ok(CmpValue::I32(lu.wrapping_add(ru as i32)))
652 }
653 (CmpValue::I32(lu), CmpValue::U32(ru)) => {
654 Ok(CmpValue::I32(lu.wrapping_add_unsigned(ru)))
655 }
656 (CmpValue::I32(lu), CmpValue::I32(ru)) => {
657 Ok(CmpValue::I32(lu.wrapping_add(ru)))
658 }
659 (CmpValue::I32(lu), CmpValue::U64(ru)) => {
660 Ok(CmpValue::I32((lu as i64).wrapping_add_unsigned(ru) as i32))
661 }
662 (CmpValue::I32(lu), CmpValue::I64(ru)) => {
663 Ok(CmpValue::I32((lu as i64).wrapping_add(ru) as i32))
664 }
665 (CmpValue::U64(lu), CmpValue::U8(ru)) => {
666 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
667 }
668 (CmpValue::U64(lu), CmpValue::I8(ru)) => {
669 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
670 }
671 (CmpValue::U64(lu), CmpValue::U16(ru)) => {
672 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
673 }
674 (CmpValue::U64(lu), CmpValue::I16(ru)) => {
675 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
676 }
677 (CmpValue::U64(lu), CmpValue::U32(ru)) => {
678 Ok(CmpValue::U64(lu.wrapping_add(ru as u64)))
679 }
680 (CmpValue::U64(lu), CmpValue::I32(ru)) => {
681 Ok(CmpValue::U64(lu.wrapping_add_signed(ru as i64)))
682 }
683 (CmpValue::U64(lu), CmpValue::U64(ru)) => {
684 Ok(CmpValue::U64(lu.wrapping_add(ru)))
685 }
686 (CmpValue::U64(lu), CmpValue::I64(ru)) => {
687 Ok(CmpValue::U64(lu.wrapping_add_signed(ru)))
688 }
689 (CmpValue::I64(lu), CmpValue::U8(ru)) => {
690 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
691 }
692 (CmpValue::I64(lu), CmpValue::I8(ru)) => {
693 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
694 }
695 (CmpValue::I64(lu), CmpValue::U16(ru)) => {
696 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
697 }
698 (CmpValue::I64(lu), CmpValue::I16(ru)) => {
699 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
700 }
701 (CmpValue::I64(lu), CmpValue::U32(ru)) => {
702 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru as u64)))
703 }
704 (CmpValue::I64(lu), CmpValue::I32(ru)) => {
705 Ok(CmpValue::I64(lu.wrapping_add(ru as i64)))
706 }
707 (CmpValue::I64(lu), CmpValue::U64(ru)) => {
708 Ok(CmpValue::I64(lu.wrapping_add_unsigned(ru)))
709 }
710 (CmpValue::I64(lu), CmpValue::I64(ru)) => {
711 Ok(CmpValue::I64(lu.wrapping_add(ru)))
712 }
713 _ => bail!("Cannot multiply non-integral types"),
714 }
715 }
716 CmpExpr::U8(_)
717 | CmpExpr::I8(_)
718 | CmpExpr::U16(_)
719 | CmpExpr::I16(_)
720 | CmpExpr::U32(_)
721 | CmpExpr::I32(_)
722 | CmpExpr::U64(_)
723 | CmpExpr::I64(_) => Ok(CmpValue::try_from(expr)?),
724 CmpExpr::Addr(a) => {
725 let address = self
726 .processor_info_v2
727 .logical_to_physical(*a, Access::Sim_Access_Read)?;
728 let bytes: [u8; 8] =
729 read_phys_memory(self.cpu, address.address, size_of::<u64>() as i32)?
730 .to_le_bytes();
731 Ok(CmpValue::U64(u64::from_le_bytes(bytes)))
732 }
733 _ => {
734 bail!("Unsupported expression type");
736 }
737 }
738 }
739}
740
741pub(crate) struct Disassembler {
742 decoder: InstDecoder,
743 last: Option<Instruction>,
744}
745
746impl Disassembler {
747 pub fn new() -> Self {
748 Self {
749 decoder: InstDecoder::default(),
750 last: None,
751 }
752 }
753}
754
755impl Default for Disassembler {
756 fn default() -> Self {
757 Self::new()
758 }
759}
760
761impl TryFrom<(&Operand, Option<u8>)> for CmpExpr {
762 type Error = Error;
763
764 fn try_from(value: (&Operand, Option<u8>)) -> Result<Self> {
765 let width = value.1;
766 let value = value.0;
767
768 let expr = match value {
769 Operand::ImmediateI8 { imm } => CmpExpr::I8(*imm),
770 Operand::ImmediateU8 { imm } => CmpExpr::U8(*imm),
771 Operand::ImmediateI16 { imm } => CmpExpr::I16(*imm),
772 Operand::ImmediateU16 { imm } => CmpExpr::U16(*imm),
773 Operand::ImmediateI32 { imm } => CmpExpr::I32(*imm),
774 Operand::ImmediateU32 { imm } => CmpExpr::U32(*imm),
775 Operand::Register { reg } => CmpExpr::Reg((reg.name().to_string(), reg.width())),
776 Operand::AbsoluteU32 { addr } => CmpExpr::Addr(*addr as u64),
777 Operand::MemDeref { base } => CmpExpr::Deref((
778 Box::new(CmpExpr::Reg((base.name().to_string(), base.width()))),
779 width,
780 )),
781 Operand::Disp { base, disp } => CmpExpr::Deref((
782 Box::new(CmpExpr::Add((
783 Box::new(CmpExpr::Reg((base.name().to_string(), base.width()))),
784 Box::new(CmpExpr::I32(*disp)),
785 ))),
786 width,
787 )),
788 Operand::MemIndexScale { index, scale } => CmpExpr::Deref((
789 Box::new(CmpExpr::Mul((
790 Box::new(CmpExpr::Reg((index.name().to_string(), index.width()))),
791 Box::new(CmpExpr::U8(*scale)),
792 ))),
793 width,
794 )),
795 Operand::MemIndexScaleDisp { index, scale, disp } => CmpExpr::Deref((
796 Box::new(CmpExpr::Add((
797 Box::new(CmpExpr::Mul((
798 Box::new(CmpExpr::Reg((index.name().to_string(), index.width()))),
799 Box::new(CmpExpr::U8(*scale)),
800 ))),
801 Box::new(CmpExpr::I32(*disp)),
802 ))),
803 width,
804 )),
805 Operand::MemBaseIndexScale { base, index, scale } => CmpExpr::Deref((
806 Box::new(CmpExpr::Add((
807 Box::new(CmpExpr::Reg((base.name().to_string(), base.width()))),
808 Box::new(CmpExpr::Add((
809 Box::new(CmpExpr::Reg((index.name().to_string(), index.width()))),
810 Box::new(CmpExpr::U8(*scale)),
811 ))),
812 ))),
813 width,
814 )),
815 Operand::MemBaseIndexScaleDisp {
816 base,
817 index,
818 scale,
819 disp,
820 } => CmpExpr::Deref((
821 Box::new(CmpExpr::Add((
822 Box::new(CmpExpr::Add((
823 Box::new(CmpExpr::Reg((base.name().to_string(), base.width()))),
824 Box::new(CmpExpr::Add((
825 Box::new(CmpExpr::Reg((index.name().to_string(), index.width()))),
826 Box::new(CmpExpr::U8(*scale)),
827 ))),
828 ))),
829 Box::new(CmpExpr::I32(*disp)),
830 ))),
831 width,
832 )),
833 _ => {
834 bail!("Unsupported operand type for cmplog");
835 }
836 };
837 Ok(expr)
838 }
839}
840
841impl TracerDisassembler for Disassembler {
842 fn last_was_control_flow(&self) -> bool {
844 if let Some(last) = self.last {
845 return matches!(
846 last.opcode(),
847 Opcode::JMP
848 | Opcode::JA
849 | Opcode::JB
850 | Opcode::JG
851 | Opcode::JGE
852 | Opcode::JL
853 | Opcode::JLE
854 | Opcode::JNA
855 | Opcode::JNB
856 | Opcode::JNO
857 | Opcode::JNP
858 | Opcode::JNS
859 | Opcode::JNZ
860 | Opcode::JO
861 | Opcode::JP
862 | Opcode::JS
863 | Opcode::JZ
864 | Opcode::LOOP
865 | Opcode::LOOPNZ
866 | Opcode::LOOPZ
867 );
868 }
869
870 false
871 }
872
873 fn last_was_call(&self) -> bool {
875 if let Some(last) = self.last {
876 return matches!(
877 last.opcode(),
878 Opcode::CALL
879 | Opcode::CALLF
880 | Opcode::INT
881 | Opcode::INTO
882 | Opcode::SYSCALL
883 | Opcode::SYSENTER
884 );
885 }
886
887 false
888 }
889
890 fn last_was_ret(&self) -> bool {
892 if let Some(last) = self.last {
893 return matches!(
894 last.opcode(),
895 Opcode::RETF
896 | Opcode::RETURN
897 | Opcode::IRET
898 | Opcode::IRETD
899 | Opcode::IRETQ
900 | Opcode::SYSRET
901 | Opcode::SYSEXIT
902 );
903 }
904
905 false
906 }
907
908 fn last_was_cmp(&self) -> bool {
910 if let Some(last) = self.last {
911 return matches!(
912 last.opcode(),
913 Opcode::CMP
914 | Opcode::CMPPD
915 | Opcode::CMPS
916 | Opcode::CMPSD
917 | Opcode::CMPSS
918 | Opcode::CMPXCHG16B
919 | Opcode::COMISD
920 | Opcode::COMISS
921 | Opcode::FCOM
922 | Opcode::FCOMI
923 | Opcode::FCOMIP
924 | Opcode::FCOMP
925 | Opcode::FCOMPP
926 | Opcode::FICOM
927 | Opcode::FICOMP
928 | Opcode::FTST
929 | Opcode::FUCOM
930 | Opcode::FUCOMI
931 | Opcode::FUCOMIP
932 | Opcode::FUCOMP
933 | Opcode::FXAM
934 | Opcode::PCMPEQB
935 | Opcode::PCMPEQD
936 | Opcode::PCMPEQW
937 | Opcode::PCMPGTB
938 | Opcode::PCMPGTD
939 | Opcode::PCMPGTQ
940 | Opcode::PCMPGTW
941 | Opcode::PMAXSB
942 | Opcode::PMAXSD
943 | Opcode::PMAXUD
944 | Opcode::PMAXUW
945 | Opcode::PMINSB
946 | Opcode::PMINSD
947 | Opcode::PMINUD
948 | Opcode::PMINUW
949 | Opcode::TEST
950 | Opcode::UCOMISD
951 | Opcode::UCOMISS
952 | Opcode::VPCMPB
953 | Opcode::VPCMPD
954 | Opcode::VPCMPQ
955 | Opcode::VPCMPUB
956 | Opcode::VPCMPUD
957 | Opcode::VPCMPUQ
958 | Opcode::VPCMPUW
959 | Opcode::VPCMPW
960 );
961 }
962
963 false
964 }
965
966 fn disassemble(&mut self, bytes: &[u8]) -> Result<()> {
967 if let Ok(insn) = self.decoder.decode_slice(bytes) {
968 self.last = Some(insn);
969 } else {
970 bail!("Could not disassemble {:?}", bytes);
971 }
972
973 Ok(())
974 }
975
976 fn disassemble_to_string(&mut self, bytes: &[u8]) -> Result<String> {
977 if let Ok(insn) = self.decoder.decode_slice(bytes) {
978 Ok(insn.to_string())
979 } else {
980 bail!("Could not disassemble {:?}", bytes);
981 }
982 }
983
984 fn cmp(&self) -> Vec<CmpExpr> {
985 let mut cmp_exprs = Vec::new();
986 if self.last_was_cmp() {
987 if let Some(last) = self.last {
988 for op_idx in 0..last.operand_count() {
989 let op = last.operand(op_idx);
990 let width = if let Some(width) = op.width() {
991 Some(width)
992 } else if let Some(width) = last.mem_size() {
993 width.bytes_size()
994 } else {
995 None
996 };
997 if let Ok(expr) = CmpExpr::try_from((&op, width)) {
998 cmp_exprs.push(expr);
999 }
1000 }
1001 }
1002 }
1003 cmp_exprs
1004 }
1005
1006 fn cmp_type(&self) -> Vec<CmpType> {
1007 if self.last_was_cmp() {
1008 if let Some(last) = self.last {
1009 if let Some(condition) = last.opcode().condition() {
1010 return match condition {
1011 ConditionCode::O => vec![],
1013 ConditionCode::NO => vec![],
1015 ConditionCode::B => vec![CmpType::Lesser],
1017 ConditionCode::AE => vec![CmpType::Greater, CmpType::Equal],
1019 ConditionCode::Z => vec![],
1021 ConditionCode::NZ => vec![],
1023 ConditionCode::A => vec![CmpType::Greater],
1025 ConditionCode::BE => vec![CmpType::Lesser, CmpType::Equal],
1027 ConditionCode::S => vec![],
1029 ConditionCode::NS => vec![],
1031 ConditionCode::P => vec![],
1033 ConditionCode::NP => vec![],
1035 ConditionCode::L => vec![CmpType::Lesser],
1037 ConditionCode::GE => vec![CmpType::Greater, CmpType::Equal],
1039 ConditionCode::G => vec![CmpType::Greater],
1041 ConditionCode::LE => vec![CmpType::Lesser, CmpType::Equal],
1043 };
1044 }
1045 }
1046 }
1047
1048 vec![]
1049 }
1050}