CodeView 類型記錄¶
簡介¶
本文檔描述了 LLVM 所理解的各種 CodeView 類型記錄的使用方式和序列化格式。本文檔並未描述每個已定義的 CodeView 類型記錄。在某些情況下,這是因為這些記錄顯然已被棄用,並且只會出現在非常舊的軟體中(例如 16 位元類型)。在其他情況下,這是因為在實務上從未觀察到這些記錄。這可能是因為它們只為非 C++ 程式碼產生(例如 Visual Basic、C#),或者因為它們已被更新的記錄取代,或者還有其他原因。但是,我們在此描述的記錄應該涵蓋了在處理現代 C++ 工具鏈時可能會遇到的 99% 的類型記錄。
記錄類別¶
我們可以將一系列的 CodeView 類型記錄視為一個由可變長度的 葉節點記錄 組成的陣列。每個此類記錄都會在其固定大小的標頭中描述其自身的長度,以及其記錄類型。葉節點記錄會填補至 4 個位元組(如果此類型串流出現在 PDB 的 TPI/IPI 串流中),或者根本不填補(如果此類型串流出現在物件檔案的 .debug$T
區段中)。填補是透過插入一系列遞減的 <_padding_records> 來實現的,並以 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
屬性是一個具有以下佈局的位元欄位
.-----------------------------------------------------------------------------------------------------.
| 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() &&)
};
屬性位元遮罩的 大小
欄位是一個 1 位元組的值,表示指標大小。例如,void* 的大小將根據目標架構為 4 或 8。另一方面,如果 模式
表示這是指向成員函式或指向數據成員的指標,則大小可以是任何實作定義的數字。
LF_POINTER
記錄的 成員 指標 資訊
欄位僅在屬性指示這是指向成員的指標時才會出現。
請注意,指向基本類型的「純」指標不是由 LF_POINTER
記錄表示,而是由特殊保留的 類型索引值 表示。