CodeView 类型记录

简介

本文档描述了 LLVM 理解的各种 CodeView 类型记录的用法和序列化格式。本文档并未描述所有定义的 CodeView 类型记录。在某些情况下,这是因为这些记录显然已弃用,并且只能出现在非常旧的软件中(例如 16 位类型)。在其他情况下,这是因为在实践中从未观察到这些记录。这可能是因为它们仅为非 C++ 代码生成(例如 Visual Basic、C#),或者因为它们已被更新的记录取代,或者其他各种原因。但是,我们在此处描述的记录应该涵盖在处理现代 C++ 工具链时可能遇到的 99% 的类型记录。

记录类别

我们可以将 CodeView 类型记录序列视为可变长度的 叶子记录 数组。每个此类记录都将其自身的长度描述为固定大小标头的一部分,以及它是什么类型的记录。叶子记录要么填充到 4 个字节(如果此类型流出现在 PDB 的 TPI/IPI 流中),要么根本不填充(如果此类型流出现在对象文件的 .debug$T 部分中)。填充是通过插入以 LF_PAD0 结束的 <_padding_records> 的递减序列来实现的。

最后一类记录是 member record。一种特殊的叶子类型 - LF_FIELDLIST - 包含一系列嵌入式记录。虽然外部 LF_FIELDLIST 描述其长度(与任何其他叶子记录一样),但嵌入式记录 - 称为 member records - 则没有。

叶子记录

所有叶子记录都以以下 4 字节前缀开头

struct RecordHeader {
  uint16_t RecordLen;  // Record length, not including this 2 byte field.
  uint16_t RecordKind; // Record kind enum.
};

LF_POINTER (0x1002)

用法:描述指向另一种类型的指针。

布局

.--------------------.-- +0
|    Referent Type   |
.--------------------.-- +4
|     Attributes     |
.--------------------.-- +8
|  Member Ptr Info   |       Only present if |Attributes| indicates this is a member pointer.
.--------------------.-- +E

Attributes 是一个具有以下布局的位字段

 .-----------------------------------------------------------------------------------------------------.
 |     Unused                   |  Flags  |       Size       |   Modifiers   |  Mode   |      Kind     |
 .-----------------------------------------------------------------------------------------------------.
 |                              |         |                  |               |         |               |
0x100                         +0x16     +0x13               +0xD            +0x8      +0x5            +0x0

其中各个字段由以下枚举定义

enum class PointerKind : uint8_t {
  Near16 = 0x00,                // 16 bit pointer
  Far16 = 0x01,                 // 16:16 far pointer
  Huge16 = 0x02,                // 16:16 huge pointer
  BasedOnSegment = 0x03,        // based on segment
  BasedOnValue = 0x04,          // based on value of base
  BasedOnSegmentValue = 0x05,   // based on segment value of base
  BasedOnAddress = 0x06,        // based on address of base
  BasedOnSegmentAddress = 0x07, // based on segment address of base
  BasedOnType = 0x08,           // based on type
  BasedOnSelf = 0x09,           // based on self
  Near32 = 0x0a,                // 32 bit pointer
  Far32 = 0x0b,                 // 16:32 pointer
  Near64 = 0x0c                 // 64 bit pointer
};
enum class PointerMode : uint8_t {
  Pointer = 0x00,                 // "normal" pointer
  LValueReference = 0x01,         // "old" reference
  PointerToDataMember = 0x02,     // pointer to data member
  PointerToMemberFunction = 0x03, // pointer to member function
  RValueReference = 0x04          // r-value reference
};
enum class PointerModifiers : uint8_t {
  None = 0x00,                    // "normal" pointer
  Flat32 = 0x01,                  // "flat" pointer
  Volatile = 0x02,                // pointer is marked volatile
  Const = 0x04,                   // pointer is marked const
  Unaligned = 0x08,               // pointer is marked unaligned
  Restrict = 0x10,                // pointer is marked restrict
};
enum class PointerFlags : uint8_t {
  WinRTSmartPointer = 0x01,       // pointer is a WinRT smart pointer
  LValueRefThisPointer = 0x02,    // pointer is a 'this' pointer of a member function with ref qualifier (e.g. void X::foo() &)
  RValueRefThisPointer = 0x04     // pointer is a 'this' pointer of a member function with ref qualifier (e.g. void X::foo() &&)
};

Attributes 位掩码的 Size 字段是一个 1 字节值,指示指针大小。例如,void* 的大小根据目标架构的不同,为 4 或 8。另一方面,如果 Mode 指示这是一个指向成员函数的指针或指向数据成员的指针,则大小可以是任何实现定义的数字。

LF_POINTER 记录的 Member Ptr Info 字段仅在属性指示这是指向成员的指针时才存在。

请注意,“普通”指向基本类型的指针不是由 LF_POINTER 记录表示的,它们由特殊的保留 TypeIndex 值 指示。

LF_MODIFIER (0x1001)

LF_PROCEDURE (0x1008)

LF_MFUNCTION (0x1009)

LF_LABEL (0x000e)

LF_ARGLIST (0x1201)

LF_FIELDLIST (0x1203)

LF_ARRAY (0x1503)

LF_CLASS (0x1504)

LF_STRUCTURE (0x1505)

LF_INTERFACE (0x1519)

LF_UNION (0x1506)

LF_ENUM (0x1507)

LF_TYPESERVER2 (0x1515)

LF_VFTABLE (0x151d)

LF_VTSHAPE (0x000a)

LF_BITFIELD (0x1205)

LF_FUNC_ID (0x1601)

LF_MFUNC_ID (0x1602)

LF_BUILDINFO (0x1603)

LF_SUBSTR_LIST (0x1604)

LF_STRING_ID (0x1605)

LF_UDT_SRC_LINE (0x1606)

LF_UDT_MOD_SRC_LINE (0x1607)

LF_METHODLIST (0x1206)

LF_PRECOMP (0x1509)

LF_ENDPRECOMP (0x0014)

成员记录

LF_BCLASS (0x1400)

LF_BINTERFACE (0x151a)

LF_VBCLASS (0x1401)

LF_IVBCLASS (0x1402)

LF_VFUNCTAB (0x1409)

LF_STMEMBER (0x150e)

LF_METHOD (0x150f)

LF_MEMBER (0x150d)

LF_NESTTYPE (0x1510)

LF_ONEMETHOD (0x1511)

LF_ENUMERATE (0x1502)

LF_INDEX (0x1404)

填充记录

LF_PADn (0xf0 + n)