Skip to content

Commit

Permalink
Add support for qThreadExtraInfo
Browse files Browse the repository at this point in the history
Add a new sub-IDET for `MultiThreadBase` to respond with extra information about a thread

Signed-off-by: Ryan Fairfax <[email protected]>
  • Loading branch information
thefaxman committed Jun 8, 2022
1 parent 2cd3bc6 commit 0dd8086
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Of course, most use-cases will want to support additional debugging features as
- Access the remote target's filesystem to read/write file
- Can be used to automatically read the remote executable on attach (using `ExecFile`)
- Read auxiliary vector (`info auxv`)
- Extra thread info (`info threads`)

_Note:_ GDB features are implemented on an as-needed basis by `gdbstub`'s contributors. If there's a missing GDB feature that you'd like `gdbstub` to implement, please file an issue and/or open a PR!

Expand Down
24 changes: 24 additions & 0 deletions examples/armv4t_multicore/gdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ impl MultiThreadBase for Emu {
) -> Option<target::ext::base::multithread::MultiThreadResumeOps<'_, Self>> {
Some(self)
}

#[inline(always)]
fn support_thread_extra_info(
&mut self,
) -> Option<gdbstub::target::ext::thread_extra_info::ThreadExtraInfoOps<'_, Self>> {
Some(self)
}
}

impl MultiThreadResume for Emu {
Expand Down Expand Up @@ -272,3 +279,20 @@ impl target::ext::breakpoints::HwWatchpoint for Emu {
Ok(true)
}
}

impl target::ext::thread_extra_info::ThreadExtraInfo for Emu {
fn thread_extra_info(&self, tid: Tid, buf: &mut [u8]) -> Result<usize, Self::Error> {
let cpu_id = tid_to_cpuid(tid)?;
let info = format!("CPU {:?}", cpu_id);

Ok(copy_to_buf(info.as_bytes(), buf))
}
}

/// Copy all bytes of `data` to `buf`.
/// Return the size of data copied.
pub fn copy_to_buf(data: &[u8], buf: &mut [u8]) -> usize {
let len = buf.len().min(data.len());
buf[..len].copy_from_slice(&data[..len]);
len
}
13 changes: 13 additions & 0 deletions src/protocol/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ macro_rules! commands {
fn support_reverse_step(&mut self) -> Option<()>;
fn support_reverse_cont(&mut self) -> Option<()>;
fn support_x_upcase_packet(&mut self) -> Option<()>;
fn support_thread_extra_info(&mut self) -> Option<()>;
}

impl<T: Target> Hack for T {
Expand Down Expand Up @@ -146,6 +147,14 @@ macro_rules! commands {
None
}
}

fn support_thread_extra_info(&mut self) -> Option<()> {
use crate::target::ext::base::BaseOps;
match self.base_ops() {
BaseOps::SingleThread(_) => None,
BaseOps::MultiThread(ops) => ops.support_thread_extra_info().map(drop),
}
}
}

// TODO?: use tries for more efficient longest prefix matching
Expand Down Expand Up @@ -288,4 +297,8 @@ commands! {
catch_syscalls use 'a {
"QCatchSyscalls" => _QCatchSyscalls::QCatchSyscalls<'a>,
}

thread_extra_info use 'a {
"qThreadExtraInfo" => _qThreadExtraInfo::qThreadExtraInfo<'a>,
}
}
34 changes: 34 additions & 0 deletions src/protocol/commands/_qThreadExtraInfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use super::prelude::*;

use crate::protocol::common::thread_id::ThreadId;
use crate::protocol::SpecificThreadId;

#[derive(Debug)]
pub struct qThreadExtraInfo<'a> {
pub id: SpecificThreadId,

pub buf: &'a mut [u8],
}

impl<'a> ParseCommand<'a> for qThreadExtraInfo<'a> {
#[inline(always)]
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let (buf, body_range) = buf.into_raw_buf();
let body = buf.get(body_range.start..body_range.end)?;

