Coverage Report

Created: 2026-11-11 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pdb2-0.10.2/src/tpi/data.rs
Line
Count
Source
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
    VirtualFunctionTable(VirtualFunctionTableType<'t>),
29
    VirtualTableShape(VirtualTableShapeType),
30
    VirtualFunctionTablePointer(VirtualFunctionTablePointerType),
31
    Procedure(ProcedureType),
32
    Pointer(PointerType),
33
    Modifier(ModifierType),
34
    Enumeration(EnumerationType<'t>),
35
    Enumerate(EnumerateType<'t>),
36
    Array(ArrayType),
37
    Union(UnionType<'t>),
38
    Alias(AliasType<'t>),
39
    Bitfield(BitfieldType),
40
    FieldList(FieldList<'t>),
41
    ArgumentList(ArgumentList),
42
    MethodList(MethodList),
43
}
44
45
impl<'t> TypeData<'t> {
46
    /// Return the name of this `TypeData`, if any
47
    #[must_use]
48
0
    pub fn name(&self) -> Option<RawString<'t>> {
49
0
        let name = match self {
50
0
            Self::Class(ClassType { ref name, .. })
51
0
            | Self::Member(MemberType { ref name, .. })
52
0
            | Self::OverloadedMethod(OverloadedMethodType { ref name, .. })
53
0
            | Self::StaticMember(StaticMemberType { ref name, .. })
54
0
            | Self::Nested(NestedType { ref name, .. })
55
0
            | Self::Enumeration(EnumerationType { ref name, .. })
56
0
            | Self::Enumerate(EnumerateType { ref name, .. })
57
0
            | Self::Union(UnionType { ref name, .. })
58
0
            | Self::Alias(AliasType { ref name, .. }) => name,
59
0
            _ => return None,
60
        };
61
62
0
        Some(*name)
63
0
    }
64
}
65
66
/// Parse a type out of a `ParseBuffer`.
67
103k
pub(crate) fn parse_type_data<'t>(buf: &mut ParseBuffer<'t>) -> Result<TypeData<'t>> {
68
103k
    let leaf = buf.parse_u16()?;
69
70
103k
    match leaf {
71
        // Basic types
72
        // -----------
73
74
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631-L1642
75
        LF_CLASS | LF_CLASS_ST | LF_STRUCTURE | LF_STRUCTURE_ST | LF_INTERFACE => {
76
17.3k
            let mut class = ClassType {
77
17.3k
                kind: match leaf {
78
12.1k
                    LF_CLASS | LF_CLASS_ST => ClassKind::Class,
79
5.22k
                    LF_STRUCTURE | LF_STRUCTURE_ST => ClassKind::Struct,
80
0
                    LF_INTERFACE => ClassKind::Interface,
81
0
                    _ => unreachable!(),
82
                },
83
17.3k
                count: buf.parse_u16()?,
84
17.3k
                properties: TypeProperties(buf.parse_u16()?),
85
17.3k
                fields: parse_optional_type_index(buf)?,
86
17.3k
                derived_from: parse_optional_type_index(buf)?,
87
17.3k
                vtable_shape: parse_optional_type_index(buf)?,
88
17.3k
                size: parse_unsigned(buf)?,
89
17.3k
                name: parse_string(leaf, buf)?,
90
17.3k
                unique_name: None,
91
            };
92
93
17.3k
            if class.properties.has_unique_name() {
94
17.3k
                class.unique_name = Some(parse_string(leaf, buf)?);
95
0
            }
96
97
17.3k
            Ok(TypeData::Class(class))
98
        }
99
100
        // https://github.com/microsoft/microsoft-pdb/issues/50#issuecomment-737890766
101
        LF_CLASS2 | LF_STRUCTURE2 | LF_INTERFACE2 => {
102
0
            let mut class = ClassType {
103
0
                kind: match leaf {
104
0
                    LF_CLASS2 => ClassKind::Class,
105
0
                    LF_STRUCTURE2 => ClassKind::Struct,
106
0
                    LF_INTERFACE2 => ClassKind::Interface,
107
0
                    _ => unreachable!(),
108
                },
109
0
                properties: TypeProperties(buf.parse_u32()? as u16),
110
0
                fields: parse_optional_type_index(buf)?,
111
0
                derived_from: parse_optional_type_index(buf)?,
112
0
                vtable_shape: parse_optional_type_index(buf)?,
113
0
                count: buf.parse_u16()?,
114
0
                size: parse_unsigned(buf)?,
115
0
                name: parse_string(leaf, buf)?,
116
0
                unique_name: None,
117
            };
118
119
0
            if class.properties.has_unique_name() {
120
0
                class.unique_name = Some(parse_string(leaf, buf)?);
121
0
            }
122
123
0
            Ok(TypeData::Class(class))
124
        }
125
126
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2580-L2586
127
        LF_MEMBER | LF_MEMBER_ST => Ok(TypeData::Member(MemberType {
128
2.21k
            attributes: FieldAttributes(buf.parse_u16()?),
129
2.21k
            field_type: buf.parse()?,
130
2.21k
            offset: parse_unsigned(buf)?,
131
2.21k
            name: parse_string(leaf, buf)?,
132
        })),
133
134
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2699-L2714
135
        LF_NESTTYPE | LF_NESTTYPE_ST | LF_NESTTYPEEX | LF_NESTTYPEEX_ST => {
136
            // These structs differ in their use of the first 16 bits
137
1.51k
            let raw_attr = match leaf {
138
0
                LF_NESTTYPEEX | LF_NESTTYPEEX_ST => buf.parse_u16()?,
139
                _ => {
140
                    // discard padding
141
1.51k
                    buf.parse_u16()?;
142
                    // assume zero
143
1.51k
                    0
144
                }
145
            };
146
147
            Ok(TypeData::Nested(NestedType {
148
1.51k
                attributes: FieldAttributes(raw_attr),
149
1.51k
                nested_type: buf.parse()?,
150
1.51k
                name: parse_string(leaf, buf)?,
151
            }))
152
        }
153
154
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1801-L1811
155
        LF_MFUNCTION => Ok(TypeData::MemberFunction(MemberFunctionType {
156
14.8k
            return_type: buf.parse()?,
157
14.8k
            class_type: buf.parse()?,
158
14.8k
            this_pointer_type: parse_optional_type_index(buf)?,
159
14.8k
            attributes: FunctionAttributes(buf.parse_u16()?),
160
14.8k
            parameter_count: buf.parse_u16()?,
161
14.8k
            argument_list: buf.parse()?,
162
14.8k
            this_adjustment: buf.parse_u32()?,
163
        })),
164
165
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2650-L2655
166
        LF_METHOD | LF_METHOD_ST => Ok(TypeData::OverloadedMethod(OverloadedMethodType {
167
1.66k
            count: buf.parse_u16()?,
168
1.66k
            method_list: buf.parse()?,
169
1.66k
            name: parse_string(leaf, buf)?,
170
        })),
171
172
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2671-L2678
173
        LF_ONEMETHOD | LF_ONEMETHOD_ST => {
174
1.81k
            let attr = FieldAttributes(buf.parse_u16()?);
175
            Ok(TypeData::Method(MethodType {
176
1.81k
                attributes: attr,
177
1.81k
                method_type: buf.parse()?,
178
1.81k
                vtable_offset: if attr.is_intro_virtual() {
179
0
                    Some(buf.parse_u32()?)
180
                } else {
181
                    // yes, this is variable length
182
1.81k
                    None
183
                },
184
1.81k
                name: parse_string(leaf, buf)?,
185
            }))
186
        }
187
188
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2499-L2505
189
        LF_BCLASS | LF_BINTERFACE => Ok(TypeData::BaseClass(BaseClassType {
190
60
            kind: match leaf {
191
60
                LF_BCLASS => ClassKind::Class,
192
0
                LF_BINTERFACE => ClassKind::Interface,
193
0
                _ => unreachable!(),
194
            },
195
60
            attributes: FieldAttributes(buf.parse_u16()?),
196
60
            base_class: buf.parse()?,
197
60
            offset: parse_unsigned(buf)? as u32,
198
        })),
199
200
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2615-L2619
201
        LF_VFUNCTAB => {
202
            // padding is supposed to be zero always, but… let's not check
203
0
            buf.parse_u16()?;
204
            Ok(TypeData::VirtualFunctionTablePointer(
205
                VirtualFunctionTablePointerType {
206
0
                    table: buf.parse()?,
207
                },
208
            ))
209
        }
210
211
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2599-L2604
212
        LF_STMEMBER | LF_STMEMBER_ST => Ok(TypeData::StaticMember(StaticMemberType {
213
162
            attributes: FieldAttributes(buf.parse_u16()?),
214
162
            field_type: buf.parse()?,
215
162
            name: parse_string(leaf, buf)?,
216
        })),
217
218
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1469-L1506
219
        LF_POINTER => {
220
25.5k
            let underlying_type = buf.parse()?;
221
25.5k
            let attributes = PointerAttributes(buf.parse()?);
222
223
25.5k
            let containing_class = if attributes.pointer_to_member() {
224
0
                Some(buf.parse()?)
225
            } else {
226
25.5k
                None
227
            };
228
229
25.5k
            Ok(TypeData::Pointer(PointerType {
230
25.5k
                underlying_type,
231
25.5k
                attributes,
232
25.5k
                containing_class,
233
25.5k
            }))
234
        }
235
236
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1775-L1782
237
        LF_PROCEDURE => Ok(TypeData::Procedure(ProcedureType {
238
6.98k
            return_type: parse_optional_type_index(buf)?,
239
6.98k
            attributes: FunctionAttributes(buf.parse_u16()?),
240
6.98k
            parameter_count: buf.parse_u16()?,
241
6.98k
            argument_list: buf.parse()?,
242
        })),
243
244
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1460-L1464
245
        LF_MODIFIER => {
246
9.26k
            let type_index = buf.parse()?;
247
248
            // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1090-L1095
249
9.26k
            let flags = buf.parse_u16()?;
250
251
9.26k
            Ok(TypeData::Modifier(ModifierType {
252
9.26k
                underlying_type: type_index,
253
9.26k
                constant: (flags & 0x01) != 0,
254
9.26k
                volatile: (flags & 0x02) != 0,
255
9.26k
                unaligned: (flags & 0x04) != 0,
256
9.26k
            }))
257
        }
258
259
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1752-L1759
260
        LF_ENUM | LF_ENUM_ST => {
261
150
            let mut enumeration = EnumerationType {
262
150
                count: buf.parse_u16()?,
263
150
                properties: TypeProperties(buf.parse_u16()?),
264
150
                underlying_type: buf.parse()?,
265
150
                fields: buf.parse()?,
266
150
                name: parse_string(leaf, buf)?,
267
150
                unique_name: None,
268
            };
269
270
150
            if enumeration.properties.has_unique_name() {
271
150
                enumeration.unique_name = Some(parse_string(leaf, buf)?);
272
0
            }
273
274
150
            Ok(TypeData::Enumeration(enumeration))
275
        }
276
277
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2683-L2688
278
        LF_ENUMERATE | LF_ENUMERATE_ST => Ok(TypeData::Enumerate(EnumerateType {
279
668
            attributes: FieldAttributes(buf.parse_u16()?),
280
668
            value: buf.parse()?,
281
668
            name: parse_string(leaf, buf)?,
282
        })),
283
284
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1564-L1579
285
        LF_ARRAY | LF_ARRAY_ST | LF_STRIDED_ARRAY => {
286
16
            let element_type = buf.parse()?;
287
16
            let indexing_type = buf.parse()?;
288
16
            let stride: Option<u32> = if leaf == LF_STRIDED_ARRAY {
289
0
                Some(buf.parse_u32()?)
290
            } else {
291
16
                None
292
            };
293
294
16
            let mut dimensions: Vec<u32> = Vec::new();
295
296
            loop {
297
16
                let dim = parse_unsigned(buf)?;
298
16
                if dim > u64::from(u32::MAX) {
299
0
                    return Err(Error::UnimplementedFeature("u64 array sizes"));
300
16
                }
301
16
                dimensions.push(dim as u32);
302
303
16
                if buf.is_empty() {
304
                    // shouldn't run out here
305
0
                    return Err(Error::UnexpectedEof);
306
16
                }
307
308
16
                if buf.peek_u8()? == 0x00 {
309
                    // end of dimensions
310
16
                    buf.parse_u8()?;
311
16
                    break;
312
0
                }
313
            }
314
315
            // eat any padding
316
16
            parse_padding(buf)?;
317
318
            //println!("array: {:x}", buf);
319
            //println!("dimensions: {:?}", dimensions);
320
321
            // Vector35/binaryninja-api#6076: NativeAOT PDBs have extra data here
322
            // of unknown purpose
323
            //assert!(buf.is_empty());
324
325
16
            Ok(TypeData::Array(ArrayType {
326
16
                element_type,
327
16
                indexing_type,
328
16
                stride,
329
16
                dimensions,
330
16
            }))
331
        }
332
333
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1657-L1664
334
        LF_UNION | LF_UNION_ST => {
335
4
            let mut union = UnionType {
336
4
                count: buf.parse_u16()?,
337
4
                properties: TypeProperties(buf.parse_u16()?),
338
4
                fields: buf.parse()?,
339
4
                size: parse_unsigned(buf)?,
340
4
                name: parse_string(leaf, buf)?,
341
4
                unique_name: None,
342
            };
343
344
4
            if union.properties.has_unique_name() {
345
4
                union.unique_name = Some(parse_string(leaf, buf)?);
346
0
            }
347
348
4
            Ok(TypeData::Union(union))
349
        }
350
351
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1669-L1673
352
        LF_ALIAS | LF_ALIAS_ST => Ok(TypeData::Alias(AliasType {
353
0
            underlying_type: buf.parse()?,
354
0
            name: parse_string(leaf, buf)?,
355
        })),
356
357
        // https://github.com/microsoft/microsoft-pdb/issues/50#issuecomment-737890766
358
        LF_UNION2 => {
359
0
            let mut union = UnionType {
360
0
                properties: TypeProperties(buf.parse_u32()? as u16),
361
0
                fields: buf.parse()?,
362
0
                count: buf.parse_u16()?,
363
0
                size: parse_unsigned(buf)?,
364
0
                name: parse_string(leaf, buf)?,
365
0
                unique_name: None,
366
            };
367
368
0
            if union.properties.has_unique_name() {
369
0
                union.unique_name = Some(parse_string(leaf, buf)?);
370
0
            }
371
372
0
            Ok(TypeData::Union(union))
373
        }
374
375
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2164-L2170
376
        LF_BITFIELD => Ok(TypeData::Bitfield(BitfieldType {
377
0
            underlying_type: buf.parse()?,
378
0
            length: buf.parse_u8()?,
379
0
            position: buf.parse_u8()?,
380
        })),
381
382
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1819-L1823
383
        LF_VTSHAPE => {
384
0
            let mut vtshape = VirtualTableShapeType {
385
0
                descriptors: vec![],
386
0
            };
387
0
            let count = buf.parse_u16()? as usize;
388
            // These are packed 4-bit values
389
0
            for _ in 0..((count + 1) / 2) {
390
0
                let desc: u8 = buf.parse()?;
391
392
0
                vtshape
393
0
                    .descriptors
394
0
                    .push(VirtualTableShapeDescriptor::from_u4(desc & 0xF));
395
0
                if vtshape.descriptors.len() < count {
396
0
                    vtshape
397
0
                        .descriptors
398
0
                        .push(VirtualTableShapeDescriptor::from_u4(desc >> 4));
399
0
                }
400
            }
401
0
            Ok(TypeData::VirtualTableShape(vtshape))
402
        }
403
404
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1825-L1837
405
        LF_VFTABLE => {
406
0
            let mut vftable = VirtualFunctionTableType {
407
0
                owner: buf.parse()?,
408
0
                base: buf.parse()?,
409
0
                object_offset: parse_unsigned(buf)? as u32,
410
0
                names: vec![],
411
            };
412
413
0
            let names_length = parse_unsigned(buf)? as usize;
414
415
0
            let mut len = 0;
416
0
            while len < names_length {
417
0
                let s = buf.parse_cstring()?;
418
0
                len += s.len() + 1;
419
0
                vftable.names.push(s);
420
            }
421
0
            assert_eq!(len, names_length);
422
423
0
            Ok(TypeData::VirtualFunctionTable(vftable))
424
        }
425
426
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2521-L2528
427
        LF_VBCLASS | LF_IVBCLASS => Ok(TypeData::VirtualBaseClass(VirtualBaseClassType {
428
0
            direct: leaf == LF_VBCLASS,
429
0
            attributes: FieldAttributes(buf.parse_u16()?),
430
0
            base_class: buf.parse()?,
431
0
            base_pointer: buf.parse()?,
432
0
            base_pointer_offset: parse_unsigned(buf)? as u32,
433
0
            virtual_base_offset: parse_unsigned(buf)? as u32,
434
        })),
435
436
        // List types
437
        // ----------
438
439
        // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2112-L2115
440
        LF_FIELDLIST => {
441
418
            let mut fields: Vec<TypeData<'t>> = Vec::new();
442
418
            let mut continuation: Option<TypeIndex> = None;
443
444
8.52k
            while !buf.is_empty() {
445
8.10k
                match buf.peek_u16()? {
446
                    LF_INDEX => {
447
                        // continuation record
448
                        // eat the leaf value, which we just peeked at
449
0
                        buf.parse_u16()?;
450
451
                        // eat another u16, which is padding (always 0 in files produced by MSVC)
452
0
                        buf.parse_u16()?;
453
454
                        // parse the TypeIndex where we continue
455
0
                        continuation = Some(buf.parse()?);
456
                    }
457
                    _ => {
458
                        // other type
459
                        // recurse because recursion is endless fun because [STACK OVERFLOW]
460
8.10k
                        fields.push(parse_type_data(buf)?);
461
                    }
462
                }
463
464
                // consume any padding
465
8.10k
                parse_padding(buf)?;
466
            }
467
468
418
            Ok(TypeData::FieldList(FieldList {
469
418
                fields,
470
418
                continuation,
471
418
            }))
472
        }
473
474
        LF_ARGLIST => {
475
20.9k
            let count = buf.parse_u32()?;
476
20.9k
            let mut arglist: Vec<TypeIndex> = Vec::with_capacity(count as usize);
477
20.9k
            for _ in 0..count {
478
21.6k
                arglist.push(buf.parse()?);
479
            }
480
20.9k
            Ok(TypeData::ArgumentList(ArgumentList { arguments: arglist }))
481
        }
482
483
        LF_METHODLIST => {
484
182
            let mut methods: Vec<MethodListEntry> = Vec::new();
485
486
842
            while !buf.is_empty() {
487
                // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2131-L2136
488
660
                let attr = FieldAttributes(buf.parse_u16()?);
489
660
                buf.parse_u16()?; // padding
490
491
660
                methods.push(MethodListEntry {
492
660
                    attributes: attr,
493
660
                    method_type: buf.parse()?,
494
660
                    vtable_offset: if attr.is_intro_virtual() {
495
88
                        Some(buf.parse_u32()?)
496
                    } else {
497
572
                        None
498
                    },
499
                });
500
            }
501
502
182
            Ok(TypeData::MethodList(MethodList { methods }))
503
        }
504
505
10
        _ => Err(Error::UnimplementedTypeKind(leaf)),
506
    }
507
103k
}
508
509
#[inline]
510
73.8k
fn parse_optional_type_index(buf: &mut ParseBuffer<'_>) -> Result<Option<TypeIndex>> {
511
73.8k
    let index = buf.parse()?;
512
73.8k
    if index == TypeIndex(0) || index == TypeIndex(0xffff) {
513
54.2k
        Ok(None)
514
    } else {
515
19.5k
        Ok(Some(index))
516
    }
517
73.8k
}
518
519
#[inline]
520
43.0k
fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result<RawString<'t>> {
521
43.0k
    if leaf > LF_ST_MAX {
522
43.0k
        buf.parse_cstring()
523
    } else {
524
0
        buf.parse_u8_pascal_string()
525
    }
526
43.0k
}
527
528
#[inline]
529
8.12k
fn parse_padding(buf: &mut ParseBuffer<'_>) -> Result<()> {
530
14.8k
    while !buf.is_empty() && buf.peek_u8()? >= 0xf0 {
531
6.68k
        let padding = buf.parse_u8()?;
532
6.68k
        if padding > 0xf0 {
533
            // low four bits indicate amount of padding
534
            // (don't ask me what 0xf0 means, then)
535
6.68k
            buf.take((padding & 0x0f) as usize - 1)?;
536
0
        }
537
    }
538
8.12k
    Ok(())
539
8.12k
}
540
541
// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/pdbdump/pdbdump.cpp#L2417-L2456
542
19.6k
fn parse_unsigned(buf: &mut ParseBuffer<'_>) -> Result<u64> {
543
19.6k
    let leaf = buf.parse_u16()?;
544
19.6k
    if leaf < LF_NUMERIC {
545
        // the u16 directly encodes a value
546
19.6k
        return Ok(u64::from(leaf));
547
0
    }
548
549
0
    match leaf {
550
0
        LF_CHAR => Ok(u64::from(buf.parse_u8()?)),
551
0
        LF_USHORT => Ok(u64::from(buf.parse_u16()?)),
552
0
        LF_ULONG => Ok(u64::from(buf.parse_u32()?)),
553
0
        LF_UQUADWORD => Ok(buf.parse_u64()?),
554
        _ => {
555
0
            if cfg!(debug_assertions) {
556
0
                unreachable!();
557
            } else {
558
0
                Err(Error::UnexpectedNumericPrefix(leaf))
559
            }
560
        }
561
    }
562
19.6k
}
563
564
/*
565
typedef struct CV_prop_t {
566
unsigned short  packed      :1;     // true if structure is packed
567
unsigned short  ctor        :1;     // true if constructors or destructors present
568
unsigned short  ovlops      :1;     // true if overloaded operators present
569
unsigned short  isnested    :1;     // true if this is a nested class
570
unsigned short  cnested     :1;     // true if this class contains nested types
571
unsigned short  opassign    :1;     // true if overloaded assignment (=)
572
unsigned short  opcast      :1;     // true if casting methods
573
unsigned short  fwdref      :1;     // true if forward reference (incomplete defn)
574
unsigned short  scoped      :1;     // scoped definition
575
unsigned short  hasuniquename :1;   // true if there is a decorated name following the regular name
576
unsigned short  sealed      :1;     // true if class cannot be used as a base class
577
unsigned short  hfa         :2;     // CV_HFA_e
578
unsigned short  intrinsic   :1;     // true if class is an intrinsic type (e.g. __m128d)
579
unsigned short  mocom       :2;     // CV_MOCOM_UDT_e
580
} CV_prop_t;
581
*/
582
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
583
pub struct TypeProperties(u16);
584
impl TypeProperties {
585
    /// Indicates if a type is packed via `#pragma pack` or similar.
586
    #[must_use]
587
0
    pub fn packed(self) -> bool {
588
0
        self.0 & 0x0001 != 0
589
0
    }
590
591
    /// Indicates if a type has constructors or destructors.
592
    #[must_use]
593
0
    pub fn constructors(self) -> bool {
594
0
        self.0 & 0x0002 != 0
595
0
    }
596
597
    /// Indicates if a type has any overloaded operators.
598
    #[must_use]
599
0
    pub fn overloaded_operators(self) -> bool {
600
0
        self.0 & 0x0004 != 0
601
0
    }
602
603
    /// Indicates if a type is a nested type, e.g. a `union` defined inside a `class`.
604
    #[must_use]
605
0
    pub fn is_nested_type(self) -> bool {
606
0
        self.0 & 0x0008 != 0
607
0
    }
608
609
    /// Indicates if a type contains nested types.
610
    #[must_use]
611
0
    pub fn contains_nested_types(self) -> bool {
612
0
        self.0 & 0x0010 != 0
613
0
    }
614
615
    /// Indicates if a class has overloaded the assignment operator.
616
    #[must_use]
617
0
    pub fn overloaded_assignment(self) -> bool {
618
0
        self.0 & 0x0020 != 0
619
0
    }
620
621
    #[must_use]
622
0
    pub fn overloaded_casting(self) -> bool {
623
0
        self.0 & 0x0040 != 0
624
0
    }
625
626
    /// Indicates if a type is a forward reference, i.e. an incomplete Type that serves as a
627
    /// placeholder until a complete Type can be built. This is necessary for e.g. self-referential
628
    /// data structures, but other more common declaration/definition idioms can cause forward
629
    /// references too.
630
    #[must_use]
631
0
    pub fn forward_reference(self) -> bool {
632
0
        self.0 & 0x0080 != 0
633
0
    }
634
635
    #[must_use]
636
0
    pub fn scoped_definition(self) -> bool {
637
0
        self.0 & 0x0100 != 0
638
0
    }
639
640
    #[must_use]
641
17.5k
    pub fn has_unique_name(self) -> bool {
642
17.5k
        self.0 & 0x0200 != 0
643
17.5k
    }
644
645
    #[must_use]
646
0
    pub fn sealed(self) -> bool {
647
0
        self.0 & 0x0400 != 0
648
0
    }
649
650
    #[must_use]
651
0
    pub fn hfa(self) -> u8 {
652
0
        ((self.0 & 0x1800) >> 11) as u8
653
0
    }
654
655
    #[must_use]
656
0
    pub fn intrinsic_type(self) -> bool {
657
0
        self.0 & 0x1000 != 0
658
0
    }
659
660
    #[must_use]
661
0
    pub fn mocom(self) -> u8 {
662
0
        ((self.0 & 0x6000) >> 14) as u8
663
0
    }
664
}
665
666
/*
667
typedef struct CV_fldattr_t {
668
    unsigned short  access      :2;     // access protection CV_access_t
669
    unsigned short  mprop       :3;     // method properties CV_methodprop_t
670
    unsigned short  pseudo      :1;     // compiler generated fcn and does not exist
671
    unsigned short  noinherit   :1;     // true if class cannot be inherited
672
    unsigned short  noconstruct :1;     // true if class cannot be constructed
673
    unsigned short  compgenx    :1;     // compiler generated fcn and does exist
674
    unsigned short  sealed      :1;     // true if method cannot be overridden
675
    unsigned short  unused      :6;     // unused
676
} CV_fldattr_t;
677
678
typedef enum CV_methodprop_e {
679
    CV_MTvanilla        = 0x00,
680
    CV_MTvirtual        = 0x01,
681
    CV_MTstatic         = 0x02,
682
    CV_MTfriend         = 0x03,
683
    CV_MTintro          = 0x04,
684
    CV_MTpurevirt       = 0x05,
685
    CV_MTpureintro      = 0x06
686
} CV_methodprop_e;
687
*/
688
689
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
690
pub struct FieldAttributes(u16);
691
impl FieldAttributes {
692
    #[inline]
693
    #[must_use]
694
0
    pub fn access(self) -> u8 {
695
0
        (self.0 & 0x0003) as u8
696
0
    }
697
698
    #[inline]
699
    #[must_use]
700
2.47k
    fn method_properties(self) -> u8 {
701
2.47k
        ((self.0 & 0x001c) >> 2) as u8
702
2.47k
    }
703
704
    #[inline]
705
    #[must_use]
706
0
    pub fn is_vanilla(self) -> bool {
707
0
        self.method_properties() == 0x00
708
0
    }
709
710
    #[inline]
711
    #[must_use]
712
0
    pub fn is_virtual(self) -> bool {
713
0
        self.method_properties() == 0x01
714
0
    }
715
716
    #[inline]
717
    #[must_use]
718
0
    pub fn is_static(self) -> bool {
719
0
        self.method_properties() == 0x02
720
0
    }
721
722
    #[inline]
723
    #[must_use]
724
0
    pub fn is_friend(self) -> bool {
725
0
        self.method_properties() == 0x03
726
0
    }
727
728
    #[inline]
729
    #[must_use]
730
0
    pub fn is_intro(self) -> bool {
731
0
        self.method_properties() == 0x04
732
0
    }
733
734
    #[inline]
735
    #[must_use]
736
0
    pub fn is_pure_virtual(self) -> bool {
737
0
        self.method_properties() == 0x05
738
0
    }
739
740
    #[inline]
741
    #[must_use]
742
0
    pub fn is_pure_intro(self) -> bool {
743
0
        self.method_properties() == 0x06
744
0
    }
745
746
    #[inline]
747
    #[must_use]
748
2.47k
    pub fn is_intro_virtual(self) -> bool {
749
2.47k
        matches!(self.method_properties(), 0x04 | 0x06)
750
2.47k
    }
751
752
    #[inline]
753
    #[must_use]
754
0
    pub fn is_pseudo(self) -> bool {
755
0
        self.0 & 0x0020 != 0
756
0
    }
757
758
    #[inline]
759
    #[must_use]
760
0
    pub fn noinherit(self) -> bool {
761
0
        self.0 & 0x0040 != 0
762
0
    }
763
764
    #[inline]
765
    #[must_use]
766
0
    pub fn noconstruct(self) -> bool {
767
0
        self.0 & 0x0080 != 0
768
0
    }
769
770
    #[inline]
771
    #[must_use]
772
0
    pub fn is_compgenx(self) -> bool {
773
0
        self.0 & 0x0100 != 0
774
0
    }
775
776
    #[inline]
777
    #[must_use]
778
0
    pub fn sealed(self) -> bool {
779
0
        self.0 & 0x0200 != 0
780
0
    }
781
782
    // TODO
783
}
784
785
#[allow(unused)]
786
#[repr(u8)]
787
enum Access {
788
    None = 0x00,
789
    Private = 0x01,
790
    Protected = 0x02,
791
    Public = 0x03,
792
}
793
794
// CV_call_t and CV_funcattr_t are always found back to back
795
// Treat them as a combined u16
796
/*
797
typedef struct CV_funcattr_t {
798
    unsigned char  cxxreturnudt :1;  // true if C++ style ReturnUDT
799
    unsigned char  ctor         :1;  // true if func is an instance constructor
800
    unsigned char  ctorvbase    :1;  // true if func is an instance constructor of a class with virtual bases
801
    unsigned char  unused       :5;  // unused
802
} CV_funcattr_t;
803
*/
804
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
805
pub struct FunctionAttributes(u16);
806
impl FunctionAttributes {
807
    #[must_use]
808
0
    pub fn calling_convention(self) -> u8 {
809
0
        (self.0 & 0xff) as u8
810
0
    }
811
812
    #[must_use]
813
0
    pub fn cxx_return_udt(self) -> bool {
814
0
        (self.0 & 0x0100) > 0
815
0
    }
816
817
    #[must_use]
818
394
    pub fn is_constructor(self) -> bool {
819
394
        (self.0 & 0x0200) > 0
820
394
    }
821
822
    #[must_use]
823
0
    pub fn is_constructor_with_virtual_bases(self) -> bool {
824
0
        (self.0 & 0x0400) > 0
825
0
    }
826
}
827
828
/// The kind of a `PointerType`.
829
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
830
pub enum PointerKind {
831
    /// 16 bit pointer.
832
    Near16,
833
    /// 16:16 far pointer.
834
    Far16,
835
    /// 16:16 huge pointer.
836
    Huge16,
837
    /// Based on segment.
838
    BaseSeg,
839
    /// Based on value of base.
840
    BaseVal,
841
    /// Based on segment value of base.
842
    BaseSegVal,
843
    /// Based on address of base.
844
    BaseAddr,
845
    /// Based on segment address of base.
846
    BaseSegAddr,
847
    /// Based on type.
848
    BaseType,
849
    /// Based on self.
850
    BaseSelf,
851
    /// 32-bit pointer.
852
    Near32,
853
    /// 48-bit 16:32 pointer.
854
    Far32,
855
    /// 64-bit pointer.
856
    Ptr64,
857
}
858
859
/// The mode of a `PointerType`.
860
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
861
pub enum PointerMode {
862
    /// A regular pointer.
863
    Pointer,
864
    /// L-Value reference.
865
    LValueReference,
866
    /// Pointer to data member.
867
    Member,
868
    /// Pointer to member function.
869
    MemberFunction,
870
    /// R-Value reference.
871
    RValueReference,
872
}
873
874
/*
875
struct lfPointerAttr {
876
    unsigned long   ptrtype     :5; // ordinal specifying pointer type (CV_ptrtype_e)
877
    unsigned long   ptrmode     :3; // ordinal specifying pointer mode (CV_ptrmode_e)
878
    unsigned long   isflat32    :1; // true if 0:32 pointer
879
    unsigned long   isvolatile  :1; // TRUE if volatile pointer
880
    unsigned long   isconst     :1; // TRUE if const pointer
881
    unsigned long   isunaligned :1; // TRUE if unaligned pointer
882
    unsigned long   isrestrict  :1; // TRUE if restricted pointer (allow agressive opts)
883
    unsigned long   size        :6; // size of pointer (in bytes)
884
    unsigned long   ismocom     :1; // TRUE if it is a MoCOM pointer (^ or %)
885
    unsigned long   islref      :1; // TRUE if it is this pointer of member function with & ref-qualifier
886
    unsigned long   isrref      :1; // TRUE if it is this pointer of member function with && ref-qualifier
887
    unsigned long   unused      :10;// pad out to 32-bits for following cv_typ_t's
888
} attr;
889
*/
890
891
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
892
pub struct PointerAttributes(u32);
893
894
impl PointerAttributes {
895
    /// Indicates the type of pointer.
896
    #[must_use]
897
0
    pub fn pointer_kind(self) -> PointerKind {
898
0
        match self.0 & 0x1f {
899
0
            0x00 => PointerKind::Near16,
900
0
            0x01 => PointerKind::Far16,
901
0
            0x02 => PointerKind::Huge16,
902
0
            0x03 => PointerKind::BaseSeg,
903
0
            0x04 => PointerKind::BaseVal,
904
0
            0x05 => PointerKind::BaseSegVal,
905
0
            0x06 => PointerKind::BaseAddr,
906
0
            0x07 => PointerKind::BaseSegAddr,
907
0
            0x08 => PointerKind::BaseType,
908
0
            0x09 => PointerKind::BaseSelf,
909
0
            0x0a => PointerKind::Near32,
910
0
            0x0b => PointerKind::Far32,
911
0
            0x0c => PointerKind::Ptr64,
912
0
            _ => unreachable!(),
913
        }
914
0
    }
915
916
    /// Returns the mode of this pointer.
917
    #[must_use]
918
39.4k
    pub fn pointer_mode(self) -> PointerMode {
919
39.4k
        match (self.0 >> 5) & 0x7 {
920
29.0k
            0x00 => PointerMode::Pointer,
921
9.24k
            0x01 => PointerMode::LValueReference,
922
0
            0x02 => PointerMode::Member,
923
0
            0x03 => PointerMode::MemberFunction,
924
1.18k
            0x04 => PointerMode::RValueReference,
925
0
            _ => unreachable!(),
926
        }
927
39.4k
    }
928
929
    /// Returns `true` if this points to a member (either data or function).
930
    #[must_use]
931
25.5k
    pub fn pointer_to_member(self) -> bool {
932
25.5k
        matches!(
933
25.5k
            self.pointer_mode(),
934
            PointerMode::Member | PointerMode::MemberFunction
935
        )
936
25.5k
    }
937
938
    /// Returns `true` if this is a flat `0:32` pointer.
939
    #[must_use]
940
0
    pub fn is_flat_32(self) -> bool {
941
0
        (self.0 & 0x100) != 0
942
0
    }
943
944
    /// Returns `true` if this pointer is `volatile`.
945
    #[must_use]
946
0
    pub fn is_volatile(self) -> bool {
947
0
        (self.0 & 0x200) != 0
948
0
    }
949
950
    /// Returns `true` if this pointer is `const`.
951
    #[must_use]
952
13.9k
    pub fn is_const(self) -> bool {
953
13.9k
        (self.0 & 0x400) != 0
954
13.9k
    }
955
956
    /// Returns `true` if this pointer is unaligned.
957
    #[must_use]
958
0
    pub fn is_unaligned(self) -> bool {
959
0
        (self.0 & 0x800) != 0
960
0
    }
961
962
    /// Returns `true` if this pointer is restricted (allow aggressive opts).
963
    #[must_use]
964
0
    pub fn is_restrict(self) -> bool {
965
0
        (self.0 & 0x1000) != 0
966
0
    }
967
968
    /// Is this a C++ reference, as opposed to a C pointer?
969
    #[must_use]
970
0
    pub fn is_reference(self) -> bool {
971
0
        matches!(
972
0
            self.pointer_mode(),
973
            PointerMode::LValueReference | PointerMode::RValueReference
974
        )
975
0
    }
976
977
    /// The size of the pointer in bytes.
978
    #[must_use]
979
0
    pub fn size(self) -> u8 {
980
0
        let size = ((self.0 >> 13) & 0x3f) as u8;
981
0
        if size != 0 {
982
0
            return size;
983
0
        }
984
985
0
        match self.pointer_kind() {
986
0
            PointerKind::Near32 | PointerKind::Far32 => 4,
987
0
            PointerKind::Ptr64 => 8,
988
0
            _ => 0,
989
        }
990
0
    }
991
992
    /// Returns `true` if this is a `MoCOM` pointer (`^` or `%`).
993
    #[must_use]
994
0
    pub fn is_mocom(self) -> bool {
995
0
        (self.0 & 0x40000) != 0
996
0
    }
997
}
998
999
/*
1000
typedef enum CV_VTS_desc_e {
1001
    CV_VTS_near         = 0x00,
1002
    CV_VTS_far          = 0x01,
1003
    CV_VTS_thin         = 0x02,
1004
    CV_VTS_outer        = 0x03,
1005
    CV_VTS_meta         = 0x04,
1006
    CV_VTS_near32       = 0x05,
1007
    CV_VTS_far32        = 0x06,
1008
    CV_VTS_unused       = 0x07
1009
} CV_VTS_desc_e;
1010
 */
1011
#[allow(unused)]
1012
#[repr(u8)]
1013
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1014
pub enum VirtualTableShapeDescriptor {
1015
    Near = 0x00,
1016
    Far = 0x01,
1017
    Thin = 0x02,
1018
    Outer = 0x03,
1019
    Meta = 0x04,
1020
    Near32 = 0x05,
1021
    Far32 = 0x06,
1022
    Unused = 0x07,
1023
}
1024
1025
impl VirtualTableShapeDescriptor {
1026
    // Convert a 4-bit "u4" value in a u8 to a VirtualTableShapeDescriptor
1027
    // This is used in the VirtualTableShapeType parsing and is not public
1028
    // so we can safely assume that the value is in the correct range.
1029
0
    pub(crate) fn from_u4(val: u8) -> Self {
1030
0
        match val {
1031
0
            0x00 => VirtualTableShapeDescriptor::Near,
1032
0
            0x01 => VirtualTableShapeDescriptor::Far,
1033
0
            0x02 => VirtualTableShapeDescriptor::Thin,
1034
0
            0x03 => VirtualTableShapeDescriptor::Outer,
1035
0
            0x04 => VirtualTableShapeDescriptor::Meta,
1036
0
            0x05 => VirtualTableShapeDescriptor::Near32,
1037
0
            0x06 => VirtualTableShapeDescriptor::Far32,
1038
0
            0x07 => VirtualTableShapeDescriptor::Unused,
1039
0
            _ => unreachable!(),
1040
        }
1041
0
    }
1042
}
1043
1044
/// The information parsed from a type record with kind
1045
/// `LF_CLASS`, `LF_CLASS_ST`, `LF_STRUCTURE`, `LF_STRUCTURE_ST` or `LF_INTERFACE`.
1046
// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631
1047
#[derive(Debug, Clone, PartialEq, Eq)]
1048
pub struct ClassType<'t> {
1049
    pub kind: ClassKind,
1050
1051
    /// Count of number of elements in this class
1052
    pub count: u16,
1053
    pub properties: TypeProperties,
1054
1055
    /// Type index which describes the fields of this class
1056
    pub fields: Option<TypeIndex>,
1057
1058
    /// Type index which describes the class from which this class is derived, if any
1059
    pub derived_from: Option<TypeIndex>,
1060
1061
    /// Type index which describes the shape of the vtable for this class, if any
1062
    pub vtable_shape: Option<TypeIndex>,
1063
1064
    pub size: u64,
1065
1066
    /// Display name of the class including type parameters.
1067
    pub name: RawString<'t>,
1068
1069
    /// Mangled name, if present.
1070
    pub unique_name: Option<RawString<'t>>,
1071
}
1072
1073
/// Used by `ClassType` to distinguish class-like concepts.
1074
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1075
pub enum ClassKind {
1076
    Class,
1077
    Struct,
1078
    Interface,
1079
}
1080
1081
/// The information parsed from a type record with kind `LF_MEMBER` or `LF_MEMBER_ST`.
1082
#[derive(Debug, Clone, PartialEq, Eq)]
1083
pub struct MemberType<'t> {
1084
    pub attributes: FieldAttributes,
