Skip to main content

tsffs/arch/
x86_64.rs

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