Verified Commit ddb2f9fe authored by jD91mZM2's avatar jD91mZM2

WIP: Redox backend

parent 2a63a5fc
......@@ -89,6 +89,8 @@ dependencies = [
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall)",
"strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)",
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -173,6 +175,14 @@ dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "git+https://gitlab.redox-os.org/redox-os/syscall#9ecdc11d73677477b37567a47af1633478093cbb"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.9"
......@@ -189,6 +199,16 @@ name = "regex-syntax"
version = "0.6.18"
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#d7f7921f50bb03fe855f27a439d2d9c2eac45646"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall)",
"structopt 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.8.0"
......@@ -353,8 +373,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
"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 redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall)" = "<none>"
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
"checksum strace 0.1.0 (git+https://gitlab.redox-os.org/redox-os/strace-redox)" = "<none>"
"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"
......
......@@ -8,6 +8,11 @@ edition = "2018"
gdb-remote-protocol = { path = "rust-gdb-remote-protocol" }
structopt = "0.2.18"
memchr = "2.2.1"
libc = "0.2.62"
env_logger = "0.7.1"
log = "0.4.8"
[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2.62"
[target.'cfg(target_os = "redox")'.dependencies]
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall" }
strace = { git = "https://gitlab.redox-os.org/redox-os/strace-redox" }
......@@ -2,7 +2,7 @@
let
gdb-test = pkgs.writers.writeBashBin "gdb-test" ''
${gdb-init}/bin/gdb \
${pkgs.gdb}/bin/gdb \
-ex "set debug remote 1" \
-ex "target remote :64126" \
"$@"
......
use std::{cmp::min, borrow::Cow, net::TcpListener, convert::TryFrom};
use std::{
cmp::min,
borrow::Cow,
net::TcpListener,
convert::TryFrom,
};
use gdb_remote_protocol::{
Error, FileSystem, Handler, Id, LibcFS, MemoryRegion, ProcessType,
......@@ -11,8 +16,10 @@ mod os;
use os::{Os, Registers, Target};
const ERROR_PARSE_STRING: u8 = 0;
const ERROR_GET_PATH: u8 = 1;
#[allow(unused)]
const ERROR_PARSE_STRING: u8 = std::u8::MAX;
#[allow(unused)]
const ERROR_GET_PATH: u8 = std::u8::MAX - 1;
#[derive(Debug, StructOpt)]
struct Opt {
......
......@@ -90,45 +90,35 @@ where
impl super::Target for Os {
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()
.map(|s| CString::new(s).map(|s| s.into_raw() as *const _))
.chain(iter::once(Ok(ptr::null())))
.collect::<Result<Vec<*const libc::c_char>, _>>()?;
unsafe {
let pid = libc::fork();
if pid == 0 {
// Must not drop any memory, not unwind (panic).
if libc::ptrace(libc::PTRACE_TRACEME) < 0 {
error!(
"ptrace(PTRACE_TRACEME) failed: {:?}",
io::Error::last_os_error()
);
libc::exit(1);
}
if libc::raise(libc::SIGSTOP) < 0 {
error!("raise(SIGSTOP) failed: {:?}", io::Error::last_os_error());
libc::exit(1);
}
if libc::execvp(program, args.as_ptr()) < 0 {
error!("execv(...) failed: {:?}", io::Error::last_os_error());
libc::exit(1);
let result = (|| -> Result<(), Box<dyn std::error::Error>> {
let program = CString::new(program)?.into_raw();
let args = args.into_iter()
.map(|s| CString::new(s).map(|s| s.into_raw() as *const _))
.chain(iter::once(Ok(ptr::null())))
.collect::<Result<Vec<*const libc::c_char>, _>>()?;
e!(libc::ptrace(libc::PTRACE_TRACEME));
e!(libc::raise(libc::SIGSTOP));
e!(libc::execvp(program, args.as_ptr()));
Ok(())
})();
match result {
Ok(()) => {
error!("execvp(...) should not be able to succeed");
libc::exit(1);
},
Err(err) => {
error!("failure: {}", err);
libc::exit(1);
},
}
error!("execv(...) should not be able to succeed");
libc::exit(1);
} else {
// Drop variables only the child needed
CString::from_raw(program);
for arg in args {
if !arg.is_null() {
// We originally get mutable memory, don't worry!
CString::from_raw(arg as *mut _);
}
}
// Wait for tracee to stop
let mut status = 0;
e!(libc::waitpid(pid, &mut status, 0));
......
......@@ -9,6 +9,9 @@ mod regs;
#[cfg(target_os = "linux")]
#[path = "linux.rs"]
mod sys;
#[cfg(target_os = "redox")]
#[path = "redox.rs"]
mod sys;
pub use regs::Registers;
pub use sys::Os;
......
use super::Registers;
use crate::Result;
use std::{
cell::{Cell, RefCell},
fs,
io,
mem,
os::unix::ffi::OsStrExt,
path::PathBuf,
};
use gdb_remote_protocol::{Error, StopReason};
use log::error;
use strace::Tracer;
use syscall::flag::*;
pub struct Os {
pid: usize,
last_status: Cell<usize>,
tracer: RefCell<Tracer>,
}
trait FromOsError<T>: Sized {
fn from_os_error(error: T) -> Self;
}
impl FromOsError<syscall::Error> for Error {
fn from_os_error(error: syscall::Error) -> Self {
Error::Error(error.errno as u8)
}
}
impl FromOsError<io::Error> for Error {
fn from_os_error(error: io::Error) -> Self {
Error::Error(error.raw_os_error().unwrap_or(0) as u8)
}
}
impl FromOsError<syscall::Error> for io::Error {
fn from_os_error(error: syscall::Error) -> Self {
io::Error::from_raw_os_error(error.errno)
}
}
impl FromOsError<io::Error> for Box<dyn std::error::Error> {
fn from_os_error(error: io::Error) -> Self {
Box::new(error)
}
}
impl FromOsError<syscall::Error> for Box<dyn std::error::Error> {
fn from_os_error(error: syscall::Error) -> Self {
Box::new(io::Error::from_os_error(error))
}
}
macro_rules! e {
($result:expr) => {{
match $result {
Ok(inner) => inner,
Err(err) => return Err(FromOsError::from_os_error(err)),
}
}};
}
impl super::Target for Os {
fn new(program: String, args: Vec<String>) -> Result<Self, Box<dyn std::error::Error>> {
unsafe {
let pid = e!(syscall::clone(CloneFlags::empty()));
if pid == 0 {
// Must not drop any memory, and not unwind (panic).
let result = (|| -> io::Result<()> {
let args = args.iter()
.map(|s| [s.as_ptr() as usize, s.len()])
.collect::<Vec<[usize; 2]>>();
let vars = std::env::vars_os()
.map(|(mut key, value)| {
key.push("=");
key.push(&value);
let slice = key.as_bytes();
let res = [slice.as_ptr() as usize, slice.len()];
mem::forget(key);
res
})
.collect::<Vec<[usize; 2]>>();
let program = e!(syscall::open(program.as_bytes(), O_RDONLY | O_CLOEXEC));
let pid = e!(syscall::getpid());
e!(syscall::kill(pid, SIGSTOP));
e!(syscall::fexec(program, &args, &vars));
Ok(())
})();
match result {
Ok(()) => {
error!("fexec(...) should not be able to succeed");
let _ = syscall::exit(1);
unreachable!();
},
Err(err) => {
error!("failure: {}", err);
let _ = syscall::exit(1);
unreachable!();
},
}
} else {
// Wait for tracee to stop
let mut status = 0;
e!(syscall::waitpid(pid, &mut status, WaitFlags::empty()));
// Attach tracer
let mut tracer = e!(Tracer::attach(pid));
// Step past fexec
e!(syscall::kill(pid, SIGCONT));
e!(tracer.next(strace::Flags::STOP_PRE_SYSCALL));
assert_eq!(e!(tracer.regs.get_int()).return_value(), syscall::SYS_FEXEC);
e!(tracer.next(strace::Flags::STOP_SINGLESTEP));
Ok(Os {
pid,
last_status: Cell::from(status),
tracer: RefCell::new(tracer),
})
}
}
}
fn status(&self) -> StopReason {
if syscall::wifexited(self.last_status.get()) {
StopReason::Exited(
self.pid as _,
syscall::wexitstatus(self.last_status.get()) as _,
)
} else if syscall::wifsignaled(self.last_status.get()) {
StopReason::ExitedWithSignal(
self.pid as _,
syscall::wtermsig(self.last_status.get()) as _,
)
} else if syscall::wifstopped(self.last_status.get()) {
StopReason::Signal(syscall::wstopsig(self.last_status.get()) as _)
} else {
unimplemented!("TODO: Implement status {}", self.last_status.get());
}
}
fn pid(&self) -> u32 {
return self.pid as _;
}
fn getregs(&self) -> Result<Registers> {
let mut tracer = self.tracer.borrow_mut();
let int = e!(tracer.regs.get_int()).0;
let float = e!(tracer.regs.get_float()).0;
let mut registers = Registers::default();
registers.r15 = Some(int.r15 as _);
registers.r14 = Some(int.r14 as _);
registers.r13 = Some(int.r13 as _);
registers.r12 = Some(int.r12 as _);
registers.rbp = Some(int.rbp as _);
registers.rbx = Some(int.rbx as _);
registers.r11 = Some(int.r11 as _);
registers.r10 = Some(int.r10 as _);
registers.r9 = Some(int.r9 as _);
registers.r8 = Some(int.r8 as _);
registers.rax = Some(int.rax as _);
registers.rcx = Some(int.rcx as _);
registers.rdx = Some(int.rdx as _);
registers.rsi = Some(int.rsi as _);
registers.rdi = Some(int.rdi as _);
registers.rip = Some(int.rip as _);
registers.cs = Some(int.cs as _);
registers.eflags = Some(int.rflags as _);
registers.rsp = Some(int.rsp as _);
registers.ss = Some(int.ss as _);
// registers.ds = Some(int.ds as _);
// registers.es = Some(int.es as _);
registers.fs = Some(int.fs as _);
// registers.gs = Some(int.gs as _);
registers.fctrl = Some(float.fcw as _);
registers.fop = Some(float.fop as _);
registers.st0 = Some(float.st_space[0] as _);
registers.st1 = Some(float.st_space[1] as _);
registers.st2 = Some(float.st_space[2] as _);
registers.st3 = Some(float.st_space[3] as _);
registers.st4 = Some(float.st_space[4] as _);
registers.st5 = Some(float.st_space[5] as _);
registers.st6 = Some(float.st_space[6] as _);
registers.st7 = Some(float.st_space[7] as _);
registers.xmm0 = Some(float.xmm_space[0] as _);
registers.xmm1 = Some(float.xmm_space[1] as _);
registers.xmm2 = Some(float.xmm_space[2] as _);
registers.xmm3 = Some(float.xmm_space[3] as _);
registers.xmm4 = Some(float.xmm_space[4] as _);
registers.xmm5 = Some(float.xmm_space[5] as _);
registers.xmm6 = Some(float.xmm_space[6] as _);
registers.xmm7 = Some(float.xmm_space[7] as _);
registers.xmm8 = Some(float.xmm_space[8] as _);
registers.xmm9 = Some(float.xmm_space[9] as _);
registers.xmm10 = Some(float.xmm_space[10] as _);
registers.xmm11 = Some(float.xmm_space[11] as _);
registers.xmm12 = Some(float.xmm_space[12] as _);
registers.xmm13 = Some(float.xmm_space[13] as _);
registers.xmm14 = Some(float.xmm_space[14] as _);
registers.xmm15 = Some(float.xmm_space[15] as _);
registers.mxcsr = Some(float.mxcsr);
// registers.fs_base = Some(int.fs_base as _);
// registers.gs_base = Some(int.gs_base as _);
registers.orig_rax = Some(int.rax as _);
Ok(registers)
}
fn setregs(&self, registers: &Registers) -> Result<()> {
let mut int = syscall::IntRegisters::default();
let mut float = syscall::FloatRegisters::default();
int.r15 = registers.r15.map(|r| r as _).unwrap_or(int.r15);
int.r14 = registers.r14.map(|r| r as _).unwrap_or(int.r14);
int.r13 = registers.r13.map(|r| r as _).unwrap_or(int.r13);
int.r12 = registers.r12.map(|r| r as _).unwrap_or(int.r12);
int.rbp = registers.rbp.map(|r| r as _).unwrap_or(int.rbp);
int.rbx = registers.rbx.map(|r| r as _).unwrap_or(int.rbx);
int.r11 = registers.r11.map(|r| r as _).unwrap_or(int.r11);
int.r10 = registers.r10.map(|r| r as _).unwrap_or(int.r10);
int.r9 = registers.r9.map(|r| r as _).unwrap_or(int.r9);
int.r8 = registers.r8.map(|r| r as _).unwrap_or(int.r8);
int.rax = registers.rax.map(|r| r as _).unwrap_or(int.rax);
int.rcx = registers.rcx.map(|r| r as _).unwrap_or(int.rcx);
int.rdx = registers.rdx.map(|r| r as _).unwrap_or(int.rdx);
int.rsi = registers.rsi.map(|r| r as _).unwrap_or(int.rsi);
int.rdi = registers.rdi.map(|r| r as _).unwrap_or(int.rdi);
int.rip = registers.rip.map(|r| r as _).unwrap_or(int.rip);
int.cs = registers.cs.map(|r| r as _).unwrap_or(int.cs);
int.rflags = registers.eflags.map(|r| r as _).unwrap_or(int.rflags);
int.rsp = registers.rsp.map(|r| r as _).unwrap_or(int.rsp);
int.ss = registers.ss.map(|r| r as _).unwrap_or(int.ss);
// int.ds = registers.ds.map(|r| r as _).unwrap_or(int.ds);
// int.es = registers.es.map(|r| r as _).unwrap_or(int.es);
int.fs = registers.fs.map(|r| r as _).unwrap_or(int.fs);
// int.gs = registers.gs.map(|r| r as _).unwrap_or(int.gs);
float.fcw = registers.fctrl.map(|r| r as _).unwrap_or(float.fcw);
float.fop = registers.fop.map(|r| r as _).unwrap_or(float.fop);
float.st_space[0] = registers.st0.map(|r| r as _).unwrap_or(float.st_space[0]);
float.st_space[1] = registers.st1.map(|r| r as _).unwrap_or(float.st_space[1]);
float.st_space[2] = registers.st2.map(|r| r as _).unwrap_or(float.st_space[2]);
float.st_space[3] = registers.st3.map(|r| r as _).unwrap_or(float.st_space[3]);
float.st_space[4] = registers.st4.map(|r| r as _).unwrap_or(float.st_space[4]);
float.st_space[5] = registers.st5.map(|r| r as _).unwrap_or(float.st_space[5]);
float.st_space[6] = registers.st6.map(|r| r as _).unwrap_or(float.st_space[6]);
float.st_space[7] = registers.st7.map(|r| r as _).unwrap_or(float.st_space[7]);
float.xmm_space[0] = registers.xmm0.map(|r| r as _).unwrap_or(float.xmm_space[0]);
float.xmm_space[1] = registers.xmm1.map(|r| r as _).unwrap_or(float.xmm_space[1]);
float.xmm_space[2] = registers.xmm2.map(|r| r as _).unwrap_or(float.xmm_space[2]);
float.xmm_space[3] = registers.xmm3.map(|r| r as _).unwrap_or(float.xmm_space[3]);
float.xmm_space[4] = registers.xmm4.map(|r| r as _).unwrap_or(float.xmm_space[4]);
float.xmm_space[5] = registers.xmm5.map(|r| r as _).unwrap_or(float.xmm_space[5]);
float.xmm_space[6] = registers.xmm6.map(|r| r as _).unwrap_or(float.xmm_space[6]);
float.xmm_space[7] = registers.xmm7.map(|r| r as _).unwrap_or(float.xmm_space[7]);
float.xmm_space[8] = registers.xmm8.map(|r| r as _).unwrap_or(float.xmm_space[8]);
float.xmm_space[9] = registers.xmm9.map(|r| r as _).unwrap_or(float.xmm_space[9]);
float.xmm_space[10] = registers
.xmm10
.map(|r| r as _)
.unwrap_or(float.xmm_space[10]);
float.xmm_space[11] = registers
.xmm11
.map(|r| r as _)
.unwrap_or(float.xmm_space[11]);
float.xmm_space[12] = registers
.xmm12
.map(|r| r as _)
.unwrap_or(float.xmm_space[12]);
float.xmm_space[13] = registers
.xmm13
.map(|r| r as _)
.unwrap_or(float.xmm_space[13]);
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]);
float.mxcsr = registers.mxcsr.unwrap_or(float.mxcsr);
// int.fs_base = registers.fs_base.map(|r| r as _).unwrap_or(int.fs_base);
// int.gs_base = registers.gs_base.map(|r| r as _).unwrap_or(int.gs_base);
int.rax = registers.orig_rax.map(|r| r as _).unwrap_or(int.rax);
let mut tracer = self.tracer.borrow_mut();
e!(tracer.regs.set_int(&strace::IntRegisters(int)));
e!(tracer.regs.set_float(&strace::FloatRegisters(float)));
Ok(())
}
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
let mut tracer = self.tracer.borrow_mut();
e!(tracer.mem.read(src as *const u8, dest));
Ok(dest.len())
}
fn setmem(&self, src: &[u8], dest: usize) -> Result<()> {
let mut tracer = self.tracer.borrow_mut();
e!(tracer.mem.write(src, dest as *mut u8));
Ok(())
}
fn step(&self, _signal: Option<u8>) -> Result<Option<u64>> {
let mut tracer = self.tracer.borrow_mut();
e!(tracer.next(strace::Flags::STOP_SINGLESTEP));
// Just pretend ptrace SIGSTOP:ped this
let status = (SIGSTOP << 8) | 0x7f;
assert!(syscall::wifstopped(status));
assert_eq!(syscall::wstopsig(status), SIGSTOP);
self.last_status.set(status);
Ok(None)
// unsafe {
// Ok(
// if libc::WIFSTOPPED(self.last_status.get())
// && libc::WSTOPSIG(self.last_status.get()) == libc::SIGTRAP
// {
// let rip = e!(libc::ptrace(
// libc::PTRACE_PEEKUSER,
// self.pid,
// libc::RIP as usize * mem::size_of::<usize>()
// ));
// Some(rip as u64)
// } else {
// None
// },
// )
// }
}
fn cont(&self, _signal: Option<u8>) -> Result<()> {
let mut tracer = self.tracer.borrow_mut();
e!(tracer.next(strace::Flags::STOP_BREAKPOINT));
// Just pretend ptrace SIGSTOP:ped this
let status = (SIGSTOP << 8) | 0x7f;
assert!(syscall::wifstopped(status));
assert_eq!(syscall::wstopsig(status), SIGSTOP);
self.last_status.set(status);
Ok(())
}
fn path(&self, pid: usize) -> Result<Vec<u8>> {
let mut path = PathBuf::from("proc:");
path.push(pid.to_string());
path.push("/exe");
Ok(e!(fs::read(path)))
}
}
impl Drop for Os {
fn drop(&mut self) {
let _ = syscall::kill(self.pid, SIGTERM);
}
}
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