Verified Commit 3476c15d authored by jD91mZM2's avatar jD91mZM2

Use local gdb-remote-protocol that supports vCont

parent cdab5f72
......@@ -41,18 +41,9 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdb-protocol"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gdb-remote-protocol"
version = "0.1.0"
source = "git+https://github.com/luser/rust-gdb-remote-protocol#c3f773ba3b232376ef904b50859a946c23910571"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -64,8 +55,7 @@ dependencies = [
name = "gdbserver"
version = "0.1.0"
dependencies = [
"gdb-protocol 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdb-remote-protocol 0.1.0 (git+https://github.com/luser/rust-gdb-remote-protocol)",
"gdb-remote-protocol 0.1.0",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -259,8 +249,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum gdb-protocol 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8b88b222a91266bb192222d46d0da29addbc423d0a9910aec233dce875eb6e"
"checksum gdb-remote-protocol 0.1.0 (git+https://github.com/luser/rust-gdb-remote-protocol)" = "<none>"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
......
......@@ -5,8 +5,8 @@ authors = ["jD91mZM2 <me@krake.one>"]
edition = "2018"
[dependencies]
gdb-protocol = "0.1.0"
gdb-remote-protocol = { git = "https://github.com/luser/rust-gdb-remote-protocol" }
# gdb-remote-protocol = { git = "https://github.com/luser/rust-gdb-remote-protocol" }
gdb-remote-protocol = { path = "../external/rust-gdb-remote-protocol/" }
structopt = "0.2.18"
memchr = "2.2.1"
libc = "0.2.62"
......@@ -4,13 +4,13 @@ use gdb_remote_protocol::{
MemoryRegion,
ProcessType,
StopReason,
ThreadId,
VCont,
VContFeature,
};
use structopt::StructOpt;
use std::{
net::{TcpListener, TcpStream},
io::prelude::*,
};
use std::{borrow::Cow, net::TcpListener};
mod os;
......@@ -27,43 +27,65 @@ struct Opt {
args: Vec<String>,
}
pub type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub struct App {
tracee: Os,
}
impl Handler for App {
fn attached(&self, _pid: Option<u64>) -> Result<ProcessType, Error> {
fn attached(&self, _pid: Option<u64>) -> Result<ProcessType> {
Ok(ProcessType::Created)
}
fn halt_reason(&self) -> Result<StopReason, Error> {
fn halt_reason(&self) -> Result<StopReason> {
Ok(self.tracee.status())
}
fn read_general_registers(&self) -> Result<Vec<u8>, Error> {
let regs = self.tracee.getregs().map_err(|e| Error::Error(e as _))?;
fn read_general_registers(&self) -> Result<Vec<u8>> {
let regs = self.tracee.getregs()?;
let mut bytes = Vec::new();
regs.encode(&mut bytes);
Ok(bytes)
}
fn write_general_registers(&self, content: &[u8]) -> Result<(), Error> {
fn write_general_registers(&self, content: &[u8]) -> Result<()> {
let regs = Registers::decode(content);
self.tracee.setregs(&regs).map_err(|e| Error::Error(e as _))?;
self.tracee.setregs(&regs)?;
Ok(())
}
fn read_memory(&self, region: MemoryRegion) -> Result<Vec<u8>, Error> {
fn read_memory(&self, region: MemoryRegion) -> Result<Vec<u8>> {
let mut buf = vec![0; region.length as usize];
self.tracee.getmem(region.address as usize, &mut buf).map_err(|e| Error::Error(e as _))?;
self.tracee.getmem(region.address as usize, &mut buf)?;
Ok(buf)
}
fn write_memory(&self, address: u64, bytes: &[u8]) -> Result<(), Error> {
self.tracee.setmem(bytes, address as usize).map_err(|e| Error::Error(e as _))?;
fn write_memory(&self, address: u64, bytes: &[u8]) -> Result<()> {
self.tracee.setmem(bytes, address as usize)?;
Ok(())
}
fn query_supported_vcont(&self) -> Result<Cow<'static, [VContFeature]>> {
Ok(Cow::Borrowed(&[
VContFeature::Continue, VContFeature::ContinueWithSignal,
VContFeature::Step, VContFeature::StepWithSignal,
VContFeature::RangeStep,
]))
}
fn vcont(&self, actions: Vec<(VCont, Option<ThreadId>)>) -> Result<StopReason> {
if let Some((cmd, _id)) = actions.first() {
match *cmd {
VCont::Continue => { self.tracee.cont(None)?; },
VCont::ContinueWithSignal(signal) => { self.tracee.cont(Some(signal))?; },
VCont::Step => { self.tracee.step(None)?; },
VCont::StepWithSignal(signal) => { self.tracee.step(Some(signal))?; },
// std::ops::Range<T: Copy> should probably also be Copy, but it isn't.
VCont::RangeStep(ref range) => { self.tracee.resume(range.clone())?; },
_ => return Err(Error::Unimplemented),
}
}
Ok(self.tracee.status())
}
}
fn main() -> Result<()> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut opt = Opt::from_args();
opt.args.insert(0, opt.program.clone());
......@@ -80,68 +102,5 @@ fn main() -> Result<()> {
tracee,
});
/*
stream.dispatch(&match packet.data.first() {
Some(b'v') => {
// if packet.data[1..].starts_with(b"Run") {
// let mut cursor = &packet.data[1..];
// loop {
// let arg_end = memchr::memchr(b';', &cursor);
// println!("Arg: {:?}", std::str::from_utf8(&cursor[..arg_end.unwrap_or_else(|| cursor.len())]));
// match arg_end {
// Some(arg_end) => cursor = &cursor[arg_end+1..],
// None => break,
// }
// }
// CheckedPacket::from_data(Kind::Packet, b"W00".to_vec())
if packet.data[1..].starts_with(b"Cont") {
let data = &packet.data[1 + 4..];
match data.first() {
Some(b'?') => {
CheckedPacket::from_data(Kind::Packet, b"vCont;s;c;S;C;r".to_vec())
}
Some(b';') => match data.get(1) {
Some(b's') => {
tracee.step(None)?;
encode_status(&mut tracee)
}
Some(b'S') => {
let slice = data.get(2..4).ok_or("gdb didn't send a signal")?;
let signal = u8::from_str_radix(std::str::from_utf8(&slice)?, 16)?;
tracee.step(Some(signal))?;
encode_status(&mut tracee)
}
Some(b'c') => {
tracee.cont(None)?;
encode_status(&mut tracee)
}
Some(b'C') => {
let slice = data.get(2..4).ok_or("gdb didn't send a signal")?;
let signal = u8::from_str_radix(std::str::from_utf8(&slice)?, 16)?;
tracee.cont(Some(signal))?;
encode_status(&mut tracee)
}
Some(b'r') => {
let data = &data[2..];
let sep1 = memchr::memchr(b',', data)
.ok_or("gdb didn't send an end value")?;
let (start, end) = data.split_at(sep1);
let sep2 = memchr::memchr(b':', end).unwrap_or_else(|| end.len());
let start = u64::from_str_radix(std::str::from_utf8(start)?, 16)?;
let end =
u64::from_str_radix(std::str::from_utf8(&end[1..sep2])?, 16)?;
tracee.resume(start..end)?;
encode_status(&mut tracee)
}
_ => CheckedPacket::empty(),
},
_ => CheckedPacket::empty(),
}
}
*/
Ok(())
}
......@@ -9,29 +9,38 @@ use std::{
ptr,
};
use gdb_remote_protocol::StopReason;
use gdb_remote_protocol::{Error, StopReason};
pub struct Os {
pid: libc::pid_t,
last_status: Cell<libc::c_int>,
}
// Handle error as Rust: Return an io::Error
macro_rules! re {
($result:expr) => {{
let result = $result;
if result == -1 {
return Err(Box::new(io::Error::last_os_error()));
}
result
}};
trait FromOsError: Sized {
fn from_os_error(errno: libc::c_int) -> Self;
}
impl FromOsError for Error {
fn from_os_error(errno: libc::c_int) -> Self {
Error::Error(errno as u8)
}
}
impl FromOsError for io::Error {
fn from_os_error(errno: libc::c_int) -> Self {
io::Error::from_raw_os_error(errno as i32)
}
}
// Handle error as C: Return the errno
macro_rules! ce {
impl FromOsError for Box<dyn std::error::Error> {
fn from_os_error(errno: libc::c_int) -> Self {
Box::new(io::Error::from_os_error(errno))
}
}
macro_rules! e {
($result:expr) => {{
let result = $result;
if result == -1 {
return Err(*libc::__errno_location() as i32);
return Err(FromOsError::from_os_error(*libc::__errno_location()));
}
result
}};
......@@ -75,7 +84,7 @@ where
}
impl super::Target for Os {
fn new(program: String, args: Vec<String>) -> Result<Self> {
fn new(program: String, args: Vec<String>) -> Result<Self, Box<dyn std::error::Error>> {
let program = CString::new(program)?.into_raw();
let args = args
.into_iter()
......@@ -117,11 +126,11 @@ impl super::Target for Os {
// Wait for tracee to stop
let mut status = 0;
re!(libc::waitpid(pid, &mut status, 0));
e!(libc::waitpid(pid, &mut status, 0));
// Skip until post-execve
re!(libc::ptrace(libc::PTRACE_CONT, pid, 0, 0));
re!(libc::waitpid(pid, &mut status, 0));
e!(libc::ptrace(libc::PTRACE_CONT, pid, 0, 0));
e!(libc::waitpid(pid, &mut status, 0));
Ok(Os {
pid,
......@@ -145,10 +154,10 @@ impl super::Target for Os {
}
}
fn getregs(&self) -> Result<Registers, i32> {
fn getregs(&self) -> Result<Registers> {
let int = unsafe {
let mut int: MaybeUninit<libc::user_regs_struct> = MaybeUninit::uninit();
ce!(libc::ptrace(
e!(libc::ptrace(
libc::PTRACE_GETREGS,
self.pid,
0,
......@@ -159,7 +168,7 @@ impl super::Target for Os {
let float = unsafe {
let mut float: MaybeUninit<libc::user_fpregs_struct> = MaybeUninit::uninit();
ce!(libc::ptrace(
e!(libc::ptrace(
libc::PTRACE_GETFPREGS,
self.pid,
0,
......@@ -231,7 +240,7 @@ impl super::Target for Os {
Ok(registers)
}
fn setregs(&self, registers: &Registers) -> Result<(), i32> {
fn setregs(&self, registers: &Registers) -> Result<()> {
let mut int: libc::user_regs_struct = unsafe { MaybeUninit::zeroed().assume_init() };
let mut float: libc::user_fpregs_struct = unsafe { MaybeUninit::zeroed().assume_init() };
......@@ -313,29 +322,29 @@ impl super::Target for Os {
int.orig_rax = registers.orig_rax.map(|r| r as _).unwrap_or(int.orig_rax);
unsafe {
ce!(libc::ptrace(libc::PTRACE_SETREGS, self.pid, 0, &int));
ce!(libc::ptrace(libc::PTRACE_SETFPREGS, self.pid, 0, &float));
e!(libc::ptrace(libc::PTRACE_SETREGS, self.pid, 0, &int));
e!(libc::ptrace(libc::PTRACE_SETFPREGS, self.pid, 0, &float));
}
Ok(())
}
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize, i32> {
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize> {
// TODO: Don't report errors when able to read part of requested?
// Also implement this in the Redox kernel perhaps
getmem(src, dest, |addr| unsafe {
Ok(ce!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, addr)) as usize)
Ok(e!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, addr)) as usize)
})
}
fn setmem(&self, src: &[u8], dest: usize) -> Result<(), i32> {
fn setmem(&self, src: &[u8], dest: usize) -> Result<()> {
println!("Writing {:02X?} to address {:X}", src, dest);
setmem(
src,
dest,
|addr| unsafe { Ok(ce!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, addr)) as usize) },
|addr| unsafe { Ok(e!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, addr)) as usize) },
|addr, word| unsafe {
ce!(libc::ptrace(libc::PTRACE_POKEDATA, self.pid, addr, word));
e!(libc::ptrace(libc::PTRACE_POKEDATA, self.pid, addr, word));
Ok(())
},
)
......@@ -343,21 +352,21 @@ impl super::Target for Os {
fn step(&self, signal: Option<u8>) -> Result<Option<u64>> {
unsafe {
re!(libc::ptrace(
e!(libc::ptrace(
libc::PTRACE_SINGLESTEP,
self.pid,
0,
signal.unwrap_or(0) as libc::c_uint
));
let mut status = 0;
re!(libc::waitpid(self.pid, &mut status, 0));
e!(libc::waitpid(self.pid, &mut status, 0));
self.last_status.set(status);
Ok(
if libc::WIFSTOPPED(self.last_status.get())
&& libc::WSTOPSIG(self.last_status.get()) == libc::SIGTRAP
{
let rip = re!(libc::ptrace(
let rip = e!(libc::ptrace(
libc::PTRACE_PEEKUSER,
self.pid,
libc::RIP as usize * mem::size_of::<usize>()
......@@ -373,14 +382,14 @@ impl super::Target for Os {
fn cont(&self, signal: Option<u8>) -> Result<()> {
unsafe {
re!(libc::ptrace(
e!(libc::ptrace(
libc::PTRACE_CONT,
self.pid,
0,
signal.unwrap_or(0) as libc::c_uint
));
let mut status = 0;
re!(libc::waitpid(self.pid, &mut status, 0));
e!(libc::waitpid(self.pid, &mut status, 0));
self.last_status.set(status);
}
Ok(())
......
......@@ -15,22 +15,22 @@ pub use sys::Os;
pub trait Target: Sized {
/// Spawn a new tracee and return a tracer for it
fn new(program: String, args: Vec<String>) -> Result<Os>;
fn new(program: String, args: Vec<String>) -> Result<Os, Box<dyn std::error::Error>>;
/// Get the last status of the tracee
fn status(&self) -> StopReason;
/// Read all the process register
fn getregs(&self) -> Result<Registers, i32>;
fn getregs(&self) -> Result<Registers>;
/// Read all the process register
fn setregs(&self, regs: &Registers) -> Result<(), i32>;
fn setregs(&self, regs: &Registers) -> Result<()>;
/// Read a region of memory from tracee
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize, i32>;
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize>;
/// Read a region of memory from tracee
fn setmem(&self, src: &[u8], dest: usize) -> Result<(), i32>;
fn setmem(&self, src: &[u8], dest: usize) -> Result<()>;
/// Single-step one instruction, return instruction pointer
fn step(&self, signal: Option<u8>) -> Result<Option<u64>>;
......
use crate::Result;
use std::{
io::prelude::*,
iter,
};
use std::iter;
#[derive(Default)]
pub struct Registers {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment