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