1 // Copyright 2017 pdb Developers
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 use std::fmt;
9 
10 use scroll::{ctx::TryFromCtx, Endian, Pread, LE};
11 
12 use crate::common::*;
13 use crate::msf::*;
14 use crate::FallibleIterator;
15 
16 mod annotations;
17 mod constants;
18 
19 use self::constants::*;
20 pub use self::constants::{CPUType, SourceLanguage};
21 
22 pub use self::annotations::*;
23 
24 /// The raw type discriminator for `Symbols`.
25 pub type SymbolKind = u16;
26 
27 /// Represents a symbol from the symbol table.
28 ///
29 /// A `Symbol` is represented internally as a `&[u8]`, and in general the bytes inside are not
30 /// inspected in any way before calling any of the accessor methods.
31 ///
32 /// To avoid copying, `Symbol`s exist as references to data owned by the parent `SymbolTable`.
33 /// Therefore, a `Symbol` may not outlive its parent `SymbolTable`.
34 #[derive(Copy, Clone, PartialEq)]
35 pub struct Symbol<'t> {
36     index: SymbolIndex,
37     data: &'t [u8],
38 }
39 
40 impl<'t> Symbol<'t> {
41     /// The index of this symbol in the containing symbol stream.
42     #[inline]
index(&self) -> SymbolIndex43     pub fn index(&self) -> SymbolIndex {
44         self.index
45     }
46 
47     /// Returns the kind of symbol identified by this Symbol.
48     #[inline]
raw_kind(&self) -> SymbolKind49     pub fn raw_kind(&self) -> SymbolKind {
50         debug_assert!(self.data.len() >= 2);
51         self.data.pread_with(0, LE).unwrap_or_default()
52     }
53 
54     /// Returns the raw bytes of this symbol record, including the symbol type and extra data, but
55     /// not including the preceding symbol length indicator.
56     #[inline]
raw_bytes(&self) -> &'t [u8]57     pub fn raw_bytes(&self) -> &'t [u8] {
58         self.data
59     }
60 
61     /// Parse the symbol into the `SymbolData` it contains.
62     #[inline]
parse(&self) -> Result<SymbolData<'t>>63     pub fn parse(&self) -> Result<SymbolData<'t>> {
64         Ok(self.raw_bytes().pread_with(0, ())?)
65     }
66 
67     /// Returns whether this symbol starts a scope.
68     ///
69     /// If `true`, this symbol has a `parent` and an `end` field, which contains the offset of the
70     /// corrsponding end symbol.
starts_scope(&self) -> bool71     pub fn starts_scope(&self) -> bool {
72         matches!(
73             self.raw_kind(),
74             S_GPROC16
75                 | S_GPROC32
76                 | S_GPROC32_ST
77                 | S_GPROCMIPS
78                 | S_GPROCMIPS_ST
79                 | S_GPROCIA64
80                 | S_GPROCIA64_ST
81                 | S_LPROC16
82                 | S_LPROC32
83                 | S_LPROC32_ST
84                 | S_LPROC32_DPC
85                 | S_LPROCMIPS
86                 | S_LPROCMIPS_ST
87                 | S_LPROCIA64
88                 | S_LPROCIA64_ST
89                 | S_LPROC32_DPC_ID
90                 | S_GPROC32_ID
91                 | S_GPROCMIPS_ID
92                 | S_GPROCIA64_ID
93                 | S_BLOCK16
94                 | S_BLOCK32
95                 | S_BLOCK32_ST
96                 | S_WITH16
97                 | S_WITH32
98                 | S_WITH32_ST
99                 | S_THUNK16
100                 | S_THUNK32
101                 | S_THUNK32_ST
102                 | S_SEPCODE
103                 | S_GMANPROC
104                 | S_GMANPROC_ST
105                 | S_LMANPROC
106                 | S_LMANPROC_ST
107                 | S_INLINESITE
108                 | S_INLINESITE2
109         )
110     }
111 
112     /// Returns whether this symbol declares the end of a scope.
ends_scope(&self) -> bool113     pub fn ends_scope(&self) -> bool {
114         matches!(self.raw_kind(), S_END | S_PROC_ID_END | S_INLINESITE_END)
115     }
116 }
117 
118 impl<'t> fmt::Debug for Symbol<'t> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result119     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120         write!(
121             f,
122             "Symbol{{ kind: 0x{:x} [{} bytes] }}",
123             self.raw_kind(),
124             self.data.len()
125         )
126     }
127 }
128 
parse_symbol_name<'t>(buf: &mut ParseBuffer<'t>, kind: SymbolKind) -> Result<RawString<'t>>129 fn parse_symbol_name<'t>(buf: &mut ParseBuffer<'t>, kind: SymbolKind) -> Result<RawString<'t>> {
130     if kind < S_ST_MAX {
131         // Pascal-style name
132         buf.parse_u8_pascal_string()
133     } else {
134         // NUL-terminated name
135         buf.parse_cstring()
136     }
137 }
138 
parse_optional_name<'t>( buf: &mut ParseBuffer<'t>, kind: SymbolKind, ) -> Result<Option<RawString<'t>>>139 fn parse_optional_name<'t>(
140     buf: &mut ParseBuffer<'t>,
141     kind: SymbolKind,
142 ) -> Result<Option<RawString<'t>>> {
143     if kind < S_ST_MAX {
144         // ST variants do not specify a name
145         Ok(None)
146     } else {
147         // NUL-terminated name
148         buf.parse_cstring().map(Some)
149     }
150 }
151 
parse_optional_index(buf: &mut ParseBuffer<'_>) -> Result<Option<SymbolIndex>>152 fn parse_optional_index(buf: &mut ParseBuffer<'_>) -> Result<Option<SymbolIndex>> {
153     Ok(match buf.parse()? {
154         SymbolIndex(0) => None,
155         index => Some(index),
156     })
157 }
158 
159 // data types are defined at:
160 //   https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3038
161 // constants defined at:
162 //   https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2735
163 // decoding reference:
164 //   https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/cvdump/dumpsym7.cpp#L264
165 
166 /// Information parsed from a [`Symbol`] record.
167 #[non_exhaustive]
168 #[derive(Clone, Debug, Eq, PartialEq)]
169 pub enum SymbolData<'t> {
170     /// End of a scope, such as a procedure.
171     ScopeEnd,
172     /// Name of the object file of this module.
173     ObjName(ObjNameSymbol<'t>),
174     /// A Register variable.
175     RegisterVariable(RegisterVariableSymbol<'t>),
176     /// A constant value.
177     Constant(ConstantSymbol<'t>),
178     /// A user defined type.
179     UserDefinedType(UserDefinedTypeSymbol<'t>),
180     /// A Register variable spanning multiple registers.
181     MultiRegisterVariable(MultiRegisterVariableSymbol<'t>),
182     /// Static data, such as a global variable.
183     Data(DataSymbol<'t>),
184     /// A public symbol with a mangled name.
185     Public(PublicSymbol<'t>),
186     /// A procedure, such as a function or method.
187     Procedure(ProcedureSymbol<'t>),
188     /// A thread local variable.
189     ThreadStorage(ThreadStorageSymbol<'t>),
190     /// Flags used to compile a module.
191     CompileFlags(CompileFlagsSymbol<'t>),
192     /// A using namespace directive.
193     UsingNamespace(UsingNamespaceSymbol<'t>),
194     /// Reference to a [`ProcedureSymbol`].
195     ProcedureReference(ProcedureReferenceSymbol<'t>),
196     /// Reference to an imported variable.
197     DataReference(DataReferenceSymbol<'t>),
198     /// Reference to an annotation.
199     AnnotationReference(AnnotationReferenceSymbol<'t>),
200     /// An exported symbol.
201     Export(ExportSymbol<'t>),
202     /// A local symbol in optimized code.
203     Local(LocalSymbol<'t>),
204     /// Reference to build information.
205     BuildInfo(BuildInfoSymbol),
206     /// The callsite of an inlined function.
207     InlineSite(InlineSiteSymbol<'t>),
208     /// End of an inline callsite.
209     InlineSiteEnd,
210     /// End of a procedure.
211     ProcedureEnd,
212     /// A label
213     Label(LabelSymbol<'t>),
214     /// A block
215     Block(BlockSymbol<'t>),
216     /// Data allocated relative to a register
217     RegisterRelative(RegisterRelativeSymbol<'t>),
218     /// A thunk
219     Thunk(ThunkSymbol<'t>),
220     /// A block of separated code
221     SeparatedCode(SeparatedCodeSymbol),
222 }
223 
224 impl<'t> SymbolData<'t> {
225     /// Returns the name of this symbol if it has one.
name(&self) -> Option<RawString<'t>>226     pub fn name(&self) -> Option<RawString<'t>> {
227         match self {
228             SymbolData::ScopeEnd => None,
229             SymbolData::ObjName(data) => Some(data.name),
230             SymbolData::RegisterVariable(_) => None,
231             SymbolData::Constant(data) => Some(data.name),
232             SymbolData::UserDefinedType(data) => Some(data.name),
233             SymbolData::MultiRegisterVariable(_) => None,
234             SymbolData::Data(data) => Some(data.name),
235             SymbolData::Public(data) => Some(data.name),
236             SymbolData::Procedure(data) => Some(data.name),
237             SymbolData::ThreadStorage(data) => Some(data.name),
238             SymbolData::CompileFlags(_) => None,
239             SymbolData::UsingNamespace(data) => Some(data.name),
240             SymbolData::ProcedureReference(data) => data.name,
241             SymbolData::DataReference(data) => data.name,
242             SymbolData::AnnotationReference(data) => Some(data.name),
243             SymbolData::Export(data) => Some(data.name),
244             SymbolData::Local(data) => Some(data.name),
245             SymbolData::InlineSite(_) => None,
246             SymbolData::BuildInfo(_) => None,
247             SymbolData::InlineSiteEnd => None,
248             SymbolData::ProcedureEnd => None,
249             SymbolData::Label(data) => Some(data.name),
250             SymbolData::Block(data) => Some(data.name),
251             SymbolData::RegisterRelative(data) => Some(data.name),
252             SymbolData::Thunk(data) => Some(data.name),
253             SymbolData::SeparatedCode(_) => None,
254         }
255     }
256 }
257 
258 impl<'t> TryFromCtx<'t> for SymbolData<'t> {
259     type Error = Error;
260 
try_from_ctx(this: &'t [u8], _ctx: ()) -> Result<(Self, usize)>261     fn try_from_ctx(this: &'t [u8], _ctx: ()) -> Result<(Self, usize)> {
262         let mut buf = ParseBuffer::from(this);
263         let kind = buf.parse()?;
264 
265         let symbol = match kind {
266             S_END => SymbolData::ScopeEnd,
267             S_OBJNAME | S_OBJNAME_ST => SymbolData::ObjName(buf.parse_with(kind)?),
268             S_REGISTER | S_REGISTER_ST => SymbolData::RegisterVariable(buf.parse_with(kind)?),
269             S_CONSTANT | S_CONSTANT_ST | S_MANCONSTANT => {
270                 SymbolData::Constant(buf.parse_with(kind)?)
271             }
272             S_UDT | S_UDT_ST | S_COBOLUDT | S_COBOLUDT_ST => {
273                 SymbolData::UserDefinedType(buf.parse_with(kind)?)
274             }
275             S_MANYREG | S_MANYREG_ST | S_MANYREG2 | S_MANYREG2_ST => {
276                 SymbolData::MultiRegisterVariable(buf.parse_with(kind)?)
277             }
278             S_LDATA32 | S_LDATA32_ST | S_GDATA32 | S_GDATA32_ST | S_LMANDATA | S_LMANDATA_ST
279             | S_GMANDATA | S_GMANDATA_ST => SymbolData::Data(buf.parse_with(kind)?),
280             S_PUB32 | S_PUB32_ST => SymbolData::Public(buf.parse_with(kind)?),
281             S_LPROC32 | S_LPROC32_ST | S_GPROC32 | S_GPROC32_ST | S_LPROC32_ID | S_GPROC32_ID
282             | S_LPROC32_DPC | S_LPROC32_DPC_ID => SymbolData::Procedure(buf.parse_with(kind)?),
283             S_LTHREAD32 | S_LTHREAD32_ST | S_GTHREAD32 | S_GTHREAD32_ST => {
284                 SymbolData::ThreadStorage(buf.parse_with(kind)?)
285             }
286             S_COMPILE2 | S_COMPILE2_ST | S_COMPILE3 => {
287                 SymbolData::CompileFlags(buf.parse_with(kind)?)
288             }
289             S_UNAMESPACE | S_UNAMESPACE_ST => SymbolData::UsingNamespace(buf.parse_with(kind)?),
290             S_PROCREF | S_PROCREF_ST | S_LPROCREF | S_LPROCREF_ST => {
291                 SymbolData::ProcedureReference(buf.parse_with(kind)?)
292             }
293             S_DATAREF | S_DATAREF_ST => SymbolData::DataReference(buf.parse_with(kind)?),
294             S_ANNOTATIONREF => SymbolData::AnnotationReference(buf.parse_with(kind)?),
295             S_EXPORT => SymbolData::Export(buf.parse_with(kind)?),
296             S_LOCAL => SymbolData::Local(buf.parse_with(kind)?),
297             S_BUILDINFO => SymbolData::BuildInfo(buf.parse_with(kind)?),
298             S_INLINESITE | S_INLINESITE2 => SymbolData::InlineSite(buf.parse_with(kind)?),
299             S_INLINESITE_END => SymbolData::InlineSiteEnd,
300             S_PROC_ID_END => SymbolData::ProcedureEnd,
301             S_LABEL32 | S_LABEL32_ST => SymbolData::Label(buf.parse_with(kind)?),
302             S_BLOCK32 | S_BLOCK32_ST => SymbolData::Block(buf.parse_with(kind)?),
303             S_REGREL32 => SymbolData::RegisterRelative(buf.parse_with(kind)?),
304             S_THUNK32 | S_THUNK32_ST => SymbolData::Thunk(buf.parse_with(kind)?),
305             S_SEPCODE => SymbolData::SeparatedCode(buf.parse_with(kind)?),
306             other => return Err(Error::UnimplementedSymbolKind(other)),
307         };
308 
309         Ok((symbol, buf.pos()))
310     }
311 }
312 
313 /// A Register variable.
314 ///
315 /// Symbol kind `S_REGISTER`, or `S_REGISTER_ST`
316 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
317 pub struct RegisterVariableSymbol<'t> {
318     /// Identifier of the variable type.
319     pub type_index: TypeIndex,
320     /// The register this variable is stored in.
321     pub register: Register,
322     /// Name of the variable.
323     pub name: RawString<'t>,
324 }
325 
326 impl<'t> TryFromCtx<'t, SymbolKind> for RegisterVariableSymbol<'t> {
327     type Error = Error;
328 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>329     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
330         let mut buf = ParseBuffer::from(this);
331 
332         let symbol = RegisterVariableSymbol {
333             type_index: buf.parse()?,
334             register: buf.parse()?,
335             name: parse_symbol_name(&mut buf, kind)?,
336         };
337 
338         Ok((symbol, buf.pos()))
339     }
340 }
341 
342 /// A Register variable spanning multiple registers.
343 ///
344 /// Symbol kind `S_MANYREG`, `S_MANYREG_ST`, `S_MANYREG2`, or `S_MANYREG2_ST`.
345 #[derive(Clone, Debug, Eq, PartialEq)]
346 pub struct MultiRegisterVariableSymbol<'t> {
347     /// Identifier of the variable type.
348     pub type_index: TypeIndex,
349     /// Most significant register first.
350     pub registers: Vec<(Register, RawString<'t>)>,
351 }
352 
353 impl<'t> TryFromCtx<'t, SymbolKind> for MultiRegisterVariableSymbol<'t> {
354     type Error = Error;
355 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>356     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
357         let mut buf = ParseBuffer::from(this);
358 
359         let type_index = buf.parse()?;
360         let count = match kind {
361             S_MANYREG2 | S_MANYREG2_ST => buf.parse::<u16>()?,
362             _ => u16::from(buf.parse::<u8>()?),
363         };
364 
365         let mut registers = Vec::with_capacity(count as usize);
366         for _ in 0..count {
367             registers.push((buf.parse()?, parse_symbol_name(&mut buf, kind)?));
368         }
369 
370         let symbol = MultiRegisterVariableSymbol {
371             type_index,
372             registers,
373         };
374 
375         Ok((symbol, buf.pos()))
376     }
377 }
378 
379 // CV_PUBSYMFLAGS_e
380 const CVPSF_CODE: u32 = 0x1;
381 const CVPSF_FUNCTION: u32 = 0x2;
382 const CVPSF_MANAGED: u32 = 0x4;
383 const CVPSF_MSIL: u32 = 0x8;
384 
385 /// A public symbol with a mangled name.
386 ///
387 /// Symbol kind `S_PUB32`, or `S_PUB32_ST`.
388 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
389 pub struct PublicSymbol<'t> {
390     /// The public symbol refers to executable code.
391     pub code: bool,
392     /// The public symbol is a function.
393     pub function: bool,
394     /// The symbol is in managed code (native or IL).
395     pub managed: bool,
396     /// The symbol is managed IL code.
397     pub msil: bool,
398     /// Start offset of the symbol.
399     pub offset: PdbInternalSectionOffset,
400     /// Mangled name of the symbol.
401     pub name: RawString<'t>,
402 }
403 
404 impl<'t> TryFromCtx<'t, SymbolKind> for PublicSymbol<'t> {
405     type Error = Error;
406 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>407     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
408         let mut buf = ParseBuffer::from(this);
409 
410         let flags = buf.parse::<u32>()?;
411         let symbol = PublicSymbol {
412             code: flags & CVPSF_CODE != 0,
413             function: flags & CVPSF_FUNCTION != 0,
414             managed: flags & CVPSF_MANAGED != 0,
415             msil: flags & CVPSF_MSIL != 0,
416             offset: buf.parse()?,
417             name: parse_symbol_name(&mut buf, kind)?,
418         };
419 
420         Ok((symbol, buf.pos()))
421     }
422 }
423 
424 /// Static data, such as a global variable.
425 ///
426 /// Symbol kinds:
427 ///  - `S_LDATA32` and `S_LDATA32_ST` for local unmanaged data
428 ///  - `S_GDATA32` and `S_GDATA32_ST` for global unmanaged data
429 ///  - `S_LMANDATA32` and `S_LMANDATA32_ST` for local managed data
430 ///  - `S_GMANDATA32` and `S_GMANDATA32_ST` for global managed data
431 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
432 pub struct DataSymbol<'t> {
433     /// Whether this data is global or local.
434     pub global: bool,
435     /// Whether this data is managed or unmanaged.
436     pub managed: bool,
437     /// Type identifier of the type of data.
438     pub type_index: TypeIndex,
439     /// Code offset of the start of the data region.
440     pub offset: PdbInternalSectionOffset,
441     /// Name of the data variable.
442     pub name: RawString<'t>,
443 }
444 
445 impl<'t> TryFromCtx<'t, SymbolKind> for DataSymbol<'t> {
446     type Error = Error;
447 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>448     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
449         let mut buf = ParseBuffer::from(this);
450 
451         let symbol = DataSymbol {
452             global: matches!(kind, S_GDATA32 | S_GDATA32_ST | S_GMANDATA | S_GMANDATA_ST),
453             managed: matches!(
454                 kind,
455                 S_LMANDATA | S_LMANDATA_ST | S_GMANDATA | S_GMANDATA_ST
456             ),
457             type_index: buf.parse()?,
458             offset: buf.parse()?,
459             name: parse_symbol_name(&mut buf, kind)?,
460         };
461 
462         Ok((symbol, buf.pos()))
463     }
464 }
465 
466 /// Reference to an imported procedure.
467 ///
468 /// Symbol kind `S_PROCREF`, `S_PROCREF_ST`, `S_LPROCREF`, or `S_LPROCREF_ST`.
469 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
470 pub struct ProcedureReferenceSymbol<'t> {
471     /// Whether the referenced procedure is global or local.
472     pub global: bool,
473     /// SUC of the name.
474     pub sum_name: u32,
475     /// Symbol index of the referenced [`ProcedureSymbol`].
476     ///
477     /// Note that this symbol might be located in a different module.
478     pub symbol_index: SymbolIndex,
479     /// Index of the module containing the actual symbol.
480     pub module: u16,
481     /// Name of the procedure reference.
482     pub name: Option<RawString<'t>>,
483 }
484 
485 impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureReferenceSymbol<'t> {
486     type Error = Error;
487 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>488     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
489         let mut buf = ParseBuffer::from(this);
490 
491         let symbol = ProcedureReferenceSymbol {
492             global: matches!(kind, S_PROCREF | S_PROCREF_ST),
493             sum_name: buf.parse()?,
494             symbol_index: buf.parse()?,
495             module: buf.parse()?,
496             name: parse_optional_name(&mut buf, kind)?,
497         };
498 
499         Ok((symbol, buf.pos()))
500     }
501 }
502 
503 /// Reference to an imported variable.
504 ///
505 /// Symbol kind `S_DATAREF`, or `S_DATAREF_ST`.
506 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
507 pub struct DataReferenceSymbol<'t> {
508     /// SUC of the name.
509     pub sum_name: u32,
510     /// Symbol index of the referenced [`DataSymbol`].
511     ///
512     /// Note that this symbol might be located in a different module.
513     pub symbol_index: SymbolIndex,
514     /// Index of the module containing the actual symbol.
515     pub module: u16,
516     /// Name of the data reference.
517     pub name: Option<RawString<'t>>,
518 }
519 
520 impl<'t> TryFromCtx<'t, SymbolKind> for DataReferenceSymbol<'t> {
521     type Error = Error;
522 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>523     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
524         let mut buf = ParseBuffer::from(this);
525 
526         let symbol = DataReferenceSymbol {
527             sum_name: buf.parse()?,
528             symbol_index: buf.parse()?,
529             module: buf.parse()?,
530             name: parse_optional_name(&mut buf, kind)?,
531         };
532 
533         Ok((symbol, buf.pos()))
534     }
535 }
536 
537 /// Reference to an annotation.
538 ///
539 /// Symbol kind `S_ANNOTATIONREF`.
540 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
541 pub struct AnnotationReferenceSymbol<'t> {
542     /// SUC of the name.
543     pub sum_name: u32,
544     /// Symbol index of the referenced symbol.
545     ///
546     /// Note that this symbol might be located in a different module.
547     pub symbol_index: SymbolIndex,
548     /// Index of the module containing the actual symbol.
549     pub module: u16,
550     /// Name of the annotation reference.
551     pub name: RawString<'t>,
552 }
553 
554 impl<'t> TryFromCtx<'t, SymbolKind> for AnnotationReferenceSymbol<'t> {
555     type Error = Error;
556 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>557     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
558         let mut buf = ParseBuffer::from(this);
559 
560         let symbol = AnnotationReferenceSymbol {
561             sum_name: buf.parse()?,
562             symbol_index: buf.parse()?,
563             module: buf.parse()?,
564             name: parse_symbol_name(&mut buf, kind)?,
565         };
566 
567         Ok((symbol, buf.pos()))
568     }
569 }
570 
571 /// A constant value.
572 ///
573 /// Symbol kind `S_CONSTANT`, or `S_CONSTANT_ST`.
574 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
575 pub struct ConstantSymbol<'t> {
576     /// Whether this constant has metadata type information.
577     pub managed: bool,
578     /// The type of this constant or metadata token.
579     pub type_index: TypeIndex,
580     /// The value of this constant.
581     pub value: Variant,
582     /// Name of the constant.
583     pub name: RawString<'t>,
584 }
585 
586 impl<'t> TryFromCtx<'t, SymbolKind> for ConstantSymbol<'t> {
587     type Error = Error;
588 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>589     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
590         let mut buf = ParseBuffer::from(this);
591 
592         let symbol = ConstantSymbol {
593             managed: kind == S_MANCONSTANT,
594             type_index: buf.parse()?,
595             value: buf.parse()?,
596             name: parse_symbol_name(&mut buf, kind)?,
597         };
598 
599         Ok((symbol, buf.pos()))
600     }
601 }
602 
603 /// A user defined type.
604 ///
605 /// Symbol kind `S_UDT`, or `S_UDT_ST`.
606 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
607 pub struct UserDefinedTypeSymbol<'t> {
608     /// Identifier of the type.
609     pub type_index: TypeIndex,
610     /// Name of the type.
611     pub name: RawString<'t>,
612 }
613 
614 impl<'t> TryFromCtx<'t, SymbolKind> for UserDefinedTypeSymbol<'t> {
615     type Error = Error;
616 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>617     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
618         let mut buf = ParseBuffer::from(this);
619 
620         let symbol = UserDefinedTypeSymbol {
621             type_index: buf.parse()?,
622             name: parse_symbol_name(&mut buf, kind)?,
623         };
624 
625         Ok((symbol, buf.pos()))
626     }
627 }
628 
629 /// A thread local variable.
630 ///
631 /// Symbol kinds:
632 ///  - `S_LTHREAD32`, `S_LTHREAD32_ST` for local thread storage.
633 ///  - `S_GTHREAD32`, or `S_GTHREAD32_ST` for global thread storage.
634 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
635 pub struct ThreadStorageSymbol<'t> {
636     /// Whether this is a global or local thread storage.
637     pub global: bool,
638     /// Identifier of the stored type.
639     pub type_index: TypeIndex,
640     /// Code offset of the thread local.
641     pub offset: PdbInternalSectionOffset,
642     /// Name of the thread local.
643     pub name: RawString<'t>,
644 }
645 
646 impl<'t> TryFromCtx<'t, SymbolKind> for ThreadStorageSymbol<'t> {
647     type Error = Error;
648 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>649     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
650         let mut buf = ParseBuffer::from(this);
651 
652         let symbol = ThreadStorageSymbol {
653             global: matches!(kind, S_GTHREAD32 | S_GTHREAD32_ST),
654             type_index: buf.parse()?,
655             offset: buf.parse()?,
656             name: parse_symbol_name(&mut buf, kind)?,
657         };
658 
659         Ok((symbol, buf.pos()))
660     }
661 }
662 
663 // CV_PROCFLAGS:
664 const CV_PFLAG_NOFPO: u8 = 0x01;
665 const CV_PFLAG_INT: u8 = 0x02;
666 const CV_PFLAG_FAR: u8 = 0x04;
667 const CV_PFLAG_NEVER: u8 = 0x08;
668 const CV_PFLAG_NOTREACHED: u8 = 0x10;
669 const CV_PFLAG_CUST_CALL: u8 = 0x20;
670 const CV_PFLAG_NOINLINE: u8 = 0x40;
671 const CV_PFLAG_OPTDBGINFO: u8 = 0x80;
672 
673 /// Flags of a [`ProcedureSymbol`](struct.ProcedureSymbol).
674 #[non_exhaustive]
675 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
676 pub struct ProcedureFlags {
677     /// Frame pointer is present (not omitted).
678     pub nofpo: bool,
679     /// Interrupt return.
680     pub int: bool,
681     /// Far return.
682     pub far: bool,
683     /// Procedure does not return.
684     pub never: bool,
685     /// Procedure is never called.
686     pub notreached: bool,
687     /// Custom calling convention.
688     pub cust_call: bool,
689     /// Marked as `noinline`.
690     pub noinline: bool,
691     /// Debug information for optimized code is present.
692     pub optdbginfo: bool,
693 }
694 
695 impl<'t> TryFromCtx<'t, Endian> for ProcedureFlags {
696     type Error = scroll::Error;
697 
try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)>698     fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
699         let (value, size) = u8::try_from_ctx(this, le)?;
700 
701         let flags = ProcedureFlags {
702             nofpo: value & CV_PFLAG_NOFPO != 0,
703             int: value & CV_PFLAG_INT != 0,
704             far: value & CV_PFLAG_FAR != 0,
705             never: value & CV_PFLAG_NEVER != 0,
706             notreached: value & CV_PFLAG_NOTREACHED != 0,
707             cust_call: value & CV_PFLAG_CUST_CALL != 0,
708             noinline: value & CV_PFLAG_NOINLINE != 0,
709             optdbginfo: value & CV_PFLAG_OPTDBGINFO != 0,
710         };
711 
712         Ok((flags, size))
713     }
714 }
715 
716 /// A procedure, such as a function or method.
717 ///
718 /// Symbol kinds:
719 ///  - `S_GPROC32`, `S_GPROC32_ST` for global procedures
720 ///  - `S_LPROC32`, `S_LPROC32_ST` for local procedures
721 ///  - `S_LPROC32_DPC` for DPC procedures
722 ///  - `S_GPROC32_ID`, `S_LPROC32_ID`, `S_LPROC32_DPC_ID` for procedures referencing types from the
723 ///    ID stream rather than the Type stream.
724 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
725 pub struct ProcedureSymbol<'t> {
726     /// Whether this is a global or local procedure.
727     pub global: bool,
728     /// Indicates Deferred Procedure Calls (DPC).
729     pub dpc: bool,
730     /// The parent scope that this procedure is nested in.
731     pub parent: Option<SymbolIndex>,
732     /// The end symbol of this procedure.
733     pub end: SymbolIndex,
734     /// The next procedure symbol.
735     pub next: Option<SymbolIndex>,
736     /// The length of the code block covered by this procedure.
737     pub len: u32,
738     /// Start offset of the procedure's body code, which marks the end of the prologue.
739     pub dbg_start_offset: u32,
740     /// End offset of the procedure's body code, which marks the start of the epilogue.
741     pub dbg_end_offset: u32,
742     /// Identifier of the procedure type.
743     ///
744     /// The type contains the complete signature, including parameters, modifiers and the return
745     /// type.
746     pub type_index: TypeIndex,
747     /// Code offset of the start of this procedure.
748     pub offset: PdbInternalSectionOffset,
749     /// Detailed flags of this procedure.
750     pub flags: ProcedureFlags,
751     /// The full, demangled name of the procedure.
752     pub name: RawString<'t>,
753 }
754 
755 impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureSymbol<'t> {
756     type Error = Error;
757 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>758     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
759         let mut buf = ParseBuffer::from(this);
760 
761         let symbol = ProcedureSymbol {
762             global: matches!(kind, S_GPROC32 | S_GPROC32_ST | S_GPROC32_ID),
763             dpc: matches!(kind, S_LPROC32_DPC | S_LPROC32_DPC_ID),
764             parent: parse_optional_index(&mut buf)?,
765             end: buf.parse()?,
766             next: parse_optional_index(&mut buf)?,
767             len: buf.parse()?,
768             dbg_start_offset: buf.parse()?,
769             dbg_end_offset: buf.parse()?,
770             type_index: buf.parse()?,
771             offset: buf.parse()?,
772             flags: buf.parse()?,
773             name: parse_symbol_name(&mut buf, kind)?,
774         };
775 
776         Ok((symbol, buf.pos()))
777     }
778 }
779 
780 /// The callsite of an inlined function.
781 ///
782 /// Symbol kind `S_INLINESITE`, or `S_INLINESITE2`.
783 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
784 pub struct InlineSiteSymbol<'t> {
785     /// Index of the parent function.
786     ///
787     /// This might either be a [`ProcedureSymbol`] or another `InlineSiteSymbol`.
788     pub parent: Option<SymbolIndex>,
789     /// The end symbol of this callsite.
790     pub end: SymbolIndex,
791     /// Identifier of the type describing the inline function.
792     pub inlinee: IdIndex,
793     /// The total number of invocations of the inline function.
794     pub invocations: Option<u32>,
795     /// Binary annotations containing the line program of this call site.
796     pub annotations: BinaryAnnotations<'t>,
797 }
798 
799 impl<'t> TryFromCtx<'t, SymbolKind> for InlineSiteSymbol<'t> {
800     type Error = Error;
801 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>802     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
803         let mut buf = ParseBuffer::from(this);
804 
805         let symbol = InlineSiteSymbol {
806             parent: parse_optional_index(&mut buf)?,
807             end: buf.parse()?,
808             inlinee: buf.parse()?,
809             invocations: match kind {
810                 S_INLINESITE2 => Some(buf.parse()?),
811                 _ => None,
812             },
813             annotations: BinaryAnnotations::new(buf.take(buf.len())?),
814         };
815 
816         Ok((symbol, buf.pos()))
817     }
818 }
819 
820 /// Reference to build information.
821 ///
822 /// Symbol kind `S_BUILDINFO`.
823 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
824 pub struct BuildInfoSymbol {
825     /// Index of the build information record.
826     pub id: IdIndex,
827 }
828 
829 impl<'t> TryFromCtx<'t, SymbolKind> for BuildInfoSymbol {
830     type Error = Error;
831 
try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)>832     fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> {
833         let mut buf = ParseBuffer::from(this);
834 
835         let symbol = BuildInfoSymbol { id: buf.parse()? };
836 
837         Ok((symbol, buf.pos()))
838     }
839 }
840 
841 /// Name of the object file of this module.
842 ///
843 /// Symbol kind `S_OBJNAME`, or `S_OBJNAME_ST`.
844 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
845 pub struct ObjNameSymbol<'t> {
846     /// Signature.
847     pub signature: u32,
848     /// Path to the object file.
849     pub name: RawString<'t>,
850 }
851 
852 impl<'t> TryFromCtx<'t, SymbolKind> for ObjNameSymbol<'t> {
853     type Error = Error;
854 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>855     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
856         let mut buf = ParseBuffer::from(this);
857 
858         let symbol = ObjNameSymbol {
859             signature: buf.parse()?,
860             name: parse_symbol_name(&mut buf, kind)?,
861         };
862 
863         Ok((symbol, buf.pos()))
864     }
865 }
866 
867 /// A version number refered to by `CompileFlagsSymbol`.
868 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
869 pub struct CompilerVersion {
870     /// The major version number.
871     pub major: u16,
872     /// The minor version number.
873     pub minor: u16,
874     /// The build (patch) version number.
875     pub build: u16,
876     /// The QFE (quick fix engineering) number.
877     pub qfe: Option<u16>,
878 }
879 
880 impl<'t> TryFromCtx<'t, bool> for CompilerVersion {
881     type Error = Error;
882 
try_from_ctx(this: &'t [u8], has_qfe: bool) -> Result<(Self, usize)>883     fn try_from_ctx(this: &'t [u8], has_qfe: bool) -> Result<(Self, usize)> {
884         let mut buf = ParseBuffer::from(this);
885 
886         let version = CompilerVersion {
887             major: buf.parse()?,
888             minor: buf.parse()?,
889             build: buf.parse()?,
890             qfe: if has_qfe { Some(buf.parse()?) } else { None },
891         };
892 
893         Ok((version, buf.pos()))
894     }
895 }
896 
897 /// Compile flags declared in `CompileFlagsSymbol`.
898 #[non_exhaustive]
899 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
900 pub struct CompileFlags {
901     /// Compiled for edit and continue.
902     pub edit_and_continue: bool,
903     /// Compiled without debugging info.
904     pub no_debug_info: bool,
905     /// Compiled with `LTCG`.
906     pub link_time_codegen: bool,
907     /// Compiled with `/bzalign`.
908     pub no_data_align: bool,
909     /// Managed code or data is present.
910     pub managed: bool,
911     /// Compiled with `/GS`.
912     pub security_checks: bool,
913     /// Compiled with `/hotpatch`.
914     pub hot_patch: bool,
915     /// Compiled with `CvtCIL`.
916     pub cvtcil: bool,
917     /// This is a MSIL .NET Module.
918     pub msil_module: bool,
919     /// Compiled with `/sdl`.
920     pub sdl: bool,
921     /// Compiled with `/ltcg:pgo` or `pgo:`.
922     pub pgo: bool,
923     /// This is a .exp module.
924     pub exp_module: bool,
925 }
926 
927 impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlags {
928     type Error = Error;
929 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>930     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
931         let is_compile3 = kind == S_COMPILE3;
932 
933         let raw = this.pread_with::<u16>(0, LE)?;
934         this.pread::<u8>(2)?; // unused
935 
936         let flags = CompileFlags {
937             edit_and_continue: raw & 1 != 0,
938             no_debug_info: (raw >> 1) & 1 != 0,
939             link_time_codegen: (raw >> 2) & 1 != 0,
940             no_data_align: (raw >> 3) & 1 != 0,
941             managed: (raw >> 4) & 1 != 0,
942             security_checks: (raw >> 5) & 1 != 0,
943             hot_patch: (raw >> 6) & 1 != 0,
944             cvtcil: (raw >> 7) & 1 != 0,
945             msil_module: (raw >> 8) & 1 != 0,
946             sdl: (raw >> 9) & 1 != 0 && is_compile3,
947             pgo: (raw >> 10) & 1 != 0 && is_compile3,
948             exp_module: (raw >> 11) & 1 != 0 && is_compile3,
949         };
950 
951         Ok((flags, 3))
952     }
953 }
954 
955 /// Flags used to compile a module.
956 ///
957 /// Symbol kind `S_COMPILE2`, `S_COMPILE2_ST`, or `S_COMPILE3`.
958 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
959 pub struct CompileFlagsSymbol<'t> {
960     /// The source code language.
961     pub language: SourceLanguage,
962     /// Compiler flags.
963     pub flags: CompileFlags,
964     /// Machine type of the compilation target.
965     pub cpu_type: CPUType,
966     /// Version of the compiler frontend.
967     pub frontend_version: CompilerVersion,
968     /// Version of the compiler backend.
969     pub backend_version: CompilerVersion,
970     /// Display name of the compiler.
971     pub version_string: RawString<'t>,
972     // TODO: Command block for S_COMPILE2?
973 }
974 
975 impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlagsSymbol<'t> {
976     type Error = Error;
977 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>978     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
979         let mut buf = ParseBuffer::from(this);
980 
981         let has_qfe = kind == S_COMPILE3;
982         let symbol = CompileFlagsSymbol {
983             language: buf.parse()?,
984             flags: buf.parse_with(kind)?,
985             cpu_type: buf.parse()?,
986             frontend_version: buf.parse_with(has_qfe)?,
987             backend_version: buf.parse_with(has_qfe)?,
988             version_string: parse_symbol_name(&mut buf, kind)?,
989         };
990 
991         Ok((symbol, buf.pos()))
992     }
993 }
994 
995 /// A using namespace directive.
996 ///
997 /// Symbol kind `S_UNAMESPACE`, or `S_UNAMESPACE_ST`.
998 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
999 pub struct UsingNamespaceSymbol<'t> {
1000     /// The name of the imported namespace.
1001     pub name: RawString<'t>,
1002 }
1003 
1004 impl<'t> TryFromCtx<'t, SymbolKind> for UsingNamespaceSymbol<'t> {
1005     type Error = Error;
1006 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1007     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1008         let mut buf = ParseBuffer::from(this);
1009 
1010         let symbol = UsingNamespaceSymbol {
1011             name: parse_symbol_name(&mut buf, kind)?,
1012         };
1013 
1014         Ok((symbol, buf.pos()))
1015     }
1016 }
1017 
1018 // CV_LVARFLAGS:
1019 const CV_LVARFLAG_ISPARAM: u16 = 0x01;
1020 const CV_LVARFLAG_ADDRTAKEN: u16 = 0x02;
1021 const CV_LVARFLAG_COMPGENX: u16 = 0x04;
1022 const CV_LVARFLAG_ISAGGREGATE: u16 = 0x08;
1023 const CV_LVARFLAG_ISALIASED: u16 = 0x10;
1024 const CV_LVARFLAG_ISALIAS: u16 = 0x20;
1025 const CV_LVARFLAG_ISRETVALUE: u16 = 0x40;
1026 const CV_LVARFLAG_ISOPTIMIZEDOUT: u16 = 0x80;
1027 const CV_LVARFLAG_ISENREG_GLOB: u16 = 0x100;
1028 const CV_LVARFLAG_ISENREG_STAT: u16 = 0x200;
1029 
1030 /// Flags for a [`LocalSymbol`].
1031 #[non_exhaustive]
1032 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1033 pub struct LocalVariableFlags {
1034     /// Variable is a parameter.
1035     pub isparam: bool,
1036     /// Address is taken.
1037     pub addrtaken: bool,
1038     /// Variable is compiler generated.
1039     pub compgenx: bool,
1040     /// The symbol is splitted in temporaries, which are treated by compiler as independent
1041     /// entities.
1042     pub isaggregate: bool,
1043     /// Variable has multiple simultaneous lifetimes.
1044     pub isaliased: bool,
1045     /// Represents one of the multiple simultaneous lifetimes.
1046     pub isalias: bool,
1047     /// Represents a function return value.
1048     pub isretvalue: bool,
1049     /// Variable has no lifetimes.
1050     pub isoptimizedout: bool,
1051     /// Variable is an enregistered global.
1052     pub isenreg_glob: bool,
1053     /// Variable is an enregistered static.
1054     pub isenreg_stat: bool,
1055 }
1056 
1057 impl<'t> TryFromCtx<'t, Endian> for LocalVariableFlags {
1058     type Error = scroll::Error;
1059 
try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)>1060     fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
1061         let (value, size) = u16::try_from_ctx(this, le)?;
1062 
1063         let flags = LocalVariableFlags {
1064             isparam: value & CV_LVARFLAG_ISPARAM != 0,
1065             addrtaken: value & CV_LVARFLAG_ADDRTAKEN != 0,
1066             compgenx: value & CV_LVARFLAG_COMPGENX != 0,
1067             isaggregate: value & CV_LVARFLAG_ISAGGREGATE != 0,
1068             isaliased: value & CV_LVARFLAG_ISALIASED != 0,
1069             isalias: value & CV_LVARFLAG_ISALIAS != 0,
1070             isretvalue: value & CV_LVARFLAG_ISRETVALUE != 0,
1071             isoptimizedout: value & CV_LVARFLAG_ISOPTIMIZEDOUT != 0,
1072             isenreg_glob: value & CV_LVARFLAG_ISENREG_GLOB != 0,
1073             isenreg_stat: value & CV_LVARFLAG_ISENREG_STAT != 0,
1074         };
1075 
1076         Ok((flags, size))
1077     }
1078 }
1079 
1080 /// A local symbol in optimized code.
1081 ///
1082 /// Symbol kind `S_LOCAL`.
1083 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1084 pub struct LocalSymbol<'t> {
1085     /// The type of the symbol.
1086     pub type_index: TypeIndex,
1087     /// Flags for this symbol.
1088     pub flags: LocalVariableFlags,
1089     /// Name of the symbol.
1090     pub name: RawString<'t>,
1091 }
1092 
1093 impl<'t> TryFromCtx<'t, SymbolKind> for LocalSymbol<'t> {
1094     type Error = Error;
1095 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1096     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1097         let mut buf = ParseBuffer::from(this);
1098 
1099         let symbol = LocalSymbol {
1100             type_index: buf.parse()?,
1101             flags: buf.parse()?,
1102             name: parse_symbol_name(&mut buf, kind)?,
1103         };
1104 
1105         Ok((symbol, buf.pos()))
1106     }
1107 }
1108 
1109 // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4456
1110 /// Flags of an [`ExportSymbol`].
1111 #[non_exhaustive]
1112 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1113 pub struct ExportSymbolFlags {
1114     /// An exported constant.
1115     pub constant: bool,
1116     /// Exported data (e.g. a static variable).
1117     pub data: bool,
1118     /// A private symbol.
1119     pub private: bool,
1120     /// A symbol with no name.
1121     pub no_name: bool,
1122     /// Ordinal was explicitly assigned.
1123     pub ordinal: bool,
1124     /// This is a forwarder.
1125     pub forwarder: bool,
1126 }
1127 
1128 impl<'t> TryFromCtx<'t, Endian> for ExportSymbolFlags {
1129     type Error = scroll::Error;
1130 
try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)>1131     fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
1132         let (value, size) = u16::try_from_ctx(this, le)?;
1133 
1134         let flags = ExportSymbolFlags {
1135             constant: value & 0x01 != 0,
1136             data: value & 0x02 != 0,
1137             private: value & 0x04 != 0,
1138             no_name: value & 0x08 != 0,
1139             ordinal: value & 0x10 != 0,
1140             forwarder: value & 0x20 != 0,
1141         };
1142 
1143         Ok((flags, size))
1144     }
1145 }
1146 
1147 /// An exported symbol.
1148 ///
1149 /// Symbol kind `S_EXPORT`.
1150 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1151 pub struct ExportSymbol<'t> {
1152     /// Ordinal of the symbol.
1153     pub ordinal: u16,
1154     /// Flags declaring the type of the exported symbol.
1155     pub flags: ExportSymbolFlags,
1156     /// The name of the exported symbol.
1157     pub name: RawString<'t>,
1158 }
1159 
1160 impl<'t> TryFromCtx<'t, SymbolKind> for ExportSymbol<'t> {
1161     type Error = Error;
1162 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1163     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1164         let mut buf = ParseBuffer::from(this);
1165 
1166         let symbol = ExportSymbol {
1167             ordinal: buf.parse()?,
1168             flags: buf.parse()?,
1169             name: parse_symbol_name(&mut buf, kind)?,
1170         };
1171 
1172         Ok((symbol, buf.pos()))
1173     }
1174 }
1175 
1176 /// A label symbol.
1177 ///
1178 /// Symbol kind `S_LABEL32`, `S_LABEL16`, or `S_LABEL32_ST`.
1179 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1180 pub struct LabelSymbol<'t> {
1181     /// Code offset of the start of this label.
1182     pub offset: PdbInternalSectionOffset,
1183     /// Detailed flags of this label.
1184     pub flags: ProcedureFlags,
1185     /// Name of the symbol.
1186     pub name: RawString<'t>,
1187 }
1188 
1189 impl<'t> TryFromCtx<'t, SymbolKind> for LabelSymbol<'t> {
1190     type Error = Error;
1191 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1192     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1193         let mut buf = ParseBuffer::from(this);
1194 
1195         let symbol = LabelSymbol {
1196             offset: buf.parse()?,
1197             flags: buf.parse()?,
1198             name: parse_symbol_name(&mut buf, kind)?,
1199         };
1200 
1201         Ok((symbol, buf.pos()))
1202     }
1203 }
1204 
1205 /// A block symbol.
1206 ///
1207 /// Symbol kind `S_BLOCK32`, or `S_BLOCK32_ST`.
1208 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1209 pub struct BlockSymbol<'t> {
1210     /// The parent scope that this block is nested in.
1211     pub parent: SymbolIndex,
1212     /// The end symbol of this block.
1213     pub end: SymbolIndex,
1214     /// The length of the block.
1215     pub len: u32,
1216     /// Code offset of the start of this label.
1217     pub offset: PdbInternalSectionOffset,
1218     /// The block name.
1219     pub name: RawString<'t>,
1220 }
1221 
1222 impl<'t> TryFromCtx<'t, SymbolKind> for BlockSymbol<'t> {
1223     type Error = Error;
1224 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1225     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1226         let mut buf = ParseBuffer::from(this);
1227 
1228         let symbol = BlockSymbol {
1229             parent: buf.parse()?,
1230             end: buf.parse()?,
1231             len: buf.parse()?,
1232             offset: buf.parse()?,
1233             name: parse_symbol_name(&mut buf, kind)?,
1234         };
1235 
1236         Ok((symbol, buf.pos()))
1237     }
1238 }
1239 
1240 /// A register relative symbol.
1241 ///
1242 /// The address of the variable is the value in the register + offset (e.g. %EBP + 8).
1243 ///
1244 /// Symbol kind `S_REGREL32`.
1245 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1246 pub struct RegisterRelativeSymbol<'t> {
1247     /// The variable offset.
1248     pub offset: i32,
1249     /// The type of the variable.
1250     pub type_index: TypeIndex,
1251     /// The register this variable address is relative to.
1252     pub register: Register,
1253     /// The variable name.
1254     pub name: RawString<'t>,
1255 }
1256 
1257 impl<'t> TryFromCtx<'t, SymbolKind> for RegisterRelativeSymbol<'t> {
1258     type Error = Error;
1259 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1260     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1261         let mut buf = ParseBuffer::from(this);
1262 
1263         let symbol = RegisterRelativeSymbol {
1264             offset: buf.parse()?,
1265             type_index: buf.parse()?,
1266             register: buf.parse()?,
1267             name: parse_symbol_name(&mut buf, kind)?,
1268         };
1269 
1270         Ok((symbol, buf.pos()))
1271     }
1272 }
1273 
1274 /// Thunk adjustor
1275 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1276 pub struct ThunkAdjustor<'t> {
1277     delta: u16,
1278     target: RawString<'t>,
1279 }
1280 
1281 /// A thunk kind
1282 #[non_exhaustive]
1283 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1284 pub enum ThunkKind<'t> {
1285     /// Standard thunk
1286     NoType,
1287     /// "this" adjustor thunk with delta and target
1288     Adjustor(ThunkAdjustor<'t>),
1289     /// Virtual call thunk with table entry
1290     VCall(u16),
1291     /// pcode thunk
1292     PCode,
1293     /// thunk which loads the address to jump to via unknown means...
1294     Load,
1295     /// Unknown with ordinal value
1296     Unknown(u8),
1297 }
1298 
1299 /// A thunk symbol.
1300 ///
1301 /// Symbol kind `S_THUNK32`, or `S_THUNK32_ST`.
1302 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1303 pub struct ThunkSymbol<'t> {
1304     /// The parent scope that this thunk is nested in.
1305     pub parent: Option<SymbolIndex>,
1306     /// The end symbol of this thunk.
1307     pub end: SymbolIndex,
1308     /// The next symbol.
1309     pub next: Option<SymbolIndex>,
1310     /// Code offset of the start of this label.
1311     pub offset: PdbInternalSectionOffset,
1312     /// The length of the thunk.
1313     pub len: u16,
1314     /// The kind of the thunk.
1315     pub kind: ThunkKind<'t>,
1316     /// The thunk name.
1317     pub name: RawString<'t>,
1318 }
1319 
1320 impl<'t> TryFromCtx<'t, SymbolKind> for ThunkSymbol<'t> {
1321     type Error = Error;
1322 
try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)>1323     fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> {
1324         let mut buf = ParseBuffer::from(this);
1325 
1326         let parent = parse_optional_index(&mut buf)?;
1327         let end = buf.parse()?;
1328         let next = parse_optional_index(&mut buf)?;
1329         let offset = buf.parse()?;
1330         let len = buf.parse()?;
1331         let ord = buf.parse::<u8>()?;
1332         let name = parse_symbol_name(&mut buf, kind)?;
1333 
1334         let kind = match ord {
1335             0 => ThunkKind::NoType,
1336             1 => ThunkKind::Adjustor(ThunkAdjustor {
1337                 delta: buf.parse::<u16>()?,
1338                 target: buf.parse_cstring()?,
1339             }),
1340             2 => ThunkKind::VCall(buf.parse::<u16>()?),
1341             3 => ThunkKind::PCode,
1342             4 => ThunkKind::Load,
1343             ord => ThunkKind::Unknown(ord),
1344         };
1345 
1346         let symbol = ThunkSymbol {
1347             parent,
1348             end,
1349             next,
1350             offset,
1351             len,
1352             kind,
1353             name,
1354         };
1355 
1356         Ok((symbol, buf.pos()))
1357     }
1358 }
1359 
1360 // CV_SEPCODEFLAGS:
1361 const CV_SEPCODEFLAG_IS_LEXICAL_SCOPE: u32 = 0x01;
1362 const CV_SEPCODEFLAG_RETURNS_TO_PARENT: u32 = 0x02;
1363 
1364 /// Flags for a [`SeparatedCodeSymbol`].
1365 #[non_exhaustive]
1366 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1367 pub struct SeparatedCodeFlags {
1368     /// S_SEPCODE doubles as lexical scope.
1369     pub islexicalscope: bool,
1370     /// code frag returns to parent.
1371     pub returnstoparent: bool,
1372 }
1373 
1374 impl<'t> TryFromCtx<'t, Endian> for SeparatedCodeFlags {
1375     type Error = scroll::Error;
1376 
try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)>1377     fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
1378         let (value, size) = u32::try_from_ctx(this, le)?;
1379 
1380         let flags = SeparatedCodeFlags {
1381             islexicalscope: value & CV_SEPCODEFLAG_IS_LEXICAL_SCOPE != 0,
1382             returnstoparent: value & CV_SEPCODEFLAG_RETURNS_TO_PARENT != 0,
1383         };
1384 
1385         Ok((flags, size))
1386     }
1387 }
1388 
1389 /// A separated code symbol.
1390 ///
1391 /// Symbol kind `S_SEPCODE`.
1392 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
1393 pub struct SeparatedCodeSymbol {
1394     /// The parent scope that this block is nested in.
1395     pub parent: SymbolIndex,
1396     /// The end symbol of this block.
1397     pub end: SymbolIndex,
1398     /// The length of the block.
1399     pub len: u32,
1400     /// Flags for this symbol
1401     pub flags: SeparatedCodeFlags,
1402     /// Code offset of the start of the separated code.
1403     pub offset: PdbInternalSectionOffset,
1404     /// Parent offset.
1405     pub parent_offset: PdbInternalSectionOffset,
1406 }
1407 
1408 impl<'t> TryFromCtx<'t, SymbolKind> for SeparatedCodeSymbol {
1409     type Error = Error;
1410 
try_from_ctx(this: &'t [u8], _: SymbolKind) -> Result<(Self, usize)>1411     fn try_from_ctx(this: &'t [u8], _: SymbolKind) -> Result<(Self, usize)> {
1412         let mut buf = ParseBuffer::from(this);
1413 
1414         let parent = buf.parse()?;
1415         let end = buf.parse()?;
1416         let len = buf.parse()?;
1417         let flags = buf.parse()?;
1418         let offset = buf.parse()?;
1419         let parent_offset = buf.parse()?;
1420         let section = buf.parse()?;
1421         let parent_section = buf.parse()?;
1422 
1423         let symbol = SeparatedCodeSymbol {
1424             parent,
1425             end,
1426             len,
1427             flags,
1428             offset: PdbInternalSectionOffset { offset, section },
1429             parent_offset: PdbInternalSectionOffset {
1430                 offset: parent_offset,
1431                 section: parent_section,
1432             },
1433         };
1434 
1435         Ok((symbol, buf.pos()))
1436     }
1437 }
1438 
1439 /// PDB symbol tables contain names, locations, and metadata about functions, global/static data,
1440 /// constants, data types, and more.
1441 ///
1442 /// The `SymbolTable` holds a `SourceView` referencing the symbol table inside the PDB file. All the
1443 /// data structures returned by a `SymbolTable` refer to that buffer.
1444 ///
1445 /// # Example
1446 ///
1447 /// ```
1448 /// # use pdb::FallibleIterator;
1449 /// #
1450 /// # fn test() -> pdb::Result<usize> {
1451 /// let file = std::fs::File::open("fixtures/self/foo.pdb")?;
1452 /// let mut pdb = pdb::PDB::open(file)?;
1453 ///
1454 /// let symbol_table = pdb.global_symbols()?;
1455 /// let address_map = pdb.address_map()?;
1456 ///
1457 /// # let mut count: usize = 0;
1458 /// let mut symbols = symbol_table.iter();
1459 /// while let Some(symbol) = symbols.next()? {
1460 ///     match symbol.parse() {
1461 ///         Ok(pdb::SymbolData::Public(data)) if data.function => {
1462 ///             // we found the location of a function!
1463 ///             let rva = data.offset.to_rva(&address_map).unwrap_or_default();
1464 ///             println!("{} is {}", rva, data.name);
1465 ///             # count += 1;
1466 ///         }
1467 ///         _ => {}
1468 ///     }
1469 /// }
1470 ///
1471 /// # Ok(count)
1472 /// # }
1473 /// # assert!(test().expect("test") > 2000);
1474 /// ```
1475 #[derive(Debug)]
1476 pub struct SymbolTable<'s> {
1477     stream: Stream<'s>,
1478 }
1479 
1480 impl<'s> SymbolTable<'s> {
1481     /// Parses a symbol table from raw stream data.
new(stream: Stream<'s>) -> Self1482     pub(crate) fn new(stream: Stream<'s>) -> Self {
1483         SymbolTable { stream }
1484     }
1485 
1486     /// Returns an iterator that can traverse the symbol table in sequential order.
iter(&self) -> SymbolIter<'_>1487     pub fn iter(&self) -> SymbolIter<'_> {
1488         SymbolIter::new(self.stream.parse_buffer())
1489     }
1490 
1491     /// Returns an iterator over symbols starting at the given index.
iter_at(&self, index: SymbolIndex) -> SymbolIter<'_>1492     pub fn iter_at(&self, index: SymbolIndex) -> SymbolIter<'_> {
1493         let mut iter = self.iter();
1494         iter.seek(index);
1495         iter
1496     }
1497 }
1498 
1499 /// A `SymbolIter` iterates over a `SymbolTable`, producing `Symbol`s.
1500 ///
1501 /// Symbol tables are represented internally as a series of records, each of which have a length, a
1502 /// type, and a type-specific field layout. Iteration performance is therefore similar to a linked
1503 /// list.
1504 #[derive(Debug)]
1505 pub struct SymbolIter<'t> {
1506     buf: ParseBuffer<'t>,
1507 }
1508 
1509 impl<'t> SymbolIter<'t> {
new(buf: ParseBuffer<'t>) -> SymbolIter<'t>1510     pub(crate) fn new(buf: ParseBuffer<'t>) -> SymbolIter<'t> {
1511         SymbolIter { buf }
1512     }
1513 
1514     /// Move the iterator to the symbol referred to by `index`.
1515     ///
1516     /// This can be used to jump to the sibiling or parent of a symbol record.
seek(&mut self, index: SymbolIndex)1517     pub fn seek(&mut self, index: SymbolIndex) {
1518         self.buf.seek(index.0 as usize);
1519     }
1520 
1521     /// Skip to the symbol referred to by `index`, returning the symbol.
1522     ///
1523     /// This can be used to jump to the sibiling or parent of a symbol record. Iteration continues
1524     /// after that symbol.
1525     ///
1526     /// Note that the symbol may be located **before** the originating symbol, for instance when
1527     /// jumping to the parent symbol. Take care not to enter an endless loop in this case.
skip_to(&mut self, index: SymbolIndex) -> Result<Option<Symbol<'t>>>1528     pub fn skip_to(&mut self, index: SymbolIndex) -> Result<Option<Symbol<'t>>> {
1529         self.seek(index);
1530         self.next()
1531     }
1532 }
1533 
1534 impl<'t> FallibleIterator for SymbolIter<'t> {
1535     type Item = Symbol<'t>;
1536     type Error = Error;
1537 
next(&mut self) -> Result<Option<Self::Item>>1538     fn next(&mut self) -> Result<Option<Self::Item>> {
1539         while !self.buf.is_empty() {
1540             let index = SymbolIndex(self.buf.pos() as u32);
1541 
1542             // read the length of the next symbol
1543             let symbol_length = self.buf.parse::<u16>()? as usize;
1544             if symbol_length < 2 {
1545                 // this can't be correct
1546                 return Err(Error::SymbolTooShort);
1547             }
1548 
1549             // grab the symbol itself
1550             let data = self.buf.take(symbol_length)?;
1551             let symbol = Symbol { index, data };
1552 
1553             // skip over padding in the symbol table
1554             match symbol.raw_kind() {
1555                 S_ALIGN | S_SKIP => continue,
1556                 _ => return Ok(Some(symbol)),
1557             }
1558         }
1559 
1560         Ok(None)
1561     }
1562 }
1563 
1564 #[cfg(test)]
1565 mod tests {
1566     mod parsing {
1567         use crate::symbol::*;
1568 
1569         #[test]
kind_0006()1570         fn kind_0006() {
1571             let data = &[6, 0];
1572 
1573             let symbol = Symbol {
1574                 data,
1575                 index: SymbolIndex(0),
1576             };
1577             assert_eq!(symbol.raw_kind(), 0x0006);
1578             assert_eq!(symbol.parse().expect("parse"), SymbolData::ScopeEnd);
1579         }
1580 
1581         #[test]
kind_1101()1582         fn kind_1101() {
1583             let data = &[1, 17, 0, 0, 0, 0, 42, 32, 67, 73, 76, 32, 42, 0];
1584 
1585             let symbol = Symbol {
1586                 data,
1587                 index: SymbolIndex(0),
1588             };
1589             assert_eq!(symbol.raw_kind(), 0x1101);
1590             assert_eq!(
1591                 symbol.parse().expect("parse"),
1592                 SymbolData::ObjName(ObjNameSymbol {
1593                     signature: 0,
1594                     name: "* CIL *".into(),
1595                 })
1596             );
1597         }
1598 
1599         #[test]
kind_1102()1600         fn kind_1102() {
1601             let data = &[
1602                 2, 17, 0, 0, 0, 0, 108, 22, 0, 0, 0, 0, 0, 0, 140, 11, 0, 0, 1, 0, 9, 0, 3, 91,
1603                 116, 104, 117, 110, 107, 93, 58, 68, 101, 114, 105, 118, 101, 100, 58, 58, 70, 117,
1604                 110, 99, 49, 96, 97, 100, 106, 117, 115, 116, 111, 114, 123, 56, 125, 39, 0, 0, 0,
1605                 0,
1606             ];
1607 
1608             let symbol = Symbol {
1609                 data,
1610                 index: SymbolIndex(0),
1611             };
1612             assert_eq!(symbol.raw_kind(), 0x1102);
1613             assert_eq!(
1614                 symbol.parse().expect("parse"),
1615                 SymbolData::Thunk(ThunkSymbol {
1616                     parent: None,
1617                     end: SymbolIndex(0x166c),
1618                     next: None,
1619                     offset: PdbInternalSectionOffset {
1620                         section: 0x1,
1621                         offset: 0xb8c
1622                     },
1623                     len: 9,
1624                     kind: ThunkKind::PCode,
1625                     name: "[thunk]:Derived::Func1`adjustor{8}'".into()
1626                 })
1627             );
1628         }
1629 
1630         #[test]
kind_1105()1631         fn kind_1105() {
1632             let data = &[
1633                 5, 17, 224, 95, 151, 0, 1, 0, 0, 100, 97, 118, 49, 100, 95, 119, 95, 97, 118, 103,
1634                 95, 115, 115, 115, 101, 51, 0, 0, 0, 0,
1635             ];
1636 
1637             let symbol = Symbol {
1638                 data,
1639                 index: SymbolIndex(0),
1640             };
1641             assert_eq!(symbol.raw_kind(), 0x1105);
1642             assert_eq!(
1643                 symbol.parse().expect("parse"),
1644                 SymbolData::Label(LabelSymbol {
1645                     offset: PdbInternalSectionOffset {
1646                         offset: 0x0097_5fe0,
1647                         section: 1
1648                     },
1649                     flags: ProcedureFlags {
1650                         nofpo: false,
1651                         int: false,
1652                         far: false,
1653                         never: false,
1654                         notreached: false,
1655                         cust_call: false,
1656                         noinline: false,
1657                         optdbginfo: false
1658                     },
1659                     name: "dav1d_w_avg_ssse3".into(),
1660                 })
1661             );
1662         }
1663 
1664         #[test]
kind_1106()1665         fn kind_1106() {
1666             let data = &[6, 17, 120, 34, 0, 0, 18, 0, 116, 104, 105, 115, 0, 0];
1667 
1668             let symbol = Symbol {
1669                 data,
1670                 index: SymbolIndex(0),
1671             };
1672             assert_eq!(symbol.raw_kind(), 0x1106);
1673             assert_eq!(
1674                 symbol.parse().expect("parse"),
1675                 SymbolData::RegisterVariable(RegisterVariableSymbol {
1676                     type_index: TypeIndex(8824),
1677                     register: Register(18),
1678                     name: "this".into(),
1679                 })
1680             );
1681         }
1682 
1683         #[test]
kind_110e()1684         fn kind_110e() {
1685             let data = &[
1686                 14, 17, 2, 0, 0, 0, 192, 85, 0, 0, 1, 0, 95, 95, 108, 111, 99, 97, 108, 95, 115,
1687                 116, 100, 105, 111, 95, 112, 114, 105, 110, 116, 102, 95, 111, 112, 116, 105, 111,
1688                 110, 115, 0, 0,
1689             ];
1690 
1691             let symbol = Symbol {
1692                 data,
1693                 index: SymbolIndex(0),
1694             };
1695             assert_eq!(symbol.raw_kind(), 0x110e);
1696             assert_eq!(
1697                 symbol.parse().expect("parse"),
1698                 SymbolData::Public(PublicSymbol {
1699                     code: false,
1700                     function: true,
1701                     managed: false,
1702                     msil: false,
1703                     offset: PdbInternalSectionOffset {
1704                         offset: 21952,
1705                         section: 1
1706                     },
1707                     name: "__local_stdio_printf_options".into(),
1708                 })
1709             );
1710         }
1711 
1712         #[test]
kind_1111()1713         fn kind_1111() {
1714             let data = &[
1715                 17, 17, 12, 0, 0, 0, 48, 16, 0, 0, 22, 0, 109, 97, 120, 105, 109, 117, 109, 95, 99,
1716                 111, 117, 110, 116, 0,
1717             ];
1718 
1719             let symbol = Symbol {
1720                 data,
1721                 index: SymbolIndex(0),
1722             };
1723             assert_eq!(symbol.raw_kind(), 0x1111);
1724             assert_eq!(
1725                 symbol.parse().expect("parse"),
1726                 SymbolData::RegisterRelative(RegisterRelativeSymbol {
1727                     offset: 12,
1728                     type_index: TypeIndex(0x1030),
1729                     register: Register(22),
1730                     name: "maximum_count".into(),
1731                 })
1732             );
1733         }
1734 
1735         #[test]
kind_1124()1736         fn kind_1124() {
1737             let data = &[36, 17, 115, 116, 100, 0];
1738 
1739             let symbol = Symbol {
1740                 data,
1741                 index: SymbolIndex(0),
1742             };
1743             assert_eq!(symbol.raw_kind(), 0x1124);
1744             assert_eq!(
1745                 symbol.parse().expect("parse"),
1746                 SymbolData::UsingNamespace(UsingNamespaceSymbol { name: "std".into() })
1747             );
1748         }
1749 
1750         #[test]
kind_1125()1751         fn kind_1125() {
1752             let data = &[
1753                 37, 17, 0, 0, 0, 0, 108, 0, 0, 0, 1, 0, 66, 97, 122, 58, 58, 102, 95, 112, 117, 98,
1754                 108, 105, 99, 0,
1755             ];
1756             let symbol = Symbol {
1757                 data,
1758                 index: SymbolIndex(0),
1759             };
1760             assert_eq!(symbol.raw_kind(), 0x1125);
1761             assert_eq!(
1762                 symbol.parse().expect("parse"),
1763                 SymbolData::ProcedureReference(ProcedureReferenceSymbol {
1764                     global: true,
1765                     sum_name: 0,
1766                     symbol_index: SymbolIndex(108),
1767                     module: 1,
1768                     name: Some("Baz::f_public".into()),
1769                 })
1770             );
1771         }
1772 
1773         #[test]
kind_1108()1774         fn kind_1108() {
1775             let data = &[8, 17, 112, 6, 0, 0, 118, 97, 95, 108, 105, 115, 116, 0];
1776             let symbol = Symbol {
1777                 data,
1778                 index: SymbolIndex(0),
1779             };
1780             assert_eq!(symbol.raw_kind(), 0x1108);
1781             assert_eq!(
1782                 symbol.parse().expect("parse"),
1783                 SymbolData::UserDefinedType(UserDefinedTypeSymbol {
1784                     type_index: TypeIndex(1648),
1785                     name: "va_list".into(),
1786                 })
1787             );
1788         }
1789 
1790         #[test]
kind_1107()1791         fn kind_1107() {
1792             let data = &[
1793                 7, 17, 201, 18, 0, 0, 1, 0, 95, 95, 73, 83, 65, 95, 65, 86, 65, 73, 76, 65, 66, 76,
1794                 69, 95, 83, 83, 69, 50, 0, 0,
1795             ];
1796             let symbol = Symbol {
1797                 data,
1798                 index: SymbolIndex(0),
1799             };
1800             assert_eq!(symbol.raw_kind(), 0x1107);
1801             assert_eq!(
1802                 symbol.parse().expect("parse"),
1803                 SymbolData::Constant(ConstantSymbol {
1804                     managed: false,
1805                     type_index: TypeIndex(4809),
1806                     value: Variant::U16(1),
1807                     name: "__ISA_AVAILABLE_SSE2".into(),
1808                 })
1809             );
1810         }
1811 
1812         #[test]
kind_110d()1813         fn kind_110d() {
1814             let data = &[
1815                 13, 17, 116, 0, 0, 0, 16, 0, 0, 0, 3, 0, 95, 95, 105, 115, 97, 95, 97, 118, 97,
1816                 105, 108, 97, 98, 108, 101, 0, 0, 0,
1817             ];
1818             let symbol = Symbol {
1819                 data,
1820                 index: SymbolIndex(0),
1821             };
1822             assert_eq!(symbol.raw_kind(), 0x110d);
1823             assert_eq!(
1824                 symbol.parse().expect("parse"),
1825                 SymbolData::Data(DataSymbol {
1826                     global: true,
1827                     managed: false,
1828                     type_index: TypeIndex(116),
1829                     offset: PdbInternalSectionOffset {
1830                         offset: 16,
1831                         section: 3
1832                     },
1833                     name: "__isa_available".into(),
1834                 })
1835             );
1836         }
1837 
1838         #[test]
kind_110c()1839         fn kind_110c() {
1840             let data = &[
1841                 12, 17, 32, 0, 0, 0, 240, 36, 1, 0, 2, 0, 36, 120, 100, 97, 116, 97, 115, 121, 109,
1842                 0,
1843             ];
1844             let symbol = Symbol {
1845                 data,
1846                 index: SymbolIndex(0),
1847             };
1848             assert_eq!(symbol.raw_kind(), 0x110c);
1849             assert_eq!(
1850                 symbol.parse().expect("parse"),
1851                 SymbolData::Data(DataSymbol {
1852                     global: false,
1853                     managed: false,
1854                     type_index: TypeIndex(32),
1855                     offset: PdbInternalSectionOffset {
1856                         offset: 74992,
1857                         section: 2
1858                     },
1859                     name: "$xdatasym".into(),
1860                 })
1861             );
1862         }
1863 
1864         #[test]
kind_1127()1865         fn kind_1127() {
1866             let data = &[
1867                 39, 17, 0, 0, 0, 0, 128, 4, 0, 0, 182, 0, 99, 97, 112, 116, 117, 114, 101, 95, 99,
1868                 117, 114, 114, 101, 110, 116, 95, 99, 111, 110, 116, 101, 120, 116, 0, 0, 0,
1869             ];
1870             let symbol = Symbol {
1871                 data,
1872                 index: SymbolIndex(0),
1873             };
1874             assert_eq!(symbol.raw_kind(), 0x1127);
1875             assert_eq!(
1876                 symbol.parse().expect("parse"),
1877                 SymbolData::ProcedureReference(ProcedureReferenceSymbol {
1878                     global: false,
1879                     sum_name: 0,
1880                     symbol_index: SymbolIndex(1152),
1881                     module: 182,
1882                     name: Some("capture_current_context".into()),
1883                 })
1884             );
1885         }
1886 
1887         #[test]
kind_1110()1888         fn kind_1110() {
1889             let data = &[
1890                 16, 17, 0, 0, 0, 0, 48, 2, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 7,
1891                 16, 0, 0, 64, 85, 0, 0, 1, 0, 0, 66, 97, 122, 58, 58, 102, 95, 112, 114, 111, 116,
1892                 101, 99, 116, 101, 100, 0,
1893             ];
1894             let symbol = Symbol {
1895                 data,
1896                 index: SymbolIndex(0),
1897             };
1898             assert_eq!(symbol.raw_kind(), 0x1110);
1899             assert_eq!(
1900                 symbol.parse().expect("parse"),
1901                 SymbolData::Procedure(ProcedureSymbol {
1902                     global: true,
1903                     dpc: false,
1904                     parent: None,
1905                     end: SymbolIndex(560),
1906                     next: None,
1907                     len: 6,
1908                     dbg_start_offset: 5,
1909                     dbg_end_offset: 5,
1910                     type_index: TypeIndex(4103),
1911                     offset: PdbInternalSectionOffset {
1912                         offset: 21824,
1913                         section: 1
1914                     },
1915                     flags: ProcedureFlags {
1916                         nofpo: false,
1917                         int: false,
1918                         far: false,
1919                         never: false,
1920                         notreached: false,
1921                         cust_call: false,
1922                         noinline: false,
1923                         optdbginfo: false
1924                     },
1925                     name: "Baz::f_protected".into(),
1926                 })
1927             );
1928         }
1929 
1930         #[test]
kind_1103()1931         fn kind_1103() {
1932             let data = &[
1933                 3, 17, 244, 149, 9, 0, 40, 151, 9, 0, 135, 1, 0, 0, 108, 191, 184, 2, 1, 0, 0, 0,
1934             ];
1935 
1936             let symbol = Symbol {
1937                 data,
1938                 index: SymbolIndex(0),
1939             };
1940             assert_eq!(symbol.raw_kind(), 0x1103);
1941             assert_eq!(
1942                 symbol.parse().expect("parse"),
1943                 SymbolData::Block(BlockSymbol {
1944                     parent: SymbolIndex(0x0009_95f4),
1945                     end: SymbolIndex(0x0009_9728),
1946                     len: 391,
1947                     offset: PdbInternalSectionOffset {
1948                         section: 0x1,
1949                         offset: 0x02b8_bf6c
1950                     },
1951                     name: "".into(),
1952                 })
1953             );
1954         }
1955 
1956         #[test]
kind_110f()1957         fn kind_110f() {
1958             let data = &[
1959                 15, 17, 0, 0, 0, 0, 156, 1, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0,
1960                 128, 16, 0, 0, 196, 87, 0, 0, 1, 0, 128, 95, 95, 115, 99, 114, 116, 95, 99, 111,
1961                 109, 109, 111, 110, 95, 109, 97, 105, 110, 0, 0, 0,
1962             ];
1963             let symbol = Symbol {
1964                 data,
1965                 index: SymbolIndex(0),
1966             };
1967             assert_eq!(symbol.raw_kind(), 0x110f);
1968             assert_eq!(
1969                 symbol.parse().expect("parse"),
1970                 SymbolData::Procedure(ProcedureSymbol {
1971                     global: false,
1972                     dpc: false,
1973                     parent: None,
1974                     end: SymbolIndex(412),
1975                     next: None,
1976                     len: 18,
1977                     dbg_start_offset: 4,
1978                     dbg_end_offset: 9,
1979                     type_index: TypeIndex(4224),
1980                     offset: PdbInternalSectionOffset {
1981                         offset: 22468,
1982                         section: 1
1983                     },
1984                     flags: ProcedureFlags {
1985                         nofpo: false,
1986                         int: false,
1987                         far: false,
1988                         never: false,
1989                         notreached: false,
1990                         cust_call: false,
1991                         noinline: false,
1992                         optdbginfo: true
1993                     },
1994                     name: "__scrt_common_main".into(),
1995                 })
1996             );
1997         }
1998 
1999         #[test]
kind_1116()2000         fn kind_1116() {
2001             let data = &[
2002                 22, 17, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 14, 0, 10, 0, 115, 98, 77, 105, 99,
2003                 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 76, 73, 78, 75, 0, 0, 0, 0,
2004             ];
2005 
2006             let symbol = Symbol {
2007                 data,
2008                 index: SymbolIndex(0),
2009             };
2010             assert_eq!(symbol.raw_kind(), 0x1116);
2011             assert_eq!(
2012                 symbol.parse().expect("parse"),
2013                 SymbolData::CompileFlags(CompileFlagsSymbol {
2014                     language: SourceLanguage::Link,
2015                     flags: CompileFlags {
2016                         edit_and_continue: false,
2017                         no_debug_info: false,
2018                         link_time_codegen: false,
2019                         no_data_align: false,
2020                         managed: false,
2021                         security_checks: false,
2022                         hot_patch: false,
2023                         cvtcil: false,
2024                         msil_module: false,
2025                         sdl: false,
2026                         pgo: false,
2027                         exp_module: false,
2028                     },
2029                     cpu_type: CPUType::Intel80386,
2030                     frontend_version: CompilerVersion {
2031                         major: 0,
2032                         minor: 0,
2033                         build: 0,
2034                         qfe: None,
2035                     },
2036                     backend_version: CompilerVersion {
2037                         major: 14,
2038                         minor: 10,
2039                         build: 25203,
2040                         qfe: None,
2041                     },
2042                     version_string: "Microsoft (R) LINK".into(),
2043                 })
2044             );
2045         }
2046 
2047         #[test]
kind_1132()2048         fn kind_1132() {
2049             let data = &[
2050                 50, 17, 0, 0, 0, 0, 108, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 196, 252, 10, 0, 56, 67,
2051                 0, 0, 1, 0, 1, 0,
2052             ];
2053 
2054             let symbol = Symbol {
2055                 data,
2056                 index: SymbolIndex(0),
2057             };
2058             assert_eq!(symbol.raw_kind(), 0x1132);
2059             assert_eq!(
2060                 symbol.parse().expect("parse"),
2061                 SymbolData::SeparatedCode(SeparatedCodeSymbol {
2062                     parent: SymbolIndex(0x0),
2063                     end: SymbolIndex(0x6c),
2064                     len: 88,
2065                     flags: SeparatedCodeFlags {
2066                         islexicalscope: false,
2067                         returnstoparent: false
2068                     },
2069                     offset: PdbInternalSectionOffset {
2070                         section: 0x1,
2071                         offset: 0xafcc4
2072                     },
2073                     parent_offset: PdbInternalSectionOffset {
2074                         section: 0x1,
2075                         offset: 0x4338
2076                     }
2077                 })
2078             );
2079         }
2080 
2081         #[test]
kind_113c()2082         fn kind_113c() {
2083             let data = &[
2084                 60, 17, 1, 36, 2, 0, 7, 0, 19, 0, 13, 0, 6, 102, 0, 0, 19, 0, 13, 0, 6, 102, 0, 0,
2085                 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 79, 112, 116, 105,
2086                 109, 105, 122, 105, 110, 103, 32, 67, 111, 109, 112, 105, 108, 101, 114, 0,
2087             ];
2088 
2089             let symbol = Symbol {
2090                 data,
2091                 index: SymbolIndex(0),
2092             };
2093             assert_eq!(symbol.raw_kind(), 0x113c);
2094             assert_eq!(
2095                 symbol.parse().expect("parse"),
2096                 SymbolData::CompileFlags(CompileFlagsSymbol {
2097                     language: SourceLanguage::Cpp,
2098                     flags: CompileFlags {
2099                         edit_and_continue: false,
2100                         no_debug_info: false,
2101                         link_time_codegen: true,
2102                         no_data_align: false,
2103                         managed: false,
2104                         security_checks: true,
2105                         hot_patch: false,
2106                         cvtcil: false,
2107                         msil_module: false,
2108                         sdl: true,
2109                         pgo: false,
2110                         exp_module: false,
2111                     },
2112                     cpu_type: CPUType::Pentium3,
2113                     frontend_version: CompilerVersion {
2114                         major: 19,
2115                         minor: 13,
2116                         build: 26118,
2117                         qfe: Some(0),
2118                     },
2119                     backend_version: CompilerVersion {
2120                         major: 19,
2121                         minor: 13,
2122                         build: 26118,
2123                         qfe: Some(0),
2124                     },
2125                     version_string: "Microsoft (R) Optimizing Compiler".into(),
2126                 })
2127             );
2128         }
2129 
2130         #[test]
kind_113e()2131         fn kind_113e() {
2132             let data = &[62, 17, 193, 19, 0, 0, 1, 0, 116, 104, 105, 115, 0, 0];
2133 
2134             let symbol = Symbol {
2135                 data,
2136                 index: SymbolIndex(0),
2137             };
2138             assert_eq!(symbol.raw_kind(), 0x113e);
2139             assert_eq!(
2140                 symbol.parse().expect("parse"),
2141                 SymbolData::Local(LocalSymbol {
2142                     type_index: TypeIndex(5057),
2143                     flags: LocalVariableFlags {
2144                         isparam: true,
2145                         addrtaken: false,
2146                         compgenx: false,
2147                         isaggregate: false,
2148                         isaliased: false,
2149                         isalias: false,
2150                         isretvalue: false,
2151                         isoptimizedout: false,
2152                         isenreg_glob: false,
2153                         isenreg_stat: false,
2154                     },
2155                     name: "this".into(),
2156                 })
2157             );
2158         }
2159 
2160         #[test]
kind_114c()2161         fn kind_114c() {
2162             let data = &[76, 17, 95, 17, 0, 0];
2163 
2164             let symbol = Symbol {
2165                 data,
2166                 index: SymbolIndex(0),
2167             };
2168             assert_eq!(symbol.raw_kind(), 0x114c);
2169             assert_eq!(
2170                 symbol.parse().expect("parse"),
2171                 SymbolData::BuildInfo(BuildInfoSymbol {
2172                     id: IdIndex(0x115F)
2173                 })
2174             );
2175         }
2176 
2177         #[test]
kind_114d()2178         fn kind_114d() {
2179             let data = &[
2180                 77, 17, 144, 1, 0, 0, 208, 1, 0, 0, 121, 17, 0, 0, 12, 6, 3, 0,
2181             ];
2182 
2183             let symbol = Symbol {
2184                 data,
2185                 index: SymbolIndex(0),
2186             };
2187             assert_eq!(symbol.raw_kind(), 0x114d);
2188             assert_eq!(
2189                 symbol.parse().expect("parse"),
2190                 SymbolData::InlineSite(InlineSiteSymbol {
2191                     parent: Some(SymbolIndex(0x0190)),
2192                     end: SymbolIndex(0x01d0),
2193                     inlinee: IdIndex(4473),
2194                     invocations: None,
2195                     annotations: BinaryAnnotations::new(&[12, 6, 3, 0]),
2196                 })
2197             );
2198         }
2199 
2200         #[test]
kind_114e()2201         fn kind_114e() {
2202             let data = &[78, 17];
2203 
2204             let symbol = Symbol {
2205                 data,
2206                 index: SymbolIndex(0),
2207             };
2208             assert_eq!(symbol.raw_kind(), 0x114e);
2209             assert_eq!(symbol.parse().expect("parse"), SymbolData::InlineSiteEnd);
2210         }
2211     }
2212 
2213     mod iterator {
2214         use crate::symbol::*;
2215 
create_iter() -> SymbolIter<'static>2216         fn create_iter() -> SymbolIter<'static> {
2217             let data = &[
2218                 0x00, 0x00, 0x00, 0x00, // module signature (padding)
2219                 0x02, 0x00, 0x4e, 0x11, // S_INLINESITE_END
2220                 0x02, 0x00, 0x06, 0x00, // S_END
2221             ];
2222 
2223             let mut buf = ParseBuffer::from(&data[..]);
2224             buf.seek(4); // skip the module signature
2225             SymbolIter::new(buf)
2226         }
2227 
2228         #[test]
test_iter()2229         fn test_iter() {
2230             let symbols: Vec<_> = create_iter().collect().expect("collect");
2231 
2232             let expected = [
2233                 Symbol {
2234                     index: SymbolIndex(0x4),
2235                     data: &[0x4e, 0x11], // S_INLINESITE_END
2236                 },
2237                 Symbol {
2238                     index: SymbolIndex(0x8),
2239                     data: &[0x06, 0x00], // S_END
2240                 },
2241             ];
2242 
2243             assert_eq!(symbols, expected);
2244         }
2245 
2246         #[test]
test_seek()2247         fn test_seek() {
2248             let mut symbols = create_iter();
2249             symbols.seek(SymbolIndex(0x8));
2250 
2251             let symbol = symbols.next().expect("get symbol");
2252             let expected = Symbol {
2253                 index: SymbolIndex(0x8),
2254                 data: &[0x06, 0x00], // S_END
2255             };
2256 
2257             assert_eq!(symbol, Some(expected));
2258         }
2259 
2260         #[test]
test_skip_to()2261         fn test_skip_to() {
2262             let mut symbols = create_iter();
2263             let symbol = symbols.skip_to(SymbolIndex(0x8)).expect("get symbol");
2264 
2265             let expected = Symbol {
2266                 index: SymbolIndex(0x8),
2267                 data: &[0x06, 0x00], // S_END
2268             };
2269 
2270             assert_eq!(symbol, Some(expected));
2271         }
2272     }
2273 }
2274