// https://llvm.org/docs/StackMaps.html#stackmap-section use byteorder::{LittleEndian, ReadBytesExt}; use std::io::{self, Cursor}; #[derive(Default, Debug, Clone)] pub struct StackmapRegistry { pub entries: Vec, } #[derive(Debug, Clone)] pub struct StackmapEntry { pub kind: StackmapEntryKind, pub local_function_id: usize, pub local_count: usize, pub stack_count: usize, } #[derive(Debug, Clone, Copy)] pub enum StackmapEntryKind { Loop, Call, Trappable, } #[derive(Clone, Debug, Default)] pub struct StackMap { pub version: u8, pub stk_size_records: Vec, pub constants: Vec, pub stk_map_records: Vec, } #[derive(Copy, Clone, Debug, Default)] pub struct StkSizeRecord { pub function_address: u64, pub stack_size: u64, pub record_count: u64, } #[derive(Copy, Clone, Debug, Default)] pub struct Constant { pub large_constant: u64, } #[derive(Clone, Debug, Default)] pub struct StkMapRecord { pub patchpoint_id: u64, pub instruction_offset: u32, pub locations: Vec, pub live_outs: Vec, } #[derive(Copy, Clone, Debug)] pub struct Location { pub ty: LocationType, pub location_size: u16, pub dwarf_regnum: u16, pub offset_or_small_constant: i32, } #[derive(Copy, Clone, Debug, Default)] pub struct LiveOut { pub dwarf_regnum: u16, pub size_in_bytes: u8, } #[derive(Copy, Clone, Debug)] pub enum LocationType { Register, Direct, Indirect, Constant, ConstantIndex, } impl StackMap { pub fn parse(raw: &[u8]) -> io::Result { let mut reader = Cursor::new(raw); let mut map = StackMap::default(); let version = reader.read_u8()?; if version != 3 { return Err(io::Error::new(io::ErrorKind::Other, "version is not 3")); } map.version = version; if reader.read_u8()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (1)", )); } if reader.read_u16::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (2)", )); } let num_functions = reader.read_u32::()?; let num_constants = reader.read_u32::()?; let num_records = reader.read_u32::()?; for _ in 0..num_functions { let mut record = StkSizeRecord::default(); record.function_address = reader.read_u64::()?; record.stack_size = reader.read_u64::()?; record.record_count = reader.read_u64::()?; map.stk_size_records.push(record); } for _ in 0..num_constants { map.constants.push(Constant { large_constant: reader.read_u64::()?, }); } for _ in 0..num_records { let mut record = StkMapRecord::default(); record.patchpoint_id = reader.read_u64::()?; record.instruction_offset = reader.read_u32::()?; if reader.read_u16::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (3)", )); } let num_locations = reader.read_u16::()?; for _ in 0..num_locations { let ty = reader.read_u8()?; let mut location = Location { ty: match ty { 1 => LocationType::Register, 2 => LocationType::Direct, 3 => LocationType::Indirect, 4 => LocationType::Constant, 5 => LocationType::ConstantIndex, _ => { return Err(io::Error::new( io::ErrorKind::Other, "unknown location type", )) } }, location_size: 0, dwarf_regnum: 0, offset_or_small_constant: 0, }; if reader.read_u8()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (4)", )); } location.location_size = reader.read_u16::()?; location.dwarf_regnum = reader.read_u16::()?; if reader.read_u16::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (5)", )); } location.offset_or_small_constant = reader.read_i32::()?; record.locations.push(location); } if reader.position() % 8 != 0 { if reader.read_u32::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (6)", )); } } if reader.read_u16::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (7)", )); } let num_live_outs = reader.read_u16::()?; for _ in 0..num_live_outs { let mut liveout = LiveOut::default(); liveout.dwarf_regnum = reader.read_u16::()?; if reader.read_u8()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (8)", )); } liveout.size_in_bytes = reader.read_u8()?; record.live_outs.push(liveout); } if reader.position() % 8 != 0 { if reader.read_u32::()? != 0 { return Err(io::Error::new( io::ErrorKind::Other, "reserved field is not zero (9)", )); } } map.stk_map_records.push(record); } Ok(map) } }