Skip to main content

starnix_core/ptrace/
hooks.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Provides access to ptrace hooks for a [`CurrentTask`].
15#[derive(Debug)]
16pub struct CurrentTaskPtrace<'a> {
17    current_task: &'a mut CurrentTask,
18}
19
20impl CurrentTask {
21    /// Returns a [`CurrentTaskPtrace`] wrapper to invoke ptrace hooks.
22    pub fn ptrace(&mut self) -> CurrentTaskPtrace<'_> {
23        CurrentTaskPtrace { current_task: self }
24    }
25}
26
27impl<'a> CurrentTaskPtrace<'a> {
28    /// Invoked upon entering a syscall to handle ptrace syscall entry tracing.
29    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    /// Invoked upon exiting a syscall to handle ptrace syscall exit tracing.
37    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}