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