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