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 #[allow(dead_code)]
166 fn cpu_instrumentation_subscribe(&mut self) -> &mut CpuInstrumentationSubscribeInterface;
167
168 fn cycle(&mut self) -> &mut CycleInterface;
170
171 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 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 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 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 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 .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 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}