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 值 指示。