1use crate::TypeKind;
2use serde::{Deserialize, Serialize};
3use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
4
5#[repr(C, packed)]
7#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
8pub struct TraceEventHeader {
9 pub magic: u32,
10}
11
12pub const TRACE_EVENT_HEADER_SIZE: usize = std::mem::size_of::<TraceEventHeader>();
13pub const TRACE_EVENT_HEADER_MAGIC_OFFSET: usize = std::mem::offset_of!(TraceEventHeader, magic);
14
15#[repr(C, packed)]
16#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
17pub struct TraceEventMessage {
18 pub trace_id: u64,
19 pub timestamp: u64,
20 pub pid: u32,
21 pub tid: u32,
22 }
24
25pub const TRACE_EVENT_MESSAGE_SIZE: usize = std::mem::size_of::<TraceEventMessage>();
26pub const TRACE_EVENT_MESSAGE_TRACE_ID_OFFSET: usize =
27 std::mem::offset_of!(TraceEventMessage, trace_id);
28pub const TRACE_EVENT_MESSAGE_TIMESTAMP_OFFSET: usize =
29 std::mem::offset_of!(TraceEventMessage, timestamp);
30pub const TRACE_EVENT_MESSAGE_PID_OFFSET: usize = std::mem::offset_of!(TraceEventMessage, pid);
31pub const TRACE_EVENT_MESSAGE_TID_OFFSET: usize = std::mem::offset_of!(TraceEventMessage, tid);
32
33#[repr(u8)]
35#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
36pub enum InstructionType {
37 PrintStringIndex = 0x01, PrintVariableIndex = 0x02, PrintComplexVariable = 0x03, PrintComplexFormat = 0x05, Backtrace = 0x10, ExprError = 0x20,
44
45 EndInstruction = 0xFF, }
48
49#[repr(C, packed)]
51#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
52pub struct InstructionHeader {
53 pub inst_type: u8, pub data_length: u16, pub reserved: u8,
56}
57
58pub const INSTRUCTION_HEADER_SIZE: usize = std::mem::size_of::<InstructionHeader>();
59pub const INSTRUCTION_HEADER_INST_TYPE_OFFSET: usize =
60 std::mem::offset_of!(InstructionHeader, inst_type);
61pub const INSTRUCTION_HEADER_DATA_LENGTH_OFFSET: usize =
62 std::mem::offset_of!(InstructionHeader, data_length);
63pub const INSTRUCTION_HEADER_RESERVED_OFFSET: usize =
64 std::mem::offset_of!(InstructionHeader, reserved);
65
66#[repr(u8)]
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum VariableStatus {
70 Ok = 0,
71 NullDeref = 1,
72 ReadError = 2,
73 AccessError = 3,
74 Truncated = 4,
75 OffsetsUnavailable = 5,
78 ZeroLength = 6,
80}
81
82#[repr(C, packed)]
84#[derive(Debug, Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
85pub struct VariableReadErrorPayload {
86 pub errno: i32,
87 pub addr: u64,
88}
89
90pub const VARIABLE_READ_ERROR_PAYLOAD_LEN: usize = std::mem::size_of::<VariableReadErrorPayload>();
91pub const VARIABLE_READ_ERROR_PAYLOAD_ERRNO_OFFSET: usize =
92 std::mem::offset_of!(VariableReadErrorPayload, errno);
93pub const VARIABLE_READ_ERROR_PAYLOAD_ADDR_OFFSET: usize =
94 std::mem::offset_of!(VariableReadErrorPayload, addr);
95
96#[repr(C, packed)]
98#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
99pub struct PrintStringIndexData {
100 pub string_index: u16, }
102
103#[repr(C, packed)]
105#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
106pub struct PrintVariableIndexData {
107 pub var_name_index: u16, pub type_encoding: u8, pub data_len: u16, pub type_index: u16, pub status: u8, }
114
115#[repr(C, packed)]
117#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
118pub struct PrintComplexVariableData {
119 pub var_name_index: u16, pub type_index: u16, pub access_path_len: u8, pub status: u8, pub data_len: u16, }
126
127#[repr(C, packed)]
129#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
130pub struct PrintComplexFormatData {
131 pub format_string_index: u16, pub arg_count: u8, pub reserved: u8, }
138
139#[repr(C, packed)]
145#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
146pub struct PrintComplexFormatArgPrefix {
147 pub var_name_index: u16,
148 pub type_index: u16,
149 pub access_path_len: u8,
150 pub status: u8,
151}
152
153pub const PRINT_COMPLEX_FORMAT_DATA_ARG_COUNT_OFFSET: usize =
154 std::mem::offset_of!(PrintComplexFormatData, arg_count);
155
156pub const PRINT_COMPLEX_FORMAT_ARG_VAR_NAME_INDEX_OFFSET: usize =
157 std::mem::offset_of!(PrintComplexFormatArgPrefix, var_name_index);
158pub const PRINT_COMPLEX_FORMAT_ARG_TYPE_INDEX_OFFSET: usize =
159 std::mem::offset_of!(PrintComplexFormatArgPrefix, type_index);
160pub const PRINT_COMPLEX_FORMAT_ARG_ACCESS_PATH_LEN_OFFSET: usize =
161 std::mem::offset_of!(PrintComplexFormatArgPrefix, access_path_len);
162pub const PRINT_COMPLEX_FORMAT_ARG_STATUS_OFFSET: usize =
163 std::mem::offset_of!(PrintComplexFormatArgPrefix, status);
164pub const PRINT_COMPLEX_FORMAT_ARG_ACCESS_PATH_OFFSET: usize =
165 std::mem::size_of::<PrintComplexFormatArgPrefix>();
166pub const PRINT_COMPLEX_FORMAT_ARG_DATA_LEN_SIZE: usize = std::mem::size_of::<u16>();
167pub const PRINT_COMPLEX_FORMAT_ARG_FIXED_HEADER_LEN: usize =
168 PRINT_COMPLEX_FORMAT_ARG_ACCESS_PATH_OFFSET + PRINT_COMPLEX_FORMAT_ARG_DATA_LEN_SIZE;
169
170#[repr(C, packed)]
175#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
176pub struct BacktraceData {
177 pub requested_depth: u8,
178 pub frame_count: u8,
179 pub flags: u8,
180 pub status: u8,
181 pub error_code: u16,
182 pub reserved: u16,
183 }
185
186pub const BACKTRACE_DATA_SIZE: usize = std::mem::size_of::<BacktraceData>();
187pub const BACKTRACE_DATA_REQUESTED_DEPTH_OFFSET: usize =
188 std::mem::offset_of!(BacktraceData, requested_depth);
189pub const BACKTRACE_DATA_FRAME_COUNT_OFFSET: usize =
190 std::mem::offset_of!(BacktraceData, frame_count);
191pub const BACKTRACE_DATA_FLAGS_OFFSET: usize = std::mem::offset_of!(BacktraceData, flags);
192pub const BACKTRACE_DATA_STATUS_OFFSET: usize = std::mem::offset_of!(BacktraceData, status);
193pub const BACKTRACE_DATA_ERROR_CODE_OFFSET: usize = std::mem::offset_of!(BacktraceData, error_code);
194
195#[repr(C, packed)]
196#[derive(
197 Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned, Serialize, Deserialize,
198)]
199pub struct BacktraceFrameData {
200 pub module_cookie: u64,
201 pub pc: u64,
203 pub raw_ip: u64,
205 pub flags: u16,
206 pub reserved: u16,
207 pub reserved2: u32,
208}
209
210pub const BACKTRACE_FRAME_DATA_SIZE: usize = std::mem::size_of::<BacktraceFrameData>();
211pub const BACKTRACE_FRAME_MODULE_COOKIE_OFFSET: usize =
212 std::mem::offset_of!(BacktraceFrameData, module_cookie);
213pub const BACKTRACE_FRAME_PC_OFFSET: usize = std::mem::offset_of!(BacktraceFrameData, pc);
214pub const BACKTRACE_FRAME_RAW_IP_OFFSET: usize = std::mem::offset_of!(BacktraceFrameData, raw_ip);
215pub const BACKTRACE_FRAME_FLAGS_OFFSET: usize = std::mem::offset_of!(BacktraceFrameData, flags);
216
217#[repr(u8)]
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
219pub enum BacktraceStatus {
220 Complete = 0,
221 Truncated = 1,
222 DwarfUnavailable = 2,
223 UnsupportedCfi = 3,
224 OffsetsUnavailable = 4,
225 ReadError = 5,
226 InternalError = 6,
227 InvalidFrame = 7,
228 NoUnwindRowsForPc = 8,
229}
230
231impl BacktraceStatus {
232 pub fn from_u8(value: u8) -> Self {
233 match value {
234 0 => Self::Complete,
235 1 => Self::Truncated,
236 2 => Self::DwarfUnavailable,
237 3 => Self::UnsupportedCfi,
238 4 => Self::OffsetsUnavailable,
239 5 => Self::ReadError,
240 6 => Self::InternalError,
241 7 => Self::InvalidFrame,
242 8 => Self::NoUnwindRowsForPc,
243 _ => Self::InternalError,
244 }
245 }
246
247 pub fn label(self) -> &'static str {
248 match self {
249 Self::Complete => "complete",
250 Self::Truncated => "truncated",
251 Self::DwarfUnavailable => "dwarf unavailable",
252 Self::UnsupportedCfi => "unsupported CFI",
253 Self::OffsetsUnavailable => "offsets unavailable",
254 Self::ReadError => "read error",
255 Self::InternalError => "internal error",
256 Self::InvalidFrame => "invalid frame",
257 Self::NoUnwindRowsForPc => "no unwind rows for PC",
258 }
259 }
260}
261
262pub const BACKTRACE_ERROR_NONE: u16 = 0;
263pub const BACKTRACE_ERROR_RETURN_ADDRESS_READ: u16 = 1;
264pub const BACKTRACE_ERROR_FRAME_POINTER_READ: u16 = 2;
265pub const BACKTRACE_ERROR_NEXT_IP_BELOW_USER: u16 = 3;
266pub const BACKTRACE_ERROR_NEXT_IP_KERNEL_LIKE: u16 = 4;
267pub const BACKTRACE_ERROR_NEXT_CFA_ZERO: u16 = 5;
268pub const BACKTRACE_ERROR_NEXT_CFA_NOT_ADVANCING: u16 = 6;
269
270pub fn backtrace_error_label(error_code: u16) -> Option<&'static str> {
271 match error_code {
272 BACKTRACE_ERROR_NONE => None,
273 BACKTRACE_ERROR_RETURN_ADDRESS_READ => Some("return-address-read-failed"),
274 BACKTRACE_ERROR_FRAME_POINTER_READ => Some("frame-pointer-read-failed"),
275 BACKTRACE_ERROR_NEXT_IP_BELOW_USER => Some("next-ip-below-user-range"),
276 BACKTRACE_ERROR_NEXT_IP_KERNEL_LIKE => Some("next-ip-kernel-like"),
277 BACKTRACE_ERROR_NEXT_CFA_ZERO => Some("next-cfa-zero"),
278 BACKTRACE_ERROR_NEXT_CFA_NOT_ADVANCING => Some("next-cfa-not-advancing"),
279 _ => Some("unknown"),
280 }
281}
282
283pub const BACKTRACE_FLAG_RAW: u8 = 0x01;
284pub const BACKTRACE_FLAG_FULL: u8 = 0x02;
285pub const BACKTRACE_FLAG_INLINE: u8 = 0x04;
286#[repr(C, packed)]
288#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
289pub struct ExprErrorData {
290 pub string_index: u16, pub error_code: u8, pub flags: u8, pub failing_addr: u64, }
295
296pub const EXPR_ERROR_DATA_SIZE: usize = std::mem::size_of::<ExprErrorData>();
297pub const EXPR_ERROR_DATA_STRING_INDEX_OFFSET: usize =
298 std::mem::offset_of!(ExprErrorData, string_index);
299pub const EXPR_ERROR_DATA_ERROR_CODE_OFFSET: usize =
300 std::mem::offset_of!(ExprErrorData, error_code);
301pub const EXPR_ERROR_DATA_FLAGS_OFFSET: usize = std::mem::offset_of!(ExprErrorData, flags);
302pub const EXPR_ERROR_DATA_FAILING_ADDR_OFFSET: usize =
303 std::mem::offset_of!(ExprErrorData, failing_addr);
304
305#[repr(C, packed)]
307#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable, Unaligned)]
308pub struct EndInstructionData {
309 pub total_instructions: u16, pub execution_status: u8, pub reserved: u8, }
313
314pub const END_INSTRUCTION_DATA_OFFSET: usize = INSTRUCTION_HEADER_SIZE;
315pub const END_INSTRUCTION_TOTAL_INSTRUCTIONS_OFFSET: usize =
316 std::mem::offset_of!(EndInstructionData, total_instructions);
317pub const END_INSTRUCTION_EXECUTION_STATUS_OFFSET: usize =
318 std::mem::offset_of!(EndInstructionData, execution_status);
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub enum Instruction {
323 PrintStringIndex {
324 string_index: u16,
325 },
326 PrintVariableIndex {
327 var_name_index: u16,
328 type_encoding: TypeKind,
329 type_index: u16, data: Vec<u8>,
331 },
332 ExprError {
334 string_index: u16,
335 error_code: u8,
336 flags: u8,
337 failing_addr: u64,
338 },
339 Backtrace {
340 requested_depth: u8,
341 frame_count: u8,
342 flags: u8,
343 status: BacktraceStatus,
344 error_code: u16,
345 frames: Vec<BacktraceFrameData>,
346 },
347 EndInstruction {
348 total_instructions: u16,
349 execution_status: u8, },
351}
352
353impl Instruction {
354 pub fn instruction_type(&self) -> InstructionType {
356 match self {
357 Instruction::PrintStringIndex { .. } => InstructionType::PrintStringIndex,
358 Instruction::PrintVariableIndex { .. } => InstructionType::PrintVariableIndex,
359 Instruction::ExprError { .. } => InstructionType::ExprError,
360 Instruction::Backtrace { .. } => InstructionType::Backtrace,
361 Instruction::EndInstruction { .. } => InstructionType::EndInstruction,
362 }
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use super::*;
369
370 #[test]
371 fn test_instruction_types() {
372 let inst1 = Instruction::PrintStringIndex { string_index: 0 };
373 assert_eq!(inst1.instruction_type(), InstructionType::PrintStringIndex);
374 }
375
376 #[test]
377 fn test_instruction_types_basic() {
378 let inst = Instruction::EndInstruction {
379 total_instructions: 5,
380 execution_status: 0,
381 };
382 assert_eq!(inst.instruction_type(), InstructionType::EndInstruction);
383 }
384
385 #[test]
386 fn backtrace_status_wire_values_and_labels_are_stable() {
387 assert_eq!(BacktraceStatus::UnsupportedCfi as u8, 3);
388 assert_eq!(BacktraceStatus::NoUnwindRowsForPc as u8, 8);
389 assert_eq!(
390 BacktraceStatus::from_u8(8),
391 BacktraceStatus::NoUnwindRowsForPc
392 );
393 assert_eq!(
394 BacktraceStatus::NoUnwindRowsForPc.label(),
395 "no unwind rows for PC"
396 );
397 assert_eq!(
398 BacktraceStatus::from_u8(255),
399 BacktraceStatus::InternalError
400 );
401 }
402
403 #[test]
404 fn protocol_layout_constants_match_wire_format() {
405 assert_eq!(TRACE_EVENT_HEADER_SIZE, 4);
406 assert_eq!(TRACE_EVENT_HEADER_MAGIC_OFFSET, 0);
407 assert_eq!(TRACE_EVENT_MESSAGE_SIZE, 24);
408 assert_eq!(TRACE_EVENT_MESSAGE_TRACE_ID_OFFSET, 0);
409 assert_eq!(TRACE_EVENT_MESSAGE_TIMESTAMP_OFFSET, 8);
410 assert_eq!(TRACE_EVENT_MESSAGE_PID_OFFSET, 16);
411 assert_eq!(TRACE_EVENT_MESSAGE_TID_OFFSET, 20);
412 assert_eq!(INSTRUCTION_HEADER_SIZE, 4);
413 assert_eq!(INSTRUCTION_HEADER_INST_TYPE_OFFSET, 0);
414 assert_eq!(INSTRUCTION_HEADER_DATA_LENGTH_OFFSET, 1);
415 assert_eq!(INSTRUCTION_HEADER_RESERVED_OFFSET, 3);
416 assert_eq!(END_INSTRUCTION_DATA_OFFSET, 4);
417 assert_eq!(END_INSTRUCTION_TOTAL_INSTRUCTIONS_OFFSET, 0);
418 assert_eq!(END_INSTRUCTION_EXECUTION_STATUS_OFFSET, 2);
419 assert_eq!(VARIABLE_READ_ERROR_PAYLOAD_LEN, 12);
420 assert_eq!(VARIABLE_READ_ERROR_PAYLOAD_ERRNO_OFFSET, 0);
421 assert_eq!(VARIABLE_READ_ERROR_PAYLOAD_ADDR_OFFSET, 4);
422 assert_eq!(EXPR_ERROR_DATA_SIZE, 12);
423 assert_eq!(EXPR_ERROR_DATA_STRING_INDEX_OFFSET, 0);
424 assert_eq!(EXPR_ERROR_DATA_ERROR_CODE_OFFSET, 2);
425 assert_eq!(EXPR_ERROR_DATA_FLAGS_OFFSET, 3);
426 assert_eq!(EXPR_ERROR_DATA_FAILING_ADDR_OFFSET, 4);
427 assert_eq!(BACKTRACE_DATA_SIZE, 8);
428 assert_eq!(BACKTRACE_DATA_REQUESTED_DEPTH_OFFSET, 0);
429 assert_eq!(BACKTRACE_DATA_FRAME_COUNT_OFFSET, 1);
430 assert_eq!(BACKTRACE_DATA_FLAGS_OFFSET, 2);
431 assert_eq!(BACKTRACE_DATA_STATUS_OFFSET, 3);
432 assert_eq!(BACKTRACE_DATA_ERROR_CODE_OFFSET, 4);
433 assert_eq!(BACKTRACE_FRAME_DATA_SIZE, 32);
434 assert_eq!(BACKTRACE_FRAME_MODULE_COOKIE_OFFSET, 0);
435 assert_eq!(BACKTRACE_FRAME_PC_OFFSET, 8);
436 assert_eq!(BACKTRACE_FRAME_RAW_IP_OFFSET, 16);
437 assert_eq!(BACKTRACE_FRAME_FLAGS_OFFSET, 24);
438 assert_eq!(PRINT_COMPLEX_FORMAT_DATA_ARG_COUNT_OFFSET, 2);
439 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_VAR_NAME_INDEX_OFFSET, 0);
440 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_TYPE_INDEX_OFFSET, 2);
441 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_ACCESS_PATH_LEN_OFFSET, 4);
442 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_STATUS_OFFSET, 5);
443 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_ACCESS_PATH_OFFSET, 6);
444 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_DATA_LEN_SIZE, 2);
445 assert_eq!(PRINT_COMPLEX_FORMAT_ARG_FIXED_HEADER_LEN, 8);
446 }
447}