-
-
Notifications
You must be signed in to change notification settings - Fork 64
Add support for x packet #186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| use super::prelude::*; | ||
|
|
||
| #[derive(Debug)] | ||
| pub struct x<'a> { | ||
| pub addr: &'a [u8], | ||
| pub len: usize, | ||
|
|
||
| /// Reuse PacketBuf underlying buffer to read the binary data into it | ||
| pub buf: &'a mut [u8], | ||
| } | ||
|
|
||
| impl<'a> ParseCommand<'a> for x<'a> { | ||
| #[inline(always)] | ||
| fn from_packet(buf: PacketBuf<'a>) -> Option<Self> { | ||
| // the total packet buffer currently looks like: | ||
| // | ||
| // +------+--------------------+-------------------+-------+-----------------+ | ||
| // | "$x" | addr (hex-encoded) | len (hex-encoded) | "#XX" | empty space ... | | ||
| // +------+--------------------+-------------------+-------+-----------------+ | ||
| // | ||
| // Unfortunately, while `len` can be hex-decoded right here and now into a | ||
| // `usize`, `addr` corresponds to a Target::Arch::Usize, which requires holding | ||
| // on to a valid &[u8] reference into the buffer. | ||
| // | ||
| // While it's not _perfectly_ efficient, simply leaving the decoded addr in | ||
| // place and wasting a couple bytes is probably the easiest way to tackle this | ||
| // problem: | ||
| // | ||
| // +------+------------------+------------------------------------------------+ | ||
| // | "$x" | addr (raw bytes) | usable buffer ... | | ||
| // +------+------------------+------------------------------------------------+ | ||
|
|
||
| let (buf, body_range) = buf.into_raw_buf(); | ||
| let body = buf.get_mut(body_range.start..body_range.end)?; | ||
|
|
||
| let mut body = body.split_mut(|b| *b == b','); | ||
|
|
||
| let addr = decode_hex_buf(body.next()?).ok()?; | ||
| let addr_len = addr.len(); | ||
| let len = decode_hex(body.next()?).ok()?; | ||
|
|
||
| // ensures that `split_at_mut` doesn't panic | ||
| if buf.len() < body_range.start + addr_len { | ||
| return None; | ||
| } | ||
|
|
||
| let (addr, buf) = buf.split_at_mut(body_range.start + addr_len); | ||
| let addr = addr.get(b"$x".len()..)?; | ||
|
|
||
| Some(x { addr, len, buf }) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| use super::prelude::*; | ||
| use crate::arch::Arch; | ||
| use crate::protocol::commands::ext::XLowcasePacket; | ||
| use crate::target::ext::base::BaseOps; | ||
|
|
||
| impl<T: Target, C: Connection> GdbStubImpl<T, C> { | ||
| pub(crate) fn handle_x_lowcase_packet( | ||
| &mut self, | ||
| res: &mut ResponseWriter<'_, C>, | ||
| target: &mut T, | ||
| command: XLowcasePacket<'_>, | ||
| ) -> Result<HandlerStatus, Error<T::Error, C::Error>> { | ||
| if !target.use_x_lowcase_packet() { | ||
| return Ok(HandlerStatus::Handled); | ||
| } | ||
|
|
||
| crate::__dead_code_marker!("x_lowcase_packet", "impl"); | ||
|
|
||
| let handler_status = match command { | ||
| XLowcasePacket::x(cmd) => { | ||
| let buf = cmd.buf; | ||
| let addr = <T::Arch as Arch>::Usize::from_be_bytes(cmd.addr) | ||
| .ok_or(Error::TargetMismatch)?; | ||
|
|
||
| let mut i = 0; | ||
| let mut n = cmd.len; | ||
| while n != 0 { | ||
| let chunk_size = n.min(buf.len()); | ||
|
|
||
| use num_traits::NumCast; | ||
|
|
||
| let addr = addr + NumCast::from(i).ok_or(Error::TargetMismatch)?; | ||
| let data = &mut buf[..chunk_size]; | ||
| let data_len = match target.base_ops() { | ||
| BaseOps::SingleThread(ops) => ops.read_addrs(addr, data), | ||
| BaseOps::MultiThread(ops) => { | ||
| ops.read_addrs(addr, data, self.current_mem_tid) | ||
| } | ||
| } | ||
| .handle_error()?; | ||
|
|
||
| // TODO: add more specific error variant? | ||
| let data = data.get(..data_len).ok_or(Error::PacketBufferOverflow)?; | ||
|
|
||
| // Start data with 'b' to indicate binary data | ||
| if i == 0 { | ||
| res.write_str("b")?; | ||
| } | ||
|
|
||
| n -= chunk_size; | ||
| i += chunk_size; | ||
|
|
||
| res.write_binary(data)?; | ||
| } | ||
|
|
||
| HandlerStatus::Handled | ||
| } | ||
| }; | ||
|
|
||
| Ok(handler_status) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -517,6 +517,23 @@ pub trait Target { | |
| true | ||
| } | ||
|
|
||
| /// Enable/disable using the `x` packet to read to target | ||
| /// memory (as opposed to the basic `m` packet). | ||
| /// | ||
| /// By default, this method returns `false`. | ||
| /// | ||
| /// GDB and LLDB have different responses for the `x` packet, and until | ||
| /// `gdbstub` supports a disabmiguation mechanism to correctly handle | ||
| /// both GDB and LLDB, this is by default set to `false`. | ||
| /// | ||
| /// _Author's note:_ Unless you're _really_ trying to squeeze `gdbstub` onto | ||
| /// a particularly resource-constrained platform, you may as well leave this | ||
| /// optimization enabled. | ||
| #[inline(always)] | ||
| fn use_x_lowcase_packet(&self) -> bool { | ||
| false | ||
| } | ||
|
|
||
| /// Enable/disable using the more efficient `X` packet to write to target | ||
| /// memory (as opposed to the basic `M` packet). | ||
| /// | ||
|
|
@@ -802,6 +819,7 @@ macro_rules! impl_dyn_target { | |
| __delegate!(fn guard_rail_implicit_sw_breakpoints(&self) -> bool); | ||
|
|
||
| __delegate!(fn use_no_ack_mode(&self) -> bool); | ||
| __delegate!(fn use_x_lowcase_packet(&self) -> bool); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure about this here, though
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is def right, and in-fact, you've just made me realize that we haven't been correctly delegating some of the new methods that were added here! I'll need to send out a follow-up bug fix to address that, lol. |
||
| __delegate!(fn use_x_upcase_packet(&self) -> bool); | ||
| __delegate!(fn use_resume_stub(&self) -> bool); | ||
| __delegate!(fn use_rle(&self) -> bool); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: we should be able to share the implementation of this method with the
mhandler inhandle_base, and avoid copy-pasting.I'll look into this myself after this diff lands, since I want to make sure however we do it, it doesn't result in poor codegen on minimal stubs.