linux_perf_data/jitdump/
header.rs

1use std::io::ErrorKind;
2
3use byteorder::{BigEndian, ByteOrder, LittleEndian};
4use linux_perf_event_reader::RawData;
5
6use super::error::JitDumpError;
7
8/// The jitdump header.
9#[derive(Debug, Clone)]
10pub struct JitDumpHeader {
11    /// Four bytes tagging the file type and declaring the endianness of this file.
12    /// When interpreted as a u32 in the correct endian, this is 0x4A695444.
13    /// Represents the string "JiTD" in ASCII form.
14    pub magic: [u8; 4],
15    /// The format version. It is currently set to 1.
16    pub version: u32,
17    /// The size in bytes of file header.
18    pub total_size: u32,
19    /// ELF architecture encoding (ELF e_machine value as specified in /usr/include/elf.h)
20    pub elf_machine_arch: u32,
21    /// The process ID of the JIT runtime process.
22    pub pid: u32,
23    /// The timestamp of when the file was created.
24    pub timestamp: u64,
25    /// A bitmask of flags.
26    pub flags: u64,
27}
28
29impl JitDumpHeader {
30    pub const SIZE: usize = 40; // 40 bytes
31
32    pub fn parse(mut data: RawData) -> Result<Self, JitDumpError> {
33        let mut magic = [0; 4];
34        data.read_exact(&mut magic)?;
35        let header_result = match &magic {
36            b"JiTD" => Self::parse_after_magic::<BigEndian>(magic, data),
37            b"DTiJ" => Self::parse_after_magic::<LittleEndian>(magic, data),
38            _ => return Err(JitDumpError::InvalidMagicBytes(magic)),
39        };
40        let header = match header_result {
41            Ok(header) => header,
42            Err(e) if e.kind() == ErrorKind::UnexpectedEof => {
43                return Err(JitDumpError::NotEnoughBytesForHeader)
44            }
45            Err(e) => panic!("Unexpected error type {e}"),
46        };
47        if header.total_size < Self::SIZE as u32 {
48            return Err(JitDumpError::InvalidHeaderSize(header.total_size));
49        }
50
51        Ok(header)
52    }
53
54    pub fn parse_after_magic<O: ByteOrder>(
55        magic: [u8; 4],
56        data: RawData,
57    ) -> Result<Self, std::io::Error> {
58        let mut cur = data;
59        let version = cur.read_u32::<O>()?;
60        let total_size = cur.read_u32::<O>()?;
61
62        // Make sure we have total_size bytes available. `data` is right after the 4 magic bytes.
63        let mut full_header = data;
64        full_header.skip(total_size.saturating_sub(4) as usize)?;
65
66        let elf_machine_arch = cur.read_u32::<O>()?;
67        let _pad1 = cur.read_u32::<O>()?;
68        let pid = cur.read_u32::<O>()?;
69        let timestamp = cur.read_u64::<O>()?;
70        let flags = cur.read_u64::<O>()?;
71        Ok(Self {
72            magic,
73            version,
74            total_size,
75            elf_machine_arch,
76            pid,
77            timestamp,
78            flags,
79        })
80    }
81}