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}