pub mod builder;
mod iter;
mod kind;
mod offset_segment;
#[doc(inline)]
pub use self::{iter::*, kind::SymKind, offset_segment::*};
use crate::parser::{Number, Parse, Parser, ParserError, ParserMut};
use crate::types::{ItemId, ItemIdLe, TypeIndex, TypeIndexLe};
use bitflags::bitflags;
use bstr::BStr;
use std::fmt::Debug;
use std::mem::size_of;
use zerocopy::{FromBytes, I32, Immutable, IntoBytes, KnownLayout, LE, U16, U32, Unaligned};
#[derive(IntoBytes, FromBytes, Unaligned, Immutable, KnownLayout, Default, Clone, Debug)]
#[repr(C)]
#[allow(missing_docs)]
pub struct BlockHeader {
pub p_parent: U32<LE>,
pub p_end: U32<LE>,
}
#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned, Debug)]
#[repr(C)]
#[allow(missing_docs)]
pub struct ProcFixed {
pub p_parent: U32<LE>,
pub p_end: U32<LE>,
pub p_next: U32<LE>,
pub proc_len: U32<LE>,
pub debug_start: U32<LE>,
pub debug_end: U32<LE>,
pub proc_type: TypeIndexLe,
pub offset_segment: OffsetSegment,
pub flags: u8,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ProcFlags: u8 {
const NOFPO = 1 << 0;
const INT = 1 << 1;
const FAR = 1 << 2;
const NEVER = 1 << 3;
const NOTREACHED = 1 << 4;
const CUST_CALL = 1 << 5;
const NOINLINE = 1 << 6;
const OPTDBGINFO = 1 << 7;
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct Proc<'a> {
pub fixed: &'a ProcFixed,
pub name: &'a BStr,
}
impl<'a> Proc<'a> {
pub fn flags(&self) -> ProcFlags {
ProcFlags::from_bits_retain(self.fixed.flags)
}
}
impl<'a> Parse<'a> for Proc<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[test]
fn test_parse_proc() {
#[rustfmt::skip]
let data = &[
0x2e, 0, 0x10, 0x11, 0, 0, 0, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 0xee, 0x10, 0, 0, 0xcc, 0x1, 0, 0, 1, 0, 0x50, b'm', b'e', b'm', b's', b'e', b't', 0, 0xf1, 0xf2, 2, 0, 6, 0
];
let mut i = SymIter::new(data);
let s0 = i.next().unwrap();
assert_eq!(s0.kind, SymKind::S_GPROC32);
assert_eq!(s0.data.len(), 0x2c);
match s0.parse().unwrap() {
SymData::Proc(proc) => {
assert_eq!(proc.fixed.p_parent.get(), 0);
assert_eq!(proc.fixed.p_end.get(), 0x40);
assert_eq!(proc.name, "memset");
}
_ => panic!(),
}
let s1 = i.next().unwrap();
assert_eq!(s1.kind, SymKind::S_END);
assert!(s1.data.is_empty());
}
#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned, Debug)]
#[repr(C)]
#[allow(missing_docs)]
pub struct ManagedProcFixed {
pub p_parent: U32<LE>,
pub p_end: U32<LE>,
pub p_next: U32<LE>,
pub proc_len: U32<LE>,
pub debug_start: U32<LE>,
pub debug_end: U32<LE>,
pub token: U32<LE>,
pub offset_segment: OffsetSegment,
pub flags: u8,
pub return_reg: U16<LE>,
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct ManagedProc<'a> {
pub fixed: &'a ManagedProcFixed,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for ManagedProc<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug, Default)]
#[allow(missing_docs)]
pub struct ThunkFixed {
pub block: BlockHeader,
pub p_next: U32<LE>,
pub offset_segment: OffsetSegment,
pub length: U16<LE>,
pub thunk_ordinal: u8,
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct Thunk<'a> {
pub fixed: &'a ThunkFixed,
pub name: &'a BStr,
pub variant: &'a [u8],
}
impl<'a> Parse<'a> for Thunk<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
variant: p.take_rest(),
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Default)]
pub struct SymHeader {
pub len: U16<LE>,
pub kind: U16<LE>,
}
#[derive(Clone)]
pub struct Sym<'a> {
pub kind: SymKind,
pub data: &'a [u8],
}
impl<'a> Sym<'a> {
pub fn parse(&self) -> Result<SymData<'a>, ParserError> {
SymData::parse(self.kind, self.data)
}
pub fn parse_as<T>(&self) -> Result<T, ParserError>
where
T: Parse<'a>,
{
let mut p = Parser::new(self.data);
p.parse::<T>()
}
}
impl<'a> Debug for Sym<'a> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{:?}", self.kind)
}
}
pub struct SymMut<'a> {
pub kind: SymKind,
pub data: &'a mut [u8],
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct Pub<'a> {
pub fixed: &'a PubFixed,
pub name: &'a BStr,
}
impl<'a> Pub<'a> {
pub fn offset_segment(&self) -> OffsetSegment {
self.fixed.offset_segment
}
}
#[allow(missing_docs)]
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct PubFixed {
pub flags: U32<LE>,
pub offset_segment: OffsetSegment,
}
#[allow(missing_docs)]
impl<'a> Parse<'a> for Pub<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
impl<'a> Pub<'a> {
pub fn parse_st(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strt_raw()?,
})
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct Constant<'a> {
pub type_: TypeIndex,
pub value: Number<'a>,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for Constant<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
type_: p.type_index()?,
value: p.number()?,
name: p.strz()?,
})
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct ManagedConstant<'a> {
pub token: u32,
pub value: Number<'a>,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for ManagedConstant<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
token: p.u32()?,
value: p.number()?,
name: p.strz()?,
})
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct RefSym2<'a> {
pub header: &'a RefSym2Fixed,
pub name: &'a BStr,
}
#[allow(missing_docs)]
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct RefSym2Fixed {
pub name_checksum: U32<LE>,
pub symbol_offset: U32<LE>,
pub module_index: U16<LE>,
}
impl<'a> Parse<'a> for RefSym2<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
header: p.get()?,
name: p.strz()?,
})
}
}
#[allow(missing_docs)]
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct ThreadStorageFixed {
pub type_: TypeIndexLe,
pub offset_segment: OffsetSegment,
}
#[derive(Clone, Debug)]
pub struct ThreadStorageData<'a> {
#[allow(missing_docs)]
pub header: &'a ThreadStorageFixed,
#[allow(missing_docs)]
pub name: &'a BStr,
}
impl<'a> Parse<'a> for ThreadStorageData<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
header: p.get()?,
name: p.strz()?,
})
}
}
#[allow(missing_docs)]
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct DataFixed {
pub type_: TypeIndexLe,
pub offset_segment: OffsetSegment,
}
#[allow(missing_docs)]
#[derive(Clone)]
pub struct Data<'a> {
pub header: &'a DataFixed,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for Data<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
header: p.get()?,
name: p.strz()?,
})
}
}
impl<'a> Debug for Data<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Data: {} {:?} {}",
self.header.offset_segment,
self.header.type_.get(),
self.name
)
}
}
#[derive(Clone, Debug)]
pub struct Udt<'a> {
pub type_: TypeIndex,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for Udt<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
type_: p.type_index()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
pub struct ObjectName<'a> {
pub signature: u32,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for ObjectName<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
signature: p.u32()?,
name: p.strz()?,
})
}
}
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[repr(C)]
#[allow(missing_docs)]
pub struct Compile3Fixed {
pub flags: U32<LE>,
pub machine: U16<LE>,
pub frontend_major: U16<LE>,
pub frontend_minor: U16<LE>,
pub frontend_build: U16<LE>,
pub frontend_qfe: U16<LE>,
pub ver_major: U16<LE>,
pub ver_minor: U16<LE>,
pub ver_build: U16<LE>,
pub ver_qfe: U16<LE>,
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct Compile3<'a> {
pub fixed: &'a Compile3Fixed,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for Compile3<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct FrameProc {
frame_size: U32<LE>,
pad_size: U32<LE>,
pad_offset: U32<LE>,
save_regs_size: U32<LE>,
offset_exception_handler: U32<LE>,
exception_handler_section: U16<LE>,
padding: U16<LE>,
flags: U32<LE>,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct RegRelFixed {
pub offset: U32<LE>,
pub ty: TypeIndexLe,
pub register: U16<LE>,
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct RegRel<'a> {
pub fixed: &'a RegRelFixed,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for RegRel<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct Block<'a> {
pub fixed: &'a BlockFixed,
pub name: &'a BStr,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct BlockFixed {
pub header: BlockHeader,
pub length: U32<LE>,
pub offset_segment: OffsetSegment,
}
impl<'a> Parse<'a> for Block<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct Local<'a> {
pub fixed: &'a LocalFixed,
pub name: &'a BStr,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct LocalFixed {
pub ty: TypeIndexLe,
pub flags: U16<LE>,
}
impl<'a> Parse<'a> for Local<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct LVarAddrRange {
pub start: OffsetSegment,
pub range_size: U16<LE>,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct LVarAddrGap {
pub gap_start_offset: U16<LE>,
pub range_size: U16<LE>,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct DefRangeFixed {
pub program: U32<LE>,
pub range: LVarAddrRange,
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct DefRange<'a> {
pub fixed: &'a DefRangeFixed,
pub gaps: &'a [LVarAddrGap],
}
impl<'a> Parse<'a> for DefRange<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
let fixed = p.get()?;
let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
Ok(Self { fixed, gaps })
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct DefRangeSymFramePointerRelFixed {
pub offset_to_frame_pointer: U32<LE>,
pub range: LVarAddrRange,
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct DefRangeSymFramePointerRel<'a> {
pub fixed: &'a DefRangeSymFramePointerRelFixed,
pub gaps: &'a [LVarAddrGap],
}
impl<'a> Parse<'a> for DefRangeSymFramePointerRel<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
let fixed = p.get()?;
let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
Ok(Self { fixed, gaps })
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct RangeAttrLe {
pub value: U16<LE>,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct DefRangeRegisterFixed {
pub reg: U16<LE>,
pub attr: RangeAttrLe,
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct DefRangeRegister<'a> {
pub fixed: &'a DefRangeRegisterFixed,
pub gaps: &'a [u8],
}
impl<'a> Parse<'a> for DefRangeRegister<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
gaps: p.take_rest(),
})
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub struct DefRangeRegisterRel<'a> {
pub fixed: &'a DefRangeRegisterRelFixed,
pub gaps: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct DefRangeRegisterRelFixed {
pub base_reg: U16<LE>,
pub flags: U16<LE>,
pub base_pointer_offset: I32<LE>,
pub range: LVarAddrRange,
}
impl<'a> Parse<'a> for DefRangeRegisterRel<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
gaps: p.take_rest(),
})
}
}
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
#[repr(C)]
pub struct DefRangeFramePointerRelFullScope {
pub frame_pointer_offset: I32<LE>,
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct DefRangeSubFieldRegister<'a> {
pub fixed: &'a DefRangeSubFieldRegisterFixed,
pub gaps: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct DefRangeSubFieldRegisterFixed {
pub reg: U16<LE>,
pub attr: RangeAttrLe,
pub flags: U32<LE>,
pub range: LVarAddrRange,
}
impl<'a> Parse<'a> for DefRangeSubFieldRegister<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
gaps: p.take_rest(),
})
}
}
pub struct ManProcSym<'a> {
#[allow(missing_docs)]
pub fixed: &'a ManProcSymFixed,
#[allow(missing_docs)]
pub name: &'a BStr,
}
pub type TokenIdLe = U32<LE>;
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct ManProcSymFixed {
pub block: BlockHeader,
pub pnext: U32<LE>,
pub len: U32<LE>,
pub dbg_start: U32<LE>,
pub dbg_end: U32<LE>,
pub token: TokenIdLe,
pub off: U32<LE>,
pub seg: U16<LE>,
pub flags: u8, pub padding: u8,
pub ret_reg: U16<LE>,
}
impl<'a> Parse<'a> for ManProcSym<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
pub struct Trampoline<'a> {
pub fixed: &'a TrampolineFixed,
pub rest: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
pub struct TrampolineFixed {
pub kind: U16<LE>,
pub thunk_len: U16<LE>,
pub thunk_offset: U32<LE>,
pub target_offset: U32<LE>,
pub thunk_segment: U16<LE>,
pub target_segment: U16<LE>,
}
impl TrampolineFixed {
pub fn thunk(&self) -> OffsetSegment {
OffsetSegment {
offset: self.thunk_offset,
segment: self.thunk_segment,
}
}
pub fn target(&self) -> OffsetSegment {
OffsetSegment {
offset: self.target_offset,
segment: self.target_segment,
}
}
}
impl<'a> Parse<'a> for Trampoline<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
rest: p.take_rest(),
})
}
}
#[test]
fn test_trampoline() {
use hex_literal::hex;
let data = hex!(
"0101" "0202" "03030303" "04040404" "0505" "0606" "cccccc" );
let sym = Trampoline::parse(&data).unwrap();
assert_eq!(sym.fixed.kind.get(), 0x0101);
assert_eq!(sym.fixed.thunk_len.get(), 0x0202);
assert_eq!(sym.fixed.thunk_offset.get(), 0x03030303);
assert_eq!(sym.fixed.target_offset.get(), 0x04040404);
assert_eq!(sym.fixed.thunk_segment.get(), 0x0505);
assert_eq!(sym.fixed.target_segment.get(), 0x0606);
assert_eq!(sym.rest, &hex!("cccccc"));
assert_eq!(sym.fixed.thunk().offset, sym.fixed.thunk_offset);
assert_eq!(sym.fixed.thunk().segment, sym.fixed.thunk_segment);
assert_eq!(sym.fixed.target().offset, sym.fixed.target_offset);
assert_eq!(sym.fixed.target().segment, sym.fixed.target_segment);
}
#[derive(Clone, Debug)]
pub struct BuildInfo {
pub item: ItemId,
}
impl<'a> Parse<'a> for BuildInfo {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self { item: p.u32()? })
}
}
#[derive(Clone, Debug)]
pub struct UsingNamespace<'a> {
pub namespace: &'a BStr,
}
impl<'a> Parse<'a> for UsingNamespace<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
namespace: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct Label<'a> {
pub fixed: &'a LabelFixed,
pub name: &'a BStr,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct LabelFixed {
pub offset_segment: OffsetSegment,
pub flags: u8,
}
impl<'a> Parse<'a> for Label<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
pub struct FunctionList<'a> {
pub funcs: &'a [ItemIdLe],
pub counts: &'a [U32<LE>],
}
impl<'a> Parse<'a> for FunctionList<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
let num_funcs = p.u32()? as usize;
let funcs: &[ItemIdLe] = p.slice(num_funcs)?;
let num_counts = num_funcs.min(p.len() / size_of::<U32<LE>>());
let counts = p.slice(num_counts)?;
Ok(Self { funcs, counts })
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct InlineSite<'a> {
pub fixed: &'a InlineSiteFixed,
pub binary_annotations: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct InlineSiteFixed {
pub block: BlockHeader,
pub inlinee: ItemIdLe,
}
impl<'a> Parse<'a> for InlineSite<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
binary_annotations: p.take_rest(),
})
}
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct InlineSite2<'a> {
pub fixed: &'a InlineSite2Fixed,
pub binary_annotations: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct InlineSite2Fixed {
pub block: BlockHeader,
pub inlinee: ItemIdLe,
pub invocations: U32<LE>,
}
impl<'a> Parse<'a> for InlineSite2<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
binary_annotations: p.take_rest(),
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct FrameCookie {
pub offset: I32<LE>,
pub reg: U16<LE>,
pub cookie_type: u8,
pub flags: u8,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct CallSiteInfo {
pub offset: OffsetSegment,
pub padding: U16<LE>,
pub func_type: TypeIndexLe,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct HeapAllocSite {
pub offset: OffsetSegment,
pub instruction_size: U16<LE>,
pub func_type: TypeIndexLe,
}
#[allow(missing_docs)]
#[derive(Clone, Debug)]
pub struct Annotation<'a> {
pub fixed: &'a AnnotationFixed,
pub strings: &'a [u8],
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
#[allow(missing_docs)]
pub struct AnnotationFixed {
pub offset: OffsetSegment,
pub num_strings: U16<LE>,
}
impl<'a> Parse<'a> for Annotation<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
strings: p.take_rest(),
})
}
}
impl<'a> Annotation<'a> {
pub fn iter_strings(&self) -> AnnotationIterStrings<'a> {
AnnotationIterStrings {
num_strings: self.fixed.num_strings.get(),
bytes: self.strings,
}
}
}
#[allow(missing_docs)]
pub struct AnnotationIterStrings<'a> {
pub num_strings: u16,
pub bytes: &'a [u8],
}
impl<'a> Iterator for AnnotationIterStrings<'a> {
type Item = &'a BStr;
fn next(&mut self) -> Option<Self::Item> {
if self.num_strings == 0 {
return None;
}
self.num_strings -= 1;
let mut p = Parser::new(self.bytes);
let s = p.strz().ok()?;
self.bytes = p.into_rest();
Some(s)
}
}
#[derive(Clone, Debug)]
pub struct HotPatchFunc<'a> {
pub func: ItemId,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for HotPatchFunc<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
func: p.u32()?,
name: p.strz()?,
})
}
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone)]
pub struct ArmSwitchTable {
pub offset_base: U32<LE>,
pub sect_base: U16<LE>,
pub switch_type: U16<LE>,
pub offset_branch: U32<LE>,
pub offset_table: U32<LE>,
pub sect_branch: U16<LE>,
pub sect_table: U16<LE>,
pub num_entries: U32<LE>,
}
impl ArmSwitchTable {
pub fn base(&self) -> OffsetSegment {
OffsetSegment {
offset: self.offset_base,
segment: self.sect_base,
}
}
pub fn branch(&self) -> OffsetSegment {
OffsetSegment {
offset: self.offset_branch,
segment: self.sect_branch,
}
}
pub fn table(&self) -> OffsetSegment {
OffsetSegment {
offset: self.offset_table,
segment: self.sect_table,
}
}
pub fn switch_type(&self) -> ArmSwitchType {
ArmSwitchType(self.switch_type.get())
}
pub fn num_entries(&self) -> u32 {
self.num_entries.get()
}
}
impl core::fmt::Debug for ArmSwitchTable {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ArmSwitchTable")
.field("base", &self.base())
.field("branch", &self.branch())
.field("table", &self.table())
.field("switch_type", &self.switch_type())
.field("num_entries", &self.num_entries())
.finish()
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ArmSwitchType(pub u16);
impl ArmSwitchType {
pub const INT1: ArmSwitchType = ArmSwitchType(0);
pub const UINT1: ArmSwitchType = ArmSwitchType(1);
pub const INT2: ArmSwitchType = ArmSwitchType(2);
pub const UINT2: ArmSwitchType = ArmSwitchType(3);
pub const INT4: ArmSwitchType = ArmSwitchType(4);
pub const UINT4: ArmSwitchType = ArmSwitchType(5);
pub const POINTER: ArmSwitchType = ArmSwitchType(6);
pub const UINT1SHL1: ArmSwitchType = ArmSwitchType(7);
pub const UINT2SHL1: ArmSwitchType = ArmSwitchType(8);
pub const INT1SHL1: ArmSwitchType = ArmSwitchType(9);
pub const INT2SHL1: ArmSwitchType = ArmSwitchType(10);
}
impl core::fmt::Debug for ArmSwitchType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
static NAMES: [&str; 11] = [
"INT1",
"UINT1",
"INT2",
"UINT2",
"INT4",
"UINT4",
"POINTER",
"UINT1SHL1",
"UINT2SHL1",
"INT1SHL1",
"INT2SHL1",
];
if let Some(&s) = NAMES.get(self.0 as usize) {
f.write_str(s)
} else {
write!(f, "??{}", self.0)
}
}
}
pub const TRAMPOLINE_KIND_INCREMENTAL: u16 = 0;
pub const TRAMPOLINE_KIND_BRANCH_ISLAND: u16 = 1;
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct CoffGroupFixed {
pub cb: U32<LE>,
pub characteristics: U32<LE>,
pub off_seg: OffsetSegment,
}
#[derive(Clone, Debug)]
pub struct CoffGroup<'a> {
pub fixed: &'a CoffGroupFixed,
pub name: &'a BStr,
}
impl<'a> Parse<'a> for CoffGroup<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
pub struct Section<'a> {
pub fixed: &'a SectionFixed,
pub name: &'a BStr,
}
#[repr(C)]
#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
pub struct SectionFixed {
pub section: U16<LE>,
pub align: u8,
pub reserved: u8,
pub rva: U32<LE>,
pub cb: U32<LE>,
pub characteristics: U32<LE>,
}
impl<'a> Parse<'a> for Section<'a> {
fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(Self {
fixed: p.get()?,
name: p.strz()?,
})
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum SymData<'a> {
Unknown,
ObjName(ObjectName<'a>),
Compile3(Compile3<'a>),
Proc(Proc<'a>),
Thunk(Thunk<'a>),
Udt(Udt<'a>),
Constant(Constant<'a>),
ManagedConstant(ManagedConstant<'a>),
RefSym2(RefSym2<'a>),
Data(Data<'a>),
ThreadData(ThreadStorageData<'a>),
Pub(Pub<'a>),
End,
FrameProc(&'a FrameProc),
RegRel(RegRel<'a>),
Block(Block<'a>),
Local(Local<'a>),
DefRange(DefRange<'a>),
DefRangeFramePointerRel(DefRangeSymFramePointerRel<'a>),
DefRangeRegister(DefRangeRegister<'a>),
DefRangeRegisterRel(DefRangeRegisterRel<'a>),
DefRangeFramePointerRelFullScope(&'a DefRangeFramePointerRelFullScope),
DefRangeSubFieldRegister(DefRangeSubFieldRegister<'a>),
Trampoline(Trampoline<'a>),
BuildInfo(BuildInfo),
UsingNamespace(UsingNamespace<'a>),
InlineSiteEnd,
Label(Label<'a>),
FunctionList(FunctionList<'a>),
InlineSite(InlineSite<'a>),
InlineSite2(InlineSite2<'a>),
FrameCookie(&'a FrameCookie),
CallSiteInfo(&'a CallSiteInfo),
HeapAllocSite(&'a HeapAllocSite),
ManagedProc(ManagedProc<'a>),
Annotation(Annotation<'a>),
HotPatchFunc(HotPatchFunc<'a>),
CoffGroup(CoffGroup<'a>),
ArmSwitchTable(&'a ArmSwitchTable),
Section(Section<'a>),
}
impl<'a> SymData<'a> {
pub fn parse(kind: SymKind, data: &'a [u8]) -> Result<Self, ParserError> {
let mut p = Parser::new(data);
Self::from_parser(kind, &mut p)
}
pub fn from_parser(kind: SymKind, p: &mut Parser<'a>) -> Result<Self, ParserError> {
Ok(match kind {
SymKind::S_OBJNAME => Self::ObjName(p.parse()?),
SymKind::S_GPROC32 | SymKind::S_LPROC32 => Self::Proc(p.parse()?),
SymKind::S_THUNK32 => Self::Thunk(p.parse()?),
SymKind::S_COMPILE3 => Self::Compile3(p.parse()?),
SymKind::S_UDT => Self::Udt(p.parse()?),
SymKind::S_CONSTANT => Self::Constant(p.parse()?),
SymKind::S_MANCONSTANT => Self::Constant(p.parse()?),
SymKind::S_PUB32 => Self::Pub(p.parse()?),
SymKind::S_PUB32_ST => Self::Pub(Pub::parse_st(p)?),
SymKind::S_PROCREF
| SymKind::S_LPROCREF
| SymKind::S_DATAREF
| SymKind::S_ANNOTATIONREF => Self::RefSym2(p.parse()?),
SymKind::S_LDATA32 | SymKind::S_GDATA32 | SymKind::S_LMANDATA | SymKind::S_GMANDATA => {
Self::Data(p.parse()?)
}
SymKind::S_LTHREAD32 | SymKind::S_GTHREAD32 => Self::ThreadData(p.parse()?),
SymKind::S_END => Self::End,
SymKind::S_FRAMEPROC => Self::FrameProc(p.get()?),
SymKind::S_REGREL32 => Self::RegRel(p.parse()?),
SymKind::S_BLOCK32 => Self::Block(p.parse()?),
SymKind::S_LOCAL => Self::Local(p.parse()?),
SymKind::S_DEFRANGE => Self::DefRange(p.parse()?),
SymKind::S_DEFRANGE_FRAMEPOINTER_REL => Self::DefRangeFramePointerRel(p.parse()?),
SymKind::S_DEFRANGE_REGISTER => Self::DefRangeRegister(p.parse()?),
SymKind::S_DEFRANGE_REGISTER_REL => Self::DefRangeRegisterRel(p.parse()?),
SymKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => {
Self::DefRangeFramePointerRelFullScope(p.get()?)
}
SymKind::S_DEFRANGE_SUBFIELD_REGISTER => Self::DefRangeSubFieldRegister(p.parse()?),
SymKind::S_TRAMPOLINE => Self::Trampoline(p.parse()?),
SymKind::S_BUILDINFO => Self::BuildInfo(p.parse()?),
SymKind::S_UNAMESPACE => Self::UsingNamespace(p.parse()?),
SymKind::S_INLINESITE_END => Self::InlineSiteEnd,
SymKind::S_LABEL32 => Self::Label(p.parse()?),
SymKind::S_CALLEES | SymKind::S_CALLERS => Self::FunctionList(p.parse()?),
SymKind::S_INLINESITE => Self::InlineSite(p.parse()?),
SymKind::S_INLINESITE2 => Self::InlineSite2(p.parse()?),
SymKind::S_INLINEES => Self::FunctionList(p.parse()?),
SymKind::S_FRAMECOOKIE => Self::FrameCookie(p.get()?),
SymKind::S_CALLSITEINFO => Self::CallSiteInfo(p.get()?),
SymKind::S_HEAPALLOCSITE => Self::HeapAllocSite(p.get()?),
SymKind::S_GMANPROC | SymKind::S_LMANPROC => Self::ManagedProc(p.parse()?),
SymKind::S_ANNOTATION => Self::Annotation(p.parse()?),
SymKind::S_HOTPATCHFUNC => Self::HotPatchFunc(p.parse()?),
SymKind::S_ARMSWITCHTABLE => Self::ArmSwitchTable(p.get()?),
SymKind::S_COFFGROUP => Self::CoffGroup(p.parse()?),
SymKind::S_SECTION => Self::Section(p.parse()?),
_ => Self::Unknown,
})
}
pub fn name(&self) -> Option<&'a BStr> {
match self {
Self::Proc(proc) => Some(proc.name),
Self::Data(data) => Some(data.name),
Self::ThreadData(thread_data) => Some(thread_data.name),
Self::Udt(udt) => Some(udt.name),
Self::Local(local) => Some(local.name),
Self::RefSym2(refsym) => Some(refsym.name),
Self::Constant(c) => Some(c.name),
Self::ManagedConstant(c) => Some(c.name),
_ => None,
}
}
}