Skip to content

Commit 4a814af

Browse files
committed
Support Host I/O operations
1 parent c40145c commit 4a814af

File tree

14 files changed

+228
-0
lines changed

14 files changed

+228
-0
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ Of course, most use-cases will want to support additional debugging features as
7575
- Get section/segment relocation offsets from the target
7676
- Custom `monitor` Commands
7777
- Extend the GDB protocol with custom debug commands using GDB's `monitor` command
78+
- Get target memory map
79+
- Perform Host I/O operations
7880

7981
_Note:_ GDB features are implemented on an as-needed basis by `gdbstub`'s contributors. If there's a missing GDB feature that you'd like `gdbstub` to implement, please file an issue and/or open a PR!
8082

examples/armv4t/gdb/host_io.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use gdbstub::target;
2+
3+
use crate::emu::Emu;
4+
5+
impl target::ext::host_io::HostIo for Emu {
6+
fn open(&self, filename: &[u8], _flags: u64, _mode: u64) -> i64 {
7+
if filename == b"/proc/1/maps" {
8+
1
9+
} else {
10+
-1
11+
}
12+
}
13+
14+
fn pread(&self, fd: usize, count: usize, offset: usize) -> &[u8] {
15+
if fd == 1 {
16+
let maps = b"0x55550000-0x55550078 r-x 0 0 0\n";
17+
let len = maps.len();
18+
&maps[offset.min(len)..(offset + count).min(len)]
19+
} else {
20+
b""
21+
}
22+
}
23+
24+
fn close(&self, fd: usize) -> i64 {
25+
if fd == 1 {
26+
0
27+
} else {
28+
-1
29+
}
30+
}
31+
32+
fn setfs(&self, _fd: usize) -> i64 {
33+
0
34+
}
35+
}

examples/armv4t/gdb/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::emu::{Emu, Event};
1717
mod breakpoints;
1818
mod catch_syscalls;
1919
mod extended_mode;
20+
mod host_io;
2021
mod memory_map;
2122
mod monitor_cmd;
2223
mod section_offsets;
@@ -94,6 +95,11 @@ impl Target for Emu {
9495
fn catch_syscalls(&mut self) -> Option<target::ext::catch_syscalls::CatchSyscallsOps<Self>> {
9596
Some(self)
9697
}
98+
99+
#[inline(always)]
100+
fn host_io(&mut self) -> Option<target::ext::host_io::HostIoOps<Self>> {
101+
Some(self)
102+
}
97103
}
98104

99105
impl Emu {

src/gdbstub_impl/ext/host_io.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use super::prelude::*;
2+
use crate::protocol::commands::ext::HostIo;
3+
4+
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
5+
pub(crate) fn handle_host_io(
6+
&mut self,
7+
res: &mut ResponseWriter<C>,
8+
target: &mut T,
9+
command: HostIo,
10+
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
11+
let ops = match target.host_io() {
12+
Some(ops) => ops,
13+
None => return Ok(HandlerStatus::Handled),
14+
};
15+
16+
crate::__dead_code_marker!("host_io", "impl");
17+
18+
let handler_status = match command {
19+
HostIo::vFileOpen(cmd) => {
20+
let ret = ops.open(cmd.filename, cmd.flags, cmd.mode);
21+
res.write_str("F")?;
22+
res.write_num(ret)?;
23+
HandlerStatus::Handled
24+
}
25+
HostIo::vFileClose(cmd) => {
26+
let ret = ops.close(cmd.fd);
27+
res.write_str("F")?;
28+
res.write_num(ret)?;
29+
HandlerStatus::Handled
30+
}
31+
HostIo::vFilePread(cmd) => {
32+
let data = ops.pread(cmd.fd, cmd.count, cmd.offset);
33+
res.write_str("F")?;
34+
res.write_num(data.len())?;
35+
res.write_str(";")?;
36+
res.write_binary(data)?;
37+
HandlerStatus::Handled
38+
}
39+
HostIo::vFileSetfs(cmd) => {
40+
let ret = ops.setfs(cmd.fd);
41+
res.write_str("F")?;
42+
res.write_num(ret)?;
43+
HandlerStatus::Handled
44+
}
45+
};
46+
47+
Ok(handler_status)
48+
}
49+
}

src/gdbstub_impl/ext/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod base;
1515
mod breakpoints;
1616
mod catch_syscalls;
1717
mod extended_mode;
18+
mod host_io;
1819
mod memory_map;
1920
mod monitor_cmd;
2021
mod reverse_exec;

src/gdbstub_impl/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
579579
Command::ReverseCont(cmd) => self.handle_reverse_cont(res, target, cmd),
580580
Command::ReverseStep(cmd) => self.handle_reverse_step(res, target, cmd),
581581
Command::MemoryMap(cmd) => self.handle_memory_map(res, target, cmd),
582+
Command::HostIo(cmd) => self.handle_host_io(res, target, cmd),
582583
}
583584
}
584585
}

src/protocol/commands.rs

