ms_pdb/
syms.rs

1//! Decodes symbols records. Reads the "Global Symbols" stream and per-module symbol streams.
2//!
3//! # References
4//!
5//! * [`cvinfo.h`](https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/include/cvinfo.h)
6//! * [CodeView Symbols](https://llvm.org/docs/PDB/CodeViewSymbols.html)
7
8pub mod builder;
9mod iter;
10mod kind;
11mod offset_segment;
12
13#[doc(inline)]
14pub use self::{iter::*, kind::SymKind, offset_segment::*};
15
16use crate::parser::{Number, Parse, Parser, ParserError, ParserMut};
17use crate::types::{ItemId, ItemIdLe, TypeIndex, TypeIndexLe};
18use bstr::BStr;
19use std::fmt::Debug;
20use std::mem::size_of;
21use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned, I32, LE, U16, U32};
22
23/// Identifies the kind of symbol streams. Some behaviors of symbol streams are different,
24/// depending on which one is being processed.
25#[derive(Copy, Clone, Eq, PartialEq, Debug)]
26pub enum SymbolStreamKind {
27    /// The Global Symbol Stream
28    Global,
29
30    /// A Module Symbol Stream
31    Module,
32}
33
34impl SymbolStreamKind {
35    /// The byte offset within a stream where the symbol records begin.
36    pub fn stream_offset(self) -> usize {
37        match self {
38            Self::Global => 0,
39            Self::Module => 4,
40        }
41    }
42}
43
44/// This header is shared by many records that can start a symbol scope.
45#[derive(IntoBytes, FromBytes, Unaligned, Immutable, KnownLayout, Default, Clone, Debug)]
46#[repr(C)]
47#[allow(missing_docs)]
48pub struct BlockHeader {
49    /// If the record containing this `BlockHeader` is a top-level symbol record (not nested within
50    /// another symbol), then this value is 0.
51    ///
52    /// If the record containing this `BlockHeader` is nested within another symbol, then this
53    /// value is the offset in the symbol stream of the parent record.
54    pub p_parent: U32<LE>,
55
56    /// Offset in symbol stream of the `P_END` which terminates this block scope.
57    pub p_end: U32<LE>,
58}
59
60/// Used for the header of procedure symbols. This is used for `S_LPROC32`, `S_GPROC32`,
61/// `S_LPROC32_ID`, etc.
62///
63/// See `PROCSYM32` in `cvinfo.h`.
64#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned, Debug)]
65#[repr(C)]
66#[allow(missing_docs)]
67pub struct ProcFixed {
68    /// This field is always zero; procedure symbols never have parents.
69    pub p_parent: U32<LE>,
70
71    /// The byte offset, relative to the start of this procedure record, of the `S_END` symbol that
72    /// closes the scope of this symbol record.
73    pub p_end: U32<LE>,
74
75    pub p_next: U32<LE>,
76
77    /// The length in bytes of the procedure instruction stream.
78    pub proc_len: U32<LE>,
79
80    /// The offset in bytes from the start of the procedure to the point where the stack frame has
81    /// been set up. Parameter and frame variables can be viewed at this point.
82    pub debug_start: U32<LE>,
83
84    /// The offset in bytes from the start of the procedure to the point where the procedure is
85    /// ready to return and has calculated its return value, if any. Frame and register variables
86    /// can still be viewed.
87    pub debug_end: U32<LE>,
88
89    /// This field is either a `TypeIndex` that points into the TPI or is an `ItemId` that
90    /// points into the IPI.
91    ///
92    /// This field is a `TypeIndex` for the following symbols: `S_GPROC32`, `S_LPROC32`,
93    /// `S_LPROC32EX`, `S_LPROC32_DPC`, `S_GPROC32EX`.
94    ///
95    /// This field is a `ItemId` for `S_LPROC32_ID`, `S_GPROC32_ID`, `S_LPROC32_DPC_ID`,
96    /// `S_GPROC32EX_ID`, `S_LPROC32EX_ID`.
97    pub proc_type: TypeIndexLe,
98
99    pub offset_segment: OffsetSegment,
100    pub flags: u8,
101}
102
103/// Used for `S_LPROC32` and `S_GPROC32`.
104///
105/// These records are found in Module Symbol Streams. They are very important; they describe the
106/// beginning of a function (procedure), and they contain other symbols recursively (are a
107/// "symbol scope"). The end of the sequence is terminated with an `S_END` symbol.
108///
109/// This is equivalent to the `PROCSYM32` type defined in `cvinfo.h`. This symbol begins with a
110/// `BLOCKSYM` header
111///
112/// # References
113/// * See `PROCSYM32` in `cvinfo.h`
114#[allow(missing_docs)]
115#[derive(Clone, Debug)]
116pub struct Proc<'a> {
117    pub fixed: &'a ProcFixed,
118    pub name: &'a BStr,
119}
120
121impl<'a> Parse<'a> for Proc<'a> {
122    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
123        Ok(Self {
124            fixed: p.get()?,
125            name: p.strz()?,
126        })
127    }
128}
129
130// Basic framing and decoding test
131#[test]
132fn test_parse_proc() {
133    #[rustfmt::skip]
134    let data = &[
135        /* 0x0000 */ 0x2e, 0, 0x10, 0x11,       // size and S_GPROC32
136        /* 0x0004 */ 0, 0, 0, 0,                // p_parent
137        /* 0x0008 */ 0x40, 0, 0, 0,             // p_end
138        /* 0x000c */ 0, 0, 0, 0,                // p_next
139        /* 0x0010 */ 42, 0, 0, 0,               // proc_len
140        /* 0x0014 */ 10, 0, 0, 0,               // debug_start
141        /* 0x0018 */ 20, 0, 0, 0,               // debug_end
142        /* 0x001c */ 0xee, 0x10, 0, 0,          // proc_type
143        /* 0x0020 */ 0xcc, 0x1, 0, 0,           // offset
144        /* 0x0024 */ 1, 0, 0x50, b'm',          // segment, flags, beginning of name
145        /* 0x0028 */ b'e', b'm', b's', b'e',    // name
146        /* 0x002c */ b't', 0, 0xf1, 0xf2,       // end and padding
147        /* 0x0030 */ 2, 0, 6, 0                 // size = 2 and S_END
148        /* 0x0034 */
149    ];
150
151    let mut i = SymIter::new(data);
152
153    let s0 = i.next().unwrap();
154    assert_eq!(s0.kind, SymKind::S_GPROC32);
155    assert_eq!(s0.data.len(), 0x2c);
156
157    match s0.parse().unwrap() {
158        SymData::Proc(proc) => {
159            assert_eq!(proc.fixed.p_parent.get(), 0);
160            assert_eq!(proc.fixed.p_end.get(), 0x40);
161            assert_eq!(proc.name, "memset");
162        }
163        _ => panic!(),
164    }
165
166    let s1 = i.next().unwrap();
167    assert_eq!(s1.kind, SymKind::S_END);
168    assert!(s1.data.is_empty());
169}
170
171/// `S_GMANPROC`, `S_LMANPROC` - Managed Procedure Start
172///
173/// See `MANPROCSYM` in `cvinfo.h`.
174#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned, Debug)]
175#[repr(C)]
176#[allow(missing_docs)]
177pub struct ManagedProcFixed {
178    pub p_parent: U32<LE>,
179    pub p_end: U32<LE>,
180    pub p_next: U32<LE>,
181    pub proc_len: U32<LE>,
182    pub debug_start: U32<LE>,
183    pub debug_end: U32<LE>,
184    pub token: U32<LE>,
185    pub offset_segment: OffsetSegment,
186    pub flags: u8,
187    pub return_reg: U16<LE>,
188}
189
190/// `S_GMANPROC`, `S_LMANPROC` - Managed Procedure Start
191#[allow(missing_docs)]
192#[derive(Clone, Debug)]
193pub struct ManagedProc<'a> {
194    pub fixed: &'a ManagedProcFixed,
195    pub name: &'a BStr,
196}
197
198impl<'a> Parse<'a> for ManagedProc<'a> {
199    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
200        Ok(Self {
201            fixed: p.get()?,
202            name: p.strz()?,
203        })
204    }
205}
206
207#[repr(C)]
208#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Default)]
209#[allow(missing_docs)]
210pub struct ThunkFixed {
211    pub block: BlockHeader,
212    pub p_next: U32<LE>,
213    pub offset_segment: OffsetSegment,
214    pub length: U16<LE>,
215    pub thunk_ordinal: u8,
216    // name: strz
217    // variant: [u8]
218}
219
220#[allow(missing_docs)]
221pub struct Thunk<'a> {
222    pub fixed: &'a ThunkFixed,
223    pub name: &'a BStr,
224    pub variant: &'a [u8],
225}
226
227impl<'a> Parse<'a> for Thunk<'a> {
228    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
229        Ok(Self {
230            fixed: p.get()?,
231            name: p.strz()?,
232            variant: p.take_rest(),
233        })
234    }
235}
236
237/// Describes the start of every symbol record.
238#[repr(C)]
239#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Default)]
240pub struct SymHeader {
241    /// The length in bytes of the record.
242    ///
243    /// This length _does not_ count the length itself, but _does_ count the `kind` that follows it.
244    /// Therefore, all well-formed symbol records have `len >= 2`.
245    pub len: U16<LE>,
246
247    /// The kind of the symbol.  See `SymKind`.
248    pub kind: U16<LE>,
249}
250
251/// Points to one symbol record in memory and gives its kind.
252#[derive(Clone)]
253pub struct Sym<'a> {
254    /// The kind of the symbol.
255    pub kind: SymKind,
256    /// The contents of the record. This slice does _not_ include the `len` or `kind` fields.
257    pub data: &'a [u8],
258}
259
260impl<'a> Sym<'a> {
261    /// Parse the payload of the symbol.
262    pub fn parse(&self) -> Result<SymData<'a>, ParserError> {
263        SymData::parse(self.kind, self.data)
264    }
265}
266
267impl<'a> Debug for Sym<'a> {
268    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
269        write!(fmt, "{:?}", self.kind)
270    }
271}
272
273/// Points to one symbol record in memory and gives its kind. Allows mutation of the contents of
274/// the symbol record.
275pub struct SymMut<'a> {
276    /// The kind of the symbol.
277    pub kind: SymKind,
278    /// The contents of the record. This slice does _not_ include the `len` or `kind` fields.
279    pub data: &'a mut [u8],
280}
281
282/// PUBSYM32
283///
284/// ```text
285/// typedef struct PUBSYM32 {
286///     unsigned short  reclen;     // Record length
287///     unsigned short  rectyp;     // S_PUB32
288///     CV_PUBSYMFLAGS  pubsymflags;
289///     CV_uoff32_t     off;
290///     unsigned short  seg;
291///     unsigned char   name[1];    // Length-prefixed name
292/// } PUBSYM32;
293/// ```
294#[allow(missing_docs)]
295#[derive(Clone, Debug)]
296pub struct Pub<'a> {
297    pub fixed: &'a PubFixed,
298    pub name: &'a BStr,
299}
300
301impl<'a> Pub<'a> {
302    /// Gets the `segment:offset` of this symbol.
303    pub fn offset_segment(&self) -> OffsetSegment {
304        self.fixed.offset_segment.clone()
305    }
306}
307
308#[allow(missing_docs)]
309#[repr(C)]
310#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
311pub struct PubFixed {
312    pub flags: U32<LE>,
313    pub offset_segment: OffsetSegment,
314    // name: &str
315}
316
317#[allow(missing_docs)]
318impl<'a> Parse<'a> for Pub<'a> {
319    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
320        Ok(Self {
321            fixed: p.get()?,
322            name: p.strz()?,
323        })
324    }
325}
326
327impl<'a> Pub<'a> {
328    /// Parses `S_PUB32_ST`
329    pub fn parse_st(p: &mut Parser<'a>) -> Result<Self, ParserError> {
330        Ok(Self {
331            fixed: p.get()?,
332            name: p.strt_raw()?,
333        })
334    }
335}
336
337/// Parsed form of `S_CONSTANT`
338#[allow(missing_docs)]
339#[derive(Clone, Debug)]
340pub struct Constant<'a> {
341    pub type_: TypeIndex,
342    pub value: Number<'a>,
343    pub name: &'a BStr,
344}
345
346impl<'a> Parse<'a> for Constant<'a> {
347    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
348        Ok(Self {
349            type_: p.type_index()?,
350            value: p.number()?,
351            name: p.strz()?,
352        })
353    }
354}
355
356/// Parsed form of `S_CONSTANT`
357#[allow(missing_docs)]
358#[derive(Clone, Debug)]
359pub struct ManagedConstant<'a> {
360    pub token: u32,
361    pub value: Number<'a>,
362    pub name: &'a BStr,
363}
364
365impl<'a> Parse<'a> for ManagedConstant<'a> {
366    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
367        Ok(Self {
368            token: p.u32()?,
369            value: p.number()?,
370            name: p.strz()?,
371        })
372    }
373}
374
375/// Several symbols use this structure: `S_PROCREF`, `S_LPROCREF`, `S_DATAREF`. These symbols
376/// are present in the Global Symbol Stream, not in module symbol streams.
377///
378/// These `S_*REF` symbols tell you where to find a specific global symbol, but they do not directly
379/// describe the symbol. Instead, you have to load the corresponding module
380///
381///
382#[allow(missing_docs)]
383#[derive(Clone, Debug)]
384pub struct RefSym2<'a> {
385    pub header: &'a RefSym2Fixed,
386    pub name: &'a BStr,
387}
388
389#[allow(missing_docs)]
390#[repr(C)]
391#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
392pub struct RefSym2Fixed {
393    /// Checksum of the name (called `SUC` in C++ code)
394    ///
395    /// This appears to be set to zero.
396    pub name_checksum: U32<LE>,
397
398    /// Offset of actual symbol in $$Symbols
399    ///
400    /// This is the byte offset into the module symbol stream for this symbol. The `module_index`
401    /// field tells you which symbol stream to load, to resolve this value.
402    pub symbol_offset: U32<LE>,
403
404    /// The 1-based index of the module containing the actual symbol.
405    ///
406    /// This value is 1-based. Subtract 1 from this value before indexing into a zero-based module array.
407    pub module_index: U16<LE>,
408    // pub name: strz, // hidden name made a first class member
409}
410
411impl<'a> Parse<'a> for RefSym2<'a> {
412    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
413        Ok(Self {
414            header: p.get()?,
415            name: p.strz()?,
416        })
417    }
418}
419
420#[allow(missing_docs)]
421#[repr(C)]
422#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
423pub struct ThreadStorageFixed {
424    pub type_: TypeIndexLe,
425    pub offset_segment: OffsetSegment,
426}
427
428/// Record data for `S_LTHREAD32` and `S_GTHREAD32`. These describes thread-local storage.
429///
430/// Thread-local storage is declared using `__declspec(thread)` or `thread_static`, in C++.
431#[derive(Clone, Debug)]
432pub struct ThreadStorageData<'a> {
433    #[allow(missing_docs)]
434    pub header: &'a ThreadStorageFixed,
435    #[allow(missing_docs)]
436    pub name: &'a BStr,
437}
438
439impl<'a> Parse<'a> for ThreadStorageData<'a> {
440    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
441        Ok(Self {
442            header: p.get()?,
443            name: p.strz()?,
444        })
445    }
446}
447
448#[allow(missing_docs)]
449#[repr(C)]
450#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
451pub struct DataFixed {
452    pub type_: TypeIndexLe,
453    pub offset_segment: OffsetSegment,
454}
455
456/// Record data for `S_LDATA32` and `S_GDATA32`. These describe global storage.
457#[allow(missing_docs)]
458#[derive(Clone)]
459pub struct Data<'a> {
460    pub header: &'a DataFixed,
461    pub name: &'a BStr,
462}
463
464impl<'a> Parse<'a> for Data<'a> {
465    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
466        Ok(Self {
467            header: p.get()?,
468            name: p.strz()?,
469        })
470    }
471}
472
473impl<'a> Debug for Data<'a> {
474    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
475        write!(
476            f,
477            "Data: {} {:?} {}",
478            self.header.offset_segment,
479            self.header.type_.get(),
480            self.name
481        )
482    }
483}
484
485/// Record data for `S_UDT` symbols
486#[derive(Clone, Debug)]
487pub struct Udt<'a> {
488    /// The type of the UDT
489    pub type_: TypeIndex,
490    /// Name
491    pub name: &'a BStr,
492}
493
494impl<'a> Parse<'a> for Udt<'a> {
495    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
496        Ok(Self {
497            type_: p.type_index()?,
498            name: p.strz()?,
499        })
500    }
501}
502
503/// `S_OBJNAME`
504#[derive(Clone, Debug)]
505pub struct ObjectName<'a> {
506    /// A robust signature that will change every time that the module will be compiled or
507    /// different in any way. It should be at least a CRC32 based upon module name and contents.
508    pub signature: u32,
509    /// Full path of the object file.
510    pub name: &'a BStr,
511}
512
513impl<'a> Parse<'a> for ObjectName<'a> {
514    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
515        Ok(Self {
516            signature: p.u32()?,
517            name: p.strz()?,
518        })
519    }
520}
521
522/// `S_COMPILE3`
523#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
524#[repr(C)]
525#[allow(missing_docs)]
526pub struct Compile3Fixed {
527    pub flags: U32<LE>,
528    pub machine: U16<LE>,
529    pub frontend_major: U16<LE>,
530    pub frontend_minor: U16<LE>,
531    pub frontend_build: U16<LE>,
532    pub frontend_qfe: U16<LE>,
533    pub ver_major: U16<LE>,
534    pub ver_minor: U16<LE>,
535    pub ver_build: U16<LE>,
536    pub ver_qfe: U16<LE>,
537    // name: strz
538}
539
540/// `S_COMPILE3`
541#[allow(missing_docs)]
542#[derive(Clone, Debug)]
543pub struct Compile3<'a> {
544    pub fixed: &'a Compile3Fixed,
545    pub name: &'a BStr,
546}
547
548impl<'a> Parse<'a> for Compile3<'a> {
549    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
550        Ok(Self {
551            fixed: p.get()?,
552            name: p.strz()?,
553        })
554    }
555}
556
557/// `S_FRAMEPROC`: This symbol is used for indicating a variety of extra information regarding a
558/// procedure and its stack frame. If any of the flags are non-zero, this record should be added
559/// to the symbols for that procedure.
560#[repr(C)]
561#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
562#[allow(missing_docs)]
563pub struct FrameProc {
564    /// Count of bytes in the whole stack frame.
565    frame_size: U32<LE>,
566    /// Count of bytes in the frame allocated as padding.
567    pad_size: U32<LE>,
568    /// Offset of pad bytes from the base of the frame.
569    pad_offset: U32<LE>,
570    /// Count of bytes in frame allocated for saved callee-save registers.
571    save_regs_size: U32<LE>,
572    offset_exception_handler: U32<LE>,
573    exception_handler_section: U16<LE>,
574    padding: U16<LE>,
575    flags: U32<LE>,
576}
577
578#[repr(C)]
579#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
580#[allow(missing_docs)]
581pub struct RegRelFixed {
582    pub offset: U32<LE>,
583    pub ty: TypeIndexLe,
584    pub register: U16<LE>,
585    // name: strz
586}
587
588/// `S_REGREGL32`: This symbol specifies symbols that are allocated relative to a register.
589/// This should be used on all platforms besides x86 and on x86 when the register is not a form of EBP.
590#[derive(Clone, Debug)]
591#[allow(missing_docs)]
592pub struct RegRel<'a> {
593    pub fixed: &'a RegRelFixed,
594    pub name: &'a BStr,
595}
596
597impl<'a> Parse<'a> for RegRel<'a> {
598    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
599        Ok(Self {
600            fixed: p.get()?,
601            name: p.strz()?,
602        })
603    }
604}
605
606/// Block Start: This symbol specifies the start of an inner block of lexically scoped symbols.
607/// The lexical scope is terminated by a matching `S_END` symbol.
608///
609/// This symbol should only be nested (directly or indirectly) within a function symbol
610/// (`S_GPROC32`, `S_LPROC32`, etc.).
611///
612/// See `BLOCKSYM32`
613#[derive(Clone, Debug)]
614#[allow(missing_docs)]
615pub struct Block<'a> {
616    pub fixed: &'a BlockFixed,
617    pub name: &'a BStr,
618}
619
620#[repr(C)]
621#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
622#[allow(missing_docs)]
623pub struct BlockFixed {
624    /// Header of the block
625    pub header: BlockHeader,
626
627    /// Length in bytes of the scope of this block within the executable code stream.
628    pub length: U32<LE>,
629
630    pub offset_segment: OffsetSegment,
631}
632
633impl<'a> Parse<'a> for Block<'a> {
634    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
635        Ok(Self {
636            fixed: p.get()?,
637            name: p.strz()?,
638        })
639    }
640}
641
642/// Local Symbol: This symbol defines a local variable.
643///
644/// This symbol must be nested (directly or indirectly) within a function symbol. It must be
645/// followed by more range descriptions.
646#[derive(Clone, Debug)]
647#[allow(missing_docs)]
648pub struct Local<'a> {
649    pub fixed: &'a LocalFixed,
650    pub name: &'a BStr,
651}
652
653#[repr(C)]
654#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
655#[allow(missing_docs)]
656pub struct LocalFixed {
657    pub ty: TypeIndexLe,
658    /// The spec says this is a 32-bit flags field, but the actual records show that this is 16-bit.
659    pub flags: U16<LE>,
660    // name: strz
661}
662
663impl<'a> Parse<'a> for Local<'a> {
664    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
665        Ok(Self {
666            fixed: p.get()?,
667            name: p.strz()?,
668        })
669    }
670}
671
672/// Represents an address range, used for optimized code debug info
673///
674/// See `CV_LVAR_ADDR_RANGE`
675#[repr(C)]
676#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
677pub struct LVarAddrRange {
678    /// Start of the address range
679    pub start: OffsetSegment,
680    /// Size of the range in bytes.
681    pub range_size: U16<LE>,
682}
683
684/// Represents the holes in overall address range, all address is pre-bbt.
685/// it is for compress and reduce the amount of relocations need.
686///
687/// See `CV_LVAR_ADDR_GAP`
688#[repr(C)]
689#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
690pub struct LVarAddrGap {
691    /// relative offset from the beginning of the live range.
692    pub gap_start_offset: U16<LE>,
693    /// length of this gap, in bytes
694    pub range_size: U16<LE>,
695}
696
697/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
698#[repr(C)]
699#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
700#[allow(missing_docs)]
701pub struct DefRangeSymFramePointerRelFixed {
702    pub offset_to_frame_pointer: U32<LE>,
703
704    /// Range of addresses where this program is valid
705    pub range: LVarAddrRange,
706}
707
708/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
709#[allow(missing_docs)]
710#[derive(Clone, Debug)]
711pub struct DefRangeSymFramePointerRel<'a> {
712    pub fixed: &'a DefRangeSymFramePointerRelFixed,
713    // The value is not available in following gaps.
714    pub gaps: &'a [LVarAddrGap],
715}
716
717impl<'a> Parse<'a> for DefRangeSymFramePointerRel<'a> {
718    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
719        let fixed = p.get()?;
720        let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
721        Ok(Self { fixed, gaps })
722    }
723}
724
725/// Attributes for a register range
726///
727/// See `CV_RANGEATTR`
728#[repr(C)]
729#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
730#[allow(missing_docs)]
731pub struct RangeAttrLe {
732    // unsigned short  maybe : 1;    // May have no user name on one of control flow path.
733    // unsigned short  padding : 15; // Padding for future use.
734    pub value: U16<LE>,
735}
736
737/// `S_DEFRANGE_REGISTER` - A live range of en-registed variable
738///
739/// See `DEFRANGESYMREGISTER`
740#[repr(C)]
741#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
742#[allow(missing_docs)]
743pub struct DefRangeRegisterFixed {
744    /// Register to hold the value of the symbol
745    pub reg: U16<LE>,
746    // Attribute of the register range.
747    pub attr: RangeAttrLe,
748}
749
750/// `S_DEFRANGE_REGISTER`
751///
752/// See `DEFRANGESYMREGISTER`
753#[derive(Clone, Debug)]
754#[allow(missing_docs)]
755pub struct DefRangeRegister<'a> {
756    pub fixed: &'a DefRangeRegisterFixed,
757    pub gaps: &'a [u8],
758}
759
760impl<'a> Parse<'a> for DefRangeRegister<'a> {
761    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
762        Ok(Self {
763            fixed: p.get()?,
764            gaps: p.take_rest(),
765        })
766    }
767}
768
769/// `S_DEFRANGE_REGISTER_REL`
770#[allow(missing_docs)]
771#[derive(Debug, Clone)]
772pub struct DefRangeRegisterRel<'a> {
773    pub fixed: &'a DefRangeRegisterRelFixed,
774
775    /// The value is not available in following gaps.
776    pub gaps: &'a [u8],
777}
778
779/// `S_DEFRANGE_REGISTER_REL`
780#[repr(C)]
781#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
782pub struct DefRangeRegisterRelFixed {
783    /// Register to hold the base pointer of the symbol
784    pub base_reg: U16<LE>,
785
786    /// ```text
787    /// unsigned short  spilledUdtMember : 1;   // Spilled member for s.i.
788    /// unsigned short  padding          : 3;   // Padding for future use.
789    /// unsigned short  offsetParent     : CV_OFFSET_PARENT_LENGTH_LIMIT;  // Offset in parent variable.
790    /// ```
791    pub flags: U16<LE>,
792
793    /// offset to register
794    pub base_pointer_offset: I32<LE>,
795
796    /// Range of addresses where this program is valid
797    pub range: LVarAddrRange,
798}
799
800impl<'a> Parse<'a> for DefRangeRegisterRel<'a> {
801    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
802        Ok(Self {
803            fixed: p.get()?,
804            gaps: p.take_rest(),
805        })
806    }
807}
808
809/// `S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE`
810///
811/// A frame variable valid in all function scope.
812#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
813#[repr(C)]
814pub struct DefRangeFramePointerRelFullScope {
815    /// offset to frame pointer
816    pub frame_pointer_offset: I32<LE>,
817}
818
819/// `S_DEFRANGE_SUBFIELD_REGISTER`
820///
821/// See `DEFRANGESYMSUBFIELDREGISTER`
822#[derive(Clone, Debug)]
823#[allow(missing_docs)]
824pub struct DefRangeSubFieldRegister<'a> {
825    pub fixed: &'a DefRangeSubFieldRegisterFixed,
826    pub gaps: &'a [u8],
827}
828
829#[repr(C)]
830#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
831#[allow(missing_docs)]
832pub struct DefRangeSubFieldRegisterFixed {
833    pub reg: U16<LE>,
834    pub attr: RangeAttrLe,
835    pub flags: U32<LE>,
836    pub range: LVarAddrRange,
837}
838
839impl<'a> Parse<'a> for DefRangeSubFieldRegister<'a> {
840    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
841        Ok(Self {
842            fixed: p.get()?,
843            gaps: p.take_rest(),
844        })
845    }
846}
847
848/// `S_GMANPROC`, `S_LMANPROC`, `S_GMANPROCIA64`, `S_LMANPROCIAC64`
849///
850/// See `MANPROCSYM`
851pub struct ManProcSym<'a> {
852    #[allow(missing_docs)]
853    pub fixed: &'a ManProcSymFixed,
854    #[allow(missing_docs)]
855    pub name: &'a BStr,
856}
857
858/// MSIL / CIL token value
859pub type TokenIdLe = U32<LE>;
860
861#[repr(C)]
862#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
863#[allow(missing_docs)]
864pub struct ManProcSymFixed {
865    pub block: BlockHeader,
866    /// pointer to next symbol
867    pub pnext: U32<LE>,
868    /// Proc length
869    pub len: U32<LE>,
870    /// Debug start offset
871    pub dbg_start: U32<LE>,
872    /// Debug end offset
873    pub dbg_end: U32<LE>,
874    // COM+ metadata token for method
875    pub token: TokenIdLe,
876    pub off: U32<LE>,
877    pub seg: U16<LE>,
878    pub flags: u8, // CV_PROCFLAGS: Proc flags
879    pub padding: u8,
880    // Register return value is in (may not be used for all archs)
881    pub ret_reg: U16<LE>,
882    // name: strz    // optional name field
883}
884
885impl<'a> Parse<'a> for ManProcSym<'a> {
886    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
887        Ok(Self {
888            fixed: p.get()?,
889            name: p.strz()?,
890        })
891    }
892}
893
894/// `S_TRAMPOLINE`
895#[derive(Clone, Debug)]
896pub struct Trampoline<'a> {
897    /// Fixed header
898    pub fixed: &'a TrampolineFixed,
899
900    /// Data whose interpretation depends on `tramp_type`
901    pub rest: &'a [u8],
902}
903
904/// `S_TRAMPOLINE`
905#[repr(C)]
906#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
907pub struct TrampolineFixed {
908    /// trampoline sym subtype
909    pub tramp_type: U16<LE>,
910    /// size of the thunk
911    pub cb_thunk: U16<LE>,
912    /// offset of the thunk
913    pub off_thunk: U32<LE>,
914    /// offset of the target of the thunk
915    pub off_target: U32<LE>,
916    /// section index of the thunk
917    pub sect_thunk: U16<LE>,
918    /// section index of the target of the thunk
919    pub sect_target: U16<LE>,
920}
921
922impl<'a> Parse<'a> for Trampoline<'a> {
923    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
924        Ok(Self {
925            fixed: p.get()?,
926            rest: p.take_rest(),
927        })
928    }
929}
930
931/// `S_BUILDINFO` - Build info for a module
932///
933/// This record is present only in module symbol streams.
934#[derive(Clone, Debug)]
935pub struct BuildInfo {
936    /// ItemId points to an `LF_BUILDINFO` record in IPI
937    pub item: ItemId,
938}
939
940impl<'a> Parse<'a> for BuildInfo {
941    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
942        Ok(Self { item: p.u32()? })
943    }
944}
945
946/// `S_UNAMESPACE` - Using Namespace
947#[derive(Clone, Debug)]
948pub struct UsingNamespace<'a> {
949    /// The namespace, e.g. `std`
950    pub namespace: &'a BStr,
951}
952
953impl<'a> Parse<'a> for UsingNamespace<'a> {
954    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
955        Ok(Self {
956            namespace: p.strz()?,
957        })
958    }
959}
960
961/// `S_LABEL32`
962#[derive(Clone, Debug)]
963#[allow(missing_docs)]
964pub struct Label<'a> {
965    pub fixed: &'a LabelFixed,
966    pub name: &'a BStr,
967}
968
969/// `S_LABEL32`
970#[repr(C)]
971#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
972#[allow(missing_docs)]
973pub struct LabelFixed {
974    pub offset_segment: OffsetSegment,
975    pub flags: u8,
976}
977
978impl<'a> Parse<'a> for Label<'a> {
979    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
980        Ok(Self {
981            fixed: p.get()?,
982            name: p.strz()?,
983        })
984    }
985}
986
987/// Data for `S_CALLERS`, `S_CALLEES`, `S_INLINEES`.
988#[derive(Clone, Debug)]
989pub struct FunctionList<'a> {
990    /// The list of functions, in the IPI. Each is either `LF_FUNC_ID` or `LF_MFUNC_ID`.
991    pub funcs: &'a [ItemIdLe],
992
993    /// Counts for each function.
994    ///
995    /// The values in `counts` parallel the items in `funcs`, but the length of `invocations` can be
996    /// less than the length of `funcs`. Unmatched counts are assumed to be zero.
997    ///
998    /// This is empty for `S_INLINEES`.
999    pub counts: &'a [U32<LE>],
1000}
1001
1002impl<'a> Parse<'a> for FunctionList<'a> {
1003    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1004        let num_funcs = p.u32()? as usize;
1005        let funcs: &[ItemIdLe] = p.slice(num_funcs)?;
1006        let num_counts = num_funcs.min(p.len() / size_of::<U32<LE>>());
1007        let counts = p.slice(num_counts)?;
1008        Ok(Self { funcs, counts })
1009    }
1010}
1011
1012/// `S_INLINESITE`
1013#[allow(missing_docs)]
1014#[derive(Clone, Debug)]
1015pub struct InlineSite<'a> {
1016    pub fixed: &'a InlineSiteFixed,
1017    /// an array of compressed binary annotations.
1018    pub binary_annotations: &'a [u8],
1019}
1020
1021/// `S_INLINESITE`
1022#[repr(C)]
1023#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1024#[allow(missing_docs)]
1025pub struct InlineSiteFixed {
1026    pub block: BlockHeader,
1027    pub inlinee: ItemIdLe,
1028}
1029
1030impl<'a> Parse<'a> for InlineSite<'a> {
1031    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1032        Ok(Self {
1033            fixed: p.get()?,
1034            binary_annotations: p.take_rest(),
1035        })
1036    }
1037}
1038
1039/// `S_INLINESITE2`
1040#[allow(missing_docs)]
1041#[derive(Clone, Debug)]
1042pub struct InlineSite2<'a> {
1043    pub fixed: &'a InlineSite2Fixed,
1044    /// an array of compressed binary annotations.
1045    pub binary_annotations: &'a [u8],
1046}
1047
1048/// `S_INLINESITE`
1049#[repr(C)]
1050#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1051#[allow(missing_docs)]
1052pub struct InlineSite2Fixed {
1053    pub block: BlockHeader,
1054    pub inlinee: ItemIdLe,
1055    pub invocations: U32<LE>,
1056}
1057
1058impl<'a> Parse<'a> for InlineSite2<'a> {
1059    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1060        Ok(Self {
1061            fixed: p.get()?,
1062            binary_annotations: p.take_rest(),
1063        })
1064    }
1065}
1066
1067/// `S_FRAMECOOKIE`: Symbol for describing security cookie's position and type
1068// (raw, xor'd with esp, xor'd with ebp).
1069#[repr(C)]
1070#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1071#[allow(missing_docs)]
1072pub struct FrameCookie {
1073    /// Frame relative offset
1074    pub offset: I32<LE>,
1075    pub reg: U16<LE>,
1076    pub cookie_type: u8,
1077    pub flags: u8,
1078}
1079
1080/// `S_CALLSITEINFO`
1081///
1082/// Symbol for describing indirect calls when they are using
1083/// a function pointer cast on some other type or temporary.
1084/// Typical content will be an LF_POINTER to an LF_PROCEDURE
1085/// type record that should mimic an actual variable with the
1086/// function pointer type in question.
1087///
1088/// Since the compiler can sometimes tail-merge a function call
1089/// through a function pointer, there may be more than one
1090/// S_CALLSITEINFO record at an address.  This is similar to what
1091/// you could do in your own code by:
1092///
1093/// ```text
1094///  if (expr)
1095///      pfn = &function1;
1096///  else
1097///      pfn = &function2;
1098///
1099///  (*pfn)(arg list);
1100/// ```
1101#[repr(C)]
1102#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1103#[allow(missing_docs)]
1104pub struct CallSiteInfo {
1105    pub offset: OffsetSegment,
1106    pub padding: U16<LE>,
1107    pub func_type: TypeIndexLe,
1108}
1109
1110/// `S_HEAPALLOCSITE`
1111#[repr(C)]
1112#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1113#[allow(missing_docs)]
1114pub struct HeapAllocSite {
1115    pub offset: OffsetSegment,
1116    /// length of heap allocation call instruction
1117    pub instruction_size: U16<LE>,
1118    pub func_type: TypeIndexLe,
1119}
1120
1121/// `S_ANNOTATION`
1122#[allow(missing_docs)]
1123#[derive(Clone, Debug)]
1124pub struct Annotation<'a> {
1125    pub fixed: &'a AnnotationFixed,
1126    pub strings: &'a [u8],
1127}
1128
1129#[repr(C)]
1130#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1131#[allow(missing_docs)]
1132pub struct AnnotationFixed {
1133    pub offset: OffsetSegment,
1134    pub num_strings: U16<LE>,
1135}
1136
1137impl<'a> Parse<'a> for Annotation<'a> {
1138    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1139        Ok(Self {
1140            fixed: p.get()?,
1141            strings: p.take_rest(),
1142        })
1143    }
1144}
1145
1146impl<'a> Annotation<'a> {
1147    /// Iterates the strings stored in the annotation.
1148    pub fn iter_strings(&self) -> AnnotationIterStrings<'a> {
1149        AnnotationIterStrings {
1150            num_strings: self.fixed.num_strings.get(),
1151            bytes: self.strings,
1152        }
1153    }
1154}
1155
1156/// Iterator state for [`Annotation::iter_strings`].
1157#[allow(missing_docs)]
1158pub struct AnnotationIterStrings<'a> {
1159    pub num_strings: u16,
1160    pub bytes: &'a [u8],
1161}
1162
1163impl<'a> Iterator for AnnotationIterStrings<'a> {
1164    type Item = &'a BStr;
1165
1166    fn next(&mut self) -> Option<Self::Item> {
1167        if self.num_strings == 0 {
1168            return None;
1169        }
1170
1171        self.num_strings -= 1;
1172        let mut p = Parser::new(self.bytes);
1173        let s = p.strz().ok()?;
1174        self.bytes = p.into_rest();
1175        Some(s)
1176    }
1177}
1178
1179/// Hot-patched function
1180#[derive(Clone, Debug)]
1181pub struct HotPatchFunc<'a> {
1182    /// ID of the function
1183    pub func: ItemId,
1184
1185    /// The name of the function
1186    pub name: &'a BStr,
1187}
1188
1189impl<'a> Parse<'a> for HotPatchFunc<'a> {
1190    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1191        Ok(Self {
1192            func: p.u32()?,
1193            name: p.strz()?,
1194        })
1195    }
1196}
1197
1198// Trampoline subtypes
1199
1200/// Incremental thunks
1201pub const TRAMPOLINE_KIND_INCREMENTAL: u16 = 0;
1202/// Branch island thunks
1203pub const TRAMPOLINE_KIND_BRANCH_ISLAND: u16 = 1;
1204
1205/// Parsed data from a symbol record
1206#[derive(Clone, Debug)]
1207#[allow(missing_docs)]
1208pub enum SymData<'a> {
1209    Unknown,
1210    ObjName(ObjectName<'a>),
1211    Compile3(Compile3<'a>),
1212    Proc(Proc<'a>),
1213    Udt(Udt<'a>),
1214    Constant(Constant<'a>),
1215    ManagedConstant(ManagedConstant<'a>),
1216    RefSym2(RefSym2<'a>),
1217    Data(Data<'a>),
1218    ThreadData(ThreadStorageData<'a>),
1219    Pub(Pub<'a>),
1220    End,
1221    FrameProc(&'a FrameProc),
1222    RegRel(RegRel<'a>),
1223    Block(Block<'a>),
1224    Local(Local<'a>),
1225    DefRangeFramePointerRel(DefRangeSymFramePointerRel<'a>),
1226    DefRangeRegister(DefRangeRegister<'a>),
1227    DefRangeRegisterRel(DefRangeRegisterRel<'a>),
1228    DefRangeFramePointerRelFullScope(&'a DefRangeFramePointerRelFullScope),
1229    DefRangeSubFieldRegister(DefRangeSubFieldRegister<'a>),
1230    Trampoline(Trampoline<'a>),
1231    BuildInfo(BuildInfo),
1232    UsingNamespace(UsingNamespace<'a>),
1233    InlineSiteEnd,
1234    Label(Label<'a>),
1235    FunctionList(FunctionList<'a>),
1236    InlineSite(InlineSite<'a>),
1237    InlineSite2(InlineSite2<'a>),
1238    FrameCookie(&'a FrameCookie),
1239    CallSiteInfo(&'a CallSiteInfo),
1240    HeapAllocSite(&'a HeapAllocSite),
1241    ManagedProc(ManagedProc<'a>),
1242    Annotation(Annotation<'a>),
1243    HotPatchFunc(HotPatchFunc<'a>),
1244}
1245
1246impl<'a> SymData<'a> {
1247    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1248    /// The `data` parameter does not include the length or kind.
1249    pub fn parse(kind: SymKind, data: &'a [u8]) -> Result<Self, ParserError> {
1250        let mut p = Parser::new(data);
1251        Self::from_parser(kind, &mut p)
1252    }
1253
1254    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1255    /// The `p` parameter does not include the length or kind.
1256    ///
1257    /// This function allows the caller to observe how many bytes were actually consumed from
1258    /// the input stream.
1259    pub fn from_parser(kind: SymKind, p: &mut Parser<'a>) -> Result<Self, ParserError> {
1260        Ok(match kind {
1261            SymKind::S_OBJNAME => Self::ObjName(p.parse()?),
1262            SymKind::S_GPROC32 | SymKind::S_LPROC32 => Self::Proc(p.parse()?),
1263            SymKind::S_COMPILE3 => Self::Compile3(p.parse()?),
1264            SymKind::S_UDT => Self::Udt(p.parse()?),
1265            SymKind::S_CONSTANT => Self::Constant(p.parse()?),
1266            SymKind::S_MANCONSTANT => Self::Constant(p.parse()?),
1267            SymKind::S_PUB32 => Self::Pub(p.parse()?),
1268            SymKind::S_PUB32_ST => Self::Pub(Pub::parse_st(p)?),
1269
1270            SymKind::S_PROCREF
1271            | SymKind::S_LPROCREF
1272            | SymKind::S_DATAREF
1273            | SymKind::S_ANNOTATIONREF => Self::RefSym2(p.parse()?),
1274
1275            SymKind::S_LDATA32 | SymKind::S_GDATA32 | SymKind::S_LMANDATA | SymKind::S_GMANDATA => {
1276                Self::Data(p.parse()?)
1277            }
1278
1279            SymKind::S_LTHREAD32 | SymKind::S_GTHREAD32 => Self::ThreadData(p.parse()?),
1280            SymKind::S_END => Self::End,
1281            SymKind::S_FRAMEPROC => Self::FrameProc(p.get()?),
1282            SymKind::S_REGREL32 => Self::RegRel(p.parse()?),
1283            SymKind::S_BLOCK32 => Self::Block(p.parse()?),
1284            SymKind::S_LOCAL => Self::Local(p.parse()?),
1285            SymKind::S_DEFRANGE_FRAMEPOINTER_REL => Self::DefRangeFramePointerRel(p.parse()?),
1286            SymKind::S_DEFRANGE_REGISTER => Self::DefRangeRegister(p.parse()?),
1287            SymKind::S_DEFRANGE_REGISTER_REL => Self::DefRangeRegisterRel(p.parse()?),
1288            SymKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => {
1289                Self::DefRangeFramePointerRelFullScope(p.get()?)
1290            }
1291            SymKind::S_DEFRANGE_SUBFIELD_REGISTER => Self::DefRangeSubFieldRegister(p.parse()?),
1292            SymKind::S_TRAMPOLINE => Self::Trampoline(p.parse()?),
1293            SymKind::S_BUILDINFO => Self::BuildInfo(p.parse()?),
1294            SymKind::S_UNAMESPACE => Self::UsingNamespace(p.parse()?),
1295            SymKind::S_INLINESITE_END => Self::InlineSiteEnd,
1296            SymKind::S_LABEL32 => Self::Label(p.parse()?),
1297            SymKind::S_CALLEES | SymKind::S_CALLERS => Self::FunctionList(p.parse()?),
1298            SymKind::S_INLINESITE => Self::InlineSite(p.parse()?),
1299            SymKind::S_INLINESITE2 => Self::InlineSite2(p.parse()?),
1300            SymKind::S_INLINEES => Self::FunctionList(p.parse()?),
1301            SymKind::S_FRAMECOOKIE => Self::FrameCookie(p.get()?),
1302            SymKind::S_CALLSITEINFO => Self::CallSiteInfo(p.get()?),
1303            SymKind::S_HEAPALLOCSITE => Self::HeapAllocSite(p.get()?),
1304            SymKind::S_GMANPROC | SymKind::S_LMANPROC => Self::ManagedProc(p.parse()?),
1305            SymKind::S_ANNOTATION => Self::Annotation(p.parse()?),
1306            SymKind::S_HOTPATCHFUNC => Self::HotPatchFunc(p.parse()?),
1307
1308            _ => Self::Unknown,
1309        })
1310    }
1311
1312    /// If this symbol record has a "name" field, return it. Else, `None`.
1313    pub fn name(&self) -> Option<&'a BStr> {
1314        match self {
1315            Self::Proc(proc) => Some(proc.name),
1316            Self::Data(data) => Some(data.name),
1317            Self::ThreadData(thread_data) => Some(thread_data.name),
1318            Self::Udt(udt) => Some(udt.name),
1319            Self::Local(local) => Some(local.name),
1320            Self::RefSym2(refsym) => Some(refsym.name),
1321            Self::Constant(c) => Some(c.name),
1322            Self::ManagedConstant(c) => Some(c.name),
1323            _ => None,
1324        }
1325    }
1326}