diff --git a/src/common/mod.rs b/src/common/mod.rs index d7c9136b..a71dad25 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -9,3 +9,15 @@ pub type Tid = core::num::NonZeroUsize; /// Process ID pub type Pid = core::num::NonZeroUsize; + +/// Endinanness. +/// +/// This is used to report target endianness to the debugger as a +/// response to certain commands. +#[derive(Clone, Copy, Debug)] +pub enum Endianness { + /// Big-endian. + Big, + /// Little-endian. + Little, +} diff --git a/src/protocol/commands.rs b/src/protocol/commands.rs index 455bd730..54e1bbbf 100644 --- a/src/protocol/commands.rs +++ b/src/protocol/commands.rs @@ -367,6 +367,14 @@ commands! { "qTsV" => _qTsV::qTsV, } + host_info { + "qHostInfo" => _qHostInfo::qHostInfo, + } + + process_info { + "qProcessInfo" => _qProcessInfo::qProcessInfo, + } + wasm use 'a { "qWasmCallStack" => _qWasmCallStack::qWasmCallStack, "qWasmLocal" => _qWasmLocal::qWasmLocal<'a>, diff --git a/src/protocol/commands/_qHostInfo.rs b/src/protocol/commands/_qHostInfo.rs new file mode 100644 index 00000000..34c98c71 --- /dev/null +++ b/src/protocol/commands/_qHostInfo.rs @@ -0,0 +1,14 @@ +use super::prelude::*; + +#[derive(Debug)] +pub struct qHostInfo; + +impl<'a> ParseCommand<'a> for qHostInfo { + #[inline(always)] + fn from_packet(buf: PacketBuf<'a>) -> Option { + if !buf.into_body().is_empty() { + return None; + } + Some(qHostInfo) + } +} diff --git a/src/protocol/commands/_qProcessInfo.rs b/src/protocol/commands/_qProcessInfo.rs new file mode 100644 index 00000000..67b48e4d --- /dev/null +++ b/src/protocol/commands/_qProcessInfo.rs @@ -0,0 +1,14 @@ +use super::prelude::*; + +#[derive(Debug)] +pub struct qProcessInfo; + +impl<'a> ParseCommand<'a> for qProcessInfo { + #[inline(always)] + fn from_packet(buf: PacketBuf<'a>) -> Option { + if !buf.into_body().is_empty() { + return None; + } + Some(qProcessInfo) + } +} diff --git a/src/stub/core_impl.rs b/src/stub/core_impl.rs index 172d3c81..0545e953 100644 --- a/src/stub/core_impl.rs +++ b/src/stub/core_impl.rs @@ -32,6 +32,7 @@ mod exec_file; mod extended_mode; mod flash; mod host_io; +mod host_process_info; mod libraries; mod lldb_register_info; mod memory_map; @@ -224,6 +225,8 @@ impl GdbStubImpl { Command::LibrariesSvr4(cmd) => self.handle_libraries_svr4(res, target, cmd), Command::Libraries(cmd) => self.handle_libraries(res, target, cmd), Command::Tracepoints(cmd) => self.handle_tracepoints(res, target, cmd), + Command::HostInfo(cmd) => self.handle_host_info(res, target, cmd), + Command::ProcessInfo(cmd) => self.handle_process_info(res, target, cmd), Command::Wasm(cmd) => self.handle_wasm(res, target, cmd), // in the worst case, the command could not be parsed... Command::Unknown(cmd) => { diff --git a/src/stub/core_impl/host_process_info.rs b/src/stub/core_impl/host_process_info.rs new file mode 100644 index 00000000..edae43e5 --- /dev/null +++ b/src/stub/core_impl/host_process_info.rs @@ -0,0 +1,134 @@ +use super::prelude::*; +use crate::common::Endianness; +use crate::common::Pid; +use crate::protocol::commands::ext::HostInfo; +use crate::protocol::commands::ext::ProcessInfo; +use crate::protocol::ResponseWriterError; +use crate::target::ext::host_info::HostInfoResponse; +use crate::target::ext::process_info::ProcessInfoResponse; + +pub(crate) enum InfoResponse<'a> { + Pid(Pid), + Triple(&'a str), + Endianness(Endianness), + PointerSize(usize), +} + +impl<'a> InfoResponse<'a> { + pub(crate) fn write_response( + &self, + res: &mut ResponseWriter<'_, C>, + ) -> Result<(), ResponseWriterError> { + match self { + InfoResponse::Pid(pid) => { + res.write_str("pid:")?; + res.write_dec(usize::from(*pid))?; + } + InfoResponse::Triple(triple) => { + res.write_str("triple:")?; + res.write_hex_buf(triple.as_bytes())?; + } + InfoResponse::Endianness(endian) => { + res.write_str("endian:")?; + res.write_str(match endian { + Endianness::Big => "big;", + Endianness::Little => "little;", + })?; + } + InfoResponse::PointerSize(p) => { + res.write_str("ptrsize:")?; + res.write_dec(*p)?; + } + } + res.write_str(";")?; + Ok(()) + } +} + +impl<'a> From<&HostInfoResponse<'a>> for InfoResponse<'a> { + fn from(resp: &HostInfoResponse<'a>) -> Self { + match *resp { + HostInfoResponse::Triple(s) => InfoResponse::Triple(s), + HostInfoResponse::Endianness(e) => InfoResponse::Endianness(e), + HostInfoResponse::PointerSize(p) => InfoResponse::PointerSize(p), + } + } +} + +impl<'a> From<&ProcessInfoResponse<'a>> for InfoResponse<'a> { + fn from(resp: &ProcessInfoResponse<'a>) -> Self { + match *resp { + ProcessInfoResponse::Pid(pid) => InfoResponse::Pid(pid), + ProcessInfoResponse::Triple(s) => InfoResponse::Triple(s), + ProcessInfoResponse::Endianness(e) => InfoResponse::Endianness(e), + ProcessInfoResponse::PointerSize(p) => InfoResponse::PointerSize(p), + } + } +} + +impl GdbStubImpl { + pub(crate) fn handle_process_info( + &mut self, + res: &mut ResponseWriter<'_, C>, + target: &mut T, + command: ProcessInfo, + ) -> Result> { + let ops = match target.support_process_info() { + Some(ops) => ops, + None => return Ok(HandlerStatus::Handled), + }; + + crate::__dead_code_marker!("process_info", "impl"); + + let mut result = Ok(()); + let mut write_info = |info: &ProcessInfoResponse<'_>| { + if result.is_ok() { + if let Err(e) = InfoResponse::from(info).write_response(res) { + result = Err(e); + } + } + }; + + match command { + ProcessInfo::qProcessInfo(_cmd) => { + ops.process_info(&mut write_info) + .map_err(Error::TargetError)?; + result?; + } + }; + + Ok(HandlerStatus::Handled) + } + + pub(crate) fn handle_host_info( + &mut self, + res: &mut ResponseWriter<'_, C>, + target: &mut T, + command: HostInfo, + ) -> Result> { + let ops = match target.support_host_info() { + Some(ops) => ops, + None => return Ok(HandlerStatus::Handled), + }; + + crate::__dead_code_marker!("host_info", "impl"); + + let mut result = Ok(()); + let mut write_info = |info: &HostInfoResponse<'_>| { + if result.is_ok() { + if let Err(e) = InfoResponse::from(info).write_response(res) { + result = Err(e); + } + } + }; + + match command { + HostInfo::qHostInfo(_cmd) => { + ops.host_info(&mut write_info).map_err(Error::TargetError)?; + result?; + } + }; + + Ok(HandlerStatus::Handled) + } +} diff --git a/src/target/ext/host_info.rs b/src/target/ext/host_info.rs new file mode 100644 index 00000000..684a3b44 --- /dev/null +++ b/src/target/ext/host_info.rs @@ -0,0 +1,45 @@ +//! (LLDB extension) Provide host information to the debugger. +//! +//! This allows for reporting key-value metadata, for example the +//! target triple, endianness, and pointer size. +//! +//! This corresponds to the `qHostInfo` command in the LLDB +//! extensions. + +use crate::common::Endianness; +use crate::target::Target; + +/// A response key-value pair to a [HostInfo::host_info] query. +/// +/// A response consists of a list of key-value pairs, each of which is +/// represented by one instance of this enum. +/// +/// The allowed responses are documented in the [LLDB extension +/// documentation]. Not all supported responses are currently +/// represented in this enum. If you need another one, please feel +/// free to send a PR! +/// +/// [LLDB extension documentation]: https://lldb.llvm.org/resources/lldbplatformpackets.html +#[derive(Clone, Copy)] +#[non_exhaustive] +pub enum HostInfoResponse<'a> { + /// The target triple for the debuggee, as a string. + Triple(&'a str), + /// The target endianness. + Endianness(Endianness), + /// The pointer size. + PointerSize(usize), +} + +/// (LLDB extension) Target Extension - Provide host information. +pub trait HostInfo: Target { + /// Write a response to a host-info query. + /// + /// Call `write_item` with each `HostInfoResponse` you wish to send. + fn host_info( + &self, + write_item: &mut dyn FnMut(&HostInfoResponse<'_>), + ) -> Result<(), Self::Error>; +} + +define_ext!(HostInfoOps, HostInfo); diff --git a/src/target/ext/mod.rs b/src/target/ext/mod.rs index 8b3adfce..1d866130 100644 --- a/src/target/ext/mod.rs +++ b/src/target/ext/mod.rs @@ -265,11 +265,13 @@ pub mod catch_syscalls; pub mod exec_file; pub mod extended_mode; pub mod flash; +pub mod host_info; pub mod host_io; pub mod libraries; pub mod lldb_register_info_override; pub mod memory_map; pub mod monitor_cmd; +pub mod process_info; pub mod section_offsets; pub mod target_description_xml_override; pub mod thread_extra_info; diff --git a/src/target/ext/process_info.rs b/src/target/ext/process_info.rs new file mode 100644 index 00000000..2460760e --- /dev/null +++ b/src/target/ext/process_info.rs @@ -0,0 +1,49 @@ +//! (LLDB extension) Provide process information to the debugger. +//! +//! This allows for reporting key-value metadata, for example the +//! current PID, target triple, endianness, and pointer size. +//! +//! This corresponds to the `qHostInfo` command in the LLDB +//! extensions. + +use crate::common::Endianness; +use crate::common::Pid; +use crate::target::Target; + +/// A response key-value pair to a [ProcessInfo::process_info] +/// query. +/// +/// A response consists of a list of key-value pairs, each of which is +/// represented by one instance of this enum. +/// +/// The allowed responses are documented in the [LLDB extension +/// documentation]. Not all supported responses are currently +/// represented in this enum. If you need another one, please feel +/// free to send a PR! +/// +/// [LLDB extension documentation]: https://lldb.llvm.org/resources/lldbplatformpackets.html +#[derive(Clone, Copy)] +#[non_exhaustive] +pub enum ProcessInfoResponse<'a> { + /// The current process PID. + Pid(Pid), + /// The target triple for the debuggee, as a string. + Triple(&'a str), + /// The target endianness. + Endianness(Endianness), + /// The pointer size. + PointerSize(usize), +} + +/// (LLDB extension) Target Extension - Provide process information. +pub trait ProcessInfo: Target { + /// Write the response to process-info query. + /// + /// Call `write_item` with each `InfoResponse` you wish to send. + fn process_info( + &self, + write_item: &mut dyn FnMut(&ProcessInfoResponse<'_>), + ) -> Result<(), Self::Error>; +} + +define_ext!(ProcessInfoOps, ProcessInfo); diff --git a/src/target/mod.rs b/src/target/mod.rs index be34a617..1c5bd77a 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -747,6 +747,18 @@ pub trait Target { None } + /// (LLDB extension) Support for reporting host information. + #[inline(always)] + fn support_host_info(&mut self) -> Option> { + None + } + + /// (LLDB extension) Support for reporting process information. + #[inline(always)] + fn support_process_info(&mut self) -> Option> { + None + } + /// (LLDB extension) Support for WebAssembly (Wasm)-specific commands. #[inline(always)] fn support_wasm(&mut self) -> Option> {