tsffs/arch/
x86.rs

1// Copyright (C) 2024 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4//! Architecture-specific implementation for x86 architecture
5
6use 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            // Check if the arch is actually x86-64, some x86-64 processors are actually
58            // i386 under the hood
59            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            // No i386 processor will actually be x86-64 under the hood
111            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                // There are other types but they are never emitted on x86
735                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    /// Check if an instruction is a control flow instruction
843    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    /// Check if an instruction is a call instruction
874    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    /// Check if an instruction is a ret instruction
891    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    /// Check if an instruction is a cmp instruction
909    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                        // Overflow
1012                        ConditionCode::O => vec![],
1013                        // No Overflow
1014                        ConditionCode::NO => vec![],
1015                        // Below
1016                        ConditionCode::B => vec![CmpType::Lesser],
1017                        // Above or Equal
1018                        ConditionCode::AE => vec![CmpType::Greater, CmpType::Equal],
1019                        // Zero
1020                        ConditionCode::Z => vec![],
1021                        // Not Zero
1022                        ConditionCode::NZ => vec![],
1023                        // Above
1024                        ConditionCode::A => vec![CmpType::Greater],
1025                        // Below or Equal
1026                        ConditionCode::BE => vec![CmpType::Lesser, CmpType::Equal],
1027                        // Signed
1028                        ConditionCode::S => vec![],
1029                        // Not Signed
1030                        ConditionCode::NS => vec![],
1031                        // Parity
1032                        ConditionCode::P => vec![],
1033                        // No Parity
1034                        ConditionCode::NP => vec![],
1035                        // Less
1036                        ConditionCode::L => vec![CmpType::Lesser],
1037                        // Greater or Equal
1038                        ConditionCode::GE => vec![CmpType::Greater, CmpType::Equal],
1039                        // Greater
1040                        ConditionCode::G => vec![CmpType::Greater],
1041                        // Less or Equal
1042                        ConditionCode::LE => vec![CmpType::Lesser, CmpType::Equal],
1043                    };
1044                }
1045            }
1046        }
1047
1048        vec![]
1049    }
1050}