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

Pass PacketBuf as an argument of API #72

Merged
merged 7 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 31 additions & 26 deletions examples/armv4t/gdb/host_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use std::io::{Read, Seek, Write};

use gdbstub::target;
use gdbstub::target::ext::host_io::{
FsKind, HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoOutput, HostIoResult,
HostIoStat, HostIoToken,
FsKind, HostIoErrno, HostIoError, HostIoOpenFlags, HostIoOpenMode, HostIoResult, HostIoStat,
};

use crate::emu::Emu;
Expand Down Expand Up @@ -133,16 +132,18 @@ impl target::ext::host_io::HostIoPread for Emu {
fn pread<'a>(
&mut self,
fd: u32,
count: u32,
offset: u32,
output: HostIoOutput<'a>,
) -> HostIoResult<HostIoToken<'a>, Self> {
count: usize,
offset: u64,
buf: &mut [u8],
) -> HostIoResult<usize, Self> {
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)],
));
let data =
&TEST_PROGRAM_ELF[len.min(offset as usize)..len.min(offset as usize + count)];
let buf = &mut buf[..data.len()];
buf.copy_from_slice(data);
return Ok(data.len());
} else {
return Err(HostIoError::Errno(HostIoErrno::EBADF));
}
Expand All @@ -153,10 +154,9 @@ impl target::ext::host_io::HostIoPread for Emu {
_ => return Err(HostIoError::Errno(HostIoErrno::EBADF)),
};

let mut buffer = vec![0; count as usize];
file.seek(std::io::SeekFrom::Start(offset as u64))?;
let n = file.read(&mut buffer)?;
Ok(output.write(&buffer[..n]))
file.seek(std::io::SeekFrom::Start(offset))?;
let n = file.read(buf)?;
Ok(n)
}
}

Expand Down Expand Up @@ -246,29 +246,34 @@ impl target::ext::host_io::HostIoUnlink for Emu {
}

impl target::ext::host_io::HostIoReadlink for Emu {
fn readlink<'a>(
&mut self,
filename: &[u8],
output: HostIoOutput<'a>,
) -> HostIoResult<HostIoToken<'a>, Self> {
fn readlink<'a>(&mut self, filename: &[u8], buf: &mut [u8]) -> HostIoResult<usize, Self> {
bet4it marked this conversation as resolved.
Show resolved Hide resolved
if filename == b"/proc/1/exe" {
// Support `info proc exe` command
return Ok(output.write(b"/test.elf"));
let exe = b"/test.elf";
let buf = &mut buf[..exe.len()];
buf.copy_from_slice(exe);
return Ok(exe.len());
} else if filename == b"/proc/1/cwd" {
// Support `info proc cwd` command
return Ok(output.write(b"/"));
let cwd = b"/";
let buf = &mut buf[..cwd.len()];
buf.copy_from_slice(cwd);
return Ok(cwd.len());
} else if filename.starts_with(b"/proc") {
return Err(HostIoError::Errno(HostIoErrno::ENOENT));
}

let path =
std::str::from_utf8(filename).map_err(|_| HostIoError::Errno(HostIoErrno::ENOENT))?;
Ok(output.write(
std::fs::read_link(path)?
.to_str()
.ok_or(HostIoError::Errno(HostIoErrno::ENOENT))?
.as_bytes(),
))
let link = std::fs::read_link(path)?;
let data = link
.to_str()
.ok_or(HostIoError::Errno(HostIoErrno::ENOENT))?
.as_bytes();
let len = data.len();
let buf = &mut buf[..len];
buf.copy_from_slice(data);
Ok(len)
}
}

Expand Down
18 changes: 16 additions & 2 deletions examples/armv4t/gdb/memory_map.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
use gdbstub::target;
use gdbstub::target::TargetResult;

use crate::emu::Emu;

