Skip to content
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

Support Host I/O operations #66

Merged
merged 13 commits into from
Aug 20, 2021
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ categories = ["development-tools::debugging", "embedded", "emulators", "network-
exclude = ["examples/**/*.elf", "examples/**/*.o"]

[dependencies]
bitflags = "1.2.1"
bitflags = "1.3"
cfg-if = "0.1.10"
log = "0.4"
managed = { version = "0.8", default-features = false }
Expand Down
13 changes: 7 additions & 6 deletions examples/armv4t/gdb/host_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use gdbstub::target;
use crate::emu::Emu;

use gdbstub::target::ext::host_io::{
HostIoErrno, HostIoError, HostIoMode, HostIoOpenFlags, HostIoResult, PreadOutput, PreadToken,
HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoOutput, HostIoResult,
HostIoToken,
};

impl target::ext::host_io::HostIo for Emu {
Expand All @@ -28,7 +29,7 @@ impl target::ext::host_io::HostIoOpen for Emu {
&mut self,
filename: &[u8],
_flags: HostIoOpenFlags,
_mode: HostIoMode,
_mode: HostIoOpenMode,
) -> HostIoResult<u32, Self> {
// Support `info proc mappings` command
if filename == b"/proc/1/maps" {
Expand All @@ -42,11 +43,11 @@ impl target::ext::host_io::HostIoOpen for Emu {
impl target::ext::host_io::HostIoPread for Emu {
fn pread<'a>(
&mut self,
fd: i32,
fd: u32,
count: u32,
offset: u32,
output: PreadOutput<'a>,
) -> HostIoResult<PreadToken<'a>, Self> {
output: HostIoOutput<'a>,
) -> HostIoResult<HostIoToken<'a>, Self> {
if fd == 1 {
let maps = b"0x55550000-0x55550078 r-x 0 0 0\n";
let len = maps.len();
Expand All @@ -60,7 +61,7 @@ impl target::ext::host_io::HostIoPread for Emu {
}

impl target::ext::host_io::HostIoClose for Emu {
fn close(&mut self, fd: i32) -> HostIoResult<u32, Self> {
fn close(&mut self, fd: u32) -> HostIoResult<u32, Self> {
if fd == 1 {
Ok(0)
} else {
Expand Down
131 changes: 71 additions & 60 deletions src/gdbstub_impl/ext/host_io.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
use super::prelude::*;
use crate::arch::Arch;
use crate::protocol::commands::ext::HostIo;
use crate::target::ext::host_io::{HostIoError, HostStat, PreadOutput};
use crate::target::ext::host_io::{HostIoError, HostIoOutput, HostIoStat};
use crate::GdbStubError;

macro_rules! handle_hostio_result {
( $ret:ident, $res:ident, $callback:expr) => {{
match $ret {
Ok(fd) => $callback(fd)?,
Err(HostIoError::Errno(errno)) => {
$res.write_str("F-1,")?;
$res.write_num(errno as i32)?;
}
Err(HostIoError::Fatal(e)) => return Err(GdbStubError::TargetError(e)),
}
}};
}

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_host_io(
&mut self,
Expand All @@ -31,25 +18,38 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {

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

macro_rules! handle_hostio_result {
( if let Ok($val:pat) = $ret:expr => $callback:block ) => {{
match $ret {
Ok($val) => $callback,
Err(HostIoError::Errno(errno)) => {
res.write_str("F-1,")?;
res.write_num(errno as i32)?;
}
Err(HostIoError::Fatal(e)) => return Err(GdbStubError::TargetError(e)),
}
}};
}

let handler_status = match command {
HostIo::vFileOpen(cmd) if ops.enable_open().is_some() => {
let ops = ops.enable_open().unwrap();
let result = ops.open(cmd.filename, cmd.flags, cmd.mode);
handle_hostio_result!(result, res, |fd| -> Result<_, Error<T::Error, C::Error>> {
res.write_str("F")?;
res.write_num(fd)?;
Ok(())
});
handle_hostio_result! {
if let Ok(fd) = ops.open(cmd.filename, cmd.flags, cmd.mode) => {
res.write_str("F")?;
res.write_num(fd)?;
}
}
HandlerStatus::Handled
}
HostIo::vFileClose(cmd) if ops.enable_close().is_some() => {
let ops = ops.enable_close().unwrap();
let result = ops.close(cmd.fd);
handle_hostio_result!(result, res, |ret| -> Result<_, Error<T::Error, C::Error>> {
res.write_str("F")?;
res.write_num(ret)?;
Ok(())
});
handle_hostio_result! {
if let Ok(ret) = ops.close(cmd.fd) => {
res.write_str("F")?;
res.write_num(ret)?;
}
}
HandlerStatus::Handled
}
HostIo::vFilePread(cmd) if ops.enable_pread().is_some() => {
Expand All @@ -73,10 +73,9 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
};

let ops = ops.enable_pread().unwrap();
let result = ops.pread(cmd.fd, count, offset, PreadOutput::new(&mut callback));
handle_hostio_result!(result, res, |_| -> Result<_, Error<T::Error, C::Error>> {
Ok(())
});
handle_hostio_result! {
if let Ok(_) = ops.pread(cmd.fd, count, offset, HostIoOutput::new(&mut callback)) => {}
};
err?;

HandlerStatus::Handled
Expand All @@ -85,22 +84,19 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
let offset = <T::Arch as Arch>::Usize::from_be_bytes(cmd.offset)
.ok_or(Error::TargetMismatch)?;
let ops = ops.enable_pwrite().unwrap();
let result = ops.pwrite(cmd.fd, offset, cmd.data);
handle_hostio_result!(result, res, |ret| -> Result<_, Error<T::Error, C::Error>> {
res.write_str("F")?;
res.write_num(ret)?;
Ok(())
});
handle_hostio_result! {
if let Ok(ret) = ops.pwrite(cmd.fd, offset, cmd.data) => {
res.write_str("F")?;
res.write_num(ret)?;
}
};
HandlerStatus::Handled
}
HostIo::vFileFstat(cmd) if ops.enable_fstat().is_some() => {
let ops = ops.enable_fstat().unwrap();
let result = ops.fstat(cmd.fd);
handle_hostio_result!(
result,
res,
|stat: HostStat| -> Result<_, Error<T::Error, C::Error>> {
let size = core::mem::size_of::<HostStat>();
handle_hostio_result! {
if let Ok(stat) = ops.fstat(cmd.fd) => {
let size = core::mem::size_of::<HostIoStat>();
res.write_str("F")?;
res.write_num(size)?;
res.write_str(";")?;
Expand All @@ -117,37 +113,52 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
res.write_binary(&stat.st_atime.to_le_bytes())?;
res.write_binary(&stat.st_mtime.to_le_bytes())?;
res.write_binary(&stat.st_ctime.to_le_bytes())?;
Ok(())
}
);
};
HandlerStatus::Handled
}
HostIo::vFileUnlink(cmd) if ops.enable_unlink().is_some() => {
let ops = ops.enable_unlink().unwrap();
let result = ops.unlink(cmd.filename);
handle_hostio_result!(result, res, |ret| -> Result<_, Error<T::Error, C::Error>> {
res.write_str("F")?;
res.write_num(ret)?;
Ok(())
});
handle_hostio_result! {
if let Ok(ret) = ops.unlink(cmd.filename) => {
res.write_str("F")?;
res.write_num(ret)?;
}
};
HandlerStatus::Handled
}
HostIo::vFileReadlink(cmd) if ops.enable_readlink().is_some() => {
let mut err: Result<_, Error<T::Error, C::Error>> = Ok(());
let mut callback = |data: &[u8]| {
let e = (|| {
res.write_str("F")?;
res.write_num(data.len())?;
res.write_str(";")?;
res.write_binary(data)?;
Ok(())
})();

if let Err(e) = e {
err = Err(e)
}
};

let ops = ops.enable_readlink().unwrap();
let result = ops.readlink(cmd.filename);
handle_hostio_result!(result, res, |ret| -> Result<_, Error<T::Error, C::Error>> {
res.write_str("F")?;
res.write_num(ret)?;
Ok(())
});
handle_hostio_result! {
if let Ok(_) = ops.readlink(cmd.filename, HostIoOutput::new(&mut callback)) => {}
};
err?;

HandlerStatus::Handled
}
HostIo::vFileSetfs(cmd) if ops.enable_setfs().is_some() => {
let ops = ops.enable_setfs().unwrap();
let result = ops.setfs(cmd.fs);
handle_hostio_result!(result, res, |_| -> Result<_, Error<T::Error, C::Error>> {
Ok(())
});
handle_hostio_result! {
if let Ok(ret) = ops.setfs(cmd.fs) => {
res.write_str("F")?;
res.write_num(ret)?;
}
};
HandlerStatus::Handled
}
_ => HandlerStatus::Handled,
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/commands/_vFile_close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::prelude::*;

#[derive(Debug)]
pub struct vFileClose {
pub fd: i32,
pub fd: u32,
}

impl<'a> ParseCommand<'a> for vFileClose {
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/commands/_vFile_fstat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::prelude::*;

#[derive(Debug)]
pub struct vFileFstat {
pub fd: i32,
pub fd: u32,
}

impl<'a> ParseCommand<'a> for vFileFstat {
Expand Down
6 changes: 3 additions & 3 deletions src/protocol/commands/_vFile_open.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::prelude::*;

use crate::target::ext::host_io::{HostIoOpenFlags, HostIoMode};
use crate::target::ext::host_io::{HostIoOpenFlags, HostIoOpenMode};

#[derive(Debug)]
pub struct vFileOpen<'a> {
pub filename: &'a [u8],
pub flags: HostIoOpenFlags,
pub mode: HostIoMode,
pub mode: HostIoOpenMode,
}

impl<'a> ParseCommand<'a> for vFileOpen<'a> {
Expand All @@ -21,7 +21,7 @@ impl<'a> ParseCommand<'a> for vFileOpen<'a> {
let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
let filename = decode_hex_buf(body.next()?).ok()?;
let flags = HostIoOpenFlags::from_bits(decode_hex(body.next()?).ok()?).unwrap();
let mode = HostIoMode::from_bits(decode_hex(body.next()?).ok()?).unwrap();
let mode = HostIoOpenMode::from_bits(decode_hex(body.next()?).ok()?).unwrap();
Some(vFileOpen{filename, flags, mode})
},
_ => None,
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/commands/_vFile_pread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::prelude::*;

#[derive(Debug)]
pub struct vFilePread<'a> {
pub fd: i32,
pub fd: u32,
pub count: &'a [u8],
pub offset: &'a [u8],
}
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/commands/_vFile_pwrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::prelude::*;

#[derive(Debug)]
pub struct vFilePwrite<'a> {
pub fd: i32,
pub fd: u32,
pub offset: &'a [u8],
pub data: &'a [u8],
}
Expand Down
Loading