1085
    pub field_type: TypeIndex,
1086
    pub offset: u64,
1087
    pub name: RawString<'t>,
1088
}
1089
1090
/// The information parsed from a type record with kind `LF_MFUNCTION`.
1091
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1092
pub struct MemberFunctionType {
1093
    pub return_type: TypeIndex,
1094
    pub class_type: TypeIndex,
1095
    pub this_pointer_type: Option<TypeIndex>,
1096
    pub attributes: FunctionAttributes,
1097
    pub parameter_count: u16,
1098
    pub argument_list: TypeIndex,
1099
    pub this_adjustment: u32,
1100
}
1101
1102
/// The information parsed from a type record with kind `LF_METHOD` or `LF_METHOD_ST`.
1103
#[derive(Debug, Clone, PartialEq, Eq)]
1104
pub struct OverloadedMethodType<'t> {
1105
    pub count: u16,
1106
    pub method_list: TypeIndex,
1107
    pub name: RawString<'t>,
1108
}
1109
1110
/// The information parsed from a type record with kind `LF_ONEMETHOD` or `LF_ONEMETHOD_ST`.
1111
#[derive(Debug, Clone, PartialEq, Eq)]
1112
pub struct MethodType<'t> {
1113
    pub attributes: FieldAttributes,
1114
    pub method_type: TypeIndex,
