ptrace.rs 2.63 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
use crate::{
    context::{self, ContextId},
    sync::WaitCondition
};

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

struct Handle {
13
14
    tracee: Arc<WaitCondition>,
    tracer: Arc<WaitCondition>,
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    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()
}

30
31
32
pub fn cont(pid: ContextId) {
    // println!("Continuing {:?}", pid);

33
34
    let breakpoints = breakpoints();
    if let Some(breakpoint) = breakpoints.get(&pid) {
35
        breakpoint.tracee.notify();
36
37
38
    }
}

39
pub fn break_syscall(pid: ContextId, sysemu: bool) {
40
41
42
    // Continue execution of the tracee and therefore also release
    // locks on breakpoints(). This has to be done before trying a
    // mutable lock.
43
44
45
46
47
48
49
50
51
    cont(pid);

    let (tracee, tracer) = match breakpoints_mut().remove(&pid) {
        Some(breakpoint) => (breakpoint.tracee, breakpoint.tracer),
        None => (
            Arc::new(WaitCondition::new()),
            Arc::new(WaitCondition::new())
        )
    };
52

53
    // println!("Breaking {:?} (sysemu: {:?})", pid, sysemu);
54
    breakpoints_mut().insert(pid, Handle {
55
56
        tracee,
        tracer,
57
58
59
60
        sysemu
    });
}

61
62
63
64
65
66
67
68
69
70
71
72
pub fn wait_breakpoint(pid: ContextId) {
    let tracer = {
        let breakpoints = breakpoints();
        match breakpoints.get(&pid) {
            Some(breakpoint) => Arc::clone(&breakpoint.tracer),
            None => return
        }
    };
    // println!("Waiting for breakpoint on {:?}", pid);
    while !tracer.wait() {}
}

73
/// Note: Don't call while holding any locks, this will switch contexts
74
pub fn syscall_callback() -> Option<bool> {
75
    // Can't hold any locks when executing wait()
76
    let (tracee, sysemu) = {
77
78
79
80
81
82
        let contexts = context::contexts();
        let context = contexts.current()?;
        let context = context.read();

        let breakpoints = breakpoints();
        let breakpoint = breakpoints.get(&context.id)?;
83
84
        // println!("{:?} reached breakpoint (sysemu: {:?})", context.id, breakpoint.sysemu);
        breakpoint.tracer.notify();
85
        (
86
            Arc::clone(&breakpoint.tracee),
87
88
89
90
91
            breakpoint.sysemu
        )
    };

    // TODO: How should signals affect the wait?
92
    while !tracee.wait() {}
93
94
95

    Some(sysemu)
}