Initial ptrace compatibility for Redox OS

This commit is contained in:
jD91mZM2
2019-07-10 11:03:31 +02:00
parent 7f702720af
commit f389010fff
9 changed files with 256 additions and 78 deletions
+27 -8
View File
@@ -1,5 +1,3 @@
//! sys/socket implementation, following http://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/socket.h.html
use core::result::Result as CoreResult;
use core::{mem, ptr, slice};
use syscall::data::Map;
@@ -17,6 +15,7 @@ use header::sys_mman::MAP_ANON;
use header::sys_stat::stat;
use header::sys_statvfs::statvfs;
use header::sys_time::{timeval, timezone};
use header::sys_wait;
use header::sys_utsname::{utsname, UTSLENGTH};
use header::time::timespec;
use header::unistd::{F_OK, R_OK, W_OK, X_OK};
@@ -922,14 +921,34 @@ impl Pal for Sys {
if pid == !0 {
pid = 0;
}
unsafe {
let mut temp: usize = 0;
let res = e(syscall::waitpid(pid as usize, &mut temp, options as usize));
if !stat_loc.is_null() {
*stat_loc = temp as c_int;
let mut res = None;
let mut status = 0;
// First, allow ptrace to handle waitpid
let state = ptrace::init_state();
let sessions = state.sessions.lock();
if let Some(session) = sessions.get(&pid) {
if options & sys_wait::WNOHANG != sys_wait::WNOHANG {
let _ = (&mut &session.tracer).write(&[syscall::PTRACE_WAIT]);
res = Some(e(syscall::waitpid(pid as usize, &mut status, (options | sys_wait::WNOHANG) as usize)));
if res == Some(0) {
// WNOHANG, just pretend ptrace SIGSTOP:ped this
status = (syscall::SIGSTOP << 8) | 0x7f;
res = Some(pid as usize);
}
}
res as pid_t
}
// If ptrace didn't impact this waitpid, proceed as normal
let res = res.unwrap_or_else(|| e(syscall::waitpid(pid as usize, &mut status, options as usize)));
// If stat_loc is non-null, set that and the return
unsafe {
if !stat_loc.is_null() {
*stat_loc = status as c_int;
}
}
res as pid_t
}
fn write(fd: c_int, buf: &[u8]) -> ssize_t {
+138 -9
View File
@@ -5,23 +5,152 @@
//! compatibility. So, this module will be a hellhole.
use super::super::types::*;
use super::super::PalPtrace;
use super::{e, Sys};
use super::super::{errno, Pal, PalPtrace, PalSignal, Sys};
use crate::c_str::CString;
use crate::fs::File;
use crate::header::sys_user::user_regs_struct;
use crate::header::{errno as errnoh, fcntl, signal, sys_ptrace};
use crate::io::{self, prelude::*};
use crate::sync::{Mutex, Once};
use alloc::collections::BTreeMap;
use alloc::collections::btree_map::Entry;
use syscall;
#[derive(Default)]
struct State {}
pub struct Session {
pub tracer: File,
pub mem: File,
pub regs: File,
pub fpregs: File
}
pub struct State {
pub sessions: Mutex<BTreeMap<pid_t, Session>>
}
impl State {
fn new() -> Self {
Self {
sessions: Mutex::new(BTreeMap::new())
}
}
}
static STATE: Once<Mutex<State>> = Once::new();
static STATE: Once<State> = Once::new();
fn state() -> &'static Mutex<State> {
STATE.call_once(|| Mutex::new(State::default()))
pub fn init_state() -> &'static State {
STATE.call_once(|| State::new())
}
fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> io::Result<c_int> {
let state = init_state();
if request == sys_ptrace::PTRACE_TRACEME {
// let pid = Sys::getpid();
// todo: only auto-open session on host if this happens
return Ok(0);
}
const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
let mut sessions = state.sessions.lock();
let session = match sessions.entry(pid) {
Entry::Vacant(entry) => entry.insert(Session {
tracer: File::open(&CString::new(format!("proc:{}/trace", pid)).unwrap(), NEW_FLAGS | fcntl::O_NONBLOCK)?,
mem: File::open(&CString::new(format!("proc:{}/mem", pid)).unwrap(), NEW_FLAGS)?,
regs: File::open(&CString::new(format!("proc:{}/regs/int", pid)).unwrap(), NEW_FLAGS)?,
fpregs: File::open(&CString::new(format!("proc:{}/regs/float", pid)).unwrap(), NEW_FLAGS)?,
}),
Entry::Occupied(entry) => entry.into_mut()
};
match request {
sys_ptrace::PTRACE_CONT | sys_ptrace::PTRACE_SINGLESTEP |
sys_ptrace::PTRACE_SYSCALL | sys_ptrace::PTRACE_SYSEMU |
sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
Sys::kill(pid, signal::SIGCONT as _);
(&mut &session.tracer).write(&[match request {
sys_ptrace::PTRACE_CONT => syscall::PTRACE_CONT,
sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_SINGLESTEP,
sys_ptrace::PTRACE_SYSCALL => syscall::PTRACE_SYSCALL,
sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_SYSEMU | syscall::PTRACE_SYSCALL,
sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => syscall::PTRACE_SYSEMU | syscall::PTRACE_SINGLESTEP,
_ => unreachable!("unhandled ptrace request type {}", request)
}])?;
Ok(0)
},
sys_ptrace::PTRACE_GETREGS => {
let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
let mut redox_regs = syscall::IntRegisters::default();
(&mut &session.regs).read(&mut redox_regs)?;
*c_regs = user_regs_struct {
r15: redox_regs.r15 as _,
r14: redox_regs.r14 as _,
r13: redox_regs.r13 as _,
r12: redox_regs.r12 as _,
rbp: redox_regs.rbp as _,
rbx: redox_regs.rbx as _,
r11: redox_regs.r11 as _,
r10: redox_regs.r10 as _,
r9: redox_regs.r9 as _,
r8: redox_regs.r8 as _,
rax: redox_regs.rax as _,
rcx: redox_regs.rcx as _,
rdx: redox_regs.rdx as _,
rsi: redox_regs.rsi as _,
rdi: redox_regs.rdi as _,
orig_rax: redox_regs.rax as _, // redox_regs.orig_rax as _,
rip: redox_regs.rip as _,
cs: redox_regs.cs as _,
eflags: redox_regs.rflags as _,
rsp: redox_regs.rsp as _,
ss: redox_regs.ss as _,
fs_base: 0, // fs_base: redox_regs.fs_base as _,
gs_base: 0, // gs_base: redox_regs.gs_base as _,
ds: 0, // ds: redox_regs.ds as _,
es: 0, // es: redox_regs.es as _,
fs: redox_regs.fs as _,
gs: 0, // gs: redox_regs.gs as _,
};
Ok(0)
},
sys_ptrace::PTRACE_SETREGS => {
let c_regs = unsafe { &*(data as *mut user_regs_struct) };
let redox_regs = syscall::IntRegisters {
r15: c_regs.r15 as _,
r14: c_regs.r14 as _,
r13: c_regs.r13 as _,
r12: c_regs.r12 as _,
rbp: c_regs.rbp as _,
rbx: c_regs.rbx as _,
r11: c_regs.r11 as _,
r10: c_regs.r10 as _,
r9: c_regs.r9 as _,
r8: c_regs.r8 as _,
rax: c_regs.orig_rax as _, // c_regs.rax as _,
rcx: c_regs.rcx as _,
rdx: c_regs.rdx as _,
rsi: c_regs.rsi as _,
rdi: c_regs.rdi as _,
// orig_rax: c_regs.orig_rax as _,
rip: c_regs.rip as _,
cs: c_regs.cs as _,
rflags: c_regs.eflags as _,
rsp: c_regs.rsp as _,
ss: c_regs.ss as _,
// fs_base: c_regs.fs_base as _,
// gs_base: c_regs.gs_base as _,
// ds: c_regs.ds as _,
// es: c_regs.es as _,
fs: c_regs.fs as _,
// gs: c_regs.gs as _,
};
(&mut &session.regs).write(&redox_regs)?;
Ok(0)
},
_ => unimplemented!()
}
}
impl PalPtrace for Sys {
fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int {
// Oh boy, this is not gonna be fun.........
unimplemented!()
inner_ptrace(request, pid, addr, data).unwrap_or(-1)
}
}