CodeView 型レコード¶
はじめに¶
このドキュメントでは、LLVM が理解する様々な CodeView 型レコードの使用法とシリアライズ形式について説明します。このドキュメントでは、定義されているすべての CodeView 型レコードを説明するわけではありません。場合によっては、レコードが明らかに非推奨であり、非常に古いソフトウェアにしか現れないためです (例: 16 ビット型)。また、他のケースでは、レコードが実際には観測されていないためです。これは、C++ 以外のコード (例: Visual Basic、C#) でのみ生成される場合や、新しいレコードによって廃止された場合、またはその他のさまざまな理由が考えられます。ただし、ここで説明するレコードは、最新の C++ ツールチェーンを扱う際に遭遇する可能性のある型レコードの 99% をカバーしているはずです。
レコードカテゴリ¶
CodeView 型レコードのシーケンスを、可変長の リーフレコード の配列として考えることができます。このような各レコードは、固定サイズのヘッダーの一部として自身の長さと、レコードの種類を記述します。リーフレコードは、4 バイト (この型ストリームが PDB の TPI/IPI ストリームに表示される場合) にパディングされるか、まったくパディングされません (この型ストリームがオブジェクトファイルの .debug$T
セクションに表示される場合)。パディングは、<_padding_records> の減少するシーケンスを挿入し、LF_PAD0
で終わることで実装されます。
レコードの最後のカテゴリは、member record
です。特定のリーフ型である LF_FIELDLIST
には、一連の埋め込みレコードが含まれています。外側の LF_FIELDLIST
は (他のリーフレコードと同様に) その長さを記述しますが、member record
と呼ばれる埋め込みレコードは記述しません。
リーフレコード¶
すべてのリーフレコードは、次の 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() &&)
};
属性ビットマスクの Size
フィールドは、ポインタサイズを示す 1 バイトの値です。たとえば、void* のサイズは、ターゲットアーキテクチャに応じて 4 または 8 になります。一方、Mode
がメンバー関数へのポインタまたはデータメンバーへのポインタであることを示す場合、サイズは実装定義の任意の数にすることができます。
LF_POINTER
レコードの Member Ptr Info
フィールドは、属性がメンバーへのポインタであることを示す場合にのみ存在します。
プリミティブ型への「プレーン」ポインタは LF_POINTER
レコードで表現されないことに注意してください。これらは、特別な予約済みの TypeIndex 値 で示されます。