pub use builder::GdbStubBuilder;
pub use builder::GdbStubBuilderError;
pub use core_impl::DisconnectReason;
pub use error::GdbStubError;
pub use stop_reason::BaseStopReason;
pub use stop_reason::IntoStopReason;
pub use stop_reason::MultiThreadStopReason;
pub use stop_reason::SingleThreadStopReason;
mod builder;
mod core_impl;
mod error;
mod stop_reason;
pub mod state_machine;
use self::error::InternalError;
use crate::conn::Connection;
use crate::conn::ConnectionExt;
use crate::target::Target;
use managed::ManagedSlice;
pub mod run_blocking {
use super::*;
use crate::conn::ConnectionExt;
pub trait BlockingEventLoop {
type Target: Target;
type Connection: ConnectionExt;
type StopReason: IntoStopReason<Self::Target>;
fn wait_for_stop_reason(
target: &mut Self::Target,
conn: &mut Self::Connection,
) -> Result<
Event<Self::StopReason>,
WaitForStopReasonError<
<Self::Target as Target>::Error,
<Self::Connection as Connection>::Error,
>,
>;
fn on_interrupt(
target: &mut Self::Target,
) -> Result<Option<Self::StopReason>, <Self::Target as Target>::Error>;
}
pub enum Event<StopReason> {
IncomingData(u8),
TargetStopped(StopReason),
}
pub enum WaitForStopReasonError<T, C> {
Target(T),
Connection(C),
}
}
pub struct GdbStub<'a, T: Target, C: Connection> {
conn: C,
packet_buffer: ManagedSlice<'a, u8>,
inner: core_impl::GdbStubImpl<T, C>,
}
impl<'a, T: Target, C: Connection> GdbStub<'a, T, C> {
pub fn builder(conn: C) -> GdbStubBuilder<'a, T, C> {
GdbStubBuilder::new(conn)
}
#[cfg(feature = "alloc")]
pub fn new(conn: C) -> GdbStub<'a, T, C> {
GdbStubBuilder::new(conn).build().unwrap()
}
pub fn run_blocking<E>(
self,
target: &mut T,
) -> Result<DisconnectReason, GdbStubError<T::Error, C::Error>>
where
C: ConnectionExt,
E: run_blocking::BlockingEventLoop<Target = T, Connection = C>,
{
let mut gdb = self.run_state_machine(target)?;
loop {
gdb = match gdb {
state_machine::GdbStubStateMachine::Idle(mut gdb) => {
let byte = gdb.borrow_conn().read().map_err(InternalError::conn_read)?;
gdb.incoming_data(target, byte)?
}
state_machine::GdbStubStateMachine::Disconnected(gdb) => {
break Ok(gdb.get_reason());
}
state_machine::GdbStubStateMachine::CtrlCInterrupt(gdb) => {
let stop_reason =
E::on_interrupt(target).map_err(InternalError::TargetError)?;
gdb.interrupt_handled(target, stop_reason)?
}
state_machine::GdbStubStateMachine::Running(mut gdb) => {
use run_blocking::Event as BlockingEventLoopEvent;
use run_blocking::WaitForStopReasonError;
let event = E::wait_for_stop_reason(target, gdb.borrow_conn());
match event {
Ok(BlockingEventLoopEvent::TargetStopped(stop_reason)) => {
gdb.report_stop(target, stop_reason)?
}
Ok(BlockingEventLoopEvent::IncomingData(byte)) => {
gdb.incoming_data(target, byte)?
}
Err(WaitForStopReasonError::Target(e)) => {
break Err(InternalError::TargetError(e).into());
}
Err(WaitForStopReasonError::Connection(e)) => {
break Err(InternalError::conn_read(e).into());
}
}
}
}
}
}
pub fn run_state_machine(
mut self,
target: &mut T,
) -> Result<state_machine::GdbStubStateMachine<'a, T, C>, GdbStubError<T::Error, C::Error>>
{
{
let support_software_breakpoints = target
.support_breakpoints()
.map(|ops| ops.support_sw_breakpoint().is_some())
.unwrap_or(false);
if !support_software_breakpoints && !target.guard_rail_implicit_sw_breakpoints() {
return Err(InternalError::ImplicitSwBreakpoints.into());
}
}
{
self.conn
.on_session_start()
.map_err(InternalError::conn_init)?;
}
Ok(state_machine::GdbStubStateMachineInner::from_plain_gdbstub(self).into())
}
}