twizzler_abi/
trace.rs

1//! Tracing data structures
2//!
3//! This module defines the object and data structures for tracing kernel, thread, etc. events.
4//! Tracing is done via the sys_ktrace system call, which takes an object and a trace spec. This
5//! object is the "prime" trace object for a sequence of trace objects. The kernel fills these
6//! objects with a stream of trace events until they fill up (reach a maximum size defined by the
7//! kernel). Once a trace object fills up, the kernel generates a new trace object with the same
8//! CreateSpec as the prime object, and starts filling that object with data. It then appends a
9//! 'next-object' entry to the object that just filled up, so readers know which object to continue
10//! reading from.
11//!
12//! A single prime tracing object can be associated with multiple TraceSpec structures, enabling
13//! that object (or its subsequent objects) to collect a wide variety of data with fine-grained
14//! control over which events are collected.
15//!
16//! Streamed data is tracked via the TraceBase structure, located at the base address of any trace
17//! object. The end field defines the current end-point of data within the object. This atomic field
18//! is updated by the kernel when trace data is written, and any threads sleeping on this value will
19//! wake up.
20//!
21//! Note that not all trace events are generated synchronously. Asynchronous events are generated by
22//! the kernel when in critical states. These events are not guaranteed to be reported in a timely
23//! manner, and may be dropped if the system is under heavy load.
24
25use core::sync::atomic::AtomicU64;
26
27use twizzler_rt_abi::object::ObjID;
28
29use crate::{
30    pager::{CompletionToKernel, CompletionToPager, KernelCommand, PagerRequest},
31    syscall::{
32        MapFlags, Syscall, ThreadSyncFlags, ThreadSyncOp, ThreadSyncReference, ThreadSyncSleep,
33        TimeSpan,
34    },
35    thread::ExecutionState,
36};
37
38#[derive(Clone, Copy, Debug, Default)]
39#[repr(C)]
40/// Header for a trace entry. This is always present, and may be optionally followed by additional
41/// data, if the `flags` field contains the `HAS_DATA` flag.
42pub struct TraceEntryHead {
43    /// The ID of the thread that generated this trace entry.
44    pub thread: ObjID,
45    /// The ID of the security context that generated this trace entry.
46    pub sctx: ObjID,
47    /// The ID of the memory context that generated this trace entry.
48    pub mctx: ObjID,
49    /// The ID of the CPU that generated this trace entry.
50    pub cpuid: u64,
51    /// The time at which this trace entry was generated.
52    pub time: TimeSpan,
53    /// The event that generated this trace entry.
54    pub event: u64,
55    /// The kind of trace entry.
56    pub kind: TraceKind,
57    /// Provided extra data from the [TraceSpec] that matched this entry, or if NEXT_OBJECT is set,
58    /// the ID of the next object.
59    pub extra_or_next: ObjID,
60    /// Flags indicating the type of trace entry.
61    pub flags: TraceEntryFlags,
62}
63
64impl TraceEntryHead {
65    /// Create a new trace entry head with the NEXT_OBJECT flag set.
66    pub fn new_next_object(id: ObjID) -> Self {
67        Self {
68            extra_or_next: id,
69            flags: TraceEntryFlags::NEXT_OBJECT,
70            ..Default::default()
71        }
72    }
73}
74
75#[derive(Clone, Copy, Debug)]
76#[repr(C)]
77/// Header for additional data.
78pub struct TraceData<T: Copy> {
79    /// Reserved for future use.
80    pub resv: u64,
81    /// Length of the data in bytes (including this header).
82    pub len: u32,
83    /// Flags for this extra data.
84    pub flags: u32,
85    /// Data associated with the trace entry.
86    pub data: T,
87}
88
89impl<T: Copy> TraceData<T> {
90    /// Try to cast the data into a concrete Trace Data type, if events match.
91    pub fn try_cast<U: TraceDataCast + Copy>(&self, events: u64) -> Option<&TraceData<U>> {
92        if events & U::EVENT != 0 {
93            unsafe {
94                Some(
95                    (self as *const Self)
96                        .cast::<TraceData<U>>()
97                        .as_ref()
98                        .unwrap(),
99                )
100            }
101        } else {
102            None
103        }
104    }
105}
106
107#[repr(C)]
108/// The base structure for a trace object.
109pub struct TraceBase {
110    /// The end point for valid data. The kernel will update this and submit a thread_sync wakeup
111    /// when writing trace data to this object.
112    pub end: AtomicU64,
113    /// The start point of valid data in this object. This is set by the kernel during
114    /// initialization and then not updated again.
115    pub start: u64,
116}
117
118impl TraceBase {
119    /// Get a waiter for this tracing object based on how much data has thus-far been read.
120    pub fn waiter(&self, pos: u64) -> ThreadSyncSleep {
121        ThreadSyncSleep::new(
122            ThreadSyncReference::Virtual(&self.end),
123            pos,
124            ThreadSyncOp::Equal,
125            ThreadSyncFlags::empty(),
126        )
127    }
128}
129
130#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PartialOrd, Ord)]
131#[repr(u16)]
132/// Kinds of tracing events.
133pub enum TraceKind {
134    Kernel,
135    Thread,
136    Object,
137    Context,
138    Security,
139    Pager,
140    #[default]
141    Other = 0xffff,
142}
143
144bitflags::bitflags! {
145    #[derive(Clone, Copy, Debug)]
146    pub struct TraceFlags: u16 {
147        /// Include additional data.
148        const DATA = 1;
149        // TODO: support collecting thread registers.
150        //const REGISTERS = 2;
151    }
152}
153
154bitflags::bitflags! {
155    #[derive(Clone, Copy, Debug, Default)]
156    /// Trace entry flags.
157    pub struct TraceEntryFlags: u16 {
158        /// The kernel dropped a trace event when processing.
159        const DROPPED = 1;
160        /// This trace entry is followed by a TraceData entry.
161        const HAS_DATA = 2;
162        /// This trace entry is NOT a trace entry, and instead indicates that
163        /// the kernel ran out of room in the current object. The extra_or_next field
164        /// contains the object ID of the next trace object to read from.
165        const NEXT_OBJECT = 4;
166    }
167}
168
169// Thread events
170/// Thread has exited.
171pub const THREAD_EXIT: u64 = 1;
172/// Thread context switch occurred.
173pub const THREAD_CONTEXT_SWITCH: u64 = 2;
174/// Thread sampling event occurred.
175pub const THREAD_SAMPLE: u64 = 4;
176/// Thread made a system call.
177pub const THREAD_SYSCALL_ENTRY: u64 = 8;
178/// Thread was blocked.
179pub const THREAD_BLOCK: u64 = 0x10;
180/// Thread was resumed from blocked state.
181pub const THREAD_RESUME: u64 = 0x20;
182/// Thread migrated to a different CPU.
183pub const THREAD_MIGRATE: u64 = 0x40;
184
185// Object events
186/// Object control operation occurred.
187pub const OBJECT_CTRL: u64 = 1;
188/// Object was created.
189pub const OBJECT_CREATE: u64 = 2;
190
191// Context events
192/// Memory mapping operation occurred.
193pub const CONTEXT_MAP: u64 = 1;
194/// Memory unmapping operation occurred.
195pub const CONTEXT_UNMAP: u64 = 2;
196/// Memory fault occurred.
197pub const CONTEXT_FAULT: u64 = 4;
198/// TLB shootdown occurred.
199pub const CONTEXT_SHOOTDOWN: u64 = 8;
200/// Memory invalidation occurred.
201pub const CONTEXT_INVALIDATION: u64 = 0x10;
202
203// Security events
204/// Entered a security context.
205pub const SECURITY_CTX_ENTRY: u64 = 1;
206/// Exited a security context.
207pub const SECURITY_CTX_EXIT: u64 = 2;
208/// Security violation occurred.
209pub const SECURITY_VIOLATION: u64 = 4;
210
211// Kernel events
212/// Kernel memory allocation occurred.
213pub const KERNEL_ALLOC: u64 = 1;
214
215// Pager events
216/// Pager command was sent.
217pub const PAGER_COMMAND_SEND: u64 = 1;
218/// Pager command was responded to.
219pub const PAGER_COMMAND_RESPONDED: u64 = 2;
220/// Pager request was received.
221pub const PAGER_REQUEST_RECV: u64 = 4;
222/// Pager request was completed.
223pub const PAGER_REQUEST_COMPLETED: u64 = 8;
224
225/// Trait for types that can be cast from trace data based on event types.
226pub trait TraceDataCast {
227    /// The event constant associated with this trace data type.
228    const EVENT: u64;
229}
230
231/// Event data for thread operations.
232#[repr(C)]
233#[derive(Clone, Copy, Debug)]
234pub struct ThreadEvent {
235    /// Generic value associated with the thread event.
236    pub val: u64,
237}
238
239/// Event data for system call entry.
240#[repr(C)]
241#[derive(Clone, Copy, Debug)]
242pub struct SyscallEntryEvent {
243    /// Instruction pointer at syscall entry.
244    pub ip: u64,
245    /// The system call number.
246    pub num: Syscall,
247    /// Arguments.
248    pub args: [u64; 6],
249}
250
251/// Event data for thread context switches.
252#[repr(C)]
253#[derive(Clone, Copy, Debug)]
254pub struct ThreadCtxSwitch {
255    /// ID of the thread being switched to, if any.
256    pub to: Option<ObjID>,
257}
258
259/// Event data for thread migration between CPUs.
260#[repr(C)]
261#[derive(Clone, Copy, Debug)]
262pub struct ThreadMigrate {
263    /// ID of the CPU being migrated to.
264    pub to: u64,
265}
266
267/// Event data for thread sampling operations.
268#[repr(C)]
269#[derive(Clone, Copy, Debug)]
270pub struct ThreadSamplingEvent {
271    /// Instruction pointer at sampling time.
272    pub ip: u64,
273    /// Thread execution state at sampling time.
274    pub state: ExecutionState,
275}
276
277/// Event data for memory mapping operations.
278#[repr(C)]
279#[derive(Clone, Copy, Debug)]
280pub struct ContextMapEvent {
281    /// Virtual address being mapped.
282    pub addr: u64,
283    /// Length of the mapping in bytes.
284    pub len: u64,
285    /// Object being mapped.
286    pub obj: ObjID,
287    /// Mapping flags.
288    pub flags: MapFlags,
289}
290
291bitflags::bitflags! {
292    #[derive(Clone, Copy, Debug)]
293    /// Flags describing memory fault characteristics.
294    pub struct FaultFlags: u64 {
295        /// Fault occurred on read access.
296        const READ = 1;
297        /// Fault occurred on write access.
298        const WRITE = 2;
299        /// Fault occurred on execute access.
300        const EXEC = 4;
301        /// Fault occurred in user mode.
302        const USER = 8;
303        /// Fault was handled by pager.
304        const PAGER = 0x10;
305        /// Fault involved large pages.
306        const LARGE = 0x20;
307    }
308}
309
310/// Event data for memory faults.
311#[derive(Clone, Copy, Debug)]
312pub struct ContextFaultEvent {
313    /// Virtual address that faulted.
314    pub addr: u64,
315    /// Object associated with the fault.
316    pub obj: ObjID,
317    /// Flags describing the fault type.
318    pub flags: FaultFlags,
319    /// Time spent processing the fault.
320    pub processing_time: TimeSpan,
321}
322
323/// Event data for pager commands sent to kernel.
324#[derive(Clone, Copy, Debug)]
325pub struct PagerCommandSent {
326    /// The command that was sent.
327    pub cmd: KernelCommand,
328    /// Queue ID for the command.
329    pub qid: u32,
330}
331
332/// Event data for pager command responses.
333#[derive(Clone, Copy, Debug)]
334pub struct PagerCommandResponded {
335    /// Queue ID for the response.
336    pub qid: u32,
337    /// The response data.
338    pub resp: CompletionToKernel,
339}
340
341/// Event data for pager requests received.
342#[derive(Clone, Copy, Debug)]
343pub struct PagerRequestRecv {
344    /// The request that was received.
345    pub req: PagerRequest,
346    /// Queue ID for the request.
347    pub qid: u32,
348}
349
350/// Event data for completed pager requests.
351#[derive(Clone, Copy, Debug)]
352pub struct PagerRequestCompleted {
353    /// Queue ID for the completed request.
354    pub qid: u32,
355    /// The completion response.
356    pub resp: CompletionToPager,
357}
358
359impl TraceDataCast for ContextMapEvent {
360    const EVENT: u64 = CONTEXT_MAP;
361}
362
363impl TraceDataCast for ContextFaultEvent {
364    const EVENT: u64 = CONTEXT_FAULT;
365}
366
367impl TraceDataCast for ThreadEvent {
368    const EVENT: u64 = THREAD_EXIT;
369}
370
371impl TraceDataCast for ThreadCtxSwitch {
372    const EVENT: u64 = THREAD_CONTEXT_SWITCH;
373}
374
375impl TraceDataCast for ThreadMigrate {
376    const EVENT: u64 = THREAD_MIGRATE;
377}
378
379impl TraceDataCast for PagerCommandSent {
380    const EVENT: u64 = PAGER_COMMAND_SEND;
381}
382
383impl TraceDataCast for PagerCommandResponded {
384    const EVENT: u64 = PAGER_COMMAND_RESPONDED;
385}
386
387impl TraceDataCast for PagerRequestRecv {
388    const EVENT: u64 = PAGER_REQUEST_RECV;
389}
390
391impl TraceDataCast for PagerRequestCompleted {
392    const EVENT: u64 = PAGER_REQUEST_COMPLETED;
393}
394
395impl TraceDataCast for SyscallEntryEvent {
396    const EVENT: u64 = THREAD_SYSCALL_ENTRY;
397}
398
399impl TraceDataCast for ThreadSamplingEvent {
400    const EVENT: u64 = THREAD_SAMPLE;
401}