The TPI and IPI streams hold CodeView type
records, the same records that compilers put in the .debug$T section of
an object file. Each record gets a type index, counting up from
TypeIndexBegin (normally 0x1000) in the order the records
appear. Numbers are little-endian; “type” fields are 4-byte type indexes.
Records
| Offset | Size | Name | Meaning |
|---|---|---|---|
| 0 | 2 | RecordLen | Length of the record, not counting this field. |
| 2 | 2 | RecordKind | The leaf kind, an LF_ value (below). |
| 4 | – | Fields | Depend on the kind. |
In a PDB every record is padded to a multiple of 4 bytes (in .debug$T it
is not). Padding is a falling run of LF_PADn bytes,
0xF0 + n, ending with LF_PAD0. The member records
inside an LF_FIELDLIST have no length of their own and are separated in
the same way.
Numeric leaves
Sizes, offsets and constant values are written as numeric leaves: a 2-byte value
below 0x8000 (LF_NUMERIC) is the number itself; otherwise it
is a kind that says what follows.
| Kind | Name | Followed by |
|---|---|---|
0x8000 | LF_CHAR | signed 1 byte |
0x8001 | LF_SHORT | signed 2 bytes |
0x8002 | LF_USHORT | unsigned 2 bytes |
0x8003 | LF_LONG | signed 4 bytes |
0x8004 | LF_ULONG | unsigned 4 bytes |
0x8009 | LF_QUADWORD | signed 8 bytes |
0x800A | LF_UQUADWORD | unsigned 8 bytes |
The other numeric kinds (LF_REAL16 to LF_UTF8STRING, in the
table of kinds) are defined but LLVM’s reader does not decode them.
Names are null-terminated strings.
Simple type indexes
Indexes below 0x1000 are not records but built-in types: bits 0–7 give
the kind and bits 8–10 the mode (a pointer to it, or the type itself). A 64-bit
int* is 0x0674. An index with the top bit set refers to the
IPI stream.
| Kind | Name | Kind | Name |
|---|---|---|---|
0x00 | None | 0x40 | Float32 |
0x03 | Void | 0x41 | Float64 |
0x07 | NotTranslated | 0x42 | Float80 |
0x08 | HResult | 0x43 | Float128 |
0x10 | SignedCharacter | 0x44 | Float48 |
0x11 | Int16Short | 0x45 | Float32PartialPrecision |
0x12 | Int32Long | 0x46 | Float16 |
0x13 | Int64Quad | 0x50 | Complex32 |
0x14 | Int128Oct | 0x51 | Complex64 |
0x20 | UnsignedCharacter | 0x52 | Complex80 |
0x21 | UInt16Short | 0x53 | Complex128 |
0x22 | UInt32Long | 0x54 | Complex48 |
0x23 | UInt64Quad | 0x55 | Complex32PartialPrecision |
0x24 | UInt128Oct | 0x56 | Complex16 |
0x30 | Boolean8 | 0x68 | SByte |
0x31 | Boolean16 | 0x69 | Byte |
0x32 | Boolean32 | 0x70 | NarrowCharacter |
0x33 | Boolean64 | 0x71 | WideCharacter |
0x34 | Boolean128 | 0x72 | Int16 |
0x73 | UInt16 | ||
0x74 | Int32 | ||
0x75 | UInt32 | ||
0x76 | Int64 | ||
0x77 | UInt64 | ||
0x78 | Int128 | ||
0x79 | UInt128 | ||
0x7A | Character16 | ||
0x7B | Character32 | ||
0x7C | Character8 |
| Mode | Name |
|---|---|
0x000 | Direct (the type itself) |
0x100 | NearPointer (16-bit near pointer; also std::nullptr_t) |
0x200 | FarPointer |
0x300 | HugePointer |
0x400 | NearPointer32 |
0x500 | FarPointer32 |
0x600 | NearPointer64 |
0x700 | NearPointer128 |
Leaf kinds
Type records (TPI)
| Value | Name | Value | Name |
|---|---|---|---|
0x1001 | LF_MODIFIER | 0x1506 | LF_UNION |
0x1002 | LF_POINTER | 0x1507 | LF_ENUM |
0x1008 | LF_PROCEDURE | 0x1509 | LF_PRECOMP |
0x1009 | LF_MFUNCTION | 0x0014 | LF_ENDPRECOMP |
0x000E | LF_LABEL | 0x1515 | LF_TYPESERVER2 |
0x1201 | LF_ARGLIST | 0x151D | LF_VFTABLE |
0x1203 | LF_FIELDLIST | 0x000A | LF_VTSHAPE |
0x1503 | LF_ARRAY | 0x1205 | LF_BITFIELD |
0x1504 | LF_CLASS | 0x1206 | LF_METHODLIST |
0x1505 | LF_STRUCTURE | 0x1608 | LF_CLASS2 |
0x1519 | LF_INTERFACE | 0x1609 | LF_STRUCTURE2 |
0x160A | LF_UNION2 | ||
0x160B | LF_INTERFACE2 |
Member records (inside LF_FIELDLIST)
| Value | Name | Value | Name |
|---|---|---|---|
0x1400 | LF_BCLASS | 0x150E | LF_STMEMBER |
0x151A | LF_BINTERFACE | 0x150F | LF_METHOD |
0x1401 | LF_VBCLASS | 0x150D | LF_MEMBER |
0x1402 | LF_IVBCLASS | 0x1510 | LF_NESTTYPE |
0x1409 | LF_VFUNCTAB | 0x1511 | LF_ONEMETHOD |
0x1404 | LF_INDEX | 0x1502 | LF_ENUMERATE |
ID records (IPI)
| Value | Name | Value | Name |
|---|---|---|---|
0x1601 | LF_FUNC_ID | 0x1605 | LF_STRING_ID |
0x1602 | LF_MFUNC_ID | 0x1606 | LF_UDT_SRC_LINE |
0x1603 | LF_BUILDINFO | 0x1607 | LF_UDT_MOD_SRC_LINE |
0x1604 | LF_SUBSTR_LIST |
Other kinds
Further kinds that LLVM’s list defines; most are older forms or for other languages, and their layouts are not given here.
| Value | Name | Value | Name | Value | Name |
|---|---|---|---|---|---|
0x0001 | LF_MODIFIER_16t | 0x0207 | LF_METHODLIST_16t | 0x1010 | LF_ALIAS_ST |
0x0002 | LF_POINTER_16t | 0x0208 | LF_DIMCONU_16t | 0x1011 | LF_OEM2 |
0x0003 | LF_ARRAY_16t | 0x0209 | LF_DIMCONLU_16t | 0x1200 | LF_SKIP |
0x0004 | LF_CLASS_16t | 0x020A | LF_DIMVARU_16t | 0x1202 | LF_DEFARG_ST |
0x0005 | LF_STRUCTURE_16t | 0x020B | LF_DIMVARLU_16t | 0x1204 | LF_DERIVED |
0x0006 | LF_UNION_16t | 0x020C | LF_REFSYM | 0x1207 | LF_DIMCONU |
0x0007 | LF_ENUM_16t | 0x0400 | LF_BCLASS_16t | 0x1208 | LF_DIMCONLU |
0x0008 | LF_PROCEDURE_16t | 0x0401 | LF_VBCLASS_16t | 0x1209 | LF_DIMVARU |
0x0009 | LF_MFUNCTION_16t | 0x0402 | LF_IVBCLASS_16t | 0x120A | LF_DIMVARLU |
0x000B | LF_COBOL0_16t | 0x0403 | LF_ENUMERATE_ST | 0x120C | LF_RANGELIST |
0x000C | LF_COBOL1 | 0x0404 | LF_FRIENDFCN_16t | 0x1403 | LF_FRIENDFCN_ST |
0x000D | LF_BARRAY_16t | 0x0405 | LF_INDEX_16t | 0x1405 | LF_MEMBER_ST |
0x000F | LF_NULLLEAF | 0x0406 | LF_MEMBER_16t | 0x1406 | LF_STMEMBER_ST |
0x0010 | LF_NOTTRAN | 0x0407 | LF_STMEMBER_16t | 0x1407 | LF_METHOD_ST |
0x0011 | LF_DIMARRAY_16t | 0x0408 | LF_METHOD_16t | 0x1408 | LF_NESTTYPE_ST |
0x0012 | LF_VFTPATH_16t | 0x0409 | LF_NESTTYPE_16t | 0x140A | LF_FRIENDCLS |
0x0013 | LF_PRECOMP_16t | 0x040A | LF_VFUNCTAB_16t | 0x140B | LF_ONEMETHOD_ST |
0x0015 | LF_OEM_16t | 0x040B | LF_FRIENDCLS_16t | 0x140C | LF_VFUNCOFF |
0x0016 | LF_TYPESERVER_ST | 0x040C | LF_ONEMETHOD_16t | 0x140D | LF_NESTTYPEEX_ST |
0x0200 | LF_SKIP_16t | 0x040D | LF_VFUNCOFF_16t | 0x140E | LF_MEMBERMODIFY_ST |
0x0201 | LF_ARGLIST_16t | 0x1000 | LF_TI16_MAX | 0x140F | LF_MANAGED_ST |
0x0202 | LF_DEFARG_16t | 0x1003 | LF_ARRAY_ST | 0x1500 | LF_ST_MAX |
0x0203 | LF_LIST | 0x1004 | LF_CLASS_ST | 0x1501 | LF_TYPESERVER |
0x0204 | LF_FIELDLIST_16t | 0x1005 | LF_STRUCTURE_ST | 0x1508 | LF_DIMARRAY |
0x0205 | LF_DERIVED_16t | 0x1006 | LF_UNION_ST | 0x150A | LF_ALIAS |
0x0206 | LF_BITFIELD_16t | 0x1007 | LF_ENUM_ST | 0x150B | LF_DEFARG |
0x100A | LF_COBOL0 | 0x100C | LF_DIMARRAY_ST | 0x150C | LF_FRIENDFCN |
0x100B | LF_BARRAY | 0x100D | LF_VFTPATH | 0x1512 | LF_NESTTYPEEX |
0x100E | LF_PRECOMP_ST | 0x100F | LF_OEM | 0x1513 | LF_MEMBERMODIFY |
0x1514 | LF_MANAGED | 0x1516 | LF_STRIDED_ARRAY | 0x1517 | LF_HLSL |
0x1518 | LF_MODIFIER_EX | 0x151B | LF_VECTOR | 0x151C | LF_MATRIX |
0x151E | LF_TAGGED_UNION | 0x151F | LF_TAGGED_UNION_CASE | 0x1520 | LF_TUCASE |
0x1522 | LF_IFC_RECORD |
Numeric and padding kinds
0x8000 LF_CHAR (also LF_NUMERIC),
0x8001 LF_SHORT, 0x8002 LF_USHORT,
0x8003 LF_LONG, 0x8004 LF_ULONG,
0x8005 LF_REAL32, 0x8006 LF_REAL64,
0x8007 LF_REAL80, 0x8008 LF_REAL128,
0x8009 LF_QUADWORD, 0x800A LF_UQUADWORD,
0x800B LF_REAL48, 0x800C LF_COMPLEX32,
0x800D LF_COMPLEX64, 0x800E LF_COMPLEX80,
0x800F LF_COMPLEX128, 0x8010 LF_VARSTRING,
0x8017 LF_OCTWORD, 0x8018 LF_UOCTWORD,
0x8019 LF_DECIMAL, 0x801A LF_DATE,
0x801B LF_UTF8STRING, 0x801C LF_REAL16;
padding 0xF0 LF_PAD0 to 0xFF
LF_PAD15.
Record layouts
Fields follow the 4-byte record header, in this order. “Numeric” is a numeric leaf; “name” a null-terminated string.
LF_MODIFIER
| Field | Size | Meaning |
|---|---|---|
| type | 4 | The modified type. |
| attr | 2 | Bit 0 const, bit 1 volatile, bit 2 unaligned. |
LF_POINTER
| Field | Size | Meaning |
|---|---|---|
| utype | 4 | The type pointed to. |
| attr | 4 | Bit fields, below. |
| member pointer information | – | Present only for pointers to members. |
| Bits | Field | Values |
|---|---|---|
| 0–4 | ptrtype | 0x00 Near16, 0x01 Far16, 0x02 Huge16, 0x03 BasedOnSegment, 0x04 BasedOnValue, 0x05 BasedOnSegmentValue, 0x06 BasedOnAddress, 0x07 BasedOnSegmentAddress, 0x08 BasedOnType, 0x09 BasedOnSelf, 0x0A Near32, 0x0B Far32, 0x0C Near64. |
| 5–7 | ptrmode | 0 pointer, 1 lvalue reference, 2 pointer to data member, 3 pointer to member function, 4 rvalue reference. |
| 8 | isflat32 | Flat 32-bit pointer. |
| 9 | isvolatile | volatile pointer. |
| 10 | isconst | const pointer. |
| 11 | isunaligned | Unaligned pointer. |
| 12 | isrestrict | restrict pointer. |
| 13–18 | size | Size of the pointer in bytes. |
| 19 | ismocom | A WinRT smart pointer. |
| 20 | islref | this pointer of a member function with an & ref-qualifier. |
| 21 | isrref | The same with &&. |
| 22–31 | unused | – |
LF_PROCEDURE, LF_MFUNCTION and LF_ARGLIST
| Record | Fields (size) |
|---|---|
LF_PROCEDURE | rvtype (4) return type; calltype (1) calling convention; funcattr (1); parmcount (2); arglist (4) an LF_ARGLIST. |
LF_MFUNCTION | rvtype (4); classtype (4) the class; thistype (4) the this pointer type; calltype (1); funcattr (1); parmcount (2); arglist (4); thisadjust (4, signed). |
LF_ARGLIST, LF_SUBSTR_LIST | count (4), then count type indexes (4 each). |
funcattr bits: 0 returns a C++ class by value, 1 is a constructor, 2 is a constructor of a class with virtual bases. Calling conventions:
| Value | Name | Value | Name |
|---|---|---|---|
0x00 | NearC | 0x0D | Generic |
0x01 | FarC | 0x0E | AlphaCall |
0x02 | NearPascal | 0x0F | PpcCall |
0x03 | FarPascal | 0x10 | SHCall |
0x04 | NearFast | 0x11 | ArmCall |
0x05 | FarFast | 0x12 | AM33Call |
0x07 | NearStdCall | 0x13 | TriCall |
0x08 | FarStdCall | 0x14 | SH5Call |
0x09 | NearSysCall | 0x15 | M32RCall |
0x0A | FarSysCall | 0x16 | ClrCall |
0x0B | ThisCall | 0x17 | Inline |
0x0C | MipsCall | 0x18 | NearVector |
0x19 | Swift |
LF_ARRAY and LF_BITFIELD
| Record | Fields (size) |
|---|---|
LF_ARRAY | elemtype (4) element type; idxtype (4) index type; size (numeric) total size in bytes; name. |
LF_BITFIELD | type (4) underlying type; length (1) width in bits; position (1) starting bit. |
LF_CLASS, LF_STRUCTURE, LF_INTERFACE, LF_UNION, LF_ENUM
| Record | Fields (size) |
|---|---|
LF_CLASS, LF_STRUCTURE, LF_INTERFACE | count (2) members; property (2); field (4) its LF_FIELDLIST; derived (4) derivation list; vshape (4) virtual function table shape; then the size (numeric), the name and, if property bit 9 is set, the unique (decorated) name. |
LF_UNION | count (2); property (2); field (4); then size (numeric), name and unique name. |
LF_ENUM | count (2); property (2); utype (4) underlying type; field (4); name and unique name. |
| Property bit | Meaning |
|---|---|
| 0 | packed |
| 1 | has constructors or destructors |
| 2 | has overloaded operators |
| 3 | is nested |
| 4 | contains nested types |
| 5 | has overloaded assignment |
| 6 | has casting operators |
| 7 | forward reference (incomplete type) |
| 8 | scoped (local) definition |
| 9 | has a unique name after the name |
| 10 | sealed |
| 11–12 | hfa (meaning not documented in the sources read) |
| 13 | intrinsic type |
| 14–15 | mocom (meaning not documented in the sources read) |
Member records and LF_METHODLIST
Most member records start with a 2-byte attribute: bits 0–1 access (1 private, 2 protected, 3 public), bits 2–4 method property (0 vanilla, 1 virtual, 2 static, 3 friend, 4 introducing virtual, 5 pure virtual, 6 pure introducing virtual), bit 5 pseudo, bit 6 no inherit, bit 7 no construct, bit 8 compiler-generated, bit 9 sealed.
| Record | Fields (size) |
|---|---|
LF_MEMBER | attr (2); type (4); offset (numeric); name. |
LF_STMEMBER | attr (2); type (4); name. |
LF_BCLASS, LF_BINTERFACE | attr (2); type (4) base class; offset (numeric). |
LF_VBCLASS, LF_IVBCLASS | attr (2); type (4) virtual base; vbptr (4) virtual base pointer type; then numeric data (vbpoff), the virtual base pointer offsets. |
LF_ONEMETHOD | attr (2); type (4); vbaseoff (4, optional: a zero-length array in cvinfo.h; when it is present is unconfirmed); name. |
LF_METHOD | count (2) overloads; mList (4) an LF_METHODLIST; name. |
LF_METHODLIST entry | attr (2); padding (2); type (4); vbaseoff (4, optional, as for LF_ONEMETHOD). |
LF_NESTTYPE | padding (2); type (4); name. |
LF_ENUMERATE | attr (2); value (numeric); name. |
LF_VFUNCTAB | padding (2); type (4) the virtual function table pointer type. |
LF_INDEX | padding (2); type (4) another type record, the index field of lfIndex (its use is not described in the sources read). |
Other type records
| Record | Fields (size) |
|---|---|
LF_LABEL | mode (2). |
LF_VTSHAPE | count (2); descriptors. |
LF_VFTABLE | type (4) owning class; baseVftable (4); offsetInObjectLayout (4); len (4) bytes of names; names. |
LF_TYPESERVER2 | sig70 (16) the type server PDB’s GUID; age (4); name (its path). |
LF_PRECOMP | start (4) first index; count (4); signature (4); name. |
LF_ENDPRECOMP | signature (4). |
ID records
| Record | Fields (size) |
|---|---|
LF_FUNC_ID | scopeId (4) ID of the enclosing scope; type (4) the function type; name. |
LF_MFUNC_ID | parentType (4) the class; type (4); name. |
LF_STRING_ID | id (4) an ID (a substring list); name (the string). |
LF_UDT_SRC_LINE | type (4) a user-defined type; src (4) an ID naming the source file; line (4). |
LF_UDT_MOD_SRC_LINE | type (4); src (4) the source file; line (4); imod (2) module. |
LF_BUILDINFO | count (2), then count IDs (4 each), in this order: 0 current directory, 1 build tool, 2 source file, 3 program database file, 4 command arguments. |
Sources
LLVM, CodeView Type
Records (record header, padding) and
The PDB TPI and IPI Streams
(type indexes, TPI and IPI kinds). LLVM source: CodeViewTypes.def (every
leaf value), TypeIndex.h (simple kinds and modes),
CodeView.h (pointer, calling-convention and class enums),
RecordSerialization.cpp (numeric leaves). Microsoft’s
cvinfo.h in
microsoft-pdb (field order
and C types of each record, attribute and property bit fields,
CV_BuildInfo_e). Meanings of a few fields (such as the unique name being
the decorated name, and when vbaseoff is present) are read from field
names, not from a written specification, and are unconfirmed.