Skip to content

Commit 8811bba

Browse files
authored
Add support for qProcessInfo and qHostInfo queries. (#190)
* Add support for `qProcessInfo` and `qHostInfo` queries. These are necessary in some cases to allow LLDB to use appropriate target-specific behaviors or modules. For example, when debugging a Wasm target, LLDB requires the stub to declare that it has a wasm32 architecture in order to actually use its Wasm module loader over the wire.
1 parent a0a73c1 commit 8811bba

10 files changed

Lines changed: 293 additions & 0 deletions

File tree

src/common/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,15 @@ pub type Tid = core::num::NonZeroUsize;
99

1010
/// Process ID
1111
pub type Pid = core::num::NonZeroUsize;
12+
13+
/// Endinanness.
14+
///
15+
/// This is used to report target endianness to the debugger as a
16+
/// response to certain commands.
17+
#[derive(Clone, Copy, Debug)]
18+
pub enum Endianness {
19+
/// Big-endian.
20+
Big,
21+
/// Little-endian.
22+
Little,
23+
}

src/protocol/commands.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,14 @@ commands! {
367367
"qTsV" => _qTsV::qTsV,
368368
}
369369

370+
host_info {
371+
"qHostInfo" => _qHostInfo::qHostInfo,
372+
}
373+
374+
process_info {
375+
"qProcessInfo" => _qProcessInfo::qProcessInfo,
376+
}
377+
370378
wasm use 'a {
371379
"qWasmCallStack" => _qWasmCallStack::qWasmCallStack,
372380
"qWasmLocal" => _qWasmLocal::qWasmLocal<'a>,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct qHostInfo;
5+
6+
impl<'a> ParseCommand<'a> for qHostInfo {
7+
#[inline(always)]
8+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
9+
if !buf.into_body().is_empty() {
10+
return None;
11+
}
12+
Some(qHostInfo)
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct qProcessInfo;
5+
6+
impl<'a> ParseCommand<'a> for qProcessInfo {
7+
#[inline(always)]
8+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
9+
if !buf.into_body().is_empty() {
10+
return None;
11+
}
12+
Some(qProcessInfo)
13+
}
14+
}

src/stub/core_impl.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod exec_file;
3232
mod extended_mode;
3333
mod flash;
3434
mod host_io;
35+
mod host_process_info;
3536
mod libraries;
3637
mod lldb_register_info;
3738
mod memory_map;
@@ -224,6 +225,8 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
224225
Command::LibrariesSvr4(cmd) => self.handle_libraries_svr4(res, target, cmd),
225226
Command::Libraries(cmd) => self.handle_libraries(res, target, cmd),
226227
Command::Tracepoints(cmd) => self.handle_tracepoints(res, target, cmd),
228+
Command::HostInfo(cmd) => self.handle_host_info(res, target, cmd),
229+
Command::ProcessInfo(cmd) => self.handle_process_info(res, target, cmd),
227230
Command::Wasm(cmd) => self.handle_wasm(res, target, cmd),
228231
// in the worst case, the command could not be parsed...
229232
Command::Unknown(cmd) => {
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use super::prelude::*;
2+
use crate::common::Endianness;
3+
use crate::common::Pid;
4+
use crate::protocol::commands::ext::HostInfo;
5+
use crate::protocol::commands::ext::ProcessInfo;
6+
use crate::protocol::ResponseWriterError;
7+
use crate::target::ext::host_info::HostInfoResponse;
8+
use crate::target::ext::process_info::ProcessInfoResponse;
9+
10+
pub(crate) enum InfoResponse<'a> {
11+
Pid(Pid),
12+
Triple(&'a str),
13+
Endianness(Endianness),
14+
PointerSize(usize),
15+
}
16+
17+
impl<'a> InfoResponse<'a> {
18+
pub(crate) fn write_response<C: Connection>(
19+
&self,
20+
res: &mut ResponseWriter<'_, C>,
21+
) -> Result<(), ResponseWriterError<C::Error>> {
22+
match self {
23+
InfoResponse::Pid(pid) => {
24+
res.write_str("pid:")?;
25+
res.write_dec(usize::from(*pid))?;
26+
}
27+
InfoResponse::Triple(triple) => {
28+
res.write_str("triple:")?;
29+
res.write_hex_buf(triple.as_bytes())?;
30+
}
31+
InfoResponse::Endianness(endian) => {
32+
res.write_str("endian:")?;
33+
res.write_str(match endian {
34+
Endianness::Big => "big;",
35+
Endianness::Little => "little;",
36+
})?;
37+
}
38+
InfoResponse::PointerSize(p) => {
39+
res.write_str("ptrsize:")?;
40+
res.write_dec(*p)?;
41+
}
42+
}
43+
res.write_str(";")?;
44+
Ok(())
45+
}
46+
}
47+
48+
impl<'a> From<&HostInfoResponse<'a>> for InfoResponse<'a> {
49+
fn from(resp: &HostInfoResponse<'a>) -> Self {
50+
match *resp {
51+
HostInfoResponse::Triple(s) => InfoResponse::Triple(s),
52+
HostInfoResponse::Endianness(e) => InfoResponse::Endianness(e),
53+
HostInfoResponse::PointerSize(p) => InfoResponse::PointerSize(p),
54+
}
55+
}
56+
}
57+
58+
impl<'a> From<&ProcessInfoResponse<'a>> for InfoResponse<'a> {
59+
fn from(resp: &ProcessInfoResponse<'a>) -> Self {
60+
match *resp {
61+
ProcessInfoResponse::Pid(pid) => InfoResponse::Pid(pid),
62+
ProcessInfoResponse::Triple(s) => InfoResponse::Triple(s),
63+
ProcessInfoResponse::Endianness(e) => InfoResponse::Endianness(e),
64+
ProcessInfoResponse::PointerSize(p) => InfoResponse::PointerSize(p),
65+
}
66+
}
67+
}
68+
69+
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
70+
pub(crate) fn handle_process_info(
71+
&mut self,
72+
res: &mut ResponseWriter<'_, C>,
73+
target: &mut T,
74+
command: ProcessInfo,
75+
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
76+
let ops = match target.support_process_info() {
77+
Some(ops) => ops,
78+
None => return Ok(HandlerStatus::Handled),
79+
};
80+
81+
crate::__dead_code_marker!("process_info", "impl");
82+
83+
let mut result = Ok(());
84+
let mut write_info = |info: &ProcessInfoResponse<'_>| {
85+
if result.is_ok() {
86+
if let Err(e) = InfoResponse::from(info).write_response(res) {
87+
result = Err(e);
88+
}
89+
}
90+
};
91+
92+
match command {
93+
ProcessInfo::qProcessInfo(_cmd) => {
94+
ops.process_info(&mut write_info)
95+
.map_err(Error::TargetError)?;
96+
result?;
97+
}
98+
};
99+
100+
Ok(HandlerStatus::Handled)
101+
}
102+
103+
pub(crate) fn handle_host_info(
104+
&mut self,
105+
res: &mut ResponseWriter<'_, C>,
106+
target: &mut T,
107+
command: HostInfo,
108+
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
109+
let ops = match target.support_host_info() {
110+
Some(ops) => ops,
111+
None => return Ok(HandlerStatus::Handled),
112+
};
113+
114+
crate::__dead_code_marker!("host_info", "impl");
115+
116+
let mut result = Ok(());
117+
let mut write_info = |info: &HostInfoResponse<'_>| {
118+
if result.is_ok() {
119+
if let Err(e) = InfoResponse::from(info).write_response(res) {
120+
result = Err(e);
121+
}
122+
}
123+
};
124+
125+
match command {
126+
HostInfo::qHostInfo(_cmd) => {
127+
ops.host_info(&mut write_info).map_err(Error::TargetError)?;
128+
result?;
129+
}
130+
};
131+
132+
Ok(HandlerStatus::Handled)
133+
}
134+
}