+7
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ commands! {
223223
"qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead,
224224
}
225225

226+
host_io use 'a{
227+
"vFile:open" => _vFile_open::vFileOpen<'a>,
228+
"vFile:close" => _vFile_close::vFileClose,
229+
"vFile:pread" => _vFile_pread::vFilePread,
230+
"vFile:setfs" => _vFile_setfs::vFileSetfs,
231+
}
232+
226233
catch_syscalls use 'a {
227234
"QCatchSyscalls" => _QCatchSyscalls::QCatchSyscalls<'a>,
228235
}

src/protocol/commands/_vFile_close.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct vFileClose {
5+
pub fd: usize,
6+
}
7+
8+
impl<'a> ParseCommand<'a> for vFileClose {
9+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
10+
let body = buf.into_body();
11+
if body.is_empty() {
12+
return None;
13+
}
14+
15+
match body {
16+
[b':', body @ ..] => {
17+
let fd = decode_hex(body).ok()?;
18+
Some(vFileClose{fd})
19+
},
20+
_ => None,
21+
}
22+
}
23+
}

src/protocol/commands/_vFile_open.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct vFileOpen<'a> {
5+
pub filename: &'a [u8],
6+
pub flags: u64,
7+
pub mode: u64,
8+
}
9+
10+
impl<'a> ParseCommand<'a> for vFileOpen<'a> {
11+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
12+
let body = buf.into_body();
13+
if body.is_empty() {
14+
return None;
15+
}
16+
17+
match body {
18+
[b':', body @ ..] => {
19+
let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
20+
let filename = decode_hex_buf(body.next()?).ok()?;
21+
let flags= decode_hex(body.next()?).ok()?;
22+
let mode= decode_hex(body.next()?).ok()?;
23+
Some(vFileOpen{filename, flags, mode})
24+
},
25+
_ => None,
26+
}
27+
}
28+
}

src/protocol/commands/_vFile_pread.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct vFilePread {
5+
pub fd: usize,
6+
pub count: usize,
7+
pub offset: usize,
8+
}
9+
10+
impl<'a> ParseCommand<'a> for vFilePread {
11+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
12+
let body = buf.into_body();
13+
if body.is_empty() {
14+
return None;
15+
}
16+
17+
match body {
18+
[b':', body @ ..] => {
19+
let mut body = body.splitn_mut_no_panic(3, |b| *b == b',');
20+
let fd = decode_hex(body.next()?).ok()?;
21+
let count= decode_hex(body.next()?).ok()?;
22+
let offset= decode_hex(body.next()?).ok()?;
23+
Some(vFilePread{fd, count, offset})
24+
},
25+
_ => None,
26+
}
27+
}
28+
}

src/protocol/commands/_vFile_setfs.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use super::prelude::*;
2+
3+
#[derive(Debug)]
4+
pub struct vFileSetfs {
5+
pub fd: usize,
6+
}
7+
8+
impl<'a> ParseCommand<'a> for vFileSetfs {
9+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
10+
let body = buf.into_body();
11+
if body.is_empty() {
12+
return None;
13+
}
14+
15+
match body {
16+
[b':', body @ ..] => {
17+
let fd = decode_hex(body).ok()?;
18+
Some(vFileSetfs{fd})
19+
},
20+
_ => None,
21+
}
22+
}
23+
}

src/target/ext/host_io.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! Provide Host I/O operations for the target.
2+
use crate::target::Target;
3+
4+
/// Target Extension - Perform I/O operations on host
5+
pub trait HostIo: Target {
6+
/// Open a file at filename and return a file descriptor for it, or return
7+
/// -1 if an error occurs.
8+
fn open(&self, filename: &[u8], flags: u64, mode: u64) -> i64;
9+
/// Close the open file corresponding to fd and return 0, or -1 if an error
10+
/// occurs.
11+
fn close(&self, fd: usize) -> i64;
12+
/// Read data from the open file corresponding to fd.
13+
fn pread(&self, fd: usize, count: usize, offset: usize) -> &[u8];
14+
/// Select the filesystem on which vFile operations with filename arguments
15+
/// will operate.
16+
fn setfs(&self, fd: usize) -> i64;
17+
}
18+
19+
define_ext!(HostIoOps, HostIo);

src/target/ext/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ pub mod base;
260260
pub mod breakpoints;
261261
pub mod catch_syscalls;
262262
pub mod extended_mode;
263+
pub mod host_io;
263264
pub mod memory_map;
264265
pub mod monitor_cmd;
265266
pub mod section_offsets;

src/target/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ pub trait Target {
358358
fn catch_syscalls(&mut self) -> Option<ext::catch_syscalls::CatchSyscallsOps<Self>> {
359359
None
360360
}
361+
362+
/// Support Host I/O operations.
363+
fn host_io(&mut self) -> Option<ext::host_io::HostIoOps<Self>> {
364+
None
365+
}
361366
}
362367

363368
macro_rules! impl_dyn_target {

0 commit comments

Comments
 (0)