Commit 7426e481 authored by jD91mZM2's avatar jD91mZM2

WIP(ptrace): Extract repeated arch-specific code to ptrace module

parent 4c2d8599
use crate::{
common::unique::Unique,
context,
interrupt::stack_trace,
ptrace,
syscall::flag::*
......@@ -20,15 +18,7 @@ interrupt_stack!(divide_by_zero, stack, {
interrupt_stack!(debug, stack, {
let mut handled = false;
{
let contexts = context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
if let Some(ref mut kstack) = context.kstack {
context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(stack)));
}
}
}
let guard = ptrace::set_process_regs(stack);
// Disable singlestep before their is a breakpoint, since the
// breakpoint handler might end up setting it again but unless it
......@@ -36,20 +26,14 @@ interrupt_stack!(debug, stack, {
let had_singlestep = stack.iret.rflags & (1 << 8) == 1 << 8;
stack.set_singlestep(false);
if ptrace::breakpoint_callback(true).is_some() {
if ptrace::breakpoint_callback(syscall::PTRACE_SINGLESTEP).is_some() {
handled = true;
} else {
// There was no breakpoint, restore original value
stack.set_singlestep(had_singlestep);
}
{
let contexts = context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
context.regs = None;
}
}
drop(guard);
if !handled {
println!("Debug trap");
......
use core::sync::atomic::{AtomicUsize, Ordering};
use crate::common::unique::Unique;
use crate::context;
use crate::context::timeout;
use crate::device::pic;
use crate::device::serial::{COM1, COM2};
use crate::ipi::{ipi, IpiKind, IpiTarget};
use crate::scheme::debug::debug_input;
use crate::time;
use crate::{context, ptrace, time};
//resets to 0 in context::switch()
pub static PIT_TICKS: AtomicUsize = AtomicUsize::new(0);
......@@ -62,25 +60,8 @@ interrupt_stack!(pit, stack, {
timeout::trigger();
if PIT_TICKS.fetch_add(1, Ordering::SeqCst) >= 10 {
{
let contexts = crate::context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
// Make all registers available to e.g. the proc:
// scheme
if let Some(ref mut kstack) = context.kstack {
context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(stack)));
}
}
}
let _guard = ptrace::set_process_regs(stack);
let _ = context::switch();
{
let contexts = crate::context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
context.regs = None;
}
}
}
});
......
use crate::arch::macros::InterruptStack;
use crate::arch::{gdt, pti};
use crate::common::unique::Unique;
use crate::{context, ptrace, syscall};
use crate::{ptrace, syscall};
use x86::shared::msr;
pub unsafe fn init() {
......@@ -20,18 +19,9 @@ macro_rules! with_interrupt_stack {
(unsafe fn $wrapped:ident($stack:ident) -> usize $code:block) => {
#[inline(never)]
unsafe fn $wrapped(stack: *mut InterruptStack) {
let stack = &mut *stack;
{
let contexts = context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
if let Some(ref mut kstack) = context.kstack {
context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new_unchecked(&mut *stack)));
}
}
}
let _guard = ptrace::set_process_regs(stack);
let is_sysemu = ptrace::breakpoint_callback(false);
let is_sysemu = ptrace::breakpoint_callback(::syscall::PTRACE_SYSCALL);
if !is_sysemu.unwrap_or(false) {
// If not on a sysemu breakpoint
let $stack = &mut *stack;
......@@ -40,15 +30,7 @@ macro_rules! with_interrupt_stack {
if is_sysemu.is_some() {
// Only callback if there was a pre-syscall
// callback too.
ptrace::breakpoint_callback(false);
}
}
{
let contexts = context::contexts();
if let Some(context) = contexts.current() {
let mut context = context.write();
context.regs = None;
ptrace::breakpoint_callback(::syscall::PTRACE_SYSCALL);
}
}
}
......
......@@ -17,7 +17,7 @@ unsafe impl<T> Sync for Unique<T> {}
impl<T> Unique<T> {
pub fn new(ptr: *mut T) -> Self {
Self(NonNull::new(ptr).unwrap())
Self(NonNull::new(ptr).expect("Did not expect pointer to be null"))
}
pub unsafe fn new_unchecked(ptr: *mut T) -> Self {
Self(NonNull::new_unchecked(ptr))
......
......@@ -33,7 +33,7 @@ use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use syscall::{
data::PtraceEvent,
error::*,
flag::{EVENT_READ, EVENT_WRITE}
flag::*
};
// ____ _
......@@ -166,9 +166,7 @@ pub fn recv_events(pid: ContextId, out: &mut [PtraceEvent]) -> Option<usize> {
struct Breakpoint {
tracee: Arc<WaitCondition>,
reached: bool,
sysemu: bool,
singlestep: bool
flags: u8
}
fn inner_cont(pid: ContextId) -> Option<Breakpoint> {
......@@ -190,7 +188,7 @@ pub fn cont(pid: ContextId) {
/// 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, sysemu: bool, singlestep: bool) {
pub fn set_breakpoint(pid: ContextId, flags: u8) {
let tracee = inner_cont(pid)
.map(|b| b.tracee)
.unwrap_or_else(|| Arc::new(WaitCondition::new()));
......@@ -200,8 +198,7 @@ pub fn set_breakpoint(pid: ContextId, sysemu: bool, singlestep: bool) {
session.breakpoint = Some(Breakpoint {
tracee,
reached: false,
sysemu,
singlestep
flags
});
}
......@@ -247,7 +244,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(singlestep: bool) -> Option<bool> {
pub fn breakpoint_callback(flags: u8) -> Option<bool> {
// Can't hold any locks when executing wait()
let (tracee, sysemu) = {
let contexts = context::contexts();
......@@ -261,8 +258,7 @@ pub fn breakpoint_callback(singlestep: bool) -> Option<bool> {
// TODO: How should singlesteps interact with syscalls? How
// does Linux handle this?
// if singlestep && !breakpoint.singlestep {
if breakpoint.singlestep != singlestep {
if breakpoint.flags & PTRACE_OPERATIONMASK != flags & PTRACE_OPERATIONMASK {
return None;
}
......@@ -275,7 +271,7 @@ pub fn breakpoint_callback(singlestep: bool) -> Option<bool> {
(
Arc::clone(&breakpoint.tracee),
breakpoint.sysemu
breakpoint.flags & PTRACE_SYSEMU == PTRACE_SYSEMU
)
};
......@@ -301,6 +297,43 @@ pub fn close_tracee(pid: ContextId) -> Option<()> {
// |_| \_\___|\__, |_|___/\__\___|_| |___/
// |___/
pub struct ProcessRegsGuard;
/// Make all registers available to e.g. the proc: scheme
/// ---
/// For use inside arch-specific code to assign the pointer of the
/// interupt stack to the current process. Meant to reduce the amount
/// of ptrace-related code that has to lie in arch-specific bits.
/// ```rust,ignore
/// let _guard = ptrace::set_process_regs(pointer);
/// ...
/// // (_guard implicitly dropped)
/// ```
pub fn set_process_regs(pointer: *mut InterruptStack) -> Option<ProcessRegsGuard> {
let contexts = context::contexts();
let context = contexts.current()?;
let mut context = context.write();
let kstack = context.kstack.as_mut()?;
context.regs = Some((kstack.as_mut_ptr() as usize, Unique::new(pointer)));
Some(ProcessRegsGuard)
}
impl Drop for ProcessRegsGuard {
fn drop(&mut self) {
fn clear_process_regs() -> Option<()> {
let contexts = context::contexts();
let context = contexts.current()?;
let mut context = context.write();
context.regs = None;
Some(())
}
clear_process_regs();
}
}
/// Return the InterruptStack pointer, but relative to the specified
/// stack instead of the original.
pub unsafe fn rebase_regs_ptr(
......
......@@ -130,7 +130,7 @@ impl Scheme for ProcScheme {
}
}
}
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
if let Operation::Trace { .. } = operation {
......@@ -368,7 +368,6 @@ impl Scheme for ProcScheme {
return Ok(0);
}
let op = buf[0];
let sysemu = op & PTRACE_SYSEMU == PTRACE_SYSEMU;
let mut blocking = flags & O_NONBLOCK != O_NONBLOCK;
let mut singlestep = false;
......@@ -377,7 +376,7 @@ impl Scheme for ProcScheme {
PTRACE_CONT => { ptrace::cont(pid); },
PTRACE_SYSCALL | PTRACE_SINGLESTEP => { // <- not a bitwise OR
singlestep = op & PTRACE_OPERATIONMASK == PTRACE_SINGLESTEP;
ptrace::set_breakpoint(pid, sysemu, singlestep);
ptrace::set_breakpoint(pid, op);
},
PTRACE_WAIT => blocking = true,
_ => return Err(Error::new(EINVAL))
......
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