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 #![allow(missing_docs)]
9 
10 use crate::common::*;
11 use crate::tpi::constants::*;
12 use crate::tpi::primitive::*;
13 
14 /// Encapsulates parsed data about a `Type`.
15 #[non_exhaustive]
16 #[derive(Debug, Clone, PartialEq, Eq)]
17 pub enum TypeData<'t> {
18     Primitive(PrimitiveType),
19     Class(ClassType<'t>),
20     Member(MemberType<'t>),
21     MemberFunction(MemberFunctionType),
22     OverloadedMethod(OverloadedMethodType<'t>),
23     Method(MethodType<'t>),
24     StaticMember(StaticMemberType<'t>),
25     Nested(NestedType<'t>),
26     BaseClass(BaseClassType),
27     VirtualBaseClass(VirtualBaseClassType),
28     VirtualFunctionTablePointer(VirtualFunctionTablePointerType),
29     Procedure(ProcedureType),
30     Pointer(PointerType),
31     Modifier(ModifierType),
32     Enumeration(EnumerationType<'t>),
33     Enumerate(EnumerateType<'t>),
34     Array(ArrayType),
35     Union(UnionType<'t>),
36     Bitfield(BitfieldType),
37     FieldList(FieldList<'t>),
38     ArgumentList(ArgumentList),
39     MethodList(MethodList),
40 }
41 
42 impl<'t> TypeData<'t> {
43     /// Return the name of this TypeData, if any
name(&self) -> Option<RawString<'t>>44     pub fn name(&self) -> Option<RawString<'t>> {
45         let name = match *self {
46             TypeData::Class(ClassType { ref name, .. })
47             | TypeData::Member(MemberType { ref name, .. })
48             | TypeData::OverloadedMethod(OverloadedMethodType { ref name, .. })
49             | TypeData::StaticMember(StaticMemberType { ref name, .. })
50             | TypeData::Nested(NestedType { ref name, .. })
51             | TypeData::Enumeration(EnumerationType { ref name, .. })
52             | TypeData::Enumerate(EnumerateType { ref name, .. })
53             | TypeData::Union(UnionType { ref name, .. }) => name,
54             _ => return None,
55         };
56 
57         Some(*name)
58     }
59 }
60 
61 /// Parse a type out of a `ParseBuffer`.
parse_type_data<'t>(mut buf: &mut ParseBuffer<'t>) -> Result<TypeData<'t>>62 pub(crate) fn parse_type_data<'t>(mut buf: &mut ParseBuffer<'t>) -> Result<TypeData<'t>> {
63     let leaf = buf.parse_u16()?;
64 
65     match leaf {
66         // Basic types
67         // -----------
68 
69         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631-L1642
70         LF_CLASS | LF_CLASS_ST | LF_STRUCTURE | LF_STRUCTURE_ST | LF_INTERFACE => {
71             let mut class = ClassType {
72                 kind: match leaf {
73                     LF_CLASS | LF_CLASS_ST => ClassKind::Class,
74                     LF_STRUCTURE | LF_STRUCTURE_ST => ClassKind::Struct,
75                     LF_INTERFACE => ClassKind::Interface,
76                     _ => unreachable!(),
77                 },
78                 count: buf.parse_u16()?,
79                 properties: TypeProperties(buf.parse_u16()?),
80                 fields: parse_optional_type_index(&mut buf)?,
81                 derived_from: parse_optional_type_index(&mut buf)?,
82                 vtable_shape: parse_optional_type_index(&mut buf)?,
83                 size: parse_unsigned(&mut buf)? as u16,
84                 name: parse_string(leaf, buf)?,
85                 unique_name: None,
86             };
87 
88             if class.properties.has_unique_name() {
89                 class.unique_name = Some(parse_string(leaf, buf)?);
90             }
91 
92             Ok(TypeData::Class(class))
93         }
94 
95         // https://github.com/microsoft/microsoft-pdb/issues/50#issuecomment-737890766
96         LF_STRUCTURE19 => {
97             let mut class = ClassType {
98                 kind: ClassKind::Struct,
99                 properties: TypeProperties(buf.parse_u32()? as u16),
100                 fields: parse_optional_type_index(&mut buf)?,
101                 derived_from: parse_optional_type_index(&mut buf)?,
102                 vtable_shape: parse_optional_type_index(&mut buf)?,
103                 count: buf.parse_u16()?,
104                 size: parse_unsigned(&mut buf)? as u16,
105                 name: parse_string(leaf, buf)?,
106                 unique_name: None,
107             };
108 
109             if class.properties.has_unique_name() {
110                 class.unique_name = Some(parse_string(leaf, buf)?);
111             }
112 
113             Ok(TypeData::Class(class))
114         }
115 
116         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2580-L2586
117         LF_MEMBER | LF_MEMBER_ST => Ok(TypeData::Member(MemberType {
118             attributes: FieldAttributes(buf.parse_u16()?),
119             field_type: buf.parse()?,
120             offset: parse_unsigned(&mut buf)? as u16,
121             name: parse_string(leaf, &mut buf)?,
122         })),
123 
124         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2699-L2714
125         LF_NESTTYPE | LF_NESTTYPE_ST | LF_NESTTYPEEX | LF_NESTTYPEEX_ST => {
126             // These structs differ in their use of the first 16 bits
127             let raw_attr = match leaf {
128                 LF_NESTTYPEEX | LF_NESTTYPEEX_ST => buf.parse_u16()?,
129                 _ => {
130                     // discard padding
131                     buf.parse_u16()?;
132                     // assume zero
133                     0
134                 }
135             };
136 
137             Ok(TypeData::Nested(NestedType {
138                 attributes: FieldAttributes(raw_attr),
139                 nested_type: buf.parse()?,
140                 name: parse_string(leaf, &mut buf)?,
141             }))
142         }
143 
144         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1801-L1811
145         LF_MFUNCTION => Ok(TypeData::MemberFunction(MemberFunctionType {
146             return_type: buf.parse()?,
147             class_type: buf.parse()?,
148             this_pointer_type: parse_optional_type_index(&mut buf)?,
149             attributes: FunctionAttributes(buf.parse_u16()?),
150             parameter_count: buf.parse_u16()?,
151             argument_list: buf.parse()?,
152             this_adjustment: buf.parse_u32()?,
153         })),
154 
155         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2650-L2655
156         LF_METHOD | LF_METHOD_ST => Ok(TypeData::OverloadedMethod(OverloadedMethodType {
157             count: buf.parse_u16()?,
158             method_list: buf.parse()?,
159             name: parse_string(leaf, &mut buf)?,
160         })),
161 
162         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2671-L2678
163         LF_ONEMETHOD | LF_ONEMETHOD_ST => {
164             let attr = FieldAttributes(buf.parse_u16()?);
165             Ok(TypeData::Method(MethodType {
166                 attributes: attr,
167                 method_type: buf.parse()?,
168                 vtable_offset: if attr.is_intro_virtual() {
169                     Some(buf.parse_u32()? as u32)
170                 } else {
171                     // yes, this is variable length
172                     None
173                 },
174                 name: parse_string(leaf, &mut buf)?,
175             }))
176         }
177 
178         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2499-L2505
179         LF_BCLASS | LF_BINTERFACE => Ok(TypeData::BaseClass(BaseClassType {
180             kind: match leaf {
181                 LF_BCLASS => ClassKind::Class,
182                 LF_BINTERFACE => ClassKind::Interface,
183                 _ => unreachable!(),
184             },
185             attributes: FieldAttributes(buf.parse_u16()?),
186             base_class: buf.parse()?,
187             offset: parse_unsigned(&mut buf)? as u32,
188         })),
189 
190         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2615-L2619
191         LF_VFUNCTAB => {
192             // padding is supposed to be zero always, but… let's not check
193             buf.parse_u16()?;
194             Ok(TypeData::VirtualFunctionTablePointer(
195                 VirtualFunctionTablePointerType {
196                     table: buf.parse()?,
197                 },
198             ))
199         }
200 
201         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2599-L2604
202         LF_STMEMBER | LF_STMEMBER_ST => Ok(TypeData::StaticMember(StaticMemberType {
203             attributes: FieldAttributes(buf.parse_u16()?),
204             field_type: buf.parse()?,
205             name: parse_string(leaf, &mut buf)?,
206         })),
207 
208         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1469-L1506
209         LF_POINTER => {
210             let underlying_type = buf.parse()?;
211             let attributes = PointerAttributes(buf.parse()?);
212 
213             let containing_class = if attributes.pointer_to_member() {
214                 Some(buf.parse()?)
215             } else {
216                 None
217             };
218 
219             Ok(TypeData::Pointer(PointerType {
220                 underlying_type,
221                 attributes,
222                 containing_class,
223             }))
224         }
225 
226         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1775-L1782
227         LF_PROCEDURE => Ok(TypeData::Procedure(ProcedureType {
228             return_type: parse_optional_type_index(&mut buf)?,
229             attributes: FunctionAttributes(buf.parse_u16()?),
230             parameter_count: buf.parse_u16()?,
231             argument_list: buf.parse()?,
232         })),
233 
234         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1460-L1464
235         LF_MODIFIER => {
236             let type_index = buf.parse()?;
237 
238             // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1090-L1095
239             let flags = buf.parse_u16()?;
240 
241             Ok(TypeData::Modifier(ModifierType {
242                 underlying_type: type_index,
243                 constant: (flags & 0x01) != 0,
244                 volatile: (flags & 0x02) != 0,
245                 unaligned: (flags & 0x04) != 0,
246             }))
247         }
248 
249         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1752-L1759
250         LF_ENUM | LF_ENUM_ST => {
251             let mut enumeration = EnumerationType {
252                 count: buf.parse_u16()?,
253                 properties: TypeProperties(buf.parse_u16()?),
254                 underlying_type: buf.parse()?,
255                 fields: buf.parse()?,
256                 name: parse_string(leaf, &mut buf)?,
257                 unique_name: None,
258             };
259 
260             if enumeration.properties.has_unique_name() {
261                 enumeration.unique_name = Some(parse_string(leaf, &mut buf)?);
262             }
263 
264             Ok(TypeData::Enumeration(enumeration))
265         }
266 
267         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2683-L2688
268         LF_ENUMERATE | LF_ENUMERATE_ST => Ok(TypeData::Enumerate(EnumerateType {
269             attributes: FieldAttributes(buf.parse_u16()?),
270             value: buf.parse()?,
271             name: parse_string(leaf, &mut buf)?,
272         })),
273 
274         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1564-L1579
275         LF_ARRAY | LF_ARRAY_ST | LF_STRIDED_ARRAY => {
276             let element_type = buf.parse()?;
277             let indexing_type = buf.parse()?;
278             let stride: Option<u32> = if leaf == LF_STRIDED_ARRAY {
279                 Some(buf.parse_u32()?)
280             } else {
281                 None
282             };
283 
284             let mut dimensions: Vec<u32> = Vec::new();
285 
286             loop {
287                 let dim = parse_unsigned(&mut buf)?;
288                 if dim > u64::from(u32::max_value()) {
289                     return Err(Error::UnimplementedFeature("u64 array sizes"));
290                 }
291                 dimensions.push(dim as u32);
292 
293                 if buf.is_empty() {
294                     // shouldn't run out here
295                     return Err(Error::UnexpectedEof);
296                 }
297 
298                 if buf.peek_u8()? == 0x00 {
299                     // end of dimensions
300                     buf.parse_u8()?;
301                     break;
302                 }
303             }
304 
305             // eat any padding
306             parse_padding(&mut buf)?;
307 
308             //println!("array: {:x}", buf);
309             //println!("dimensions: {:?}", dimensions);
310 
311             assert!(buf.is_empty());
312 
313             Ok(TypeData::Array(ArrayType {
314                 element_type,
315                 indexing_type,
316                 stride,
317                 dimensions,
318             }))
319         }
320 
321         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1657-L1664
322         LF_UNION | LF_UNION_ST => {
323             let mut union = UnionType {
324                 count: buf.parse_u16()?,
325                 properties: TypeProperties(buf.parse_u16()?),
326                 fields: buf.parse()?,
327                 size: parse_unsigned(&mut buf)? as u32,
328                 name: parse_string(leaf, &mut buf)?,
329                 unique_name: None,
330             };
331 
332             if union.properties.has_unique_name() {
333                 union.unique_name = Some(parse_string(leaf, &mut buf)?);
334             }
335 
336             Ok(TypeData::Union(union))
337         }
338 
339         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2164-L2170
340         LF_BITFIELD => Ok(TypeData::Bitfield(BitfieldType {
341             underlying_type: buf.parse()?,
342             length: buf.parse_u8()?,
343             position: buf.parse_u8()?,
344         })),
345 
346         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1819-L1823
347         LF_VTSHAPE => {
348             // TODO
349             Err(Error::UnimplementedTypeKind(leaf))
350         }
351 
352         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1825-L1837
353         LF_VFTABLE => {
354             // TODO
355             Err(Error::UnimplementedTypeKind(leaf))
356         }
357 
358         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2521-L2528
359         LF_VBCLASS | LF_IVBCLASS => Ok(TypeData::VirtualBaseClass(VirtualBaseClassType {
360             direct: leaf == LF_VBCLASS,
361             attributes: FieldAttributes(buf.parse_u16()?),
362             base_class: buf.parse()?,
363             base_pointer: buf.parse()?,
364             base_pointer_offset: parse_unsigned(&mut buf)? as u32,
365             virtual_base_offset: parse_unsigned(&mut buf)? as u32,
366         })),
367 
368         // List types
369         // ----------
370 
371         // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2112-L2115
372         LF_FIELDLIST => {
373             let mut fields: Vec<TypeData<'t>> = Vec::new();
374             let mut continuation: Option<TypeIndex> = None;
375 
376             while !buf.is_empty() {
377                 match buf.peek_u16()? {
378                     LF_INDEX => {
379                         // continuation record
380                         // eat the leaf value
381                         buf.parse_u16()?;
382 
383                         // parse the TypeIndex where we continue
384                         continuation = Some(buf.parse()?);
385                     }
386                     _ => {
387                         // other type
388                         // recurse because recursion is endless fun because [STACK OVERFLOW]
389                         fields.push(parse_type_data(&mut buf)?);
390                     }
391                 }
392 
393                 // consume any padding
394                 parse_padding(&mut buf)?;
395             }
396 
397             Ok(TypeData::FieldList(FieldList {
398                 fields,
399                 continuation,
400             }))
401         }
402 
403         LF_ARGLIST => {
404             let count = buf.parse_u32()?;
405             let mut arglist: Vec<TypeIndex> = Vec::with_capacity(count as usize);
406             for _ in 0..count {
407                 arglist.push(buf.parse()?);
408             }
409             Ok(TypeData::ArgumentList(ArgumentList { arguments: arglist }))
410         }
411 
412         LF_METHODLIST => {
413             let mut methods: Vec<MethodListEntry> = Vec::new();
414 
415             while !buf.is_empty() {
416                 // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2131-L2136
417                 let attr = FieldAttributes(buf.parse_u16()?);
418                 buf.parse_u16()?; // padding
419 
420                 methods.push(MethodListEntry {
421                     attributes: attr,
422                     method_type: buf.parse()?,
423                     vtable_offset: if attr.is_intro_virtual() {
424                         Some(buf.parse_u32()?)
425                     } else {
426                         None
427                     },
428                 });
429             }
430 
431             Ok(TypeData::MethodList(MethodList { methods }))
432         }
433 
434         _ => Err(Error::UnimplementedTypeKind(leaf)),
435     }
436 }
437 
438 #[inline]
parse_optional_type_index(buf: &mut ParseBuffer<'_>) -> Result<Option<TypeIndex>>439 fn parse_optional_type_index(buf: &mut ParseBuffer<'_>) -> Result<Option<TypeIndex>> {
440     let index = buf.parse()?;
441     if index == TypeIndex(0) || index == TypeIndex(0xffff) {
442         Ok(None)
443     } else {
444         Ok(Some(index))
445     }
446 }
447 
448 #[inline]
parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>>449 fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
450     if leaf > LF_ST_MAX {
451         buf.parse_cstring()
452     } else {
453         buf.parse_u8_pascal_string()
454     }
455 }
456 
457 #[inline]
parse_padding(buf: &mut ParseBuffer<'_>) -> Result<()>458 fn parse_padding(buf: &mut ParseBuffer<'_>) -> Result<()> {
459     while !buf.is_empty() && buf.peek_u8()? >= 0xf0 {
460         let padding = buf.parse_u8()?;
461         if padding > 0xf0 {
462             // low four bits indicate amount of padding
463             // (don't ask me what 0xf0 means, then)
464             buf.take((padding & 0x0f) as usize - 1)?;
465         }
466     }
467     Ok(())
468 }
469 
470 // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/pdbdump/pdbdump.cpp#L2417-L2456
parse_unsigned(buf: &mut ParseBuffer<'_>) -> Result<u64>471 fn parse_unsigned(buf: &mut ParseBuffer<'_>) -> Result<u64> {
472     let leaf = buf.parse_u16()?;
473     if leaf < LF_NUMERIC {
474         // the u16 directly encodes a value
475         return Ok(u64::from(leaf));
476     }
477 
478     match leaf {
479         LF_CHAR => Ok(u64::from(buf.parse_u8()?)),
480         LF_USHORT => Ok(u64::from(buf.parse_u16()?)),
481         LF_ULONG => Ok(u64::from(buf.parse_u32()?)),
482         LF_UQUADWORD => Ok(buf.parse_u64()?),
483         _ => {
484             if cfg!(debug_assertions) {
485                 unreachable!();
486             } else {
487                 Err(Error::UnexpectedNumericPrefix(leaf))
488             }
489         }
490     }
491 }
492 
493 /*
494 typedef struct CV_prop_t {
495 unsigned short  packed      :1;     // true if structure is packed
496 unsigned short  ctor        :1;     // true if constructors or destructors present
497 unsigned short  ovlops      :1;     // true if overloaded operators present
498 unsigned short  isnested    :1;     // true if this is a nested class
499 unsigned short  cnested     :1;     // true if this class contains nested types
500 unsigned short  opassign    :1;     // true if overloaded assignment (=)
501 unsigned short  opcast      :1;     // true if casting methods
502 unsigned short  fwdref      :1;     // true if forward reference (incomplete defn)
503 unsigned short  scoped      :1;     // scoped definition
504 unsigned short  hasuniquename :1;   // true if there is a decorated name following the regular name
505 unsigned short  sealed      :1;     // true if class cannot be used as a base class
506 unsigned short  hfa         :2;     // CV_HFA_e
507 unsigned short  intrinsic   :1;     // true if class is an intrinsic type (e.g. __m128d)
508 unsigned short  mocom       :2;     // CV_MOCOM_UDT_e
509 } CV_prop_t;
510 */
511 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
512 pub struct TypeProperties(u16);
513 impl TypeProperties {
514     /// Indicates if a type is packed via `#pragma pack` or similar.
packed(self) -> bool515     pub fn packed(self) -> bool {
516         self.0 & 0x0001 != 0
517     }
518 
519     /// Indicates if a type has constructors or destructors.
constructors(self) -> bool520     pub fn constructors(self) -> bool {
521         self.0 & 0x0002 != 0
522     }
523 
524     /// Indicates if a type has any overloaded operators.
overloaded_operators(self) -> bool525     pub fn overloaded_operators(self) -> bool {
526         self.0 & 0x0004 != 0
527     }
528 
529     /// Indicates if a type is a nested type, e.g. a `union` defined inside a `class`.
is_nested_type(self) -> bool530     pub fn is_nested_type(self) -> bool {
531         self.0 & 0x0008 != 0
532     }
533 
534     /// Indicates if a type contains nested types.
contains_nested_types(self) -> bool535     pub fn contains_nested_types(self) -> bool {
536         self.0 & 0x0010 != 0
537     }
538 
539     /// Indicates if a class has overloaded the assignment operator.
overloaded_assignment(self) -> bool540     pub fn overloaded_assignment(self) -> bool {
541         self.0 & 0x0020 != 0
542     }
overloaded_casting(self) -> bool543     pub fn overloaded_casting(self) -> bool {
544         self.0 & 0x0040 != 0
545     }
546 
547     /// Indicates if a type is a forward reference, i.e. an incomplete Type that serves as a
548     /// placeholder until a complete Type can be built. This is necessary for e.g. self-referential
549     /// data structures, but other more common declaration/definition idioms can cause forward
550     /// references too.
forward_reference(self) -> bool551     pub fn forward_reference(self) -> bool {
552         self.0 & 0x0080 != 0
553     }
554 
scoped_definition(self) -> bool555     pub fn scoped_definition(self) -> bool {
556         self.0 & 0x0100 != 0
557     }
has_unique_name(self) -> bool558     pub fn has_unique_name(self) -> bool {
559         self.0 & 0x0200 != 0
560     }
sealed(self) -> bool561     pub fn sealed(self) -> bool {
562         self.0 & 0x0400 != 0
563     }
hfa(self) -> u8564     pub fn hfa(self) -> u8 {
565         ((self.0 & 0x1800) >> 11) as u8
566     }
intrinsic_type(self) -> bool567     pub fn intrinsic_type(self) -> bool {
568         self.0 & 0x1000 != 0
569     }
mocom(self) -> u8570     pub fn mocom(self) -> u8 {
571         ((self.0 & 0x6000) >> 14) as u8
572     }
573 }
574 
575 /*
576 typedef struct CV_fldattr_t {
577     unsigned short  access      :2;     // access protection CV_access_t
578     unsigned short  mprop       :3;     // method properties CV_methodprop_t
579     unsigned short  pseudo      :1;     // compiler generated fcn and does not exist
580     unsigned short  noinherit   :1;     // true if class cannot be inherited
581     unsigned short  noconstruct :1;     // true if class cannot be constructed
582     unsigned short  compgenx    :1;     // compiler generated fcn and does exist
583     unsigned short  sealed      :1;     // true if method cannot be overridden
584     unsigned short  unused      :6;     // unused
585 } CV_fldattr_t;
586 
587 typedef enum CV_methodprop_e {
588     CV_MTvanilla        = 0x00,
589     CV_MTvirtual        = 0x01,
590     CV_MTstatic         = 0x02,
591     CV_MTfriend         = 0x03,
592     CV_MTintro          = 0x04,
593     CV_MTpurevirt       = 0x05,
594     CV_MTpureintro      = 0x06
595 } CV_methodprop_e;
596 
597 */
598 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
599 pub struct FieldAttributes(u16);
600 impl FieldAttributes {
601     #[inline]
access(self) -> u8602     pub fn access(self) -> u8 {
603         (self.0 & 0x0003) as u8
604     }
605     #[inline]
method_properties(self) -> u8606     fn method_properties(self) -> u8 {
607         ((self.0 & 0x001c) >> 2) as u8
608     }
609 
610     #[inline]
is_static(self) -> bool611     pub fn is_static(self) -> bool {
612         self.method_properties() == 0x02
613     }
614 
615     #[inline]
is_virtual(self) -> bool616     pub fn is_virtual(self) -> bool {
617         self.method_properties() == 0x01
618     }
619 
620     #[inline]
is_pure_virtual(self) -> bool621     pub fn is_pure_virtual(self) -> bool {
622         self.method_properties() == 0x05
623     }
624 
625     #[inline]
is_intro_virtual(self) -> bool626     pub fn is_intro_virtual(self) -> bool {
627         matches!(self.method_properties(), 0x04 | 0x06)
628     }
629 
630     // TODO
631 }
632 
633 #[allow(unused)]
634 #[repr(u8)]
635 enum Access {
636     None = 0x00,
637     Private = 0x01,
638     Protected = 0x02,
639     Public = 0x03,
640 }
641 
642 // CV_call_t and CV_funcattr_t are always found back to back
643 // Treat them as a combined u16
644 /*
645 typedef struct CV_funcattr_t {
646     unsigned char  cxxreturnudt :1;  // true if C++ style ReturnUDT
647     unsigned char  ctor         :1;  // true if func is an instance constructor
648     unsigned char  ctorvbase    :1;  // true if func is an instance constructor of a class with virtual bases
649     unsigned char  unused       :5;  // unused
650 } CV_funcattr_t;
651 */
652 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
653 pub struct FunctionAttributes(u16);
654 impl FunctionAttributes {
calling_convention(self) -> u8655     pub fn calling_convention(self) -> u8 {
656         (self.0 & 0xff) as u8
657     }
cxx_return_udt(self) -> bool658     pub fn cxx_return_udt(self) -> bool {
659         (self.0 & 0x0100) > 0
660     }
is_constructor(self) -> bool661     pub fn is_constructor(self) -> bool {
662         (self.0 & 0x0200) > 0
663     }
is_constructor_with_virtual_bases(self) -> bool664     pub fn is_constructor_with_virtual_bases(self) -> bool {
665         (self.0 & 0x0400) > 0
666     }
667 }
668 
669 /// The kind of a `PointerType`.
670 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
671 pub enum PointerKind {
672     /// 16 bit pointer.
673     Near16,
674     /// 16:16 far pointer.
675     Far16,
676     /// 16:16 huge pointer.
677     Huge16,
678     /// Based on segment.
679     BaseSeg,
680     /// Based on value of base.
681     BaseVal,
682     /// Based on segment value of base.
683     BaseSegVal,
684     /// Based on address of base.
685     BaseAddr,
686     /// Based on segment address of base.
687     BaseSegAddr,
688     /// Based on type.
689     BaseType,
690     /// Based on self.
691     BaseSelf,
692     /// 32-bit pointer.
693     Near32,
694     /// 48-bit 16:32 pointer.
695     Far32,
696     /// 64-bit pointer.
697     Ptr64,
698 }
699 
700 /// The mode of a `PointerType`.
701 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
702 pub enum PointerMode {
703     /// A regular pointer.
704     Pointer,
705     /// L-Value reference.
706     LValueReference,
707     /// Pointer to data member.
708     Member,
709     /// Pointer to member function.
710     MemberFunction,
711     /// R-Value reference.
712     RValueReference,
713 }
714 
715 /*
716 struct lfPointerAttr {
717     unsigned long   ptrtype     :5; // ordinal specifying pointer type (CV_ptrtype_e)
718     unsigned long   ptrmode     :3; // ordinal specifying pointer mode (CV_ptrmode_e)
719     unsigned long   isflat32    :1; // true if 0:32 pointer
720     unsigned long   isvolatile  :1; // TRUE if volatile pointer
721     unsigned long   isconst     :1; // TRUE if const pointer
722     unsigned long   isunaligned :1; // TRUE if unaligned pointer
723     unsigned long   isrestrict  :1; // TRUE if restricted pointer (allow agressive opts)
724     unsigned long   size        :6; // size of pointer (in bytes)
725     unsigned long   ismocom     :1; // TRUE if it is a MoCOM pointer (^ or %)
726     unsigned long   islref      :1; // TRUE if it is this pointer of member function with & ref-qualifier
727     unsigned long   isrref      :1; // TRUE if it is this pointer of member function with && ref-qualifier
728     unsigned long   unused      :10;// pad out to 32-bits for following cv_typ_t's
729 } attr;
730 */
731 
732 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
733 pub struct PointerAttributes(u32);
734 
735 impl PointerAttributes {
736     /// Indicates the type of pointer.
pointer_kind(self) -> PointerKind737     pub fn pointer_kind(self) -> PointerKind {
738         match self.0 & 0x1f {
739             0x00 => PointerKind::Near16,
740             0x01 => PointerKind::Far16,
741             0x02 => PointerKind::Huge16,
742             0x03 => PointerKind::BaseSeg,
743             0x04 => PointerKind::BaseVal,
744             0x05 => PointerKind::BaseSegVal,
745             0x06 => PointerKind::BaseAddr,
746             0x07 => PointerKind::BaseSegAddr,
747             0x08 => PointerKind::BaseType,
748             0x09 => PointerKind::BaseSelf,
749             0x0a => PointerKind::Near32,
750             0x0b => PointerKind::Far32,
751             0x0c => PointerKind::Ptr64,
752             _ => unreachable!(),
753         }
754     }
755 
756     /// Returns the mode of this pointer.
pointer_mode(self) -> PointerMode757     pub fn pointer_mode(self) -> PointerMode {
758         match (self.0 >> 5) & 0x7 {
759             0x00 => PointerMode::Pointer,
760             0x01 => PointerMode::LValueReference,
761             0x02 => PointerMode::Member,
762             0x03 => PointerMode::MemberFunction,
763             0x04 => PointerMode::RValueReference,
764             _ => unreachable!(),
765         }
766     }
767 
768     /// Returns `true` if this points to a member (either data or function).
pointer_to_member(self) -> bool769     pub fn pointer_to_member(self) -> bool {
770         matches!(
771             self.pointer_mode(),
772             PointerMode::Member | PointerMode::MemberFunction
773         )
774     }
775 
776     /// Returns `true` if this is a flat `0:32` pointer.
is_flat_32(self) -> bool777     pub fn is_flat_32(self) -> bool {
778         (self.0 & 0x100) != 0
779     }
780 
781     /// Returns `true` if this pointer is `volatile`.
is_volatile(self) -> bool782     pub fn is_volatile(self) -> bool {
783         (self.0 & 0x200) != 0
784     }
785 
786     /// Returns `true` if this pointer is `const`.
is_const(self) -> bool787     pub fn is_const(self) -> bool {
788         (self.0 & 0x400) != 0
789     }
790 
791     /// Returns `true` if this pointer is unaligned.
is_unaligned(self) -> bool792     pub fn is_unaligned(self) -> bool {
793         (self.0 & 0x800) != 0
794     }
795 
796     /// Returns `true` if this pointer is restricted (allow aggressive opts).
is_restrict(self) -> bool797     pub fn is_restrict(self) -> bool {
798         (self.0 & 0x1000) != 0
799     }
800 
801     /// Is this a C++ reference, as opposed to a C pointer?
is_reference(self) -> bool802     pub fn is_reference(self) -> bool {
803         matches!(
804             self.pointer_mode(),
805             PointerMode::LValueReference | PointerMode::RValueReference
806         )
807     }
808 
809     /// The size of the pointer in bytes.
size(self) -> u8810     pub fn size(self) -> u8 {
811         let size = ((self.0 >> 13) & 0x3f) as u8;
812         if size != 0 {
813             return size;
814         }
815 
816         match self.pointer_kind() {
817             PointerKind::Near32 | PointerKind::Far32 => 4,
818             PointerKind::Ptr64 => 8,
819             _ => 0,
820         }
821     }
822 
823     /// Returns `true` if this is a MoCOM pointer (`^` or `%`).
is_mocom(self) -> bool824     pub fn is_mocom(self) -> bool {
825         (self.0 & 0x40000) != 0
826     }
827 }
828 
829 /// The information parsed from a type record with kind
830 /// `LF_CLASS`, `LF_CLASS_ST`, `LF_STRUCTURE`, `LF_STRUCTURE_ST` or `LF_INTERFACE`.
831 // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631
832 #[derive(Debug, Clone, PartialEq, Eq)]
833 pub struct ClassType<'t> {
834     pub kind: ClassKind,
835 
836     /// Count of number of elements in this class
837     pub count: u16,
838     pub properties: TypeProperties,
839 
840     /// Type index which describes the fields of this class
841     pub fields: Option<TypeIndex>,
842 
843     /// Type index which describes the class from which this class is derived, if any
844     pub derived_from: Option<TypeIndex>,
845 
846     /// Type index which describes the shape of the vtable for this class, if any
847     pub vtable_shape: Option<TypeIndex>,
848 
849     pub size: u16,
850 
851     /// Display name of the class including type parameters.
852     pub name: RawString<'t>,
853 
854     /// Mangled name, if present.
855     pub unique_name: Option<RawString<'t>>,
856 }
857 
858 /// Used by `ClassType` to distinguish class-like concepts.
859 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
860 pub enum ClassKind {
861     Class,
862     Struct,
863     Interface,
864 }
865 
866 /// The information parsed from a type record with kind `LF_MEMBER` or `LF_MEMBER_ST`.
867 #[derive(Debug, Clone, PartialEq, Eq)]
868 pub struct MemberType<'t> {
869     pub attributes: FieldAttributes,
870     pub field_type: TypeIndex,
871     pub offset: u16,
872     pub name: RawString<'t>,
873 }
874 
875 /// The information parsed from a type record with kind `LF_MFUNCTION`.
876 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
877 pub struct MemberFunctionType {
878     pub return_type: TypeIndex,
879     pub class_type: TypeIndex,
880     pub this_pointer_type: Option<TypeIndex>,
881     pub attributes: FunctionAttributes,
882     pub parameter_count: u16,
883     pub argument_list: TypeIndex,
884     pub this_adjustment: u32,
885 }
886 
887 /// The information parsed from a type record with kind `LF_METHOD` or `LF_METHOD_ST`.
888 #[derive(Debug, Clone, PartialEq, Eq)]
889 pub struct OverloadedMethodType<'t> {
890     pub count: u16,
891     pub method_list: TypeIndex,
892     pub name: RawString<'t>,
893 }
894 
895 /// The information parsed from a type record with kind `LF_ONEMETHOD` or `LF_ONEMETHOD_ST`.
896 #[derive(Debug, Clone, PartialEq, Eq)]
897 pub struct MethodType<'t> {
898     pub attributes: FieldAttributes,
899     pub method_type: TypeIndex,
900     pub vtable_offset: Option<u32>,
901     pub name: RawString<'t>,
902 }
903 
904 /// The information parsed from a type record with kind `LF_STMEMBER` or `LF_STMEMBER_ST`.
905 #[derive(Debug, Clone, PartialEq, Eq)]
906 pub struct StaticMemberType<'t> {
907     pub attributes: FieldAttributes,
908     pub field_type: TypeIndex,
909     pub name: RawString<'t>,
910 }
911 
912 /// The information parsed from a type record with kind
913 /// `LF_NESTTYPE`, `LF_NESTTYPE_ST`, `LF_NESTTYPEEX`, or `LF_NESTTYPEEX_ST`.
914 #[derive(Debug, Clone, PartialEq, Eq)]
915 pub struct NestedType<'t> {
916     pub attributes: FieldAttributes,
917     pub nested_type: TypeIndex,
918     pub name: RawString<'t>,
919 }
920 
921 /// The information parsed from a type record with kind `LF_BCLASS` or `LF_BINTERFACE`.
922 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
923 pub struct BaseClassType {
924     pub kind: ClassKind,
925     pub attributes: FieldAttributes,
926     pub base_class: TypeIndex,
927 
928     /// Describes the offset of the base class within the class
929     pub offset: u32,
930 }
931 
932 /// The information parsed from a type record with kind `LF_VBCLASS` or `LF_IVBCLASS`.
933 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
934 pub struct VirtualBaseClassType {
935     pub direct: bool,
936     pub attributes: FieldAttributes,
937     pub base_class: TypeIndex,
938     pub base_pointer: TypeIndex,
939 
940     pub base_pointer_offset: u32,
941     pub virtual_base_offset: u32,
942 }
943 
944 /// The information parsed from a type record with kind `LF_VFUNCTAB`.
945 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
946 pub struct VirtualFunctionTablePointerType {
947     pub table: TypeIndex,
948 }
949 
950 /// The information parsed from a type record with kind `LF_PROCEDURE`.
951 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
952 pub struct ProcedureType {
953     pub return_type: Option<TypeIndex>,
954     pub attributes: FunctionAttributes,
955     pub parameter_count: u16,
956     pub argument_list: TypeIndex,
957 }
958 
959 /// The information parsed from a type record with kind `LF_POINTER`.
960 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
961 pub struct PointerType {
962     pub underlying_type: TypeIndex,
963     pub attributes: PointerAttributes,
964     pub containing_class: Option<TypeIndex>,
965 }
966 
967 /// The information parsed from a type record with kind `LF_MODIFIER`.
968 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
969 pub struct ModifierType {
970     pub underlying_type: TypeIndex,
971     pub constant: bool,
972     pub volatile: bool,
973     pub unaligned: bool,
974 }
975 
976 /// The information parsed from a type record with kind `LF_ENUM` or `LF_ENUM_ST`.
977 #[derive(Debug, Clone, PartialEq, Eq)]
978 pub struct EnumerationType<'t> {
979     pub count: u16,
980     pub properties: TypeProperties,
981     pub underlying_type: TypeIndex,
982     pub fields: TypeIndex,
983     pub name: RawString<'t>,
984     pub unique_name: Option<RawString<'t>>,
985 }
986 
987 /// The information parsed from a type record with kind `LF_ENUMERATE` or `LF_ENUMERATE_ST`.
988 #[derive(Debug, Clone, PartialEq, Eq)]
989 pub struct EnumerateType<'t> {
990     pub attributes: FieldAttributes,
991     pub value: Variant,
992     pub name: RawString<'t>,
993 }
994 
995 /// The information parsed from a type record with kind
996 /// `LF_ARRAY`, `LF_ARRAY_ST` or `LF_STRIDED_ARRAY`.
997 #[derive(Debug, Clone, PartialEq, Eq)]
998 pub struct ArrayType {
999     pub element_type: TypeIndex,
1000     pub indexing_type: TypeIndex,
1001     pub stride: Option<u32>,
1002 
1003     /// Contains array dimensions as specified in the PDB. This is not what you expect:
1004     ///
1005     /// * Dimensions are specified in terms of byte sizes, not element counts.
1006     /// * Multidimensional arrays aggregate the lower dimensions into the sizes of the higher
1007     ///   dimensions.
1008     ///
1009     /// Thus a `float[4][4]` has `dimensions: [16, 64]`. Determining array dimensions in terms
1010     /// of element counts requires determining the size of the `element_type` and iteratively
1011     /// dividing.
1012     pub dimensions: Vec<u32>,
1013 }
1014 
1015 /// The information parsed from a type record with kind `LF_UNION` or `LF_UNION_ST`.
1016 #[derive(Debug, Clone, PartialEq, Eq)]
1017 pub struct UnionType<'t> {
1018     pub count: u16,
1019     pub properties: TypeProperties,
1020     pub fields: TypeIndex,
1021     pub size: u32,
1022     pub name: RawString<'t>,
1023     pub unique_name: Option<RawString<'t>>,
1024 }
1025 
1026 /// The information parsed from a type record with kind `LF_BITFIELD`.
1027 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1028 pub struct BitfieldType {
1029     pub underlying_type: TypeIndex,
1030     pub length: u8,
1031     pub position: u8,
1032 }
1033 
1034 /// The information parsed from a type record with kind `LF_FIELDLIST`.
1035 #[derive(Debug, Clone, PartialEq, Eq)]
1036 pub struct FieldList<'t> {
1037     pub fields: Vec<TypeData<'t>>,
1038 
1039     /// Sometimes fields can't all fit in a single FieldList, in which case the FieldList
1040     /// refers to another FieldList in a chain.
1041     pub continuation: Option<TypeIndex>,
1042 }
1043 
1044 /// The information parsed from a type record with kind `LF_ARGLIST`.
1045 #[derive(Debug, Clone, PartialEq, Eq)]
1046 pub struct ArgumentList {
1047     pub arguments: Vec<TypeIndex>,
1048 }
1049 
1050 /// The information parsed from a type record with kind `LF_METHODLIST`.
1051 #[derive(Debug, Clone, PartialEq, Eq)]
1052 pub struct MethodList {
1053     pub methods: Vec<MethodListEntry>,
1054 }
1055 
1056 /// An entry in a `MethodList`.
1057 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1058 pub struct MethodListEntry {
1059     pub attributes: FieldAttributes,
1060     pub method_type: TypeIndex,
1061     pub vtable_offset: Option<u32>,
1062 }
1063 
1064 /*
1065 // arrays:
1066 ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x40\x00\x00\xf1").as_bytes(),
1067 ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x50\x00\x00\xf1").as_bytes(),
1068 ParseBuf::from("\x03\x15\xa9\x12\x00\x00\x23\x00\x00\x00\x50\x02\x00\xf1").as_bytes(),
1069 ParseBuf::from("\x03\x15\xac\x12\x00\x00\x23\x00\x00\x00\x6c\x00\x00\xf1").as_bytes(),
1070 ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x80\x00\x00\xf1").as_bytes(),
1071 ParseBuf::from("\x03\x15\x75\x00\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(),
1072 ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x70\x0e\x00\xf1").as_bytes(),
1073 ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x04\x02\x00\xf1").as_bytes(),
1074 ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x0e\x03\x00\xf1").as_bytes(),
1075 ParseBuf::from("\x03\x15\x77\x13\x00\x00\x23\x00\x00\x00\x02\x80\xbd\xda\x00\xf3\xf2\xf1").as_bytes(),
1076 ParseBuf::from("\x03\x15\xb7\x16\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(),
1077 ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x55\x00\x00\xf1").as_bytes(),
1078 */
1079 
1080 #[test]
kind_1609()1081 fn kind_1609() {
1082     let data = &[
1083         9, 22, 0, 2, 0, 0, 22, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 0, 72, 95, 115, 105, 122,
1084         101, 0, 46, 63, 65, 85, 72, 95, 115, 105, 122, 101, 64, 64, 0,
1085     ][..];
1086 
1087     assert_eq!(
1088         parse_type_data(&mut ParseBuffer::from(data)).expect("parse"),
1089         TypeData::Class(ClassType {
1090             kind: ClassKind::Struct,
1091             count: 2,
1092             properties: TypeProperties(512),
1093             fields: Some(TypeIndex(0x1016)),
1094             derived_from: None,
1095             vtable_shape: None,
1096             size: 6,
1097             name: RawString::from("H_size"),
1098             unique_name: Some(RawString::from(".?AUH_size@@")),
1099         })
1100     );
1101 }
1102