1use 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)]
35pub(crate) enum ArchitectureHint {
37 X86_64,
39 I386,
41 Riscv,
43 Arm,
45 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 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 X86_64(X86_64ArchitectureOperations),
103 I386(X86ArchitectureOperations),
105 Riscv(RISCVArchitectureOperations),
107 Arm(ARMArchitectureOperations),
109 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}
128pub 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 fn new(cpu: *mut ConfObject) -> Result<Self>
138 where
139 Self: Sized;
140
141 fn new_unchecked(_: *mut ConfObject) -> Result<Self>
143 where
144 Self: Sized,
145 {
146 bail!("Invalid CPU");
147 }
148
149 fn cpu(&self) -> *mut ConfObject;
151
152 fn disassembler(&mut self) -> &mut dyn TracerDisassembler;
154
155 fn int_register(&mut self) -> &mut IntRegisterInterface;
157
158 fn processor_info_v2(&mut self) -> &mut ProcessorInfoV2Interface;
160
161 fn cpu_instruction_query(&mut self) -> &mut CpuInstructionQueryInterface;
163
164 fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface;
166
167 fn cycle(&mut self) -> &mut CycleInterface;
169
170 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 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 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 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 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 .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 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}