Home | History | Annotate | Download | only in CodeView
      1 //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
     10 
     11 #include "llvm/ADT/ArrayRef.h"
     12 #include "llvm/Support/Endian.h"
     13 
     14 using namespace llvm;
     15 using namespace llvm::codeview;
     16 
     17 static inline MethodKind getMethodKind(uint16_t Attrs) {
     18   Attrs &= uint16_t(MethodOptions::MethodKindMask);
     19   Attrs >>= 2;
     20   return MethodKind(Attrs);
     21 }
     22 
     23 static inline bool isIntroVirtual(uint16_t Attrs) {
     24   MethodKind MK = getMethodKind(Attrs);
     25   return MK == MethodKind::IntroducingVirtual ||
     26          MK == MethodKind::PureIntroducingVirtual;
     27 }
     28 
     29 static inline PointerMode getPointerMode(uint32_t Attrs) {
     30   return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
     31                                   PointerRecord::PointerModeMask);
     32 }
     33 
     34 static inline bool isMemberPointer(uint32_t Attrs) {
     35   PointerMode Mode = getPointerMode(Attrs);
     36   return Mode == PointerMode::PointerToDataMember ||
     37          Mode == PointerMode::PointerToMemberFunction;
     38 }
     39 
     40 static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
     41   uint16_t N = support::endian::read16le(Data.data());
     42   if (N < LF_NUMERIC)
     43     return 2;
     44 
     45   assert(N <= LF_UQUADWORD);
     46 
     47   constexpr uint32_t Sizes[] = {
     48       1,  // LF_CHAR
     49       2,  // LF_SHORT
     50       2,  // LF_USHORT
     51       4,  // LF_LONG
     52       4,  // LF_ULONG
     53       4,  // LF_REAL32
     54       8,  // LF_REAL64
     55       10, // LF_REAL80
     56       16, // LF_REAL128
     57       8,  // LF_QUADWORD
     58       8,  // LF_UQUADWORD
     59   };
     60 
     61   return 2 + Sizes[N - LF_NUMERIC];
     62 }
     63 
     64 static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
     65   const char *S = reinterpret_cast<const char *>(Data.data());
     66   return strlen(S) + 1;
     67 }
     68 
     69 static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
     70                                      SmallVectorImpl<TiReference> &Refs) {
     71   uint32_t Offset = 0;
     72 
     73   while (!Content.empty()) {
     74     // Array of:
     75     //   0: Attrs
     76     //   2: Padding
     77     //   4: TypeIndex
     78     //   if (isIntroVirtual())
     79     //     8: VFTableOffset
     80 
     81     // At least 8 bytes are guaranteed.  4 extra bytes come iff function is an
     82     // intro virtual.
     83     uint32_t Len = 8;
     84 
     85     uint16_t Attrs = support::endian::read16le(Content.data());
     86     Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
     87 
     88     if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
     89       Len += 4;
     90     Offset += Len;
     91     Content = Content.drop_front(Len);
     92   }
     93 }
     94 
     95 static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
     96                                 SmallVectorImpl<TiReference> &Refs) {
     97   // 0: Kind
     98   // 2: Padding
     99   // 4: TypeIndex
    100   // 8: Encoded Integer
    101   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    102   return 8 + getEncodedIntegerLength(Data.drop_front(8));
    103 }
    104 
    105 static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
    106                                  SmallVectorImpl<TiReference> &Refs) {
    107   // 0: Kind
    108   // 2: Padding
    109   // 4: Encoded Integer
    110   // <next>: Name
    111   uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
    112   return Size + getCStringLength(Data.drop_front(Size));
    113 }
    114 
    115 static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
    116                                  SmallVectorImpl<TiReference> &Refs) {
    117   // 0: Kind
    118   // 2: Padding
    119   // 4: TypeIndex
    120   // 8: Encoded Integer
    121   // <next>: Name
    122   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    123   uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
    124   return Size + getCStringLength(Data.drop_front(Size));
    125 }
    126 
    127 static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
    128                                        SmallVectorImpl<TiReference> &Refs) {
    129   // 0: Kind
    130   // 2: Padding
    131   // 4: TypeIndex
    132   // 8: Name
    133   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    134   return 8 + getCStringLength(Data.drop_front(8));
    135 }
    136 
    137 static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
    138                                 SmallVectorImpl<TiReference> &Refs) {
    139   // 0: Kind
    140   // 2: Attributes
    141   // 4: Type
    142   // if (isIntroVirtual)
    143   //   8: VFTableOffset
    144   // <next>: Name
    145   uint32_t Size = 8;
    146   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    147 
    148   uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
    149   if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
    150     Size += 4;
    151 
    152   return Size + getCStringLength(Data.drop_front(Size));
    153 }
    154 
    155 static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
    156                                  SmallVectorImpl<TiReference> &Refs) {
    157   // 0: Kind
    158   // 2: Padding
    159   // 4: TypeIndex
    160   // 8: Name
    161   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    162   return 8 + getCStringLength(Data.drop_front(8));
    163 }
    164 
    165 static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
    166                                        SmallVectorImpl<TiReference> &Refs) {
    167   // 0: Kind
    168   // 2: Padding
    169   // 4: TypeIndex
    170   // 8: Name
    171   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    172   return 8 + getCStringLength(Data.drop_front(8));
    173 }
    174 
    175 static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
    176                                        bool IsIndirect,
    177                                        SmallVectorImpl<TiReference> &Refs) {
    178   // 0: Kind
    179   // 2: Attrs
    180   // 4: TypeIndex
    181   // 8: TypeIndex
    182   // 12: Encoded Integer
    183   // <next>: Encoded Integer
    184   uint32_t Size = 12;
    185   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
    186   Size += getEncodedIntegerLength(Data.drop_front(Size));
    187   Size += getEncodedIntegerLength(Data.drop_front(Size));
    188   return Size;
    189 }
    190 
    191 static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
    192                             SmallVectorImpl<TiReference> &Refs) {
    193   // 0: Kind
    194   // 2: Padding
    195   // 4: TypeIndex
    196   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    197   return 8;
    198 }
    199 
    200 static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
    201                                        SmallVectorImpl<TiReference> &Refs) {
    202   // 0: Kind
    203   // 2: Padding
    204   // 4: TypeIndex
    205   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
    206   return 8;
    207 }
    208 
    209 static void handleFieldList(ArrayRef<uint8_t> Content,
    210                             SmallVectorImpl<TiReference> &Refs) {
    211   uint32_t Offset = 0;
    212   uint32_t ThisLen = 0;
    213   while (!Content.empty()) {
    214     TypeLeafKind Kind =
    215         static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
    216     switch (Kind) {
    217     case LF_BCLASS:
    218       ThisLen = handleBaseClass(Content, Offset, Refs);
    219       break;
    220     case LF_ENUMERATE:
    221       ThisLen = handleEnumerator(Content, Offset, Refs);
    222       break;
    223     case LF_MEMBER:
    224       ThisLen = handleDataMember(Content, Offset, Refs);
    225       break;
    226     case LF_METHOD:
    227       ThisLen = handleOverloadedMethod(Content, Offset, Refs);
    228       break;
    229     case LF_ONEMETHOD:
    230       ThisLen = handleOneMethod(Content, Offset, Refs);
    231       break;
    232     case LF_NESTTYPE:
    233       ThisLen = handleNestedType(Content, Offset, Refs);
    234       break;
    235     case LF_STMEMBER:
    236       ThisLen = handleStaticDataMember(Content, Offset, Refs);
    237       break;
    238     case LF_VBCLASS:
    239     case LF_IVBCLASS:
    240       ThisLen =
    241           handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
    242       break;
    243     case LF_VFUNCTAB:
    244       ThisLen = handleVFPtr(Content, Offset, Refs);
    245       break;
    246     case LF_INDEX:
    247       ThisLen = handleListContinuation(Content, Offset, Refs);
    248       break;
    249     default:
    250       return;
    251     }
    252     Content = Content.drop_front(ThisLen);
    253     Offset += ThisLen;
    254     if (!Content.empty()) {
    255       uint8_t Pad = Content.front();
    256       if (Pad >= LF_PAD0) {
    257         uint32_t Skip = Pad & 0x0F;
    258         Content = Content.drop_front(Skip);
    259         Offset += Skip;
    260       }
    261     }
    262   }
    263 }
    264 
    265 static void handlePointer(ArrayRef<uint8_t> Content,
    266                           SmallVectorImpl<TiReference> &Refs) {
    267   Refs.push_back({TiRefKind::TypeRef, 0, 1});
    268 
    269   uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
    270   if (isMemberPointer(Attrs))
    271     Refs.push_back({TiRefKind::TypeRef, 8, 1});
    272 }
    273 
    274 static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
    275                                 SmallVectorImpl<TiReference> &Refs) {
    276   uint32_t Count;
    277   // FIXME: In the future it would be nice if we could avoid hardcoding these
    278   // values.  One idea is to define some structures representing these types
    279   // that would allow the use of offsetof().
    280   switch (Kind) {
    281   case TypeLeafKind::LF_FUNC_ID:
    282     Refs.push_back({TiRefKind::IndexRef, 0, 1});
    283     Refs.push_back({TiRefKind::TypeRef, 4, 1});
    284     break;
    285   case TypeLeafKind::LF_MFUNC_ID:
    286     Refs.push_back({TiRefKind::TypeRef, 0, 2});
    287     break;
    288   case TypeLeafKind::LF_STRING_ID:
    289     Refs.push_back({TiRefKind::IndexRef, 0, 1});
    290     break;
    291   case TypeLeafKind::LF_SUBSTR_LIST:
    292     Count = support::endian::read32le(Content.data());
    293     if (Count > 0)
    294       Refs.push_back({TiRefKind::IndexRef, 4, Count});
    295     break;
    296   case TypeLeafKind::LF_BUILDINFO:
    297     Count = support::endian::read16le(Content.data());
    298     if (Count > 0)
    299       Refs.push_back({TiRefKind::IndexRef, 2, Count});
    300     break;
    301   case TypeLeafKind::LF_UDT_SRC_LINE:
    302     Refs.push_back({TiRefKind::TypeRef, 0, 1});
    303     Refs.push_back({TiRefKind::IndexRef, 4, 1});
    304     break;
    305   case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
    306     Refs.push_back({TiRefKind::TypeRef, 0, 1});
    307     break;
    308   case TypeLeafKind::LF_MODIFIER:
    309     Refs.push_back({TiRefKind::TypeRef, 0, 1});
    310     break;
    311   case TypeLeafKind::LF_PROCEDURE:
    312     Refs.push_back({TiRefKind::TypeRef, 0, 1});
    313     Refs.push_back({TiRefKind::TypeRef, 8, 1});
    314     break;
    315   case TypeLeafKind::LF_MFUNCTION:
    316     Refs.push_back({TiRefKind::TypeRef, 0, 3});
    317     Refs.push_back({TiRefKind::TypeRef, 16, 1});
    318     break;
    319   case TypeLeafKind::LF_ARGLIST:
    320     Count = support::endian::read32le(Content.data());
    321     if (Count > 0)
    322       Refs.push_back({TiRefKind::TypeRef, 4, Count});
    323     break;
    324   case TypeLeafKind::LF_ARRAY:
    325     Refs.push_back({TiRefKind::TypeRef, 0, 2});
    326     break;
    327   case TypeLeafKind::LF_CLASS:
    328   case TypeLeafKind::LF_STRUCTURE:
    329   case TypeLeafKind::LF_INTERFACE:
    330     Refs.push_back({TiRefKind::TypeRef, 4, 3});
    331     break;
    332   case TypeLeafKind::LF_UNION:
    333     Refs.push_back({TiRefKind::TypeRef, 4, 1});
    334     break;
    335   case TypeLeafKind::LF_ENUM:
    336     Refs.push_back({TiRefKind::TypeRef, 4, 2});
    337     break;
    338   case TypeLeafKind::LF_BITFIELD:
    339     Refs.push_back({TiRefKind::TypeRef, 0, 1});
    340     break;
    341   case TypeLeafKind::LF_VFTABLE:
    342     Refs.push_back({TiRefKind::TypeRef, 0, 2});
    343     break;
    344   case TypeLeafKind::LF_VTSHAPE:
    345     break;
    346   case TypeLeafKind::LF_METHODLIST:
    347     handleMethodOverloadList(Content, Refs);
    348     break;
    349   case TypeLeafKind::LF_FIELDLIST:
    350     handleFieldList(Content, Refs);
    351     break;
    352   case TypeLeafKind::LF_POINTER:
    353     handlePointer(Content, Refs);
    354     break;
    355   default:
    356     break;
    357   }
    358 }
    359 
    360 static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
    361                                 SmallVectorImpl<TiReference> &Refs) {
    362   uint32_t Count;
    363   // FIXME: In the future it would be nice if we could avoid hardcoding these
    364   // values.  One idea is to define some structures representing these types
    365   // that would allow the use of offsetof().
    366   switch (Kind) {
    367   case SymbolKind::S_GPROC32:
    368   case SymbolKind::S_LPROC32:
    369   case SymbolKind::S_GPROC32_ID:
    370   case SymbolKind::S_LPROC32_ID:
    371   case SymbolKind::S_LPROC32_DPC:
    372   case SymbolKind::S_LPROC32_DPC_ID:
    373     Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
    374     break;
    375   case SymbolKind::S_UDT:
    376     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
    377     break;
    378   case SymbolKind::S_GDATA32:
    379   case SymbolKind::S_LDATA32:
    380     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    381     break;
    382   case SymbolKind::S_BUILDINFO:
    383     Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
    384     break;
    385   case SymbolKind::S_LTHREAD32:
    386   case SymbolKind::S_GTHREAD32:
    387     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    388     break;
    389   case SymbolKind::S_FILESTATIC:
    390     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    391     break;
    392   case SymbolKind::S_LOCAL:
    393     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    394     break;
    395   case SymbolKind::S_REGISTER:
    396     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    397     break;
    398   case SymbolKind::S_CONSTANT:
    399     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
    400     break;
    401   case SymbolKind::S_BPREL32:
    402   case SymbolKind::S_REGREL32:
    403     Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
    404     break;
    405   case SymbolKind::S_CALLSITEINFO:
    406     Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
    407     break;
    408   case SymbolKind::S_CALLERS:
    409   case SymbolKind::S_CALLEES:
    410   case SymbolKind::S_INLINEES:
    411     // The record is a count followed by an array of type indices.
    412     Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
    413     Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
    414     break;
    415   case SymbolKind::S_INLINESITE:
    416     Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
    417     break;
    418   case SymbolKind::S_HEAPALLOCSITE:
    419     Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
    420     break;
    421 
    422   // Defranges don't have types, just registers and code offsets.
    423   case SymbolKind::S_DEFRANGE_REGISTER:
    424   case SymbolKind::S_DEFRANGE_REGISTER_REL:
    425   case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
    426   case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
    427   case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
    428   case SymbolKind::S_DEFRANGE_SUBFIELD:
    429     break;
    430 
    431   // No type references.
    432   case SymbolKind::S_LABEL32:
    433   case SymbolKind::S_OBJNAME:
    434   case SymbolKind::S_COMPILE:
    435   case SymbolKind::S_COMPILE2:
    436   case SymbolKind::S_COMPILE3:
    437   case SymbolKind::S_ENVBLOCK:
    438   case SymbolKind::S_BLOCK32:
    439   case SymbolKind::S_FRAMEPROC:
    440   case SymbolKind::S_THUNK32:
    441   case SymbolKind::S_FRAMECOOKIE:
    442   case SymbolKind::S_UNAMESPACE:
    443     break;
    444   // Scope ending symbols.
    445   case SymbolKind::S_END:
    446   case SymbolKind::S_INLINESITE_END:
    447   case SymbolKind::S_PROC_ID_END:
    448     break;
    449   default:
    450     return false; // Unknown symbol.
    451   }
    452   return true;
    453 }
    454 
    455 void llvm::codeview::discoverTypeIndices(const CVType &Type,
    456                                          SmallVectorImpl<TiReference> &Refs) {
    457   ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
    458 }
    459 
    460 static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
    461                                        ArrayRef<TiReference> Refs,
    462                                        SmallVectorImpl<TypeIndex> &Indices) {
    463   Indices.clear();
    464 
    465   if (Refs.empty())
    466     return;
    467 
    468   RecordData = RecordData.drop_front(sizeof(RecordPrefix));
    469 
    470   BinaryStreamReader Reader(RecordData, support::little);
    471   for (const auto &Ref : Refs) {
    472     Reader.setOffset(Ref.Offset);
    473     FixedStreamArray<TypeIndex> Run;
    474     cantFail(Reader.readArray(Run, Ref.Count));
    475     Indices.append(Run.begin(), Run.end());
    476   }
    477 }
    478 
    479 void llvm::codeview::discoverTypeIndices(const CVType &Type,
    480                                          SmallVectorImpl<TypeIndex> &Indices) {
    481   return discoverTypeIndices(Type.RecordData, Indices);
    482 }
    483 
    484 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
    485                                          SmallVectorImpl<TypeIndex> &Indices) {
    486   SmallVector<TiReference, 4> Refs;
    487   discoverTypeIndices(RecordData, Refs);
    488   resolveTypeIndexReferences(RecordData, Refs, Indices);
    489 }
    490 
    491 void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
    492                                          SmallVectorImpl<TiReference> &Refs) {
    493   const RecordPrefix *P =
    494       reinterpret_cast<const RecordPrefix *>(RecordData.data());
    495   TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
    496   ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
    497 }
    498 
    499 bool llvm::codeview::discoverTypeIndicesInSymbol(
    500     const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
    501   SymbolKind K = Sym.kind();
    502   return ::discoverTypeIndices(Sym.content(), K, Refs);
    503 }
    504 
    505 bool llvm::codeview::discoverTypeIndicesInSymbol(
    506     ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
    507   const RecordPrefix *P =
    508       reinterpret_cast<const RecordPrefix *>(RecordData.data());
    509   SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
    510   return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
    511                                Refs);
    512 }
    513 
    514 bool llvm::codeview::discoverTypeIndicesInSymbol(
    515     ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
    516   SmallVector<TiReference, 2> Refs;
    517   if (!discoverTypeIndicesInSymbol(RecordData, Refs))
    518     return false;
    519   resolveTypeIndexReferences(RecordData, Refs, Indices);
    520   return true;
    521 }
    522