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 記錄表示,而是由特殊保留的 類型索引值 表示。

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)