linux_perf_data/jitdump/
record.rs

1use byteorder::{BigEndian, ByteOrder, LittleEndian};
2use linux_perf_event_reader::{Endianness, RawData};
3
4use super::records::*;
5
6/// The record type of a jitdump record.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct JitDumpRecordType(pub u32);
9
10impl JitDumpRecordType {
11    pub const JIT_CODE_LOAD: Self = Self(0);
12    pub const JIT_CODE_MOVE: Self = Self(1);
13    pub const JIT_CODE_DEBUG_INFO: Self = Self(2);
14    pub const JIT_CODE_CLOSE: Self = Self(3);
15    pub const JIT_CODE_UNWINDING_INFO: Self = Self(4);
16}
17
18/// The header which is at the start of every jitdump record.
19#[derive(Debug, Clone)]
20pub struct JitDumpRecordHeader {
21    /// The record type.
22    pub record_type: JitDumpRecordType,
23    /// The size in bytes of the record including the header.
24    pub total_size: u32,
25    /// A timestamp of when the record was created.
26    pub timestamp: u64,
27}
28
29impl JitDumpRecordHeader {
30    pub const SIZE: usize = 16; // 16 bytes
31
32    pub fn parse(endian: Endianness, data: RawData) -> Result<Self, std::io::Error> {
33        match endian {
34            Endianness::LittleEndian => Self::parse_impl::<LittleEndian>(data),
35            Endianness::BigEndian => Self::parse_impl::<BigEndian>(data),
36        }
37    }
38
39    pub fn parse_impl<O: ByteOrder>(data: RawData) -> Result<Self, std::io::Error> {
40        let mut cur = data;
41        let record_type = JitDumpRecordType(cur.read_u32::<O>()?);
42        let total_size = cur.read_u32::<O>()?;
43        let timestamp = cur.read_u64::<O>()?;
44        Ok(Self {
45            record_type,
46            total_size,
47            timestamp,
48        })
49    }
50}
51
52/// An enum carrying a parsed jitdump record.
53#[derive(Debug, Clone)]
54pub enum JitDumpRecord<'a> {
55    CodeLoad(JitCodeLoadRecord<'a>),
56    CodeMove(JitCodeMoveRecord),
57    CodeDebugInfo(JitCodeDebugInfoRecord<'a>),
58    CodeClose,
59    CodeUnwindingInfo(JitCodeUnwindingInfoRecord<'a>),
60    Other(JitDumpRawRecord<'a>),
61}
62
63/// A raw jitdump record whose body hasn't been parsed yet.
64#[derive(Debug, Clone)]
65pub struct JitDumpRawRecord<'a> {
66    /// The file endian (needs to be known during parsing).
67    pub endian: Endianness,
68    /// The record type.
69    pub record_type: JitDumpRecordType,
70    /// The timestamp.
71    pub timestamp: u64,
72    /// The offset in the jitdump file at which this record is stored. This
73    /// points to the start of the record header.
74    pub start_offset: u64,
75    /// The size of this record in bytes, including the record header.
76    pub record_size: u32,
77    /// The raw data for the body of this record.
78    pub body: RawData<'a>,
79}
80
81impl JitDumpRawRecord<'_> {
82    pub fn parse(&self) -> Result<JitDumpRecord, std::io::Error> {
83        match self.record_type {
84            JitDumpRecordType::JIT_CODE_LOAD => {
85                let record = JitCodeLoadRecord::parse(self.endian, self.body)?;
86                Ok(JitDumpRecord::CodeLoad(record))
87            }
88            JitDumpRecordType::JIT_CODE_MOVE => {
89                let record = JitCodeMoveRecord::parse(self.endian, self.body)?;
90                Ok(JitDumpRecord::CodeMove(record))
91            }
92            JitDumpRecordType::JIT_CODE_DEBUG_INFO => {
93                let record = JitCodeDebugInfoRecord::parse(self.endian, self.body)?;
94                Ok(JitDumpRecord::CodeDebugInfo(record))
95            }
96            JitDumpRecordType::JIT_CODE_CLOSE => Ok(JitDumpRecord::CodeClose),
97            JitDumpRecordType::JIT_CODE_UNWINDING_INFO => {
98                let record = JitCodeUnwindingInfoRecord::parse(self.endian, self.body)?;
99                Ok(JitDumpRecord::CodeUnwindingInfo(record))
100            }
101            _ => Ok(JitDumpRecord::Other(self.clone())),
102        }
103    }
104}