10b57cec5SDimitry Andric //===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
9e8d8bef9SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
10e8d8bef9SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeRecord.h"
110b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
120b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric using namespace llvm;
150b57cec5SDimitry Andric using namespace llvm::codeview;
160b57cec5SDimitry Andric 
getMethodKind(uint16_t Attrs)170b57cec5SDimitry Andric static inline MethodKind getMethodKind(uint16_t Attrs) {
180b57cec5SDimitry Andric   Attrs &= uint16_t(MethodOptions::MethodKindMask);
190b57cec5SDimitry Andric   Attrs >>= 2;
200b57cec5SDimitry Andric   return MethodKind(Attrs);
210b57cec5SDimitry Andric }
220b57cec5SDimitry Andric 
isIntroVirtual(uint16_t Attrs)230b57cec5SDimitry Andric static inline bool isIntroVirtual(uint16_t Attrs) {
240b57cec5SDimitry Andric   MethodKind MK = getMethodKind(Attrs);
250b57cec5SDimitry Andric   return MK == MethodKind::IntroducingVirtual ||
260b57cec5SDimitry Andric          MK == MethodKind::PureIntroducingVirtual;
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric 
getPointerMode(uint32_t Attrs)290b57cec5SDimitry Andric static inline PointerMode getPointerMode(uint32_t Attrs) {
300b57cec5SDimitry Andric   return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
310b57cec5SDimitry Andric                                   PointerRecord::PointerModeMask);
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
isMemberPointer(uint32_t Attrs)340b57cec5SDimitry Andric static inline bool isMemberPointer(uint32_t Attrs) {
350b57cec5SDimitry Andric   PointerMode Mode = getPointerMode(Attrs);
360b57cec5SDimitry Andric   return Mode == PointerMode::PointerToDataMember ||
370b57cec5SDimitry Andric          Mode == PointerMode::PointerToMemberFunction;
380b57cec5SDimitry Andric }
390b57cec5SDimitry Andric 
getEncodedIntegerLength(ArrayRef<uint8_t> Data)400b57cec5SDimitry Andric static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
410b57cec5SDimitry Andric   uint16_t N = support::endian::read16le(Data.data());
420b57cec5SDimitry Andric   if (N < LF_NUMERIC)
430b57cec5SDimitry Andric     return 2;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   assert(N <= LF_UQUADWORD);
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   constexpr uint32_t Sizes[] = {
480b57cec5SDimitry Andric       1,  // LF_CHAR
490b57cec5SDimitry Andric       2,  // LF_SHORT
500b57cec5SDimitry Andric       2,  // LF_USHORT
510b57cec5SDimitry Andric       4,  // LF_LONG
520b57cec5SDimitry Andric       4,  // LF_ULONG
530b57cec5SDimitry Andric       4,  // LF_REAL32
540b57cec5SDimitry Andric       8,  // LF_REAL64
550b57cec5SDimitry Andric       10, // LF_REAL80
560b57cec5SDimitry Andric       16, // LF_REAL128
570b57cec5SDimitry Andric       8,  // LF_QUADWORD
580b57cec5SDimitry Andric       8,  // LF_UQUADWORD
590b57cec5SDimitry Andric   };
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   return 2 + Sizes[N - LF_NUMERIC];
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
getCStringLength(ArrayRef<uint8_t> Data)640b57cec5SDimitry Andric static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
650b57cec5SDimitry Andric   const char *S = reinterpret_cast<const char *>(Data.data());
660b57cec5SDimitry Andric   return strlen(S) + 1;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
handleMethodOverloadList(ArrayRef<uint8_t> Content,SmallVectorImpl<TiReference> & Refs)690b57cec5SDimitry Andric static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
700b57cec5SDimitry Andric                                      SmallVectorImpl<TiReference> &Refs) {
710b57cec5SDimitry Andric   uint32_t Offset = 0;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   while (!Content.empty()) {
740b57cec5SDimitry Andric     // Array of:
750b57cec5SDimitry Andric     //   0: Attrs
760b57cec5SDimitry Andric     //   2: Padding
770b57cec5SDimitry Andric     //   4: TypeIndex
780b57cec5SDimitry Andric     //   if (isIntroVirtual())
790b57cec5SDimitry Andric     //     8: VFTableOffset
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     // At least 8 bytes are guaranteed.  4 extra bytes come iff function is an
820b57cec5SDimitry Andric     // intro virtual.
830b57cec5SDimitry Andric     uint32_t Len = 8;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     uint16_t Attrs = support::endian::read16le(Content.data());
860b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
890b57cec5SDimitry Andric       Len += 4;
900b57cec5SDimitry Andric     Offset += Len;
910b57cec5SDimitry Andric     Content = Content.drop_front(Len);
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
handleBaseClass(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)950b57cec5SDimitry Andric static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
960b57cec5SDimitry Andric                                 SmallVectorImpl<TiReference> &Refs) {
970b57cec5SDimitry Andric   // 0: Kind
980b57cec5SDimitry Andric   // 2: Padding
990b57cec5SDimitry Andric   // 4: TypeIndex
1000b57cec5SDimitry Andric   // 8: Encoded Integer
1010b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1020b57cec5SDimitry Andric   return 8 + getEncodedIntegerLength(Data.drop_front(8));
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
handleEnumerator(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1050b57cec5SDimitry Andric static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
1060b57cec5SDimitry Andric                                  SmallVectorImpl<TiReference> &Refs) {
1070b57cec5SDimitry Andric   // 0: Kind
1080b57cec5SDimitry Andric   // 2: Padding
1090b57cec5SDimitry Andric   // 4: Encoded Integer
1100b57cec5SDimitry Andric   // <next>: Name
1110b57cec5SDimitry Andric   uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
1120b57cec5SDimitry Andric   return Size + getCStringLength(Data.drop_front(Size));
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
handleDataMember(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1150b57cec5SDimitry Andric static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
1160b57cec5SDimitry Andric                                  SmallVectorImpl<TiReference> &Refs) {
1170b57cec5SDimitry Andric   // 0: Kind
1180b57cec5SDimitry Andric   // 2: Padding
1190b57cec5SDimitry Andric   // 4: TypeIndex
1200b57cec5SDimitry Andric   // 8: Encoded Integer
1210b57cec5SDimitry Andric   // <next>: Name
1220b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1230b57cec5SDimitry Andric   uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
1240b57cec5SDimitry Andric   return Size + getCStringLength(Data.drop_front(Size));
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
handleOverloadedMethod(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1270b57cec5SDimitry Andric static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
1280b57cec5SDimitry Andric                                        SmallVectorImpl<TiReference> &Refs) {
1290b57cec5SDimitry Andric   // 0: Kind
1300b57cec5SDimitry Andric   // 2: Padding
1310b57cec5SDimitry Andric   // 4: TypeIndex
1320b57cec5SDimitry Andric   // 8: Name
1330b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1340b57cec5SDimitry Andric   return 8 + getCStringLength(Data.drop_front(8));
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
handleOneMethod(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1370b57cec5SDimitry Andric static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
1380b57cec5SDimitry Andric                                 SmallVectorImpl<TiReference> &Refs) {
1390b57cec5SDimitry Andric   // 0: Kind
1400b57cec5SDimitry Andric   // 2: Attributes
1410b57cec5SDimitry Andric   // 4: Type
1420b57cec5SDimitry Andric   // if (isIntroVirtual)
1430b57cec5SDimitry Andric   //   8: VFTableOffset
1440b57cec5SDimitry Andric   // <next>: Name
1450b57cec5SDimitry Andric   uint32_t Size = 8;
1460b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
1490b57cec5SDimitry Andric   if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
1500b57cec5SDimitry Andric     Size += 4;
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   return Size + getCStringLength(Data.drop_front(Size));
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
handleNestedType(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1550b57cec5SDimitry Andric static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
1560b57cec5SDimitry Andric                                  SmallVectorImpl<TiReference> &Refs) {
1570b57cec5SDimitry Andric   // 0: Kind
1580b57cec5SDimitry Andric   // 2: Padding
1590b57cec5SDimitry Andric   // 4: TypeIndex
1600b57cec5SDimitry Andric   // 8: Name
1610b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1620b57cec5SDimitry Andric   return 8 + getCStringLength(Data.drop_front(8));
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
handleStaticDataMember(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1650b57cec5SDimitry Andric static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
1660b57cec5SDimitry Andric                                        SmallVectorImpl<TiReference> &Refs) {
1670b57cec5SDimitry Andric   // 0: Kind
1680b57cec5SDimitry Andric   // 2: Padding
1690b57cec5SDimitry Andric   // 4: TypeIndex
1700b57cec5SDimitry Andric   // 8: Name
1710b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1720b57cec5SDimitry Andric   return 8 + getCStringLength(Data.drop_front(8));
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
handleVirtualBaseClass(ArrayRef<uint8_t> Data,uint32_t Offset,bool IsIndirect,SmallVectorImpl<TiReference> & Refs)1750b57cec5SDimitry Andric static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
1760b57cec5SDimitry Andric                                        bool IsIndirect,
1770b57cec5SDimitry Andric                                        SmallVectorImpl<TiReference> &Refs) {
1780b57cec5SDimitry Andric   // 0: Kind
1790b57cec5SDimitry Andric   // 2: Attrs
1800b57cec5SDimitry Andric   // 4: TypeIndex
1810b57cec5SDimitry Andric   // 8: TypeIndex
1820b57cec5SDimitry Andric   // 12: Encoded Integer
1830b57cec5SDimitry Andric   // <next>: Encoded Integer
1840b57cec5SDimitry Andric   uint32_t Size = 12;
1850b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
1860b57cec5SDimitry Andric   Size += getEncodedIntegerLength(Data.drop_front(Size));
1870b57cec5SDimitry Andric   Size += getEncodedIntegerLength(Data.drop_front(Size));
1880b57cec5SDimitry Andric   return Size;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
handleVFPtr(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)1910b57cec5SDimitry Andric static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
1920b57cec5SDimitry Andric                             SmallVectorImpl<TiReference> &Refs) {
1930b57cec5SDimitry Andric   // 0: Kind
1940b57cec5SDimitry Andric   // 2: Padding
1950b57cec5SDimitry Andric   // 4: TypeIndex
1960b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
1970b57cec5SDimitry Andric   return 8;
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
handleListContinuation(ArrayRef<uint8_t> Data,uint32_t Offset,SmallVectorImpl<TiReference> & Refs)2000b57cec5SDimitry Andric static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
2010b57cec5SDimitry Andric                                        SmallVectorImpl<TiReference> &Refs) {
2020b57cec5SDimitry Andric   // 0: Kind
2030b57cec5SDimitry Andric   // 2: Padding
2040b57cec5SDimitry Andric   // 4: TypeIndex
2050b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
2060b57cec5SDimitry Andric   return 8;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
handleFieldList(ArrayRef<uint8_t> Content,SmallVectorImpl<TiReference> & Refs)2090b57cec5SDimitry Andric static void handleFieldList(ArrayRef<uint8_t> Content,
2100b57cec5SDimitry Andric                             SmallVectorImpl<TiReference> &Refs) {
2110b57cec5SDimitry Andric   uint32_t Offset = 0;
2120b57cec5SDimitry Andric   uint32_t ThisLen = 0;
2130b57cec5SDimitry Andric   while (!Content.empty()) {
2140b57cec5SDimitry Andric     TypeLeafKind Kind =
2150b57cec5SDimitry Andric         static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
2160b57cec5SDimitry Andric     switch (Kind) {
2170b57cec5SDimitry Andric     case LF_BCLASS:
2180b57cec5SDimitry Andric       ThisLen = handleBaseClass(Content, Offset, Refs);
2190b57cec5SDimitry Andric       break;
2200b57cec5SDimitry Andric     case LF_ENUMERATE:
2210b57cec5SDimitry Andric       ThisLen = handleEnumerator(Content, Offset, Refs);
2220b57cec5SDimitry Andric       break;
2230b57cec5SDimitry Andric     case LF_MEMBER:
2240b57cec5SDimitry Andric       ThisLen = handleDataMember(Content, Offset, Refs);
2250b57cec5SDimitry Andric       break;
2260b57cec5SDimitry Andric     case LF_METHOD:
2270b57cec5SDimitry Andric       ThisLen = handleOverloadedMethod(Content, Offset, Refs);
2280b57cec5SDimitry Andric       break;
2290b57cec5SDimitry Andric     case LF_ONEMETHOD:
2300b57cec5SDimitry Andric       ThisLen = handleOneMethod(Content, Offset, Refs);
2310b57cec5SDimitry Andric       break;
2320b57cec5SDimitry Andric     case LF_NESTTYPE:
2330b57cec5SDimitry Andric       ThisLen = handleNestedType(Content, Offset, Refs);
2340b57cec5SDimitry Andric       break;
2350b57cec5SDimitry Andric     case LF_STMEMBER:
2360b57cec5SDimitry Andric       ThisLen = handleStaticDataMember(Content, Offset, Refs);
2370b57cec5SDimitry Andric       break;
2380b57cec5SDimitry Andric     case LF_VBCLASS:
2390b57cec5SDimitry Andric     case LF_IVBCLASS:
2400b57cec5SDimitry Andric       ThisLen =
2410b57cec5SDimitry Andric           handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
2420b57cec5SDimitry Andric       break;
2430b57cec5SDimitry Andric     case LF_VFUNCTAB:
2440b57cec5SDimitry Andric       ThisLen = handleVFPtr(Content, Offset, Refs);
2450b57cec5SDimitry Andric       break;
2460b57cec5SDimitry Andric     case LF_INDEX:
2470b57cec5SDimitry Andric       ThisLen = handleListContinuation(Content, Offset, Refs);
2480b57cec5SDimitry Andric       break;
2490b57cec5SDimitry Andric     default:
2500b57cec5SDimitry Andric       return;
2510b57cec5SDimitry Andric     }
2520b57cec5SDimitry Andric     Content = Content.drop_front(ThisLen);
2530b57cec5SDimitry Andric     Offset += ThisLen;
2540b57cec5SDimitry Andric     if (!Content.empty()) {
2550b57cec5SDimitry Andric       uint8_t Pad = Content.front();
2560b57cec5SDimitry Andric       if (Pad >= LF_PAD0) {
2570b57cec5SDimitry Andric         uint32_t Skip = Pad & 0x0F;
2580b57cec5SDimitry Andric         Content = Content.drop_front(Skip);
2590b57cec5SDimitry Andric         Offset += Skip;
2600b57cec5SDimitry Andric       }
2610b57cec5SDimitry Andric     }
2620b57cec5SDimitry Andric   }
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
handlePointer(ArrayRef<uint8_t> Content,SmallVectorImpl<TiReference> & Refs)2650b57cec5SDimitry Andric static void handlePointer(ArrayRef<uint8_t> Content,
2660b57cec5SDimitry Andric                           SmallVectorImpl<TiReference> &Refs) {
2670b57cec5SDimitry Andric   Refs.push_back({TiRefKind::TypeRef, 0, 1});
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
2700b57cec5SDimitry Andric   if (isMemberPointer(Attrs))
2710b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 8, 1});
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric 
discoverTypeIndices(ArrayRef<uint8_t> Content,TypeLeafKind Kind,SmallVectorImpl<TiReference> & Refs)2740b57cec5SDimitry Andric static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
2750b57cec5SDimitry Andric                                 SmallVectorImpl<TiReference> &Refs) {
2760b57cec5SDimitry Andric   uint32_t Count;
2770b57cec5SDimitry Andric   // FIXME: In the future it would be nice if we could avoid hardcoding these
2780b57cec5SDimitry Andric   // values.  One idea is to define some structures representing these types
2790b57cec5SDimitry Andric   // that would allow the use of offsetof().
2800b57cec5SDimitry Andric   switch (Kind) {
2810b57cec5SDimitry Andric   case TypeLeafKind::LF_FUNC_ID:
2820b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 0, 1});
2830b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 4, 1});
2840b57cec5SDimitry Andric     break;
2850b57cec5SDimitry Andric   case TypeLeafKind::LF_MFUNC_ID:
2860b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 2});
2870b57cec5SDimitry Andric     break;
2880b57cec5SDimitry Andric   case TypeLeafKind::LF_STRING_ID:
2890b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 0, 1});
2900b57cec5SDimitry Andric     break;
2910b57cec5SDimitry Andric   case TypeLeafKind::LF_SUBSTR_LIST:
2920b57cec5SDimitry Andric     Count = support::endian::read32le(Content.data());
2930b57cec5SDimitry Andric     if (Count > 0)
2940b57cec5SDimitry Andric       Refs.push_back({TiRefKind::IndexRef, 4, Count});
2950b57cec5SDimitry Andric     break;
2960b57cec5SDimitry Andric   case TypeLeafKind::LF_BUILDINFO:
2970b57cec5SDimitry Andric     Count = support::endian::read16le(Content.data());
2980b57cec5SDimitry Andric     if (Count > 0)
2990b57cec5SDimitry Andric       Refs.push_back({TiRefKind::IndexRef, 2, Count});
3000b57cec5SDimitry Andric     break;
3010b57cec5SDimitry Andric   case TypeLeafKind::LF_UDT_SRC_LINE:
3020b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1});
3030b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 4, 1});
3040b57cec5SDimitry Andric     break;
3050b57cec5SDimitry Andric   case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
3060b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1});
3070b57cec5SDimitry Andric     break;
3080b57cec5SDimitry Andric   case TypeLeafKind::LF_MODIFIER:
3090b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1});
3100b57cec5SDimitry Andric     break;
3110b57cec5SDimitry Andric   case TypeLeafKind::LF_PROCEDURE:
3120b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1});
3130b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 8, 1});
3140b57cec5SDimitry Andric     break;
3150b57cec5SDimitry Andric   case TypeLeafKind::LF_MFUNCTION:
3160b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 3});
3170b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 16, 1});
3180b57cec5SDimitry Andric     break;
3190b57cec5SDimitry Andric   case TypeLeafKind::LF_ARGLIST:
3200b57cec5SDimitry Andric     Count = support::endian::read32le(Content.data());
3210b57cec5SDimitry Andric     if (Count > 0)
3220b57cec5SDimitry Andric       Refs.push_back({TiRefKind::TypeRef, 4, Count});
3230b57cec5SDimitry Andric     break;
3240b57cec5SDimitry Andric   case TypeLeafKind::LF_ARRAY:
3250b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 2});
3260b57cec5SDimitry Andric     break;
3270b57cec5SDimitry Andric   case TypeLeafKind::LF_CLASS:
3280b57cec5SDimitry Andric   case TypeLeafKind::LF_STRUCTURE:
3290b57cec5SDimitry Andric   case TypeLeafKind::LF_INTERFACE:
3300b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 4, 3});
3310b57cec5SDimitry Andric     break;
3320b57cec5SDimitry Andric   case TypeLeafKind::LF_UNION:
3330b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 4, 1});
3340b57cec5SDimitry Andric     break;
3350b57cec5SDimitry Andric   case TypeLeafKind::LF_ENUM:
3360b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 4, 2});
3370b57cec5SDimitry Andric     break;
3380b57cec5SDimitry Andric   case TypeLeafKind::LF_BITFIELD:
3390b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1});
3400b57cec5SDimitry Andric     break;
3410b57cec5SDimitry Andric   case TypeLeafKind::LF_VFTABLE:
3420b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 2});
3430b57cec5SDimitry Andric     break;
3440b57cec5SDimitry Andric   case TypeLeafKind::LF_VTSHAPE:
3450b57cec5SDimitry Andric     break;
3460b57cec5SDimitry Andric   case TypeLeafKind::LF_METHODLIST:
3470b57cec5SDimitry Andric     handleMethodOverloadList(Content, Refs);
3480b57cec5SDimitry Andric     break;
3490b57cec5SDimitry Andric   case TypeLeafKind::LF_FIELDLIST:
3500b57cec5SDimitry Andric     handleFieldList(Content, Refs);
3510b57cec5SDimitry Andric     break;
3520b57cec5SDimitry Andric   case TypeLeafKind::LF_POINTER:
3530b57cec5SDimitry Andric     handlePointer(Content, Refs);
3540b57cec5SDimitry Andric     break;
3550b57cec5SDimitry Andric   default:
3560b57cec5SDimitry Andric     break;
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric }
3590b57cec5SDimitry Andric 
discoverTypeIndices(ArrayRef<uint8_t> Content,SymbolKind Kind,SmallVectorImpl<TiReference> & Refs)3600b57cec5SDimitry Andric static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
3610b57cec5SDimitry Andric                                 SmallVectorImpl<TiReference> &Refs) {
3620b57cec5SDimitry Andric   uint32_t Count;
3630b57cec5SDimitry Andric   // FIXME: In the future it would be nice if we could avoid hardcoding these
3640b57cec5SDimitry Andric   // values.  One idea is to define some structures representing these types
3650b57cec5SDimitry Andric   // that would allow the use of offsetof().
3660b57cec5SDimitry Andric   switch (Kind) {
3670b57cec5SDimitry Andric   case SymbolKind::S_GPROC32_ID:
3680b57cec5SDimitry Andric   case SymbolKind::S_LPROC32_ID:
3690b57cec5SDimitry Andric   case SymbolKind::S_LPROC32_DPC:
3700b57cec5SDimitry Andric   case SymbolKind::S_LPROC32_DPC_ID:
3710b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
3720b57cec5SDimitry Andric     break;
3730b57cec5SDimitry Andric   case SymbolKind::S_GPROC32:
3740b57cec5SDimitry Andric   case SymbolKind::S_LPROC32:
3750b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
3760b57cec5SDimitry Andric     break;
3770b57cec5SDimitry Andric   case SymbolKind::S_UDT:
3780b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
3790b57cec5SDimitry Andric     break;
3800b57cec5SDimitry Andric   case SymbolKind::S_GDATA32:
3810b57cec5SDimitry Andric   case SymbolKind::S_LDATA32:
3820b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
3830b57cec5SDimitry Andric     break;
3840b57cec5SDimitry Andric   case SymbolKind::S_BUILDINFO:
3850b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
3860b57cec5SDimitry Andric     break;
3870b57cec5SDimitry Andric   case SymbolKind::S_LTHREAD32:
3880b57cec5SDimitry Andric   case SymbolKind::S_GTHREAD32:
3890b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
3900b57cec5SDimitry Andric     break;
3910b57cec5SDimitry Andric   case SymbolKind::S_FILESTATIC:
3920b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
3930b57cec5SDimitry Andric     break;
3940b57cec5SDimitry Andric   case SymbolKind::S_LOCAL:
3950b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
3960b57cec5SDimitry Andric     break;
3970b57cec5SDimitry Andric   case SymbolKind::S_REGISTER:
3980b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
3990b57cec5SDimitry Andric     break;
4000b57cec5SDimitry Andric   case SymbolKind::S_CONSTANT:
4010b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
4020b57cec5SDimitry Andric     break;
4030b57cec5SDimitry Andric   case SymbolKind::S_BPREL32:
4040b57cec5SDimitry Andric   case SymbolKind::S_REGREL32:
4050b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
4060b57cec5SDimitry Andric     break;
4070b57cec5SDimitry Andric   case SymbolKind::S_CALLSITEINFO:
4080b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
4090b57cec5SDimitry Andric     break;
4100b57cec5SDimitry Andric   case SymbolKind::S_CALLERS:
4110b57cec5SDimitry Andric   case SymbolKind::S_CALLEES:
4120b57cec5SDimitry Andric   case SymbolKind::S_INLINEES:
4130b57cec5SDimitry Andric     // The record is a count followed by an array of type indices.
4140b57cec5SDimitry Andric     Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
4150b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
4160b57cec5SDimitry Andric     break;
4170b57cec5SDimitry Andric   case SymbolKind::S_INLINESITE:
4180b57cec5SDimitry Andric     Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
4190b57cec5SDimitry Andric     break;
4200b57cec5SDimitry Andric   case SymbolKind::S_HEAPALLOCSITE:
4210b57cec5SDimitry Andric     Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
4220b57cec5SDimitry Andric     break;
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   // Defranges don't have types, just registers and code offsets.
4250b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_REGISTER:
4260b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_REGISTER_REL:
4270b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
4280b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
4290b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
4300b57cec5SDimitry Andric   case SymbolKind::S_DEFRANGE_SUBFIELD:
4310b57cec5SDimitry Andric     break;
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   // No type references.
4340b57cec5SDimitry Andric   case SymbolKind::S_LABEL32:
4350b57cec5SDimitry Andric   case SymbolKind::S_OBJNAME:
4360b57cec5SDimitry Andric   case SymbolKind::S_COMPILE:
4370b57cec5SDimitry Andric   case SymbolKind::S_COMPILE2:
4380b57cec5SDimitry Andric   case SymbolKind::S_COMPILE3:
4390b57cec5SDimitry Andric   case SymbolKind::S_ENVBLOCK:
4400b57cec5SDimitry Andric   case SymbolKind::S_BLOCK32:
4410b57cec5SDimitry Andric   case SymbolKind::S_FRAMEPROC:
4420b57cec5SDimitry Andric   case SymbolKind::S_THUNK32:
4430b57cec5SDimitry Andric   case SymbolKind::S_FRAMECOOKIE:
4440b57cec5SDimitry Andric   case SymbolKind::S_UNAMESPACE:
4455f757f3fSDimitry Andric   case SymbolKind::S_ARMSWITCHTABLE:
4460b57cec5SDimitry Andric     break;
4470b57cec5SDimitry Andric   // Scope ending symbols.
4480b57cec5SDimitry Andric   case SymbolKind::S_END:
4490b57cec5SDimitry Andric   case SymbolKind::S_INLINESITE_END:
4500b57cec5SDimitry Andric   case SymbolKind::S_PROC_ID_END:
4510b57cec5SDimitry Andric     break;
4520b57cec5SDimitry Andric   default:
4530b57cec5SDimitry Andric     return false; // Unknown symbol.
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric   return true;
4560b57cec5SDimitry Andric }
4570b57cec5SDimitry Andric 
discoverTypeIndices(const CVType & Type,SmallVectorImpl<TiReference> & Refs)4580b57cec5SDimitry Andric void llvm::codeview::discoverTypeIndices(const CVType &Type,
4590b57cec5SDimitry Andric                                          SmallVectorImpl<TiReference> &Refs) {
4600b57cec5SDimitry Andric   ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric 
resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,ArrayRef<TiReference> Refs,SmallVectorImpl<TypeIndex> & Indices)4630b57cec5SDimitry Andric static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
4640b57cec5SDimitry Andric                                        ArrayRef<TiReference> Refs,
4650b57cec5SDimitry Andric                                        SmallVectorImpl<TypeIndex> &Indices) {
4660b57cec5SDimitry Andric   Indices.clear();
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   if (Refs.empty())
4690b57cec5SDimitry Andric     return;
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   RecordData = RecordData.drop_front(sizeof(RecordPrefix));
4720b57cec5SDimitry Andric 
4735f757f3fSDimitry Andric   BinaryStreamReader Reader(RecordData, llvm::endianness::little);
4740b57cec5SDimitry Andric   for (const auto &Ref : Refs) {
4750b57cec5SDimitry Andric     Reader.setOffset(Ref.Offset);
4760b57cec5SDimitry Andric     FixedStreamArray<TypeIndex> Run;
4770b57cec5SDimitry Andric     cantFail(Reader.readArray(Run, Ref.Count));
4780b57cec5SDimitry Andric     Indices.append(Run.begin(), Run.end());
4790b57cec5SDimitry Andric   }
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
discoverTypeIndices(const CVType & Type,SmallVectorImpl<TypeIndex> & Indices)4820b57cec5SDimitry Andric void llvm::codeview::discoverTypeIndices(const CVType &Type,
4830b57cec5SDimitry Andric                                          SmallVectorImpl<TypeIndex> &Indices) {
4840b57cec5SDimitry Andric   return discoverTypeIndices(Type.RecordData, Indices);
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric 
discoverTypeIndices(ArrayRef<uint8_t> RecordData,SmallVectorImpl<TypeIndex> & Indices)4870b57cec5SDimitry Andric void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
4880b57cec5SDimitry Andric                                          SmallVectorImpl<TypeIndex> &Indices) {
4890b57cec5SDimitry Andric   SmallVector<TiReference, 4> Refs;
4900b57cec5SDimitry Andric   discoverTypeIndices(RecordData, Refs);
4910b57cec5SDimitry Andric   resolveTypeIndexReferences(RecordData, Refs, Indices);
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric 
discoverTypeIndices(ArrayRef<uint8_t> RecordData,SmallVectorImpl<TiReference> & Refs)4940b57cec5SDimitry Andric void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
4950b57cec5SDimitry Andric                                          SmallVectorImpl<TiReference> &Refs) {
4960b57cec5SDimitry Andric   const RecordPrefix *P =
4970b57cec5SDimitry Andric       reinterpret_cast<const RecordPrefix *>(RecordData.data());
4980b57cec5SDimitry Andric   TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
4990b57cec5SDimitry Andric   ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
5000b57cec5SDimitry Andric }
5010b57cec5SDimitry Andric 
discoverTypeIndicesInSymbol(const CVSymbol & Sym,SmallVectorImpl<TiReference> & Refs)5020b57cec5SDimitry Andric bool llvm::codeview::discoverTypeIndicesInSymbol(
5030b57cec5SDimitry Andric     const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
5040b57cec5SDimitry Andric   SymbolKind K = Sym.kind();
5050b57cec5SDimitry Andric   return ::discoverTypeIndices(Sym.content(), K, Refs);
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric 
discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData,SmallVectorImpl<TiReference> & Refs)5080b57cec5SDimitry Andric bool llvm::codeview::discoverTypeIndicesInSymbol(
5090b57cec5SDimitry Andric     ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
5100b57cec5SDimitry Andric   const RecordPrefix *P =
5110b57cec5SDimitry Andric       reinterpret_cast<const RecordPrefix *>(RecordData.data());
5120b57cec5SDimitry Andric   SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
5130b57cec5SDimitry Andric   return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
5140b57cec5SDimitry Andric                                Refs);
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData,SmallVectorImpl<TypeIndex> & Indices)5170b57cec5SDimitry Andric bool llvm::codeview::discoverTypeIndicesInSymbol(
5180b57cec5SDimitry Andric     ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
5190b57cec5SDimitry Andric   SmallVector<TiReference, 2> Refs;
5200b57cec5SDimitry Andric   if (!discoverTypeIndicesInSymbol(RecordData, Refs))
5210b57cec5SDimitry Andric     return false;
5220b57cec5SDimitry Andric   resolveTypeIndexReferences(RecordData, Refs, Indices);
5230b57cec5SDimitry Andric   return true;
5240b57cec5SDimitry Andric }
525