Skip to content

Commit 8f0aa74

Browse files
committed
Support read exec-file
1 parent 9227dfd commit 8f0aa74

File tree

16 files changed

+162
-8
lines changed

16 files changed

+162
-8
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Of course, most use-cases will want to support additional debugging features as
7777
- Extend the GDB protocol with custom debug commands using GDB's `monitor` command
7878
- Get target memory map
7979
- Perform Host I/O operations
80+
- Get target exec file
8081

8182
_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!
8283

examples/armv4t/gdb/exec_file.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use gdbstub::common::Pid;
2+
use gdbstub::target;
3+
4+
use crate::emu::Emu;
5+
6+
impl target::ext::exec_file::ExecFile for Emu {
7+
fn get_exec_file(&self, _pid: Option<Pid>) -> &[u8] {
8+
b"/test.elf"
9+
}
10+
}

examples/armv4t/gdb/host_io.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::io::{Read, Seek, Write};
22

3+
use crate::TEST_PROGRAM_ELF;
34
use gdbstub::target;
45
use gdbstub::target::ext::host_io::{
56
FsKind, HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoOutput, HostIoResult,
@@ -8,6 +9,8 @@ use gdbstub::target::ext::host_io::{
89

910
use crate::emu::Emu;
1011

12+
const FD_RESERVED: u32 = 1;
13+
1114
impl target::ext::host_io::HostIo for Emu {
1215
#[inline(always)]
1316
fn enable_open(&mut self) -> Option<target::ext::host_io::HostIoOpenOps<Self>> {
@@ -61,6 +64,10 @@ impl target::ext::host_io::HostIoOpen for Emu {
6164
return Err(HostIoError::Errno(HostIoErrno::ENOENT));
6265
}
6366

67+
if filename == b"/test.elf" {
68+
return Ok(0);
69+
}
70+
6471
let path =
6572
std::str::from_utf8(filename).map_err(|_| HostIoError::Errno(HostIoErrno::ENOENT))?;
6673

@@ -95,13 +102,17 @@ impl target::ext::host_io::HostIoOpen for Emu {
95102
}
96103
};
97104

98-
Ok(n as u32)
105+
Ok(n as u32 + FD_RESERVED)
99106
}
100107
}
101108

102109
impl target::ext::host_io::HostIoClose for Emu {
103110
fn close(&mut self, fd: u32) -> HostIoResult<(), Self> {
104-
let file = match self.files.get_mut(fd as usize) {
111+
if fd < FD_RESERVED {
112+
return Ok(());
113+
}
114+
115+
let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
105116
Some(file) => file,
106117
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
107118
};
@@ -122,7 +133,18 @@ impl target::ext::host_io::HostIoPread for Emu {
122133
offset: u32,
123134
output: HostIoOutput<'a>,
124135
) -> HostIoResult<HostIoToken<'a>, Self> {
125-
let file = match self.files.get_mut(fd as usize) {
136+
if fd < FD_RESERVED {
137+
if fd == 0 {
138+
let len = TEST_PROGRAM_ELF.len();
139+
return Ok(output.write(
140+
&TEST_PROGRAM_ELF[len.min(offset as usize)..len.min((offset + count) as usize)],
141+
));
142+
} else {
143+
return Err(HostIoError::Errno(HostIoErrno::EBADF));
144+
}
145+
}
146+
147+
let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
126148
Some(Some(file)) => file,
127149
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
128150
};
@@ -136,7 +158,11 @@ impl target::ext::host_io::HostIoPread for Emu {
136158

137159
impl target::ext::host_io::HostIoPwrite for Emu {
138160
fn pwrite(&mut self, fd: u32, offset: u32, data: &[u8]) -> HostIoResult<u32, Self> {
139-
let file = match self.files.get_mut(fd as usize) {
161+
if fd < FD_RESERVED {
162+
return Err(HostIoError::Errno(HostIoErrno::EACCES));
163+
}
164+
165+
let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
140166
Some(Some(file)) => file,
141167
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
142168
};
@@ -149,7 +175,28 @@ impl target::ext::host_io::HostIoPwrite for Emu {
149175

150176
impl target::ext::host_io::HostIoFstat for Emu {
151177
fn fstat(&mut self, fd: u32) -> HostIoResult<HostIoStat, Self> {
152-
let metadata = match self.files.get(fd as usize) {
178+
if fd < FD_RESERVED {
179+
if fd == 0 {
180+
return Ok(HostIoStat {
181+
st_dev: 0,
182+
st_ino: 0,
183+
st_mode: HostIoOpenMode::empty(),
184+
st_nlink: 0,
185+
st_uid: 0,
186+
st_gid: 0,
187+
st_rdev: 0,
188+
st_size: TEST_PROGRAM_ELF.len() as u64,
189+
st_blksize: 0,
190+
st_blocks: 0,
191+
st_atime: 0,
192+
st_mtime: 0,
193+
st_ctime: 0,
194+
});
195+
} else {
196+
return Err(HostIoError::Errno(HostIoErrno::EBADF));
197+
}
198+
}
199+
let metadata = match self.files.get((fd - FD_RESERVED) as usize) {
153200
Some(Some(file)) => file.metadata()?,
154201
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
155202
};

examples/armv4t/gdb/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::emu::{Emu, Event};
1616

1717
mod breakpoints;
1818
mod catch_syscalls;
19+
mod exec_file;
1920
mod extended_mode;
2021
mod host_io;
2122
mod memory_map;
@@ -100,6 +101,11 @@ impl Target for Emu {
100101
fn host_io(&mut self) -> Option<target::ext::host_io::HostIoOps<Self>> {
101102
Some(self)
102103
}
104+
105+
#[inline(always)]
106+
fn exec_file(&mut self) -> Option<target::ext::exec_file::ExecFileOps<Self>> {
107+
Some(self)
108+
}
103109
}
104110

105111
impl Emu {

examples/armv4t/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use gdbstub::{target::Target, ConnectionExt, DisconnectReason, GdbStub};
99

1010
pub type DynResult<T> = Result<T, Box<dyn std::error::Error>>;
1111

12-
static TEST_PROGRAM_ELF: &[u8] = include_bytes!("test_bin/test.elf");
12+
pub static TEST_PROGRAM_ELF: &[u8] = include_bytes!("test_bin/test.elf");
1313

1414
mod emu;
1515
mod gdb;

examples/armv4t/test_bin/.gdbinit

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
file test.elf
21
target extended-remote :9001

src/gdbstub_impl/ext/base.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
115115
res.write_str(";qXfer:memory-map:read+")?;
116116
}
117117

118+
if target.exec_file().is_some() {
119+
res.write_str(";qXfer:exec-file:read+")?;
120+
}
121+
118122
HandlerStatus::Handled
119123
}
120124
Base::QStartNoAckMode(_) => {

src/gdbstub_impl/ext/exec_file.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use super::prelude::*;
2+
use crate::protocol::commands::ext::ExecFile;
3+
4+
impl<T: Target, C: Connection> GdbStubImpl<T, C> {
5+
pub(crate) fn handle_exec_file(
6+
&mut self,
7+
res: &mut ResponseWriter<C>,
8+
target: &mut T,
9+
command: ExecFile,
10+
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
11+
let ops = match target.exec_file() {
12+
Some(ops) => ops,
13+
None => return Ok(HandlerStatus::Handled),
14+
};
15+
16+
crate::__dead_code_marker!("exec_file", "impl");
17+
18+
let handler_status = match command {
19+
ExecFile::qXferExecFileRead(cmd) => {
20+
let filename = ops.get_exec_file(cmd.pid);
21+
res.write_binary_range(filename, cmd.offset, cmd.len)?;
22+
HandlerStatus::Handled
23+
}
24+
};
25+
26+
Ok(handler_status)
27+
}
28+
}

src/gdbstub_impl/ext/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod prelude {
1414
mod base;
1515
mod breakpoints;
1616
mod catch_syscalls;
17+
mod exec_file;
1718
mod extended_mode;
1819
mod host_io;
1920
mod memory_map;

src/gdbstub_impl/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
578578
Command::ReverseStep(cmd) => self.handle_reverse_step(res, target, cmd),
579579
Command::MemoryMap(cmd) => self.handle_memory_map(res, target, cmd),
580580
Command::HostIo(cmd) => self.handle_host_io(res, target, cmd),
581+
Command::ExecFile(cmd) => self.handle_exec_file(res, target, cmd),
581582
}
582583
}
583584
}

src/protocol/commands.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ commands! {
225225
"qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead,
226226
}
227227

228+
exec_file {
229+
"qXfer:exec-file:read" => _qXfer_exec_file::qXferExecFileRead,
230+
}
231+
228232
host_io use 'a {
229233
"vFile:open" => _vFile_open::vFileOpen<'a>,
230234
"vFile:close" => _vFile_close::vFileClose,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use super::prelude::*;
2+
3+
use crate::common::Pid;
4+
5+
#[derive(Debug)]
6+
pub struct qXferExecFileRead {
7+
pub pid: Option<Pid>,
8+
pub offset: usize,
9+
pub len: usize,
10+
}
11+
12+
impl<'a> ParseCommand<'a> for qXferExecFileRead {
13+
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
14+
let body = buf.into_body();
15+
16+
if body.is_empty() {
17+
return None;
18+
}
19+
20+
let mut body = body.split(|b| *b == b':').skip(1);
21+
let pid = decode_hex(body.next()?).ok().and_then(Pid::new);
22+
23+
let mut body = body.next()?.split(|b| *b == b',');
24+
let offset = decode_hex(body.next()?).ok()?;
25+
let len = decode_hex(body.next()?).ok()?;
26+
27+
Some(qXferExecFileRead {pid, offset, len})
28+
}
29+
}

src/protocol/commands/_vFile_setfs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ impl<'a> ParseCommand<'a> for vFileSetfs {
1616

1717
match body {
1818
[b':', body @ ..] => {
19-
let fs = match core::num::NonZeroUsize::new(decode_hex(body).ok()?) {
19+
let fs = match crate::common::Pid::new(decode_hex(body).ok()?) {
2020
None => FsKind::Stub,
2121
Some(pid) => FsKind::Pid(pid),
2222
};

src/target/ext/exec_file.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! Provide exec-file path for the target.
2+
use crate::target::Target;
3+
4+
use crate::common::Pid;
5+
6+
/// Target Extension - Provide current exec-file.
7+
pub trait ExecFile: Target {
8+
/// Return the full absolute name of the file that was executed to create a
9+
/// process running on the remote system.
10+
fn get_exec_file(&self, pid: Option<Pid>) -> &[u8];
11+
}
12+
13+
define_ext!(ExecFileOps, ExecFile);

src/target/ext/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ macro_rules! define_ext {
259259
pub mod base;
260260
pub mod breakpoints;
261261
pub mod catch_syscalls;
262+
pub mod exec_file;
262263
pub mod extended_mode;
263264
pub mod host_io;
264265
pub mod memory_map;

src/target/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ pub trait Target {
364364
fn host_io(&mut self) -> Option<ext::host_io::HostIoOps<Self>> {
365365
None
366366
}
367+
368+
/// Provide exec-file
369+
fn exec_file(&mut self) -> Option<ext::exec_file::ExecFileOps<Self>> {
370+
None
371+
}
367372
}
368373

369374
macro_rules! impl_dyn_target {
@@ -395,6 +400,11 @@ macro_rules! impl_dyn_target {
395400
(**self).monitor_cmd()
396401
}
397402

403+
#[inline(always)]
404+
fn exec_file(&mut self) -> Option<ext::exec_file::ExecFileOps<Self>> {
405+
(**self).exec_file()
406+
}
407+
398408
#[inline(always)]
399409
fn extended_mode(&mut self) -> Option<ext::extended_mode::ExtendedModeOps<Self>> {
400410
(**self).extended_mode()

0 commit comments

Comments
 (0)