Commit 3ac1416d authored by jD91mZM2's avatar jD91mZM2

First step for ptrace overhaul

parent e95cb74d
......@@ -55,7 +55,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]]
......@@ -175,7 +175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "kernel"
version = "0.1.54"
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)",
"clippy 0.0.209 (registry+https://github.com/rust-lang/crates.io-index)",
"goblin 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
"linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -268,7 +268,7 @@ name = "raw-cpuid"
version = "4.0.0"
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)",
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -495,7 +495,7 @@ dependencies = [
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"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 cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
......
......@@ -26,7 +26,7 @@ interrupt_stack!(debug, stack, {
let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8;
stack.set_singlestep(false);
if ptrace::breakpoint_callback(syscall::PTRACE_SINGLESTEP).is_some() {
if ptrace::breakpoint_callback(PTRACE_STOP_SINGLESTEP, None).is_some() {
handled = true;
} else {
// There was no breakpoint, restore original value
......
use crate::arch::macros::InterruptStack;
use crate::arch::{gdt, pti};
use crate::syscall::flag::{PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL, PTRACE_FLAG_SYSEMU};
use crate::{ptrace, syscall};
use x86::shared::msr;
......@@ -21,18 +22,14 @@ macro_rules! with_interrupt_stack {
unsafe fn $wrapped(stack: *mut InterruptStack) {
let _guard = ptrace::set_process_regs(stack);
let is_sysemu = ptrace::breakpoint_callback(syscall::flag::PTRACE_SYSCALL)
.map(|fl| fl & syscall::flag::PTRACE_SYSEMU == syscall::flag::PTRACE_SYSEMU);
if !is_sysemu.unwrap_or(false) {
ptrace::breakpoint_callback(PTRACE_STOP_PRE_SYSCALL, None);
let not_sysemu = ptrace::next_breakpoint().map(|b| b & PTRACE_FLAG_SYSEMU != PTRACE_FLAG_SYSEMU);
if not_sysemu.unwrap_or(true) {
// If not on a sysemu breakpoint
let $stack = &mut *stack;
$stack.scratch.rax = $code;
if is_sysemu.is_some() {
// Only callback if there was a pre-syscall
// callback too.
ptrace::breakpoint_callback(::syscall::PTRACE_SYSCALL);
}
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
}
}
}
......
use alloc::sync::Arc;
use core::mem;
use syscall::data::PtraceEvent;
use syscall::flag::{PTRACE_STOP_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
use syscall::ptrace_event;
use crate::context::{contexts, switch, Status, WaitpidKey};
use crate::start::usermode;
use crate::{ptrace, syscall};
use crate::syscall::flag::{PTRACE_EVENT_SIGNAL, PTRACE_SIGNAL, SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
use crate::syscall::data::{PtraceEvent, PtraceEventData};
use crate::ptrace;
pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool {
let handler = handler.map(|ptr| ptr as usize).unwrap_or(0);
......@@ -21,12 +22,10 @@ pub extern "C" fn signal_handler(sig: usize) {
actions[sig]
};
ptrace::send_event(PtraceEvent {
tag: PTRACE_EVENT_SIGNAL,
data: PtraceEventData { signal: sig }
});
let handler = action.sa_handler.map(|ptr| ptr as usize).unwrap_or(0);
ptrace::breakpoint_callback(PTRACE_STOP_SIGNAL, Some(ptrace_event!(PTRACE_STOP_SIGNAL, sig, handler)));
if handler == SIG_DFL {
match sig {
SIGCHLD => {
......@@ -92,7 +91,7 @@ pub extern "C" fn signal_handler(sig: usize) {
},
_ => {
// println!("Exit {}", sig);
syscall::exit(sig);
crate::syscall::exit(sig);
}
}
} else if handler == SIG_IGN {
......@@ -100,8 +99,6 @@ pub extern "C" fn signal_handler(sig: usize) {
} else {
// println!("Call {:X}", handler);
ptrace::breakpoint_callback(PTRACE_SIGNAL);
unsafe {
let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256;
......@@ -114,5 +111,5 @@ pub extern "C" fn signal_handler(sig: usize) {
}
}
syscall::sigreturn().unwrap();
crate::syscall::sigreturn().unwrap();
}
//! The backend of the "proc:" scheme. Most internal breakpoint
//! handling should go here, unless they closely depend on the design
//! of the scheme.
use crate::{
arch::{
macros::InterruptStack,
......@@ -33,7 +37,8 @@ use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use syscall::{
data::PtraceEvent,
error::*,
flag::*
flag::*,
ptrace_event
};
// ____ _
......@@ -44,10 +49,11 @@ use syscall::{
#[derive(Debug)]
struct Session {
file_id: usize,
events: VecDeque<PtraceEvent>,
breakpoint: Option<Breakpoint>,
tracer: Arc<WaitCondition>
events: VecDeque<PtraceEvent>,
file_id: usize,
tracee: Arc<WaitCondition>,
tracer: Arc<WaitCondition>,
}
type SessionMap = BTreeMap<ContextId, Session>;
......@@ -73,10 +79,11 @@ pub fn try_new_session(pid: ContextId, file_id: usize) -> bool {
Entry::Occupied(_) => false,
Entry::Vacant(vacant) => {
vacant.insert(Session {
file_id,
events: VecDeque::new(),
breakpoint: None,
tracer: Arc::new(WaitCondition::new())
events: VecDeque::new(),
file_id,
tracee: Arc::new(WaitCondition::new()),
tracer: Arc::new(WaitCondition::new()),
});
true
}
......@@ -107,9 +114,7 @@ pub fn session_fevent_flags(pid: ContextId) -> Option<usize> {
pub fn close_session(pid: ContextId) {
if let Some(session) = sessions_mut().remove(&pid) {
session.tracer.notify();
if let Some(breakpoint) = session.breakpoint {
breakpoint.tracee.notify();
}
session.tracee.notify();
}
}
......@@ -164,39 +169,31 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> {
#[derive(Debug)]
struct Breakpoint {
tracee: Arc<WaitCondition>,
reached: bool,
flags: u8
flags: u64
}
fn inner_cont(pid: ContextId) -> Option<Breakpoint> {
// Remove the breakpoint to both save space and also make sure any
// yet unreached but obsolete breakpoints don't stop the program.
/// Continue the process with the specified ID
pub fn cont(pid: ContextId) {
let mut sessions = sessions_mut();
let session = sessions.get_mut(&pid)?;
let breakpoint = session.breakpoint.take()?;
breakpoint.tracee.notify();
let session = match sessions.get_mut(&pid) {
Some(session) => session,
None => return
};
Some(breakpoint)
}
// Remove the breakpoint to make sure any yet unreached but
// obsolete breakpoints don't stop the program.
session.breakpoint = None;
/// Continue the process with the specified ID
pub fn cont(pid: ContextId) {
inner_cont(pid);
session.tracee.notify();
}
/// Create a new breakpoint for the specified tracee, optionally with
/// a sysemu flag. Panics if the session is invalid.
pub fn set_breakpoint(pid: ContextId, flags: u8) {
let tracee = inner_cont(pid)
.map(|b| b.tracee)
.unwrap_or_else(|| Arc::new(WaitCondition::new()));
pub fn set_breakpoint(pid: ContextId, flags: u64) {
let mut sessions = sessions_mut();
let session = sessions.get_mut(&pid).expect("proc (set_breakpoint): invalid session");
session.breakpoint = Some(Breakpoint {
tracee,
reached: false,
flags
});
......@@ -244,7 +241,7 @@ pub fn wait(pid: ContextId) -> Result<Option<PtraceEvent>> {
/// Notify the tracer and await green flag to continue.
/// Note: Don't call while holding any locks, this will switch contexts
pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
pub fn breakpoint_callback(match_flags: u64, event: Option<PtraceEvent>) -> Option<u64> {
// Can't hold any locks when executing wait()
let (tracee, flags) = {
let contexts = context::contexts();
......@@ -258,10 +255,12 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
// TODO: How should singlesteps interact with syscalls? How
// does Linux handle this?
if breakpoint.flags & PTRACE_OPERATIONMASK != match_flags & PTRACE_OPERATIONMASK {
if breakpoint.flags & match_flags != match_flags {
return None;
}
session.events.push_back(event.unwrap_or(ptrace_event!(match_flags)));
// In case no tracer is waiting, make sure the next one gets
// the memo
breakpoint.reached = true;
......@@ -270,7 +269,7 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
proc_trigger_event(session.file_id, EVENT_WRITE);
(
Arc::clone(&breakpoint.tracee),
Arc::clone(&session.tracee),
breakpoint.flags
)
};
......@@ -280,6 +279,21 @@ pub fn breakpoint_callback(match_flags: u8) -> Option<u8> {
Some(flags)
}
/// Obtain the next breakpoint flags for the current process. This is
/// used for detecting whether or not the tracer decided to use sysemu
/// mode.
pub fn next_breakpoint() -> Option<u64> {
let contexts = context::contexts();
let context = contexts.current()?;
let context = context.read();
let sessions = sessions();
let session = sessions.get(&context.id)?;
let breakpoint = session.breakpoint.as_ref()?;
Some(breakpoint.flags)
}
/// Call when a context is closed to alert any tracers
pub fn close_tracee(pid: ContextId) -> Option<()> {
let mut sessions = sessions_mut();
......
This diff is collapsed.
......@@ -4,7 +4,7 @@
extern crate syscall;
pub use self::syscall::{data, error, flag, io, number, scheme};
pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};
pub use self::driver::*;
pub use self::fs::*;
......
......@@ -18,17 +18,17 @@ use crate::paging::entry::EntryFlags;
use crate::paging::mapper::MapperFlushAll;
use crate::paging::temporary_page::TemporaryPage;
use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE};
use crate::ptrace;
use crate::{ptrace, syscall};
use crate::scheme::FileHandle;
use crate::start::usermode;
use crate::syscall::data::{PtraceEvent, PtraceEventData, SigAction, Stat};
use crate::syscall::data::{PtraceEvent, SigAction, Stat};
use crate::syscall::error::*;
use crate::syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, CLONE_STACK,
PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE,
SIG_DFL, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, SIGCONT, SIGTERM,
WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped};
use crate::syscall::ptrace_event;
use crate::syscall::validate::{validate_slice, validate_slice_mut};
use crate::syscall;
pub fn brk(address: usize) -> Result<usize> {
let contexts = context::contexts();
......@@ -585,14 +585,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
}
}
let ptrace_event = PtraceEvent {
tag: PTRACE_EVENT_CLONE,
data: PtraceEventData {
clone: pid.into()
}
};
if ptrace::send_event(ptrace_event).is_some() {
if ptrace::send_event(ptrace_event!(PTRACE_EVENT_CLONE, pid.into())).is_some() {
// Freeze the clone, allow ptrace to put breakpoints
// to it before it starts
let contexts = context::contexts();
......
Subproject commit 9e9f47d2a570c55dd96cd80c83bc818d63cab8af
Subproject commit 52441c28b1daa6f9febf1bc6588b625b167bd2c3
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