14#include <fmt/format.h>
16#include <libassert/assert.hpp>
23#include <bits/types/siginfo_t.h>
25#include <sys/ptrace.h>
32 Stop = PTRACE_EVENT_STOP,
33 Clone = PTRACE_EVENT_CLONE,
34 Exec = PTRACE_EVENT_EXEC,
35 Exit = PTRACE_EVENT_EXIT,
36 Fork = PTRACE_EVENT_FORK,
37 VFork = PTRACE_EVENT_VFORK,
70 template <ChronoDuration Duration1, ChronoDuration Duration2 = std::chrono::microseconds>
72 Duration2 poll_period = std::chrono::microseconds{1}) {
73 using std::chrono::steady_clock;
75 ASSERT(timeout > poll_period);
77 const auto start_time = steady_clock::now();
80 while (steady_clock::now() - start_time < timeout) {
82 linux::waitid(P_PID, gsl::narrow_cast<id_t>(pid), WEXITED | WSTOPPED | WNOHANG);
88 if (waitid_res.
value().si_pid != 0) {
92 std::this_thread::sleep_for(poll_period);
95 LOG_DEBUG(
"waitid timed out at {}", timeout);
96 return ErrorKind::TimedOut;
101 result.
type = siginfo.si_code;
114 if (result.type == CLD_EXITED) {
115 result.exit_code = gsl::narrow_cast<int>(siginfo.si_status);
119 constexpr u64 SIG_MASK = 0x7f;
120 constexpr u64 SYSCALL_TRAP_MASK = 0x80;
121 u32 signal_bits = gsl::narrow_cast<u32>(siginfo.si_status);
124 result.signal_num = signal_bits & SIG_MASK;
127 if (result.type != CLD_TRAPPED) {
131 if ((signal_bits & SYSCALL_TRAP_MASK) != 0) {
132 result.is_syscall_trap =
true;
133 }
else if ((signal_bits >> 8) != 0) {
134 result.ptrace_event =
static_cast<PtraceEvent>(signal_bits >> 8);
146 auto format(const ::asmgrader::PtraceEvent& from, format_context& ctx)
const {
147 auto res = enum_to_str(from);
150 return format_to(ctx.out(),
"{}", *res);
153 return format_to(ctx.out(),
"<unknown ({})>", fmt::underlying(from));
157 static constexpr std::optional<const char*> enum_to_str(const ::asmgrader::PtraceEvent& from) {
185 auto format(const ::asmgrader::TracedWaitid& from, format_context& ctx)
const {
186 auto type_to_str = [](
int wait_type) -> std::string {
201 return fmt::format(
"<unkown ({})>", wait_type);
205 return fmt::format_to(
206 ctx.out(),
"TracedWaitid{{type={}, exit_code={}, signal={}, is_syscall_trap={}, ptrace_event={}}}",
207 type_to_str(from.type), from.exit_code, from.signal_num, from.is_syscall_trap, from.ptrace_event);
std::variant wrapper for a partial implementation of C++23's expected type
Definition expected.hpp:34
constexpr U & value()
Definition expected.hpp:78
#define LOG_DEBUG(...)
Definition logging.hpp:44
Expected< siginfo_t > waitid(idtype_t idtype, id_t id, int options=WSTOPPED|WEXITED)
see waitid(2) returns success/failure; logs failure at debug level
Definition linux.hpp:257
Definition asm_buffer.hpp:19
PtraceEvent
Definition tracer_types.hpp:31
Definition tracer_types.hpp:43
static constexpr TracedWaitid parse(const siginfo_t &siginfo)
Definition tracer_types.hpp:99
bool is_syscall_trap
Whether a system call trape was delivered via ptrace.
Definition tracer_types.hpp:58
std::optional< int > exit_code
Has value if and only if type == CLD_EXITED.
Definition tracer_types.hpp:49
std::optional< PtraceEvent > ptrace_event
A PTRACE_EVENT_* value if an event was recieved.
Definition tracer_types.hpp:55
std::optional< linux::Signal > signal_num
Has value if type is not CLD_EXITED.
Definition tracer_types.hpp:52
int type
type is si_code in waitid(2). One of: CLD_EXITED, CLD_KILLED, CLD_DUMPED, CLD_STOPPED,...
Definition tracer_types.hpp:46
static Result< TracedWaitid > wait_with_timeout(pid_t pid, Duration1 timeout, Duration2 poll_period=std::chrono::microseconds{1})
Definition tracer_types.hpp:71
static Expected< TracedWaitid > waitid(idtype_t idtype, id_t id, int options=WSTOPPED|WEXITED)
Definition tracer_types.hpp:60