src/target/ext/host_info.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//! (LLDB extension) Provide host information to the debugger.
2+
//!
3+
//! This allows for reporting key-value metadata, for example the
4+
//! target triple, endianness, and pointer size.
5+
//!
6+
//! This corresponds to the `qHostInfo` command in the LLDB
7+
//! extensions.
8+
9+
use crate::common::Endianness;
10+
use crate::target::Target;
11+
12+
/// A response key-value pair to a [HostInfo::host_info] query.
13+
///
14+
/// A response consists of a list of key-value pairs, each of which is
15+
/// represented by one instance of this enum.
16+
///
17+
/// The allowed responses are documented in the [LLDB extension
18+
/// documentation]. Not all supported responses are currently
19+
/// represented in this enum. If you need another one, please feel
20+
/// free to send a PR!
21+
///
22+
/// [LLDB extension documentation]: https://lldb.llvm.org/resources/lldbplatformpackets.html
23+
#[derive(Clone, Copy)]
24+
#[non_exhaustive]
25+
pub enum HostInfoResponse<'a> {
26+
/// The target triple for the debuggee, as a string.
27+
Triple(&'a str),
28+
/// The target endianness.
29+
Endianness(Endianness),
30+
/// The pointer size.
31+
PointerSize(usize),
32+
}
33+
34+
/// (LLDB extension) Target Extension - Provide host information.
35+
pub trait HostInfo: Target {
36+
/// Write a response to a host-info query.
37+
///
38+
/// Call `write_item` with each `HostInfoResponse` you wish to send.
39+
fn host_info(
40+
&self,
41+
write_item: &mut dyn FnMut(&HostInfoResponse<'_>),
42+
) -> Result<(), Self::Error>;
43+
}
44+
45+
define_ext!(HostInfoOps, HostInfo);

src/target/ext/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,13 @@ pub mod catch_syscalls;
265265
pub mod exec_file;
266266
pub mod extended_mode;
267267
pub mod flash;
268+
pub mod host_info;
268269
pub mod host_io;
269270
pub mod libraries;
270271
pub mod lldb_register_info_override;
271272
pub mod memory_map;
272273
pub mod monitor_cmd;
274+
pub mod process_info;
273275
pub mod section_offsets;
274276
pub mod target_description_xml_override;
275277
pub mod thread_extra_info;

src/target/ext/process_info.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//! (LLDB extension) Provide process information to the debugger.
2+
//!
3+
//! This allows for reporting key-value metadata, for example the
4+
//! current PID, target triple, endianness, and pointer size.
5+
//!
6+
//! This corresponds to the `qHostInfo` command in the LLDB
7+
//! extensions.
8+
9+
use crate::common::Endianness;
10+
use crate::common::Pid;
11+
use crate::target::Target;
12+
13+
/// A response key-value pair to a [ProcessInfo::process_info]
14+
/// query.
15+
///
16+
/// A response consists of a list of key-value pairs, each of which is
17+
/// represented by one instance of this enum.
18+
///
19+
/// The allowed responses are documented in the [LLDB extension
20+
/// documentation]. Not all supported responses are currently
21+
/// represented in this enum. If you need another one, please feel
22+
/// free to send a PR!
23+
///
24+
/// [LLDB extension documentation]: https://lldb.llvm.org/resources/lldbplatformpackets.html
25+
#[derive(Clone, Copy)]
26+
#[non_exhaustive]
27+
pub enum ProcessInfoResponse<'a> {
28+
/// The current process PID.
29+
Pid(Pid),
30+
/// The target triple for the debuggee, as a string.
31+
Triple(&'a str),
32+
/// The target endianness.
33+
Endianness(Endianness),
34+
/// The pointer size.
35+
PointerSize(usize),
36+
}
37+
38+
/// (LLDB extension) Target Extension - Provide process information.
39+
pub trait ProcessInfo: Target {
40+
/// Write the response to process-info query.
41+
///
42+
/// Call `write_item` with each `InfoResponse` you wish to send.
43+
fn process_info(
44+
&self,
45+
write_item: &mut dyn FnMut(&ProcessInfoResponse<'_>),
46+
) -> Result<(), Self::Error>;
47+
}
48+
49+
define_ext!(ProcessInfoOps, ProcessInfo);

src/target/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,18 @@ pub trait Target {
747747
None
748748
}
749749

750+
/// (LLDB extension) Support for reporting host information.
751+
#[inline(always)]
752+
fn support_host_info(&mut self) -> Option<ext::host_info::HostInfoOps<'_, Self>> {
753+
None
754+
}
755+
756+
/// (LLDB extension) Support for reporting process information.
757+
#[inline(always)]
758+
fn support_process_info(&mut self) -> Option<ext::process_info::ProcessInfoOps<'_, Self>> {
759+
None
760+
}
761+
750762
/// (LLDB extension) Support for WebAssembly (Wasm)-specific commands.
751763
#[inline(always)]
752764
fn support_wasm(&mut self) -> Option<ext::wasm::WasmOps<'_, Self>> {

0 commit comments

Comments
 (0)