ptrace.rs 1.92 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::{
    context::{self, ContextId},
    sync::WaitCondition
};

use alloc::{
    collections::BTreeMap,
    sync::Arc
};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
use syscall::data::IntRegisters;

struct Handle {
    condition: Arc<WaitCondition>,
    sysemu: bool
}

static SYSCALL_BREAKPOINTS: Once<RwLock<BTreeMap<ContextId, Handle>>> = Once::new();

fn init_breakpoints() -> RwLock<BTreeMap<ContextId, Handle>> {
    RwLock::new(BTreeMap::new())
}
fn breakpoints() -> RwLockReadGuard<'static, BTreeMap<ContextId, Handle>> {
    SYSCALL_BREAKPOINTS.call_once(init_breakpoints).read()
}
fn breakpoints_mut() -> RwLockWriteGuard<'static, BTreeMap<ContextId, Handle>> {
    SYSCALL_BREAKPOINTS.call_once(init_breakpoints).write()
}

pub fn ptrace_cont(pid: ContextId) {
    let breakpoints = breakpoints();
    if let Some(breakpoint) = breakpoints.get(&pid) {
        breakpoint.condition.notify();
    }
}

pub fn ptrace_break_syscall(pid: ContextId, sysemu: bool) {
    // Continue execution of the tracee and therefore also release
    // locks on breakpoints(). This has to be done before trying a
    // mutable lock.
    ptrace_cont(pid);

    // TODO: reuse WaitConditions?
    breakpoints_mut().insert(pid, Handle {
        condition: Arc::new(WaitCondition::new()),
        sysemu
    });
}

/// Note: Don't call while holding any locks, this will switch contexts
pub fn ptrace_syscall_callback() -> Option<bool> {
    // Can't hold any locks when executing wait()
    let (condition, sysemu) = {
        let contexts = context::contexts();
        let context = contexts.current()?;
        let context = context.read();

        let breakpoints = breakpoints();
        let breakpoint = breakpoints.get(&context.id)?;
        (
            Arc::clone(&breakpoint.condition),
            breakpoint.sysemu
        )
    };

    // TODO: How should signals affect the wait?
    while !condition.wait() {}

    Some(sysemu)
}