Verified Commit 197dc304 authored by jD91mZM2's avatar jD91mZM2
Browse files

WIP(ptrace): Test floating point registers

parent 27960a3c
......@@ -4,7 +4,8 @@
name = "acid"
version = "0.1.0"
dependencies = [
"redox_syscall 0.1.54",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)",
"strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)",
"x86 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -15,7 +16,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -28,7 +29,7 @@ name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -45,7 +46,7 @@ name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -204,7 +205,8 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.54"
version = "0.1.56"
source = "git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace#49dd22260bd8bada8b835d12ee8e460a5a1c4af4"
[[package]]
name = "rustc-serialize"
......@@ -233,6 +235,15 @@ name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strace"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/strace-redox#e64d9fb900c825e6f370da7d4bef89f10adff475"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)",
]
[[package]]
name = "winapi"
version = "0.3.6"
......@@ -266,7 +277,7 @@ dependencies = [
[metadata]
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum csv 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "266c1815d7ca63a5bd86284043faf91e8c95e943e55ce05dc0ae08e952de18bc"
......@@ -289,10 +300,12 @@ dependencies = [
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
"checksum raw-cpuid 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13b844e4049605ff38fed943f5c7b2c691fad68d9d5bf074d2720554c4e48246"
"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/jD91mZM2/syscall.git?branch=ptrace)" = "<none>"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97b18e9e53de541f11e497357d6c5eaeb39f0cb9c8734e274abe4935f6991fa"
"checksum serde_json 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5aaee47e038bf9552d30380d3973fff2593ee0a76d81ad4c581f267cdcadf36"
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)" = "<none>"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
......
......@@ -2,8 +2,11 @@
name = "acid"
version = "0.1.0"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
edition = "2018"
[dependencies]
x86 = "0.7"
# redox_syscall = { git = "https://gitlab.redox-os.org/jD91mZM2/syscall.git", branch = "ptrace" }
redox_syscall = { path = "/home/user/redox-nix/redox/kernel/syscall" }
redox_syscall = { git = "https://gitlab.redox-os.org/jD91mZM2/syscall.git", branch = "ptrace" }
# redox_syscall = { path = "/home/user/redox-nix/redox/kernel/syscall" }
strace = { git = "https://gitlab.redox-os.org/redox-os/strace-redox" }
# strace = { path = "/home/user/Coding/Rust/strace-redox" }
//!Acid testing program
#![feature(thread_local, asm)]
extern crate x86;
fn e<T, E: ToString>(error: Result<T, E>) -> Result<T, String> {
error.map_err(|e| e.to_string())
}
fn create_test() -> Result<(), String> {
use std::fs;
......@@ -51,15 +53,15 @@ fn page_fault_test() -> Result<(), String> {
Ok(())
}
fn ptrace() -> Result<(), String> {
pub fn ptrace() -> Result<(), String> {
use std::{
fs::File,
io::{prelude::*, SeekFrom},
mem,
os::{raw::c_int, unix::io::{AsRawFd, FromRawFd}}
os::unix::io::{AsRawFd, FromRawFd, RawFd}
};
use strace::*;
let pid = unsafe { syscall::clone(0).map_err(|e| format!("clone failed: {}", e))? };
let pid = e(unsafe { syscall::clone(0) })?;
if pid == 0 {
unsafe {
asm!("
......@@ -88,7 +90,13 @@ fn ptrace() -> Result<(), String> {
push 3
push 2
push 1
add rsp, 3 // pop 3 items, ignore values
add rsp, 8*3 // pop 3 items, ignore values
// Testing floating point
push 32
fild QWORD PTR [rsp]
fsqrt
add rsp, 8 // pop 1 item, ignore value
// Test behavior if tracer aborts a breakpoint before it's reached
call wait_for_a_while
......@@ -126,57 +134,49 @@ fn ptrace() -> Result<(), String> {
println!("Waiting until child is ready to be traced...");
let mut status = 0;
syscall::waitpid(pid, &mut status, syscall::WUNTRACED).map_err(|e| format!("waitpid failed: {}", e))?;
e(syscall::waitpid(pid, &mut status, syscall::WUNTRACED))?;
println!("Done! Attaching tracer...");
// Stop and attach process + get handle to registers
let proc_file = File::open(format!("proc:{}/trace", pid)).map_err(|e| format!("open failed: {}", e))?;
// Stop and attach process + get handle to registers.
// This also tests the behaviour of dup(...)
let proc_file = e(File::open(format!("proc:{}/trace", pid)))?;
let regs_file = unsafe {
File::from_raw_fd(
syscall::dup(proc_file.as_raw_fd() as usize, b"regs/int")
.map_err(|e| format!("dup failed: {}", e))? as c_int
)
File::from_raw_fd(e(syscall::dup(proc_file.as_raw_fd() as usize, b"regs/int"))? as RawFd)
};
let mut mem_file = File::open(format!("proc:{}/mem", pid)).map_err(|e| format!("open failed: {}", e))?;
println!("Schedule restart of process when resumed...");
syscall::kill(pid, syscall::SIGCONT).map_err(|e| format!("kill failed: {}", e))?;
let getregs = || -> Result<syscall::IntRegisters, String> {
let mut regs: syscall::IntRegisters = syscall::IntRegisters::default();
(&regs_file).read(&mut regs).map_err(|e| format!("reading registers failed: {}", e))?;
Ok(regs)
let regs_file_float = unsafe {
File::from_raw_fd(e(syscall::dup(regs_file.as_raw_fd() as usize, b"regs/float"))? as RawFd)
};
let setregs = |regs: &syscall::IntRegisters| -> Result<(), String> {
(&regs_file).write(&regs).map_err(|e| format!("writing registers failed: {}", e))?;
Ok(())
let mut tracer = Tracer {
file: proc_file,
regs: Registers {
float: regs_file_float,
int: regs_file
},
mem: e(Memory::attach(pid))?
};
let next = |op| -> Result<syscall::IntRegisters, String> {
(&proc_file).write(&[op]).map_err(|e| format!("ptrace operation failed: {}", e))?;
getregs()
};
println!("Schedule restart of process when resumed...");
e(syscall::kill(pid, syscall::SIGCONT))?;
println!("Stepping away from the syscall instruction...");
next(syscall::PTRACE_SINGLESTEP)?;
e(tracer.next(Stop::INSTRUCTION))?;
println!("Testing basic singlestepping...");
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 1);
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2);
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2);
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 3);
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 2);
assert_eq!(next(syscall::PTRACE_SINGLESTEP)?.rax, 1);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 1);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 2);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 2);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 3);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 2);
assert_eq!(e(e(tracer.next(Stop::INSTRUCTION))?.regs.get_int())?.rax, 1);
println!("Testing memory access...");
next(syscall::PTRACE_SINGLESTEP)?;
next(syscall::PTRACE_SINGLESTEP)?;
e(tracer.next(Stop::INSTRUCTION))?;
e(tracer.next(Stop::INSTRUCTION))?;
let rsp = next(syscall::PTRACE_SINGLESTEP)?.rsp;
mem_file.seek(SeekFrom::Start(rsp as u64)).map_err(|e| format!("memory seek failed: {}", e))?;
e(tracer.next(Stop::INSTRUCTION))?;
let regs = e(tracer.regs.get_int())?;
unsafe {
union Stack {
......@@ -184,57 +184,60 @@ fn ptrace() -> Result<(), String> {
bytes: [u8; 3 * mem::size_of::<usize>()]
}
let mut out = Stack { words: [0; 3] };
mem_file.read(&mut out.bytes).map_err(|e| format!("memory read failed: {}", e))?;
e(tracer.mem.read(regs.rsp as *const _, &mut out.bytes))?;
assert_eq!(out.words, [1, 2, 3]);
assert_eq!(
mem_file.seek(SeekFrom::Current(0)).map_err(|e| format!("memory seek failed: {}", e))? as usize,
rsp + out.bytes.len()
);
assert_eq!(e(tracer.mem.cursor())? as usize, regs.rsp + out.bytes.len());
}
next(syscall::PTRACE_SINGLESTEP)?;
e(tracer.next(Stop::INSTRUCTION))?;
println!("Testing floating point...");
for _ in 0..3 {
e(tracer.next(Stop::INSTRUCTION))?;
}
let regs = e(tracer.regs.get_float())?;
let f = regs.st_space_nth(0);
let fs = regs.st_space();
assert_eq!(fs, [f, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
assert!((f - 5.65685424949238).abs() < std::f64::EPSILON);
// Activate nonblock
let old_flags = syscall::fcntl(proc_file.as_raw_fd() as usize, syscall::F_GETFL, 0)
.map_err(|e| format!("fcntl get failed: {}", e))?;
let new_flags = old_flags | syscall::O_NONBLOCK;
syscall::fcntl(proc_file.as_raw_fd() as usize, syscall::F_SETFL, new_flags)
.map_err(|e| format!("fcntl set failed: {}", e))?;
let mut tracer = e(tracer.nonblocking())?;
println!("Testing behavior of obsolete breakpoints...");
next(syscall::PTRACE_SYSCALL)?;
next(syscall::PTRACE_CONT)?;
println!("Tracee RAX: {}", getregs()?.rax);
e(tracer.next(Stop::SYSCALL))?;
e(tracer.next(Stop::COMPLETION))?;
println!("Tracee RAX: {}", e(tracer.regs.get_int())?.rax);
println!("Waiting for next signal from tracee that it's ready to be traced again...");
syscall::waitpid(pid, &mut status, syscall::WUNTRACED).map_err(|e| format!("waitpid failed: {}", e))?;
e(syscall::waitpid(pid, &mut status, syscall::WUNTRACED))?;
println!("Setting sysemu breakpoint...");
next(syscall::PTRACE_SYSCALL | syscall::PTRACE_SYSEMU)?;
e(tracer.next(Stop::SYSCALL | Stop::SYSEMU))?;
println!("Schedule restart of process after breakpoint is set...");
syscall::kill(pid, syscall::SIGCONT).map_err(|e| format!("kill failed: {}", e))?;
e(syscall::kill(pid, syscall::SIGCONT))?;
println!("After non-blocking ptrace, execution continues as normal:");
for _ in 0..5 {
println!("Tracee RAX: {}", getregs()?.rax);
println!("Tracee RAX: {}", e(tracer.regs.get_int())?.rax);
}
println!("Overriding GETPID call...");
let mut regs = next(syscall::PTRACE_WAIT)?;
e(tracer.wait())?;
let mut regs = e(tracer.regs.get_int())?;
assert_eq!(regs.rax, syscall::SYS_GETPID);
regs.rax = 123;
setregs(&regs)?;
e(tracer.regs.set_int(&regs))?;
// Deactivate nonblock
syscall::fcntl(proc_file.as_raw_fd() as usize, syscall::F_SETFL, old_flags)
.map_err(|e| format!("fcntl set failed: {}", e))?;
let mut tracer = e(tracer.blocking())?;
println!("Checking exit status...");
let regs = next(syscall::PTRACE_SYSCALL)?;
e(tracer.next(Stop::SYSCALL))?;
let regs = e(tracer.regs.get_int())?;
assert_eq!(regs.rax, syscall::SYS_EXIT);
assert_eq!(regs.rdi, 123);
assert_eq!((&proc_file).write(&[syscall::PTRACE_SYSCALL]).unwrap_err().raw_os_error(), Some(syscall::ESRCH));
assert_eq!(tracer.next(Stop::SYSCALL).unwrap_err().raw_os_error(), Some(syscall::ESRCH));
println!("All done and tested!");
......
Supports Markdown
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