use std::fmt;
use scroll::{ctx::TryFromCtx, Endian, Pread, LE};
use crate::common::*;
use crate::msf::*;
use crate::FallibleIterator;
use crate::SectionCharacteristics;
mod annotations;
mod constants;
use self::constants::*;
pub use self::constants::{CPUType, SourceLanguage};
pub use self::annotations::*;
pub type SymbolKind = u16;
#[derive(Copy, Clone, PartialEq)]
pub struct Symbol<'t> {
index: SymbolIndex,
data: &'t [u8],
}
impl<'t> Symbol<'t> {
#[inline]
#[must_use]
pub fn index(&self) -> SymbolIndex {
self.index
}
#[inline]
#[must_use]
pub fn raw_kind(&self) -> SymbolKind {
debug_assert!(self.data.len() >= 2);
self.data.pread_with(0, LE).unwrap_or_default()
}
#[inline]
#[must_use]
pub fn raw_bytes(&self) -> &'t [u8] {
self.data
}
#[inline]
pub fn parse(&self) -> Result<SymbolData<'t>> {
self.raw_bytes().pread_with(0, ())
}
#[must_use]
pub fn starts_scope(&self) -> bool {
matches!(
self.raw_kind(),
S_GPROC16
| S_GPROC32
| S_GPROC32_ST
| S_GPROCMIPS
| S_GPROCMIPS_ST
| S_GPROCIA64
| S_GPROCIA64_ST
| S_LPROC16
| S_LPROC32
| S_LPROC32_ST
| S_LPROC32_DPC
| S_LPROCMIPS
| S_LPROCMIPS_ST
| S_LPROCIA64
| S_LPROCIA64_ST
| S_LPROC32_DPC_ID
| S_GPROC32_ID
| S_GPROCMIPS_ID
| S_GPROCIA64_ID
| S_BLOCK16
| S_BLOCK32
| S_BLOCK32_ST
| S_WITH16
| S_WITH32
| S_WITH32_ST
| S_THUNK16
| S_THUNK32
| S_THUNK32_ST
| S_SEPCODE
| S_GMANPROC
| S_GMANPROC_ST
| S_LMANPROC
| S_LMANPROC_ST
| S_INLINESITE
| S_INLINESITE2
)
}
#[must_use]
pub fn ends_scope(&self) -> bool {
matches!(self.raw_kind(), S_END | S_PROC_ID_END | S_INLINESITE_END)
}
}
impl fmt::Debug for Symbol<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Symbol{{ kind: 0x{:x} [{} bytes] }}",
self.raw_kind(),
self.data.len()
)
}
}
fn parse_symbol_name<'t>(buf: &mut ParseBuffer<'t>, kind: SymbolKind) -> Result<RawString<'t>> {
if kind < S_ST_MAX {
buf.parse_u8_pascal_string()
} else {
buf.parse_cstring()
}
}
fn parse_optional_name<'t>(
buf: &mut ParseBuffer<'t>,
kind: SymbolKind,
) -> Result<Option<RawString<'t>>> {
if kind < S_ST_MAX {
Ok(None)
} else {
buf.parse_cstring().map(Some)
}
}
fn parse_optional_index(buf: &mut ParseBuffer<'_>) -> Result<Option<SymbolIndex>> {
Ok(match buf.parse()? {
SymbolIndex(0) => None,
index => Some(index),
})
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SymbolData<'t> {
ScopeEnd,
ObjName(ObjNameSymbol<'t>),
RegisterVariable(RegisterVariableSymbol<'t>),
Constant(ConstantSymbol<'t>),
UserDefinedType(UserDefinedTypeSymbol<'t>),
MultiRegisterVariable(MultiRegisterVariableSymbol<'t>),
Data(DataSymbol<'t>),
Public(PublicSymbol<'t>),
Procedure(ProcedureSymbol<'t>),
ManagedProcedure(ManagedProcedureSymbol<'t>),
ThreadStorage(ThreadStorageSymbol<'t>),
CompileFlags(CompileFlagsSymbol<'t>),
UsingNamespace(UsingNamespaceSymbol<'t>),
ProcedureReference(ProcedureReferenceSymbol<'t>),
DataReference(DataReferenceSymbol<'t>),
Annotation(AnnotationSymbol<'t>),
AnnotationReference(AnnotationReferenceSymbol<'t>),
TokenReference(TokenReferenceSymbol<'t>),
Trampoline(TrampolineSymbol),
Export(ExportSymbol<'t>),
Local(LocalSymbol<'t>),
ManagedSlot(ManagedSlotSymbol<'t>),
BuildInfo(BuildInfoSymbol),
InlineSite(InlineSiteSymbol<'t>),
InlineSiteEnd,
ProcedureEnd,
Label(LabelSymbol<'t>),
Block(BlockSymbol<'t>),
RegisterRelative(RegisterRelativeSymbol<'t>),
Thunk(ThunkSymbol<'t>),
SeparatedCode(SeparatedCodeSymbol),
OEM(OemSymbol<'t>),
EnvBlock(EnvBlockSymbol<'t>),
Section(SectionSymbol<'t>),
CoffGroup(CoffGroupSymbol<'t>),
DefRange(DefRangeSymbol),
DefRangeSubField(DefRangeSubFieldSymbol),
DefRangeRegister(DefRangeRegisterSymbol),
DefRangeFramePointerRelative(DefRangeFramePointerRelativeSymbol),
DefRangeFramePointerRelativeFullScope(DefRangeFramePointerRelativeFullScopeSymbol),
DefRangeSubFieldRegister(DefRangeSubFieldRegisterSymbol),
DefRangeRegisterRelative(DefRangeRegisterRelativeSymbol),
BasePointerRelative(BasePointerRelativeSymbol<'t>),
FrameProcedure(FrameProcedureSymbol),
CallSiteInfo(CallSiteInfoSymbol),
Callers(FunctionListSymbol),
Callees(FunctionListSymbol),
Inlinees(InlineesSymbol),
ArmSwitchTable(ArmSwitchTableSymbol),
HeapAllocationSite(HeapAllocationSiteSymbol),
FrameCookie(FrameCookieSymbol),
FileStatic(FileStaticSymbol<'t>),
}
impl<'t> SymbolData<'t> {
#[must_use]
pub fn name(&self) -> Option<RawString<'t>> {
match self {
Self::ObjName(data) => Some(data.name),
Self::Constant(data) => Some(data.name),
Self::UserDefinedType(data) => Some(data.name),
Self::Data(data) => Some(data.name),
Self::Public(data) => Some(data.name),
Self::Procedure(data) => Some(data.name),
Self::ManagedProcedure(data) => data.name,
Self::ThreadStorage(data) => Some(data.name),
Self::UsingNamespace(data) => Some(data.name),
Self::ProcedureReference(data) => data.name,
Self::DataReference(data) => data.name,
Self::AnnotationReference(data) => Some(data.name),
Self::TokenReference(data) => Some(data.name),
Self::Export(data) => Some(data.name),
Self::Local(data) => Some(data.name),
Self::ManagedSlot(data) => Some(data.name),
Self::Label(data) => Some(data.name),
Self::Block(data) => Some(data.name),
Self::RegisterRelative(data) => Some(data.name),
Self::Thunk(data) => Some(data.name),
Self::Section(data) => Some(data.name),
Self::CoffGroup(data) => Some(data.name),
Self::BasePointerRelative(data) => Some(data.name),
Self::FileStatic(data) => Some(data.name),
Self::ScopeEnd
| Self::RegisterVariable(_)
| Self::MultiRegisterVariable(_)
| Self::CompileFlags(_)
| Self::Trampoline(_)
| Self::InlineSite(_)
| Self::BuildInfo(_)
| Self::InlineSiteEnd
| Self::ProcedureEnd
| Self::SeparatedCode(_)
| Self::OEM(_)
| Self::EnvBlock(_)
| Self::DefRange(_)
| Self::DefRangeSubField(_)
| Self::DefRangeRegister(_)
| Self::DefRangeFramePointerRelative(_)
| Self::DefRangeFramePointerRelativeFullScope(_)
| Self::DefRangeSubFieldRegister(_)
| Self::DefRangeRegisterRelative(_)
| Self::FrameProcedure(_)
| Self::CallSiteInfo(_)
| Self::Callers(_)
| Self::Callees(_)
| Self::Inlinees(_)
| Self::ArmSwitchTable(_)
| Self::HeapAllocationSite(_)
| Self::FrameCookie(_)
| Self::Annotation(_) => None,
}
}
}
impl<'t> TryFromCtx<'t> for SymbolData<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _ctx: ()) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let kind = buf.parse()?;
let symbol = match kind {
S_END => SymbolData::ScopeEnd,
S_OBJNAME | S_OBJNAME_ST => SymbolData::ObjName(buf.parse_with(kind)?),
S_REGISTER | S_REGISTER_ST => SymbolData::RegisterVariable(buf.parse_with(kind)?),
S_CONSTANT | S_CONSTANT_ST | S_MANCONSTANT => {
SymbolData::Constant(buf.parse_with(kind)?)
}
S_UDT | S_UDT_ST | S_COBOLUDT | S_COBOLUDT_ST => {
SymbolData::UserDefinedType(buf.parse_with(kind)?)
}
S_MANYREG | S_MANYREG_ST | S_MANYREG2 | S_MANYREG2_ST => {
SymbolData::MultiRegisterVariable(buf.parse_with(kind)?)
}
S_LDATA32 | S_LDATA32_ST | S_GDATA32 | S_GDATA32_ST | S_LMANDATA | S_LMANDATA_ST
| S_GMANDATA | S_GMANDATA_ST => SymbolData::Data(buf.parse_with(kind)?),
S_PUB32 | S_PUB32_ST => SymbolData::Public(buf.parse_with(kind)?),
S_LPROC32 | S_LPROC32_ST | S_GPROC32 | S_GPROC32_ST | S_LPROC32_ID | S_GPROC32_ID
| S_LPROC32_DPC | S_LPROC32_DPC_ID => SymbolData::Procedure(buf.parse_with(kind)?),
S_LMANPROC | S_GMANPROC => SymbolData::ManagedProcedure(buf.parse_with(kind)?),
S_LTHREAD32 | S_LTHREAD32_ST | S_GTHREAD32 | S_GTHREAD32_ST => {
SymbolData::ThreadStorage(buf.parse_with(kind)?)
}
S_COMPILE2 | S_COMPILE2_ST | S_COMPILE3 => {
SymbolData::CompileFlags(buf.parse_with(kind)?)
}
S_UNAMESPACE | S_UNAMESPACE_ST => SymbolData::UsingNamespace(buf.parse_with(kind)?),
S_PROCREF | S_PROCREF_ST | S_LPROCREF | S_LPROCREF_ST => {
SymbolData::ProcedureReference(buf.parse_with(kind)?)
}
S_TRAMPOLINE => Self::Trampoline(buf.parse_with(kind)?),
S_DATAREF | S_DATAREF_ST => SymbolData::DataReference(buf.parse_with(kind)?),
S_ANNOTATION => SymbolData::Annotation(buf.parse_with(kind)?),
S_ANNOTATIONREF => SymbolData::AnnotationReference(buf.parse_with(kind)?),
S_TOKENREF => SymbolData::TokenReference(buf.parse_with(kind)?),
S_EXPORT => SymbolData::Export(buf.parse_with(kind)?),
S_LOCAL => SymbolData::Local(buf.parse_with(kind)?),
S_MANSLOT | S_MANSLOT_ST => SymbolData::ManagedSlot(buf.parse_with(kind)?),
S_BUILDINFO => SymbolData::BuildInfo(buf.parse_with(kind)?),
S_INLINESITE | S_INLINESITE2 => SymbolData::InlineSite(buf.parse_with(kind)?),
S_INLINESITE_END => SymbolData::InlineSiteEnd,
S_PROC_ID_END => SymbolData::ProcedureEnd,
S_LABEL32 | S_LABEL32_ST => SymbolData::Label(buf.parse_with(kind)?),
S_BLOCK32 | S_BLOCK32_ST => SymbolData::Block(buf.parse_with(kind)?),
S_REGREL32 => SymbolData::RegisterRelative(buf.parse_with(kind)?),
S_THUNK32 | S_THUNK32_ST => SymbolData::Thunk(buf.parse_with(kind)?),
S_SEPCODE => SymbolData::SeparatedCode(buf.parse_with(kind)?),
S_OEM => SymbolData::OEM(buf.parse_with(kind)?),
S_ENVBLOCK => SymbolData::EnvBlock(buf.parse_with(kind)?),
S_SECTION => SymbolData::Section(buf.parse_with(kind)?),
S_COFFGROUP => SymbolData::CoffGroup(buf.parse_with(kind)?),
S_DEFRANGE => SymbolData::DefRange(buf.parse_with(kind)?),
S_DEFRANGE_SUBFIELD => SymbolData::DefRangeSubField(buf.parse_with(kind)?),
S_DEFRANGE_REGISTER => SymbolData::DefRangeRegister(buf.parse_with(kind)?),
S_DEFRANGE_FRAMEPOINTER_REL => {
SymbolData::DefRangeFramePointerRelative(buf.parse_with(kind)?)
}
S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => {
SymbolData::DefRangeFramePointerRelativeFullScope(buf.parse_with(kind)?)
}
S_DEFRANGE_SUBFIELD_REGISTER => {
SymbolData::DefRangeSubFieldRegister(buf.parse_with(kind)?)
}
S_DEFRANGE_REGISTER_REL => SymbolData::DefRangeRegisterRelative(buf.parse_with(kind)?),
S_BPREL32 | S_BPREL32_ST | S_BPREL32_16T => {
SymbolData::BasePointerRelative(buf.parse_with(kind)?)
}
S_FRAMEPROC => SymbolData::FrameProcedure(buf.parse_with(kind)?),
S_CALLSITEINFO => SymbolData::CallSiteInfo(buf.parse_with(kind)?),
S_CALLERS => SymbolData::Callers(buf.parse_with(kind)?),
S_CALLEES => SymbolData::Callees(buf.parse_with(kind)?),
S_INLINEES => SymbolData::Inlinees(buf.parse_with(kind)?),
S_ARMSWITCHTABLE => SymbolData::ArmSwitchTable(buf.parse_with(kind)?),
S_HEAPALLOCSITE => SymbolData::HeapAllocationSite(buf.parse_with(kind)?),
S_FRAMECOOKIE => SymbolData::FrameCookie(buf.parse_with(kind)?),
S_FILESTATIC => SymbolData::FileStatic(buf.parse_with(kind)?),
other => return Err(Error::UnimplementedSymbolKind(other)),
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RegisterVariableSymbol<'t> {
pub type_index: TypeIndex,
pub register: Register,
pub name: RawString<'t>,
pub slot: Option<i32>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for RegisterVariableSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let type_index: TypeIndex = buf.parse()?;
let register: Register = buf.parse()?;
let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?;
let slot: Option<i32> = if (this.len() as i64 - name.len() as i64 - 8i64) >= 6 {
if this[name.len() + 0xb] == 0x24 {
Some(ParseBuffer::from(&this[(name.len() + 0xc)..]).parse()?)
} else {
None
}
} else {
None
};
Ok((
Self {
type_index,
register,
name,
slot,
},
buf.pos(),
))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MultiRegisterVariableSymbol<'t> {
pub type_index: TypeIndex,
pub registers: Vec<(Register, RawString<'t>)>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for MultiRegisterVariableSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let type_index = buf.parse()?;
let count = match kind {
S_MANYREG2 | S_MANYREG2_ST => buf.parse::<u16>()?,
_ => u16::from(buf.parse::<u8>()?),
};
let mut registers = Vec::with_capacity(count as usize);
for _ in 0..count {
registers.push((buf.parse()?, parse_symbol_name(&mut buf, kind)?));
}
let symbol = MultiRegisterVariableSymbol {
type_index,
registers,
};
Ok((symbol, buf.pos()))
}
}
const CVPSF_CODE: u32 = 0x1;
const CVPSF_FUNCTION: u32 = 0x2;
const CVPSF_MANAGED: u32 = 0x4;
const CVPSF_MSIL: u32 = 0x8;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PublicSymbol<'t> {
pub code: bool,
pub function: bool,
pub managed: bool,
pub msil: bool,
pub offset: PdbInternalSectionOffset,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for PublicSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let flags = buf.parse::<u32>()?;
let symbol = PublicSymbol {
code: flags & CVPSF_CODE != 0,
function: flags & CVPSF_FUNCTION != 0,
managed: flags & CVPSF_MANAGED != 0,
msil: flags & CVPSF_MSIL != 0,
offset: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DataSymbol<'t> {
pub global: bool,
pub managed: bool,
pub type_index: TypeIndex,
pub offset: PdbInternalSectionOffset,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for DataSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = DataSymbol {
global: matches!(kind, S_GDATA32 | S_GDATA32_ST | S_GMANDATA | S_GMANDATA_ST),
managed: matches!(
kind,
S_LMANDATA | S_LMANDATA_ST | S_GMANDATA | S_GMANDATA_ST
),
type_index: buf.parse()?,
offset: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProcedureReferenceSymbol<'t> {
pub global: bool,
pub sum_name: u32,
pub symbol_index: SymbolIndex,
pub module: Option<usize>,
pub name: Option<RawString<'t>>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureReferenceSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let global = matches!(kind, S_PROCREF | S_PROCREF_ST);
let sum_name = buf.parse()?;
let symbol_index = buf.parse()?;
let module = buf.parse::<u16>()?.checked_sub(1).map(usize::from);
let name = parse_optional_name(&mut buf, kind)?;
let symbol = ProcedureReferenceSymbol {
global,
sum_name,
symbol_index,
module,
name,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct DataReferenceSymbol<'t> {
pub sum_name: u32,
pub symbol_index: SymbolIndex,
pub module: Option<usize>,
pub name: Option<RawString<'t>>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for DataReferenceSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let sum_name = buf.parse()?;
let symbol_index = buf.parse()?;
let module = buf.parse::<u16>()?.checked_sub(1).map(usize::from);
let name = parse_optional_name(&mut buf, kind)?;
let symbol = DataReferenceSymbol {
sum_name,
symbol_index,
module,
name,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AnnotationSymbol<'t> {
pub offset: PdbInternalSectionOffset,
pub strings: Vec<RawString<'t>>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for AnnotationSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset = buf.parse()?;
let string_count = buf.parse_u16()?;
let mut strings = vec![];
for _ in 0..string_count {
strings.push(buf.parse_cstring()?);
}
let symbol = AnnotationSymbol {
offset,
strings,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AnnotationReferenceSymbol<'t> {
pub sum_name: u32,
pub symbol_index: SymbolIndex,
pub module: Option<usize>,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for AnnotationReferenceSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let sum_name = buf.parse()?;
let symbol_index = buf.parse()?;
let module = buf.parse::<u16>()?.checked_sub(1).map(usize::from);
let name = parse_symbol_name(&mut buf, kind)?;
let symbol = AnnotationReferenceSymbol {
sum_name,
symbol_index,
module,
name,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TokenReferenceSymbol<'t> {
pub sum_name: u32,
pub symbol_index: SymbolIndex,
pub module: Option<usize>,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for TokenReferenceSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let sum_name = buf.parse()?;
let symbol_index = buf.parse()?;
let module = buf.parse::<u16>()?.checked_sub(1).map(usize::from);
let name = parse_symbol_name(&mut buf, kind)?;
let symbol = TokenReferenceSymbol {
sum_name,
symbol_index,
module,
name,
};
Ok((symbol, buf.pos()))
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TrampolineType {
Incremental,
BranchIsland,
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct TrampolineSymbol {
pub tramp_type: TrampolineType,
pub size: u16,
pub thunk: PdbInternalSectionOffset,
pub target: PdbInternalSectionOffset,
}
impl TryFromCtx<'_, SymbolKind> for TrampolineSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let tramp_type = match buf.parse::<u16>()? {
0x00 => TrampolineType::Incremental,
0x01 => TrampolineType::BranchIsland,
_ => TrampolineType::Unknown,
};
let size = buf.parse()?;
let thunk_offset = buf.parse()?;
let target_offset = buf.parse()?;
let thunk_section = buf.parse()?;
let target_section = buf.parse()?;
let symbol = Self {
tramp_type,
size,
thunk: PdbInternalSectionOffset::new(thunk_section, thunk_offset),
target: PdbInternalSectionOffset::new(target_section, target_offset),
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ConstantSymbol<'t> {
pub managed: bool,
pub type_index: TypeIndex,
pub value: Variant,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ConstantSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ConstantSymbol {
managed: kind == S_MANCONSTANT,
type_index: buf.parse()?,
value: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UserDefinedTypeSymbol<'t> {
pub type_index: TypeIndex,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for UserDefinedTypeSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = UserDefinedTypeSymbol {
type_index: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ThreadStorageSymbol<'t> {
pub global: bool,
pub type_index: TypeIndex,
pub offset: PdbInternalSectionOffset,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ThreadStorageSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ThreadStorageSymbol {
global: matches!(kind, S_GTHREAD32 | S_GTHREAD32_ST),
type_index: buf.parse()?,
offset: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
const CV_PFLAG_NOFPO: u8 = 0x01;
const CV_PFLAG_INT: u8 = 0x02;
const CV_PFLAG_FAR: u8 = 0x04;
const CV_PFLAG_NEVER: u8 = 0x08;
const CV_PFLAG_NOTREACHED: u8 = 0x10;
const CV_PFLAG_CUST_CALL: u8 = 0x20;
const CV_PFLAG_NOINLINE: u8 = 0x40;
const CV_PFLAG_OPTDBGINFO: u8 = 0x80;
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProcedureFlags {
pub nofpo: bool,
pub int: bool,
pub far: bool,
pub never: bool,
pub notreached: bool,
pub cust_call: bool,
pub noinline: bool,
pub optdbginfo: bool,
}
impl<'t> TryFromCtx<'t, Endian> for ProcedureFlags {
type Error = scroll::Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
let (value, size) = u8::try_from_ctx(this, le)?;
let flags = Self {
nofpo: value & CV_PFLAG_NOFPO != 0,
int: value & CV_PFLAG_INT != 0,
far: value & CV_PFLAG_FAR != 0,
never: value & CV_PFLAG_NEVER != 0,
notreached: value & CV_PFLAG_NOTREACHED != 0,
cust_call: value & CV_PFLAG_CUST_CALL != 0,
noinline: value & CV_PFLAG_NOINLINE != 0,
optdbginfo: value & CV_PFLAG_OPTDBGINFO != 0,
};
Ok((flags, size))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ProcedureSymbol<'t> {
pub global: bool,
pub dpc: bool,
pub parent: Option<SymbolIndex>,
pub end: SymbolIndex,
pub next: Option<SymbolIndex>,
pub len: u32,
pub dbg_start_offset: u32,
pub dbg_end_offset: u32,
pub type_index: TypeIndex,
pub offset: PdbInternalSectionOffset,
pub flags: ProcedureFlags,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ProcedureSymbol {
global: matches!(kind, S_GPROC32 | S_GPROC32_ST | S_GPROC32_ID),
dpc: matches!(kind, S_LPROC32_DPC | S_LPROC32_DPC_ID),
parent: parse_optional_index(&mut buf)?,
end: buf.parse()?,
next: parse_optional_index(&mut buf)?,
len: buf.parse()?,
dbg_start_offset: buf.parse()?,
dbg_end_offset: buf.parse()?,
type_index: buf.parse()?,
offset: buf.parse()?,
flags: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ManagedProcedureSymbol<'t> {
pub global: bool,
pub parent: Option<SymbolIndex>,
pub end: SymbolIndex,
pub next: Option<SymbolIndex>,
pub len: u32,
pub dbg_start_offset: u32,
pub dbg_end_offset: u32,
pub token: COMToken,
pub offset: PdbInternalSectionOffset,
pub flags: ProcedureFlags,
pub return_register: u16,
pub name: Option<RawString<'t>>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ManagedProcedureSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ManagedProcedureSymbol {
global: matches!(kind, S_GMANPROC),
parent: parse_optional_index(&mut buf)?,
end: buf.parse()?,
next: parse_optional_index(&mut buf)?,
len: buf.parse()?,
dbg_start_offset: buf.parse()?,
dbg_end_offset: buf.parse()?,
token: buf.parse()?,
offset: buf.parse()?,
flags: buf.parse()?,
return_register: buf.parse()?,
name: parse_optional_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct InlineSiteSymbol<'t> {
pub parent: Option<SymbolIndex>,
pub end: SymbolIndex,
pub inlinee: IdIndex,
pub invocations: Option<u32>,
pub annotations: BinaryAnnotations<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for InlineSiteSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = InlineSiteSymbol {
parent: parse_optional_index(&mut buf)?,
end: buf.parse()?,
inlinee: buf.parse()?,
invocations: match kind {
S_INLINESITE2 => Some(buf.parse()?),
_ => None,
},
annotations: BinaryAnnotations::new(buf.take(buf.len())?),
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BuildInfoSymbol {
pub id: IdIndex,
}
impl<'t> TryFromCtx<'t, SymbolKind> for BuildInfoSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = Self { id: buf.parse()? };
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ObjNameSymbol<'t> {
pub signature: u32,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ObjNameSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ObjNameSymbol {
signature: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CompilerVersion {
pub major: u16,
pub minor: u16,
pub build: u16,
pub qfe: Option<u16>,
}
impl<'t> TryFromCtx<'t, bool> for CompilerVersion {
type Error = Error;
fn try_from_ctx(this: &'t [u8], has_qfe: bool) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let version = Self {
major: buf.parse()?,
minor: buf.parse()?,
build: buf.parse()?,
qfe: if has_qfe { Some(buf.parse()?) } else { None },
};
Ok((version, buf.pos()))
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CompileFlags {
pub edit_and_continue: bool,
pub no_debug_info: bool,
pub link_time_codegen: bool,
pub no_data_align: bool,
pub managed: bool,
pub security_checks: bool,
pub hot_patch: bool,
pub cvtcil: bool,
pub msil_module: bool,
pub sdl: bool,
pub pgo: bool,
pub exp_module: bool,
}
impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlags {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let is_compile3 = kind == S_COMPILE3;
let raw = this.pread_with::<u16>(0, LE)?;
this.pread::<u8>(2)?;
let flags = Self {
edit_and_continue: raw & 1 != 0,
no_debug_info: (raw >> 1) & 1 != 0,
link_time_codegen: (raw >> 2) & 1 != 0,
no_data_align: (raw >> 3) & 1 != 0,
managed: (raw >> 4) & 1 != 0,
security_checks: (raw >> 5) & 1 != 0,
hot_patch: (raw >> 6) & 1 != 0,
cvtcil: (raw >> 7) & 1 != 0,
msil_module: (raw >> 8) & 1 != 0,
sdl: (raw >> 9) & 1 != 0 && is_compile3,
pgo: (raw >> 10) & 1 != 0 && is_compile3,
exp_module: (raw >> 11) & 1 != 0 && is_compile3,
};
Ok((flags, 3))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CompileFlagsSymbol<'t> {
pub language: SourceLanguage,
pub flags: CompileFlags,
pub cpu_type: CPUType,
pub frontend_version: CompilerVersion,
pub backend_version: CompilerVersion,
pub version_string: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlagsSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let has_qfe = kind == S_COMPILE3;
let symbol = CompileFlagsSymbol {
language: buf.parse()?,
flags: buf.parse_with(kind)?,
cpu_type: buf.parse()?,
frontend_version: buf.parse_with(has_qfe)?,
backend_version: buf.parse_with(has_qfe)?,
version_string: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UsingNamespaceSymbol<'t> {
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for UsingNamespaceSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = UsingNamespaceSymbol {
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
const CV_LVARFLAG_ISPARAM: u16 = 0x01;
const CV_LVARFLAG_ADDRTAKEN: u16 = 0x02;
const CV_LVARFLAG_COMPGENX: u16 = 0x04;
const CV_LVARFLAG_ISAGGREGATE: u16 = 0x08;
const CV_LVARFLAG_ISALIASED: u16 = 0x10;
const CV_LVARFLAG_ISALIAS: u16 = 0x20;
const CV_LVARFLAG_ISRETVALUE: u16 = 0x40;
const CV_LVARFLAG_ISOPTIMIZEDOUT: u16 = 0x80;
const CV_LVARFLAG_ISENREG_GLOB: u16 = 0x100;
const CV_LVARFLAG_ISENREG_STAT: u16 = 0x200;
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LocalVariableFlags {
pub isparam: bool,
pub addrtaken: bool,
pub compgenx: bool,
pub isaggregate: bool,
pub isaliased: bool,
pub isalias: bool,
pub isretvalue: bool,
pub isoptimizedout: bool,
pub isenreg_glob: bool,
pub isenreg_stat: bool,
}
impl<'t> TryFromCtx<'t, Endian> for LocalVariableFlags {
type Error = scroll::Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
let (value, size) = u16::try_from_ctx(this, le)?;
let flags = Self {
isparam: value & CV_LVARFLAG_ISPARAM != 0,
addrtaken: value & CV_LVARFLAG_ADDRTAKEN != 0,
compgenx: value & CV_LVARFLAG_COMPGENX != 0,
isaggregate: value & CV_LVARFLAG_ISAGGREGATE != 0,
isaliased: value & CV_LVARFLAG_ISALIASED != 0,
isalias: value & CV_LVARFLAG_ISALIAS != 0,
isretvalue: value & CV_LVARFLAG_ISRETVALUE != 0,
isoptimizedout: value & CV_LVARFLAG_ISOPTIMIZEDOUT != 0,
isenreg_glob: value & CV_LVARFLAG_ISENREG_GLOB != 0,
isenreg_stat: value & CV_LVARFLAG_ISENREG_STAT != 0,
};
Ok((flags, size))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LocalSymbol<'t> {
pub type_index: TypeIndex,
pub flags: LocalVariableFlags,
pub name: RawString<'t>,
pub slot: Option<i32>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for LocalSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let type_index: TypeIndex = buf.parse()?;
let flags: LocalVariableFlags = buf.parse()?;
let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?;
let slot: Option<i32> = if (this.len() as i64 - name.len() as i64 - 8i64) >= 6 {
if this[name.len() + 0xb] == 0x24 {
Some(ParseBuffer::from(&this[(name.len() + 0xc)..]).parse()?)
} else {
None
}
} else {
None
};
Ok((
Self {
type_index,
flags,
name,
slot,
},
buf.pos(),
))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ManagedSlotSymbol<'t> {
pub slot: u32,
pub type_index: TypeIndex,
pub offset: PdbInternalSectionOffset,
pub flags: LocalVariableFlags,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ManagedSlotSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ManagedSlotSymbol {
slot: buf.parse()?,
type_index: buf.parse()?,
offset: buf.parse()?,
flags: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AddressRange {
pub offset: PdbInternalSectionOffset,
pub cb_range: u16,
}
impl<'t> TryFromCtx<'t, Endian> for AddressRange {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _le: Endian) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let range = Self {
offset: buf.parse()?,
cb_range: buf.parse()?,
};
Ok((range, buf.pos()))
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExportSymbolFlags {
pub constant: bool,
pub data: bool,
pub private: bool,
pub no_name: bool,
pub ordinal: bool,
pub forwarder: bool,
}
impl<'t> TryFromCtx<'t, Endian> for ExportSymbolFlags {
type Error = scroll::Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
let (value, size) = u16::try_from_ctx(this, le)?;
let flags = Self {
constant: value & 0x01 != 0,
data: value & 0x02 != 0,
private: value & 0x04 != 0,
no_name: value & 0x08 != 0,
ordinal: value & 0x10 != 0,
forwarder: value & 0x20 != 0,
};
Ok((flags, size))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ExportSymbol<'t> {
pub ordinal: u16,
pub flags: ExportSymbolFlags,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ExportSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = ExportSymbol {
ordinal: buf.parse()?,
flags: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LabelSymbol<'t> {
pub offset: PdbInternalSectionOffset,
pub flags: ProcedureFlags,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for LabelSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = LabelSymbol {
offset: buf.parse()?,
flags: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct BlockSymbol<'t> {
pub parent: SymbolIndex,
pub end: SymbolIndex,
pub len: u32,
pub offset: PdbInternalSectionOffset,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for BlockSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = BlockSymbol {
parent: buf.parse()?,
end: buf.parse()?,
len: buf.parse()?,
offset: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RegisterRelativeSymbol<'t> {
pub offset: i32,
pub type_index: TypeIndex,
pub register: Register,
pub name: RawString<'t>,
pub slot: Option<i32>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for RegisterRelativeSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset: i32 = buf.parse()?;
let type_index: TypeIndex = buf.parse()?;
let register: Register = buf.parse()?;
let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?;
let slot: Option<i32> = if (this.len() as i64 - name.len() as i64 - 0xci64) >= 6 {
if this[name.len() + 0xf] == 0x24 {
Some(ParseBuffer::from(&this[(name.len() + 0x10)..]).parse()?)
} else {
None
}
} else {
None
};
Ok((
Self {
offset,
type_index,
register,
name,
slot,
},
buf.pos(),
))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ThunkAdjustor<'t> {
pub delta: u16,
pub target: RawString<'t>,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ThunkKind<'t> {
NoType,
Adjustor(ThunkAdjustor<'t>),
VCall(u16),
PCode,
Load,
Unknown(u8),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ThunkSymbol<'t> {
pub parent: Option<SymbolIndex>,
pub end: SymbolIndex,
pub next: Option<SymbolIndex>,
pub offset: PdbInternalSectionOffset,
pub len: u16,
pub kind: ThunkKind<'t>,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ThunkSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let parent = parse_optional_index(&mut buf)?;
let end = buf.parse()?;
let next = parse_optional_index(&mut buf)?;
let offset = buf.parse()?;
let len = buf.parse()?;
let ord = buf.parse::<u8>()?;
let name = parse_symbol_name(&mut buf, kind)?;
let kind = match ord {
0 => ThunkKind::NoType,
1 => ThunkKind::Adjustor(ThunkAdjustor {
delta: buf.parse::<u16>()?,
target: buf.parse_cstring()?,
}),
2 => ThunkKind::VCall(buf.parse::<u16>()?),
3 => ThunkKind::PCode,
4 => ThunkKind::Load,
ord => ThunkKind::Unknown(ord),
};
let symbol = ThunkSymbol {
parent,
end,
next,
offset,
len,
kind,
name,
};
Ok((symbol, buf.pos()))
}
}
const CV_SEPCODEFLAG_IS_LEXICAL_SCOPE: u32 = 0x01;
const CV_SEPCODEFLAG_RETURNS_TO_PARENT: u32 = 0x02;
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SeparatedCodeFlags {
pub islexicalscope: bool,
pub returnstoparent: bool,
}
impl<'t> TryFromCtx<'t, Endian> for SeparatedCodeFlags {
type Error = scroll::Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
let (value, size) = u32::try_from_ctx(this, le)?;
let flags = Self {
islexicalscope: value & CV_SEPCODEFLAG_IS_LEXICAL_SCOPE != 0,
returnstoparent: value & CV_SEPCODEFLAG_RETURNS_TO_PARENT != 0,
};
Ok((flags, size))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SeparatedCodeSymbol {
pub parent: SymbolIndex,
pub end: SymbolIndex,
pub len: u32,
pub flags: SeparatedCodeFlags,
pub offset: PdbInternalSectionOffset,
pub parent_offset: PdbInternalSectionOffset,
}
impl<'t> TryFromCtx<'t, SymbolKind> for SeparatedCodeSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let parent = buf.parse()?;
let end = buf.parse()?;
let len = buf.parse()?;
let flags = buf.parse()?;
let offset = buf.parse()?;
let parent_offset = buf.parse()?;
let section = buf.parse()?;
let parent_section = buf.parse()?;
let symbol = Self {
parent,
end,
len,
flags,
offset: PdbInternalSectionOffset { offset, section },
parent_offset: PdbInternalSectionOffset {
offset: parent_offset,
section: parent_section,
},
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OemSymbol<'t> {
pub id_oem: RawString<'t>,
pub type_index: TypeIndex,
pub rgl: u32,
}
impl<'t> TryFromCtx<'t, SymbolKind> for OemSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = OemSymbol {
id_oem: buf.parse_cstring()?,
type_index: buf.parse()?,
rgl: buf.parse()?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EnvBlockSymbol<'t> {
pub edit_and_continue: bool,
pub rgsz: Vec<RawString<'t>>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for EnvBlockSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let flags: u8 = buf.parse()?;
let mut strings: Vec<RawString<'t>> = Vec::new();
while !buf.is_empty() {
strings.push(parse_symbol_name(&mut buf, kind)?);
}
let symbol = EnvBlockSymbol {
edit_and_continue: flags & 1 != 0,
rgsz: strings,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SectionSymbol<'t> {
pub isec: u16,
pub align: u8,
pub reserved: u8,
pub rva: u32,
pub cb: u32,
pub characteristics: SectionCharacteristics,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for SectionSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = SectionSymbol {
isec: buf.parse()?,
align: buf.parse()?,
reserved: buf.parse()?,
rva: buf.parse()?,
cb: buf.parse()?,
characteristics: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CoffGroupSymbol<'t> {
pub cb: u32,
pub characteristics: u32,
pub offset: PdbInternalSectionOffset,
pub name: RawString<'t>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for CoffGroupSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = CoffGroupSymbol {
cb: buf.parse()?,
characteristics: buf.parse()?,
offset: buf.parse()?,
name: parse_symbol_name(&mut buf, kind)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AddressGap {
pub gap_start_offset: u16,
pub cb_range: u16,
}
impl<'t> TryFromCtx<'t, Endian> for AddressGap {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _: Endian) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let range = Self {
gap_start_offset: buf.parse()?,
cb_range: buf.parse()?,
};
Ok((range, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeSymbol {
pub program: u32,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 16
) / 4 ;
let mut symbol = Self {
program: buf.parse()?,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeSubFieldSymbol {
pub program: u32,
pub parent_offset: u32,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeSubFieldSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 20
) / 4 ;
let mut symbol = Self {
program: buf.parse()?,
parent_offset: buf.parse()?,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RangeFlags {
pub maybe: bool,
}
impl<'t> TryFromCtx<'t, Endian> for RangeFlags {
type Error = Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> std::result::Result<(Self, usize), Self::Error> {
let (value, size) = u16::try_from_ctx(this, le)?;
let flags = Self {
maybe: value & 0x01 != 0,
};
Ok((flags, size))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeRegisterSymbol {
pub register: Register,
pub flags: RangeFlags,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeRegisterSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 16
) / 4 ;
let mut symbol = Self {
register: buf.parse()?,
flags: buf.parse()?,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeFramePointerRelativeSymbol {
pub offset: i32,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeFramePointerRelativeSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 16
) / 4 ;
let mut symbol = Self {
offset: buf.parse()?,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct DefRangeFramePointerRelativeFullScopeSymbol {
pub offset: i32,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeFramePointerRelativeFullScopeSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = Self {
offset: buf.parse()?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeSubFieldRegisterSymbol {
pub register: Register,
pub flags: RangeFlags,
pub offset: u32,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeSubFieldRegisterSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 20
) / 4 ;
let register: Register = buf.parse()?;
let flags: RangeFlags = buf.parse()?;
let offset_padding: u32 = buf.parse()?;
let offset = offset_padding & 0xFFFu32;
let mut symbol = Self {
register,
flags,
offset,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DefRangeRegisterRelativeSymbol {
pub base_register: Register,
pub spilled_udt_member: u16,
pub offset_parent: u16,
pub offset_base_pointer: i32,
pub range: AddressRange,
pub gaps: Vec<AddressGap>,
}
impl TryFromCtx<'_, SymbolKind> for DefRangeRegisterRelativeSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let gap_count = (
buf.len() + 4
- 20
) / 4 ;
let base_register: Register = buf.parse()?;
let bitfield: u16 = buf.parse()?;
let spilled_udt_member = bitfield & 0x1;
let offset_parent = (bitfield >> 4) & 0xFFF;
let mut symbol = Self {
base_register,
spilled_udt_member,
offset_parent,
offset_base_pointer: buf.parse()?,
range: buf.parse()?,
gaps: vec![],
};
for _ in 0..gap_count {
symbol.gaps.push(buf.parse()?);
}
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BasePointerRelativeSymbol<'t> {
pub offset: i32,
pub type_index: TypeIndex,
pub name: RawString<'t>,
pub slot: Option<i32>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for BasePointerRelativeSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset: i32 = buf.parse()?;
let type_index = match kind {
S_BPREL32 | S_BPREL32_ST => buf.parse()?,
S_BPREL32_16T => TypeIndex::from(buf.parse::<u16>()? as u32),
_ => return Err(Error::UnimplementedSymbolKind(kind)),
};
let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?;
let slot: Option<i32> = if (this.len() as i64 - name.len() as i64 - 0xai64) >= 6 {
if this[name.len() + 0xd] == 0x24 {
Some(ParseBuffer::from(&this[(name.len() + 0xe)..]).parse()?)
} else {
None
}
} else {
None
};
Ok((
Self {
offset,
type_index,
name,
slot,
},
buf.pos(),
))
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FrameProcedureFlags {
pub has_alloca: bool,
pub has_setjmp: bool,
pub has_longjmp: bool,
pub has_inline_asm: bool,
pub has_eh: bool,
pub inline_spec: bool,
pub has_seh: bool,
pub naked: bool,
pub security_checks: bool,
pub async_eh: bool,
pub gs_no_stack_ordering: bool,
pub was_inlined: bool,
pub gs_check: bool,
pub safe_buffers: bool,
pub encoded_local_base_pointer: u8,
pub encoded_param_base_pointer: u8,
pub pogo_on: bool,
pub valid_counts: bool,
pub opt_speed: bool,
pub guard_cf: bool,
pub guard_cfw: bool,
}
impl<'t> TryFromCtx<'t, Endian> for FrameProcedureFlags {
type Error = Error;
fn try_from_ctx(this: &'t [u8], le: Endian) -> Result<(Self, usize)> {
let raw = this.pread_with::<u32>(0, le)?;
let flags = Self {
has_alloca: raw & 1 != 0,
has_setjmp: (raw >> 1) & 1 != 0,
has_longjmp: (raw >> 2) & 1 != 0,
has_inline_asm: (raw >> 3) & 1 != 0,
has_eh: (raw >> 4) & 1 != 0,
inline_spec: (raw >> 5) & 1 != 0,
has_seh: (raw >> 6) & 1 != 0,
naked: (raw >> 7) & 1 != 0,
security_checks: (raw >> 8) & 1 != 0,
async_eh: (raw >> 9) & 1 != 0,
gs_no_stack_ordering: (raw >> 10) & 1 != 0,
was_inlined: (raw >> 11) & 1 != 0,
gs_check: (raw >> 12) & 1 != 0,
safe_buffers: (raw >> 13) & 1 != 0,
encoded_local_base_pointer: (raw >> 14) as u8 & 3,
encoded_param_base_pointer: (raw >> 16) as u8 & 3,
pogo_on: (raw >> 18) & 1 != 0,
valid_counts: (raw >> 19) & 1 != 0,
opt_speed: (raw >> 20) & 1 != 0,
guard_cf: (raw >> 21) & 1 != 0,
guard_cfw: (raw >> 22) & 1 != 0,
};
Ok((flags, 4))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FrameProcedureSymbol {
pub frame_byte_count: u32,
pub padding_byte_count: u32,
pub offset_padding: u32,
pub callee_save_registers_byte_count: u32,
pub exception_handler_offset: PdbInternalSectionOffset,
pub flags: FrameProcedureFlags,
}
impl TryFromCtx<'_, SymbolKind> for FrameProcedureSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let symbol = FrameProcedureSymbol {
frame_byte_count: buf.parse()?,
padding_byte_count: buf.parse()?,
offset_padding: buf.parse()?,
callee_save_registers_byte_count: buf.parse()?,
exception_handler_offset: buf.parse()?,
flags: buf.parse_with(LE)?,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CallSiteInfoSymbol {
pub offset: PdbInternalSectionOffset,
pub type_index: TypeIndex,
}
impl TryFromCtx<'_, SymbolKind> for CallSiteInfoSymbol {
type Error = Error;
fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset: PdbInternalSectionOffset = buf.parse()?;
let _padding = buf.parse::<u16>()?;
let type_index: TypeIndex = buf.parse()?;
let symbol = Self { offset, type_index };
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FunctionListSymbol {
pub functions: Vec<TypeIndex>,
pub invocations: Vec<u32>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for FunctionListSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let count: u32 = buf.parse()?;
let functions = vec![buf.parse()?; count as usize];
let mut invocations = Vec::new();
while !buf.is_empty() {
invocations.push(buf.parse()?);
}
debug_assert!(invocations.len() <= functions.len());
invocations.resize(functions.len(), 0);
let symbol = FunctionListSymbol {
functions,
invocations,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InlineesSymbol {
pub inlinees: Vec<TypeIndex>,
}
impl<'t> TryFromCtx<'t, SymbolKind> for InlineesSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let count = buf.parse::<u32>()?;
let mut inlinees = Vec::new();
while !buf.is_empty() {
inlinees.push(buf.parse()?);
}
debug_assert_eq!(inlinees.len(), count as usize);
let symbol = InlineesSymbol { inlinees };
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ArmSwitchTableSymbol {
pub offset_base: PdbInternalSectionOffset,
pub switch_type: JumpTableEntrySize,
pub offset_branch: PdbInternalSectionOffset,
pub offset_table: PdbInternalSectionOffset,
pub num_entries: u32,
}
impl<'t> TryFromCtx<'t, SymbolKind> for ArmSwitchTableSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset_base = buf.parse()?;
let switch_type = buf.parse()?;
let off_branch = buf.parse()?;
let off_table = buf.parse()?;
let sec_branch = buf.parse()?;
let sec_table = buf.parse()?;
let num_entries = buf.parse()?;
let symbol = ArmSwitchTableSymbol {
offset_base,
switch_type,
offset_branch: PdbInternalSectionOffset {
offset: off_branch,
section: sec_branch,
},
offset_table: PdbInternalSectionOffset {
offset: off_table,
section: sec_table,
},
num_entries,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(u16)]
pub enum JumpTableEntrySize {
Int8 = 0,
UInt8 = 1,
Int16 = 2,
UInt16 = 3,
Int32 = 4,
UInt32 = 5,
Pointer = 6,
UInt8ShiftLeft = 7,
UInt16ShiftLeft = 8,
Int8ShiftLeft = 9,
Int16ShiftLeft = 10,
Invalid = 0xffff,
}
impl<'t> TryFromCtx<'t, Endian> for JumpTableEntrySize {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _unused: Endian) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let value = buf.parse::<u16>()?;
let size = match value {
0 => Self::Int8,
1 => Self::UInt8,
2 => Self::Int16,
3 => Self::UInt16,
4 => Self::Int32,
5 => Self::UInt32,
6 => Self::Pointer,
7 => Self::UInt8ShiftLeft,
8 => Self::UInt16ShiftLeft,
9 => Self::Int8ShiftLeft,
10 => Self::Int16ShiftLeft,
_ => Self::Invalid,
};
Ok((size, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HeapAllocationSiteSymbol {
pub offset: PdbInternalSectionOffset,
pub instr_length: u16,
pub type_index: TypeIndex,
}
impl<'t> TryFromCtx<'t, SymbolKind> for HeapAllocationSiteSymbol {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset = buf.parse()?;
let instr_length = buf.parse()?;
let type_index = buf.parse()?;
let symbol = HeapAllocationSiteSymbol {
offset,
instr_length,
type_index,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FrameCookieSymbol {
pub offset: i32,
pub register: Register,
pub cookie_type: FrameCookieType,
pub flags: u8, }
impl TryFromCtx<'_, SymbolKind> for FrameCookieSymbol {
type Error = Error;
fn try_from_ctx(this: &[u8], _kind: SymbolKind) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let offset = buf.parse()?;
let register = buf.parse()?;
let cookie_type = buf.parse()?;
let flags = buf.parse()?;
let symbol = FrameCookieSymbol {
offset,
register,
cookie_type,
flags,
};
Ok((symbol, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum FrameCookieType {
Copy = 0,
XorStackPointer = 1,
XorBasePointer = 2,
XorR13 = 3,
Invalid(u8),
}
impl<'t> TryFromCtx<'t, Endian> for FrameCookieType {
type Error = Error;
fn try_from_ctx(this: &'t [u8], _le: Endian) -> Result<(Self, usize)> {
let mut buf = ParseBuffer::from(this);
let value = buf.parse::<u8>()?;
let cookie_type = match value {
0 => Self::Copy,
1 => Self::XorStackPointer,
2 => Self::XorBasePointer,
3 => Self::XorR13,
_ => Self::Invalid(value),
};
Ok((cookie_type, buf.pos()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FileStaticSymbol<'b> {
pub type_index: TypeIndex,
pub module_filename_ref: StringRef,
pub flags: LocalVariableFlags,
pub name: RawString<'b>
}
impl<'t> TryFromCtx<'t, SymbolKind> for FileStaticSymbol<'t> {
type Error = Error;
fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> std::result::Result<(Self, usize), Self::Error> {
let mut buf = ParseBuffer::from(this);
let type_index = buf.parse()?;
let module_filename_ref = buf.parse()?;
let flags = buf.parse()?;
let name = parse_symbol_name(&mut buf, kind)?;
let result = FileStaticSymbol {
type_index,
module_filename_ref,
flags,
name,
};
Ok((result, buf.pos()))
}
}
#[derive(Debug)]
pub struct SymbolTable<'s> {
stream: Stream<'s>,
}
impl<'s> SymbolTable<'s> {
#[must_use]
pub(crate) fn new(stream: Stream<'s>) -> Self {
SymbolTable { stream }
}
#[must_use]
pub fn iter(&self) -> SymbolIter<'_> {
SymbolIter::new(self.stream.parse_buffer())
}
#[must_use]
pub fn iter_at(&self, index: SymbolIndex) -> SymbolIter<'_> {
let mut iter = self.iter();
iter.seek(index);
iter
}
}
#[derive(Debug)]
pub struct SymbolIter<'t> {
buf: ParseBuffer<'t>,
}
impl<'t> SymbolIter<'t> {
pub(crate) fn new(buf: ParseBuffer<'t>) -> SymbolIter<'t> {
SymbolIter { buf }
}
pub fn seek(&mut self, index: SymbolIndex) {
self.buf.seek(index.0 as usize);
}
pub fn skip_to(&mut self, index: SymbolIndex) -> Result<Option<Symbol<'t>>> {
self.seek(index);
self.next()
}
}
impl<'t> FallibleIterator for SymbolIter<'t> {
type Item = Symbol<'t>;
type Error = Error;
fn next(&mut self) -> Result<Option<Self::Item>> {
while !self.buf.is_empty() {
let index = SymbolIndex(self.buf.pos() as u32);
let symbol_length = self.buf.parse::<u16>()? as usize;
if symbol_length < 2 {
return Err(Error::SymbolTooShort);
}
let data = self.buf.take(symbol_length)?;
let symbol = Symbol { index, data };
match symbol.raw_kind() {
S_ALIGN | S_SKIP => continue,
_ => return Ok(Some(symbol)),
}
}
Ok(None)
}
}
#[cfg(test)]
mod tests {
mod parsing {
use crate::symbol::*;
#[test]
fn kind_0006() {
let data = &[6, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x0006);
assert_eq!(symbol.parse().expect("parse"), SymbolData::ScopeEnd);
}
#[test]
fn kind_1101() {
let data = &[1, 17, 0, 0, 0, 0, 42, 32, 67, 73, 76, 32, 42, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1101);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::ObjName(ObjNameSymbol {
signature: 0,
name: "* CIL *".into(),
})
);
}
#[test]
fn kind_1102() {
let data = &[
2, 17, 0, 0, 0, 0, 108, 22, 0, 0, 0, 0, 0, 0, 140, 11, 0, 0, 1, 0, 9, 0, 3, 91,
116, 104, 117, 110, 107, 93, 58, 68, 101, 114, 105, 118, 101, 100, 58, 58, 70, 117,
110, 99, 49, 96, 97, 100, 106, 117, 115, 116, 111, 114, 123, 56, 125, 39, 0, 0, 0,
0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1102);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Thunk(ThunkSymbol {
parent: None,
end: SymbolIndex(0x166c),
next: None,
offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0xb8c
},
len: 9,
kind: ThunkKind::PCode,
name: "[thunk]:Derived::Func1`adjustor{8}'".into()
})
);
}
#[test]
fn kind_1105() {
let data = &[
5, 17, 224, 95, 151, 0, 1, 0, 0, 100, 97, 118, 49, 100, 95, 119, 95, 97, 118, 103,
95, 115, 115, 115, 101, 51, 0, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1105);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Label(LabelSymbol {
offset: PdbInternalSectionOffset {
offset: 0x0097_5fe0,
section: 1
},
flags: ProcedureFlags {
nofpo: false,
int: false,
far: false,
never: false,
notreached: false,
cust_call: false,
noinline: false,
optdbginfo: false
},
name: "dav1d_w_avg_ssse3".into(),
})
);
}
#[test]
fn kind_1106() {
let data = &[6, 17, 120, 34, 0, 0, 18, 0, 116, 104, 105, 115, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1106);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::RegisterVariable(RegisterVariableSymbol {
type_index: TypeIndex(8824),
register: Register(18),
name: "this".into(),
slot: None,
})
);
}
#[test]
fn kind_110e() {
let data = &[
14, 17, 2, 0, 0, 0, 192, 85, 0, 0, 1, 0, 95, 95, 108, 111, 99, 97, 108, 95, 115,
116, 100, 105, 111, 95, 112, 114, 105, 110, 116, 102, 95, 111, 112, 116, 105, 111,
110, 115, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x110e);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Public(PublicSymbol {
code: false,
function: true,
managed: false,
msil: false,
offset: PdbInternalSectionOffset {
offset: 21952,
section: 1
},
name: "__local_stdio_printf_options".into(),
})
);
}
#[test]
fn kind_1111() {
let data = &[
17, 17, 12, 0, 0, 0, 48, 16, 0, 0, 22, 0, 109, 97, 120, 105, 109, 117, 109, 95, 99,
111, 117, 110, 116, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1111);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::RegisterRelative(RegisterRelativeSymbol {
offset: 12,
type_index: TypeIndex(0x1030),
register: Register(22),
name: "maximum_count".into(),
slot: None,
})
);
}
#[test]
fn kind_1124() {
let data = &[36, 17, 115, 116, 100, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1124);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::UsingNamespace(UsingNamespaceSymbol { name: "std".into() })
);
}
#[test]
fn kind_1125() {
let data = &[
37, 17, 0, 0, 0, 0, 108, 0, 0, 0, 1, 0, 66, 97, 122, 58, 58, 102, 95, 112, 117, 98,
108, 105, 99, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1125);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::ProcedureReference(ProcedureReferenceSymbol {
global: true,
sum_name: 0,
symbol_index: SymbolIndex(108),
module: Some(0),
name: Some("Baz::f_public".into()),
})
);
}
#[test]
fn kind_1108() {
let data = &[8, 17, 112, 6, 0, 0, 118, 97, 95, 108, 105, 115, 116, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1108);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::UserDefinedType(UserDefinedTypeSymbol {
type_index: TypeIndex(1648),
name: "va_list".into(),
})
);
}
#[test]
fn kind_1107() {
let data = &[
7, 17, 201, 18, 0, 0, 1, 0, 95, 95, 73, 83, 65, 95, 65, 86, 65, 73, 76, 65, 66, 76,
69, 95, 83, 83, 69, 50, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1107);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Constant(ConstantSymbol {
managed: false,
type_index: TypeIndex(4809),
value: Variant::U16(1),
name: "__ISA_AVAILABLE_SSE2".into(),
})
);
}
#[test]
fn kind_110d() {
let data = &[
13, 17, 116, 0, 0, 0, 16, 0, 0, 0, 3, 0, 95, 95, 105, 115, 97, 95, 97, 118, 97,
105, 108, 97, 98, 108, 101, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x110d);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Data(DataSymbol {
global: true,
managed: false,
type_index: TypeIndex(116),
offset: PdbInternalSectionOffset {
offset: 16,
section: 3
},
name: "__isa_available".into(),
})
);
}
#[test]
fn kind_110c() {
let data = &[
12, 17, 32, 0, 0, 0, 240, 36, 1, 0, 2, 0, 36, 120, 100, 97, 116, 97, 115, 121, 109,
0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x110c);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Data(DataSymbol {
global: false,
managed: false,
type_index: TypeIndex(32),
offset: PdbInternalSectionOffset {
offset: 74992,
section: 2
},
name: "$xdatasym".into(),
})
);
}
#[test]
fn kind_1127() {
let data = &[
39, 17, 0, 0, 0, 0, 128, 4, 0, 0, 182, 0, 99, 97, 112, 116, 117, 114, 101, 95, 99,
117, 114, 114, 101, 110, 116, 95, 99, 111, 110, 116, 101, 120, 116, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1127);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::ProcedureReference(ProcedureReferenceSymbol {
global: false,
sum_name: 0,
symbol_index: SymbolIndex(1152),
module: Some(181),
name: Some("capture_current_context".into()),
})
);
}
#[test]
fn kind_112c() {
let data = &[44, 17, 0, 0, 5, 0, 5, 0, 0, 0, 32, 124, 0, 0, 2, 0, 2, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x112c);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Trampoline(TrampolineSymbol {
tramp_type: TrampolineType::Incremental,
size: 0x5,
thunk: PdbInternalSectionOffset {
offset: 0x5,
section: 0x2
},
target: PdbInternalSectionOffset {
offset: 0x7c20,
section: 0x2
},
})
);
}
#[test]
fn kind_1110() {
let data = &[
16, 17, 0, 0, 0, 0, 48, 2, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 7,
16, 0, 0, 64, 85, 0, 0, 1, 0, 0, 66, 97, 122, 58, 58, 102, 95, 112, 114, 111, 116,
101, 99, 116, 101, 100, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1110);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Procedure(ProcedureSymbol {
global: true,
dpc: false,
parent: None,
end: SymbolIndex(560),
next: None,
len: 6,
dbg_start_offset: 5,
dbg_end_offset: 5,
type_index: TypeIndex(4103),
offset: PdbInternalSectionOffset {
offset: 21824,
section: 1
},
flags: ProcedureFlags {
nofpo: false,
int: false,
far: false,
never: false,
notreached: false,
cust_call: false,
noinline: false,
optdbginfo: false
},
name: "Baz::f_protected".into(),
})
);
}
#[test]
fn kind_1103() {
let data = &[
3, 17, 244, 149, 9, 0, 40, 151, 9, 0, 135, 1, 0, 0, 108, 191, 184, 2, 1, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1103);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Block(BlockSymbol {
parent: SymbolIndex(0x0009_95f4),
end: SymbolIndex(0x0009_9728),
len: 391,
offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0x02b8_bf6c
},
name: "".into(),
})
);
}
#[test]
fn kind_110f() {
let data = &[
15, 17, 0, 0, 0, 0, 156, 1, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0,
128, 16, 0, 0, 196, 87, 0, 0, 1, 0, 128, 95, 95, 115, 99, 114, 116, 95, 99, 111,
109, 109, 111, 110, 95, 109, 97, 105, 110, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x110f);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Procedure(ProcedureSymbol {
global: false,
dpc: false,
parent: None,
end: SymbolIndex(412),
next: None,
len: 18,
dbg_start_offset: 4,
dbg_end_offset: 9,
type_index: TypeIndex(4224),
offset: PdbInternalSectionOffset {
offset: 22468,
section: 1
},
flags: ProcedureFlags {
nofpo: false,
int: false,
far: false,
never: false,
notreached: false,
cust_call: false,
noinline: false,
optdbginfo: true
},
name: "__scrt_common_main".into(),
})
);
}
#[test]
fn kind_1116() {
let data = &[
22, 17, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 14, 0, 10, 0, 115, 98, 77, 105, 99,
114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 76, 73, 78, 75, 0, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1116);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::CompileFlags(CompileFlagsSymbol {
language: SourceLanguage::Link,
flags: CompileFlags {
edit_and_continue: false,
no_debug_info: false,
link_time_codegen: false,
no_data_align: false,
managed: false,
security_checks: false,
hot_patch: false,
cvtcil: false,
msil_module: false,
sdl: false,
pgo: false,
exp_module: false,
},
cpu_type: CPUType::Intel80386,
frontend_version: CompilerVersion {
major: 0,
minor: 0,
build: 0,
qfe: None,
},
backend_version: CompilerVersion {
major: 14,
minor: 10,
build: 25203,
qfe: None,
},
version_string: "Microsoft (R) LINK".into(),
})
);
}
#[test]
fn kind_1132() {
let data = &[
50, 17, 0, 0, 0, 0, 108, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 196, 252, 10, 0, 56, 67,
0, 0, 1, 0, 1, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1132);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::SeparatedCode(SeparatedCodeSymbol {
parent: SymbolIndex(0x0),
end: SymbolIndex(0x6c),
len: 88,
flags: SeparatedCodeFlags {
islexicalscope: false,
returnstoparent: false
},
offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0xafcc4
},
parent_offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0x4338
}
})
);
}
#[test]
fn kind_1137() {
let data = &[
55, 17, 160, 17, 0, 0, 64, 0, 0, 192, 0, 0, 0, 0, 3, 0, 46, 100, 97, 116, 97, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1137);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::CoffGroup(CoffGroupSymbol {
cb: 4512,
characteristics: 0xc000_0040,
offset: PdbInternalSectionOffset {
section: 0x3,
offset: 0
},
name: ".data".into(),
})
);
}
#[test]
fn kind_1139() {
let data = &[57, 17, 134, 123, 8, 0, 1, 0, 0, 0, 17, 91, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1139);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::CallSiteInfo(CallSiteInfoSymbol {
offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0x87b86
},
type_index: TypeIndex(0x5b11)
})
);
}
#[test]
fn kind_113a() {
let data = &[58, 17, 32, 2, 0, 0, 79, 1, 1, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x113a);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::FrameCookie(FrameCookieSymbol {
offset: 544,
register: Register(335),
cookie_type: FrameCookieType::XorStackPointer,
flags: 0,
})
);
}
#[test]
fn kind_113c() {
let data = &[
60, 17, 1, 36, 2, 0, 7, 0, 19, 0, 13, 0, 6, 102, 0, 0, 19, 0, 13, 0, 6, 102, 0, 0,
77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 79, 112, 116, 105,
109, 105, 122, 105, 110, 103, 32, 67, 111, 109, 112, 105, 108, 101, 114, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x113c);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::CompileFlags(CompileFlagsSymbol {
language: SourceLanguage::Cpp,
flags: CompileFlags {
edit_and_continue: false,
no_debug_info: false,
link_time_codegen: true,
no_data_align: false,
managed: false,
security_checks: true,
hot_patch: false,
cvtcil: false,
msil_module: false,
sdl: true,
pgo: false,
exp_module: false,
},
cpu_type: CPUType::Pentium3,
frontend_version: CompilerVersion {
major: 19,
minor: 13,
build: 26118,
qfe: Some(0),
},
backend_version: CompilerVersion {
major: 19,
minor: 13,
build: 26118,
qfe: Some(0),
},
version_string: "Microsoft (R) Optimizing Compiler".into(),
})
);
}
#[test]
fn kind_113e() {
let data = &[62, 17, 193, 19, 0, 0, 1, 0, 116, 104, 105, 115, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x113e);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Local(LocalSymbol {
type_index: TypeIndex(5057),
flags: LocalVariableFlags {
isparam: true,
addrtaken: false,
compgenx: false,
isaggregate: false,
isaliased: false,
isalias: false,
isretvalue: false,
isoptimizedout: false,
isenreg_glob: false,
isenreg_stat: false,
},
name: "this".into(),
slot: None,
})
);
}
#[test]
fn kind_114c() {
let data = &[76, 17, 95, 17, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x114c);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::BuildInfo(BuildInfoSymbol {
id: IdIndex(0x115F)
})
);
}
#[test]
fn kind_114d() {
let data = &[
77, 17, 144, 1, 0, 0, 208, 1, 0, 0, 121, 17, 0, 0, 12, 6, 3, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x114d);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::InlineSite(InlineSiteSymbol {
parent: Some(SymbolIndex(0x0190)),
end: SymbolIndex(0x01d0),
inlinee: IdIndex(4473),
invocations: None,
annotations: BinaryAnnotations::new(&[12, 6, 3, 0]),
})
);
}
#[test]
fn kind_114e() {
let data = &[78, 17];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x114e);
assert_eq!(symbol.parse().expect("parse"), SymbolData::InlineSiteEnd);
}
#[test]
fn kind_1141() {
let data = &[65, 17, 17, 0, 0, 0, 70, 40, 0, 0, 1, 0, 66, 0, 44, 0, 19, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1141);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::DefRangeRegister(DefRangeRegisterSymbol {
register: Register(17),
flags: RangeFlags { maybe: false },
range: AddressRange {
offset: PdbInternalSectionOffset {
offset: 0x2846,
section: 1,
},
cb_range: 0x42,
},
gaps: vec![AddressGap {
gap_start_offset: 0x2c,
cb_range: 0x13
}]
})
);
let data = &[65, 17, 19, 0, 1, 0, 156, 41, 0, 0, 1, 0, 2, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1141);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::DefRangeRegister(DefRangeRegisterSymbol {
register: Register(0x13),
flags: RangeFlags { maybe: true },
range: AddressRange {
offset: PdbInternalSectionOffset {
offset: 0x299c,
section: 1,
},
cb_range: 2,
},
gaps: vec![]
})
);
}
#[test]
fn kind_1012() {
let data = &[
18, 16, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48,
160, 2, 0, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1012);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::FrameProcedure(FrameProcedureSymbol {
frame_byte_count: 152,
padding_byte_count: 0,
offset_padding: 0,
callee_save_registers_byte_count: 0,
exception_handler_offset: PdbInternalSectionOffset {
section: 0x0,
offset: 0x0
},
flags: FrameProcedureFlags {
has_alloca: false,
has_setjmp: false,
has_longjmp: false,
has_inline_asm: false,
has_eh: true,
inline_spec: true,
has_seh: false,
naked: false,
security_checks: false,
async_eh: false,
gs_no_stack_ordering: false,
was_inlined: false,
gs_check: false,
safe_buffers: true,
encoded_local_base_pointer: 2,
encoded_param_base_pointer: 2,
pogo_on: false,
valid_counts: false,
opt_speed: false,
guard_cf: false,
guard_cfw: false,
},
})
);
}
#[test]
fn kind_115a() {
let data = &[
90, 17, 3, 0, 0, 0, 191, 72, 0, 0, 192, 72, 0, 0, 193, 72, 0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x115a);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Callees(FunctionListSymbol {
functions: vec![TypeIndex(0x48bf), TypeIndex(0x48bf), TypeIndex(0x48bf)],
invocations: vec![18624, 18625, 0]
})
);
}
#[test]
fn kind_1168() {
let data = &[104, 17, 2, 0, 0, 0, 74, 18, 0, 0, 80, 18, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1168);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::Inlinees(InlineesSymbol {
inlinees: vec![TypeIndex(0x124a), TypeIndex(0x1250)]
})
);
}
#[test]
fn kind_1159() {
let data = &[
89, 17, 136, 7, 1, 0, 2, 0, 4, 0, 161, 229, 7, 0, 136, 7, 1, 0, 1, 0, 2, 0, 4, 0,
0, 0,
];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x1159);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::ArmSwitchTable(ArmSwitchTableSymbol {
offset_base: PdbInternalSectionOffset {
section: 2,
offset: 0x10788
},
switch_type: JumpTableEntrySize::Int32,
offset_branch: PdbInternalSectionOffset {
section: 0x1,
offset: 0x7e5a1
},
offset_table: PdbInternalSectionOffset {
section: 2,
offset: 0x10788
},
num_entries: 4,
})
);
}
#[test]
fn kind_115e() {
let data = &[94, 17, 18, 166, 84, 0, 1, 0, 5, 0, 138, 20, 0, 0];
let symbol = Symbol {
data,
index: SymbolIndex(0),
};
assert_eq!(symbol.raw_kind(), 0x115e);
assert_eq!(
symbol.parse().expect("parse"),
SymbolData::HeapAllocationSite(HeapAllocationSiteSymbol {
offset: PdbInternalSectionOffset {
section: 0x1,
offset: 0x54a612
},
type_index: TypeIndex(0x148a),
instr_length: 5,
})
);
}
}
mod iterator {
use crate::symbol::*;
fn create_iter() -> SymbolIter<'static> {
let data = &[
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4e, 0x11, 0x02, 0x00, 0x06, 0x00, ];
let mut buf = ParseBuffer::from(&data[..]);
buf.seek(4); SymbolIter::new(buf)
}
#[test]
fn test_iter() {
let symbols: Vec<_> = create_iter().collect().expect("collect");
let expected = [
Symbol {
index: SymbolIndex(0x4),
data: &[0x4e, 0x11], },
Symbol {
index: SymbolIndex(0x8),
data: &[0x06, 0x00], },
];
assert_eq!(symbols, expected);
}
#[test]
fn test_seek() {
let mut symbols = create_iter();
symbols.seek(SymbolIndex(0x8));
let symbol = symbols.next().expect("get symbol");
let expected = Symbol {
index: SymbolIndex(0x8),
data: &[0x06, 0x00], };
assert_eq!(symbol, Some(expected));
}
#[test]
fn test_skip_to() {
let mut symbols = create_iter();
let symbol = symbols.skip_to(SymbolIndex(0x8)).expect("get symbol");
let expected = Symbol {
index: SymbolIndex(0x8),
data: &[0x06, 0x00], };
assert_eq!(symbol, Some(expected));
}
}
}