ms_pdb/
syms.rs

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