starnix_core/ptrace/
hooks.rs1use std::sync::atomic::Ordering;
6
7use starnix_logging::CATEGORY_STARNIX;
8use starnix_uapi::signals::SIGTRAP;
9
10use crate::ptrace::{PtraceOptions, StopState};
11use crate::signals::{SignalDetail, SignalInfo};
12use crate::task::CurrentTask;
13
14#[derive(Debug)]
16pub struct CurrentTaskPtrace<'a> {
17 current_task: &'a mut CurrentTask,
18}
19
20impl CurrentTask {
21 pub fn ptrace(&mut self) -> CurrentTaskPtrace<'_> {
23 CurrentTaskPtrace { current_task: self }
24 }
25}
26
27impl<'a> CurrentTaskPtrace<'a> {
28 pub fn on_syscall_enter(self) {
30 if self.current_task.trace_syscalls.load(Ordering::Relaxed) {
31 fuchsia_trace::duration!(CATEGORY_STARNIX, "ptrace:syscall_enter");
32 self.syscall_stop(StopState::SyscallEnterStopping, None);
33 }
34 }
35
36 pub fn on_syscall_exit(self, is_error: bool) {
38 if self.current_task.trace_syscalls.load(Ordering::Relaxed) {
39 fuchsia_trace::duration!(CATEGORY_STARNIX, "ptrace:syscall_exit");
40 self.syscall_stop(StopState::SyscallExitStopping, Some(is_error));
41 }
42 }
43
44 #[inline(never)]
45 fn syscall_stop(self, stop_state: StopState, is_error: Option<bool>) {
46 let block = {
47 let mut state = self.current_task.write();
48 self.current_task.trace_syscalls.store(false, Ordering::Relaxed);
49 if let Some(ptrace) = &mut state.ptrace {
50 let mut sig = SignalInfo::with_detail(
51 SIGTRAP,
52 (linux_uapi::SIGTRAP | 0x80) as i32,
53 SignalDetail::None,
54 );
55 if ptrace.has_option(PtraceOptions::TRACESYSGOOD) {
56 sig.signal.set_ptrace_syscall_bit();
57 }
58 if let Some(is_error) = is_error {
59 ptrace.last_syscall_was_error = is_error;
60 }
61 state.set_stopped(stop_state, Some(sig), None, None);
62 true
63 } else {
64 false
65 }
66 };
67 if block {
68 self.current_task.block_if_stopped();
69 }
70 }
71}