1115
    pub vtable_offset: Option<u32>,
1116
    pub name: RawString<'t>,
1117
}
1118
1119
/// The information parsed from a type record with kind `LF_STMEMBER` or `LF_STMEMBER_ST`.
1120
#[derive(Debug, Clone, PartialEq, Eq)]
1121
pub struct StaticMemberType<'t> {
1122
    pub attributes: FieldAttributes,
1123
    pub field_type: TypeIndex,
1124
    pub name: RawString<'t>,
1125
}
1126
1127
/// The information parsed from a type record with kind
1128
/// `LF_NESTTYPE`, `LF_NESTTYPE_ST`, `LF_NESTTYPEEX`, or `LF_NESTTYPEEX_ST`.
1129
#[derive(Debug, Clone, PartialEq, Eq)]
1130
pub struct NestedType<'t> {
1131
    pub attributes: FieldAttributes,
1132
    pub nested_type: TypeIndex,
1133
    pub name: RawString<'t>,
1134
}
1135
1136
/// The information parsed from a type record with kind `LF_BCLASS` or `LF_BINTERFACE`.
1137
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1138
pub struct BaseClassType {
1139
    pub kind: ClassKind,
1140
    pub attributes: FieldAttributes,
1141
    pub base_class: TypeIndex,
1142
1143
    /// Describes the offset of the base class within the class
1144
    pub offset: u32,
1145
}
1146
1147
/// The information parsed from a type record with kind `LF_VBCLASS` or `LF_IVBCLASS`.
1148
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1149
pub struct VirtualBaseClassType {
1150
    pub direct: bool,
1151
    pub attributes: FieldAttributes,
1152
    pub base_class: TypeIndex,
1153
    pub base_pointer: TypeIndex,
1154
1155
    pub base_pointer_offset: u32,
1156
    pub virtual_base_offset: u32,
1157
}
1158
1159
/// The information parsed from a type record with kind `LF_VFUNCTAB`.
1160
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1161
pub struct VirtualFunctionTablePointerType {
1162
    pub table: TypeIndex,
1163
}
1164
1165
/// The information parsed from a type record with kind `LF_VTSHAPE`.
1166
#[derive(Debug, Clone, PartialEq, Eq)]
1167
pub struct VirtualTableShapeType {
1168
    pub descriptors: Vec<VirtualTableShapeDescriptor>,
1169
}
1170
1171
/// The information parsed from a type record with kind `LF_VFTABLE`.
1172
#[derive(Debug, Clone, PartialEq, Eq)]
1173
pub struct VirtualFunctionTableType<'t> {
1174
    pub owner: TypeIndex,
