Verified Commit 2a3e9008 authored by jD91mZM2's avatar jD91mZM2

Bugfixes, still segfaults :(

parent d95475a2
......@@ -116,6 +116,24 @@ fn main() -> Result<()> {
}
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..];
......
......@@ -35,6 +35,42 @@ macro_rules! ce {
}}
}
fn getmem<G, E>(mut src: usize, dest: &mut [u8], mut get: G) -> Result<usize, E>
where G: FnMut(usize) -> Result<usize, E>
{
for chunk in dest.chunks_mut(mem::size_of::<usize>()) {
let bytes = get(src)?.to_ne_bytes();
chunk.copy_from_slice(&bytes[..chunk.len()]);
src += mem::size_of::<usize>();
}
Ok(dest.len())
}
fn setmem<G, S, E>(src: &[u8], mut dest: usize, mut get: G, mut set: S) -> Result<(), E>
where
G: FnMut(usize) -> Result<usize, E>,
S: FnMut(usize, usize) -> Result<(), E>,
{
let mut iter = src.chunks_exact(mem::size_of::<usize>());
for chunk in iter.by_ref() {
let mut bytes = [0; mem::size_of::<usize>()];
bytes.copy_from_slice(chunk);
let word = usize::from_ne_bytes(bytes);
set(dest, word)?;
dest += mem::size_of::<usize>();
}
let mut bytes = get(dest)?.to_ne_bytes();
let rest = iter.remainder();
bytes[..rest.len()].copy_from_slice(rest);
let word = usize::from_ne_bytes(bytes);
set(dest, word)?;
Ok(())
}
impl super::Target for Os {
fn new(program: String, args: Vec<String>) -> Result<Self> {
let program = CString::new(program)?.into_raw();
......@@ -233,47 +269,46 @@ impl super::Target for Os {
float.xmm_space[14] = registers.xmm14.map(|r| r as _).unwrap_or(float.xmm_space[14]);
float.xmm_space[15] = registers.xmm15.map(|r| r as _).unwrap_or(float.xmm_space[15]);
unsafe {
ce!(libc::ptrace(libc::PTRACE_SETREGS, self.pid, 0, &int));
ce!(libc::ptrace(libc::PTRACE_SETFPREGS, self.pid, 0, &float));
}
Ok(())
}
fn getmem(&mut self, mut src: usize, dest: &mut [u8]) -> Result<usize, i32> {
fn getmem(&mut 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
for dest in dest.chunks_mut(mem::size_of::<usize>()) {
unsafe {
let word = ce!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, src));
let bytes = word.to_ne_bytes();
dest.copy_from_slice(&bytes[..dest.len()]);
src += 1;
}
}
Ok(dest.len())
getmem(
src,
dest,
|addr| unsafe { Ok(ce!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, addr)) as usize) },
)
}
fn setmem(&mut self, src: &[u8], mut dest: usize) -> Result<(), i32> {
for src in src.chunks(mem::size_of::<usize>()) {
unsafe {
let word = ce!(libc::ptrace(libc::PTRACE_PEEKDATA, self.pid, dest));
let mut bytes = word.to_ne_bytes();
bytes[..src.len()].copy_from_slice(src);
dest += 1;
let word = usize::from_ne_bytes(bytes);
libc::ptrace(libc::PTRACE_POKEDATA, self.pid, dest, word);
}
}
Ok(())
fn setmem(&mut self, src: &[u8], dest: usize) -> Result<(), i32> {
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, word| unsafe { ce!(libc::ptrace(libc::PTRACE_POKEDATA, self.pid, addr, word)); Ok(()) }
)
}
fn step(&mut self, signal: Option<u8>) -> Result<u64> {
fn step(&mut self, signal: Option<u8>) -> Result<Option<u64>> {
unsafe {
re!(libc::ptrace(libc::PTRACE_SINGLESTEP, self.pid, 0, signal.unwrap_or(0) as libc::c_uint));
re!(libc::waitpid(self.pid, &mut self.last_status, 0));
let rip = re!(libc::ptrace(libc::PTRACE_PEEKUSER, self.pid, libc::RIP as usize * mem::size_of::<usize>()));
Ok(rip as u64)
Ok(if libc::WIFSTOPPED(self.last_status) && libc::WSTOPSIG(self.last_status) == libc::SIGTRAP {
let rip = re!(libc::ptrace(libc::PTRACE_PEEKUSER, self.pid, libc::RIP as usize * mem::size_of::<usize>()));
Some(rip as u64)
} else {
dbg!(self.status());
None
})
}
}
......@@ -292,3 +327,49 @@ impl Drop for Os {
}
}
}
#[cfg(test)]
mod tests {
use std::{
cell::Cell,
mem,
};
#[test]
fn getmem() {
const SOURCE: &[u8] = b"testing one two three";
let mut dest = [0; 9];
super::getmem(
3,
&mut dest,
|addr| -> Result<usize, ()> {
let mut bytes = [0; mem::size_of::<usize>()];
bytes.copy_from_slice(&SOURCE[addr..addr+mem::size_of::<usize>()]);
Ok(usize::from_ne_bytes(bytes))
}
).unwrap();
assert_eq!(&dest, b"ting one ");
}
#[test]
fn setmem() {
let source = Cell::new(*b"testing one two three");
let dest = b"XXXXXXXXX";
super::setmem(
dest,
3,
|addr| -> Result<usize, ()> {
let mut bytes = [0; mem::size_of::<usize>()];
bytes.copy_from_slice(&source.get()[addr..addr+mem::size_of::<usize>()]);
Ok(usize::from_ne_bytes(bytes))
},
|addr, word| -> Result<(), ()> {
let mut slice = source.get();
slice[addr..addr+mem::size_of::<usize>()]
.copy_from_slice(&word.to_ne_bytes());
source.set(slice);
Ok(())
},
).unwrap();
assert_eq!(&source.get(), b"tesXXXXXXXXXtwo three");
}
}
......@@ -11,11 +11,32 @@ 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
......@@ -37,24 +58,20 @@ pub trait Target: Sized {
fn setmem(&mut self, src: &[u8], dest: usize) -> Result<(), i32>;
/// Single-step one instruction, return instruction pointer
fn step(&mut self, signal: Option<u8>) -> Result<u64>;
fn step(&mut self, signal: Option<u8>) -> Result<Option<u64>>;
/// Resume execution while instruction pointer is inside the range
fn resume<R>(&mut self, range: R) -> Result<u64>
fn resume<R>(&mut self, range: R) -> Result<()>
where R: RangeBounds<u64>
{
let mut last = None;
loop {
let rip = self.step(None)?;
println!("{:X}", rip);
// Break if outside the range or if in what appears to be
// an infinite loop? Somehow this seems to sometimes occur
// and I don't know what it means
if !range.contains(&rip) || last == Some(rip) {
break Ok(rip);
println!("{:X?}", rip);
if rip.map(|rip| !range.contains(&rip)).unwrap_or(true) {
break;
}
last = Some(rip);
}
Ok(())
}
/// Continue execution until signal or other breakpoint
......
......@@ -2,5 +2,7 @@
#include <stdio.h>
int main() {
printf("Hello World\n");
for (int i = 0; i < 5; ++i) {
puts("Hello World");
}
}
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