-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1f7d5ce
commit b824e9e
Showing
5 changed files
with
141 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use super::{GdbError, GdbExecutor, GdbHandler, GdbSession}; | ||
|
||
/// Implementation of [`GdbExecutor`] to execute requests from GDB client. | ||
pub struct ClientHandler<'a, H> { | ||
session: &'a mut GdbSession, | ||
handler: &'a mut H, | ||
} | ||
|
||
impl<'a, H> ClientHandler<'a, H> { | ||
pub fn new(session: &'a mut GdbSession, handler: &'a mut H) -> Self { | ||
Self { session, handler } | ||
} | ||
} | ||
|
||
impl<'a, H: GdbHandler> GdbExecutor for ClientHandler<'a, H> { | ||
fn pump(&mut self) -> Result<Option<impl AsRef<[u8]> + '_>, GdbError> { | ||
Ok(Some(self.session.res.drain(..))) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/// Provides methods to handle debug events. | ||
pub trait GdbHandler {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,38 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
use std::io::{Error, ErrorKind, Read, Write}; | ||
use std::net::TcpStream; | ||
pub use self::handler::*; | ||
|
||
/// Encapsulate a debugger connection. | ||
pub struct DebugClient { | ||
sock: TcpStream, | ||
buf: Vec<u8>, | ||
next: usize, | ||
} | ||
|
||
impl DebugClient { | ||
pub(super) fn new(sock: TcpStream) -> Self { | ||
Self { | ||
sock, | ||
buf: Vec::new(), | ||
next: 0, | ||
} | ||
} | ||
|
||
#[cfg(unix)] | ||
pub fn socket(&self) -> std::os::fd::RawFd { | ||
std::os::fd::AsRawFd::as_raw_fd(&self.sock) | ||
} | ||
|
||
#[cfg(windows)] | ||
pub fn socket(&self) -> std::os::windows::io::RawSocket { | ||
std::os::windows::io::AsRawSocket::as_raw_socket(&self.sock) | ||
} | ||
|
||
pub fn read(&mut self) -> Result<u8, Error> { | ||
// Fill the buffer if needed. | ||
while self.next == self.buf.len() { | ||
// Clear previous data. | ||
self.buf.clear(); | ||
self.next = 0; | ||
|
||
// Read. | ||
let mut buf = [0; 1024]; | ||
let len = match self.sock.read(&mut buf) { | ||
Ok(v) => v, | ||
Err(e) if e.kind() == ErrorKind::Interrupted => continue, | ||
Err(e) => return Err(e), | ||
}; | ||
|
||
if len == 0 { | ||
return Err(Error::from(ErrorKind::UnexpectedEof)); | ||
} | ||
|
||
self.buf.extend_from_slice(&buf[..len]); | ||
} | ||
|
||
// Get byte. | ||
let b = self.buf[self.next]; | ||
use self::client::ClientHandler; | ||
use thiserror::Error; | ||
|
||
self.next += 1; | ||
mod client; | ||
mod handler; | ||
|
||
Ok(b) | ||
} | ||
/// Contains states for a GDB remote session. | ||
#[derive(Default)] | ||
pub struct GdbSession { | ||
req: Vec<u8>, | ||
res: Vec<u8>, | ||
} | ||
|
||
impl gdbstub::conn::Connection for DebugClient { | ||
type Error = std::io::Error; | ||
|
||
fn write(&mut self, byte: u8) -> Result<(), Self::Error> { | ||
self.write_all(std::slice::from_ref(&byte)) | ||
} | ||
|
||
fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::Error> { | ||
while !buf.is_empty() { | ||
let written = match Write::write(&mut self.sock, buf) { | ||
Ok(v) => v, | ||
Err(e) if matches!(e.kind(), ErrorKind::Interrupted | ErrorKind::WouldBlock) => { | ||
continue; | ||
} | ||
Err(e) => return Err(e), | ||
}; | ||
|
||
if written == 0 { | ||
return Err(std::io::Error::from(ErrorKind::WriteZero)); | ||
} | ||
|
||
buf = &buf[written..]; | ||
} | ||
impl GdbSession { | ||
#[must_use] | ||
pub fn dispatch_client<'a, H: GdbHandler>( | ||
&'a mut self, | ||
data: &[u8], | ||
h: &'a mut H, | ||
) -> impl GdbExecutor + 'a { | ||
self.req.extend_from_slice(data); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn flush(&mut self) -> Result<(), Self::Error> { | ||
while let Err(e) = Write::flush(&mut self.sock) { | ||
if !matches!(e.kind(), ErrorKind::Interrupted | ErrorKind::WouldBlock) { | ||
return Err(e); | ||
} | ||
} | ||
|
||
Ok(()) | ||
ClientHandler::new(self, h) | ||
} | ||
} | ||
|
||
fn on_session_start(&mut self) -> Result<(), Self::Error> { | ||
self.sock.set_nodelay(true) | ||
} | ||
/// Provides method to execute debug operations. | ||
pub trait GdbExecutor { | ||
/// The returned response can be empty if this pump does not produce any response. | ||
fn pump(&mut self) -> Result<Option<impl AsRef<[u8]> + '_>, GdbError>; | ||
} | ||
|
||
/// Represents an error when [`GdbExecutor`] fails. | ||
#[derive(Debug, Error)] | ||
pub enum GdbError {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.