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