Verified Commit cdab5f72 authored by jD91mZM2's avatar jD91mZM2

Switch to rust-gdb-remote-protocol

parent 7fd60c8d
......@@ -22,6 +22,11 @@ name = "bitflags"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.0"
......@@ -44,11 +49,23 @@ 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)",
"strum 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strum_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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)",
"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)",
......@@ -67,11 +84,35 @@ name = "libc"
version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "3.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
......@@ -80,6 +121,11 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.6.13"
......@@ -113,6 +159,30 @@ dependencies = [
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strum"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strum_macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.44"
......@@ -123,6 +193,14 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
......@@ -141,6 +219,11 @@ name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
......@@ -174,20 +257,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"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"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "16c2cdbf9cc375f15d1b4141bc48aeef444806655cd0e904207edc8d68d86ed7"
"checksum structopt-derive 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
"checksum strum 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da"
"checksum strum_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3384590878eb0cab3b128e844412e2d010821e7e091211b9d87324173ada7db8"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
......
......@@ -6,8 +6,7 @@ edition = "2018"
[dependencies]
gdb-protocol = "0.1.0"
# gdb-protocol = { git = "https://gitlab.redox-os.org/redox-os/gdb-protocol" }
# gdb-protocol = { path = "../gdb-protocol/" }
gdb-remote-protocol = { git = "https://github.com/luser/rust-gdb-remote-protocol" }
structopt = "0.2.18"
memchr = "2.2.1"
libc = "0.2.62"
......@@ -8,6 +8,7 @@ let
'';
gdb-test = pkgs.writers.writeBashBin "gdb-test" ''
${gdb-init}/bin/gdb \
-ex "set debug remote 1" \
-ex "target remote :64126" \
"$@"
'';
......
use gdb_protocol::{
io::GdbServer,
packet::{CheckedPacket, Kind},
use gdb_remote_protocol::{
Error,
Handler,
MemoryRegion,
ProcessType,
StopReason,
};
use structopt::StructOpt;
use std::io::prelude::*;
use std::{
net::{TcpListener, TcpStream},
io::prelude::*,
};
mod os;
use os::{Os, Registers, Status, Target};
use os::{Os, Registers, Target};
#[derive(Debug, StructOpt)]
struct Opt {
......@@ -23,122 +29,59 @@ struct Opt {
pub type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
// fn get_hex_int(buf: &[u8]) -> Result<(&[u8], usize)> {
// let nondigit = buf.iter().position(|b| !(b as char).is_digit(16));
// let (digits, trail) = buf.split_at(nondigit);
// let string = std::str::from_utf8(&digits)?;
// Ok((&trail, string.parse()?))
// }
fn encode_status(tracee: &mut Os) -> CheckedPacket {
let mut bytes = Vec::new();
match tracee.status() {
Status::Exited(status) => write!(bytes, "W{:02X}", status).unwrap(),
Status::Signaled(status) => write!(bytes, "X{:02X}", status).unwrap(),
Status::Stopped(status) => write!(bytes, "T{:02X}", status).unwrap(),
pub struct App {
tracee: Os,
}
impl Handler for App {
fn attached(&self, _pid: Option<u64>) -> Result<ProcessType, Error> {
Ok(ProcessType::Created)
}
fn halt_reason(&self) -> Result<StopReason, Error> {
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 _))?;
let mut bytes = Vec::new();
regs.encode(&mut bytes);
Ok(bytes)
}
fn write_general_registers(&self, content: &[u8]) -> Result<(), Error> {
let regs = Registers::decode(content);
self.tracee.setregs(&regs).map_err(|e| Error::Error(e as _))?;
Ok(())
}
fn read_memory(&self, region: MemoryRegion) -> Result<Vec<u8>, Error> {
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 _))?;
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 _))?;
Ok(())
}
CheckedPacket::from_data(Kind::Packet, bytes)
}
fn main() -> Result<()> {
let mut opt = Opt::from_args();
let mut stream = GdbServer::listen(opt.addr)?;
opt.args.insert(0, opt.program.clone());
let mut tracee = Os::new(opt.program, opt.args)?;
while let Some(packet) = stream.next_packet()? {
println!(
"-> {:?} {:?}",
packet.kind,
std::str::from_utf8(&packet.data)
);
let mut writer = {
let listener = TcpListener::bind(opt.addr)?;
let (stream, _addr) = listener.accept()?;
stream
};
let mut reader = writer.try_clone()?;
let tracee = Os::new(opt.program, opt.args)?;
gdb_remote_protocol::process_packets_from(&mut reader, &mut writer, App {
tracee,
});
/*
stream.dispatch(&match packet.data.first() {
// Maybe extended mode isn't that good, as it'll allow GDB to read the whole filesystem
// Some(b'!') => {
// CheckedPacket::from_data(Kind::Packet, b"OK".to_vec())
// },
Some(b'?') => encode_status(&mut tracee),
Some(b'g') => {
let mut out = Vec::new();
match tracee.getregs() {
Ok(regs) => regs.encode(&mut out)?,
Err(errno) => write!(out, "E{:02X}", errno).unwrap(),
}
CheckedPacket::from_data(Kind::Packet, out)
}
Some(b'G') => {
let mut out = Vec::new();
let regs = Registers::decode(&packet.data[1..])?;
match tracee.setregs(&regs) {
Ok(()) => write!(out, "OK").unwrap(),
Err(errno) => write!(out, "E{:02X}", errno).unwrap(),
}
CheckedPacket::from_data(Kind::Packet, out)
}
Some(b'm') => {
let data = &packet.data[1..];
let sep = memchr::memchr(b',', &data).ok_or("gdb didn't send a memory length")?;
let (addr, len) = data.split_at(sep);
let addr = usize::from_str_radix(std::str::from_utf8(&addr)?, 16)?;
let len = usize::from_str_radix(std::str::from_utf8(&len[1..])?, 16)?;
let mut out = Vec::new();
let mut bytes = vec![0; len];
match tracee.getmem(addr, &mut bytes) {
Ok(read) => {
for byte in &bytes[..read] {
write!(out, "{:02X}", byte).unwrap();
}
}
Err(errno) => write!(out, "E{:02X}", errno).unwrap(),
}
CheckedPacket::from_data(Kind::Packet, out)
}
Some(b'M') => {
let data = &packet.data[1..];
let sep1 = memchr::memchr(b',', &data).ok_or("gdb didn't send a memory length")?;
let (addr, rest) = data.split_at(sep1);
let sep2 = memchr::memchr(b':', &rest).ok_or("gdb didn't send memory content")?;
let (_, content) = rest.split_at(sep2);
let addr = usize::from_str_radix(std::str::from_utf8(&addr)?, 16)?;
// let len = usize::from_str_radix(std::str::from_utf8(&len[1..])?, 16)?;
let mut bytes = Vec::new();
for byte in content[1..].chunks(2) {
bytes.push(u8::from_str_radix(std::str::from_utf8(&byte)?, 16)?);
}
let mut out = Vec::new();
match tracee.setmem(&bytes, addr) {
Ok(()) => write!(out, "OK").unwrap(),
Err(errno) => write!(out, "E{:02X}", errno).unwrap(),
}
CheckedPacket::from_data(Kind::Packet, out)
}
Some(b'X') => {
let data = &packet.data[1..];
let sep1 = memchr::memchr(b',', &data).ok_or("gdb didn't send a memory length")?;
let (addr, rest) = data.split_at(sep1);
let sep2 = memchr::memchr(b':', &rest).ok_or("gdb didn't send memory content")?;
let (_, content) = rest.split_at(sep2);
let addr = usize::from_str_radix(std::str::from_utf8(&addr)?, 16)?;
// let len = usize::from_str_radix(std::str::from_utf8(&len[1..])?, 16)?;
let mut out = Vec::new();
match tracee.setmem(&content[1..], addr) {
Ok(()) => write!(out, "OK").unwrap(),
Err(errno) => write!(out, "E{:02X}", errno).unwrap(),
}
CheckedPacket::from_data(Kind::Packet, out)
}
Some(b'v') => {
// if packet.data[1..].starts_with(b"Run") {
// let mut cursor = &packet.data[1..];
......@@ -197,15 +140,8 @@ fn main() -> Result<()> {
},
_ => CheckedPacket::empty(),
}
} else if packet.data[1..].starts_with(b"Kill") {
break;
} else {
CheckedPacket::empty()
}
}
_ => CheckedPacket::empty(),
})?;
}
*/
Ok(())
}
use super::{Registers, Status};
use super::Registers;
use crate::Result;
use std::{
cell::Cell,
ffi::CString,
io, iter,
mem::{self, MaybeUninit},
ptr,
};
use gdb_remote_protocol::StopReason;
pub struct Os {
pid: libc::pid_t,
last_status: libc::c_int,
last_status: Cell<libc::c_int>,
}
// Handle error as Rust: Return an io::Error
......@@ -122,27 +125,27 @@ impl super::Target for Os {
Ok(Os {
pid,
last_status: status,
last_status: Cell::from(status),
})
}
}
}
fn status(&mut self) -> Status {
fn status(&self) -> StopReason {
unsafe {
if libc::WIFEXITED(self.last_status) {
Status::Exited(libc::WEXITSTATUS(self.last_status))
} else if libc::WIFSIGNALED(self.last_status) {
Status::Signaled(libc::WTERMSIG(self.last_status))
} else if libc::WIFSTOPPED(self.last_status) {
Status::Stopped(libc::WSTOPSIG(self.last_status))
if libc::WIFEXITED(self.last_status.get()) {
StopReason::Exited(self.pid as _, libc::WEXITSTATUS(self.last_status.get()) as _)
} else if libc::WIFSIGNALED(self.last_status.get()) {
StopReason::ExitedWithSignal(self.pid as _, libc::WTERMSIG(self.last_status.get()) as _)
} else if libc::WIFSTOPPED(self.last_status.get()) {
StopReason::Signal(libc::WSTOPSIG(self.last_status.get()) as _)
} else {
unimplemented!("TODO: Implement status {}", self.last_status);
unimplemented!("TODO: Implement status {}", self.last_status.get());
}
}
}
fn getregs(&mut self) -> Result<Registers, i32> {
fn getregs(&self) -> Result<Registers, i32> {
let int = unsafe {
let mut int: MaybeUninit<libc::user_regs_struct> = MaybeUninit::uninit();
ce!(libc::ptrace(
......@@ -228,7 +231,7 @@ impl super::Target for Os {
Ok(registers)
}
fn setregs(&mut self, registers: &Registers) -> Result<(), i32> {
fn setregs(&self, registers: &Registers) -> Result<(), i32> {
let mut int: libc::user_regs_struct = unsafe { MaybeUninit::zeroed().assume_init() };
let mut float: libc::user_fpregs_struct = unsafe { MaybeUninit::zeroed().assume_init() };
......@@ -317,7 +320,7 @@ impl super::Target for Os {
Ok(())
}
fn getmem(&mut self, src: usize, dest: &mut [u8]) -> Result<usize, i32> {
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize, i32> {
// 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 {
......@@ -325,7 +328,7 @@ impl super::Target for Os {
})
}
fn setmem(&mut self, src: &[u8], dest: usize) -> Result<(), i32> {
fn setmem(&self, src: &[u8], dest: usize) -> Result<(), i32> {
println!("Writing {:02X?} to address {:X}", src, dest);
setmem(
src,
......@@ -338,7 +341,7 @@ impl super::Target for Os {
)
}
fn step(&mut self, signal: Option<u8>) -> Result<Option<u64>> {
fn step(&self, signal: Option<u8>) -> Result<Option<u64>> {
unsafe {
re!(libc::ptrace(
libc::PTRACE_SINGLESTEP,
......@@ -346,11 +349,13 @@ impl super::Target for Os {
0,
signal.unwrap_or(0) as libc::c_uint
));
re!(libc::waitpid(self.pid, &mut self.last_status, 0));
let mut status = 0;
re!(libc::waitpid(self.pid, &mut status, 0));
self.last_status.set(status);
Ok(
if libc::WIFSTOPPED(self.last_status)
&& libc::WSTOPSIG(self.last_status) == libc::SIGTRAP
if libc::WIFSTOPPED(self.last_status.get())
&& libc::WSTOPSIG(self.last_status.get()) == libc::SIGTRAP
{
let rip = re!(libc::ptrace(
libc::PTRACE_PEEKUSER,
......@@ -366,7 +371,7 @@ impl super::Target for Os {
}
}
fn cont(&mut self, signal: Option<u8>) -> Result<()> {
fn cont(&self, signal: Option<u8>) -> Result<()> {
unsafe {
re!(libc::ptrace(
libc::PTRACE_CONT,
......@@ -374,7 +379,9 @@ impl super::Target for Os {
0,
signal.unwrap_or(0) as libc::c_uint
));
re!(libc::waitpid(self.pid, &mut self.last_status, 0));
let mut status = 0;
re!(libc::waitpid(self.pid, &mut status, 0));
self.last_status.set(status);
}
Ok(())
}
......
......@@ -2,6 +2,8 @@ use crate::Result;
use std::ops::RangeBounds;
use gdb_remote_protocol::StopReason;
mod regs;
#[cfg(target_os = "linux")]
......@@ -11,57 +13,30 @@ mod sys;
pub use regs::Registers;
pub use sys::Os;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Status {
Exited(i32),
Signaled(i32),
Stopped(i32),
}
impl Status {
pub fn is_exited(&self) -> bool {
match self {
Status::Exited(_) => true,
_ => false,
}
}
pub fn is_signaled(&self) -> bool {
match self {
Status::Signaled(_) => true,
_ => false,
}
}
pub fn is_stopped(&self) -> bool {
match self {
Status::Stopped(_) => true,
_ => false,
}
}
}
pub trait Target: Sized {
/// Spawn a new tracee and return a tracer for it
fn new(program: String, args: Vec<String>) -> Result<Os>;
/// Get the last status of the tracee
fn status(&mut self) -> Status;
fn status(&self) -> StopReason;
/// Read all the process register
fn getregs(&mut self) -> Result<Registers, i32>;
fn getregs(&self) -> Result<Registers, i32>;
/// Read all the process register
fn setregs(&mut self, regs: &Registers) -> Result<(), i32>;
fn setregs(&self, regs: &Registers) -> Result<(), i32>;
/// Read a region of memory from tracee
fn getmem(&mut self, src: usize, dest: &mut [u8]) -> Result<usize, i32>;
fn getmem(&self, src: usize, dest: &mut [u8]) -> Result<usize, i32>;
/// Read a region of memory from tracee
fn setmem(&mut self, src: &[u8], dest: usize) -> Result<(), i32>;
fn setmem(&self, src: &[u8], dest: usize) -> Result<(), i32>;
/// Single-step one instruction, return instruction pointer
fn step(&mut self, signal: Option<u8>) -> Result<Option<u64>>;
fn step(&self, signal: Option<u8>) -> Result<Option<u64>>;
/// Resume execution while instruction pointer is inside the range
fn resume<R>(&mut self, range: R) -> Result<()>
fn resume<R>(&self, range: R) -> Result<()>
where
R: RangeBounds<u64>,
{
......@@ -76,5 +51,5 @@ pub trait Target: Sized {
}
/// Continue execution until signal or other breakpoint
fn cont(&mut self, signal: Option<u8>) -> Result<()>;
fn cont(&self, signal: Option<u8>) -> Result<()>;
}
use crate::Result;
use std::io::prelude::*;
use std::{
io::prelude::*,
iter,
};
#[derive(Default)]
pub struct Registers {
......@@ -70,91 +73,84 @@ impl Registers {
// The following sadly assume the endianness in order to only read
// 10 bits in the st* stuff instead of the full 16.
#[rustfmt::skip] // formatting can only make this horrible code look worse
pub fn decode(mut input: &[u8]) -> Result<Self> {
let mut byte = || -> Result<u8> {
let hex = input.get(..2).ok_or("Unexpected EOF decoding registers")?;
input = &input[2..];
let hex = std::str::from_utf8(hex)?;
Ok(u8::from_str_radix(hex, 16)?)
pub fn decode(mut input: &[u8]) -> Self {
let mut byte = || -> u8 {
let b = input[0];
input = &input[1..];
b
};
Ok(Self {
rax: Some(u64::from_le_bytes([byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?])),
rbx: Some(u64::from_le_bytes([byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?])),
rcx: Some(u64::from_le_bytes([byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?])),
rdx: Some(u64::from_le_bytes([byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?])),
rsi: Some(u64::from_le_bytes([byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?, byte()?])),
rdi: Some(u64::from_le_bytes([byte()?, byte()?