tsffs/arch/
mod.rs

1// Copyright (C) 2024 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4//! Architecture specific data and definitions
5
6use self::{
7    aarch64::AArch64ArchitectureOperations, arm::ARMArchitectureOperations,
8    risc_v::RISCVArchitectureOperations, x86::X86ArchitectureOperations,
9    x86_64::X86_64ArchitectureOperations,
10};
11use crate::{
12    tracer::TraceEntry, traits::TracerDisassembler, ManualStartAddress, ManualStartInfo, StartInfo,
13    StartPhysicalAddress, StartSize,
14};
15use anyhow::anyhow;
16use anyhow::{bail, ensure, Error, Result};
17use raw_cstr::AsRawCstr;
18use simics::{
19    api::{
20        read_phys_memory, sys::instruction_handle_t, write_byte, Access, AttrValueType, ConfObject,
21        CpuInstructionQueryInterface, CpuInstrumentationSubscribeInterface, CycleInterface,
22        IntRegisterInterface, ProcessorInfoV2Interface,
23    },
24    read_byte,
25};
26use std::{fmt::Debug, str::FromStr};
27
28pub mod aarch64;
29pub mod arm;
30pub mod risc_v;
31pub mod x86;
32pub mod x86_64;
33
34#[derive(Debug, Clone)]
35/// An architecture hint that can be parsed from a string
36pub(crate) enum ArchitectureHint {
37    /// The architecture is x86_64
38    X86_64,
39    /// The architecture is i386
40    I386,
41    /// The architecture is RISCV
42    Riscv,
43    /// The architecture is arm
44    Arm,
45    /// The architecture is aarch64
46    Aarch64,
47}
48
49impl FromStr for ArchitectureHint {
50    type Err = Error;
51
52    fn from_str(s: &str) -> Result<Self> {
53        Ok(match s {
54            "x86-64" => Self::X86_64,
55            "i386" | "i486" | "i586" | "i686" | "ia-32" | "x86" => Self::I386,
56            "riscv" | "risc-v" | "riscv32" | "riscv64" => Self::Riscv,
57            "armv4" | "armv5" | "armv6" | "armv7" | "arm" | "arm32" => Self::Arm,
58            "aarch64" | "armv8" | "arm64" => Self::Aarch64,
59            _ => bail!("Unknown hint: {}", s),
60        })
61    }
62}
63
64impl From<ArchitectureHint> for AttrValueType {
65    fn from(val: ArchitectureHint) -> Self {
66        match val {
67            ArchitectureHint::X86_64 => "x86-64",
68            ArchitectureHint::I386 => "i386",
69            ArchitectureHint::Riscv => "risc-v",
70            ArchitectureHint::Arm => "arm",
71            ArchitectureHint::Aarch64 => "aarch64",
72        }
73        .into()
74    }
75}
76
77impl ArchitectureHint {
78    /// Return the architecture for the given CPU object
79    pub fn architecture(&self, cpu: *mut ConfObject) -> Result<Architecture> {
80        Ok(match self {
81            ArchitectureHint::X86_64 => {
82                Architecture::X86_64(X86_64ArchitectureOperations::new_unchecked(cpu)?)
83            }
84            ArchitectureHint::I386 => {
85                Architecture::I386(X86ArchitectureOperations::new_unchecked(cpu)?)
86            }
87            ArchitectureHint::Riscv => {
88                Architecture::Riscv(RISCVArchitectureOperations::new_unchecked(cpu)?)
89            }
90            ArchitectureHint::Arm => {
91                Architecture::Arm(ARMArchitectureOperations::new_unchecked(cpu)?)
92            }
93            ArchitectureHint::Aarch64 => {
94                Architecture::Aarch64(AArch64ArchitectureOperations::new_unchecked(cpu)?)
95            }
96        })
97    }
98}
99
100pub(crate) enum Architecture {
101    /// The x86_64 architecture
102    X86_64(X86_64ArchitectureOperations),
103    /// The i386 architecture
104    I386(X86ArchitectureOperations),
105    /// The RISC-V architecture
106    Riscv(RISCVArchitectureOperations),
107    /// The ARM architecture (v7 and below)
108    Arm(ARMArchitectureOperations),
109    /// The AARCH64 architecture (v8 and above)
110    Aarch64(AArch64ArchitectureOperations),
111}
112
113impl Debug for Architecture {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        write!(
116            f,
117            "{}",
118            match self {
119                Architecture::X86_64(_) => "x86-64",
120                Architecture::I386(_) => "i386",
121                Architecture::Riscv(_) => "risc-v",
122                Architecture::Arm(_) => "arm",
123                Architecture::Aarch64(_) => "aarch64",
124            }
125        )
126    }
127}
128/// Each architecture must provide a struct that performs architecture-specific operations
129pub trait ArchitectureOperations {
130    const INDEX_SELECTOR_REGISTER: &'static str;
131    const ARGUMENT_REGISTER_0: &'static str;
132    const ARGUMENT_REGISTER_1: &'static str;
133    const ARGUMENT_REGISTER_2: &'static str;
134    const POINTER_WIDTH_OVERRIDE: Option<i32> = None;
135
136    /// Create a new instance of the architecture operations
137    fn new(cpu: *mut ConfObject) -> Result<Self>
138    where
139        Self: Sized;
140
141    /// Create a new instance of the architecture operations without checking the CPU
142    fn new_unchecked(_: *mut ConfObject) -> Result<Self>
143    where
144        Self: Sized,
145    {
146        bail!("Invalid CPU");
147    }
148
149    /// Return the saved CPU object for this archtiecture
150    fn cpu(&self) -> *mut ConfObject;
151
152    /// Return a mutable reference to the disassembler for this architecture
153    fn disassembler(&mut self) -> &mut dyn TracerDisassembler;
154
155    /// Return a mutable reference to the interface for reading and writing registers
156    fn int_register(&mut self) -> &mut IntRegisterInterface;
157
158    /// Return a mutable reference to the interface for reading processor information
159    fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface;
160
161    /// Return a mutable reference to the interface for querying CPU instructions
162    fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface;
163
164    /// Return a mutable reference to the interface for subscribing to CPU instrumentation events
165    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface;
166
167    /// Return a mutable reference to the interface for querying CPU cycles and timing
168    fn cycle(&mut self) -> &mut CycleInterface;
169
170    /// Return the value of the magic index selector register, which is used to determine
171    /// whether a magic instruction should be used or skipped.
172    fn get_magic_index_selector(&mut self) -> Result<u64> {
173        Ok(self
174            .int_register()
175            .get_number(Self::INDEX_SELECTOR_REGISTER.as_raw_cstr()?)
176            .and_then(|n| self.int_register().read(n))?)
177    }
178
179    /// Get the magic start information from the harness which takes the arguments:
180    ///
181    /// - buffer: The address of the buffer containing the testcase
182    /// - size_ptr: A pointer to a pointer-sized variable containing the size of the testcase
183    fn get_magic_start_buffer_ptr_size_ptr(&mut self) -> Result<StartInfo> {
184        let buffer_register_number = self
185            .int_register()
186            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
187        let size_ptr_register_number = self
188            .int_register()
189            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
190        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
191        let size_ptr_logical_address = self.int_register().read(size_ptr_register_number)?;
192        let buffer_physical_address_block = self
193            .processor_info_v2()
194            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
195        let size_ptr_physical_address_block = self
196            .processor_info_v2()
197            .logical_to_physical(size_ptr_logical_address, Access::Sim_Access_Read)?;
198
199        ensure!(
200            buffer_physical_address_block.valid != 0,
201            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
202        );
203        ensure!(
204            size_ptr_physical_address_block.valid != 0,
205            "Invalid linear address found in magic start size register {size_ptr_register_number}: {size_ptr_logical_address:#x}"
206        );
207
208        let size_size = if let Some(width) = Self::POINTER_WIDTH_OVERRIDE {
209            width
210        } else {
211            self.processor_info_v2().get_logical_address_width()? / u8::BITS as i32
212        };
213
214        let size = read_phys_memory(
215            self.cpu(),
216            size_ptr_physical_address_block.address,
217            size_size,
218        )?;
219
220        let contents = (0..size)
221            .map(|i| {
222                read_byte(
223                    self.processor_info_v2().get_physical_memory()?,
224                    buffer_physical_address_block.address + i,
225                )
226                .map_err(|e| {
227                    anyhow!(
228                        "Failed to read byte at {:#x}: {}",
229                        buffer_physical_address_block.address + i,
230                        e
231                    )
232                })
233            })
234            .collect::<Result<Vec<_>>>()?;
235
236        Ok(StartInfo::builder()
237            .address(
238                if buffer_physical_address_block.address != buffer_logical_address {
239                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
240                } else {
241                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
242                },
243            )
244            .contents(contents)
245            .size(StartSize::SizePtr {
246                address: if size_ptr_physical_address_block.address != size_ptr_logical_address {
247                    StartPhysicalAddress::WasVirtual(size_ptr_physical_address_block.address)
248                } else {
249                    StartPhysicalAddress::WasPhysical(size_ptr_physical_address_block.address)
250                },
251                maximum_size: size as usize,
252            })
253            .build())
254    }
255
256    /// Get the magic start information from the harness which takes the arguments:
257    ///
258    /// - buffer: The address of the buffer containing the testcase
259    /// - size_val: The maximum size of the testcase
260    fn get_magic_start_buffer_ptr_size_val(&mut self) -> Result<StartInfo> {
261        let buffer_register_number = self
262            .int_register()
263            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
264        let size_val_register_number = self
265            .int_register()
266            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
267        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
268        let size_val = self.int_register().read(size_val_register_number)?;
269        let buffer_physical_address_block = self
270            .processor_info_v2()
271            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
272
273        ensure!(
274            buffer_physical_address_block.valid != 0,
275            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
276        );
277
278        let contents = (0..size_val)
279            .map(|i| {
280                read_byte(
281                    self.processor_info_v2().get_physical_memory()?,
282                    buffer_physical_address_block.address + i,
283                )
284                .map_err(|e| {
285                    anyhow!(
286                        "Failed to read byte at {:#x}: {}",
287                        buffer_physical_address_block.address + i,
288                        e
289                    )
290                })
291            })
292            .collect::<Result<Vec<_>>>()?;
293
294        Ok(StartInfo::builder()
295            .address(
296                if buffer_physical_address_block.address != buffer_logical_address {
297                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
298                } else {
299                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
300                },
301            )
302            .contents(contents)
303            .size(StartSize::MaxSize(size_val as usize))
304            .build())
305    }
306
307    /// Get the magic start information from the harness which takes the arguments:
308    ///
309    /// - buffer: The address of the buffer containing the testcase
310    /// - size_ptr: A pointer to a pointer-sized variable to which the size is written
311    /// - size_val: The maximum size of the testcase
312    fn get_magic_start_buffer_ptr_size_ptr_val(&mut self) -> Result<StartInfo> {
313        let buffer_register_number = self
314            .int_register()
315            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
316        let size_ptr_register_number = self
317            .int_register()
318            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
319        let size_val_register_number = self
320            .int_register()
321            .get_number(Self::ARGUMENT_REGISTER_2.as_raw_cstr()?)?;
322
323        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
324        let size_ptr_logical_address = self.int_register().read(size_ptr_register_number)?;
325        let size_val = self.int_register().read(size_val_register_number)?;
326
327        let buffer_physical_address_block = self
328            .processor_info_v2()
329            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
330
331        let size_ptr_physical_address_block = self
332            .processor_info_v2()
333            .logical_to_physical(size_ptr_logical_address, Access::Sim_Access_Read)?;
334
335        ensure!(
336            buffer_physical_address_block.valid != 0,
337            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
338        );
339        ensure!(
340            size_ptr_physical_address_block.valid != 0,
341            "Invalid linear address found in magic start size register {size_ptr_register_number}: {size_ptr_logical_address:#x}"
342        );
343
344        let contents = (0..size_val)
345            .map(|i| {
346                read_byte(
347                    self.processor_info_v2().get_physical_memory()?,
348                    buffer_physical_address_block.address + i,
349                )
350                .map_err(|e| {
351                    anyhow!(
352                        "Failed to read byte at {:#x}: {}",
353                        buffer_physical_address_block.address + i,
354                        e
355                    )
356                })
357            })
358            .collect::<Result<Vec<_>>>()?;
359
360        Ok(StartInfo::builder()
361            .address(
362                if buffer_physical_address_block.address != buffer_logical_address {
363                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
364                } else {
365                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
366                },
367            )
368            .contents(contents)
369            .size(StartSize::SizePtrAndMaxSize {
370                address: if size_ptr_physical_address_block.address != size_ptr_logical_address {
371                    StartPhysicalAddress::WasVirtual(size_ptr_physical_address_block.address)
372                } else {
373                    StartPhysicalAddress::WasPhysical(size_ptr_physical_address_block.address)
374                },
375                maximum_size: size_val as usize,
376            })
377            .build())
378    }
379
380    /// Returns the address and whether the address is virtual for the testcase buffer used by
381    /// the manual start functionality
382    fn get_manual_start_info(&mut self, info: &ManualStartInfo) -> Result<StartInfo> {
383        let buffer_physical_address = if matches!(info.address, ManualStartAddress::Virtual(_)) {
384            let physical_address_block = self
385                .processor_info_v2()
386                // NOTE: Do we need to support segmented memory via logical_to_physical?
387                .logical_to_physical(
388                    match info.address {
389                        ManualStartAddress::Virtual(address) => address,
390                        ManualStartAddress::Physical(address) => address,
391                    },
392                    Access::Sim_Access_Read,
393                )?;
394
395            if physical_address_block.valid == 0 {
396                bail!(
397                    "Invalid linear address for given buffer address {:?}",
398                    info.address
399                );
400            }
401
402            physical_address_block.address
403        } else {
404            info.address.address()
405        };
406
407        let address = StartPhysicalAddress::WasPhysical(buffer_physical_address);
408
409        let size = match &info.size {
410            crate::ManualStartSize::SizePtr { address } => {
411                let address = match address {
412                    ManualStartAddress::Virtual(v) => {
413                        let physical_address = self
414                            .processor_info_v2()
415                            .logical_to_physical(*v, Access::Sim_Access_Read)?;
416
417                        if physical_address.valid == 0 {
418                            bail!("Invalid linear address given for start buffer : {v:#x}");
419                        }
420
421                        StartPhysicalAddress::WasVirtual(physical_address.address)
422                    }
423                    ManualStartAddress::Physical(p) => StartPhysicalAddress::WasPhysical(*p),
424                };
425
426                let size_size = if let Some(width) = Self::POINTER_WIDTH_OVERRIDE {
427                    width
428                } else {
429                    self.processor_info_v2().get_logical_address_width()? / u8::BITS as i32
430                };
431                let maximum_size =
432                    read_phys_memory(self.cpu(), address.physical_address(), size_size)?;
433                StartSize::SizePtr {
434                    address,
435                    maximum_size: maximum_size as usize,
436                }
437            }
438            crate::ManualStartSize::MaxSize(maximum_size) => StartSize::MaxSize(*maximum_size),
439            crate::ManualStartSize::SizePtrAndMaxSize {
440                address,
441                maximum_size,
442            } => {
443                let address = match address {
444                    ManualStartAddress::Virtual(v) => {
445                        let physical_address = self
446                            .processor_info_v2()
447                            .logical_to_physical(*v, Access::Sim_Access_Read)?;
448
449                        if physical_address.valid == 0 {
450                            bail!("Invalid linear address given for start buffer : {v:#x}");
451                        }
452
453                        StartPhysicalAddress::WasVirtual(physical_address.address)
454                    }
455                    ManualStartAddress::Physical(p) => StartPhysicalAddress::WasPhysical(*p),
456                };
457
458                StartSize::SizePtrAndMaxSize {
459                    address,
460                    maximum_size: *maximum_size,
461                }
462            }
463        };
464
465        let contents = (0..size.maximum_size())
466            .map(|i| {
467                read_byte(
468                    self.processor_info_v2().get_physical_memory()?,
469                    buffer_physical_address + i as u64,
470                )
471                .map_err(|e| {
472                    anyhow!(
473                        "Failed to read byte at {:#x}: {}",
474                        buffer_physical_address + i as u64,
475                        e
476                    )
477                })
478            })
479            .collect::<Result<Vec<_>>>()?;
480
481        Ok(StartInfo::builder()
482            .address(address)
483            .contents(contents)
484            .size(size)
485            .build())
486    }
487
488    fn write_start(&mut self, testcase: &[u8], info: &StartInfo) -> Result<()> {
489        let mut testcase = testcase.to_vec();
490        // NOTE: We have to handle both riscv64 and riscv32 here
491        let addr_size =
492            self.processor_info_v2().get_logical_address_width()? as usize / u8::BITS as usize;
493
494        let physical_memory = self.processor_info_v2().get_physical_memory()?;
495
496        testcase.truncate(info.size.maximum_size());
497
498        testcase.iter().enumerate().try_for_each(|(i, c)| {
499            let physical_address = info.address.physical_address() + (i as u64);
500            write_byte(physical_memory, physical_address, *c)
501        })?;
502
503        if let Some(size_address) = info.size.physical_address().map(|s| s.physical_address()) {
504            testcase
505                .len()
506                .to_le_bytes()
507                .iter()
508                .take(addr_size)
509                .enumerate()
510                .try_for_each(|(i, c)| {
511                    let physical_address = size_address + (i as u64);
512                    write_byte(physical_memory, physical_address, *c)
513                })?;
514        }
515
516        Ok(())
517    }
518
519    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry>;
520    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry>;
521}
522
523impl ArchitectureOperations for Architecture {
524    const INDEX_SELECTOR_REGISTER: &'static str = "";
525    const ARGUMENT_REGISTER_0: &'static str = "";
526    const ARGUMENT_REGISTER_1: &'static str = "";
527    const ARGUMENT_REGISTER_2: &'static str = "";
528
529    fn new(cpu: *mut ConfObject) -> Result<Self>
530    where
531        Self: Sized,
532    {
533        if let Ok(x86_64) = X86_64ArchitectureOperations::new(cpu) {
534            Ok(Self::X86_64(x86_64))
535        } else if let Ok(x86) = X86ArchitectureOperations::new(cpu) {
536            Ok(Self::I386(x86))
537        } else if let Ok(riscv) = RISCVArchitectureOperations::new(cpu) {
538            Ok(Self::Riscv(riscv))
539        } else if let Ok(arm) = ARMArchitectureOperations::new(cpu) {
540            Ok(Self::Arm(arm))
541        } else if let Ok(aarch64) = AArch64ArchitectureOperations::new(cpu) {
542            Ok(Self::Aarch64(aarch64))
543        } else {
544            bail!("Unsupported architecture");
545        }
546    }
547
548    fn cpu(&self) -> *mut ConfObject {
549        match self {
550            Architecture::X86_64(x86_64) => x86_64.cpu(),
551            Architecture::I386(i386) => i386.cpu(),
552            Architecture::Riscv(riscv) => riscv.cpu(),
553            Architecture::Arm(arm) => arm.cpu(),
554            Architecture::Aarch64(aarch64) => aarch64.cpu(),
555        }
556    }
557
558    fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
559        match self {
560            Architecture::X86_64(x86_64) => x86_64.disassembler(),
561            Architecture::I386(i386) => i386.disassembler(),
562            Architecture::Riscv(riscv) => riscv.disassembler(),
563            Architecture::Arm(arm) => arm.disassembler(),
564            Architecture::Aarch64(aarch64) => aarch64.disassembler(),
565        }
566    }
567
568    fn int_register(&mut self) -> &mut IntRegisterInterface {
569        match self {
570            Architecture::X86_64(x86_64) => x86_64.int_register(),
571            Architecture::I386(i386) => i386.int_register(),
572            Architecture::Riscv(riscv) => riscv.int_register(),
573            Architecture::Arm(arm) => arm.int_register(),
574            Architecture::Aarch64(aarch64) => aarch64.int_register(),
575        }
576    }
577
578    fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
579        match self {
580            Architecture::X86_64(x86_64) => x86_64.processor_info_v2(),
581            Architecture::I386(i386) => i386.processor_info_v2(),
582            Architecture::Riscv(riscv) => riscv.processor_info_v2(),
583            Architecture::Arm(arm) => arm.processor_info_v2(),
584            Architecture::Aarch64(aarch64) => aarch64.processor_info_v2(),
585        }
586    }
587
588    fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
589        match self {
590            Architecture::X86_64(x86_64) => x86_64.cpu_instruction_query(),
591            Architecture::I386(i386) => i386.cpu_instruction_query(),
592            Architecture::Riscv(riscv) => riscv.cpu_instruction_query(),
593            Architecture::Arm(arm) => arm.cpu_instruction_query(),
594            Architecture::Aarch64(aarch64) => aarch64.cpu_instruction_query(),
595        }
596    }
597
598    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
599        match self {
600            Architecture::X86_64(x86_64) => x86_64.cpu_instrumentation_subscribe(),
601            Architecture::I386(i386) => i386.cpu_instrumentation_subscribe(),
602            Architecture::Riscv(riscv) => riscv.cpu_instrumentation_subscribe(),
603            Architecture::Arm(arm) => arm.cpu_instrumentation_subscribe(),
604            Architecture::Aarch64(aarch64) => aarch64.cpu_instrumentation_subscribe(),
605        }
606    }
607
608    fn cycle(&mut self) -> &mut CycleInterface {
609        match self {
610            Architecture::X86_64(x86_64) => x86_64.cycle(),
611            Architecture::I386(i386) => i386.cycle(),
612            Architecture::Riscv(riscv) => riscv.cycle(),
613            Architecture::Arm(arm) => arm.cycle(),
614            Architecture::Aarch64(aarch64) => aarch64.cycle(),
615        }
616    }
617
618    fn get_magic_index_selector(&mut self) -> Result<u64> {
619        match self {
620            Architecture::X86_64(x86_64) => x86_64.get_magic_index_selector(),
621            Architecture::I386(i386) => i386.get_magic_index_selector(),
622            Architecture::Riscv(riscv) => riscv.get_magic_index_selector(),
623            Architecture::Arm(arm) => arm.get_magic_index_selector(),
624            Architecture::Aarch64(aarch64) => aarch64.get_magic_index_selector(),
625        }
626    }
627
628    fn get_magic_start_buffer_ptr_size_ptr(&mut self) -> Result<StartInfo> {
629        match self {
630            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_ptr(),
631            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_ptr(),
632            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_ptr(),
633            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_ptr(),
634            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_ptr(),
635        }
636    }
637
638    fn get_magic_start_buffer_ptr_size_val(&mut self) -> Result<StartInfo> {
639        match self {
640            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_val(),
641            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_val(),
642            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_val(),
643            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_val(),
644            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_val(),
645        }
646    }
647
648    fn get_magic_start_buffer_ptr_size_ptr_val(&mut self) -> Result<StartInfo> {
649        match self {
650            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_ptr(),
651            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_ptr(),
652            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_ptr(),
653            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_ptr_val(),
654            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_ptr_val(),
655        }
656    }
657
658    fn get_manual_start_info(&mut self, info: &ManualStartInfo) -> Result<StartInfo> {
659        match self {
660            Architecture::X86_64(x86_64) => x86_64.get_manual_start_info(info),
661            Architecture::I386(i386) => i386.get_manual_start_info(info),
662            Architecture::Riscv(riscv) => riscv.get_manual_start_info(info),
663            Architecture::Arm(arm) => arm.get_manual_start_info(info),
664            Architecture::Aarch64(aarch64) => aarch64.get_manual_start_info(info),
665        }
666    }
667
668    fn write_start(&mut self, testcase: &[u8], info: &StartInfo) -> Result<()> {
669        match self {
670            Architecture::X86_64(x86_64) => x86_64.write_start(testcase, info),
671            Architecture::I386(i386) => i386.write_start(testcase, info),
672            Architecture::Riscv(riscv) => riscv.write_start(testcase, info),
673            Architecture::Arm(arm) => arm.write_start(testcase, info),
674            Architecture::Aarch64(aarch64) => aarch64.write_start(testcase, info),
675        }
676    }
677
678    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
679        match self {
680            Architecture::X86_64(x86_64) => x86_64.trace_pc(instruction_query),
681            Architecture::I386(i386) => i386.trace_pc(instruction_query),
682            Architecture::Riscv(riscv) => riscv.trace_pc(instruction_query),
683            Architecture::Arm(arm) => arm.trace_pc(instruction_query),
684            Architecture::Aarch64(aarch64) => aarch64.trace_pc(instruction_query),
685        }
686    }
687
688    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
689        match self {
690            Architecture::X86_64(x86_64) => x86_64.trace_cmp(instruction_query),
691            Architecture::I386(i386) => i386.trace_cmp(instruction_query),
692            Architecture::Riscv(riscv) => riscv.trace_cmp(instruction_query),
693            Architecture::Arm(arm) => arm.trace_cmp(instruction_query),
694            Architecture::Aarch64(aarch64) => aarch64.trace_cmp(instruction_query),
695        }
696    }
697}