use byteorder::{BigEndian, ByteOrder, LittleEndian};
use linux_perf_event_reader::{Endianness, RawData};
use super::record::JitDumpRecordHeader;
#[derive(Debug, Clone)]
pub struct JitCodeLoadRecord<'a> {
pub pid: u32,
pub tid: u32,
pub vma: u64,
pub code_addr: u64,
pub code_index: u64,
pub function_name: RawData<'a>,
pub code_bytes: RawData<'a>,
}
impl<'a> JitCodeLoadRecord<'a> {
pub const NAME_OFFSET_FROM_RECORD_START: usize =
JitDumpRecordHeader::SIZE + 4 + 4 + 8 + 8 + 8 + 8;
pub fn parse(endian: Endianness, data: RawData<'a>) -> Result<Self, std::io::Error> {
match endian {
Endianness::LittleEndian => Self::parse_impl::<LittleEndian>(data),
Endianness::BigEndian => Self::parse_impl::<BigEndian>(data),
}
}
pub fn parse_impl<O: ByteOrder>(data: RawData<'a>) -> Result<Self, std::io::Error> {
let mut cur = data;
let pid = cur.read_u32::<O>()?;
let tid = cur.read_u32::<O>()?;
let vma = cur.read_u64::<O>()?;
let code_addr = cur.read_u64::<O>()?;
let code_size = cur.read_u64::<O>()?;
let code_index = cur.read_u64::<O>()?;
let function_name = cur.read_string().ok_or(std::io::ErrorKind::UnexpectedEof)?;
let code_bytes = cur.split_off_prefix(code_size as usize)?;
Ok(Self {
pid,
tid,
vma,
code_addr,
code_index,
function_name,
code_bytes,
})
}
pub fn code_bytes_offset_from_record_header_start(&self) -> usize {
JitDumpRecordHeader::SIZE + 4 + 4 + 8 + 8 + 8 + 8 + self.function_name.len() + 1
}
}
#[derive(Debug, Clone)]
pub struct JitCodeMoveRecord {
pub pid: u32,
pub tid: u32,
pub vma: u64,
pub old_code_addr: u64,
pub new_code_addr: u64,
pub code_size: u64,
pub code_index: u64,
}
impl JitCodeMoveRecord {
pub fn parse(endian: Endianness, data: RawData) -> Result<Self, std::io::Error> {
match endian {
Endianness::LittleEndian => Self::parse_impl::<LittleEndian>(data),
Endianness::BigEndian => Self::parse_impl::<BigEndian>(data),
}
}
pub fn parse_impl<O: ByteOrder>(data: RawData) -> Result<Self, std::io::Error> {
let mut cur = data;
let pid = cur.read_u32::<O>()?;
let tid = cur.read_u32::<O>()?;
let vma = cur.read_u64::<O>()?;
let old_code_addr = cur.read_u64::<O>()?;
let new_code_addr = cur.read_u64::<O>()?;
let code_size = cur.read_u64::<O>()?;
let code_index = cur.read_u64::<O>()?;
Ok(Self {
pid,
tid,
vma,
old_code_addr,
new_code_addr,
code_size,
code_index,
})
}
}
#[derive(Debug, Clone)]
pub struct JitCodeDebugInfoRecord<'a> {
pub code_addr: u64,
pub entries: Vec<JitCodeDebugInfoEntry<'a>>,
}
#[derive(Debug, Clone)]
pub struct JitCodeDebugInfoEntry<'a> {
pub code_addr: u64,
pub line: u32,
pub column: u32,
pub file_path: RawData<'a>,
}
impl<'a> JitCodeDebugInfoRecord<'a> {
pub fn parse(endian: Endianness, data: RawData<'a>) -> Result<Self, std::io::Error> {
match endian {
Endianness::LittleEndian => Self::parse_impl::<LittleEndian>(data),
Endianness::BigEndian => Self::parse_impl::<BigEndian>(data),
}
}
pub fn parse_impl<O: ByteOrder>(data: RawData<'a>) -> Result<Self, std::io::Error> {
let mut cur = data;
let code_addr = cur.read_u64::<O>()?;
let nr_entry = cur.read_u64::<O>()?;
let mut entries = Vec::with_capacity(nr_entry as usize);
for _ in 0..nr_entry {
let code_addr = cur.read_u64::<O>()?;
let line = cur.read_u32::<O>()?;
let column = cur.read_u32::<O>()?;
let file_path = cur.read_string().ok_or(std::io::ErrorKind::UnexpectedEof)?;
entries.push(JitCodeDebugInfoEntry {
code_addr,
line,
column,
file_path,
});
}
Ok(Self { code_addr, entries })
}
pub fn lookup(&self, addr: u64) -> Option<&JitCodeDebugInfoEntry<'a>> {
let index = match self
.entries
.binary_search_by_key(&addr, |entry| entry.code_addr)
{
Ok(i) => i,
Err(0) => return None,
Err(i) => i - 1,
};
Some(&self.entries[index])
}
}
#[derive(Debug, Clone)]
pub struct JitCodeUnwindingInfoRecord<'a> {
pub mapped_size: u64,
pub eh_frame_hdr: RawData<'a>,
pub eh_frame: RawData<'a>,
}
impl<'a> JitCodeUnwindingInfoRecord<'a> {
pub fn parse(endian: Endianness, data: RawData<'a>) -> Result<Self, std::io::Error> {
match endian {
Endianness::LittleEndian => Self::parse_impl::<LittleEndian>(data),
Endianness::BigEndian => Self::parse_impl::<BigEndian>(data),
}
}
pub fn parse_impl<O: ByteOrder>(data: RawData<'a>) -> Result<Self, std::io::Error> {
let mut cur = data;
let unwind_data_size = cur.read_u64::<O>()?;
let eh_frame_hdr_size = cur.read_u64::<O>()? as usize;
let mapped_size = cur.read_u64::<O>()?;
let mut unwind_data = cur.split_off_prefix(unwind_data_size as usize)?;
let eh_frame_hdr = unwind_data.split_off_prefix(eh_frame_hdr_size)?;
let eh_frame = unwind_data;
Ok(Self {
mapped_size,
eh_frame_hdr,
eh_frame,
})
}
}