Skip to main content

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