1175
    pub base: TypeIndex,
1176
    pub object_offset: u32,
1177
    pub names: Vec<RawString<'t>>,
1178
}
1179
1180
/// The information parsed from a type record with kind `LF_PROCEDURE`.
1181
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1182
pub struct ProcedureType {
1183
    pub return_type: Option<TypeIndex>,
1184
    pub attributes: FunctionAttributes,
1185
    pub parameter_count: u16,
1186
    pub argument_list: TypeIndex,
1187
}
1188
1189
/// The information parsed from a type record with kind `LF_POINTER`.
1190
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1191
pub struct PointerType {
1192
    pub underlying_type: TypeIndex,
1193
    pub attributes: PointerAttributes,
1194
    pub containing_class: Option<TypeIndex>,
1195
}
1196
1197
/// The information parsed from a type record with kind `LF_MODIFIER`.
1198
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1199
pub struct ModifierType {
1200
    pub underlying_type: TypeIndex,
1201
    pub constant: bool,
1202
    pub volatile: bool,
1203
    pub unaligned: bool,
1204
}
1205
1206
/// The information parsed from a type record with kind `LF_ENUM` or `LF_ENUM_ST`.
1207
#[derive(Debug, Clone, PartialEq, Eq)]
1208
pub struct EnumerationType<'t> {
1209
    pub count: u16,