if body.is_empty() {
return None;
}

match body {
[b',', body @ ..] => {
let id = SpecificThreadId::try_from(ThreadId::try_from(body).ok()?).ok()?;

drop(body);

Some(qThreadExtraInfo { id, buf })
}
_ => None,
}
}
}
2 changes: 2 additions & 0 deletions src/stub/core_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod reverse_exec;
mod section_offsets;
mod single_register_access;
mod target_xml;
mod thread_extra_info;
mod x_upcase_packet;

pub(crate) use resume::FinishExecStatus;
Expand Down Expand Up @@ -207,6 +208,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Command::HostIo(cmd) => self.handle_host_io(res, target, cmd),
Command::ExecFile(cmd) => self.handle_exec_file(res, target, cmd),
Command::Auxv(cmd) => self.handle_auxv(res, target, cmd),
Command::ThreadExtraInfo(cmd) => self.handle_thread_extra_info(res, target, cmd),
// in the worst case, the command could not be parsed...
Command::Unknown(cmd) => {
// HACK: if the user accidentally sends a resume command to a
Expand Down
40 changes: 40 additions & 0 deletions src/stub/core_impl/thread_extra_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use super::prelude::*;
use crate::protocol::commands::ext::ThreadExtraInfo;
use crate::protocol::SpecificIdKind;
use crate::target::ext::base::BaseOps;

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_thread_extra_info<'a>(
&mut self,
res: &mut ResponseWriter<'_, C>,
target: &mut T,
command: ThreadExtraInfo<'a>,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.base_ops() {
BaseOps::SingleThread(_) => return Ok(HandlerStatus::Handled),
BaseOps::MultiThread(ops) => match ops.support_thread_extra_info() {
Some(ops) => ops,
None => return Ok(HandlerStatus::Handled),
},
};

crate::__dead_code_marker!("thread_extra_info", "impl");

let handler_status = match command {
ThreadExtraInfo::qThreadExtraInfo(info) => {
if let SpecificIdKind::WithId(tid) = info.id.tid {
let size = ops
.thread_extra_info(tid, info.buf)
.map_err(Error::TargetError)?;
let data = info.buf.get(..size).ok_or(Error::PacketBufferOverflow)?;

res.write_hex_buf(data)?;
}

HandlerStatus::Handled
}
};

Ok(handler_status)
}
}
8 changes: 8 additions & 0 deletions src/target/ext/base/multithread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ pub trait MultiThreadBase: Target {
fn support_resume(&mut self) -> Option<MultiThreadResumeOps<'_, Self>> {
None
}

/// Support for providing thread extra information.
#[inline(always)]
fn support_thread_extra_info(
&mut self,
) -> Option<crate::target::ext::thread_extra_info::ThreadExtraInfoOps<'_, Self>> {
None
}
}

/// Target extension - support for resuming multi threaded targets.
Expand Down
1 change: 1 addition & 0 deletions src/target/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,4 @@ pub mod memory_map;
pub mod monitor_cmd;
pub mod section_offsets;
pub mod target_description_xml_override;
pub mod thread_extra_info;
22 changes: 22 additions & 0 deletions src/target/ext/thread_extra_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Provide extra information for a thread
use crate::common::Tid;
use crate::target::Target;

/// Target Extension - Provide extra information for a thread
pub trait ThreadExtraInfo: Target {
/// Provide extra information about a thread
///
/// GDB queries for extra information for a thread as part of the
/// `info threads` command. This function will be called once
/// for each active thread.
///
/// A string can be copied into `buf` that will then be displayed
/// to the client. The string is displayed as `(value)`, such as:
///
/// `Thread 1.1 (value)`
///
/// Return the number of bytes written into `buf`.
fn thread_extra_info(&self, tid: Tid, buf: &mut [u8]) -> Result<usize, Self::Error>;
}

define_ext!(ThreadExtraInfoOps, ThreadExtraInfo);

0 comments on commit 0dd8086

Please sign in to comment.