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
21 changes: 11 additions & 10 deletions examples/armv4t/gdb/host_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use gdbstub::target;

use crate::emu::Emu;

use gdbstub::target::ext::host_io::{HostMode, HostOpenFlags, PreadOutput, PreadToken};
use gdbstub::target::TargetResult;
use gdbstub::target::ext::host_io::{
HostIoErrno, HostIoError, HostIoMode, HostIoOpenFlags, HostIoResult, PreadOutput, PreadToken,
};

impl target::ext::host_io::HostIo for Emu {
#[inline(always)]
Expand All @@ -26,14 +27,14 @@ impl target::ext::host_io::HostIoOpen for Emu {
fn open(
&mut self,
filename: &[u8],
_flags: HostOpenFlags,
_mode: HostMode,
) -> TargetResult<i32, Self> {
_flags: HostIoOpenFlags,
_mode: HostIoMode,
) -> HostIoResult<u32, Self> {
// Support `info proc mappings` command
if filename == b"/proc/1/maps" {
bet4it marked this conversation as resolved.
Show resolved Hide resolved
bet4it marked this conversation as resolved.
Show resolved Hide resolved
Ok(1)
} else {
Ok(-1)
Err(HostIoError::Errno(HostIoErrno::EPERM))
}
}
}
Expand All @@ -45,25 +46,25 @@ impl target::ext::host_io::HostIoPread for Emu {
count: u32,
offset: u32,
output: PreadOutput<'a>,
) -> TargetResult<PreadToken<'a>, Self> {
) -> HostIoResult<PreadToken<'a>, Self> {
if fd == 1 {
let maps = b"0x55550000-0x55550078 r-x 0 0 0\n";
let len = maps.len();
let count: usize = count as usize;
let offset: usize = offset as usize;
Ok(output.write(&maps[offset.min(len)..(offset + count).min(len)]))
} else {
Err(().into())
Err(HostIoError::Errno(HostIoErrno::EPERM))
}
}
}

impl target::ext::host_io::HostIoClose for Emu {
fn close(&mut self, fd: i32) -> TargetResult<i64, Self> {
fn close(&mut self, fd: i32) -> HostIoResult<u32, Self> {
if fd == 1 {
Ok(0)
} else {
Ok(-1)
Err(HostIoError::Errno(HostIoErrno::EPERM))
}
}
}
105 changes: 78 additions & 27 deletions src/gdbstub_impl/ext/host_io.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
use super::prelude::*;
use crate::arch::Arch;
use crate::protocol::commands::ext::HostIo;
use crate::target::ext::host_io::{HostStat, PreadOutput};
use crate::target::ext::host_io::{HostIoError, HostStat, PreadOutput};
use crate::GdbStubError;
bet4it marked this conversation as resolved.
Show resolved Hide resolved

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)),
}
}};
}
bet4it marked this conversation as resolved.
Show resolved Hide resolved

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_host_io(
Expand All @@ -20,16 +34,22 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
let handler_status = match command {
HostIo::vFileOpen(cmd) if ops.enable_open().is_some() => {
let ops = ops.enable_open().unwrap();
let ret = ops.open(cmd.filename, cmd.flags, cmd.mode).handle_error()?;
res.write_str("F")?;
res.write_num(ret)?;
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(())
});
HandlerStatus::Handled
}
HostIo::vFileClose(cmd) if ops.enable_close().is_some() => {
let ops = ops.enable_close().unwrap();
let ret = ops.close(cmd.fd).handle_error()?;
res.write_str("F")?;
res.write_num(ret)?;
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(())
});
HandlerStatus::Handled
}
HostIo::vFilePread(cmd) if ops.enable_pread().is_some() => {
Expand All @@ -53,8 +73,10 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
};

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