1210
    pub properties: TypeProperties,
1211
    pub underlying_type: TypeIndex,
1212
    pub fields: TypeIndex,
1213
    pub name: RawString<'t>,
1214
    pub unique_name: Option<RawString<'t>>,
1215
}
1216
1217
/// The information parsed from a type record with kind `LF_ENUMERATE` or `LF_ENUMERATE_ST`.
1218
#[derive(Debug, Clone, PartialEq, Eq)]
1219
pub struct EnumerateType<'t> {
1220
    pub attributes: FieldAttributes,
1221
    pub value: Variant,
1222
    pub name: RawString<'t>,
1223
}
1224
1225
/// The information parsed from a type record with kind
1226
/// `LF_ARRAY`, `LF_ARRAY_ST` or `LF_STRIDED_ARRAY`.
1227
#[derive(Debug, Clone, PartialEq, Eq)]
1228
pub struct ArrayType {
1229
    pub element_type: TypeIndex,
1230
    pub indexing_type: TypeIndex,
1231
    pub stride: Option<u32>,
1232
1233
    /// Contains array dimensions as specified in the PDB. This is not what you expect:
1234
    ///
1235
    /// * Dimensions are specified in terms of byte sizes, not element counts.
1236
    /// * Multidimensional arrays aggregate the lower dimensions into the sizes of the higher
1237
    ///   dimensions.
1238
    ///
1239
    /// Thus a `float[4][4]` has `dimensions: [16, 64]`. Determining array dimensions in terms
1240
    /// of element counts requires determining the size of the `element_type` and iteratively
1241
    /// dividing.
1242
    pub dimensions: Vec<u32>,
1243
}
1244
1245
/// The information parsed from a type record with kind `LF_UNION` or `LF_UNION_ST`.
1246
#[derive(Debug, Clone, PartialEq, Eq)]
1247
pub struct UnionType<'t> {
1248
    pub count: u16,
