|
@@ -4,16 +4,15 @@
|
|
//! we are NOT going to bend our API for the sake of
|
|
//! we are NOT going to bend our API for the sake of
|
|
//! compatibility. So, this module will be a hellhole.
|
|
//! compatibility. So, this module will be a hellhole.
|
|
|
|
|
|
-use super::super::types::*;
|
|
|
|
-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 super::super::{errno, types::*, Pal, PalPtrace, PalSignal, Sys};
|
|
|
|
+use crate::{
|
|
|
|
+ c_str::CString,
|
|
|
|
+ fs::File,
|
|
|
|
+ header::{errno as errnoh, fcntl, signal, sys_ptrace, sys_user::user_regs_struct},
|
|
|
|
+ io::{self, prelude::*},
|
|
|
|
+ sync::{Mutex, Once},
|
|
|
|
+};
|
|
|
|
+use alloc::collections::{btree_map::Entry, BTreeMap};
|
|
use core::mem;
|
|
use core::mem;
|
|
use syscall;
|
|
use syscall;
|
|
|
|
|
|
@@ -21,15 +20,15 @@ pub struct Session {
|
|
pub tracer: File,
|
|
pub tracer: File,
|
|
pub mem: File,
|
|
pub mem: File,
|
|
pub regs: File,
|
|
pub regs: File,
|
|
- pub fpregs: File
|
|
|
|
|
|
+ pub fpregs: File,
|
|
}
|
|
}
|
|
pub struct State {
|
|
pub struct State {
|
|
- pub sessions: Mutex<BTreeMap<pid_t, Session>>
|
|
|
|
|
|
+ pub sessions: Mutex<BTreeMap<pid_t, Session>>,
|
|
}
|
|
}
|
|
impl State {
|
|
impl State {
|
|
fn new() -> Self {
|
|
fn new() -> Self {
|
|
Self {
|
|
Self {
|
|
- sessions: Mutex::new(BTreeMap::new())
|
|
|
|
|
|
+ sessions: Mutex::new(BTreeMap::new()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -40,28 +39,53 @@ pub fn init_state() -> &'static State {
|
|
STATE.call_once(|| State::new())
|
|
STATE.call_once(|| State::new())
|
|
}
|
|
}
|
|
pub fn is_traceme(pid: pid_t) -> bool {
|
|
pub fn is_traceme(pid: pid_t) -> bool {
|
|
- File::open(&CString::new(format!("chan:ptrace-relibc/{}/traceme", pid)).unwrap(), fcntl::O_PATH).is_ok()
|
|
|
|
|
|
+ File::open(
|
|
|
|
+ &CString::new(format!("chan:ptrace-relibc/{}/traceme", pid)).unwrap(),
|
|
|
|
+ fcntl::O_PATH,
|
|
|
|
+ )
|
|
|
|
+ .is_ok()
|
|
}
|
|
}
|
|
pub fn get_session(sessions: &mut BTreeMap<pid_t, Session>, pid: pid_t) -> io::Result<&Session> {
|
|
pub fn get_session(sessions: &mut BTreeMap<pid_t, Session>, pid: pid_t) -> io::Result<&Session> {
|
|
const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
|
|
const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
|
|
|
|
|
|
match sessions.entry(pid) {
|
|
match sessions.entry(pid) {
|
|
- Entry::Vacant(entry) => if is_traceme(pid) {
|
|
|
|
- Ok(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)?,
|
|
|
|
- }))
|
|
|
|
- } else {
|
|
|
|
- unsafe { errno = errnoh::ESRCH; }
|
|
|
|
- Err(io::last_os_error())
|
|
|
|
- },
|
|
|
|
- Entry::Occupied(entry) => Ok(entry.into_mut())
|
|
|
|
|
|
+ Entry::Vacant(entry) => {
|
|
|
|
+ if is_traceme(pid) {
|
|
|
|
+ Ok(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,
|
|
|
|
+ )?,
|
|
|
|
+ }))
|
|
|
|
+ } else {
|
|
|
|
+ unsafe {
|
|
|
|
+ errno = errnoh::ESRCH;
|
|
|
|
+ }
|
|
|
|
+ Err(io::last_os_error())
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ Entry::Occupied(entry) => Ok(entry.into_mut()),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> io::Result<c_int> {
|
|
|
|
|
|
+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();
|
|
let state = init_state();
|
|
|
|
|
|
if request == sys_ptrace::PTRACE_TRACEME {
|
|
if request == sys_ptrace::PTRACE_TRACEME {
|
|
@@ -69,7 +93,7 @@ fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void
|
|
let pid = Sys::getpid();
|
|
let pid = Sys::getpid();
|
|
mem::forget(File::open(
|
|
mem::forget(File::open(
|
|
&CString::new(format!("chan:ptrace-relibc/{}/traceme", pid)).unwrap(),
|
|
&CString::new(format!("chan:ptrace-relibc/{}/traceme", pid)).unwrap(),
|
|
- fcntl::O_CREAT | fcntl::O_PATH | fcntl::O_EXCL
|
|
|
|
|
|
+ fcntl::O_CREAT | fcntl::O_PATH | fcntl::O_EXCL,
|
|
)?);
|
|
)?);
|
|
return Ok(0);
|
|
return Ok(0);
|
|
}
|
|
}
|
|
@@ -78,23 +102,31 @@ fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void
|
|
let session = get_session(&mut sessions, pid)?;
|
|
let session = get_session(&mut sessions, pid)?;
|
|
|
|
|
|
match request {
|
|
match request {
|
|
- sys_ptrace::PTRACE_CONT | sys_ptrace::PTRACE_SINGLESTEP |
|
|
|
|
- sys_ptrace::PTRACE_SYSCALL | sys_ptrace::PTRACE_SYSEMU |
|
|
|
|
- sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
|
|
|
|
|
|
+ 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 _);
|
|
Sys::kill(pid, signal::SIGCONT as _);
|
|
|
|
|
|
// TODO: Translate errors
|
|
// TODO: Translate errors
|
|
- let syscall = syscall::PTRACE_STOP_PRE_SYSCALL.bits() | syscall::PTRACE_STOP_POST_SYSCALL.bits();
|
|
|
|
- (&mut &session.tracer).write(&match request {
|
|
|
|
- sys_ptrace::PTRACE_CONT => 0,
|
|
|
|
- sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_STOP_SINGLESTEP.bits(),
|
|
|
|
- sys_ptrace::PTRACE_SYSCALL => syscall,
|
|
|
|
- sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_FLAG_SYSEMU.bits() | syscall,
|
|
|
|
- sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => syscall::PTRACE_FLAG_SYSEMU.bits() | syscall::PTRACE_STOP_SINGLESTEP.bits(),
|
|
|
|
- _ => unreachable!("unhandled ptrace request type {}", request)
|
|
|
|
- }.to_ne_bytes())?;
|
|
|
|
|
|
+ let syscall =
|
|
|
|
+ syscall::PTRACE_STOP_PRE_SYSCALL.bits() | syscall::PTRACE_STOP_POST_SYSCALL.bits();
|
|
|
|
+ (&mut &session.tracer).write(
|
|
|
|
+ &match request {
|
|
|
|
+ sys_ptrace::PTRACE_CONT => 0,
|
|
|
|
+ sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_STOP_SINGLESTEP.bits(),
|
|
|
|
+ sys_ptrace::PTRACE_SYSCALL => syscall,
|
|
|
|
+ sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_FLAG_SYSEMU.bits() | syscall,
|
|
|
|
+ sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
|
|
|
|
+ syscall::PTRACE_FLAG_SYSEMU.bits() | syscall::PTRACE_STOP_SINGLESTEP.bits()
|
|
|
|
+ }
|
|
|
|
+ _ => unreachable!("unhandled ptrace request type {}", request),
|
|
|
|
+ }
|
|
|
|
+ .to_ne_bytes(),
|
|
|
|
+ )?;
|
|
Ok(0)
|
|
Ok(0)
|
|
- },
|
|
|
|
|
|
+ }
|
|
sys_ptrace::PTRACE_GETREGS => {
|
|
sys_ptrace::PTRACE_GETREGS => {
|
|
let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
|
|
let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
|
|
let mut redox_regs = syscall::IntRegisters::default();
|
|
let mut redox_regs = syscall::IntRegisters::default();
|
|
@@ -123,13 +155,13 @@ fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void
|
|
ss: redox_regs.ss as _,
|
|
ss: redox_regs.ss as _,
|
|
fs_base: 0, // fs_base: redox_regs.fs_base as _,
|
|
fs_base: 0, // fs_base: redox_regs.fs_base as _,
|
|
gs_base: 0, // gs_base: redox_regs.gs_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 _,
|
|
|
|
|
|
+ ds: 0, // ds: redox_regs.ds as _,
|
|
|
|
+ es: 0, // es: redox_regs.es as _,
|
|
fs: redox_regs.fs as _,
|
|
fs: redox_regs.fs as _,
|
|
gs: 0, // gs: redox_regs.gs as _,
|
|
gs: 0, // gs: redox_regs.gs as _,
|
|
};
|
|
};
|
|
Ok(0)
|
|
Ok(0)
|
|
- },
|
|
|
|
|
|
+ }
|
|
sys_ptrace::PTRACE_SETREGS => {
|
|
sys_ptrace::PTRACE_SETREGS => {
|
|
let c_regs = unsafe { &*(data as *mut user_regs_struct) };
|
|
let c_regs = unsafe { &*(data as *mut user_regs_struct) };
|
|
let redox_regs = syscall::IntRegisters {
|
|
let redox_regs = syscall::IntRegisters {
|
|
@@ -163,8 +195,8 @@ fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void
|
|
};
|
|
};
|
|
(&mut &session.regs).write(&redox_regs)?;
|
|
(&mut &session.regs).write(&redox_regs)?;
|
|
Ok(0)
|
|
Ok(0)
|
|
- },
|
|
|
|
- _ => unimplemented!()
|
|
|
|
|
|
+ }
|
|
|
|
+ _ => unimplemented!(),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|