Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions example_no_std/src/gdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ impl Target for DummyTarget {
false
}

// disable fork events to save space
#[inline(always)]
fn use_fork_stop_reason(&self) -> bool {
false
}

// disable vfork events to save space
#[inline(always)]
fn use_vfork_stop_reason(&self) -> bool {
false
}

// disable vforkdone events to save space
#[inline(always)]
fn use_vforkdone_stop_reason(&self) -> bool {
false
}

#[inline(always)]
fn support_breakpoints(
&mut self,
Expand Down
12 changes: 12 additions & 0 deletions src/stub/core_impl/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
res.write_str(";QStartNoAckMode+")?;
}

if target.use_fork_stop_reason() {
res.write_str(";fork-events+")?;
}

if target.use_vfork_stop_reason() {
res.write_str(";vfork-events+")?;
}

if target.use_vforkdone_stop_reason() {
res.write_str(";vforkdone-events+")?;
}

if let Some(resume_ops) = target.base_ops().resume_ops() {
let (reverse_cont, reverse_step) = match resume_ops {
ResumeOps::MultiThread(ops) => (
Expand Down
62 changes: 61 additions & 1 deletion src/stub/core_impl/resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,24 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
};
}

macro_rules! guard_fork_events {
() => {
target.use_fork_stop_reason()
};
}

macro_rules! guard_vfork_events {
() => {
target.use_vfork_stop_reason()
};
}

macro_rules! guard_vforkdone_events {
() => {
target.use_vforkdone_stop_reason()
};
}

let status = match stop_reason {
MultiThreadStopReason::DoneStep => {
res.write_str("S")?;
Expand Down Expand Up @@ -425,13 +443,55 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {

FinishExecStatus::Handled
}
MultiThreadStopReason::Library(tid) => {
self.write_stop_common(res, target, Some(tid), Signal::SIGTRAP)?;
res.write_str("library:;")?;
FinishExecStatus::Handled
}
MultiThreadStopReason::Fork { cur_tid, new_tid } if guard_fork_events!() => {
crate::__dead_code_marker!("fork_events", "stop_reason");
self.write_stop_common(res, target, Some(cur_tid), Signal::SIGTRAP)?;
res.write_str("fork:")?;
res.write_specific_thread_id(SpecificThreadId {
pid: self
.features
.multiprocess()
.then_some(SpecificIdKind::WithId(self.get_current_pid(target)?)),
tid: SpecificIdKind::WithId(new_tid),
})?;
res.write_str(";")?;
FinishExecStatus::Handled
}
MultiThreadStopReason::VFork { cur_tid, new_tid } if guard_vfork_events!() => {
crate::__dead_code_marker!("vfork_events", "stop_reason");
self.write_stop_common(res, target, Some(cur_tid), Signal::SIGTRAP)?;
res.write_str("vfork:")?;
res.write_specific_thread_id(SpecificThreadId {
pid: self
.features
.multiprocess()
.then_some(SpecificIdKind::WithId(self.get_current_pid(target)?)),
tid: SpecificIdKind::WithId(new_tid),
})?;
res.write_str(";")?;
FinishExecStatus::Handled
}
MultiThreadStopReason::VForkDone(tid) if guard_vforkdone_events!() => {
crate::__dead_code_marker!("vforkdone_events", "stop_reason");
self.write_stop_common(res, target, Some(tid), Signal::SIGTRAP)?;
res.write_str("vforkdone:;")?;
FinishExecStatus::Handled
}
// Explicitly avoid using `_ =>` to handle the "unguarded" variants, as doing so would
// squelch the useful compiler error that crops up whenever stop reasons are added.
MultiThreadStopReason::SwBreak(_)
| MultiThreadStopReason::HwBreak(_)
| MultiThreadStopReason::Watch { .. }
| MultiThreadStopReason::ReplayLog { .. }
| MultiThreadStopReason::CatchSyscall { .. } => {
| MultiThreadStopReason::CatchSyscall { .. }
| MultiThreadStopReason::Fork { .. }
| MultiThreadStopReason::VFork { .. }
| MultiThreadStopReason::VForkDone { .. } => {
return Err(Error::UnsupportedStopReason);
}
};
Expand Down
42 changes: 42 additions & 0 deletions src/stub/stop_reason.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,38 @@ pub enum BaseStopReason<Tid, U> {
/// The location the event occurred at.
position: CatchSyscallPosition,
},
/// A thread hit a specific library event.
///
/// This stop reason indicates that loaded libraries have changed. The
/// debugger should fetch a new list of loaded libraries.
Library(Tid),
/// A thread created a new process via fork.
///
/// This indicates that a fork system call was executed, creating a new
/// child process.
Fork {
/// Tid of the thread that called fork
cur_tid: Tid,
/// Tid of the new child process
new_tid: core::num::NonZeroUsize,
},
/// A thread created a new process via vfork.
///
/// Similar to Fork, but the parent process is suspended until the child
/// calls exec or exits, as the parent and child temporarily share the
/// same address space.
VFork {
/// Tid of the thread that called vfork
cur_tid: Tid,
/// Tid of the new child process
new_tid: core::num::NonZeroUsize,
},
/// A vfork child process has completed its operation.
///
/// This indicates that a child process created by vfork has either called
/// exec or terminated, so the address spaces of parent and child are no
/// longer shared.
VForkDone(Tid),
}

/// A stop reason for a single threaded target.
Expand Down Expand Up @@ -140,6 +172,16 @@ impl<U> From<BaseStopReason<(), U>> for BaseStopReason<Tid, U> {
number,
position,
},
BaseStopReason::Library(_) => BaseStopReason::Library(crate::SINGLE_THREAD_TID),
BaseStopReason::Fork { new_tid, .. } => BaseStopReason::Fork {
cur_tid: crate::SINGLE_THREAD_TID,
new_tid,
},
BaseStopReason::VFork { new_tid, .. } => BaseStopReason::VFork {
cur_tid: crate::SINGLE_THREAD_TID,
new_tid,
},
BaseStopReason::VForkDone(_) => BaseStopReason::VForkDone(crate::SINGLE_THREAD_TID),
}
}
}
Expand Down
42 changes: 42 additions & 0 deletions src/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,48 @@ pub trait Target {
true
}

/// Enable support for [`BaseStopReason::Fork`].
///
/// By default, this method returns `true`.
///
/// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto
/// a particularly resource-constrained platform (and looking to save ~100
/// bytes), you may as well leave this enabled.
///
/// [`BaseStopReason::Fork`]: crate::stub::BaseStopReason::Fork
#[inline(always)]
fn use_fork_stop_reason(&self) -> bool {
true
}

/// Enable support for [`BaseStopReason::VFork`].
///
/// By default, this method returns `true`.
///
/// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto
/// a particularly resource-constrained platform (and looking to save ~100
/// bytes), you may as well leave this enabled.
///
/// [`BaseStopReason::VFork`]: crate::stub::BaseStopReason::VFork
#[inline(always)]
fn use_vfork_stop_reason(&self) -> bool {
true
}

/// Enable support for [`BaseStopReason::VForkDone`].
///
/// By default, this method returns `true`.
///
/// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto
/// a particularly resource-constrained platform (and looking to save ~100
/// bytes), you may as well leave this enabled.
///
/// [`BaseStopReason::VForkDone`]: crate::stub::BaseStopReason::VForkDone
#[inline(always)]
fn use_vforkdone_stop_reason(&self) -> bool {
true
}

/// Support for setting / removing breakpoints.
#[inline(always)]
fn support_breakpoints(&mut self) -> Option<ext::breakpoints::BreakpointsOps<'_, Self>> {
Expand Down
Loading