1249
    pub properties: TypeProperties,
1250
    pub fields: TypeIndex,
1251
    pub size: u64,
1252
    pub name: RawString<'t>,
1253
    pub unique_name: Option<RawString<'t>>,
1254
}
1255
1256
/// The information parsed from a type record with kind `LF_ALIAS` or `LF_ALIAS_ST`.
1257
#[derive(Debug, Clone, PartialEq, Eq)]
1258
pub struct AliasType<'t> {
1259
    pub underlying_type: TypeIndex,
1260
    pub name: RawString<'t>,
1261
}
1262
1263
/// The information parsed from a type record with kind `LF_BITFIELD`.
1264
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1265
pub struct BitfieldType {
1266
    pub underlying_type: TypeIndex,
1267
    pub length: u8,
1268
    pub position: u8,
1269
}
1270
1271
/// The information parsed from a type record with kind `LF_FIELDLIST`.
1272
#[derive(Debug, Clone, PartialEq, Eq)]
1273
pub struct FieldList<'t> {
1274
    pub fields: Vec<TypeData<'t>>,
1275
1276
    /// Sometimes fields can't all fit in a single `FieldList`, in which case the `FieldList`
1277
    /// refers to another `FieldList` in a chain.
1278
    pub continuation: Option<TypeIndex>,
