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