1#![expect(missing_docs)] use crate::{
3 MemoryInterface, MemoryMappedRegister,
4 architecture::arm::{
5 ArmDebugInterface, ArmError, DapAccess, FullyQualifiedApAddress, RawDapAccess,
6 RegisterAddress, SwoAccess,
7 ap::memory_ap::mock::MockMemoryAp,
8 armv8m::Dhcsr,
9 communication_interface::{DapProbe, SwdSequence},
10 dp::{DpAddress, DpRegisterAddress},
11 memory::{ADIMemoryInterface, ArmMemoryInterface},
12 sequences::ArmDebugSequence,
13 },
14 probe::{DebugProbe, DebugProbeError, Probe, WireProtocol},
15};
16use object::{
17 Endianness, Object, ObjectSection,
18 elf::{FileHeader32, FileHeader64, PT_LOAD},
19 read::elf::{ElfFile, FileHeader, ProgramHeader},
20};
21use probe_rs_target::MemoryRange;
22use std::{
23 cell::RefCell,
24 collections::{BTreeSet, VecDeque},
25 fmt::Debug,
26 path::Path,
27 sync::Arc,
28};
29
30#[expect(clippy::type_complexity)]
32pub struct FakeProbe {
33 protocol: WireProtocol,
34 speed: u32,
35
36 dap_register_read_handler: Option<Box<dyn Fn(RegisterAddress) -> Result<u32, ArmError> + Send>>,
37
38 dap_register_write_handler:
39 Option<Box<dyn Fn(RegisterAddress, u32) -> Result<(), ArmError> + Send>>,
40
41 operations: RefCell<VecDeque<Operation>>,
42
43 memory_ap: MockedAp,
44}
45
46enum MockedAp {
47 MemoryAp(MockMemoryAp),
49 Core(MockCore),
51}
52
53struct LoadableSegment {
54 physical_address: u64,
55 offset: u64,
56 size: u64,
57}
58
59impl LoadableSegment {
60 fn contains(&self, physical_address: u64, len: u64) -> bool {
61 physical_address >= self.physical_address
62 && physical_address < (self.physical_address + self.size - len)
63 }
64
65 fn load_addr(&self, physical_address: u64) -> u64 {
66 let offset_in_segment = physical_address - self.physical_address;
67 self.offset + offset_in_segment
68 }
69}
70
71struct MockCore {
72 dhcsr: Dhcsr,
73
74 is_halted: bool,
76
77 program_binary: Option<Vec<u8>>,
78 loadable_segments: Vec<LoadableSegment>,
79 endianness: Endianness,
80}
81
82impl MockCore {
83 pub fn new() -> Self {
84 Self {
85 dhcsr: Dhcsr(0),
86 is_halted: false,
87 program_binary: None,
88 loadable_segments: Vec::new(),
89 endianness: Endianness::Little,
90 }
91 }
92}
93
94impl SwdSequence for &mut MockCore {
95 fn swj_sequence(&mut self, _bit_len: u8, _bits: u64) -> Result<(), DebugProbeError> {
96 todo!()
97 }
98
99 fn swj_pins(
100 &mut self,
101 _pin_out: u32,
102 _pin_select: u32,
103 _pin_wait: u32,
104 ) -> Result<u32, DebugProbeError> {
105 todo!()
106 }
107}
108
109impl MemoryInterface<ArmError> for &mut MockCore {
110 fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), ArmError> {
111 let mut curr_seg: Option<&LoadableSegment> = None;
112
113 for (offset, val) in data.iter_mut().enumerate() {
114 let address = address + offset as u64;
115 println!("Read {address:#010x} = 0");
116
117 match self.program_binary {
118 Some(ref program_binary) => {
119 if !curr_seg.is_some_and(|seg| seg.contains(address, 1)) {
120 curr_seg = self
121 .loadable_segments
122 .iter()
123 .find(|&seg| seg.contains(address, 1));
124 }
125 match curr_seg {
126 Some(seg) => {
127 *val = program_binary[seg.load_addr(address) as usize];
128 }
129 None => *val = 0,
130 }
131 }
132 None => *val = 0,
133 }
134 }
135
136 Ok(())
137 }
138
139 fn read_16(&mut self, _address: u64, _data: &mut [u16]) -> Result<(), ArmError> {
140 todo!()
141 }
142
143 fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), ArmError> {
144 let mut curr_seg: Option<&LoadableSegment> = None;
145
146 for (offset, val) in data.iter_mut().enumerate() {
147 const U32_BYTES: usize = 4;
148 let address = address + (offset * U32_BYTES) as u64;
149
150 match address {
151 Dhcsr::ADDRESS_OFFSET => {
153 let mut dhcsr: u32 = self.dhcsr.into();
154
155 if self.is_halted {
156 dhcsr |= 1 << 17;
157 }
158
159 dhcsr |= 1 << 16;
162
163 *val = dhcsr;
164 println!("Read DHCSR: {address:#x} = {val:#x}");
165 }
166
167 address => {
168 println!("Read {address:#010x} = 0");
169
170 match self.program_binary {
171 Some(ref program_binary) => {
172 if !curr_seg.is_some_and(|seg| seg.contains(address, U32_BYTES as u64))
173 {
174 curr_seg = self
175 .loadable_segments
176 .iter()
177 .find(|&seg| seg.contains(address, U32_BYTES as u64));
178 }
179 match curr_seg {
180 Some(seg) => {
181 let from = seg.load_addr(address) as usize;
182 let to = from + U32_BYTES;
183
184 let u32_as_bytes: [u8; U32_BYTES] =
185 program_binary[from..to].try_into().unwrap();
186
187 *val = if self.endianness == Endianness::Little {
189 u32::from_le_bytes(u32_as_bytes)
190 } else {
191 u32::from_be_bytes(u32_as_bytes)
192 };
193 }
194 None => *val = 0,
195 }
196 }
197 None => *val = 0,
198 }
199 }
200 }
201 }
202
203 Ok(())
204 }
205
206 fn read_64(&mut self, _address: u64, _data: &mut [u64]) -> Result<(), ArmError> {
207 todo!()
208 }
209
210 fn write_8(&mut self, _address: u64, _data: &[u8]) -> Result<(), ArmError> {
211 todo!()
212 }
213
214 fn write_16(&mut self, _address: u64, _data: &[u16]) -> Result<(), ArmError> {
215 todo!()
216 }
217
218 fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), ArmError> {
219 for (i, word) in data.iter().enumerate() {
220 let address = address + (i as u64 * 4);
221
222 match address {
223 Dhcsr::ADDRESS_OFFSET => {
225 let dbg_key = (*word >> 16) & 0xffff;
226
227 if dbg_key == 0xa05f {
228 self.dhcsr = Dhcsr::from(*word & 0xffff);
230 println!("Write DHCSR = {word:#010x}");
231
232 let request_halt = self.dhcsr.c_halt();
233
234 self.is_halted = request_halt;
235
236 if !self.dhcsr.c_halt() && self.dhcsr.c_debugen() && self.dhcsr.c_step() {
237 tracing::debug!("MockCore: Single step requested, setting s_halt");
238 self.is_halted = true;
239 }
240 }
241 }
242 _ => println!("Write {address:#010x} = {word:#010x}"),
243 }
244 }
245
246 Ok(())
247 }
248
249 fn write_64(&mut self, _address: u64, _data: &[u64]) -> Result<(), ArmError> {
250 todo!()
251 }
252
253 fn flush(&mut self) -> Result<(), ArmError> {
254 Ok(())
255 }
256
257 fn supports_native_64bit_access(&mut self) -> bool {
258 true
259 }
260
261 fn supports_8bit_transfers(&self) -> Result<bool, ArmError> {
262 todo!()
263 }
264}
265
266impl ArmMemoryInterface for &mut MockCore {
267 fn base_address(&mut self) -> Result<u64, ArmError> {
268 todo!()
269 }
270
271 fn fully_qualified_address(&self) -> FullyQualifiedApAddress {
272 todo!()
273 }
274
275 fn get_arm_debug_interface(&mut self) -> Result<&mut dyn ArmDebugInterface, DebugProbeError> {
276 todo!()
277 }
278
279 fn generic_status(&mut self) -> Result<crate::architecture::arm::ap::CSW, ArmError> {
280 todo!()
281 }
282
283 fn update_core_status(&mut self, _state: crate::CoreStatus) {}
284}
285
286#[derive(Debug, Clone, PartialEq)]
287pub enum Operation {
288 ReadRawApRegister {
289 ap: FullyQualifiedApAddress,
290 address: u64,
291 result: u32,
292 },
293}
294
295impl Debug for FakeProbe {
296 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297 f.debug_struct("FakeProbe")
298 .field("protocol", &self.protocol)
299 .field("speed", &self.speed)
300 .finish_non_exhaustive()
301 }
302}
303
304impl FakeProbe {
305 pub fn new() -> Self {
307 FakeProbe {
308 protocol: WireProtocol::Swd,
309 speed: 1000,
310
311 dap_register_read_handler: None,
312 dap_register_write_handler: None,
313
314 operations: RefCell::new(VecDeque::new()),
315
316 memory_ap: MockedAp::MemoryAp(MockMemoryAp::with_pattern()),
317 }
318 }
319
320 pub fn with_mocked_core() -> Self {
322 FakeProbe {
323 memory_ap: MockedAp::Core(MockCore::new()),
324 ..Self::default()
325 }
326 }
327
328 pub fn with_mocked_core_and_binary(program_binary: &Path) -> Self {
331 let file_data = std::fs::read(program_binary).unwrap();
332 let file_data_slice = file_data.as_slice();
333
334 let file_kind = object::FileKind::parse(file_data.as_slice()).unwrap();
335 let core = match file_kind {
336 object::FileKind::Elf32 => core_with_binary(
337 object::read::elf::ElfFile::<FileHeader32<Endianness>>::parse(file_data_slice)
338 .unwrap(),
339 ),
340 object::FileKind::Elf64 => core_with_binary(
341 object::read::elf::ElfFile::<FileHeader64<Endianness>>::parse(file_data_slice)
342 .unwrap(),
343 ),
344 _ => {
345 unimplemented!("unsupported file format")
346 }
347 };
348
349 FakeProbe {
350 memory_ap: MockedAp::Core(core),
351 ..Self::default()
352 }
353 }
354
355 pub fn set_dap_register_read_handler(
358 &mut self,
359 handler: Box<dyn Fn(RegisterAddress) -> Result<u32, ArmError> + Send>,
360 ) {
361 self.dap_register_read_handler = Some(handler);
362 }
363
364 pub fn set_dap_register_write_handler(
367 &mut self,
368 handler: Box<dyn Fn(RegisterAddress, u32) -> Result<(), ArmError> + Send>,
369 ) {
370 self.dap_register_write_handler = Some(handler);
371 }
372
373 pub fn into_probe(self) -> Probe {
375 Probe::from_specific_probe(Box::new(self))
376 }
377
378 fn next_operation(&self) -> Option<Operation> {
379 self.operations.borrow_mut().pop_front()
380 }
381
382 fn read_raw_ap_register(
383 &mut self,
384 expected_ap: &FullyQualifiedApAddress,
385 expected_address: u64,
386 ) -> Result<u32, ArmError> {
387 let operation = self.next_operation();
388
389 match operation {
390 Some(Operation::ReadRawApRegister {
391 ap,
392 address,
393 result,
394 }) => {
395 assert_eq!(&ap, expected_ap);
396 assert_eq!(address, expected_address);
397
398 Ok(result)
399 }
400 None => panic!(
401 "No more operations expected, but got read_raw_ap_register ap={expected_ap:?}, address:{expected_address}"
402 ),
403 }
405 }
406
407 pub fn expect_operation(&self, operation: Operation) {
408 self.operations.borrow_mut().push_back(operation);
409 }
410}
411
412fn core_with_binary<T: FileHeader>(elf_file: ElfFile<T>) -> MockCore {
413 let elf_header = elf_file.elf_header();
414 let elf_data = elf_file.data();
415 let endian = elf_header.endian().unwrap();
416
417 let mut loadable_sections = Vec::new();
418 for segment in elf_header.program_headers(endian, elf_data).unwrap() {
419 let physical_address = segment.p_paddr(endian).into();
420 let segment_data = segment.data(endian, elf_data).unwrap();
421
422 if !segment_data.is_empty() && segment.p_type(endian) == PT_LOAD {
423 let (segment_offset, segment_filesize) = segment.file_range(endian);
424 let segment_range = segment_offset..segment_offset + segment_filesize;
425
426 let mut found_section_in_segment = false;
427
428 for section in elf_file.sections() {
429 let (section_offset, section_filesize) = match section.file_range() {
430 Some(range) => range,
431 None => continue,
432 };
433
434 if segment_range
435 .contains_range(&(section_offset..section_offset + section_filesize))
436 {
437 found_section_in_segment = true;
438 break;
439 }
440 }
441
442 if found_section_in_segment {
443 loadable_sections.push(LoadableSegment {
444 physical_address,
445 offset: segment_offset,
446 size: segment_filesize,
447 });
448 }
449 }
450 }
451
452 let mut core = MockCore::new();
453 core.program_binary = Some(elf_data.to_owned());
454 core.loadable_segments = loadable_sections;
455 core.endianness = if elf_header.is_little_endian() {
456 Endianness::Little
457 } else {
458 Endianness::Big
459 };
460
461 core
462}
463
464impl Default for FakeProbe {
465 fn default() -> Self {
466 FakeProbe::new()
467 }
468}
469
470impl DebugProbe for FakeProbe {
471 fn get_name(&self) -> &str {
473 "Mock probe for testing"
474 }
475
476 fn speed_khz(&self) -> u32 {
477 self.speed
478 }
479
480 fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
481 self.speed = speed_khz;
482
483 Ok(speed_khz)
484 }
485
486 fn attach(&mut self) -> Result<(), DebugProbeError> {
487 Ok(())
488 }
489
490 fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
491 self.protocol = protocol;
492
493 Ok(())
494 }
495
496 fn active_protocol(&self) -> Option<WireProtocol> {
497 Some(self.protocol)
498 }
499
500 fn detach(&mut self) -> Result<(), crate::Error> {
502 Ok(())
503 }
504
505 fn target_reset(&mut self) -> Result<(), DebugProbeError> {
507 Err(DebugProbeError::CommandNotSupportedByProbe {
508 command_name: "target_reset",
509 })
510 }
511
512 fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
513 unimplemented!()
514 }
515
516 fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
517 Ok(())
518 }
519
520 fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
521 self
522 }
523
524 fn try_get_arm_debug_interface<'probe>(
525 self: Box<Self>,
526 sequence: Arc<dyn ArmDebugSequence>,
527 ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
528 Ok(Box::new(FakeArmInterface::new(self, sequence)))
529 }
530
531 fn has_arm_interface(&self) -> bool {
532 true
533 }
534}
535
536impl RawDapAccess for FakeProbe {
537 fn raw_read_register(&mut self, address: RegisterAddress) -> Result<u32, ArmError> {
539 let handler = self.dap_register_read_handler.as_ref().unwrap();
540
541 handler(address)
542 }
543
544 fn raw_write_register(&mut self, address: RegisterAddress, value: u32) -> Result<(), ArmError> {
546 let handler = self.dap_register_write_handler.as_ref().unwrap();
547
548 handler(address, value)
549 }
550
551 fn jtag_sequence(&mut self, _cycles: u8, _tms: bool, _tdi: u64) -> Result<(), DebugProbeError> {
552 todo!()
553 }
554
555 fn swj_sequence(&mut self, _bit_len: u8, _bits: u64) -> Result<(), DebugProbeError> {
556 todo!()
557 }
558
559 fn swj_pins(
560 &mut self,
561 _pin_out: u32,
562 _pin_select: u32,
563 _pin_wait: u32,
564 ) -> Result<u32, DebugProbeError> {
565 todo!()
566 }
567
568 fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
569 self
570 }
571
572 fn core_status_notification(&mut self, _: crate::CoreStatus) -> Result<(), DebugProbeError> {
573 Ok(())
574 }
575}
576
577#[derive(Debug)]
578struct FakeArmInterface {
579 probe: Box<FakeProbe>,
580 current_dp: Option<DpAddress>,
581}
582
583impl FakeArmInterface {
584 pub(crate) fn new(probe: Box<FakeProbe>, _sequence: Arc<dyn ArmDebugSequence>) -> Self {
585 FakeArmInterface {
586 probe,
587 current_dp: None,
588 }
589 }
590}
591
592impl SwdSequence for FakeArmInterface {
593 fn swj_sequence(&mut self, bit_len: u8, bits: u64) -> Result<(), DebugProbeError> {
594 self.probe.swj_sequence(bit_len, bits)?;
595
596 Ok(())
597 }
598
599 fn swj_pins(
600 &mut self,
601 pin_out: u32,
602 pin_select: u32,
603 pin_wait: u32,
604 ) -> Result<u32, DebugProbeError> {
605 let value = self.probe.swj_pins(pin_out, pin_select, pin_wait)?;
606
607 Ok(value)
608 }
609}
610
611impl ArmDebugInterface for FakeArmInterface {
612 fn memory_interface(
613 &mut self,
614 access_port_address: &FullyQualifiedApAddress,
615 ) -> Result<Box<dyn ArmMemoryInterface + '_>, ArmError> {
616 match self.probe.memory_ap {
617 MockedAp::MemoryAp(ref mut _memory_ap) => {
618 let memory = ADIMemoryInterface::new(self, access_port_address)?;
619
620 Ok(Box::new(memory) as _)
621 }
622 MockedAp::Core(ref mut core) => Ok(Box::new(core) as _),
623 }
624 }
625
626 fn access_ports(
627 &mut self,
628 dp: DpAddress,
629 ) -> Result<BTreeSet<FullyQualifiedApAddress>, ArmError> {
630 Ok(BTreeSet::from([FullyQualifiedApAddress::v1_with_dp(dp, 1)]))
631 }
632
633 fn close(self: Box<Self>) -> Probe {
634 Probe::from_attached_probe(self.probe)
635 }
636
637 fn current_debug_port(&self) -> Option<DpAddress> {
638 self.current_dp
639 }
640
641 fn select_debug_port(&mut self, dp: DpAddress) -> Result<(), ArmError> {
642 self.current_dp = Some(dp);
643 Ok(())
644 }
645
646 fn reinitialize(&mut self) -> Result<(), ArmError> {
647 Ok(())
648 }
649}
650
651impl SwoAccess for FakeArmInterface {
652 fn enable_swo(
653 &mut self,
654 _config: &crate::architecture::arm::SwoConfig,
655 ) -> Result<(), ArmError> {
656 unimplemented!()
657 }
658
659 fn disable_swo(&mut self) -> Result<(), ArmError> {
660 unimplemented!()
661 }
662
663 fn read_swo_timeout(&mut self, _timeout: std::time::Duration) -> Result<Vec<u8>, ArmError> {
664 unimplemented!()
665 }
666}
667
668impl DapAccess for FakeArmInterface {
669 fn read_raw_dp_register(
670 &mut self,
671 _dp: DpAddress,
672 _address: DpRegisterAddress,
673 ) -> Result<u32, ArmError> {
674 todo!()
675 }
676
677 fn write_raw_dp_register(
678 &mut self,
679 _dp: DpAddress,
680 _address: DpRegisterAddress,
681 _value: u32,
682 ) -> Result<(), ArmError> {
683 todo!()
684 }
685
686 fn read_raw_ap_register(
687 &mut self,
688 _ap: &FullyQualifiedApAddress,
689 _address: u64,
690 ) -> Result<u32, ArmError> {
691 self.probe.read_raw_ap_register(_ap, _address)
692 }
693
694 fn read_raw_ap_register_repeated(
695 &mut self,
696 _ap: &FullyQualifiedApAddress,
697 _address: u64,
698 _values: &mut [u32],
699 ) -> Result<(), ArmError> {
700 todo!()
701 }
702
703 fn write_raw_ap_register(
704 &mut self,
705 _ap: &FullyQualifiedApAddress,
706 _address: u64,
707 _value: u32,
708 ) -> Result<(), ArmError> {
709 todo!()
710 }
711
712 fn write_raw_ap_register_repeated(
713 &mut self,
714 _ap: &FullyQualifiedApAddress,
715 _address: u64,
716 _values: &[u32],
717 ) -> Result<(), ArmError> {
718 todo!()
719 }
720
721 fn try_dap_probe(&self) -> Option<&dyn DapProbe> {
722 None
723 }
724
725 fn try_dap_probe_mut(&mut self) -> Option<&mut dyn DapProbe> {
726 None
727 }
728}
729
730#[cfg(all(test, feature = "builtin-targets"))]
731mod test {
732 use super::FakeProbe;
733 use crate::Permissions;
734
735 #[test]
736 fn create_session_with_fake_probe() {
737 let fake_probe = FakeProbe::with_mocked_core();
738
739 let probe = fake_probe.into_probe();
740
741 probe
742 .attach("nrf51822_xxAC", Permissions::default())
743 .unwrap();
744 }
745}