1279
}
1280
1281
/// The information parsed from a type record with kind `LF_ARGLIST`.
1282
#[derive(Debug, Clone, PartialEq, Eq)]
1283
pub struct ArgumentList {
1284
    pub arguments: Vec<TypeIndex>,
1285
}
1286
1287
/// The information parsed from a type record with kind `LF_METHODLIST`.
1288
#[derive(Debug, Clone, PartialEq, Eq)]
1289
pub struct MethodList {
1290
    pub methods: Vec<MethodListEntry>,
1291
}
1292
1293
/// An entry in a `MethodList`.
1294
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1295
pub struct MethodListEntry {
1296
    pub attributes: FieldAttributes,
1297
    pub method_type: TypeIndex,
1298
    pub vtable_offset: Option<u32>,
1299
}
1300
1301
/*
1302
// arrays:
1303
ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x40\x00\x00\xf1").as_bytes(),
1304
ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x50\x00\x00\xf1").as_bytes(),
1305
ParseBuf::from("\x03\x15\xa9\x12\x00\x00\x23\x00\x00\x00\x50\x02\x00\xf1").as_bytes(),
1306
ParseBuf::from("\x03\x15\xac\x12\x00\x00\x23\x00\x00\x00\x6c\x00\x00\xf1").as_bytes(),
1307
ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x80\x00\x00\xf1").as_bytes(),
1308
ParseBuf::from("\x03\x15\x75\x00\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(),
1309
ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x70\x0e\x00\xf1").as_bytes(),
1310
ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x04\x02\x00\xf1").as_bytes(),
1311
ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x0e\x03\x00\xf1").as_bytes(),
1312
ParseBuf::from("\x03\x15\x77\x13\x00\x00\x23\x00\x00\x00\x02\x80\xbd\xda\x00\xf3\xf2\xf1").as_bytes(),
1313
ParseBuf::from("\x03\x15\xb7\x16\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(),
1314
ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x55\x00\x00\xf1").as_bytes(),
1315
*/
1316
1317
#[test]
1318
fn kind_1609() {
1319
    let data = &[
1320
        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,
1321
        101, 0, 46, 63, 65, 85, 72, 95, 115, 105, 122, 101, 64, 64, 0,
1322
    ][..];
1323
1324
    assert_eq!(
1325
        parse_type_data(&mut ParseBuffer::from(data)).expect("parse"),
1326
        TypeData::Class(ClassType {
1327
            kind: ClassKind::Struct,
1328
            count: 2,
1329
            properties: TypeProperties(512),
1330
            fields: Some(TypeIndex(0x1016)),
1331
            derived_from: None,
1332
            vtable_shape: None,
1333
            size: 6,
1334
            name: RawString::from("H_size"),
1335
            unique_name: Some(RawString::from(".?AUH_size@@")),
1336
        })
1337
    );
1338
}