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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
package main
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
// itimerspec mirrors struct itimerspec from <time.h> (it_interval, it_value).
// Used as the argument to timer_settime / timer_gettime.
type itimerspec struct {
Interval unix.Timespec
Value unix.Timespec
}
// itimerval mirrors struct itimerval from <sys/time.h> (it_interval, it_value),
// each a struct timeval. It is the argument to setitimer/getitimer (the classic
// interval timers, distinct from the POSIX per-process timer_* family above).
type itimerval struct {
Interval unix.Timeval
Value unix.Timeval
}
// itimerReal is ITIMER_REAL (=0): a real-time interval timer that, when armed,
// delivers SIGALRM on expiry.
const itimerReal = 0
// intervalTimerNoop exercises the classic interval-timer syscalls setitimer(2)
// and getitimer(2) without ever arming anything, so the enter_setitimer /
// enter_getitimer tracepoints fire end-to-end while remaining fully SIGNAL-SAFE.
//
// SAFETY: setitimer is called with an ALL-ZERO struct itimerval. A zero it_value
// disarms the timer and arms nothing new, so NO SIGALRM is ever scheduled or
// delivered — this mirrors the alarm(0) pattern in miscAlarmCancel and the
// far-future / never-firing approach in posixTimerLifecycle. getitimer is a pure
// read of the (now disarmed) timer's state.
//
// Both setitimer and getitimer are KindNull (null_event) on enter and return an
// UNCLASSIFIED ret_event on exit: neither takes a pathname nor an fd, and the
// return value is not a descriptor. We therefore only assert enter-presence.
func intervalTimerNoop() error {
// All-zero itimerval: it_interval = it_value = {0,0}. This disarms
// ITIMER_REAL and arms nothing, so no SIGALRM can fire.
var zero itimerval
if _, _, errno := syscall.RawSyscall(
unix.SYS_SETITIMER,
itimerReal,
uintptr(unsafe.Pointer(&zero)),
0, // old_value == NULL (we don't care about the previous setting)
); errno != 0 {
return fmt.Errorf("setitimer: %w", errno)
}
// getitimer reads the current (disarmed) ITIMER_REAL state into out; a safe,
// side-effect-free read included for symmetry with setitimer.
var out itimerval
if _, _, errno := syscall.RawSyscall(
unix.SYS_GETITIMER,
itimerReal,
uintptr(unsafe.Pointer(&out)),
0,
); errno != 0 {
return fmt.Errorf("getitimer: %w", errno)
}
return nil
}
// posixTimerLifecycle exercises the full POSIX per-process timer family so the
// tracer's null_event handling is covered end-to-end:
//
// timer_create -> timer_settime -> timer_gettime -> timer_getoverrun -> timer_delete
//
// These are deliberately distinct from timerfd_create: timer_create returns a
// timer_t through an OUTPUT pointer (args[2]), NOT a file descriptor, so the
// tracer must emit a null_event for it and must never treat any argument or the
// return value as an fd (contrast with timerfd_create, which is an fd-returning
// eventfd-family syscall). See man 2 timer_create.
func posixTimerLifecycle() error {
// timer_t (__kernel_timer_t) is an int in the Linux UAPI, not an fd.
var timerID int32
// timer_create(CLOCK_MONOTONIC, NULL, &timerID): a NULL sigevent requests
// the default notification (SIGALRM via signal), and timerID is the output
// timer_t — not an fd.
if _, _, errno := syscall.RawSyscall(
unix.SYS_TIMER_CREATE,
uintptr(unix.CLOCK_MONOTONIC),
0, // sevp == NULL
uintptr(unsafe.Pointer(&timerID)),
); errno != 0 {
return fmt.Errorf("timer_create: %w", errno)
}
// Arm the timer with a far-future one-shot expiry so it never actually
// fires during the test; we only care about the syscalls being traced.
newValue := itimerspec{
Value: unix.Timespec{Sec: 3600, Nsec: 0},
}
if _, _, errno := syscall.RawSyscall6(
unix.SYS_TIMER_SETTIME,
uintptr(timerID),
0, // flags (relative)
uintptr(unsafe.Pointer(&newValue)),
0, // old_value == NULL
0, 0,
); errno != 0 {
return fmt.Errorf("timer_settime: %w", errno)
}
var curValue itimerspec
if _, _, errno := syscall.RawSyscall(
unix.SYS_TIMER_GETTIME,
uintptr(timerID),
uintptr(unsafe.Pointer(&curValue)),
0,
); errno != 0 {
return fmt.Errorf("timer_gettime: %w", errno)
}
if _, _, errno := syscall.RawSyscall(
unix.SYS_TIMER_GETOVERRUN,
uintptr(timerID),
0, 0,
); errno != 0 {
return fmt.Errorf("timer_getoverrun: %w", errno)
}
if _, _, errno := syscall.RawSyscall(
unix.SYS_TIMER_DELETE,
uintptr(timerID),
0, 0,
); errno != 0 {
return fmt.Errorf("timer_delete: %w", errno)
}
return nil
}
|