#![allow(missing_docs)]
#![no_std]
#![cfg_attr(not(target_arch = "arm"), allow(unused))]
#[cfg(feature = "alloc")]
extern crate alloc;
use core::any::Any;
use spin::Once;
use crate::exceptions::DebugEventContext;
pub mod cpu;
pub mod exceptions;
mod sys;
pub mod transport;
cfg_select! {
target_arch = "arm" => {
pub mod gdb_target;
mod sdk;
pub mod debugger;
}
_ => {
pub use debugger_stub as debugger;
}
}
#[allow(dead_code, reason = "only used on non-armv7a")]
mod debugger_stub {
use crate::{Debugger, transport::Transport};
pub struct V5Debugger<S: Transport> {
_stream: spin::Mutex<S>,
config: DebuggerConfig,
}
#[derive(Debug, Default, Clone)]
pub struct DebuggerConfig {
pub stop_motors_on_break: bool,
}
impl<S: Transport> V5Debugger<S> {
#[must_use]
pub fn new(stream: S) -> Self {
Self {
_stream: spin::Mutex::new(stream),
config: DebuggerConfig::default(),
}
}
#[must_use]
pub fn with_motor_stop(mut self, enabled: bool) -> Self {
self.config.stop_motors_on_break = enabled;
self
}
}
unsafe impl<S: Transport + Send + 'static> Debugger for V5Debugger<S> {
fn initialize(&self) {}
unsafe fn handle_debug_event(
&self,
_ctx: &mut crate::exceptions::DebugEventContext,
) -> bool {
unimplemented!()
}
}
}
pub static DEBUGGER: Once<&dyn Debugger> = Once::new();
pub unsafe trait Debugger: Send + Sync + Any {
fn initialize(&self);
unsafe fn handle_debug_event(&self, ctx: &mut DebugEventContext) -> bool;
fn poll(&self) {}
}
#[cfg(feature = "alloc")]
pub fn install(debugger: impl Debugger + 'static) {
use alloc::boxed::Box;
install_by_ref(Box::leak(Box::new(debugger)));
}
pub fn install_by_ref(debugger: &'static dyn Debugger) {
assert!(!DEBUGGER.is_completed(), "A debugger is already installed.");
DEBUGGER.call_once(|| debugger);
#[cfg(target_arch = "arm")]
exceptions::install_vectors();
DEBUGGER.get().unwrap().initialize();
}
#[macro_export]
macro_rules! breakpoint {
() => {
#[cfg(target_arch = "arm")]
unsafe {
::core::arch::asm!("bkpt", options(nostack, nomem, preserves_flags));
}
};
}