Skip to content

Commit

Permalink
Support read exec-file
Browse files Browse the repository at this point in the history
  • Loading branch information
bet4it committed Aug 23, 2021
1 parent 9227dfd commit 8f0aa74
Show file tree
Hide file tree
Showing 16 changed files with 162 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Of course, most use-cases will want to support additional debugging features as
- Extend the GDB protocol with custom debug commands using GDB's `monitor` command
- Get target memory map
- Perform Host I/O operations
- Get target exec file

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

Expand Down
10 changes: 10 additions & 0 deletions examples/armv4t/gdb/exec_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use gdbstub::common::Pid;
use gdbstub::target;

use crate::emu::Emu;

impl target::ext::exec_file::ExecFile for Emu {
fn get_exec_file(&self, _pid: Option<Pid>) -> &[u8] {
b"/test.elf"
}
}
57 changes: 52 additions & 5 deletions examples/armv4t/gdb/host_io.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::io::{Read, Seek, Write};

use crate::TEST_PROGRAM_ELF;
use gdbstub::target;
use gdbstub::target::ext::host_io::{
FsKind, HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoOutput, HostIoResult,
Expand All @@ -8,6 +9,8 @@ use gdbstub::target::ext::host_io::{

use crate::emu::Emu;

const FD_RESERVED: u32 = 1;

impl target::ext::host_io::HostIo for Emu {
#[inline(always)]
fn enable_open(&mut self) -> Option<target::ext::host_io::HostIoOpenOps<Self>> {
Expand Down Expand Up @@ -61,6 +64,10 @@ impl target::ext::host_io::HostIoOpen for Emu {
return Err(HostIoError::Errno(HostIoErrno::ENOENT));
}

if filename == b"/test.elf" {
return Ok(0);
}

let path =
std::str::from_utf8(filename).map_err(|_| HostIoError::Errno(HostIoErrno::ENOENT))?;

Expand Down Expand Up @@ -95,13 +102,17 @@ impl target::ext::host_io::HostIoOpen for Emu {
}
};

Ok(n as u32)
Ok(n as u32 + FD_RESERVED)
}
}

impl target::ext::host_io::HostIoClose for Emu {
fn close(&mut self, fd: u32) -> HostIoResult<(), Self> {
let file = match self.files.get_mut(fd as usize) {
if fd < FD_RESERVED {
return Ok(());
}

let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
Some(file) => file,
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
};
Expand All @@ -122,7 +133,18 @@ impl target::ext::host_io::HostIoPread for Emu {
offset: u32,
output: HostIoOutput<'a>,
) -> HostIoResult<HostIoToken<'a>, Self> {
let file = match self.files.get_mut(fd as usize) {
if fd < FD_RESERVED {
if fd == 0 {
let len = TEST_PROGRAM_ELF.len();
return Ok(output.write(
&TEST_PROGRAM_ELF[len.min(offset as usize)..len.min((offset + count) as usize)],
));
} else {
return Err(HostIoError::Errno(HostIoErrno::EBADF));
}
}

let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
Some(Some(file)) => file,
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
};
Expand All @@ -136,7 +158,11 @@ impl target::ext::host_io::HostIoPread for Emu {

impl target::ext::host_io::HostIoPwrite for Emu {
fn pwrite(&mut self, fd: u32, offset: u32, data: &[u8]) -> HostIoResult<u32, Self> {
let file = match self.files.get_mut(fd as usize) {
if fd < FD_RESERVED {
return Err(HostIoError::Errno(HostIoErrno::EACCES));
}

let file = match self.files.get_mut((fd - FD_RESERVED) as usize) {
Some(Some(file)) => file,
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
};
Expand All @@ -149,7 +175,28 @@ impl target::ext::host_io::HostIoPwrite for Emu {

impl target::ext::host_io::HostIoFstat for Emu {
fn fstat(&mut self, fd: u32) -> HostIoResult<HostIoStat, Self> {
let metadata = match self.files.get(fd as usize) {
if fd < FD_RESERVED {
if fd == 0 {
return Ok(HostIoStat {
st_dev: 0,
st_ino: 0,
st_mode: HostIoOpenMode::empty(),
st_nlink: 0,
st_uid: 0,
st_gid: 0,
st_rdev: 0,
st_size: TEST_PROGRAM_ELF.len() as u64,
st_blksize: 0,
st_blocks: 0,
st_atime: 0,
st_mtime: 0,
st_ctime: 0,
});
} else {
return Err(HostIoError::Errno(HostIoErrno::EBADF));
}
}
let metadata = match self.files.get((fd - FD_RESERVED) as usize) {
Some(Some(file)) => file.metadata()?,
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
};
Expand Down
6 changes: 6 additions & 0 deletions examples/armv4t/gdb/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::emu::{Emu, Event};

mod breakpoints;
mod catch_syscalls;
mod exec_file;
mod extended_mode;
mod host_io;
mod memory_map;
Expand Down Expand Up @@ -100,6 +101,11 @@ impl Target for Emu {
fn host_io(&mut self) -> Option<target::ext::host_io::HostIoOps<Self>> {
Some(self)
}

#[inline(always)]
fn exec_file(&mut self) -> Option<target::ext::exec_file::ExecFileOps<Self>> {
Some(self)
}
}

impl Emu {
Expand Down
2 changes: 1 addition & 1 deletion examples/armv4t/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use gdbstub::{target::Target, ConnectionExt, DisconnectReason, GdbStub};

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

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

mod emu;
mod gdb;
Expand Down
1 change: 0 additions & 1 deletion examples/armv4t/test_bin/.gdbinit
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
file test.elf
target extended-remote :9001
4 changes: 4 additions & 0 deletions src/gdbstub_impl/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
res.write_str(";qXfer:memory-map:read+")?;
}

if target.exec_file().is_some() {
res.write_str(";qXfer:exec-file:read+")?;
}

HandlerStatus::Handled
}
Base::QStartNoAckMode(_) => {
Expand Down
28 changes: 28 additions & 0 deletions src/gdbstub_impl/ext/exec_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use super::prelude::*;
use crate::protocol::commands::ext::ExecFile;

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_exec_file(
&mut self,
res: &mut ResponseWriter<C>,
target: &mut T,
command: ExecFile,
) -> Result<HandlerStatus, Error<T::Error, C::Error>> {
let ops = match target.exec_file() {
Some(ops) => ops,
None => return Ok(HandlerStatus::Handled),
};

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

let handler_status = match command {
ExecFile::qXferExecFileRead(cmd) => {
let filename = ops.get_exec_file(cmd.pid);
res.write_binary_range(filename, cmd.offset, cmd.len)?;
HandlerStatus::Handled
}
};

Ok(handler_status)
}
}
1 change: 1 addition & 0 deletions src/gdbstub_impl/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod prelude {
mod base;
mod breakpoints;
mod catch_syscalls;
mod exec_file;
mod extended_mode;
mod host_io;
mod memory_map;
Expand Down
1 change: 1 addition & 0 deletions src/gdbstub_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
Command::ReverseStep(cmd) => self.handle_reverse_step(res, target, cmd),
Command::MemoryMap(cmd) => self.handle_memory_map(res, target, cmd),
Command::HostIo(cmd) => self.handle_host_io(res, target, cmd),
Command::ExecFile(cmd) => self.handle_exec_file(res, target, cmd),
}
}
}
4 changes: 4 additions & 0 deletions src/protocol/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ commands! {
"qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead,
}

exec_file {
"qXfer:exec-file:read" => _qXfer_exec_file::qXferExecFileRead,
}

host_io use 'a {
"vFile:open" => _vFile_open::vFileOpen<'a>,
"vFile:close" => _vFile_close::vFileClose,
Expand Down
29 changes: 29 additions & 0 deletions src/protocol/commands/_qXfer_exec_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use super::prelude::*;

use crate::common::Pid;

#[derive(Debug)]
pub struct qXferExecFileRead {
pub pid: Option<Pid>,
pub offset: usize,
pub len: usize,
}

impl<'a> ParseCommand<'a> for qXferExecFileRead {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();

if body.is_empty() {
return None;
}

let mut body = body.split(|b| *b == b':').skip(1);
let pid = decode_hex(body.next()?).ok().and_then(Pid::new);

let mut body = body.next()?.split(|b| *b == b',');
let offset = decode_hex(body.next()?).ok()?;
let len = decode_hex(body.next()?).ok()?;

Some(qXferExecFileRead {pid, offset, len})
}
}
2 changes: 1 addition & 1 deletion src/protocol/commands/_vFile_setfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl<'a> ParseCommand<'a> for vFileSetfs {

match body {
[b':', body @ ..] => {
let fs = match core::num::NonZeroUsize::new(decode_hex(body).ok()?) {
let fs = match crate::common::Pid::new(decode_hex(body).ok()?) {
None => FsKind::Stub,
Some(pid) => FsKind::Pid(pid),
};
Expand Down
13 changes: 13 additions & 0 deletions src/target/ext/exec_file.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//! Provide exec-file path for the target.
use crate::target::Target;

use crate::common::Pid;

/// Target Extension - Provide current exec-file.
pub trait ExecFile: Target {
/// Return the full absolute name of the file that was executed to create a
/// process running on the remote system.
fn get_exec_file(&self, pid: Option<Pid>) -> &[u8];
}

define_ext!(ExecFileOps, ExecFile);
1 change: 1 addition & 0 deletions src/target/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ macro_rules! define_ext {
pub mod base;
pub mod breakpoints;
pub mod catch_syscalls;
pub mod exec_file;
pub mod extended_mode;
pub mod host_io;
pub mod memory_map;
Expand Down
10 changes: 10 additions & 0 deletions src/target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ pub trait Target {
fn host_io(&mut self) -> Option<ext::host_io::HostIoOps<Self>> {
None
}

/// Provide exec-file
fn exec_file(&mut self) -> Option<ext::exec_file::ExecFileOps<Self>> {
None
}
}

macro_rules! impl_dyn_target {
Expand Down Expand Up @@ -395,6 +400,11 @@ macro_rules! impl_dyn_target {
(**self).monitor_cmd()
}

#[inline(always)]
fn exec_file(&mut self) -> Option<ext::exec_file::ExecFileOps<Self>> {
(**self).exec_file()
}

#[inline(always)]
fn extended_mode(&mut self) -> Option<ext::extended_mode::ExtendedModeOps<Self>> {
(**self).extended_mode()
Expand Down

0 comments on commit 8f0aa74

Please sign in to comment.