HandlerStatus::Handled
Expand All @@ -63,40 +85,69 @@ 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 ret = ops.pwrite(cmd.fd, offset, cmd.data).handle_error()?;
res.write_str("F")?;
res.write_num(ret)?;
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(())
});
HandlerStatus::Handled
}
HostIo::vFileFstat(cmd) if ops.enable_fstat().is_some() => {
let ops = ops.enable_fstat().unwrap();
let stat = ops.fstat(cmd.fd).handle_error()?;
let size = core::mem::size_of_val(&stat);
let p: *const HostStat = &stat;
let p: *const u8 = p as *const u8;
res.write_str("F")?;
res.write_num(size)?;
res.write_str(";")?;
res.write_binary(unsafe { core::slice::from_raw_parts(p, size) })?;
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>();
res.write_str("F")?;
res.write_num(size)?;
res.write_str(";")?;
res.write_binary(&stat.st_dev.to_le_bytes())?;
res.write_binary(&stat.st_ino.to_le_bytes())?;
res.write_binary(&(stat.st_mode.bits()).to_le_bytes())?;
res.write_binary(&stat.st_nlink.to_le_bytes())?;
res.write_binary(&stat.st_uid.to_le_bytes())?;
res.write_binary(&stat.st_gid.to_le_bytes())?;
res.write_binary(&stat.st_rdev.to_le_bytes())?;
res.write_binary(&stat.st_size.to_le_bytes())?;
res.write_binary(&stat.st_blksize.to_le_bytes())?;
res.write_binary(&stat.st_blocks.to_le_bytes())?;
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())?;
bet4it marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}
);
HandlerStatus::Handled
}
HostIo::vFileUnlink(cmd) if ops.enable_unlink().is_some() => {
let ops = ops.enable_unlink().unwrap();
let ret = ops.unlink(cmd.filename).handle_error()?;
res.write_str("F")?;
res.write_num(ret)?;
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(())
});
HandlerStatus::Handled
}
HostIo::vFileReadlink(cmd) if ops.enable_readlink().is_some() => {
let ops = ops.enable_readlink().unwrap();
let ret = ops.readlink(cmd.filename).handle_error()?;
res.write_str("F")?;
res.write_num(ret)?;
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(())
});
HandlerStatus::Handled
}
HostIo::vFileSetfs(cmd) if ops.enable_setfs().is_some() => {
let ops = ops.enable_setfs().unwrap();
ops.setfs(cmd.fs).handle_error()?;
let result = ops.setfs(cmd.fs);
handle_hostio_result!(result, res, |_| -> Result<_, Error<T::Error, C::Error>> {
Ok(())
bet4it marked this conversation as resolved.
Show resolved Hide resolved
});
HandlerStatus::Handled
}
_ => HandlerStatus::Handled,
Expand Down
10 changes: 5 additions & 5 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::{HostOpenFlags, HostMode};
use crate::target::ext::host_io::{HostIoOpenFlags, HostIoMode};

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

impl<'a> ParseCommand<'a> for vFileOpen<'a> {
Expand All @@ -20,8 +20,8 @@ impl<'a> ParseCommand<'a> for vFileOpen<'a> {
[b':', body @ ..] => {
let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
let filename = decode_hex_buf(body.next()?).ok()?;
let flags = HostOpenFlags::from_bits(decode_hex(body.next()?).ok()?).unwrap();
let mode = HostMode::from_bits(decode_hex(body.next()?).ok()?).unwrap();
let flags = HostIoOpenFlags::from_bits(decode_hex(body.next()?).ok()?).unwrap();
let mode = HostIoMode::from_bits(decode_hex(body.next()?).ok()?).unwrap();
Some(vFileOpen{filename, flags, mode})
},
_ => None,
Expand Down
6 changes: 3 additions & 3 deletions src/protocol/commands/_vFile_setfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ impl<'a> ParseCommand<'a> for vFileSetfs {

match body {
[b':', body @ ..] => {
let fs = match decode_hex(body).ok()? {
0 => FsKind::Stub,
pid => FsKind::Pid(NonZeroUsize::new(pid).unwrap()),
let fs = match NonZeroUsize::new(decode_hex(body).ok()?) {
None => FsKind::Stub,
Some(pid) => FsKind::Pid(pid),
};
Some(vFileSetfs{fs})
},
Expand Down
Loading