Skip to main content

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    #[allow(dead_code)]
166    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface;
167
168    /// Return a mutable reference to the interface for querying CPU cycles and timing
169    fn cycle(&mut self) -> &mut CycleInterface;
170
171    /// Return the value of the magic index selector register, which is used to determine
172    /// whether a magic instruction should be used or skipped.
173    fn get_magic_index_selector(&mut self) -> Result<u64> {
174        Ok(self
175            .int_register()
176            .get_number(Self::INDEX_SELECTOR_REGISTER.as_raw_cstr()?)
177            .and_then(|n| self.int_register().read(n))?)
178    }
179
180    /// Get the magic start information from the harness which takes the arguments:
181    ///
182    /// - buffer: The address of the buffer containing the testcase
183    /// - size_ptr: A pointer to a pointer-sized variable containing the size of the testcase
184    fn get_magic_start_buffer_ptr_size_ptr(&mut self) -> Result<StartInfo> {
185        let buffer_register_number = self
186            .int_register()
187            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
188        let size_ptr_register_number = self
189            .int_register()
190            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
191        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
192        let size_ptr_logical_address = self.int_register().read(size_ptr_register_number)?;
193        let buffer_physical_address_block = self
194            .processor_info_v2()
195            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
196        let size_ptr_physical_address_block = self
197            .processor_info_v2()
198            .logical_to_physical(size_ptr_logical_address, Access::Sim_Access_Read)?;
199
200        ensure!(
201            buffer_physical_address_block.valid != 0,
202            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
203        );
204        ensure!(
205            size_ptr_physical_address_block.valid != 0,
206            "Invalid linear address found in magic start size register {size_ptr_register_number}: {size_ptr_logical_address:#x}"
207        );
208
209        let size_size = if let Some(width) = Self::POINTER_WIDTH_OVERRIDE {
210            width
211        } else {
212            self.processor_info_v2().get_logical_address_width()? / u8::BITS as i32
213        };
214
215        let size = read_phys_memory(
216            self.cpu(),
217            size_ptr_physical_address_block.address,
218            size_size,
219        )?;
220
221        let contents = (0..size)
222            .map(|i| {
223                read_byte(
224                    self.processor_info_v2().get_physical_memory()?,
225                    buffer_physical_address_block.address + i,
226                )
227                .map_err(|e| {
228                    anyhow!(
229                        "Failed to read byte at {:#x}: {}",
230                        buffer_physical_address_block.address + i,
231                        e
232                    )
233                })
234            })
235            .collect::<Result<Vec<_>>>()?;
236
237        Ok(StartInfo::builder()
238            .address(
239                if buffer_physical_address_block.address != buffer_logical_address {
240                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
241                } else {
242                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
243                },
244            )
245            .contents(contents)
246            .size(StartSize::SizePtr {
247                address: if size_ptr_physical_address_block.address != size_ptr_logical_address {
248                    StartPhysicalAddress::WasVirtual(size_ptr_physical_address_block.address)
249                } else {
250                    StartPhysicalAddress::WasPhysical(size_ptr_physical_address_block.address)
251                },
252                maximum_size: size as usize,
253            })
254            .build())
255    }
256
257    /// Get the magic start information from the harness which takes the arguments:
258    ///
259    /// - buffer: The address of the buffer containing the testcase
260    /// - size_val: The maximum size of the testcase
261    fn get_magic_start_buffer_ptr_size_val(&mut self) -> Result<StartInfo> {
262        let buffer_register_number = self
263            .int_register()
264            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
265        let size_val_register_number = self
266            .int_register()
267            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
268        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
269        let size_val = self.int_register().read(size_val_register_number)?;
270        let buffer_physical_address_block = self
271            .processor_info_v2()
272            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
273
274        ensure!(
275            buffer_physical_address_block.valid != 0,
276            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
277        );
278
279        let contents = (0..size_val)
280            .map(|i| {
281                read_byte(
282                    self.processor_info_v2().get_physical_memory()?,
283                    buffer_physical_address_block.address + i,
284                )
285                .map_err(|e| {
286                    anyhow!(
287                        "Failed to read byte at {:#x}: {}",
288                        buffer_physical_address_block.address + i,
289                        e
290                    )
291                })
292            })
293            .collect::<Result<Vec<_>>>()?;
294
295        Ok(StartInfo::builder()
296            .address(
297                if buffer_physical_address_block.address != buffer_logical_address {
298                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
299                } else {
300                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
301                },
302            )
303            .contents(contents)
304            .size(StartSize::MaxSize(size_val as usize))
305            .build())
306    }
307
308    /// Get the magic start information from the harness which takes the arguments:
309    ///
310    /// - buffer: The address of the buffer containing the testcase
311    /// - size_ptr: A pointer to a pointer-sized variable to which the size is written
312    /// - size_val: The maximum size of the testcase
313    fn get_magic_start_buffer_ptr_size_ptr_val(&mut self) -> Result<StartInfo> {
314        let buffer_register_number = self
315            .int_register()
316            .get_number(Self::ARGUMENT_REGISTER_0.as_raw_cstr()?)?;
317        let size_ptr_register_number = self
318            .int_register()
319            .get_number(Self::ARGUMENT_REGISTER_1.as_raw_cstr()?)?;
320        let size_val_register_number = self
321            .int_register()
322            .get_number(Self::ARGUMENT_REGISTER_2.as_raw_cstr()?)?;
323
324        let buffer_logical_address = self.int_register().read(buffer_register_number)?;
325        let size_ptr_logical_address = self.int_register().read(size_ptr_register_number)?;
326        let size_val = self.int_register().read(size_val_register_number)?;
327
328        let buffer_physical_address_block = self
329            .processor_info_v2()
330            .logical_to_physical(buffer_logical_address, Access::Sim_Access_Read)?;
331
332        let size_ptr_physical_address_block = self
333            .processor_info_v2()
334            .logical_to_physical(size_ptr_logical_address, Access::Sim_Access_Read)?;
335
336        ensure!(
337            buffer_physical_address_block.valid != 0,
338            "Invalid linear address found in magic start buffer register {buffer_register_number}: {buffer_logical_address:#x}"
339        );
340        ensure!(
341            size_ptr_physical_address_block.valid != 0,
342            "Invalid linear address found in magic start size register {size_ptr_register_number}: {size_ptr_logical_address:#x}"
343        );
344
345        let contents = (0..size_val)
346            .map(|i| {
347                read_byte(
348                    self.processor_info_v2().get_physical_memory()?,
349                    buffer_physical_address_block.address + i,
350                )
351                .map_err(|e| {
352                    anyhow!(
353                        "Failed to read byte at {:#x}: {}",
354                        buffer_physical_address_block.address + i,
355                        e
356                    )
357                })
358            })
359            .collect::<Result<Vec<_>>>()?;
360
361        Ok(StartInfo::builder()
362            .address(
363                if buffer_physical_address_block.address != buffer_logical_address {
364                    StartPhysicalAddress::WasVirtual(buffer_physical_address_block.address)
365                } else {
366                    StartPhysicalAddress::WasPhysical(buffer_physical_address_block.address)
367                },
368            )
369            .contents(contents)
370            .size(StartSize::SizePtrAndMaxSize {
371                address: if size_ptr_physical_address_block.address != size_ptr_logical_address {
372                    StartPhysicalAddress::WasVirtual(size_ptr_physical_address_block.address)
373                } else {
374                    StartPhysicalAddress::WasPhysical(size_ptr_physical_address_block.address)
375                },
376                maximum_size: size_val as usize,
377            })
378            .build())
379    }
380
381    /// Returns the address and whether the address is virtual for the testcase buffer used by
382    /// the manual start functionality
383    fn get_manual_start_info(&mut self, info: &ManualStartInfo) -> Result<StartInfo> {
384        let buffer_physical_address = if matches!(info.address, ManualStartAddress::Virtual(_)) {
385            let physical_address_block = self
386                .processor_info_v2()
387                // NOTE: Do we need to support segmented memory via logical_to_physical?
388                .logical_to_physical(
389                    match info.address {
390                        ManualStartAddress::Virtual(address) => address,
391                        ManualStartAddress::Physical(address) => address,
392                    },
393                    Access::Sim_Access_Read,
394                )?;
395
396            if physical_address_block.valid == 0 {
397                bail!(
398                    "Invalid linear address for given buffer address {:?}",
399                    info.address
400                );
401            }
402
403            physical_address_block.address
404        } else {
405            info.address.address()
406        };
407
408        let address = StartPhysicalAddress::WasPhysical(buffer_physical_address);
409
410        let size = match &info.size {
411            crate::ManualStartSize::SizePtr { address } => {
412                let address = match address {
413                    ManualStartAddress::Virtual(v) => {
414                        let physical_address = self
415                            .processor_info_v2()
416                            .logical_to_physical(*v, Access::Sim_Access_Read)?;
417
418                        if physical_address.valid == 0 {
419                            bail!("Invalid linear address given for start buffer : {v:#x}");
420                        }
421
422                        StartPhysicalAddress::WasVirtual(physical_address.address)
423                    }
424                    ManualStartAddress::Physical(p) => StartPhysicalAddress::WasPhysical(*p),
425                };
426
427                let size_size = if let Some(width) = Self::POINTER_WIDTH_OVERRIDE {
428                    width
429                } else {
430                    self.processor_info_v2().get_logical_address_width()? / u8::BITS as i32
431                };
432                let maximum_size =
433                    read_phys_memory(self.cpu(), address.physical_address(), size_size)?;
434                StartSize::SizePtr {
435                    address,
436                    maximum_size: maximum_size as usize,
437                }
438            }
439            crate::ManualStartSize::MaxSize(maximum_size) => StartSize::MaxSize(*maximum_size),
440            crate::ManualStartSize::SizePtrAndMaxSize {
441                address,
442                maximum_size,
443            } => {
444                let address = match address {
445                    ManualStartAddress::Virtual(v) => {
446                        let physical_address = self
447                            .processor_info_v2()
448                            .logical_to_physical(*v, Access::Sim_Access_Read)?;
449
450                        if physical_address.valid == 0 {
451                            bail!("Invalid linear address given for start buffer : {v:#x}");
452                        }
453
454                        StartPhysicalAddress::WasVirtual(physical_address.address)
455                    }
456                    ManualStartAddress::Physical(p) => StartPhysicalAddress::WasPhysical(*p),
457                };
458
459                StartSize::SizePtrAndMaxSize {
460                    address,
461                    maximum_size: *maximum_size,
462                }
463            }
464        };
465
466        let contents = (0..size.maximum_size())
467            .map(|i| {
468                read_byte(
469                    self.processor_info_v2().get_physical_memory()?,
470                    buffer_physical_address + i as u64,
471                )
472                .map_err(|e| {
473                    anyhow!(
474                        "Failed to read byte at {:#x}: {}",
475                        buffer_physical_address + i as u64,
476                        e
477                    )
478                })
479            })
480            .collect::<Result<Vec<_>>>()?;
481
482        Ok(StartInfo::builder()
483            .address(address)
484            .contents(contents)
485            .size(size)
486            .build())
487    }
488
489    fn write_start(&mut self, testcase: &[u8], info: &StartInfo) -> Result<()> {
490        let mut testcase = testcase.to_vec();
491        // NOTE: We have to handle both riscv64 and riscv32 here
492        let addr_size =
493            self.processor_info_v2().get_logical_address_width()? as usize / u8::BITS as usize;
494
495        let physical_memory = self.processor_info_v2().get_physical_memory()?;
496
497        testcase.truncate(info.size.maximum_size());
498
499        testcase.iter().enumerate().try_for_each(|(i, c)| {
500            let physical_address = info.address.physical_address() + (i as u64);
501            write_byte(physical_memory, physical_address, *c)
502        })?;
503
504        if let Some(size_address) = info.size.physical_address().map(|s| s.physical_address()) {
505            testcase
506                .len()
507                .to_le_bytes()
508                .iter()
509                .take(addr_size)
510                .enumerate()
511                .try_for_each(|(i, c)| {
512                    let physical_address = size_address + (i as u64);
513                    write_byte(physical_memory, physical_address, *c)
514                })?;
515        }
516
517        Ok(())
518    }
519
520    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry>;
521    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry>;
522}
523
524impl ArchitectureOperations for Architecture {
525    const INDEX_SELECTOR_REGISTER: &'static str = "";
526    const ARGUMENT_REGISTER_0: &'static str = "";
527    const ARGUMENT_REGISTER_1: &'static str = "";
528    const ARGUMENT_REGISTER_2: &'static str = "";
529
530    fn new(cpu: *mut ConfObject) -> Result<Self>
531    where
532        Self: Sized,
533    {
534        if let Ok(x86_64) = X86_64ArchitectureOperations::new(cpu) {
535            Ok(Self::X86_64(x86_64))
536        } else if let Ok(x86) = X86ArchitectureOperations::new(cpu) {
537            Ok(Self::I386(x86))
538        } else if let Ok(riscv) = RISCVArchitectureOperations::new(cpu) {
539            Ok(Self::Riscv(riscv))
540        } else if let Ok(arm) = ARMArchitectureOperations::new(cpu) {
541            Ok(Self::Arm(arm))
542        } else if let Ok(aarch64) = AArch64ArchitectureOperations::new(cpu) {
543            Ok(Self::Aarch64(aarch64))
544        } else {
545            bail!("Unsupported architecture");
546        }
547    }
548
549    fn cpu(&self) -> *mut ConfObject {
550        match self {
551            Architecture::X86_64(x86_64) => x86_64.cpu(),
552            Architecture::I386(i386) => i386.cpu(),
553            Architecture::Riscv(riscv) => riscv.cpu(),
554            Architecture::Arm(arm) => arm.cpu(),
555            Architecture::Aarch64(aarch64) => aarch64.cpu(),
556        }
557    }
558
559    fn disassembler(&mut self) -> &mut dyn TracerDisassembler {
560        match self {
561            Architecture::X86_64(x86_64) => x86_64.disassembler(),
562            Architecture::I386(i386) => i386.disassembler(),
563            Architecture::Riscv(riscv) => riscv.disassembler(),
564            Architecture::Arm(arm) => arm.disassembler(),
565            Architecture::Aarch64(aarch64) => aarch64.disassembler(),
566        }
567    }
568
569    fn int_register(&mut self) -> &mut IntRegisterInterface {
570        match self {
571            Architecture::X86_64(x86_64) => x86_64.int_register(),
572            Architecture::I386(i386) => i386.int_register(),
573            Architecture::Riscv(riscv) => riscv.int_register(),
574            Architecture::Arm(arm) => arm.int_register(),
575            Architecture::Aarch64(aarch64) => aarch64.int_register(),
576        }
577    }
578
579    fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface {
580        match self {
581            Architecture::X86_64(x86_64) => x86_64.processor_info_v2(),
582            Architecture::I386(i386) => i386.processor_info_v2(),
583            Architecture::Riscv(riscv) => riscv.processor_info_v2(),
584            Architecture::Arm(arm) => arm.processor_info_v2(),
585            Architecture::Aarch64(aarch64) => aarch64.processor_info_v2(),
586        }
587    }
588
589    fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface {
590        match self {
591            Architecture::X86_64(x86_64) => x86_64.cpu_instruction_query(),
592            Architecture::I386(i386) => i386.cpu_instruction_query(),
593            Architecture::Riscv(riscv) => riscv.cpu_instruction_query(),
594            Architecture::Arm(arm) => arm.cpu_instruction_query(),
595            Architecture::Aarch64(aarch64) => aarch64.cpu_instruction_query(),
596        }
597    }
598
599    fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface {
600        match self {
601            Architecture::X86_64(x86_64) => x86_64.cpu_instrumentation_subscribe(),
602            Architecture::I386(i386) => i386.cpu_instrumentation_subscribe(),
603            Architecture::Riscv(riscv) => riscv.cpu_instrumentation_subscribe(),
604            Architecture::Arm(arm) => arm.cpu_instrumentation_subscribe(),
605            Architecture::Aarch64(aarch64) => aarch64.cpu_instrumentation_subscribe(),
606        }
607    }
608
609    fn cycle(&mut self) -> &mut CycleInterface {
610        match self {
611            Architecture::X86_64(x86_64) => x86_64.cycle(),
612            Architecture::I386(i386) => i386.cycle(),
613            Architecture::Riscv(riscv) => riscv.cycle(),
614            Architecture::Arm(arm) => arm.cycle(),
615            Architecture::Aarch64(aarch64) => aarch64.cycle(),
616        }
617    }
618
619    fn get_magic_index_selector(&mut self) -> Result<u64> {
620        match self {
621            Architecture::X86_64(x86_64) => x86_64.get_magic_index_selector(),
622            Architecture::I386(i386) => i386.get_magic_index_selector(),
623            Architecture::Riscv(riscv) => riscv.get_magic_index_selector(),
624            Architecture::Arm(arm) => arm.get_magic_index_selector(),
625            Architecture::Aarch64(aarch64) => aarch64.get_magic_index_selector(),
626        }
627    }
628
629    fn get_magic_start_buffer_ptr_size_ptr(&mut self) -> Result<StartInfo> {
630        match self {
631            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_ptr(),
632            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_ptr(),
633            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_ptr(),
634            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_ptr(),
635            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_ptr(),
636        }
637    }
638
639    fn get_magic_start_buffer_ptr_size_val(&mut self) -> Result<StartInfo> {
640        match self {
641            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_val(),
642            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_val(),
643            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_val(),
644            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_val(),
645            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_val(),
646        }
647    }
648
649    fn get_magic_start_buffer_ptr_size_ptr_val(&mut self) -> Result<StartInfo> {
650        match self {
651            Architecture::X86_64(x86_64) => x86_64.get_magic_start_buffer_ptr_size_ptr(),
652            Architecture::I386(i386) => i386.get_magic_start_buffer_ptr_size_ptr(),
653            Architecture::Riscv(riscv) => riscv.get_magic_start_buffer_ptr_size_ptr(),
654            Architecture::Arm(arm) => arm.get_magic_start_buffer_ptr_size_ptr_val(),
655            Architecture::Aarch64(aarch64) => aarch64.get_magic_start_buffer_ptr_size_ptr_val(),
656        }
657    }
658
659    fn get_manual_start_info(&mut self, info: &ManualStartInfo) -> Result<StartInfo> {
660        match self {
661            Architecture::X86_64(x86_64) => x86_64.get_manual_start_info(info),
662            Architecture::I386(i386) => i386.get_manual_start_info(info),
663            Architecture::Riscv(riscv) => riscv.get_manual_start_info(info),
664            Architecture::Arm(arm) => arm.get_manual_start_info(info),
665            Architecture::Aarch64(aarch64) => aarch64.get_manual_start_info(info),
666        }
667    }
668
669    fn write_start(&mut self, testcase: &[u8], info: &StartInfo) -> Result<()> {
670        match self {
671            Architecture::X86_64(x86_64) => x86_64.write_start(testcase, info),
672            Architecture::I386(i386) => i386.write_start(testcase, info),
673            Architecture::Riscv(riscv) => riscv.write_start(testcase, info),
674            Architecture::Arm(arm) => arm.write_start(testcase, info),
675            Architecture::Aarch64(aarch64) => aarch64.write_start(testcase, info),
676        }
677    }
678
679    fn trace_pc(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
680        match self {
681            Architecture::X86_64(x86_64) => x86_64.trace_pc(instruction_query),
682            Architecture::I386(i386) => i386.trace_pc(instruction_query),
683            Architecture::Riscv(riscv) => riscv.trace_pc(instruction_query),
684            Architecture::Arm(arm) => arm.trace_pc(instruction_query),
685            Architecture::Aarch64(aarch64) => aarch64.trace_pc(instruction_query),
686        }
687    }
688
689    fn trace_cmp(&mut self, instruction_query: *mut instruction_handle_t) -> Result<TraceEntry> {
690        match self {
691            Architecture::X86_64(x86_64) => x86_64.trace_cmp(instruction_query),
692            Architecture::I386(i386) => i386.trace_cmp(instruction_query),
693            Architecture::Riscv(riscv) => riscv.trace_cmp(instruction_query),
694            Architecture::Arm(arm) => arm.trace_cmp(instruction_query),
695            Architecture::Aarch64(aarch64) => aarch64.trace_cmp(instruction_query),
696        }
697    }
698}