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