CodeView 類型記錄¶
簡介¶
本文檔描述 LLVM 理解的各種 CodeView 類型記錄的使用方式和序列化格式。本文檔並未描述定義的每個 CodeView 類型記錄。在某些情況下,這是因為這些記錄顯然已被棄用,並且只能出現在非常舊的軟體中(例如 16 位元類型)。在其他情況下,這是因為這些記錄從未在實務中觀察到。這可能是因為它們僅針對非 C++ 程式碼(例如 Visual Basic、C#)生成,或者因為它們已被較新的記錄取代,或任何其他原因。但是,我們在此處描述的記錄應涵蓋在處理現代 C++ 工具鏈時可能遇到的 99% 的類型記錄。
記錄類別¶
我們可以將 CodeView 類型記錄的序列視為可變長度的葉記錄陣列。每個這樣的記錄都將其自身的長度描述為固定大小標頭的一部分,以及它是哪種記錄。葉記錄會填充到 4 個位元組(如果此類型流出現在 PDB 的 TPI/IPI 流中)或完全不填充(如果此類型流出現在物件檔案的 .debug$T
區段中)。填充是透過插入遞減的 <填充記錄> 序列來實作的,該序列以 LF_PAD0
終止。
記錄的最後一個類別是 成員 記錄
。一種特殊的葉類型 – LF_FIELDLIST
– 包含一系列嵌入式記錄。雖然外部 LF_FIELDLIST
描述了其長度(像任何其他葉記錄一樣),但嵌入式記錄 – 稱為 成員 記錄
則不描述長度。
葉記錄¶
所有葉記錄都以以下 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 值 指示。