impl target::ext::memory_map::MemoryMap for Emu {
fn memory_map_xml(&self) -> &str {
fn memory_map_xml(
&self,
offset: u64,
length: usize,
buf: &mut [u8],
) -> TargetResult<usize, Self> {
// Sample memory map, with RAM coverying the whole
// memory space.
r#"<?xml version="1.0"?>
let memory_map = r#"<?xml version="1.0"?>
<!DOCTYPE memory-map
PUBLIC "+//IDN gnu.org//DTD GDB Memory Map V1.0//EN"
"http://sourceware.org/gdb/gdb-memory-map.dtd">
<memory-map>
<memory type="ram" start="0x0" length="0x100000000"/>
</memory-map>"#
.trim()
.as_bytes();

let len = memory_map.len();
let data = &memory_map[len.min(offset as usize)..len.min(offset as usize + length)];
let buf = &mut buf[..data.len()];
buf.copy_from_slice(data);
Ok(data.len())
}
}
18 changes: 16 additions & 2 deletions examples/armv4t/gdb/target_description_xml_override.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use gdbstub::target;
use gdbstub::target::TargetResult;

use crate::emu::Emu;

impl target::ext::target_description_xml_override::TargetDescriptionXmlOverride for Emu {
fn target_description_xml(&self) -> &str {
r#"<?xml version="1.0"?>
fn target_description_xml(
&self,
offset: u64,
length: usize,
buf: &mut [u8],
) -> TargetResult<usize, Self> {
let xml = r#"<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>armv4t</architecture>
Expand Down Expand Up @@ -67,5 +73,13 @@ impl target::ext::target_description_xml_override::TargetDescriptionXmlOverride
</feature>
</target>
"#
.trim()
.as_bytes();

let len = xml.len();
let data = &xml[len.min(offset as usize)..len.min(offset as usize + length)];
let buf = &mut buf[..data.len()];
buf.copy_from_slice(data);
Ok(data.len())
}
}
33 changes: 21 additions & 12 deletions src/gdbstub_impl/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,29 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
}
Base::qXferFeaturesRead(cmd) => {
#[allow(clippy::redundant_closure)]
bet4it marked this conversation as resolved.
Show resolved Hide resolved
let xml = target
.target_description_xml_override()
.map(|ops| ops.target_description_xml())
.or_else(|| T::Arch::target_description_xml());

match xml {
Some(xml) => {
let ret = if let Some(ops) = target.target_description_xml_override() {
ops.target_description_xml(cmd.offset, cmd.length, cmd.buf)
.handle_error()?
} else {
bet4it marked this conversation as resolved.
Show resolved Hide resolved
if let Some(xml) = T::Arch::target_description_xml() {
let xml = xml.trim().as_bytes();
res.write_binary_range(xml, cmd.offset, cmd.len)?;
let len = xml.len();
let data = &xml[len.min(cmd.offset as usize)
..len.min(cmd.offset as usize + cmd.length)];
let buf = &mut cmd.buf[..data.len()];
buf.copy_from_slice(data);
data.len()
} else {
0
bet4it marked this conversation as resolved.
Show resolved Hide resolved
}
// If the target hasn't provided their own XML, then the initial response to
// "qSupported" wouldn't have included "qXfer:features:read", and gdb wouldn't
// send this packet unless it was explicitly marked as supported.
None => return Err(Error::PacketUnexpected),
};

if ret == 0 {
res.write_str("l")?;
} else {
res.write_str("m")?;
// TODO: add more specific error variant?
res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
}
HandlerStatus::Handled
}
Expand Down
48 changes: 11 additions & 37 deletions src/gdbstub_impl/ext/host_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::prelude::*;
use crate::protocol::commands::ext::HostIo;

use crate::arch::Arch;
use crate::target::ext::host_io::{HostIoError, HostIoOutput, HostIoStat};
use crate::target::ext::host_io::{HostIoError, HostIoStat};

impl<T: Target, C: Connection> GdbStubImpl<T, C> {
pub(crate) fn handle_host_io(
Expand Down Expand Up @@ -52,31 +52,16 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
HandlerStatus::Handled
}
HostIo::vFilePread(cmd) if ops.enable_pread().is_some() => {
let count = <T::Arch as Arch>::Usize::from_be_bytes(cmd.count)
.ok_or(Error::TargetMismatch)?;
let offset = <T::Arch as Arch>::Usize::from_be_bytes(cmd.offset)
.ok_or(Error::TargetMismatch)?;
let mut err: Result<_, Error<T::Error, C::Error>> = Ok(());
let mut callback = |data: &[u8]| {
let e = (|| {
let ops = ops.enable_pread().unwrap();
handle_hostio_result! {
if let Ok(ret) = ops.pread(cmd.fd, cmd.count, cmd.offset, cmd.buf) => {
res.write_str("F")?;
res.write_num(data.len())?;
res.write_num(ret)?;
res.write_str(";")?;
res.write_binary(data)?;
Ok(())
})();

if let Err(e) = e {
err = Err(e)
res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
}
};

let ops = ops.enable_pread().unwrap();
handle_hostio_result! {
if let Ok(_) = ops.pread(cmd.fd, count, offset, HostIoOutput::new(&mut callback)) => {}
};
err?;

HandlerStatus::Handled
}
HostIo::vFilePwrite(cmd) if ops.enable_pwrite().is_some() => {
Expand Down Expand Up @@ -126,27 +111,16 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {
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 = (|| {
let ops = ops.enable_readlink().unwrap();
handle_hostio_result! {
if let Ok(ret) = ops.readlink(cmd.filename, cmd.buf) => {
res.write_str("F")?;
res.write_num(data.len())?;
res.write_num(ret)?;
res.write_str(";")?;
res.write_binary(data)?;
Ok(())
})();

if let Err(e) = e {
err = Err(e)
res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
}
};

let ops = ops.enable_readlink().unwrap();
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() => {
Expand Down
12 changes: 10 additions & 2 deletions src/gdbstub_impl/ext/memory_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,16 @@ impl<T: Target, C: Connection> GdbStubImpl<T, C> {

let handler_status = match command {
MemoryMap::qXferMemoryMapRead(cmd) => {
let xml = ops.memory_map_xml().trim().as_bytes();
res.write_binary_range(xml, cmd.offset, cmd.len)?;
let ret = ops
.memory_map_xml(cmd.offset, cmd.length, cmd.buf)
.handle_error()?;
if ret == 0 {
res.write_str("l")?;
} else {
res.write_str("m")?;
// TODO: add more specific error variant?
res.write_binary(cmd.buf.get(..ret).ok_or(Error::PacketBufferOverflow)?)?;
}
HandlerStatus::Handled
}
};
Expand Down
6 changes: 3 additions & 3 deletions src/protocol/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ commands! {
"QStartNoAckMode" => _QStartNoAckMode::QStartNoAckMode,
"qsThreadInfo" => _qsThreadInfo::qsThreadInfo,
"qSupported" => _qSupported::qSupported<'a>,
"qXfer:features:read" => _qXfer_features_read::qXferFeaturesRead,
"qXfer:features:read" => _qXfer_features_read::qXferFeaturesRead<'a>,
"s" => _s::s<'a>,
"T" => _t_upcase::T,
"vCont" => _vCont::vCont<'a>,
Expand Down Expand Up @@ -221,8 +221,8 @@ commands! {
"bs" => _bs::bs,
}

memory_map {
"qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead,
memory_map use 'a {
"qXfer:memory-map:read" => _qXfer_memory_map::qXferMemoryMapRead<'a>,
}

exec_file use 'a {
Expand Down
19 changes: 12 additions & 7 deletions src/protocol/commands/_qXfer_features_read.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use super::prelude::*;

#[derive(Debug)]
pub struct qXferFeaturesRead {
pub offset: usize,
pub len: usize,
pub struct qXferFeaturesRead<'a> {
pub offset: u64,
pub length: usize,

pub buf: &'a mut [u8],
}

impl<'a> ParseCommand<'a> for qXferFeaturesRead {
impl<'a> ParseCommand<'a> for qXferFeaturesRead<'a> {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();
let (buf, body_range) = buf.into_raw_buf();
let body = buf.get_mut(body_range.start..body_range.end)?;

if body.is_empty() {
return None;
Expand All @@ -22,8 +25,10 @@ impl<'a> ParseCommand<'a> for qXferFeaturesRead {

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

drop(body);

Some(qXferFeaturesRead { offset, len })
Some(qXferFeaturesRead { offset, length, buf })
}
}
19 changes: 12 additions & 7 deletions src/protocol/commands/_qXfer_memory_map.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use super::prelude::*;

#[derive(Debug)]
pub struct qXferMemoryMapRead {
pub offset: usize,
pub len: usize,
pub struct qXferMemoryMapRead<'a> {
pub offset: u64,
pub length: usize,

pub buf: &'a mut [u8],
}

impl<'a> ParseCommand<'a> for qXferMemoryMapRead {
impl<'a> ParseCommand<'a> for qXferMemoryMapRead<'a> {
fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
let body = buf.into_body();
let (buf, body_range) = buf.into_raw_buf();
let body = buf.get_mut(body_range.start..body_range.end)?;

if body.is_empty() {
return None;
Expand All @@ -22,8 +25,10 @@ impl<'a> ParseCommand<'a> for qXferMemoryMapRead {

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

drop(body);

Some(qXferMemoryMapRead { offset, len })
Some(qXferMemoryMapRead { offset, length , buf})
}
}