CodeView 类型记录¶
简介¶
本文档描述了 LLVM 理解的各种 CodeView 类型记录的用法和序列化格式。本文档并未描述所有已定义的 CodeView 类型记录。在某些情况下,这是因为这些记录显然已被弃用,并且只能在非常旧的软件(例如 16 位类型)中出现。在其他情况下,这是因为这些记录从未在实践中被观察到。这可能是因为它们仅为非 C++ 代码(例如 Visual Basic、C#)生成,或者因为它们已被较新的记录淘汰,或者任何其他原因。但是,我们在此处描述的记录应涵盖在处理现代 C++ 工具链时可能遇到的 99% 的类型记录。
记录类别¶
我们可以将 CodeView 类型记录序列视为可变长度叶记录的数组。每个这样的记录都将其自身的长度描述为固定大小标头的一部分,以及它是什么类型的记录。叶记录要么填充到 4 字节(如果此类型流出现在 PDB 的 TPI/IPI 流中),要么根本不填充(如果此类型流出现在对象文件的 .debug$T section 中)。填充是通过插入一个递减的 <_padding_records> 序列来实现的,该序列以 LF_PAD0
终止。
记录的最后一个类别是 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 值表示的。