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