Skip to main content

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#[repr(C)]
729#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
730#[allow(missing_docs)]
731pub struct DefRangeFixed {
732    /// DIA program to evaluate the value of the symbol
733    pub program: U32<LE>,
734
735    pub range: LVarAddrRange,
736    // gaps: [LVAddrGap]
737}
738
739/// `S_DEFRANGE`
740#[allow(missing_docs)]
741#[derive(Clone, Debug)]
742pub struct DefRange<'a> {
743    pub fixed: &'a DefRangeFixed,
744    pub gaps: &'a [LVarAddrGap],
745}
746
747impl<'a> Parse<'a> for DefRange<'a> {
748    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
749        let fixed = p.get()?;
750        let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
751        Ok(Self { fixed, gaps })
752    }
753}
754
755/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
756#[repr(C)]
757#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
758#[allow(missing_docs)]
759pub struct DefRangeSymFramePointerRelFixed {
760    pub offset_to_frame_pointer: U32<LE>,
761
762    /// Range of addresses where this program is valid
763    pub range: LVarAddrRange,
764}
765
766/// `S_DEFRANGE_FRAMEPOINTER_REL`: A live range of frame variable
767#[allow(missing_docs)]
768#[derive(Clone, Debug)]
769pub struct DefRangeSymFramePointerRel<'a> {
770    pub fixed: &'a DefRangeSymFramePointerRelFixed,
771    // The value is not available in following gaps.
772    pub gaps: &'a [LVarAddrGap],
773}
774
775impl<'a> Parse<'a> for DefRangeSymFramePointerRel<'a> {
776    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
777        let fixed = p.get()?;
778        let gaps = p.slice(p.len() / size_of::<LVarAddrGap>())?;
779        Ok(Self { fixed, gaps })
780    }
781}
782
783/// Attributes for a register range
784///
785/// See `CV_RANGEATTR`
786#[repr(C)]
787#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
788#[allow(missing_docs)]
789pub struct RangeAttrLe {
790    // unsigned short  maybe : 1;    // May have no user name on one of control flow path.
791    // unsigned short  padding : 15; // Padding for future use.
792    pub value: U16<LE>,
793}
794
795/// `S_DEFRANGE_REGISTER` - A live range of en-registed variable
796///
797/// See `DEFRANGESYMREGISTER`
798#[repr(C)]
799#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
800#[allow(missing_docs)]
801pub struct DefRangeRegisterFixed {
802    /// Register to hold the value of the symbol
803    pub reg: U16<LE>,
804    // Attribute of the register range.
805    pub attr: RangeAttrLe,
806}
807
808/// `S_DEFRANGE_REGISTER`
809///
810/// See `DEFRANGESYMREGISTER`
811#[derive(Clone, Debug)]
812#[allow(missing_docs)]
813pub struct DefRangeRegister<'a> {
814    pub fixed: &'a DefRangeRegisterFixed,
815    pub gaps: &'a [u8],
816}
817
818impl<'a> Parse<'a> for DefRangeRegister<'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_DEFRANGE_REGISTER_REL`
828#[allow(missing_docs)]
829#[derive(Debug, Clone)]
830pub struct DefRangeRegisterRel<'a> {
831    pub fixed: &'a DefRangeRegisterRelFixed,
832
833    /// The value is not available in following gaps.
834    pub gaps: &'a [u8],
835}
836
837/// `S_DEFRANGE_REGISTER_REL`
838#[repr(C)]
839#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
840pub struct DefRangeRegisterRelFixed {
841    /// Register to hold the base pointer of the symbol
842    pub base_reg: U16<LE>,
843
844    /// ```text
845    /// unsigned short  spilledUdtMember : 1;   // Spilled member for s.i.
846    /// unsigned short  padding          : 3;   // Padding for future use.
847    /// unsigned short  offsetParent     : CV_OFFSET_PARENT_LENGTH_LIMIT;  // Offset in parent variable.
848    /// ```
849    pub flags: U16<LE>,
850
851    /// offset to register
852    pub base_pointer_offset: I32<LE>,
853
854    /// Range of addresses where this program is valid
855    pub range: LVarAddrRange,
856}
857
858impl<'a> Parse<'a> for DefRangeRegisterRel<'a> {
859    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
860        Ok(Self {
861            fixed: p.get()?,
862            gaps: p.take_rest(),
863        })
864    }
865}
866
867/// `S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE`
868///
869/// A frame variable valid in all function scope.
870#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
871#[repr(C)]
872pub struct DefRangeFramePointerRelFullScope {
873    /// offset to frame pointer
874    pub frame_pointer_offset: I32<LE>,
875}
876
877/// `S_DEFRANGE_SUBFIELD_REGISTER`
878///
879/// See `DEFRANGESYMSUBFIELDREGISTER`
880#[derive(Clone, Debug)]
881#[allow(missing_docs)]
882pub struct DefRangeSubFieldRegister<'a> {
883    pub fixed: &'a DefRangeSubFieldRegisterFixed,
884    pub gaps: &'a [u8],
885}
886
887#[repr(C)]
888#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
889#[allow(missing_docs)]
890pub struct DefRangeSubFieldRegisterFixed {
891    pub reg: U16<LE>,
892    pub attr: RangeAttrLe,
893    pub flags: U32<LE>,
894    pub range: LVarAddrRange,
895}
896
897impl<'a> Parse<'a> for DefRangeSubFieldRegister<'a> {
898    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
899        Ok(Self {
900            fixed: p.get()?,
901            gaps: p.take_rest(),
902        })
903    }
904}
905
906/// `S_GMANPROC`, `S_LMANPROC`, `S_GMANPROCIA64`, `S_LMANPROCIAC64`
907///
908/// See `MANPROCSYM`
909pub struct ManProcSym<'a> {
910    #[allow(missing_docs)]
911    pub fixed: &'a ManProcSymFixed,
912    #[allow(missing_docs)]
913    pub name: &'a BStr,
914}
915
916/// MSIL / CIL token value
917pub type TokenIdLe = U32<LE>;
918
919#[repr(C)]
920#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
921#[allow(missing_docs)]
922pub struct ManProcSymFixed {
923    pub block: BlockHeader,
924    /// pointer to next symbol
925    pub pnext: U32<LE>,
926    /// Proc length
927    pub len: U32<LE>,
928    /// Debug start offset
929    pub dbg_start: U32<LE>,
930    /// Debug end offset
931    pub dbg_end: U32<LE>,
932    // COM+ metadata token for method
933    pub token: TokenIdLe,
934    pub off: U32<LE>,
935    pub seg: U16<LE>,
936    pub flags: u8, // CV_PROCFLAGS: Proc flags
937    pub padding: u8,
938    // Register return value is in (may not be used for all archs)
939    pub ret_reg: U16<LE>,
940    // name: strz    // optional name field
941}
942
943impl<'a> Parse<'a> for ManProcSym<'a> {
944    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
945        Ok(Self {
946            fixed: p.get()?,
947            name: p.strz()?,
948        })
949    }
950}
951
952/// `S_TRAMPOLINE`
953#[derive(Clone, Debug)]
954pub struct Trampoline<'a> {
955    /// Fixed header
956    pub fixed: &'a TrampolineFixed,
957
958    /// Data whose interpretation depends on `tramp_type`
959    pub rest: &'a [u8],
960}
961
962/// `S_TRAMPOLINE`
963#[repr(C)]
964#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone, Debug)]
965pub struct TrampolineFixed {
966    /// trampoline sym subtype
967    pub tramp_type: U16<LE>,
968    /// size of the thunk
969    pub cb_thunk: U16<LE>,
970    /// offset of the thunk
971    pub off_thunk: U32<LE>,
972    /// offset of the target of the thunk
973    pub off_target: U32<LE>,
974    /// section index of the thunk
975    pub sect_thunk: U16<LE>,
976    /// section index of the target of the thunk
977    pub sect_target: U16<LE>,
978}
979
980impl<'a> Parse<'a> for Trampoline<'a> {
981    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
982        Ok(Self {
983            fixed: p.get()?,
984            rest: p.take_rest(),
985        })
986    }
987}
988
989/// `S_BUILDINFO` - Build info for a module
990///
991/// This record is present only in module symbol streams.
992#[derive(Clone, Debug)]
993pub struct BuildInfo {
994    /// ItemId points to an `LF_BUILDINFO` record in IPI
995    pub item: ItemId,
996}
997
998impl<'a> Parse<'a> for BuildInfo {
999    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1000        Ok(Self { item: p.u32()? })
1001    }
1002}
1003
1004/// `S_UNAMESPACE` - Using Namespace
1005#[derive(Clone, Debug)]
1006pub struct UsingNamespace<'a> {
1007    /// The namespace, e.g. `std`
1008    pub namespace: &'a BStr,
1009}
1010
1011impl<'a> Parse<'a> for UsingNamespace<'a> {
1012    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1013        Ok(Self {
1014            namespace: p.strz()?,
1015        })
1016    }
1017}
1018
1019/// `S_LABEL32`
1020#[derive(Clone, Debug)]
1021#[allow(missing_docs)]
1022pub struct Label<'a> {
1023    pub fixed: &'a LabelFixed,
1024    pub name: &'a BStr,
1025}
1026
1027/// `S_LABEL32`
1028#[repr(C)]
1029#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1030#[allow(missing_docs)]
1031pub struct LabelFixed {
1032    pub offset_segment: OffsetSegment,
1033    pub flags: u8,
1034}
1035
1036impl<'a> Parse<'a> for Label<'a> {
1037    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1038        Ok(Self {
1039            fixed: p.get()?,
1040            name: p.strz()?,
1041        })
1042    }
1043}
1044
1045/// Data for `S_CALLERS`, `S_CALLEES`, `S_INLINEES`.
1046#[derive(Clone, Debug)]
1047pub struct FunctionList<'a> {
1048    /// The list of functions, in the IPI. Each is either `LF_FUNC_ID` or `LF_MFUNC_ID`.
1049    pub funcs: &'a [ItemIdLe],
1050
1051    /// Counts for each function.
1052    ///
1053    /// The values in `counts` parallel the items in `funcs`, but the length of `invocations` can be
1054    /// less than the length of `funcs`. Unmatched counts are assumed to be zero.
1055    ///
1056    /// This is empty for `S_INLINEES`.
1057    pub counts: &'a [U32<LE>],
1058}
1059
1060impl<'a> Parse<'a> for FunctionList<'a> {
1061    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1062        let num_funcs = p.u32()? as usize;
1063        let funcs: &[ItemIdLe] = p.slice(num_funcs)?;
1064        let num_counts = num_funcs.min(p.len() / size_of::<U32<LE>>());
1065        let counts = p.slice(num_counts)?;
1066        Ok(Self { funcs, counts })
1067    }
1068}
1069
1070/// `S_INLINESITE`
1071#[allow(missing_docs)]
1072#[derive(Clone, Debug)]
1073pub struct InlineSite<'a> {
1074    pub fixed: &'a InlineSiteFixed,
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 InlineSiteFixed {
1084    pub block: BlockHeader,
1085    pub inlinee: ItemIdLe,
1086}
1087
1088impl<'a> Parse<'a> for InlineSite<'a> {
1089    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1090        Ok(Self {
1091            fixed: p.get()?,
1092            binary_annotations: p.take_rest(),
1093        })
1094    }
1095}
1096
1097/// `S_INLINESITE2`
1098#[allow(missing_docs)]
1099#[derive(Clone, Debug)]
1100pub struct InlineSite2<'a> {
1101    pub fixed: &'a InlineSite2Fixed,
1102    /// an array of compressed binary annotations.
1103    pub binary_annotations: &'a [u8],
1104}
1105
1106/// `S_INLINESITE`
1107#[repr(C)]
1108#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1109#[allow(missing_docs)]
1110pub struct InlineSite2Fixed {
1111    pub block: BlockHeader,
1112    pub inlinee: ItemIdLe,
1113    pub invocations: U32<LE>,
1114}
1115
1116impl<'a> Parse<'a> for InlineSite2<'a> {
1117    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1118        Ok(Self {
1119            fixed: p.get()?,
1120            binary_annotations: p.take_rest(),
1121        })
1122    }
1123}
1124
1125/// `S_FRAMECOOKIE`: Symbol for describing security cookie's position and type
1126// (raw, xor'd with esp, xor'd with ebp).
1127#[repr(C)]
1128#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1129#[allow(missing_docs)]
1130pub struct FrameCookie {
1131    /// Frame relative offset
1132    pub offset: I32<LE>,
1133    pub reg: U16<LE>,
1134    pub cookie_type: u8,
1135    pub flags: u8,
1136}
1137
1138/// `S_CALLSITEINFO`
1139///
1140/// Symbol for describing indirect calls when they are using
1141/// a function pointer cast on some other type or temporary.
1142/// Typical content will be an LF_POINTER to an LF_PROCEDURE
1143/// type record that should mimic an actual variable with the
1144/// function pointer type in question.
1145///
1146/// Since the compiler can sometimes tail-merge a function call
1147/// through a function pointer, there may be more than one
1148/// S_CALLSITEINFO record at an address.  This is similar to what
1149/// you could do in your own code by:
1150///
1151/// ```text
1152///  if (expr)
1153///      pfn = &function1;
1154///  else
1155///      pfn = &function2;
1156///
1157///  (*pfn)(arg list);
1158/// ```
1159#[repr(C)]
1160#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1161#[allow(missing_docs)]
1162pub struct CallSiteInfo {
1163    pub offset: OffsetSegment,
1164    pub padding: U16<LE>,
1165    pub func_type: TypeIndexLe,
1166}
1167
1168/// `S_HEAPALLOCSITE`
1169#[repr(C)]
1170#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1171#[allow(missing_docs)]
1172pub struct HeapAllocSite {
1173    pub offset: OffsetSegment,
1174    /// length of heap allocation call instruction
1175    pub instruction_size: U16<LE>,
1176    pub func_type: TypeIndexLe,
1177}
1178
1179/// `S_ANNOTATION`
1180#[allow(missing_docs)]
1181#[derive(Clone, Debug)]
1182pub struct Annotation<'a> {
1183    pub fixed: &'a AnnotationFixed,
1184    pub strings: &'a [u8],
1185}
1186
1187#[repr(C)]
1188#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1189#[allow(missing_docs)]
1190pub struct AnnotationFixed {
1191    pub offset: OffsetSegment,
1192    pub num_strings: U16<LE>,
1193}
1194
1195impl<'a> Parse<'a> for Annotation<'a> {
1196    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1197        Ok(Self {
1198            fixed: p.get()?,
1199            strings: p.take_rest(),
1200        })
1201    }
1202}
1203
1204impl<'a> Annotation<'a> {
1205    /// Iterates the strings stored in the annotation.
1206    pub fn iter_strings(&self) -> AnnotationIterStrings<'a> {
1207        AnnotationIterStrings {
1208            num_strings: self.fixed.num_strings.get(),
1209            bytes: self.strings,
1210        }
1211    }
1212}
1213
1214/// Iterator state for [`Annotation::iter_strings`].
1215#[allow(missing_docs)]
1216pub struct AnnotationIterStrings<'a> {
1217    pub num_strings: u16,
1218    pub bytes: &'a [u8],
1219}
1220
1221impl<'a> Iterator for AnnotationIterStrings<'a> {
1222    type Item = &'a BStr;
1223
1224    fn next(&mut self) -> Option<Self::Item> {
1225        if self.num_strings == 0 {
1226            return None;
1227        }
1228
1229        self.num_strings -= 1;
1230        let mut p = Parser::new(self.bytes);
1231        let s = p.strz().ok()?;
1232        self.bytes = p.into_rest();
1233        Some(s)
1234    }
1235}
1236
1237/// Hot-patched function
1238#[derive(Clone, Debug)]
1239pub struct HotPatchFunc<'a> {
1240    /// ID of the function
1241    pub func: ItemId,
1242
1243    /// The name of the function
1244    pub name: &'a BStr,
1245}
1246
1247impl<'a> Parse<'a> for HotPatchFunc<'a> {
1248    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1249        Ok(Self {
1250            func: p.u32()?,
1251            name: p.strz()?,
1252        })
1253    }
1254}
1255
1256/// Data for `S_ARMSWITCHTABLE`.
1257///
1258/// This describes a switch table (jump table).
1259///
1260/// MSVC generates this symbol only when targeting ARM64.
1261/// LLVM generates this symbol for all target architectures.
1262#[repr(C)]
1263#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Clone)]
1264pub struct ArmSwitchTable {
1265    /// Section-relative offset to the base for switch offsets
1266    pub offset_base: U32<LE>,
1267    /// Section index of the base for switch offsets
1268    pub sect_base: U16<LE>,
1269    /// type of each entry
1270    pub switch_type: U16<LE>,
1271    /// Section-relative offset to the table branch instruction
1272    pub offset_branch: U32<LE>,
1273    /// Section-relative offset to the start of the table
1274    pub offset_table: U32<LE>,
1275    /// Section index of the table branch instruction
1276    pub sect_branch: U16<LE>,
1277    /// Section index of the table
1278    pub sect_table: U16<LE>,
1279    /// number of switch table entries
1280    pub num_entries: U32<LE>,
1281}
1282
1283impl ArmSwitchTable {
1284    /// The `[segment:offset]` of the jump base.
1285    ///
1286    /// This is the base address of the target of the jump. The value stored within the jump table
1287    /// entry is added to this base.
1288    ///
1289    /// LLVM often generates tables where `base` and `table` have the same address, but this is
1290    /// not necessarily true for all tables.
1291    pub fn base(&self) -> OffsetSegment {
1292        OffsetSegment {
1293            offset: self.offset_base,
1294            segment: self.sect_base,
1295        }
1296    }
1297
1298    /// The `[segment:offset]` of the branch instruction.
1299    pub fn branch(&self) -> OffsetSegment {
1300        OffsetSegment {
1301            offset: self.offset_branch,
1302            segment: self.sect_branch,
1303        }
1304    }
1305
1306    /// The `[segment:offset]` of the jump table.
1307    pub fn table(&self) -> OffsetSegment {
1308        OffsetSegment {
1309            offset: self.offset_table,
1310            segment: self.sect_table,
1311        }
1312    }
1313
1314    /// The type of switch table (2-byte, 4-byte, etc.).
1315    pub fn switch_type(&self) -> ArmSwitchType {
1316        ArmSwitchType(self.switch_type.get())
1317    }
1318
1319    /// The number of entries in the jump table.
1320    pub fn num_entries(&self) -> u32 {
1321        self.num_entries.get()
1322    }
1323}
1324
1325impl core::fmt::Debug for ArmSwitchTable {
1326    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1327        f.debug_struct("ArmSwitchTable")
1328            .field("base", &self.base())
1329            .field("branch", &self.branch())
1330            .field("table", &self.table())
1331            .field("switch_type", &self.switch_type())
1332            .field("num_entries", &self.num_entries())
1333            .finish()
1334    }
1335}
1336
1337/// The type of switch table, as defined by `S_ARMSWITCHTABLE`.
1338#[derive(Copy, Clone, Eq, PartialEq)]
1339pub struct ArmSwitchType(pub u16);
1340
1341impl ArmSwitchType {
1342    /// Signed 1-byte offset
1343    pub const INT1: ArmSwitchType = ArmSwitchType(0);
1344    /// Unsigned 1-byte offset
1345    pub const UINT1: ArmSwitchType = ArmSwitchType(1);
1346    /// Signed 2-byte offset
1347    pub const INT2: ArmSwitchType = ArmSwitchType(2);
1348    /// Unsigned 2-byte offset
1349    pub const UINT2: ArmSwitchType = ArmSwitchType(3);
1350    /// Signed 4-byte offset
1351    pub const INT4: ArmSwitchType = ArmSwitchType(4);
1352    /// Unsigned 4-byte offset
1353    pub const UINT4: ArmSwitchType = ArmSwitchType(5);
1354    /// Absolute pointer (no base)
1355    pub const POINTER: ArmSwitchType = ArmSwitchType(6);
1356    /// Unsigned 1-byte offset, shift left by 1
1357    pub const UINT1SHL1: ArmSwitchType = ArmSwitchType(7);
1358    /// Unsigned 2-byte offset, shift left by 2
1359    pub const UINT2SHL1: ArmSwitchType = ArmSwitchType(8);
1360    /// Signed 1-byte offset, shift left by 1
1361    pub const INT1SHL1: ArmSwitchType = ArmSwitchType(9);
1362    /// Signed 2-byte offset, shift left by 1
1363    pub const INT2SHL1: ArmSwitchType = ArmSwitchType(10);
1364    // CV_SWT_TBB          = CV_SWT_UINT1SHL1,
1365    // CV_SWT_TBH          = CV_SWT_UINT2SHL1,
1366}
1367
1368impl core::fmt::Debug for ArmSwitchType {
1369    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1370        static NAMES: [&str; 11] = [
1371            "INT1",
1372            "UINT1",
1373            "INT2",
1374            "UINT2",
1375            "INT4",
1376            "UINT4",
1377            "POINTER",
1378            "UINT1SHL1",
1379            "UINT2SHL1",
1380            "INT1SHL1",
1381            "INT2SHL1",
1382        ];
1383
1384        if let Some(&s) = NAMES.get(self.0 as usize) {
1385            f.write_str(s)
1386        } else {
1387            write!(f, "??{}", self.0)
1388        }
1389    }
1390}
1391
1392// Trampoline subtypes
1393
1394/// Incremental thunks
1395pub const TRAMPOLINE_KIND_INCREMENTAL: u16 = 0;
1396/// Branch island thunks
1397pub const TRAMPOLINE_KIND_BRANCH_ISLAND: u16 = 1;
1398
1399/// The fixed header of `S_COFFGROUP` symbols.
1400#[repr(C)]
1401#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1402pub struct CoffGroupFixed {
1403    /// Size in bytes of the coff group
1404    pub cb: U32<LE>,
1405    /// Characteristics flags. These are the same as the COFF section characteristics.
1406    ///
1407    /// See: <https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header>
1408    pub characteristics: U32<LE>,
1409    /// Location of the COFF group
1410    pub off_seg: OffsetSegment,
1411}
1412
1413/// For `S_COFFGROUP`.
1414///
1415/// `S_COFFGROUP` records are present in the `* Linker *` special module. These records describe
1416/// contiguous subsections within COFF sections. For example, `.text$mn` is a COFF group within
1417/// the `.text` segment.
1418#[derive(Clone, Debug)]
1419pub struct CoffGroup<'a> {
1420    /// The fixed-size header
1421    pub fixed: &'a CoffGroupFixed,
1422    /// The name of the COFF group
1423    pub name: &'a BStr,
1424}
1425
1426impl<'a> Parse<'a> for CoffGroup<'a> {
1427    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1428        Ok(Self {
1429            fixed: p.get()?,
1430            name: p.strz()?,
1431        })
1432    }
1433}
1434
1435/// For `S_SECTION`
1436#[derive(Clone, Debug)]
1437pub struct Section<'a> {
1438    /// The fixed-size header
1439    pub fixed: &'a SectionFixed,
1440    /// The name of the section
1441    pub name: &'a BStr,
1442}
1443
1444/// The fixed header of `S_SECTION` symbols.
1445#[repr(C)]
1446#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned, Debug)]
1447pub struct SectionFixed {
1448    /// Section number
1449    pub section: U16<LE>,
1450    /// Alignment of this section (power of 2)
1451    pub align: u8,
1452    /// Reserved
1453    pub reserved: u8,
1454    /// RVA of this section base
1455    pub rva: U32<LE>,
1456    /// Size in bytes of this section
1457    pub cb: U32<LE>,
1458    /// Section characteristics (bit flags)
1459    pub characteristics: U32<LE>,
1460}
1461
1462impl<'a> Parse<'a> for Section<'a> {
1463    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
1464        Ok(Self {
1465            fixed: p.get()?,
1466            name: p.strz()?,
1467        })
1468    }
1469}
1470
1471/// Parsed data from a symbol record
1472#[derive(Clone, Debug)]
1473#[allow(missing_docs)]
1474pub enum SymData<'a> {
1475    Unknown,
1476    ObjName(ObjectName<'a>),
1477    Compile3(Compile3<'a>),
1478    Proc(Proc<'a>),
1479    Udt(Udt<'a>),
1480    Constant(Constant<'a>),
1481    ManagedConstant(ManagedConstant<'a>),
1482    RefSym2(RefSym2<'a>),
1483    Data(Data<'a>),
1484    ThreadData(ThreadStorageData<'a>),
1485    Pub(Pub<'a>),
1486    End,
1487    FrameProc(&'a FrameProc),
1488    RegRel(RegRel<'a>),
1489    Block(Block<'a>),
1490    Local(Local<'a>),
1491    DefRange(DefRange<'a>),
1492    DefRangeFramePointerRel(DefRangeSymFramePointerRel<'a>),
1493    DefRangeRegister(DefRangeRegister<'a>),
1494    DefRangeRegisterRel(DefRangeRegisterRel<'a>),
1495    DefRangeFramePointerRelFullScope(&'a DefRangeFramePointerRelFullScope),
1496    DefRangeSubFieldRegister(DefRangeSubFieldRegister<'a>),
1497    Trampoline(Trampoline<'a>),
1498    BuildInfo(BuildInfo),
1499    UsingNamespace(UsingNamespace<'a>),
1500    InlineSiteEnd,
1501    Label(Label<'a>),
1502    FunctionList(FunctionList<'a>),
1503    InlineSite(InlineSite<'a>),
1504    InlineSite2(InlineSite2<'a>),
1505    FrameCookie(&'a FrameCookie),
1506    CallSiteInfo(&'a CallSiteInfo),
1507    HeapAllocSite(&'a HeapAllocSite),
1508    ManagedProc(ManagedProc<'a>),
1509    Annotation(Annotation<'a>),
1510    HotPatchFunc(HotPatchFunc<'a>),
1511    CoffGroup(CoffGroup<'a>),
1512    ArmSwitchTable(&'a ArmSwitchTable),
1513    Section(Section<'a>),
1514}
1515
1516impl<'a> SymData<'a> {
1517    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1518    /// The `data` parameter does not include the length or kind.
1519    pub fn parse(kind: SymKind, data: &'a [u8]) -> Result<Self, ParserError> {
1520        let mut p = Parser::new(data);
1521        Self::from_parser(kind, &mut p)
1522    }
1523
1524    /// Parses a symbol record. The caller has already parsed the length and kind of the record.
1525    /// The `p` parameter does not include the length or kind.
1526    ///
1527    /// This function allows the caller to observe how many bytes were actually consumed from
1528    /// the input stream.
1529    pub fn from_parser(kind: SymKind, p: &mut Parser<'a>) -> Result<Self, ParserError> {
1530        Ok(match kind {
1531            SymKind::S_OBJNAME => Self::ObjName(p.parse()?),
1532            SymKind::S_GPROC32 | SymKind::S_LPROC32 => Self::Proc(p.parse()?),
1533            SymKind::S_COMPILE3 => Self::Compile3(p.parse()?),
1534            SymKind::S_UDT => Self::Udt(p.parse()?),
1535            SymKind::S_CONSTANT => Self::Constant(p.parse()?),
1536            SymKind::S_MANCONSTANT => Self::Constant(p.parse()?),
1537            SymKind::S_PUB32 => Self::Pub(p.parse()?),
1538            SymKind::S_PUB32_ST => Self::Pub(Pub::parse_st(p)?),
1539
1540            SymKind::S_PROCREF
1541            | SymKind::S_LPROCREF
1542            | SymKind::S_DATAREF
1543            | SymKind::S_ANNOTATIONREF => Self::RefSym2(p.parse()?),
1544
1545            SymKind::S_LDATA32 | SymKind::S_GDATA32 | SymKind::S_LMANDATA | SymKind::S_GMANDATA => {
1546                Self::Data(p.parse()?)
1547            }
1548
1549            SymKind::S_LTHREAD32 | SymKind::S_GTHREAD32 => Self::ThreadData(p.parse()?),
1550            SymKind::S_END => Self::End,
1551            SymKind::S_FRAMEPROC => Self::FrameProc(p.get()?),
1552            SymKind::S_REGREL32 => Self::RegRel(p.parse()?),
1553            SymKind::S_BLOCK32 => Self::Block(p.parse()?),
1554            SymKind::S_LOCAL => Self::Local(p.parse()?),
1555            SymKind::S_DEFRANGE => Self::DefRange(p.parse()?),
1556            SymKind::S_DEFRANGE_FRAMEPOINTER_REL => Self::DefRangeFramePointerRel(p.parse()?),
1557            SymKind::S_DEFRANGE_REGISTER => Self::DefRangeRegister(p.parse()?),
1558            SymKind::S_DEFRANGE_REGISTER_REL => Self::DefRangeRegisterRel(p.parse()?),
1559            SymKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => {
1560                Self::DefRangeFramePointerRelFullScope(p.get()?)
1561            }
1562            SymKind::S_DEFRANGE_SUBFIELD_REGISTER => Self::DefRangeSubFieldRegister(p.parse()?),
1563            SymKind::S_TRAMPOLINE => Self::Trampoline(p.parse()?),
1564            SymKind::S_BUILDINFO => Self::BuildInfo(p.parse()?),
1565            SymKind::S_UNAMESPACE => Self::UsingNamespace(p.parse()?),
1566            SymKind::S_INLINESITE_END => Self::InlineSiteEnd,
1567            SymKind::S_LABEL32 => Self::Label(p.parse()?),
1568            SymKind::S_CALLEES | SymKind::S_CALLERS => Self::FunctionList(p.parse()?),
1569            SymKind::S_INLINESITE => Self::InlineSite(p.parse()?),
1570            SymKind::S_INLINESITE2 => Self::InlineSite2(p.parse()?),
1571            SymKind::S_INLINEES => Self::FunctionList(p.parse()?),
1572            SymKind::S_FRAMECOOKIE => Self::FrameCookie(p.get()?),
1573            SymKind::S_CALLSITEINFO => Self::CallSiteInfo(p.get()?),
1574            SymKind::S_HEAPALLOCSITE => Self::HeapAllocSite(p.get()?),
1575            SymKind::S_GMANPROC | SymKind::S_LMANPROC => Self::ManagedProc(p.parse()?),
1576            SymKind::S_ANNOTATION => Self::Annotation(p.parse()?),
1577            SymKind::S_HOTPATCHFUNC => Self::HotPatchFunc(p.parse()?),
1578            SymKind::S_ARMSWITCHTABLE => Self::ArmSwitchTable(p.get()?),
1579            SymKind::S_COFFGROUP => Self::CoffGroup(p.parse()?),
1580            SymKind::S_SECTION => Self::Section(p.parse()?),
1581
1582            _ => Self::Unknown,
1583        })
1584    }
1585
1586    /// If this symbol record has a "name" field, return it. Else, `None`.
1587    pub fn name(&self) -> Option<&'a BStr> {
1588        match self {
1589            Self::Proc(proc) => Some(proc.name),
1590            Self::Data(data) => Some(data.name),
1591            Self::ThreadData(thread_data) => Some(thread_data.name),
1592            Self::Udt(udt) => Some(udt.name),
1593            Self::Local(local) => Some(local.name),
1594            Self::RefSym2(refsym) => Some(refsym.name),
1595            Self::Constant(c) => Some(c.name),
1596            Self::ManagedConstant(c) => Some(c.name),
1597            _ => None,
1598        }
1599    }
1600}