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, I32, Immutable, IntoBytes, KnownLayout, LE, U16, U32, Unaligned};
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    /// Parses the payload of the symbol with a type chosen by the caller.
286    ///
287    /// This is useful when the caller has already tested `Sym::kind` and knows the type of the
288    /// payload.
289    pub fn parse_as<T>(&self) -> Result<T, ParserError>
290    where
291        T: Parse<'a>,
292    {
293        let mut p = Parser::new(self.data);
294        p.parse::<T>()
295    }
296}
297
298impl<'a> Debug for Sym<'a> {
299    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
300        write!(fmt, "{:?}", self.kind)
301    }
302}
303
304/// Points to one symbol record in memory and gives its kind. Allows mutation of the contents of
305/// the symbol record.
306pub struct SymMut<'a> {
307    /// The kind of the symbol.
308    pub kind: SymKind,
309    /// The contents of the record. This slice does _not_ include the `len` or `kind` fields.
310    pub data: &'a mut [u8],
311}
312
313/// PUBSYM32
314///
315/// ```text
316/// typedef struct PUBSYM32 {
317///     unsigned short  reclen;     // Record length
318///     unsigned short  rectyp;     // S_PUB32
319///     CV_PUBSYMFLAGS  pubsymflags;
320///     CV_uoff32_t     off;
321///     unsigned short  seg;
322///     unsigned char   name[1];    // Length-prefixed name
323/// } PUBSYM32;
324/// ```
325#[allow(missing_docs)]
326#[derive(Clone, Debug)]
327pub struct Pub<'a> {
328    pub fixed: &'a PubFixed,
329    pub name: &'a BStr,
330}
331
332impl<'a> Pub<'a> {
333    /// Gets the `segment:offset` of this symbol.
334    pub fn offset_segment(&self) -> OffsetSegment {
335        self.fixed.offset_segment
336    }
337}
338
339#[allow(missing_docs)]
340#[repr(C)]
341#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
342pub struct PubFixed {
343    pub flags: U32<LE>,
344    pub offset_segment: OffsetSegment,
345    // name: &str
346}
347
348#[allow(missing_docs)]
349impl<'a> Parse<'a> for Pub<'a> {
350    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
351        Ok(Self {
352            fixed: p.get()?,
353            name: p.strz()?,
354        })
355    }
356}
357
358impl<'a> Pub<'a> {
359    /// Parses `S_PUB32_ST`
360    pub fn parse_st(p: &mut Parser<'a>) -> Result<Self, ParserError> {
361        Ok(Self {
362            fixed: p.get()?,
363            name: p.strt_raw()?,
364        })
365    }
366}
367
368/// Parsed form of `S_CONSTANT`
369#[allow(missing_docs)]
370#[derive(Clone, Debug)]
371pub struct Constant<'a> {
372    pub type_: TypeIndex,
373    pub value: Number<'a>,
374    pub name: &'a BStr,
375}
376
377impl<'a> Parse<'a> for Constant<'a> {
378    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
379        Ok(Self {
380            type_: p.type_index()?,
381            value: p.number()?,
382            name: p.strz()?,
383        })
384    }
385}
386
387/// Parsed form of `S_CONSTANT`
388#[allow(missing_docs)]
389#[derive(Clone, Debug)]
390pub struct ManagedConstant<'a> {
391    pub token: u32,
392    pub value: Number<'a>,
393    pub name: &'a BStr,
394}
395
396impl<'a> Parse<'a> for ManagedConstant<'a> {
397    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
398        Ok(Self {
399            token: p.u32()?,
400            value: p.number()?,
401            name: p.strz()?,
402        })
403    }
404}
405
406/// Several symbols use this structure: `S_PROCREF`, `S_LPROCREF`, `S_DATAREF`. These symbols
407/// are present in the Global Symbol Stream, not in module symbol streams.
408///
409/// These `S_*REF` symbols tell you where to find a specific global symbol, but they do not directly
410/// describe the symbol. Instead, you have to load the corresponding module
411///
412///
413#[allow(missing_docs)]
414#[derive(Clone, Debug)]
415pub struct RefSym2<'a> {
416    pub header: &'a RefSym2Fixed,
417    pub name: &'a BStr,
418}
419
420#[allow(missing_docs)]
421#[repr(C)]
422#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
423pub struct RefSym2Fixed {
424    /// Checksum of the name (called `SUC` in C++ code)
425    ///
426    /// This appears to be set to zero.
427    pub name_checksum: U32<LE>,
428
429    /// Offset of actual symbol in $$Symbols
430    ///
431    /// This is the byte offset into the module symbol stream for this symbol. The `module_index`
432    /// field tells you which symbol stream to load, to resolve this value.
433    pub symbol_offset: U32<LE>,
434
435    /// The 1-based index of the module containing the actual symbol.
436    ///
437    /// This value is 1-based. Subtract 1 from this value before indexing into a zero-based module array.
438    pub module_index: U16<LE>,
439    // pub name: strz, // hidden name made a first class member
440}
441
442impl<'a> Parse<'a> for RefSym2<'a> {
443    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
444        Ok(Self {
445            header: p.get()?,
446            name: p.strz()?,
447        })
448    }
449}
450
451#[allow(missing_docs)]
452#[repr(C)]
453#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
454pub struct ThreadStorageFixed {
455    pub type_: TypeIndexLe,
456    pub offset_segment: OffsetSegment,
457}
458
459/// Record data for `S_LTHREAD32` and `S_GTHREAD32`. These describes thread-local storage.
460///
461/// Thread-local storage is declared using `__declspec(thread)` or `thread_static`, in C++.
462#[derive(Clone, Debug)]
463pub struct ThreadStorageData<'a> {
464    #[allow(missing_docs)]
465    pub header: &'a ThreadStorageFixed,
466    #[allow(missing_docs)]
467    pub name: &'a BStr,
468}
469
470impl<'a> Parse<'a> for ThreadStorageData<'a> {
471    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
472        Ok(Self {
473            header: p.get()?,
474            name: p.strz()?,
475        })
476    }
477}
478
479#[allow(missing_docs)]
480#[repr(C)]
481#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
482pub struct DataFixed {
483    pub type_: TypeIndexLe,
484    pub offset_segment: OffsetSegment,
485}
486
487/// Record data for `S_LDATA32` and `S_GDATA32`. These describe global storage.
488#[allow(missing_docs)]
489#[derive(Clone)]
490pub struct Data<'a> {
491    pub header: &'a DataFixed,
492    pub name: &'a BStr,
493}
494
495impl<'a> Parse<'a> for Data<'a> {
496    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
497        Ok(Self {
498            header: p.get()?,
499            name: p.strz()?,
500        })
501    }
502}
503
504impl<'a> Debug for Data<'a> {
505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506        write!(
507            f,
508            "Data: {} {:?} {}",
509            self.header.offset_segment,
510            self.header.type_.get(),
511            self.name
512        )
513    }
514}
515
516/// Record data for `S_UDT` symbols
517#[derive(Clone, Debug)]
518pub struct Udt<'a> {
519    /// The type of the UDT
520    pub type_: TypeIndex,
521    /// Name
522    pub name: &'a BStr,
523}
524
525impl<'a> Parse<'a> for Udt<'a> {
526    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
527        Ok(Self {
528            type_: p.type_index()?,
529            name: p.strz()?,
530        })
531    }
532}
533
534/// `S_OBJNAME`
535#[derive(Clone, Debug)]
536pub struct ObjectName<'a> {
537    /// A robust signature that will change every time that the module will be compiled or
538    /// different in any way. It should be at least a CRC32 based upon module name and contents.
539    pub signature: u32,
540    /// Full path of the object file.
541    pub name: &'a BStr,
542}
543
544impl<'a> Parse<'a> for ObjectName<'a> {
545    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
546        Ok(Self {
547            signature: p.u32()?,
548            name: p.strz()?,
549        })
550    }
551}
552
553/// `S_COMPILE3`
554#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
555#[repr(C)]
556#[allow(missing_docs)]
557pub struct Compile3Fixed {
558    pub flags: U32<LE>,
559    pub machine: U16<LE>,
560    pub frontend_major: U16<LE>,
561    pub frontend_minor: U16<LE>,
562    pub frontend_build: U16<LE>,
563    pub frontend_qfe: U16<LE>,
564    pub ver_major: U16<LE>,
565    pub ver_minor: U16<LE>,
566    pub ver_build: U16<LE>,
567    pub ver_qfe: U16<LE>,
568    // name: strz
569}
570
571/// `S_COMPILE3`
572#[allow(missing_docs)]
573#[derive(Clone, Debug)]
574pub struct Compile3<'a> {
575    pub fixed: &'a Compile3Fixed,
576    pub name: &'a BStr,
577}
578
579impl<'a> Parse<'a> for Compile3<'a> {
580    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
581        Ok(Self {
582            fixed: p.get()?,
583            name: p.strz()?,
584        })
585    }
586}
587
588/// `S_FRAMEPROC`: This symbol is used for indicating a variety of extra information regarding a
589/// procedure and its stack frame. If any of the flags are non-zero, this record should be added
590/// to the symbols for that procedure.
591#[repr(C)]
592#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
593#[allow(missing_docs)]
594pub struct FrameProc {
595    /// Count of bytes in the whole stack frame.
596    frame_size: U32<LE>,
597    /// Count of bytes in the frame allocated as padding.
598    pad_size: U32<LE>,
599    /// Offset of pad bytes from the base of the frame.
600    pad_offset: U32<LE>,
601    /// Count of bytes in frame allocated for saved callee-save registers.
602    save_regs_size: U32<LE>,
603    offset_exception_handler: U32<LE>,
604    exception_handler_section: U16<LE>,
605    padding: U16<LE>,
606    flags: U32<LE>,
607}
608
609#[repr(C)]
610#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
611#[allow(missing_docs)]
612pub struct RegRelFixed {
613    pub offset: U32<LE>,
614    pub ty: TypeIndexLe,
615    pub register: U16<LE>,
616    // name: strz
617}
618
619/// `S_REGREGL32`: This symbol specifies symbols that are allocated relative to a register.
620/// This should be used on all platforms besides x86 and on x86 when the register is not a form of EBP.
621#[derive(Clone, Debug)]
622#[allow(missing_docs)]
623pub struct RegRel<'a> {
624    pub fixed: &'a RegRelFixed,
625    pub name: &'a BStr,
626}
627
628impl<'a> Parse<'a> for RegRel<'a> {
629    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
630        Ok(Self {
631            fixed: p.get()?,
632            name: p.strz()?,
633        })
634    }
635}
636
637/// Block Start: This symbol specifies the start of an inner block of lexically scoped symbols.
638/// The lexical scope is terminated by a matching `S_END` symbol.
639///
640/// This symbol should only be nested (directly or indirectly) within a function symbol
641/// (`S_GPROC32`, `S_LPROC32`, etc.).
642///
643/// See `BLOCKSYM32`
644#[derive(Clone, Debug)]
645#[allow(missing_docs)]
646pub struct Block<'a> {
647    pub fixed: &'a BlockFixed,
648    pub name: &'a BStr,
649}
650
651#[repr(C)]
652#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
653#[allow(missing_docs)]
654pub struct BlockFixed {
655    /// Header of the block
656    pub header: BlockHeader,
657
658    /// Length in bytes of the scope of this block within the executable code stream.
659    pub length: U32<LE>,
660
661    pub offset_segment: OffsetSegment,
662}
663
664impl<'a> Parse<'a> for Block<'a> {
665    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
666        Ok(Self {
667            fixed: p.get()?,
668            name: p.strz()?,
669        })
670    }
671}
672
673/// Local Symbol: This symbol defines a local variable.
674///
675/// This symbol must be nested (directly or indirectly) within a function symbol. It must be
676/// followed by more range descriptions.
677#[derive(Clone, Debug)]
678#[allow(missing_docs)]
679pub struct Local<'a> {
680    pub fixed: &'a LocalFixed,
681    pub name: &'a BStr,
682}
683
684#[repr(C)]
685#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
686#[allow(missing_docs)]
687pub struct LocalFixed {
688    pub ty: TypeIndexLe,
689    /// The spec says this is a 32-bit flags field, but the actual records show that this is 16-bit.
690    pub flags: U16<LE>,
691    // name: strz
692}
693
694impl<'a> Parse<'a> for Local<'a> {
695    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
696        Ok(Self {
697            fixed: p.get()?,
698            name: p.strz()?,
699        })
700    }
701}
702
703/// Represents an address range, used for optimized code debug info
704///
705/// See `CV_LVAR_ADDR_RANGE`
706#[repr(C)]
707#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
708pub struct LVarAddrRange {
709    /// Start of the address range
710    pub start: OffsetSegment,
711    /// Size of the range in bytes.
712    pub range_size: U16<LE>,
713}
714
715/// Represents the holes in overall address range, all address is pre-bbt.
716/// it is for compress and reduce the amount of relocations need.
717///
718/// See `CV_LVAR_ADDR_GAP`
719#[repr(C)]
720#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
721pub struct LVarAddrGap {
722    /// relative offset from the beginning of the live range.
723    pub gap_start_offset: U16<LE>,
724    /// length of this gap, in bytes
725    pub range_size: U16<LE>,
726}
727
728/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
729#[repr(C)]
730#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
731#[allow(missing_docs)]
732pub struct DefRangeSymFramePointerRelFixed {
733    pub offset_to_frame_pointer: U32<LE>,
734
735    /// Range of addresses where this program is valid
736    pub range: LVarAddrRange,
737}
738
739/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
740#[allow(missing_docs)]
741#[derive(Clone, Debug)]
742pub struct DefRangeSymFramePointerRel<'a> {
743    pub fixed: &'a DefRangeSymFramePointerRelFixed,
744    // The value is not available in following gaps.
745    pub gaps: &'a [LVarAddrGap],
746}
747
748impl<'a> Parse<'a> for DefRangeSymFramePointerRel<'a> {
749    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
750        let fixed = p.get()?;
751        let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
752        Ok(Self { fixed, gaps })
753    }
754}
755
756/// Attributes for a register range
757///
758/// See `CV_RANGEATTR`
759#[repr(C)]
760#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
761#[allow(missing_docs)]
762pub struct RangeAttrLe {
763    // unsigned short  maybe : 1;    // May have no user name on one of control flow path.
764    // unsigned short  padding : 15; // Padding for future use.
765    pub value: U16<LE>,
766}
767
768/// `S_DEFRANGE_REGISTER` - A live range of en-registed variable
769///
770/// See `DEFRANGESYMREGISTER`
771#[repr(C)]
772#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
773#[allow(missing_docs)]
774pub struct DefRangeRegisterFixed {
775    /// Register to hold the value of the symbol
776    pub reg: U16<LE>,
777    // Attribute of the register range.
778    pub attr: RangeAttrLe,
779}
780
781/// `S_DEFRANGE_REGISTER`
782///
783/// See `DEFRANGESYMREGISTER`
784#[derive(Clone, Debug)]
785#[allow(missing_docs)]
786pub struct DefRangeRegister<'a> {
787    pub fixed: &'a DefRangeRegisterFixed,
788    pub gaps: &'a [u8],
789}
790
791impl<'a> Parse<'a> for DefRangeRegister<'a> {
792    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
793        Ok(Self {
794            fixed: p.get()?,
795            gaps: p.take_rest(),
796        })
797    }
798}
799
800/// `S_DEFRANGE_REGISTER_REL`
801#[allow(missing_docs)]
802#[derive(Debug, Clone)]
803pub struct DefRangeRegisterRel<'a> {
804    pub fixed: &'a DefRangeRegisterRelFixed,
805
806    /// The value is not available in following gaps.
807    pub gaps: &'a [u8],
808}
809
810/// `S_DEFRANGE_REGISTER_REL`
811#[repr(C)]
812#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
813pub struct DefRangeRegisterRelFixed {
814    /// Register to hold the base pointer of the symbol
815    pub base_reg: U16<LE>,
816
817    /// ```text
818    /// unsigned short  spilledUdtMember : 1;   // Spilled member for s.i.
819    /// unsigned short  padding          : 3;   // Padding for future use.
820    /// unsigned short  offsetParent     : CV_OFFSET_PARENT_LENGTH_LIMIT;  // Offset in parent variable.
821    /// ```
822    pub flags: U16<LE>,
823
824    /// offset to register
825    pub base_pointer_offset: I32<LE>,
826
827    /// Range of addresses where this program is valid
828    pub range: LVarAddrRange,
829}
830
831impl<'a> Parse<'a> for DefRangeRegisterRel<'a> {
832    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
833        Ok(Self {
834            fixed: p.get()?,
835            gaps: p.take_rest(),
836        })
837    }
838}
839
840/// `S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE`
841///
842/// A frame variable valid in all function scope.
843#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
844#[repr(C)]
845pub struct DefRangeFramePointerRelFullScope {
846    /// offset to frame pointer
847    pub frame_pointer_offset: I32<LE>,
848}
849
850/// `S_DEFRANGE_SUBFIELD_REGISTER`
851///
852/// See `DEFRANGESYMSUBFIELDREGISTER`
853#[derive(Clone, Debug)]
854#[allow(missing_docs)]
855pub struct DefRangeSubFieldRegister<'a> {
856    pub fixed: &'a DefRangeSubFieldRegisterFixed,
857    pub gaps: &'a [u8],
858}
859
860#[repr(C)]
861#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
862#[allow(missing_docs)]
863pub struct DefRangeSubFieldRegisterFixed {
864    pub reg: U16<LE>,
865    pub attr: RangeAttrLe,
866    pub flags: U32<LE>,
867    pub range: LVarAddrRange,
868}
869
870impl<'a> Parse<'a> for DefRangeSubFieldRegister<'a> {
871    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
872        Ok(Self {
873            fixed: p.get()?,
874            gaps: p.take_rest(),
875        })
876    }
877}
878
879/// `S_GMANPROC`, `S_LMANPROC`, `S_GMANPROCIA64`, `S_LMANPROCIAC64`
880///
881/// See `MANPROCSYM`
882pub struct ManProcSym<'a> {
883    #[allow(missing_docs)]
884    pub fixed: &'a ManProcSymFixed,
885    #[allow(missing_docs)]
886    pub name: &'a BStr,
887}
888
889/// MSIL / CIL token value
890pub type TokenIdLe = U32<LE>;
891
892#[repr(C)]
893#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
894#[allow(missing_docs)]
895pub struct ManProcSymFixed {
896    pub block: BlockHeader,
897    /// pointer to next symbol
898    pub pnext: U32<LE>,
899    /// Proc length
900    pub len: U32<LE>,
901    /// Debug start offset
902    pub dbg_start: U32<LE>,
903    /// Debug end offset
904    pub dbg_end: U32<LE>,
905    // COM+ metadata token for method
906    pub token: TokenIdLe,
907    pub off: U32<LE>,
908    pub seg: U16<LE>,
909    pub flags: u8, // CV_PROCFLAGS: Proc flags
910    pub padding: u8,
911    // Register return value is in (may not be used for all archs)
912    pub ret_reg: U16<LE>,
913    // name: strz    // optional name field
914}
915
916impl<'a> Parse<'a> for ManProcSym<'a> {
917    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
918        Ok(Self {
919            fixed: p.get()?,
920            name: p.strz()?,
921        })
922    }
923}
924
925/// `S_TRAMPOLINE`
926#[derive(Clone, Debug)]
927pub struct Trampoline<'a> {
928    /// Fixed header
929    pub fixed: &'a TrampolineFixed,
930
931    /// Data whose interpretation depends on `tramp_type`
932    pub rest: &'a [u8],
933}
934
935/// `S_TRAMPOLINE`
936#[repr(C)]
937#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
938pub struct TrampolineFixed {
939    /// trampoline sym subtype
940    pub tramp_type: U16<LE>,
941    /// size of the thunk
942    pub cb_thunk: U16<LE>,
943    /// offset of the thunk
944    pub off_thunk: U32<LE>,
945    /// offset of the target of the thunk
946    pub off_target: U32<LE>,
947    /// section index of the thunk
948    pub sect_thunk: U16<LE>,
949    /// section index of the target of the thunk
950    pub sect_target: U16<LE>,
951}
952
953impl<'a> Parse<'a> for Trampoline<'a> {
954    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
955        Ok(Self {
956            fixed: p.get()?,
957            rest: p.take_rest(),
958        })
959    }
960}
961
962/// `S_BUILDINFO` - Build info for a module
963///
964/// This record is present only in module symbol streams.
965#[derive(Clone, Debug)]
966pub struct BuildInfo {
967    /// ItemId points to an `LF_BUILDINFO` record in IPI
968    pub item: ItemId,
969}
970
971impl<'a> Parse<'a> for BuildInfo {
972    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
973        Ok(Self { item: p.u32()? })
974    }
975}
976
977/// `S_UNAMESPACE` - Using Namespace
978#[derive(Clone, Debug)]
979pub struct UsingNamespace<'a> {
980    /// The namespace, e.g. `std`
981    pub namespace: &'a BStr,
982}
983
984impl<'a> Parse<'a> for UsingNamespace<'a> {
985    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
986        Ok(Self {
987            namespace: p.strz()?,
988        })
989    }
990}
991
992/// `S_LABEL32`
993#[derive(Clone, Debug)]
994#[allow(missing_docs)]
995pub struct Label<'a> {
996    pub fixed: &'a LabelFixed,
997    pub name: &'a BStr,
998}
999
1000/// `S_LABEL32`
1001#[repr(C)]
1002#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1003#[allow(missing_docs)]
1004pub struct LabelFixed {
1005    pub offset_segment: OffsetSegment,
1006    pub flags: u8,
1007}
1008
1009impl<'a> Parse<'a> for Label<'a> {
1010    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1011        Ok(Self {
1012            fixed: p.get()?,
1013            name: p.strz()?,
1014        })
1015    }
1016}
1017
1018/// Data for `S_CALLERS`, `S_CALLEES`, `S_INLINEES`.
1019#[derive(Clone, Debug)]
1020pub struct FunctionList<'a> {
1021    /// The list of functions, in the IPI. Each is either `LF_FUNC_ID` or `LF_MFUNC_ID`.
1022    pub funcs: &'a [ItemIdLe],
1023
1024    /// Counts for each function.
1025    ///
1026    /// The values in `counts` parallel the items in `funcs`, but the length of `invocations` can be
1027    /// less than the length of `funcs`. Unmatched counts are assumed to be zero.
1028    ///
1029    /// This is empty for `S_INLINEES`.
1030    pub counts: &'a [U32<LE>],
1031}
1032
1033impl<'a> Parse<'a> for FunctionList<'a> {
1034    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1035        let num_funcs = p.u32()? as usize;
1036        let funcs: &[ItemIdLe] = p.slice(num_funcs)?;
1037        let num_counts = num_funcs.min(p.len() / size_of::<U32<LE>>());
1038        let counts = p.slice(num_counts)?;
1039        Ok(Self { funcs, counts })
1040    }
1041}
1042
1043/// `S_INLINESITE`
1044#[allow(missing_docs)]
1045#[derive(Clone, Debug)]
1046pub struct InlineSite<'a> {
1047    pub fixed: &'a InlineSiteFixed,
1048    /// an array of compressed binary annotations.
1049    pub binary_annotations: &'a [u8],
1050}
1051
1052/// `S_INLINESITE`
1053#[repr(C)]
1054#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1055#[allow(missing_docs)]
1056pub struct InlineSiteFixed {
1057    pub block: BlockHeader,
1058    pub inlinee: ItemIdLe,
1059}
1060
1061impl<'a> Parse<'a> for InlineSite<'a> {
1062    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1063        Ok(Self {
1064            fixed: p.get()?,
1065            binary_annotations: p.take_rest(),
1066        })
1067    }
1068}
1069
1070/// `S_INLINESITE2`
1071#[allow(missing_docs)]
1072#[derive(Clone, Debug)]
1073pub struct InlineSite2<'a> {
1074    pub fixed: &'a InlineSite2Fixed,
1075    /// an array of compressed binary annotations.
1076    pub binary_annotations: &'a [u8],
1077}
1078
1079/// `S_INLINESITE`
1080#[repr(C)]
1081#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1082#[allow(missing_docs)]
1083pub struct InlineSite2Fixed {
1084    pub block: BlockHeader,
1085    pub inlinee: ItemIdLe,
1086    pub invocations: U32<LE>,
1087}
1088
1089impl<'a> Parse<'a> for InlineSite2<'a> {
1090    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1091        Ok(Self {
1092            fixed: p.get()?,
1093            binary_annotations: p.take_rest(),
1094        })
1095    }
1096}
1097
1098/// `S_FRAMECOOKIE`: Symbol for describing security cookie's position and type
1099// (raw, xor'd with esp, xor'd with ebp).
1100#[repr(C)]
1101#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1102#[allow(missing_docs)]
1103pub struct FrameCookie {
1104    /// Frame relative offset
1105    pub offset: I32<LE>,
1106    pub reg: U16<LE>,
1107    pub cookie_type: u8,
1108    pub flags: u8,
1109}
1110
1111/// `S_CALLSITEINFO`
1112///
1113/// Symbol for describing indirect calls when they are using
1114/// a function pointer cast on some other type or temporary.
1115/// Typical content will be an LF_POINTER to an LF_PROCEDURE
1116/// type record that should mimic an actual variable with the
1117/// function pointer type in question.
1118///
1119/// Since the compiler can sometimes tail-merge a function call
1120/// through a function pointer, there may be more than one
1121/// S_CALLSITEINFO record at an address.  This is similar to what
1122/// you could do in your own code by:
1123///
1124/// ```text
1125///  if (expr)
1126///      pfn = &function1;
1127///  else
1128///      pfn = &function2;
1129///
1130///  (*pfn)(arg list);
1131/// ```
1132#[repr(C)]
1133#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1134#[allow(missing_docs)]
1135pub struct CallSiteInfo {
1136    pub offset: OffsetSegment,
1137    pub padding: U16<LE>,
1138    pub func_type: TypeIndexLe,
1139}
1140
1141/// `S_HEAPALLOCSITE`
1142#[repr(C)]
1143#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1144#[allow(missing_docs)]
1145pub struct HeapAllocSite {
1146    pub offset: OffsetSegment,
1147    /// length of heap allocation call instruction
1148    pub instruction_size: U16<LE>,
1149    pub func_type: TypeIndexLe,
1150}
1151
1152/// `S_ANNOTATION`
1153#[allow(missing_docs)]
1154#[derive(Clone, Debug)]
1155pub struct Annotation<'a> {
1156    pub fixed: &'a AnnotationFixed,
1157    pub strings: &'a [u8],
1158}
1159
1160#[repr(C)]
1161#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1162#[allow(missing_docs)]
1163pub struct AnnotationFixed {
1164    pub offset: OffsetSegment,
1165    pub num_strings: U16<LE>,
1166}
1167
1168impl<'a> Parse<'a> for Annotation<'a> {
1169    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1170        Ok(Self {
1171            fixed: p.get()?,
1172            strings: p.take_rest(),
1173        })
1174    }
1175}
1176
1177impl<'a> Annotation<'a> {
1178    /// Iterates the strings stored in the annotation.
1179    pub fn iter_strings(&self) -> AnnotationIterStrings<'a> {
1180        AnnotationIterStrings {
1181            num_strings: self.fixed.num_strings.get(),
1182            bytes: self.strings,
1183        }
1184    }
1185}
1186
1187/// Iterator state for [`Annotation::iter_strings`].
1188#[allow(missing_docs)]
1189pub struct AnnotationIterStrings<'a> {
1190    pub num_strings: u16,
1191    pub bytes: &'a [u8],
1192}
1193
1194impl<'a> Iterator for AnnotationIterStrings<'a> {
1195    type Item = &'a BStr;
1196
1197    fn next(&mut self) -> Option<Self::Item> {
1198        if self.num_strings == 0 {
1199            return None;
1200        }
1201
1202        self.num_strings -= 1;
1203        let mut p = Parser::new(self.bytes);
1204        let s = p.strz().ok()?;
1205        self.bytes = p.into_rest();
1206        Some(s)
1207    }
1208}
1209
1210/// Hot-patched function
1211#[derive(Clone, Debug)]
1212pub struct HotPatchFunc<'a> {
1213    /// ID of the function
1214    pub func: ItemId,
1215
1216    /// The name of the function
1217    pub name: &'a BStr,
1218}
1219
1220impl<'a> Parse<'a> for HotPatchFunc<'a> {
1221    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1222        Ok(Self {
1223            func: p.u32()?,
1224            name: p.strz()?,
1225        })
1226    }
1227}
1228
1229/// Data for `S_ARMSWITCHTABLE`.
1230///
1231/// This describes a switch table (jump table).
1232///
1233/// MSVC generates this symbol only when targeting ARM64.
1234/// LLVM generates this symbol for all target architectures.
1235#[repr(C)]
1236#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone)]
1237pub struct ArmSwitchTable {
1238    /// Section-relative offset to the base for switch offsets
1239    pub offset_base: U32<LE>,
1240    /// Section index of the base for switch offsets
1241    pub sect_base: U16<LE>,
1242    /// type of each entry
1243    pub switch_type: U16<LE>,
1244    /// Section-relative offset to the table branch instruction
1245    pub offset_branch: U32<LE>,
1246    /// Section-relative offset to the start of the table
1247    pub offset_table: U32<LE>,
1248    /// Section index of the table branch instruction
1249    pub sect_branch: U16<LE>,
1250    /// Section index of the table
1251    pub sect_table: U16<LE>,
1252    /// number of switch table entries
1253    pub num_entries: U32<LE>,
1254}
1255
1256impl ArmSwitchTable {
1257    /// The `[segment:offset]` of the jump base.
1258    ///
1259    /// This is the base address of the target of the jump. The value stored within the jump table
1260    /// entry is added to this base.
1261    ///
1262    /// LLVM often generates tables where `base` and `table` have the same address, but this is
1263    /// not necessarily true for all tables.
1264    pub fn base(&self) -> OffsetSegment {
1265        OffsetSegment {
1266            offset: self.offset_base,
1267            segment: self.sect_base,
1268        }
1269    }
1270
1271    /// The `[segment:offset]` of the branch instruction.
1272    pub fn branch(&self) -> OffsetSegment {
1273        OffsetSegment {
1274            offset: self.offset_branch,
1275            segment: self.sect_branch,
1276        }
1277    }
1278
1279    /// The `[segment:offset]` of the jump table.
1280    pub fn table(&self) -> OffsetSegment {
1281        OffsetSegment {
1282            offset: self.offset_table,
1283            segment: self.sect_table,
1284        }
1285    }
1286
1287    /// The type of switch table (2-byte, 4-byte, etc.).
1288    pub fn switch_type(&self) -> ArmSwitchType {
1289        ArmSwitchType(self.switch_type.get())
1290    }
1291
1292    /// The number of entries in the jump table.
1293    pub fn num_entries(&self) -> u32 {
1294        self.num_entries.get()
1295    }
1296}
1297
1298impl core::fmt::Debug for ArmSwitchTable {
1299    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1300        f.debug_struct("ArmSwitchTable")
1301            .field("base", &self.base())
1302            .field("branch", &self.branch())
1303            .field("table", &self.table())
1304            .field("switch_type", &self.switch_type())
1305            .field("num_entries", &self.num_entries())
1306            .finish()
1307    }
1308}
1309
1310/// The type of switch table, as defined by `S_ARMSWITCHTABLE`.
1311#[derive(Copy, Clone, Eq, PartialEq)]
1312pub struct ArmSwitchType(pub u16);
1313
1314impl ArmSwitchType {
1315    /// Signed 1-byte offset
1316    pub const INT1: ArmSwitchType = ArmSwitchType(0);
1317    /// Unsigned 1-byte offset
1318    pub const UINT1: ArmSwitchType = ArmSwitchType(1);
1319    /// Signed 2-byte offset
1320    pub const INT2: ArmSwitchType = ArmSwitchType(2);
1321    /// Unsigned 2-byte offset
1322    pub const UINT2: ArmSwitchType = ArmSwitchType(3);
1323    /// Signed 4-byte offset
1324    pub const INT4: ArmSwitchType = ArmSwitchType(4);
1325    /// Unsigned 4-byte offset
1326    pub const UINT4: ArmSwitchType = ArmSwitchType(5);
1327    /// Absolute pointer (no base)
1328    pub const POINTER: ArmSwitchType = ArmSwitchType(6);
1329    /// Unsigned 1-byte offset, shift left by 1
1330    pub const UINT1SHL1: ArmSwitchType = ArmSwitchType(7);
1331    /// Unsigned 2-byte offset, shift left by 2
1332    pub const UINT2SHL1: ArmSwitchType = ArmSwitchType(8);
1333    /// Signed 1-byte offset, shift left by 1
1334    pub const INT1SHL1: ArmSwitchType = ArmSwitchType(9);
1335    /// Signed 2-byte offset, shift left by 1
1336    pub const INT2SHL1: ArmSwitchType = ArmSwitchType(10);
1337    // CV_SWT_TBB          = CV_SWT_UINT1SHL1,
1338    // CV_SWT_TBH          = CV_SWT_UINT2SHL1,
1339}
1340
1341impl core::fmt::Debug for ArmSwitchType {
1342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1343        static NAMES: [&str; 11] = [
1344            "INT1",
1345            "UINT1",
1346            "INT2",
1347            "UINT2",
1348            "INT4",
1349            "UINT4",
1350            "POINTER",
1351            "UINT1SHL1",
1352            "UINT2SHL1",
1353            "INT1SHL1",
1354            "INT2SHL1",
1355        ];
1356
1357        if let Some(&s) = NAMES.get(self.0 as usize) {
1358            f.write_str(s)
1359        } else {
1360            write!(f, "??{}", self.0)
1361        }
1362    }
1363}
1364
1365// Trampoline subtypes
1366
1367/// Incremental thunks
1368pub const TRAMPOLINE_KIND_INCREMENTAL: u16 = 0;
1369/// Branch island thunks
1370pub const TRAMPOLINE_KIND_BRANCH_ISLAND: u16 = 1;
1371
1372/// The fixed header of `S_COFFGROUP` symbols.
1373#[repr(C)]
1374#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1375pub struct CoffGroupFixed {
1376    /// Size in bytes of the coff group
1377    pub cb: U32<LE>,
1378    /// Characteristics flags. These are the same as the COFF section characteristics.
1379    ///
1380    /// See: <https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header>
1381    pub characteristics: U32<LE>,
1382    /// Location of the COFF group
1383    pub off_seg: OffsetSegment,
1384}
1385
1386/// For `S_COFFGROUP`.
1387///
1388/// `S_COFFGROUP` records are present in the `* Linker *` special module. These records describe
1389/// contiguous subsections within COFF sections. For example, `.text$mn` is a COFF group within
1390/// the `.text` segment.
1391#[derive(Clone, Debug)]
1392pub struct CoffGroup<'a> {
1393    /// The fixed-size header
1394    pub fixed: &'a CoffGroupFixed,
1395    /// The name of the COFF group
1396    pub name: &'a BStr,
1397}
1398
1399impl<'a> Parse<'a> for CoffGroup<'a> {
1400    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1401        Ok(Self {
1402            fixed: p.get()?,
1403            name: p.strz()?,
1404        })
1405    }
1406}
1407
1408/// For `S_SECTION`
1409#[derive(Clone, Debug)]
1410pub struct Section<'a> {
1411    /// The fixed-size header
1412    pub fixed: &'a SectionFixed,
1413    /// The name of the section
1414    pub name: &'a BStr,
1415}
1416
1417/// The fixed header of `S_SECTION` symbols.
1418#[repr(C)]
1419#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1420pub struct SectionFixed {
1421    /// Section number
1422    pub section: U16<LE>,
1423    /// Alignment of this section (power of 2)
1424    pub align: u8,
1425    /// Reserved
1426    pub reserved: u8,
1427    /// RVA of this section base
1428    pub rva: U32<LE>,
1429    /// Size in bytes of this section
1430    pub cb: U32<LE>,
1431    /// Section characteristics (bit flags)
1432    pub characteristics: U32<LE>,
1433}
1434
1435impl<'a> Parse<'a> for Section<'a> {
1436    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1437        Ok(Self {
1438            fixed: p.get()?,
1439            name: p.strz()?,
1440        })
1441    }
1442}
1443
1444/// Parsed data from a symbol record
1445#[derive(Clone, Debug)]
1446#[allow(missing_docs)]
1447pub enum SymData<'a> {
1448    Unknown,
1449    ObjName(ObjectName<'a>),
1450    Compile3(Compile3<'a>),
1451    Proc(Proc<'a>),
1452    Udt(Udt<'a>),
1453    Constant(Constant<'a>),
1454    ManagedConstant(ManagedConstant<'a>),
1455    RefSym2(RefSym2<'a>),
1456    Data(Data<'a>),
1457    ThreadData(ThreadStorageData<'a>),
1458    Pub(Pub<'a>),
1459    End,
1460    FrameProc(&'a FrameProc),
1461    RegRel(RegRel<'a>),
1462    Block(Block<'a>),
1463    Local(Local<'a>),
1464    DefRangeFramePointerRel(DefRangeSymFramePointerRel<'a>),
1465    DefRangeRegister(DefRangeRegister<'a>),
1466    DefRangeRegisterRel(DefRangeRegisterRel<'a>),
1467    DefRangeFramePointerRelFullScope(&'a DefRangeFramePointerRelFullScope),
1468    DefRangeSubFieldRegister(DefRangeSubFieldRegister<'a>),
1469    Trampoline(Trampoline<'a>),
1470    BuildInfo(BuildInfo),
1471    UsingNamespace(UsingNamespace<'a>),
1472    InlineSiteEnd,
1473    Label(Label<'a>),
1474    FunctionList(FunctionList<'a>),
1475    InlineSite(InlineSite<'a>),
1476    InlineSite2(InlineSite2<'a>),
1477    FrameCookie(&'a FrameCookie),
1478    CallSiteInfo(&'a CallSiteInfo),
1479    HeapAllocSite(&'a HeapAllocSite),
1480    ManagedProc(ManagedProc<'a>),
1481    Annotation(Annotation<'a>),
1482    HotPatchFunc(HotPatchFunc<'a>),
1483    CoffGroup(CoffGroup<'a>),
1484    ArmSwitchTable(&'a ArmSwitchTable),
1485    Section(Section<'a>),
1486}
1487
1488impl<'a> SymData<'a> {
1489    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1490    /// The `data` parameter does not include the length or kind.
1491    pub fn parse(kind: SymKind, data: &'a [u8]) -> Result<Self, ParserError> {
1492        let mut p = Parser::new(data);
1493        Self::from_parser(kind, &mut p)
1494    }
1495
1496    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1497    /// The `p` parameter does not include the length or kind.
1498    ///
1499    /// This function allows the caller to observe how many bytes were actually consumed from
1500    /// the input stream.
1501    pub fn from_parser(kind: SymKind, p: &mut Parser<'a>) -> Result<Self, ParserError> {
1502        Ok(match kind {
1503            SymKind::S_OBJNAME => Self::ObjName(p.parse()?),
1504            SymKind::S_GPROC32 | SymKind::S_LPROC32 => Self::Proc(p.parse()?),
1505            SymKind::S_COMPILE3 => Self::Compile3(p.parse()?),
1506            SymKind::S_UDT => Self::Udt(p.parse()?),
1507            SymKind::S_CONSTANT => Self::Constant(p.parse()?),
1508            SymKind::S_MANCONSTANT => Self::Constant(p.parse()?),
1509            SymKind::S_PUB32 => Self::Pub(p.parse()?),
1510            SymKind::S_PUB32_ST => Self::Pub(Pub::parse_st(p)?),
1511
1512            SymKind::S_PROCREF
1513            | SymKind::S_LPROCREF
1514            | SymKind::S_DATAREF
1515            | SymKind::S_ANNOTATIONREF => Self::RefSym2(p.parse()?),
1516
1517            SymKind::S_LDATA32 | SymKind::S_GDATA32 | SymKind::S_LMANDATA | SymKind::S_GMANDATA => {
1518                Self::Data(p.parse()?)
1519            }
1520
1521            SymKind::S_LTHREAD32 | SymKind::S_GTHREAD32 => Self::ThreadData(p.parse()?),
1522            SymKind::S_END => Self::End,
1523            SymKind::S_FRAMEPROC => Self::FrameProc(p.get()?),
1524            SymKind::S_REGREL32 => Self::RegRel(p.parse()?),
1525            SymKind::S_BLOCK32 => Self::Block(p.parse()?),
1526            SymKind::S_LOCAL => Self::Local(p.parse()?),
1527            SymKind::S_DEFRANGE_FRAMEPOINTER_REL => Self::DefRangeFramePointerRel(p.parse()?),
1528            SymKind::S_DEFRANGE_REGISTER => Self::DefRangeRegister(p.parse()?),
1529            SymKind::S_DEFRANGE_REGISTER_REL => Self::DefRangeRegisterRel(p.parse()?),
1530            SymKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => {
1531                Self::DefRangeFramePointerRelFullScope(p.get()?)
1532            }
1533            SymKind::S_DEFRANGE_SUBFIELD_REGISTER => Self::DefRangeSubFieldRegister(p.parse()?),
1534            SymKind::S_TRAMPOLINE => Self::Trampoline(p.parse()?),
1535            SymKind::S_BUILDINFO => Self::BuildInfo(p.parse()?),
1536            SymKind::S_UNAMESPACE => Self::UsingNamespace(p.parse()?),
1537            SymKind::S_INLINESITE_END => Self::InlineSiteEnd,
1538            SymKind::S_LABEL32 => Self::Label(p.parse()?),
1539            SymKind::S_CALLEES | SymKind::S_CALLERS => Self::FunctionList(p.parse()?),
1540            SymKind::S_INLINESITE => Self::InlineSite(p.parse()?),
1541            SymKind::S_INLINESITE2 => Self::InlineSite2(p.parse()?),
1542            SymKind::S_INLINEES => Self::FunctionList(p.parse()?),
1543            SymKind::S_FRAMECOOKIE => Self::FrameCookie(p.get()?),
1544            SymKind::S_CALLSITEINFO => Self::CallSiteInfo(p.get()?),
1545            SymKind::S_HEAPALLOCSITE => Self::HeapAllocSite(p.get()?),
1546            SymKind::S_GMANPROC | SymKind::S_LMANPROC => Self::ManagedProc(p.parse()?),
1547            SymKind::S_ANNOTATION => Self::Annotation(p.parse()?),
1548            SymKind::S_HOTPATCHFUNC => Self::HotPatchFunc(p.parse()?),
1549            SymKind::S_ARMSWITCHTABLE => Self::ArmSwitchTable(p.get()?),
1550            SymKind::S_COFFGROUP => Self::CoffGroup(p.parse()?),
1551            SymKind::S_SECTION => Self::Section(p.parse()?),
1552
1553            _ => Self::Unknown,
1554        })
1555    }
1556
1557    /// If this symbol record has a "name" field, return it. Else, `None`.
1558    pub fn name(&self) -> Option<&'a BStr> {
1559        match self {
1560            Self::Proc(proc) => Some(proc.name),
1561            Self::Data(data) => Some(data.name),
1562            Self::ThreadData(thread_data) => Some(thread_data.name),
1563            Self::Udt(udt) => Some(udt.name),
1564            Self::Local(local) => Some(local.name),
1565            Self::RefSym2(refsym) => Some(refsym.name),
1566            Self::Constant(c) => Some(c.name),
1567            Self::ManagedConstant(c) => Some(c.name),
1568            _ => None,
1569        }
1570    }
1571}