1use crate::{
2 Core, CoreType, Error,
3 architecture::{
4 arm::{
5 ArmError, SwoReader,
6 communication_interface::ArmDebugInterface,
7 component::{TraceSink, get_arm_components},
8 dp::DpAddress,
9 memory::CoresightComponent,
10 sequences::{ArmDebugSequence, DefaultArmSequence},
11 },
12 riscv::communication_interface::{
13 RiscvCommunicationInterface, RiscvDebugInterfaceState, RiscvError,
14 },
15 xtensa::communication_interface::{
16 XtensaCommunicationInterface, XtensaDebugInterfaceState, XtensaError,
17 },
18 },
19 config::{CoreExt, DebugSequence, RegistryError, Target, TargetSelector, registry::Registry},
20 core::{Architecture, CombinedCoreState},
21 probe::{
22 AttachMethod, DebugProbeError, Probe, ProbeCreationError, WireProtocol,
23 fake_probe::FakeProbe, list::Lister,
24 },
25};
26use std::ops::DerefMut;
27use std::{fmt, sync::Arc, time::Duration};
28
29#[derive(Debug)]
48pub struct Session {
49 target: Target,
50 interfaces: ArchitectureInterface,
51 cores: Vec<CombinedCoreState>,
52 configured_trace_sink: Option<TraceSink>,
53}
54
55#[derive(Default, Debug)]
63pub struct SessionConfig {
64 pub permissions: Permissions,
66 pub speed: Option<u32>,
68 pub protocol: Option<WireProtocol>,
70}
71
72enum JtagInterface {
73 Riscv(RiscvDebugInterfaceState),
74 Xtensa(XtensaDebugInterfaceState),
75 Unknown,
76}
77
78impl JtagInterface {
79 fn architecture(&self) -> Option<Architecture> {
81 match self {
82 JtagInterface::Riscv(_) => Some(Architecture::Riscv),
83 JtagInterface::Xtensa(_) => Some(Architecture::Xtensa),
84 JtagInterface::Unknown => None,
85 }
86 }
87}
88
89impl fmt::Debug for JtagInterface {
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 match self {
92 JtagInterface::Riscv(_) => f.write_str("Riscv(..)"),
93 JtagInterface::Xtensa(_) => f.write_str("Xtensa(..)"),
94 JtagInterface::Unknown => f.write_str("Unknown"),
95 }
96 }
97}
98
99enum ArchitectureInterface {
101 Arm(Box<dyn ArmDebugInterface + 'static>),
102 Jtag(Probe, Vec<JtagInterface>),
103}
104
105impl fmt::Debug for ArchitectureInterface {
106 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107 match self {
108 ArchitectureInterface::Arm(_) => f.write_str("ArchitectureInterface::Arm(..)"),
109 ArchitectureInterface::Jtag(_, ifaces) => f
110 .debug_tuple("ArchitectureInterface::Jtag(..)")
111 .field(ifaces)
112 .finish(),
113 }
114 }
115}
116
117impl ArchitectureInterface {
118 fn attach<'probe, 'target: 'probe>(
119 &'probe mut self,
120 target: &'probe Target,
121 combined_state: &'probe mut CombinedCoreState,
122 ) -> Result<Core<'probe>, Error> {
123 match self {
124 ArchitectureInterface::Arm(interface) => combined_state.attach_arm(target, interface),
125 ArchitectureInterface::Jtag(probe, ifaces) => {
126 let idx = combined_state.jtag_tap_index();
127 if let Some(probe) = probe.try_as_jtag_probe() {
128 probe.select_target(idx)?;
129 }
130 match &mut ifaces[idx] {
131 JtagInterface::Riscv(state) => {
132 let factory = probe.try_get_riscv_interface_builder()?;
133 let iface = factory.attach_auto(target, state)?;
134 combined_state.attach_riscv(target, iface)
135 }
136 JtagInterface::Xtensa(state) => {
137 let iface = probe.try_get_xtensa_interface(state)?;
138 combined_state.attach_xtensa(target, iface)
139 }
140 JtagInterface::Unknown => {
141 unreachable!(
142 "Tried to attach to unknown interface {idx}. This should never happen."
143 )
144 }
145 }
146 }
147 }
148 }
149}
150
151impl Session {
152 pub(crate) fn new(
154 probe: Probe,
155 target: TargetSelector,
156 attach_method: AttachMethod,
157 permissions: Permissions,
158 registry: &Registry,
159 ) -> Result<Self, Error> {
160 let (probe, target) = get_target_from_selector(target, attach_method, probe, registry)?;
161
162 let cores = target
163 .cores
164 .iter()
165 .enumerate()
166 .map(|(id, core)| {
167 Core::create_state(
168 id,
169 core.core_access_options.clone(),
170 &target,
171 core.core_type,
172 )
173 })
174 .collect();
175
176 let mut session = if let Architecture::Arm = target.architecture() {
177 Self::attach_arm_debug_interface(probe, target, attach_method, permissions, cores)?
178 } else {
179 Self::attach_jtag(probe, target, attach_method, permissions, cores)?
180 };
181
182 session.clear_all_hw_breakpoints()?;
183
184 Ok(session)
185 }
186
187 fn attach_arm_debug_interface(
188 mut probe: Probe,
189 target: Target,
190 attach_method: AttachMethod,
191 permissions: Permissions,
192 cores: Vec<CombinedCoreState>,
193 ) -> Result<Self, Error> {
194 let default_core = target.default_core();
195
196 let default_memory_ap = default_core.memory_ap().ok_or_else(|| {
197 Error::Other(format!(
198 "Unable to connect to core {default_core:?}, no memory AP configured"
199 ))
200 })?;
201
202 let default_dp = default_memory_ap.dp();
203
204 let sequence_handle = match &target.debug_sequence {
205 DebugSequence::Arm(sequence) => sequence.clone(),
206 _ => unreachable!("Mismatch between architecture and sequence type!"),
207 };
208
209 if AttachMethod::UnderReset == attach_method {
210 let _span = tracing::debug_span!("Asserting hardware reset").entered();
211
212 if let Some(dap_probe) = probe.try_as_dap_probe() {
213 sequence_handle.reset_hardware_assert(dap_probe)?;
214 } else {
215 tracing::info!(
216 "Custom reset sequences are not supported on {}.",
217 probe.get_name()
218 );
219 tracing::info!("Falling back to standard probe reset.");
220 probe.target_reset_assert()?;
221 }
222 }
223
224 if let Some(jtag) = target.jtag.as_ref()
225 && let Some(scan_chain) = jtag.scan_chain.clone()
226 && let Some(probe) = probe.try_as_jtag_probe()
227 {
228 probe.set_scan_chain(&scan_chain)?;
229 }
230
231 probe.attach_to_unspecified()?;
232 if probe.protocol() == Some(WireProtocol::Jtag)
233 && let Some(probe) = probe.try_as_jtag_probe()
234 && let Ok(chain) = probe.scan_chain()
235 && !chain.is_empty()
236 {
237 for core in &cores {
238 probe.select_target(core.jtag_tap_index())?;
239 }
240 }
241
242 let mut interface = probe
243 .try_into_arm_debug_interface(sequence_handle.clone())
244 .map_err(|(_, err)| err)?;
245
246 interface.select_debug_port(default_dp)?;
247
248 let unlock_span = tracing::debug_span!("debug_device_unlock").entered();
249
250 let unlock_res =
252 sequence_handle.debug_device_unlock(&mut *interface, &default_memory_ap, &permissions);
253 drop(unlock_span);
254
255 match unlock_res {
256 Ok(()) => (),
257 Err(ArmError::ReAttachRequired) => {
259 Self::reattach_arm_interface(&mut interface, &sequence_handle)?;
260 }
261 Err(e) => return Err(Error::Arm(e)),
262 }
263
264 if attach_method == AttachMethod::UnderReset {
265 {
266 for core in &cores {
267 core.arm_reset_catch_set(&mut *interface)?;
268 }
269
270 let reset_hardware_deassert =
271 tracing::debug_span!("reset_hardware_deassert").entered();
272
273 if let Err(e) =
275 sequence_handle.reset_hardware_deassert(&mut *interface, &default_memory_ap)
276 {
277 if matches!(e, ArmError::Timeout) {
278 tracing::warn!(
279 "Timeout while deasserting hardware reset pin. This indicates that the reset pin is not properly connected. Please check your hardware setup."
280 );
281 }
282
283 return Err(e.into());
284 }
285 drop(reset_hardware_deassert);
286 }
287
288 for core in &cores {
291 core.enable_arm_debug(&mut *interface)?;
292 }
293
294 let mut session = Session {
295 target,
296 interfaces: ArchitectureInterface::Arm(interface),
297 cores,
298 configured_trace_sink: None,
299 };
300
301 {
302 for core_id in 0..session.cores.len() {
307 let mut core = session
308 .core(core_id)
309 .inspect_err(|e| tracing::error!("Unable to get core {core_id}: {e}"))?;
310
311 core.wait_for_core_halted(Duration::from_millis(100))
312 .inspect_err(|e| {
313 tracing::error!("Unable to wait for {core_id} halted: {e}")
314 })?;
315
316 core.reset_catch_clear().inspect_err(|e| {
317 tracing::error!("Unable to clear catch for {core_id} : {e}")
318 })?;
319 }
320 }
321
322 Ok(session)
323 } else {
324 for core in &cores {
326 core.enable_arm_debug(&mut *interface)?;
327 }
328
329 Ok(Session {
330 target,
331 interfaces: ArchitectureInterface::Arm(interface),
332 cores,
333 configured_trace_sink: None,
334 })
335 }
336 }
337
338 fn attach_jtag(
339 mut probe: Probe,
340 target: Target,
341 _attach_method: AttachMethod,
342 _permissions: Permissions,
343 cores: Vec<CombinedCoreState>,
344 ) -> Result<Self, Error> {
345 if let Some(jtag) = target.jtag.as_ref()
349 && let Some(scan_chain) = jtag.scan_chain.clone()
350 && let Some(probe) = probe.try_as_jtag_probe()
351 {
352 probe.set_scan_chain(&scan_chain)?;
353 }
354
355 probe.attach_to_unspecified()?;
356 if let Some(probe) = probe.try_as_jtag_probe()
357 && let Ok(chain) = probe.scan_chain()
358 && !chain.is_empty()
359 {
360 for core in &cores {
361 probe.select_target(core.jtag_tap_index())?;
362 }
363 }
364
365 let highest_idx = cores.iter().map(|c| c.jtag_tap_index()).max().unwrap_or(0);
372 let tap_count = if let Some(probe) = probe.try_as_jtag_probe() {
373 match probe.scan_chain() {
374 Ok(scan_chain) => scan_chain.len().max(highest_idx + 1),
375 Err(_) => highest_idx + 1,
376 }
377 } else {
378 highest_idx + 1
379 };
380 let mut interfaces = std::iter::repeat_with(|| JtagInterface::Unknown)
381 .take(tap_count)
382 .collect::<Vec<_>>();
383
384 for core in cores.iter() {
387 let iface_idx = core.jtag_tap_index();
388
389 let core_arch = core.core_type().architecture();
390
391 if let Some(debug_arch) = interfaces[iface_idx].architecture() {
392 if core_arch == debug_arch {
393 continue;
395 }
396 return Err(Error::Probe(DebugProbeError::Other(format!(
397 "{core_arch:?} core can not be mixed with a {debug_arch:?} debug module.",
398 ))));
399 }
400
401 interfaces[iface_idx] = match core_arch {
402 Architecture::Riscv => {
403 let factory = probe.try_get_riscv_interface_builder()?;
404 let mut state = factory.create_state();
405 {
406 let mut interface = factory.attach_auto(&target, &mut state)?;
407 interface.enter_debug_mode()?;
408 }
409
410 JtagInterface::Riscv(state)
411 }
412 Architecture::Xtensa => JtagInterface::Xtensa(XtensaDebugInterfaceState::default()),
413 _ => {
414 return Err(Error::Probe(DebugProbeError::Other(format!(
415 "Unsupported core architecture {core_arch:?}",
416 ))));
417 }
418 };
419 }
420
421 let interfaces = ArchitectureInterface::Jtag(probe, interfaces);
422
423 let mut session = Session {
424 target,
425 interfaces,
426 cores,
427 configured_trace_sink: None,
428 };
429
430 match session.target.debug_sequence.clone() {
432 DebugSequence::Xtensa(_) => {}
433
434 DebugSequence::Riscv(sequence) => {
435 for core_id in 0..session.cores.len() {
436 sequence.on_connect(&mut session.get_riscv_interface(core_id)?)?;
437 }
438 }
439 _ => unreachable!("Other architectures should have already been handled"),
440 };
441
442 Ok(session)
443 }
444
445 fn auto_probe(session_config: &SessionConfig) -> Result<Probe, Error> {
447 let lister = Lister::new();
449
450 let probes = lister.list_all();
451
452 let mut probe = probes
454 .first()
455 .ok_or(Error::Probe(DebugProbeError::ProbeCouldNotBeCreated(
456 ProbeCreationError::NotFound,
457 )))?
458 .open()?;
459
460 if let Some(speed) = session_config.speed {
462 probe.set_speed(speed)?;
463 }
464
465 if let Some(protocol) = session_config.protocol {
466 probe.select_protocol(protocol)?;
467 }
468 Ok(probe)
469 }
470
471 #[tracing::instrument(skip(target))]
473 pub fn auto_attach(
474 target: impl Into<TargetSelector>,
475 session_config: SessionConfig,
476 ) -> Result<Session, Error> {
477 Self::auto_probe(&session_config)?.attach(target, session_config.permissions)
479 }
480
481 #[tracing::instrument(skip(target, registry))]
484 pub fn auto_attach_with_registry(
485 target: impl Into<TargetSelector>,
486 session_config: SessionConfig,
487 registry: &Registry,
488 ) -> Result<Session, Error> {
489 Self::auto_probe(&session_config)?.attach_with_registry(
491 target,
492 session_config.permissions,
493 registry,
494 )
495 }
496
497 pub fn list_cores(&self) -> Vec<(usize, CoreType)> {
499 self.cores.iter().map(|t| (t.id(), t.core_type())).collect()
500 }
501
502 pub fn halted_access<R>(
506 &mut self,
507 f: impl FnOnce(&mut Self) -> Result<R, Error>,
508 ) -> Result<R, Error> {
509 let mut resume_state = vec![];
510 for (core, _) in self.list_cores() {
511 let mut c = match self.core(core) {
512 Err(Error::CoreDisabled(_)) => continue,
513 other => other?,
514 };
515 if c.core_halted()? {
516 tracing::info!("Core {core} already halted");
517 } else {
518 tracing::info!("Halting core {core}...");
519 resume_state.push(core);
520 c.halt(Duration::from_millis(100))?;
521 }
522 }
523
524 let r = f(self);
525
526 for core in resume_state {
527 tracing::debug!("Resuming core...");
528 self.core(core)?.run()?;
529 }
530
531 r
532 }
533
534 fn interface_idx(&self, core: usize) -> Result<usize, Error> {
535 self.cores
536 .get(core)
537 .map(|c| c.jtag_tap_index())
538 .ok_or(Error::CoreNotFound(core))
539 }
540
541 #[tracing::instrument(level = "trace", skip(self), name = "attach_to_core")]
558 pub fn core(&mut self, core_index: usize) -> Result<Core<'_>, Error> {
559 let combined_state = self
560 .cores
561 .get_mut(core_index)
562 .ok_or(Error::CoreNotFound(core_index))?;
563
564 self.interfaces
565 .attach(&self.target, combined_state)
566 .map_err(|e| {
567 if matches!(
568 e,
569 Error::Xtensa(XtensaError::CoreDisabled)
570 | Error::Riscv(RiscvError::HartUnavailable),
571 ) {
572 Error::CoreDisabled(core_index)
577 } else {
578 e
579 }
580 })
581 }
582
583 #[tracing::instrument(skip(self))]
588 pub fn read_trace_data(&mut self) -> Result<Vec<u8>, ArmError> {
589 let sink = self
590 .configured_trace_sink
591 .as_ref()
592 .ok_or(ArmError::TracingUnconfigured)?;
593
594 match sink {
595 TraceSink::Swo(_) => {
596 let interface = self.get_arm_interface()?;
597 interface.read_swo()
598 }
599
600 TraceSink::Tpiu(_) => {
601 panic!("Probe-rs does not yet support reading parallel trace ports");
602 }
603
604 TraceSink::TraceMemory => {
605 let components = self.get_arm_components(DpAddress::Default)?;
606 let interface = self.get_arm_interface()?;
607 crate::architecture::arm::component::read_trace_memory(interface, &components)
608 }
609 }
610 }
611
612 pub fn swo_reader(&mut self) -> Result<SwoReader<'_>, Error> {
621 let interface = self.get_arm_interface()?;
622 Ok(SwoReader::new(interface))
623 }
624
625 pub fn get_arm_interface(&mut self) -> Result<&mut dyn ArmDebugInterface, ArmError> {
627 let interface = match &mut self.interfaces {
628 ArchitectureInterface::Arm(state) => state.deref_mut(),
629 _ => return Err(ArmError::NoArmTarget),
630 };
631
632 Ok(interface)
633 }
634
635 pub fn get_riscv_interface(
637 &mut self,
638 core_id: usize,
639 ) -> Result<RiscvCommunicationInterface<'_>, Error> {
640 let tap_idx = self.interface_idx(core_id)?;
641 if let ArchitectureInterface::Jtag(probe, ifaces) = &mut self.interfaces {
642 if let Some(probe) = probe.try_as_jtag_probe() {
643 probe.select_target(tap_idx)?;
644 }
645 if let JtagInterface::Riscv(state) = &mut ifaces[tap_idx] {
646 let factory = probe.try_get_riscv_interface_builder()?;
647 return Ok(factory.attach_auto(&self.target, state)?);
648 }
649 }
650 Err(RiscvError::NoRiscvTarget.into())
651 }
652
653 pub fn get_xtensa_interface(
655 &mut self,
656 core_id: usize,
657 ) -> Result<XtensaCommunicationInterface<'_>, Error> {
658 let tap_idx = self.interface_idx(core_id)?;
659 if let ArchitectureInterface::Jtag(probe, ifaces) = &mut self.interfaces {
660 if let Some(probe) = probe.try_as_jtag_probe() {
661 probe.select_target(tap_idx)?;
662 }
663 if let JtagInterface::Xtensa(state) = &mut ifaces[tap_idx] {
664 return Ok(probe.try_get_xtensa_interface(state)?);
665 }
666 }
667 Err(XtensaError::NoXtensaTarget.into())
668 }
669
670 #[tracing::instrument(skip_all)]
671 fn reattach_arm_interface(
672 interface: &mut Box<dyn ArmDebugInterface>,
673 debug_sequence: &Arc<dyn ArmDebugSequence>,
674 ) -> Result<(), Error> {
675 use crate::probe::DebugProbe;
676
677 let current_dp = interface.current_debug_port();
678
679 let mut tmp_interface = Box::<FakeProbe>::default()
684 .try_get_arm_debug_interface(DefaultArmSequence::create())
685 .unwrap();
686
687 std::mem::swap(interface, &mut tmp_interface);
688
689 tracing::debug!("Re-attaching Probe");
690 let mut probe = tmp_interface.close();
691 probe.detach()?;
692 probe.attach_to_unspecified()?;
693
694 let mut new_interface = probe
695 .try_into_arm_debug_interface(debug_sequence.clone())
696 .map_err(|(_, err)| err)?;
697
698 if let Some(current_dp) = current_dp {
699 new_interface.select_debug_port(current_dp)?;
700 }
701 std::mem::swap(interface, &mut new_interface);
703
704 tracing::debug!("Probe re-attached");
705 Ok(())
706 }
707
708 pub fn prepare_running_on_ram(&mut self, vector_table_addr: u64) -> Result<(), crate::Error> {
710 match &self.target.debug_sequence.clone() {
711 crate::config::DebugSequence::Arm(arm) => {
712 arm.prepare_running_on_ram(vector_table_addr, self)
713 }
714 _ => Err(crate::Error::NotImplemented(
715 "ram flash non-ARM architectures",
716 )),
717 }
718 }
719
720 pub fn has_sequence_erase_all(&self) -> bool {
722 match &self.target.debug_sequence {
723 DebugSequence::Arm(seq) => seq.debug_erase_sequence().is_some(),
724 _ => false,
726 }
727 }
728
729 pub fn sequence_erase_all(&mut self) -> Result<(), Error> {
738 let ArchitectureInterface::Arm(ref mut interface) = self.interfaces else {
739 return Err(Error::NotImplemented(
740 "Debug Erase Sequence is not implemented for non-ARM targets.",
741 ));
742 };
743
744 let DebugSequence::Arm(ref debug_sequence) = self.target.debug_sequence else {
745 unreachable!("This should never happen. Please file a bug if it does.");
746 };
747
748 let erase_sequence = debug_sequence
749 .debug_erase_sequence()
750 .ok_or(Error::Arm(ArmError::NotImplemented("Debug Erase Sequence")))?;
751
752 tracing::info!("Trying Debug Erase Sequence");
753 let erase_result = erase_sequence.erase_all(interface.deref_mut());
754
755 match erase_result {
756 Ok(()) => (),
757 Err(ArmError::ReAttachRequired) => {
759 Self::reattach_arm_interface(interface, debug_sequence)?;
760 for core_state in &self.cores {
762 core_state.enable_arm_debug(interface.deref_mut())?;
763 }
764 }
765 Err(e) => return Err(Error::Arm(e)),
766 }
767 tracing::info!("Device Erased Successfully");
768 Ok(())
769 }
770
771 pub fn get_arm_components(
776 &mut self,
777 dp: DpAddress,
778 ) -> Result<Vec<CoresightComponent>, ArmError> {
779 let interface = self.get_arm_interface()?;
780
781 get_arm_components(interface, dp)
782 }
783
784 pub fn target(&self) -> &Target {
786 &self.target
787 }
788
789 pub fn setup_tracing(
791 &mut self,
792 core_index: usize,
793 destination: TraceSink,
794 ) -> Result<(), Error> {
795 {
797 let mut core = self.core(core_index)?;
798 crate::architecture::arm::component::enable_tracing(&mut core)?;
799 }
800
801 let sequence_handle = match &self.target.debug_sequence {
802 DebugSequence::Arm(sequence) => sequence.clone(),
803 _ => unreachable!("Mismatch between architecture and sequence type!"),
804 };
805
806 let components = self.get_arm_components(DpAddress::Default)?;
807 let interface = self.get_arm_interface()?;
808
809 match destination {
812 TraceSink::Swo(ref config) => {
813 interface.enable_swo(config)?;
814 }
815 TraceSink::Tpiu(ref config) => {
816 interface.enable_swo(config)?;
817 }
818 TraceSink::TraceMemory => {}
819 }
820
821 sequence_handle.trace_start(interface, &components, &destination)?;
822 crate::architecture::arm::component::setup_tracing(interface, &components, &destination)?;
823
824 self.configured_trace_sink.replace(destination);
825
826 Ok(())
827 }
828
829 #[tracing::instrument(skip(self))]
831 pub fn disable_swv(&mut self, core_index: usize) -> Result<(), Error> {
832 crate::architecture::arm::component::disable_swv(&mut self.core(core_index)?)
833 }
834
835 pub fn add_swv_data_trace(&mut self, unit: usize, address: u32) -> Result<(), ArmError> {
837 let components = self.get_arm_components(DpAddress::Default)?;
838 let interface = self.get_arm_interface()?;
839 crate::architecture::arm::component::add_swv_data_trace(
840 interface,
841 &components,
842 unit,
843 address,
844 )
845 }
846
847 pub fn remove_swv_data_trace(&mut self, unit: usize) -> Result<(), ArmError> {
849 let components = self.get_arm_components(DpAddress::Default)?;
850 let interface = self.get_arm_interface()?;
851 crate::architecture::arm::component::remove_swv_data_trace(interface, &components, unit)
852 }
853
854 pub fn architecture(&self) -> Architecture {
856 match &self.interfaces {
857 ArchitectureInterface::Arm(_) => Architecture::Arm,
858 ArchitectureInterface::Jtag(_, ifaces) => {
859 if let JtagInterface::Riscv(_) = &ifaces[0] {
860 Architecture::Riscv
861 } else {
862 Architecture::Xtensa
863 }
864 }
865 }
866 }
867
868 pub fn clear_all_hw_breakpoints(&mut self) -> Result<(), Error> {
870 self.halted_access(|session| {
871 { 0..session.cores.len() }.try_for_each(|core| {
872 tracing::info!("Clearing breakpoints for core {core}");
873
874 match session.core(core) {
875 Ok(mut core) => core.clear_all_hw_breakpoints(),
876 Err(Error::CoreDisabled(_)) => Ok(()),
877 Err(err) => Err(err),
878 }
879 })
880 })
881 }
882
883 pub fn resume_all_cores(&mut self) -> Result<(), Error> {
885 for core_id in 0..self.cores.len() {
887 match self.core(core_id) {
888 Ok(mut core) => {
889 if core.core_halted()? {
890 core.run()?;
891 }
892 }
893 Err(Error::CoreDisabled(i)) => tracing::debug!("Core {i} is disabled"),
894 Err(error) => return Err(error),
895 }
896 }
897
898 Ok(())
899 }
900}
901
902const _: fn() = || {
904 fn assert_impl_all<T: ?Sized + Send>() {}
905
906 assert_impl_all::<Session>();
907};
908
909impl Drop for Session {
910 #[tracing::instrument(name = "session_drop", skip(self))]
911 fn drop(&mut self) {
912 if let Err(err) = self.clear_all_hw_breakpoints() {
913 tracing::warn!(
914 "Could not clear all hardware breakpoints: {:?}",
915 anyhow::anyhow!(err)
916 );
917 }
918
919 if let Err(err) = { 0..self.cores.len() }.try_for_each(|core| match self.core(core) {
921 Ok(mut core) => core.debug_core_stop(),
922 Err(Error::CoreDisabled(_)) => Ok(()),
923 Err(err) => Err(err),
924 }) {
925 tracing::warn!("Failed to deconfigure device during shutdown: {:?}", err);
926 }
927 }
928}
929
930fn get_target_from_selector(
936 target: TargetSelector,
937 attach_method: AttachMethod,
938 mut probe: Probe,
939 registry: &Registry,
940) -> Result<(Probe, Target), Error> {
941 let target = match target {
942 TargetSelector::Unspecified(name) => registry.get_target_by_name(name)?,
943 TargetSelector::Specified(target) => target,
944 TargetSelector::Auto => {
945 if AttachMethod::UnderReset == attach_method {
949 probe.target_reset_assert()?;
950 }
951 probe.attach_to_unspecified()?;
952
953 let (returned_probe, found_target) =
954 crate::vendor::auto_determine_target(registry, probe)?;
955 probe = returned_probe;
956
957 if AttachMethod::UnderReset == attach_method {
958 probe.target_reset_deassert()?;
960 }
961
962 if let Some(target) = found_target {
963 target
964 } else {
965 return Err(Error::ChipNotFound(RegistryError::ChipAutodetectFailed));
966 }
967 }
968 };
969
970 Ok((probe, target))
971}
972
973#[non_exhaustive]
984#[derive(Debug, Clone, Default)]
985pub struct Permissions {
986 erase_all: bool,
988}
989
990impl Permissions {
991 pub fn new() -> Self {
993 Self::default()
994 }
995
996 #[must_use]
1002 pub fn allow_erase_all(self) -> Self {
1003 Self {
1004 erase_all: true,
1005 ..self
1006 }
1007 }
1008
1009 pub(crate) fn erase_all(&self) -> Result<(), MissingPermissions> {
1010 if self.erase_all {
1011 Ok(())
1012 } else {
1013 Err(MissingPermissions("erase_all".into()))
1014 }
1015 }
1016}
1017
1018#[derive(Debug, Clone, thiserror::Error)]
1019#[error("An operation could not be performed because it lacked the permission to do so: {0}")]
1020pub struct MissingPermissions(pub String);