From 76025e5d0273cf0dc0800e74d8f8cb883f5f10cf Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Fri, 17 Feb 2023 00:38:51 +0100 Subject: [PATCH 1/6] Add support for managed procedures Added symbols: - S_TOKENREF - S_LMANPROC - S_GMANPROC --- examples/pdb_symbols.rs | 8 +++- src/common.rs | 8 ++++ src/symbol/mod.rs | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/examples/pdb_symbols.rs b/examples/pdb_symbols.rs index e8f0738..18727e8 100644 --- a/examples/pdb_symbols.rs +++ b/examples/pdb_symbols.rs @@ -1,7 +1,7 @@ use std::env; use getopts::Options; -use pdb::{FallibleIterator, PdbInternalSectionOffset}; +use pdb::{FallibleIterator, PdbInternalSectionOffset, RawString}; fn print_usage(program: &str, opts: Options) { let brief = format!("Usage: {} input.pdb", program); @@ -26,6 +26,12 @@ fn print_symbol(symbol: &pdb::Symbol<'_>) -> pdb::Result<()> { pdb::SymbolData::Procedure(data) => { print_row(data.offset, "function", data.name); } + pdb::SymbolData::ManagedProcedure(data) => { + match data.name { + None => print_row(data.offset, "function", RawString::from(&b""[..])), + Some(name) => print_row(data.offset, "function", name), + } + } _ => { // ignore everything else } diff --git a/src/common.rs b/src/common.rs index 893a857..39321b6 100644 --- a/src/common.rs +++ b/src/common.rs @@ -605,6 +605,14 @@ impl_pread!(TypeIndex); impl ItemIndex for TypeIndex {} +/// COM+ metadata token for managed procedures (`CV_tkn_t`). +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct COMToken(pub u32); + +impl_convert!(COMToken, u32); +impl_hex_fmt!(COMToken); +impl_pread!(COMToken); + /// Index of an [`Id`](crate::Id) in [`IdInformation`](crate::IdInformation) stream. /// /// If this index is a [cross module reference](ItemIndex::is_cross_module), it must be resolved diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index 765b730..ba6e71b 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -185,6 +185,8 @@ pub enum SymbolData<'t> { Public(PublicSymbol<'t>), /// A procedure, such as a function or method. Procedure(ProcedureSymbol<'t>), + /// A managed procedure, such as a function or method. + ManagedProcedure(ManagedProcedureSymbol<'t>), /// A thread local variable. ThreadStorage(ThreadStorageSymbol<'t>), /// Flags used to compile a module. @@ -197,6 +199,8 @@ pub enum SymbolData<'t> { DataReference(DataReferenceSymbol<'t>), /// Reference to an annotation. AnnotationReference(AnnotationReferenceSymbol<'t>), + /// Reference to a managed procedure. + TokenReference(TokenReferenceSymbol<'t>), /// Trampoline thunk. Trampoline(TrampolineSymbol), /// An exported symbol. @@ -236,12 +240,14 @@ impl<'t> SymbolData<'t> { 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::CompileFlags(_) => None, 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::Trampoline(_) => None, Self::Export(data) => Some(data.name), Self::Local(data) => Some(data.name), @@ -283,6 +289,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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)?) } @@ -296,6 +303,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { S_TRAMPOLINE => Self::Trampoline(buf.parse_with(kind)?), S_DATAREF | S_DATAREF_ST => SymbolData::DataReference(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_BUILDINFO => SymbolData::BuildInfo(buf.parse_with(kind)?), @@ -575,6 +583,41 @@ impl<'t> TryFromCtx<'t, SymbolKind> for AnnotationReferenceSymbol<'t> { } } +/// Reference to a managed procedure symbol (`S_LMANPROC` or `S_GMANPROC`). +/// +/// Symbol kind `S_TOKENREF`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct TokenReferenceSymbol<'t> { + /// SUC of the name. + pub sum_name: u32, + /// Symbol index of the referenced [`ManagedProcedureSymbol`]. + /// + /// Note that this symbol might be located in a different module. + pub symbol_index: SymbolIndex, + /// Index of the module in [`DebugInformation::modules`](crate::DebugInformation::modules) + /// containing the actual symbol. + pub module: Option, + /// Name of the procedure reference. + 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 symbol = TokenReferenceSymbol { + sum_name: buf.parse()?, + symbol_index: buf.parse()?, + module: buf.parse::()?.checked_sub(1).map(usize::from), + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + /// Subtype of [`TrampolineSymbol`]. #[non_exhaustive] #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -840,6 +883,66 @@ impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureSymbol<'t> { } } +/// A managed procedure, such as a function or method. +/// +/// Symbol kinds: +/// - `S_GMANPROC`, `S_GMANPROCIA64` for global procedures +/// - `S_LMANPROC`, `S_LMANPROCIA64` for local procedures +/// +/// `S_GMANPROCIA64` and `S_LMANPROCIA64` are only mentioned, there is no available source. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ManagedProcedureSymbol<'t> { + /// Whether this is a global or local procedure. + pub global: bool, + /// The parent scope that this procedure is nested in. + pub parent: Option, + /// The end symbol of this procedure. + pub end: SymbolIndex, + /// The next procedure symbol. + pub next: Option, + /// The length of the code block covered by this procedure. + pub len: u32, + /// Start offset of the procedure's body code, which marks the end of the prologue. + pub dbg_start_offset: u32, + /// End offset of the procedure's body code, which marks the start of the epilogue. + pub dbg_end_offset: u32, + /// COM+ metadata token + pub token: COMToken, + /// Code offset of the start of this procedure. + pub offset: PdbInternalSectionOffset, + /// Detailed flags of this procedure. + pub flags: ProcedureFlags, + /// Register return value is in (may not be used for all archs). + pub return_register: u16, + /// Optional name of the procedure. + pub name: Option>, +} + +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())) + } +} + /// The callsite of an inlined function. /// /// Symbol kind `S_INLINESITE`, or `S_INLINESITE2`. From 9d4269fbea450ec4656e5c68e2f89e44cb9c69a9 Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Fri, 17 Feb 2023 02:06:24 +0100 Subject: [PATCH 2/6] Add OEM symbols Added base for S_OEM parsing, needs improvements in future. --- src/symbol/mod.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index ba6e71b..990838d 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -225,6 +225,8 @@ pub enum SymbolData<'t> { Thunk(ThunkSymbol<'t>), /// A block of separated code. SeparatedCode(SeparatedCodeSymbol), + /// OEM information. + OEM(OemSymbol<'t>), } impl<'t> SymbolData<'t> { @@ -260,6 +262,7 @@ impl<'t> SymbolData<'t> { Self::RegisterRelative(data) => Some(data.name), Self::Thunk(data) => Some(data.name), Self::SeparatedCode(_) => None, + Self::OEM(_) => None, } } } @@ -315,6 +318,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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)?), other => return Err(Error::UnimplementedSymbolKind(other)), }; @@ -1602,6 +1606,37 @@ impl<'t> TryFromCtx<'t, SymbolKind> for SeparatedCodeSymbol { } } +/// An OEM symbol. +/// +/// Symbol kind `S_OEM`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct OemSymbol<'t> { + /// OEM's identifier (16B GUID). + pub id_oem: RawString<'t>, + /// Type index. + pub type_index: TypeIndex, + /// User data with forced 4B-alignment. + /// + /// An array of variable size, currently only the first 4B are parsed. + 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())) + } +} + /// PDB symbol tables contain names, locations, and metadata about functions, global/static data, /// constants, data types, and more. /// From f6a2b9d63074c3b23010d866a08342dea7759e02 Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Fri, 17 Feb 2023 02:56:43 +0100 Subject: [PATCH 3/6] Add support for managed local variable slots Added support for: - S_MANSLOT - S_MANSLOT_ST --- examples/pdb_symbols.rs | 3 +++ src/symbol/mod.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/examples/pdb_symbols.rs b/examples/pdb_symbols.rs index 18727e8..59f4f88 100644 --- a/examples/pdb_symbols.rs +++ b/examples/pdb_symbols.rs @@ -32,6 +32,9 @@ fn print_symbol(symbol: &pdb::Symbol<'_>) -> pdb::Result<()> { Some(name) => print_row(data.offset, "function", name), } } + pdb::SymbolData::ManagedSlot(data) => { + print_row(data.offset, "data", data.name); + } _ => { // ignore everything else } diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index 990838d..b384602 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -207,6 +207,8 @@ pub enum SymbolData<'t> { Export(ExportSymbol<'t>), /// A local symbol in optimized code. Local(LocalSymbol<'t>), + /// A managed local variable slot. + ManagedSlot(ManagedSlotSymbol<'t>), /// Reference to build information. BuildInfo(BuildInfoSymbol), /// The callsite of an inlined function. @@ -253,6 +255,7 @@ impl<'t> SymbolData<'t> { Self::Trampoline(_) => None, Self::Export(data) => Some(data.name), Self::Local(data) => Some(data.name), + Self::ManagedSlot(data) => Some(data.name), Self::InlineSite(_) => None, Self::BuildInfo(_) => None, Self::InlineSiteEnd => None, @@ -309,6 +312,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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, @@ -1276,6 +1280,41 @@ impl<'t> TryFromCtx<'t, SymbolKind> for LocalSymbol<'t> { } } +/// A managed local variable slot. +/// +/// Symbol kind `S_MANSLOT`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ManagedSlotSymbol<'t> { + /// Slot index. + pub slot: u32, + /// Type index or metadata token. + pub type_index: TypeIndex, + /// First code address where var is live. + pub offset: PdbInternalSectionOffset, + /// Local variable flags. + pub flags: LocalVariableFlags, + /// Length-prefixed name of the variable. + 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())) + } +} + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4456 /// Flags of an [`ExportSymbol`]. #[non_exhaustive] From 6d77fc2d47c218f83968b523202beff76bfa159e Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Sun, 14 May 2023 20:13:14 +0200 Subject: [PATCH 4/6] S_ENVBLOCK support + support for env block symbol --- src/symbol/mod.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index b384602..56da7b2 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -229,6 +229,8 @@ pub enum SymbolData<'t> { SeparatedCode(SeparatedCodeSymbol), /// OEM information. OEM(OemSymbol<'t>), + /// Environment block split off from S_COMPILE2. + EnvBlock(EnvBlockSymbol<'t>) } impl<'t> SymbolData<'t> { @@ -266,6 +268,7 @@ impl<'t> SymbolData<'t> { Self::Thunk(data) => Some(data.name), Self::SeparatedCode(_) => None, Self::OEM(_) => None, + Self::EnvBlock(_) => None, } } } @@ -323,6 +326,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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)?), other => return Err(Error::UnimplementedSymbolKind(other)), }; @@ -1676,6 +1680,39 @@ impl<'t> TryFromCtx<'t, SymbolKind> for OemSymbol<'t> { } } +/// Environment block split off from `S_COMPILE2`. +/// +/// Symbol kind `S_ENVBLOCK`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EnvBlockSymbol<'t> { + /// EC flag (previously called `rev`). + pub edit_and_continue: bool, + /// Sequence of zero-terminated command strings. + pub rgsz: Vec>, +} + +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> = 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())) + } +} + /// PDB symbol tables contain names, locations, and metadata about functions, global/static data, /// constants, data types, and more. /// From 81891efc44f1ea3f9eaa3c6886945760300a0027 Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Sun, 14 May 2023 21:04:41 +0200 Subject: [PATCH 5/6] S_SECTION support + support for PE section symbol --- src/symbol/mod.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index 56da7b2..0cddea3 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -230,7 +230,9 @@ pub enum SymbolData<'t> { /// OEM information. OEM(OemSymbol<'t>), /// Environment block split off from S_COMPILE2. - EnvBlock(EnvBlockSymbol<'t>) + EnvBlock(EnvBlockSymbol<'t>), + /// A COFF section in a PE executable. + Section(SectionSymbol<'t>), } impl<'t> SymbolData<'t> { @@ -269,6 +271,7 @@ impl<'t> SymbolData<'t> { Self::SeparatedCode(_) => None, Self::OEM(_) => None, Self::EnvBlock(_) => None, + Self::Section(data) => Some(data.name), } } } @@ -327,6 +330,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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)?), other => return Err(Error::UnimplementedSymbolKind(other)), }; @@ -1713,6 +1717,48 @@ impl<'t> TryFromCtx<'t, SymbolKind> for EnvBlockSymbol <'t> { } } +/// A COFF section in a PE executable. +/// +/// Symbol kind `S_SECTION`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SectionSymbol<'t> { + /// Section number. + pub isec: u16, + /// Alignment of this section (power of 2). + pub align: u8, + /// Reserved. Must be zero. + pub reserved: u8, + /// Section's RVA. + pub rva: u32, + /// Section's CB. + pub cb: u32, + /// Section characteristics. + pub characteristics: u32, + /// Section name. + 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())) + } +} + /// PDB symbol tables contain names, locations, and metadata about functions, global/static data, /// constants, data types, and more. /// From 3b28ae0484a883d5cd6e753ad39e0c1be613d84a Mon Sep 17 00:00:00 2001 From: michal-kapala Date: Sun, 14 May 2023 21:21:48 +0200 Subject: [PATCH 6/6] S_COFFGROUP support + support for COFF group symbol --- src/symbol/mod.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index 0cddea3..9a28506 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -233,6 +233,8 @@ pub enum SymbolData<'t> { EnvBlock(EnvBlockSymbol<'t>), /// A COFF section in a PE executable. Section(SectionSymbol<'t>), + /// A COFF group. + CoffGroup(CoffGroupSymbol<'t>), } impl<'t> SymbolData<'t> { @@ -272,6 +274,7 @@ impl<'t> SymbolData<'t> { Self::OEM(_) => None, Self::EnvBlock(_) => None, Self::Section(data) => Some(data.name), + Self::CoffGroup(data) => Some(data.name), } } } @@ -331,6 +334,7 @@ impl<'t> TryFromCtx<'t> for SymbolData<'t> { 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)?), other => return Err(Error::UnimplementedSymbolKind(other)), }; @@ -1759,6 +1763,42 @@ impl<'t> TryFromCtx<'t, SymbolKind> for SectionSymbol <'t> { } } +/// A COFF section in a PE executable. +/// +/// Symbol kind `S_SECTION`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CoffGroupSymbol<'t> { + /// COFF group's CB. + pub cb: u32, + /// COFF group characteristics. + pub characteristics: u32, + /// Symbol offset. + pub offset: PdbInternalSectionOffset, + /// Symbol segment. + pub segment: u16, + /// COFF group name. + 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()?, + segment: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)? + }; + + Ok((symbol, buf.pos())) + } +} + /// PDB symbol tables contain names, locations, and metadata about functions, global/static data, /// constants, data types, and more. ///