diff options
Diffstat (limited to 'include/llvm/DebugInfo/CodeView')
26 files changed, 973 insertions, 464 deletions
| diff --git a/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h new file mode 100644 index 000000000000..bd1743511ed4 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h @@ -0,0 +1,70 @@ +//===- AppendingTypeTableBuilder.h -------------------------------*- C++-*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_APPENDINGTYPETABLEBUILDER_H +#define LLVM_DEBUGINFO_CODEVIEW_APPENDINGTYPETABLEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { + +class ContinuationRecordBuilder; + +class AppendingTypeTableBuilder : public TypeCollection { + +  BumpPtrAllocator &RecordStorage; +  SimpleTypeSerializer SimpleSerializer; + +  /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). +  SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; + +public: +  explicit AppendingTypeTableBuilder(BumpPtrAllocator &Storage); +  ~AppendingTypeTableBuilder(); + +  // TypeTableCollection overrides +  Optional<TypeIndex> getFirst() override; +  Optional<TypeIndex> getNext(TypeIndex Prev) override; +  CVType getType(TypeIndex Index) override; +  StringRef getTypeName(TypeIndex Index) override; +  bool contains(TypeIndex Index) override; +  uint32_t size() override; +  uint32_t capacity() override; + +  // public interface +  void reset(); +  TypeIndex nextTypeIndex() const; + +  BumpPtrAllocator &getAllocator() { return RecordStorage; } + +  ArrayRef<ArrayRef<uint8_t>> records() const; +  TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record); +  TypeIndex insertRecord(ContinuationRecordBuilder &Builder); + +  template <typename T> TypeIndex writeLeafType(T &Record) { +    ArrayRef<uint8_t> Data = SimpleSerializer.serialize(Record); +    return insertRecordBytes(Data); +  } +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h index 44040e04388a..9f3a753ad1ae 100644 --- a/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -61,30 +61,38 @@ template <typename Kind> struct RemappedRecord {    SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;  }; +/// Read a complete record from a stream at a random offset. +template <typename Kind> +inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream, +                                                       uint32_t Offset) { +  const RecordPrefix *Prefix = nullptr; +  BinaryStreamReader Reader(Stream); +  Reader.setOffset(Offset); + +  if (auto EC = Reader.readObject(Prefix)) +    return std::move(EC); +  if (Prefix->RecordLen < 2) +    return make_error<CodeViewError>(cv_error_code::corrupt_record); +  Kind K = static_cast<Kind>(uint16_t(Prefix->RecordKind)); + +  Reader.setOffset(Offset); +  ArrayRef<uint8_t> RawData; +  if (auto EC = Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t))) +    return std::move(EC); +  return codeview::CVRecord<Kind>(K, RawData); +} +  } // end namespace codeview  template <typename Kind>  struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> {    Error operator()(BinaryStreamRef Stream, uint32_t &Len,                     codeview::CVRecord<Kind> &Item) { -    using namespace codeview; -    const RecordPrefix *Prefix = nullptr; -    BinaryStreamReader Reader(Stream); -    uint32_t Offset = Reader.getOffset(); - -    if (auto EC = Reader.readObject(Prefix)) -      return EC; -    if (Prefix->RecordLen < 2) -      return make_error<CodeViewError>(cv_error_code::corrupt_record); -    Kind K = static_cast<Kind>(uint16_t(Prefix->RecordKind)); - -    Reader.setOffset(Offset); -    ArrayRef<uint8_t> RawData; -    if (auto EC = -            Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t))) -      return EC; -    Item = codeview::CVRecord<Kind>(K, RawData); -    Len = Item.length(); +    auto ExpectedRec = codeview::readCVRecordFromStream<Kind>(Stream, 0); +    if (!ExpectedRec) +      return ExpectedRec.takeError(); +    Item = *ExpectedRec; +    Len = ExpectedRec->length();      return Error::success();    }  }; diff --git a/include/llvm/DebugInfo/CodeView/CodeView.h b/include/llvm/DebugInfo/CodeView/CodeView.h index b7a7e33abadf..1a4f510c24ab 100644 --- a/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/include/llvm/DebugInfo/CodeView/CodeView.h @@ -124,6 +124,7 @@ enum class CPUType : uint16_t {    ARM_XMAC = 0x66,    ARM_WMMX = 0x67,    ARM7 = 0x68, +  ARM64 = 0x69,    Omni = 0x70,    Ia64 = 0x80,    Ia64_2 = 0x81, @@ -157,7 +158,11 @@ enum SourceLanguage : uint8_t {    Java = 0x0d,    JScript = 0x0e,    MSIL = 0x0f, -  HLSL = 0x10 +  HLSL = 0x10, + +  /// The DMD compiler emits 'D' for the CV source language. Microsoft doesn't +  /// have an enumerator for it yet. +  D = 'D',  };  /// These values correspond to the CV_call_e enumeration, and are documented @@ -500,55 +505,9 @@ enum class FrameCookieKind : uint8_t {  // Corresponds to CV_HREG_e enum.  enum class RegisterId : uint16_t { -  Unknown = 0, -  VFrame = 30006, -  AL = 1, -  CL = 2, -  DL = 3, -  BL = 4, -  AH = 5, -  CH = 6, -  DH = 7, -  BH = 8, -  AX = 9, -  CX = 10, -  DX = 11, -  BX = 12, -  SP = 13, -  BP = 14, -  SI = 15, -  DI = 16, -  EAX = 17, -  ECX = 18, -  EDX = 19, -  EBX = 20, -  ESP = 21, -  EBP = 22, -  ESI = 23, -  EDI = 24, -  ES = 25, -  CS = 26, -  SS = 27, -  DS = 28, -  FS = 29, -  GS = 30, -  IP = 31, -  RAX = 328, -  RBX = 329, -  RCX = 330, -  RDX = 331, -  RSI = 332, -  RDI = 333, -  RBP = 334, -  RSP = 335, -  R8 = 336, -  R9 = 337, -  R10 = 338, -  R11 = 339, -  R12 = 340, -  R13 = 341, -  R14 = 342, -  R15 = 343, +#define CV_REGISTER(name, value) name = value, +#include "CodeViewRegisters.def" +#undef CV_REGISTER  };  /// These values correspond to the THUNK_ORDINAL enumeration. diff --git a/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def b/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def new file mode 100644 index 000000000000..3f0660294866 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def @@ -0,0 +1,268 @@ +//===-- CodeViewRegisters.def - CodeView registers --------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// See CV_HREG_e in cvconst.h. This should match the constants there. +// +//===----------------------------------------------------------------------===// + +#ifndef CV_REGISTER +#define CV_REGISTER(name, value) +#endif + +// This currently only contains the "register subset shraed by all processor +// types" (ERR etc.) and the x86 registers. + +CV_REGISTER(ERR, 30000) +CV_REGISTER(TEB, 30001) +CV_REGISTER(TIMER, 30002) +CV_REGISTER(EFAD1, 30003) +CV_REGISTER(EFAD2, 30004) +CV_REGISTER(EFAD3, 30005) +CV_REGISTER(VFRAME, 30006) +CV_REGISTER(HANDLE, 30007) +CV_REGISTER(PARAMS, 30008) +CV_REGISTER(LOCALS, 30009) +CV_REGISTER(TID, 30010) +CV_REGISTER(ENV, 30011) +CV_REGISTER(CMDLN, 30012) + +CV_REGISTER(NONE, 0) +CV_REGISTER(AL, 1) +CV_REGISTER(CL, 2) +CV_REGISTER(DL, 3) +CV_REGISTER(BL, 4) +CV_REGISTER(AH, 5) +CV_REGISTER(CH, 6) +CV_REGISTER(DH, 7) +CV_REGISTER(BH, 8) +CV_REGISTER(AX, 9) +CV_REGISTER(CX, 10) +CV_REGISTER(DX, 11) +CV_REGISTER(BX, 12) +CV_REGISTER(SP, 13) +CV_REGISTER(BP, 14) +CV_REGISTER(SI, 15) +CV_REGISTER(DI, 16) +CV_REGISTER(EAX, 17) +CV_REGISTER(ECX, 18) +CV_REGISTER(EDX, 19) +CV_REGISTER(EBX, 20) +CV_REGISTER(ESP, 21) +CV_REGISTER(EBP, 22) +CV_REGISTER(ESI, 23) +CV_REGISTER(EDI, 24) +CV_REGISTER(ES, 25) +CV_REGISTER(CS, 26) +CV_REGISTER(SS, 27) +CV_REGISTER(DS, 28) +CV_REGISTER(FS, 29) +CV_REGISTER(GS, 30) +CV_REGISTER(IP, 31) +CV_REGISTER(FLAGS, 32) +CV_REGISTER(EIP, 33) +CV_REGISTER(EFLAGS, 34) +CV_REGISTER(TEMP, 40) +CV_REGISTER(TEMPH, 41) +CV_REGISTER(QUOTE, 42) +CV_REGISTER(PCDR3, 43) +CV_REGISTER(PCDR4, 44) +CV_REGISTER(PCDR5, 45) +CV_REGISTER(PCDR6, 46) +CV_REGISTER(PCDR7, 47) +CV_REGISTER(CR0, 80) +CV_REGISTER(CR1, 81) +CV_REGISTER(CR2, 82) +CV_REGISTER(CR3, 83) +CV_REGISTER(CR4, 84) +CV_REGISTER(DR0, 90) +CV_REGISTER(DR1, 91) +CV_REGISTER(DR2, 92) +CV_REGISTER(DR3, 93) +CV_REGISTER(DR4, 94) +CV_REGISTER(DR5, 95) +CV_REGISTER(DR6, 96) +CV_REGISTER(DR7, 97) +CV_REGISTER(GDTR, 110) +CV_REGISTER(GDTL, 111) +CV_REGISTER(IDTR, 112) +CV_REGISTER(IDTL, 113) +CV_REGISTER(LDTR, 114) +CV_REGISTER(TR, 115) + +CV_REGISTER(PSEUDO1, 116) +CV_REGISTER(PSEUDO2, 117) +CV_REGISTER(PSEUDO3, 118) +CV_REGISTER(PSEUDO4, 119) +CV_REGISTER(PSEUDO5, 120) +CV_REGISTER(PSEUDO6, 121) +CV_REGISTER(PSEUDO7, 122) +CV_REGISTER(PSEUDO8, 123) +CV_REGISTER(PSEUDO9, 124) + +CV_REGISTER(ST0, 128) +CV_REGISTER(ST1, 129) +CV_REGISTER(ST2, 130) +CV_REGISTER(ST3, 131) +CV_REGISTER(ST4, 132) +CV_REGISTER(ST5, 133) +CV_REGISTER(ST6, 134) +CV_REGISTER(ST7, 135) +CV_REGISTER(CTRL, 136) +CV_REGISTER(STAT, 137) +CV_REGISTER(TAG, 138) +CV_REGISTER(FPIP, 139) +CV_REGISTER(FPCS, 140) +CV_REGISTER(FPDO, 141) +CV_REGISTER(FPDS, 142) +CV_REGISTER(ISEM, 143) +CV_REGISTER(FPEIP, 144) +CV_REGISTER(FPEDO, 145) + +CV_REGISTER(MM0, 146) +CV_REGISTER(MM1, 147) +CV_REGISTER(MM2, 148) +CV_REGISTER(MM3, 149) +CV_REGISTER(MM4, 150) +CV_REGISTER(MM5, 151) +CV_REGISTER(MM6, 152) +CV_REGISTER(MM7, 153) + +CV_REGISTER(XMM0, 154) +CV_REGISTER(XMM1, 155) +CV_REGISTER(XMM2, 156) +CV_REGISTER(XMM3, 157) +CV_REGISTER(XMM4, 158) +CV_REGISTER(XMM5, 159) +CV_REGISTER(XMM6, 160) +CV_REGISTER(XMM7, 161) + +CV_REGISTER(MXCSR, 211) + +CV_REGISTER(EDXEAX, 212) + +CV_REGISTER(EMM0L, 220) +CV_REGISTER(EMM1L, 221) +CV_REGISTER(EMM2L, 222) +CV_REGISTER(EMM3L, 223) +CV_REGISTER(EMM4L, 224) +CV_REGISTER(EMM5L, 225) +CV_REGISTER(EMM6L, 226) +CV_REGISTER(EMM7L, 227) + +CV_REGISTER(EMM0H, 228) +CV_REGISTER(EMM1H, 229) +CV_REGISTER(EMM2H, 230) +CV_REGISTER(EMM3H, 231) +CV_REGISTER(EMM4H, 232) +CV_REGISTER(EMM5H, 233) +CV_REGISTER(EMM6H, 234) +CV_REGISTER(EMM7H, 235) + +CV_REGISTER(MM00, 236) +CV_REGISTER(MM01, 237) +CV_REGISTER(MM10, 238) +CV_REGISTER(MM11, 239) +CV_REGISTER(MM20, 240) +CV_REGISTER(MM21, 241) +CV_REGISTER(MM30, 242) +CV_REGISTER(MM31, 243) +CV_REGISTER(MM40, 244) +CV_REGISTER(MM41, 245) +CV_REGISTER(MM50, 246) +CV_REGISTER(MM51, 247) +CV_REGISTER(MM60, 248) +CV_REGISTER(MM61, 249) +CV_REGISTER(MM70, 250) +CV_REGISTER(MM71, 251) + +CV_REGISTER(BND0, 396) +CV_REGISTER(BND1, 397) +CV_REGISTER(BND2, 398) + + +CV_REGISTER(XMM8, 252) +CV_REGISTER(XMM9, 253) +CV_REGISTER(XMM10, 254) +CV_REGISTER(XMM11, 255) +CV_REGISTER(XMM12, 256) +CV_REGISTER(XMM13, 257) +CV_REGISTER(XMM14, 258) +CV_REGISTER(XMM15, 259) + + +CV_REGISTER(SIL, 324) +CV_REGISTER(DIL, 325) +CV_REGISTER(BPL, 326) +CV_REGISTER(SPL, 327) + +CV_REGISTER(RAX, 328) +CV_REGISTER(RBX, 329) +CV_REGISTER(RCX, 330) +CV_REGISTER(RDX, 331) +CV_REGISTER(RSI, 332) +CV_REGISTER(RDI, 333) +CV_REGISTER(RBP, 334) +CV_REGISTER(RSP, 335) + +CV_REGISTER(R8, 336) +CV_REGISTER(R9, 337) +CV_REGISTER(R10, 338) +CV_REGISTER(R11, 339) +CV_REGISTER(R12, 340) +CV_REGISTER(R13, 341) +CV_REGISTER(R14, 342) +CV_REGISTER(R15, 343) + +CV_REGISTER(R8B, 344) +CV_REGISTER(R9B, 345) +CV_REGISTER(R10B, 346) +CV_REGISTER(R11B, 347) +CV_REGISTER(R12B, 348) +CV_REGISTER(R13B, 349) +CV_REGISTER(R14B, 350) +CV_REGISTER(R15B, 351) + +CV_REGISTER(R8W, 352) +CV_REGISTER(R9W, 353) +CV_REGISTER(R10W, 354) +CV_REGISTER(R11W, 355) +CV_REGISTER(R12W, 356) +CV_REGISTER(R13W, 357) +CV_REGISTER(R14W, 358) +CV_REGISTER(R15W, 359) + +CV_REGISTER(R8D, 360) +CV_REGISTER(R9D, 361) +CV_REGISTER(R10D, 362) +CV_REGISTER(R11D, 363) +CV_REGISTER(R12D, 364) +CV_REGISTER(R13D, 365) +CV_REGISTER(R14D, 366) +CV_REGISTER(R15D, 367) + + +// cvconst.h defines both CV_REG_YMM0 (252) and CV_AMD64_YMM0 (368). Keep the +// original prefix to distinguish them. + +CV_REGISTER(AMD64_YMM0, 368) +CV_REGISTER(AMD64_YMM1, 369) +CV_REGISTER(AMD64_YMM2, 370) +CV_REGISTER(AMD64_YMM3, 371) +CV_REGISTER(AMD64_YMM4, 372) +CV_REGISTER(AMD64_YMM5, 373) +CV_REGISTER(AMD64_YMM6, 374) +CV_REGISTER(AMD64_YMM7, 375) +CV_REGISTER(AMD64_YMM8, 376) +CV_REGISTER(AMD64_YMM9, 377) +CV_REGISTER(AMD64_YMM10, 378) +CV_REGISTER(AMD64_YMM11, 379) +CV_REGISTER(AMD64_YMM12, 380) +CV_REGISTER(AMD64_YMM13, 381) +CV_REGISTER(AMD64_YMM14, 382) +CV_REGISTER(AMD64_YMM15, 383) diff --git a/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def b/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def index 32813d861d90..41c538076798 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def +++ b/include/llvm/DebugInfo/CodeView/CodeViewSymbols.def @@ -1,4 +1,4 @@ -//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +//===-- CodeViewSymbols.def - All CodeView leaf types -----------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -184,6 +184,9 @@ CV_SYMBOL(S_LDATA_HLSL32   , 0x1163)  CV_SYMBOL(S_GDATA_HLSL32_EX, 0x1164)  CV_SYMBOL(S_LDATA_HLSL32_EX, 0x1165) +CV_SYMBOL(S_FASTLINK, 0x1167) // Undocumented +SYMBOL_RECORD_ALIAS(S_INLINEES, 0x1168, InlineesSym, CallerSym) // Undocumented +  // Known symbol types  SYMBOL_RECORD(S_END                  , 0x0006, ScopeEndSym)  SYMBOL_RECORD_ALIAS(S_INLINESITE_END , 0x114e, InlineSiteEnd, ScopeEndSym) @@ -232,7 +235,7 @@ SYMBOL_RECORD(S_HEAPALLOCSITE  , 0x115e, HeapAllocationSiteSym)  SYMBOL_RECORD(S_FRAMECOOKIE   , 0x113a, FrameCookieSym)  SYMBOL_RECORD(S_CALLEES        , 0x115a, CallerSym) -SYMBOL_RECORD_ALIAS(S_CALLERS        , 0x115b, CalleeSym, CallerSym) +SYMBOL_RECORD_ALIAS(S_CALLERS, 0x115b, CalleeSym, CallerSym)  SYMBOL_RECORD(S_UDT           , 0x1108, UDTSym)  SYMBOL_RECORD_ALIAS(S_COBOLUDT      , 0x1109, CobolUDT, UDTSym) diff --git a/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/include/llvm/DebugInfo/CodeView/CodeViewTypes.def index 8c193bb13cb7..69ce9606a670 100644 --- a/include/llvm/DebugInfo/CodeView/CodeViewTypes.def +++ b/include/llvm/DebugInfo/CodeView/CodeViewTypes.def @@ -1,5 +1,4 @@ - -//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===// +//===-- CodeViewTypes.def - All CodeView leaf types -------------*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // diff --git a/include/llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h b/include/llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h new file mode 100644 index 000000000000..7f851a2595dc --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h @@ -0,0 +1,65 @@ +//===- ContinuationRecordBuilder.h ------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_CONTINUATIONRECORDBUILDER_H +#define LLVM_DEBUGINFO_CODEVIEW_CONTINUATIONRECORDBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { +enum class ContinuationRecordKind { FieldList, MethodOverloadList }; + +class ContinuationRecordBuilder { +  SmallVector<uint32_t, 4> SegmentOffsets; +  Optional<ContinuationRecordKind> Kind; +  AppendingBinaryByteStream Buffer; +  BinaryStreamWriter SegmentWriter; +  TypeRecordMapping Mapping; +  ArrayRef<uint8_t> InjectedSegmentBytes; + +  uint32_t getCurrentSegmentLength() const; + +  void insertSegmentEnd(uint32_t Offset); +  CVType createSegmentRecord(uint32_t OffBegin, uint32_t OffEnd, +                             Optional<TypeIndex> RefersTo); + +public: +  ContinuationRecordBuilder(); +  ~ContinuationRecordBuilder(); + +  void begin(ContinuationRecordKind RecordKind); + +  // This template is explicitly instantiated in the implementation file for all +  // supported types.  The method itself is ugly, so inlining it into the header +  // file clutters an otherwise straightforward interface. +  template <typename RecordType> void writeMemberType(RecordType &Record); + +  std::vector<CVType> end(TypeIndex Index); +}; +} // namespace codeview +} // namespace llvm + +#endif
\ No newline at end of file diff --git a/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h new file mode 100644 index 000000000000..d8ac3343c15f --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h @@ -0,0 +1,87 @@ +//===- GlobalTypeTableBuilder.h ----------------------------------*- C++-*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_GLOBALTYPETABLEBUILDER_H +#define LLVM_DEBUGINFO_CODEVIEW_GLOBALTYPETABLEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeHashing.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { + +class ContinuationRecordBuilder; + +class GlobalTypeTableBuilder : public TypeCollection { +  /// Storage for records.  These need to outlive the TypeTableBuilder. +  BumpPtrAllocator &RecordStorage; + +  /// A serializer that can write non-continuation leaf types.  Only used as +  /// a convenience function so that we can provide an interface method to +  /// write an unserialized record. +  SimpleTypeSerializer SimpleSerializer; + +  /// Hash table. +  DenseMap<GloballyHashedType, TypeIndex> HashedRecords; + +  /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). +  SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; + +  /// Contains a list of all hash values inexed by TypeIndex.toArrayIndex(). +  SmallVector<GloballyHashedType, 2> SeenHashes; + +public: +  explicit GlobalTypeTableBuilder(BumpPtrAllocator &Storage); +  ~GlobalTypeTableBuilder(); + +  // TypeTableCollection overrides +  Optional<TypeIndex> getFirst() override; +  Optional<TypeIndex> getNext(TypeIndex Prev) override; +  CVType getType(TypeIndex Index) override; +  StringRef getTypeName(TypeIndex Index) override; +  bool contains(TypeIndex Index) override; +  uint32_t size() override; +  uint32_t capacity() override; + +  // public interface +  void reset(); +  TypeIndex nextTypeIndex() const; + +  BumpPtrAllocator &getAllocator() { return RecordStorage; } + +  ArrayRef<ArrayRef<uint8_t>> records() const; +  ArrayRef<GloballyHashedType> hashes() const; + +  using CreateRecord = llvm::function_ref<ArrayRef<uint8_t>()>; + +  TypeIndex insertRecordAs(GloballyHashedType Hash, CreateRecord Create); +  TypeIndex insertRecordBytes(ArrayRef<uint8_t> Data); +  TypeIndex insertRecord(ContinuationRecordBuilder &Builder); + +  template <typename T> TypeIndex writeLeafType(T &Record) { +    ArrayRef<uint8_t> Data = SimpleSerializer.serialize(Record); +    return insertRecordBytes(Data); +  } +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MERGINGTYPETABLEBUILDER_H diff --git a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h index cc0c24301d49..16d78692c839 100644 --- a/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h +++ b/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -67,9 +67,12 @@ public:    void reset(ArrayRef<uint8_t> Data, uint32_t RecordCountHint);    void reset(StringRef Data, uint32_t RecordCountHint); +  void reset(BinaryStreamReader &Reader, uint32_t RecordCountHint);    uint32_t getOffsetOfType(TypeIndex Index); +  Optional<CVType> tryGetType(TypeIndex Index); +    CVType getType(TypeIndex Index) override;    StringRef getTypeName(TypeIndex Index) override;    bool contains(TypeIndex Index) override; diff --git a/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h new file mode 100644 index 000000000000..9030918ebbb3 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h @@ -0,0 +1,81 @@ +//===- MergingTypeTableBuilder.h ---------------------------------*- C++-*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_MERGINGTYPETABLEBUILDER_H +#define LLVM_DEBUGINFO_CODEVIEW_MERGINGTYPETABLEBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeHashing.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { + +class ContinuationRecordBuilder; + +class MergingTypeTableBuilder : public TypeCollection { +  /// Storage for records.  These need to outlive the TypeTableBuilder. +  BumpPtrAllocator &RecordStorage; + +  /// A serializer that can write non-continuation leaf types.  Only used as +  /// a convenience function so that we can provide an interface method to +  /// write an unserialized record. +  SimpleTypeSerializer SimpleSerializer; + +  /// Hash table. +  DenseMap<LocallyHashedType, TypeIndex> HashedRecords; + +  /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). +  SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; + +public: +  explicit MergingTypeTableBuilder(BumpPtrAllocator &Storage); +  ~MergingTypeTableBuilder(); + +  // TypeTableCollection overrides +  Optional<TypeIndex> getFirst() override; +  Optional<TypeIndex> getNext(TypeIndex Prev) override; +  CVType getType(TypeIndex Index) override; +  StringRef getTypeName(TypeIndex Index) override; +  bool contains(TypeIndex Index) override; +  uint32_t size() override; +  uint32_t capacity() override; + +  // public interface +  void reset(); +  TypeIndex nextTypeIndex() const; + +  BumpPtrAllocator &getAllocator() { return RecordStorage; } + +  ArrayRef<ArrayRef<uint8_t>> records() const; + +  TypeIndex insertRecordAs(hash_code Hash, ArrayRef<uint8_t> &Record); +  TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record); +  TypeIndex insertRecord(ContinuationRecordBuilder &Builder); + +  template <typename T> TypeIndex writeLeafType(T &Record) { +    ArrayRef<uint8_t> Data = SimpleSerializer.serialize(Record); +    return insertRecordBytes(Data); +  } +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_MERGINGTYPETABLEBUILDER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeName.h b/include/llvm/DebugInfo/CodeView/RecordName.h index a987b4afd283..b022108df3d6 100644 --- a/include/llvm/DebugInfo/CodeView/TypeName.h +++ b/include/llvm/DebugInfo/CodeView/RecordName.h @@ -1,4 +1,4 @@ -//===- TypeName.h --------------------------------------------- *- C++ --*-===// +//===- RecordName.h ------------------------------------------- *- C++ --*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -7,16 +7,18 @@  //  //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H +#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDNAME_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDNAME_H +#include "llvm/DebugInfo/CodeView/SymbolRecord.h"  #include "llvm/DebugInfo/CodeView/TypeCollection.h"  #include "llvm/DebugInfo/CodeView/TypeIndex.h"  namespace llvm {  namespace codeview {  std::string computeTypeName(TypeCollection &Types, TypeIndex Index); -} +StringRef getSymbolName(CVSymbol Sym); +} // namespace codeview  } // namespace llvm  #endif diff --git a/include/llvm/DebugInfo/CodeView/SimpleTypeSerializer.h b/include/llvm/DebugInfo/CodeView/SimpleTypeSerializer.h new file mode 100644 index 000000000000..a85d9270186b --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/SimpleTypeSerializer.h @@ -0,0 +1,53 @@ +//===- SimpleTypeSerializer.h -----------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_SIMPLETYPESERIALIZER_H +#define LLVM_DEBUGINFO_CODEVIEW_SIMPLETYPESERIALIZER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +namespace llvm { +namespace codeview { + +class SimpleTypeSerializer { +  std::vector<uint8_t> ScratchBuffer; + +public: +  SimpleTypeSerializer(); +  ~SimpleTypeSerializer(); + +  // This template is explicitly instantiated in the implementation file for all +  // supported types.  The method itself is ugly, so inlining it into the header +  // file clutters an otherwise straightforward interface. +  template <typename T> ArrayRef<uint8_t> serialize(T &Record); + +  // Don't allow serialization of field list records using this interface. +  ArrayRef<uint8_t> serialize(const FieldListRecord &Record) = delete; +}; + +} // end namespace codeview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_SIMPLETYPESERIALIZER_H diff --git a/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h b/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h index 1a8388224665..22a333e631a0 100644 --- a/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h +++ b/include/llvm/DebugInfo/CodeView/StringsAndChecksums.h @@ -31,8 +31,13 @@ public:    StringsAndChecksumsRef(const DebugStringTableSubsectionRef &Strings,                           const DebugChecksumsSubsectionRef &Checksums); +  void setStrings(const DebugStringTableSubsectionRef &Strings);    void setChecksums(const DebugChecksumsSubsectionRef &CS); +  void reset(); +  void resetStrings(); +  void resetChecksums(); +    template <typename T> void initialize(T &&FragmentRange) {      for (const DebugSubsectionRecord &R : FragmentRange) {        if (Strings && Checksums) @@ -67,8 +72,8 @@ private:    void initializeStrings(const DebugSubsectionRecord &SR);    void initializeChecksums(const DebugSubsectionRecord &FCR); -  std::unique_ptr<DebugStringTableSubsectionRef> OwnedStrings; -  std::unique_ptr<DebugChecksumsSubsectionRef> OwnedChecksums; +  std::shared_ptr<DebugStringTableSubsectionRef> OwnedStrings; +  std::shared_ptr<DebugChecksumsSubsectionRef> OwnedChecksums;    const DebugStringTableSubsectionRef *Strings = nullptr;    const DebugChecksumsSubsectionRef *Checksums = nullptr; diff --git a/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h b/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h index 5b6599d8c1db..b5479db97a15 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ b/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h @@ -46,6 +46,12 @@ public:        return EC;      return Error::success();    } +  template <typename T> static Expected<T> deserializeAs(CVSymbol Symbol) { +    T Record(Symbol.kind()); +    if (auto EC = deserializeAs<T>(Symbol, Record)) +      return std::move(EC); +    return Record; +  }    explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate,                                CodeViewContainer Container) diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h index f3086cf3dbb9..cf267f23967b 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -363,12 +363,12 @@ public:        : SymbolRecord(SymbolRecordKind::PublicSym32),          RecordOffset(RecordOffset) {} -  PublicSymFlags Flags; -  uint32_t Offset; -  uint16_t Segment; +  PublicSymFlags Flags = PublicSymFlags::None; +  uint32_t Offset = 0; +  uint16_t Segment = 0;    StringRef Name; -  uint32_t RecordOffset; +  uint32_t RecordOffset = 0;  };  // S_REGISTER @@ -942,9 +942,14 @@ public:    uint32_t RecordOffset;  }; +// S_ANNOTATION +  using CVSymbol = CVRecord<SymbolKind>;  using CVSymbolArray = VarStreamArray<CVSymbol>; +Expected<CVSymbol> readSymbolFromStream(BinaryStreamRef Stream, +                                        uint32_t Offset); +  } // end namespace codeview  } // end namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/SymbolSerializer.h b/include/llvm/DebugInfo/CodeView/SymbolSerializer.h index b63ced5217b4..f4d8ab0c3c2e 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolSerializer.h +++ b/include/llvm/DebugInfo/CodeView/SymbolSerializer.h @@ -28,7 +28,10 @@ namespace codeview {  class SymbolSerializer : public SymbolVisitorCallbacks {    BumpPtrAllocator &Storage; -  std::vector<uint8_t> RecordBuffer; +  // Since this is a fixed size buffer, use a stack allocated buffer.  This +  // yields measurable performance increase over the repeated heap allocations +  // when serializing many independent records via writeOneSymbol. +  std::array<uint8_t, MaxRecordLength> RecordBuffer;    MutableBinaryByteStream Stream;    BinaryStreamWriter Writer;    SymbolRecordMapping Mapping; diff --git a/include/llvm/DebugInfo/CodeView/TypeCollection.h b/include/llvm/DebugInfo/CodeView/TypeCollection.h index 0f856f57a727..e9fc9b0de8ef 100644 --- a/include/llvm/DebugInfo/CodeView/TypeCollection.h +++ b/include/llvm/DebugInfo/CodeView/TypeCollection.h @@ -31,6 +31,16 @@ public:    virtual bool contains(TypeIndex Index) = 0;    virtual uint32_t size() = 0;    virtual uint32_t capacity() = 0; + +  template <typename TFunc> void ForEachRecord(TFunc Func) { +    Optional<TypeIndex> Next = getFirst(); + +    while (Next.hasValue()) { +      TypeIndex N = *Next; +      Func(N, getType(N)); +      Next = getNext(N); +    } +  }  };  }  } diff --git a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h index 965cdfd85f48..9887d901773a 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ b/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -52,6 +52,19 @@ public:      return Error::success();    } +  template <typename T> +  static Expected<T> deserializeAs(ArrayRef<uint8_t> Data) { +    const RecordPrefix *Prefix = +        reinterpret_cast<const RecordPrefix *>(Data.data()); +    TypeRecordKind K = +        static_cast<TypeRecordKind>(uint16_t(Prefix->RecordKind)); +    T Record(K); +    CVType CVT(static_cast<TypeLeafKind>(K), Data); +    if (auto EC = deserializeAs<T>(CVT, Record)) +      return std::move(EC); +    return Record; +  } +    Error visitTypeBegin(CVType &Record) override {      assert(!Mapping && "Already in a type mapping!");      Mapping = llvm::make_unique<MappingInfo>(Record.content()); diff --git a/include/llvm/DebugInfo/CodeView/TypeHashing.h b/include/llvm/DebugInfo/CodeView/TypeHashing.h new file mode 100644 index 000000000000..741337533701 --- /dev/null +++ b/include/llvm/DebugInfo/CodeView/TypeHashing.h @@ -0,0 +1,204 @@ +//===- TypeHashing.h ---------------------------------------------*- C++-*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEHASHING_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/Hashing.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +#include "llvm/Support/FormatProviders.h" + +#include <type_traits> + +namespace llvm { +namespace codeview { + +/// A locally hashed type represents a straightforward hash code of a serialized +/// record.  The record is simply serialized, and then the bytes are hashed by +/// a standard algorithm.  This is sufficient for the case of de-duplicating +/// records within a single sequence of types, because if two records both have +/// a back-reference to the same type in the same stream, they will both have +/// the same numeric value for the TypeIndex of the back reference. +struct LocallyHashedType { +  hash_code Hash; +  ArrayRef<uint8_t> RecordData; + +  /// Given a type, compute its local hash. +  static LocallyHashedType hashType(ArrayRef<uint8_t> RecordData); + +  /// Given a sequence of types, compute all of the local hashes. +  template <typename Range> +  static std::vector<LocallyHashedType> hashTypes(Range &&Records) { +    std::vector<LocallyHashedType> Hashes; +    Hashes.reserve(std::distance(std::begin(Records), std::end(Records))); +    for (const auto &R : Records) +      Hashes.push_back(hashType(R)); + +    return Hashes; +  } + +  static std::vector<LocallyHashedType> +  hashTypeCollection(TypeCollection &Types) { +    std::vector<LocallyHashedType> Hashes; +    Types.ForEachRecord([&Hashes](TypeIndex TI, const CVType &Type) { +      Hashes.push_back(hashType(Type.RecordData)); +    }); +    return Hashes; +  } +}; + +enum class GlobalTypeHashAlg : uint16_t { SHA1 = 0 }; + +/// A globally hashed type represents a hash value that is sufficient to +/// uniquely identify a record across multiple type streams or type sequences. +/// This works by, for any given record A which references B, replacing the +/// TypeIndex that refers to B with a previously-computed global hash for B.  As +/// this is a recursive algorithm (e.g. the global hash of B also depends on the +/// global hashes of the types that B refers to), a global hash can uniquely +/// identify identify that A occurs in another stream that has a completely +/// different graph structure.  Although the hash itself is slower to compute, +/// probing is much faster with a globally hashed type, because the hash itself +/// is considered "as good as" the original type.  Since type records can be +/// quite large, this makes the equality comparison of the hash much faster than +/// equality comparison of a full record. +struct GloballyHashedType { +  GloballyHashedType() = default; +  GloballyHashedType(StringRef H) +      : GloballyHashedType(ArrayRef<uint8_t>(H.bytes_begin(), H.bytes_end())) {} +  GloballyHashedType(ArrayRef<uint8_t> H) { +    assert(H.size() == 20); +    ::memcpy(Hash.data(), H.data(), 20); +  } +  std::array<uint8_t, 20> Hash; + +  /// Given a sequence of bytes representing a record, compute a global hash for +  /// this record.  Due to the nature of global hashes incorporating the hashes +  /// of referenced records, this function requires a list of types and ids +  /// that RecordData might reference, indexable by TypeIndex. +  static GloballyHashedType hashType(ArrayRef<uint8_t> RecordData, +                                     ArrayRef<GloballyHashedType> PreviousTypes, +                                     ArrayRef<GloballyHashedType> PreviousIds); + +  /// Given a sequence of bytes representing a record, compute a global hash for +  /// this record.  Due to the nature of global hashes incorporating the hashes +  /// of referenced records, this function requires a list of types and ids +  /// that RecordData might reference, indexable by TypeIndex. +  static GloballyHashedType hashType(CVType Type, +                                     ArrayRef<GloballyHashedType> PreviousTypes, +                                     ArrayRef<GloballyHashedType> PreviousIds) { +    return hashType(Type.RecordData, PreviousTypes, PreviousIds); +  } + +  /// Given a sequence of combined type and ID records, compute global hashes +  /// for each of them, returning the results in a vector of hashed types. +  template <typename Range> +  static std::vector<GloballyHashedType> hashTypes(Range &&Records) { +    std::vector<GloballyHashedType> Hashes; +    for (const auto &R : Records) +      Hashes.push_back(hashType(R, Hashes, Hashes)); + +    return Hashes; +  } + +  /// Given a sequence of combined type and ID records, compute global hashes +  /// for each of them, returning the results in a vector of hashed types. +  template <typename Range> +  static std::vector<GloballyHashedType> +  hashIds(Range &&Records, ArrayRef<GloballyHashedType> TypeHashes) { +    std::vector<GloballyHashedType> IdHashes; +    for (const auto &R : Records) +      IdHashes.push_back(hashType(R, TypeHashes, IdHashes)); + +    return IdHashes; +  } + +  static std::vector<GloballyHashedType> +  hashTypeCollection(TypeCollection &Types) { +    std::vector<GloballyHashedType> Hashes; +    Types.ForEachRecord([&Hashes](TypeIndex TI, const CVType &Type) { +      Hashes.push_back(hashType(Type.RecordData, Hashes, Hashes)); +    }); +    return Hashes; +  } +}; +#if defined(_MSC_VER) +// is_trivially_copyable is not available in older versions of libc++, but it is +// available in all supported versions of MSVC, so at least this gives us some +// coverage. +static_assert(std::is_trivially_copyable<GloballyHashedType>::value, +              "GloballyHashedType must be trivially copyable so that we can " +              "reinterpret_cast arrays of hash data to arrays of " +              "GloballyHashedType"); +#endif +} // namespace codeview + +template <> struct DenseMapInfo<codeview::LocallyHashedType> { +  static codeview::LocallyHashedType Empty; +  static codeview::LocallyHashedType Tombstone; + +  static codeview::LocallyHashedType getEmptyKey() { return Empty; } + +  static codeview::LocallyHashedType getTombstoneKey() { return Tombstone; } + +  static unsigned getHashValue(codeview::LocallyHashedType Val) { +    return Val.Hash; +  } + +  static bool isEqual(codeview::LocallyHashedType LHS, +                      codeview::LocallyHashedType RHS) { +    if (LHS.Hash != RHS.Hash) +      return false; +    return LHS.RecordData == RHS.RecordData; +  } +}; + +template <> struct DenseMapInfo<codeview::GloballyHashedType> { +  static codeview::GloballyHashedType Empty; +  static codeview::GloballyHashedType Tombstone; + +  static codeview::GloballyHashedType getEmptyKey() { return Empty; } + +  static codeview::GloballyHashedType getTombstoneKey() { return Tombstone; } + +  static unsigned getHashValue(codeview::GloballyHashedType Val) { +    return *reinterpret_cast<const unsigned *>(Val.Hash.data()); +  } + +  static bool isEqual(codeview::GloballyHashedType LHS, +                      codeview::GloballyHashedType RHS) { +    return LHS.Hash == RHS.Hash; +  } +}; + +template <> struct format_provider<codeview::LocallyHashedType> { +public: +  static void format(const codeview::LocallyHashedType &V, +                     llvm::raw_ostream &Stream, StringRef Style) { +    write_hex(Stream, V.Hash, HexPrintStyle::Upper, 8); +  } +}; + +template <> struct format_provider<codeview::GloballyHashedType> { +public: +  static void format(const codeview::GloballyHashedType &V, +                     llvm::raw_ostream &Stream, StringRef Style) { +    for (uint8_t B : V.Hash) { +      write_hex(Stream, B, HexPrintStyle::Upper, 2); +    } +  } +}; + +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/CodeView/TypeIndex.h b/include/llvm/DebugInfo/CodeView/TypeIndex.h index e0c2226bdbd7..c71281de7145 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndex.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndex.h @@ -98,6 +98,7 @@ public:    static const uint32_t FirstNonSimpleIndex = 0x1000;    static const uint32_t SimpleKindMask = 0x000000ff;    static const uint32_t SimpleModeMask = 0x00000700; +  static const uint32_t DecoratedItemIdMask = 0x80000000;  public:    TypeIndex() : Index(static_cast<uint32_t>(SimpleTypeKind::None)) {} @@ -110,6 +111,7 @@ public:    uint32_t getIndex() const { return Index; }    void setIndex(uint32_t I) { Index = I; }    bool isSimple() const { return Index < FirstNonSimpleIndex; } +  bool isDecoratedItemId() const { return !!(Index & DecoratedItemIdMask); }    bool isNoneType() const { return *this == None(); } diff --git a/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h b/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h index afe8942159e8..c424a09ece89 100644 --- a/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h +++ b/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h @@ -30,11 +30,17 @@ void discoverTypeIndices(const CVType &Type,                           SmallVectorImpl<TiReference> &Refs);  void discoverTypeIndices(const CVType &Type,                           SmallVectorImpl<TypeIndex> &Indices); +void discoverTypeIndices(ArrayRef<uint8_t> RecordData, +                         SmallVectorImpl<TypeIndex> &Indices);  /// Discover type indices in symbol records. Returns false if this is an unknown  /// record. -bool discoverTypeIndices(const CVSymbol &Symbol, -                         SmallVectorImpl<TiReference> &Refs); +bool discoverTypeIndicesInSymbol(const CVSymbol &Symbol, +                                 SmallVectorImpl<TiReference> &Refs); +bool discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData, +                                 SmallVectorImpl<TiReference> &Refs); +bool discoverTypeIndicesInSymbol(ArrayRef<uint8_t> RecordData, +                                 SmallVectorImpl<TypeIndex> &Indices);  }  } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecord.h b/include/llvm/DebugInfo/CodeView/TypeRecord.h index 7942c0c0bc21..508bdd395f74 100644 --- a/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -334,6 +334,11 @@ public:    uint32_t Attrs;    Optional<MemberPointerInfo> MemberInfo; +  void setAttrs(PointerKind PK, PointerMode PM, PointerOptions PO, +                uint8_t Size) { +    Attrs = calcAttrs(PK, PM, PO, Size); +  } +  private:    static uint32_t calcAttrs(PointerKind PK, PointerMode PM, PointerOptions PO,                              uint8_t Size) { @@ -412,6 +417,14 @@ public:      return (Options & ClassOptions::HasUniqueName) != ClassOptions::None;    } +  bool isNested() const { +    return (Options & ClassOptions::Nested) != ClassOptions::None; +  } + +  bool isForwardRef() const { +    return (Options & ClassOptions::ForwardReference) != ClassOptions::None; +  } +    uint16_t getMemberCount() const { return MemberCount; }    ClassOptions getOptions() const { return Options; }    TypeIndex getFieldList() const { return FieldList; } diff --git a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h b/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h deleted file mode 100644 index 5a6507ee7f5b..000000000000 --- a/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ /dev/null @@ -1,78 +0,0 @@ -//===- TypeRecordBuilder.h --------------------------------------*- C++ -*-===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/EndianStream.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { -namespace codeview { - -class TypeRecordBuilder { -private: -  TypeRecordBuilder(const TypeRecordBuilder &) = delete; -  TypeRecordBuilder &operator=(const TypeRecordBuilder &) = delete; - -public: -  explicit TypeRecordBuilder(TypeRecordKind Kind); - -  void writeUInt8(uint8_t Value); -  void writeInt16(int16_t Value); -  void writeUInt16(uint16_t Value); -  void writeInt32(int32_t Value); -  void writeUInt32(uint32_t Value); -  void writeInt64(int64_t Value); -  void writeUInt64(uint64_t Value); -  void writeTypeIndex(TypeIndex TypeInd); -  void writeTypeRecordKind(TypeRecordKind Kind); -  void writeEncodedInteger(int64_t Value); -  void writeEncodedSignedInteger(int64_t Value); -  void writeEncodedUnsignedInteger(uint64_t Value); -  void writeNullTerminatedString(StringRef Value); -  void writeGuid(StringRef Guid); -  void writeBytes(StringRef Value) { Stream << Value; } - -  llvm::StringRef str(); - -  uint64_t size() const { return Stream.tell(); } -  TypeRecordKind kind() const { return Kind; } - -  /// Returns the number of bytes remaining before this record is larger than -  /// the maximum record length. Accounts for the extra two byte size field in -  /// the header. -  size_t maxBytesRemaining() const { return MaxRecordLength - size() - 2; } - -  void truncate(uint64_t Size) { -    // This works because raw_svector_ostream is not buffered. -    assert(Size < Buffer.size()); -    Buffer.resize(Size); -  } - -  void reset(TypeRecordKind K) { -    Buffer.clear(); -    Kind = K; -    writeTypeRecordKind(K); -  } - -private: -  TypeRecordKind Kind; -  llvm::SmallVector<char, 256> Buffer; -  llvm::raw_svector_ostream Stream; -  llvm::support::endian::Writer<llvm::support::endianness::little> Writer; -}; -} -} - -#endif diff --git a/include/llvm/DebugInfo/CodeView/TypeSerializer.h b/include/llvm/DebugInfo/CodeView/TypeSerializer.h deleted file mode 100644 index 0e734a8170bd..000000000000 --- a/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ /dev/null @@ -1,159 +0,0 @@ -//===- TypeSerializer.h -----------------------------------------*- C++ -*-===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include <cassert> -#include <cstdint> -#include <memory> -#include <vector> - -namespace llvm { -namespace codeview { - -class TypeHasher; - -class TypeSerializer : public TypeVisitorCallbacks { -  struct SubRecord { -    SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {} - -    TypeLeafKind Kind; -    uint32_t Size = 0; -  }; -  struct RecordSegment { -    SmallVector<SubRecord, 16> SubRecords; - -    uint32_t length() const { -      uint32_t L = sizeof(RecordPrefix); -      for (const auto &R : SubRecords) { -        L += R.Size; -      } -      return L; -    } -  }; - -  using MutableRecordList = SmallVector<MutableArrayRef<uint8_t>, 2>; - -  static constexpr uint8_t ContinuationLength = 8; -  BumpPtrAllocator &RecordStorage; -  RecordSegment CurrentSegment; -  MutableRecordList FieldListSegments; - -  Optional<TypeLeafKind> TypeKind; -  Optional<TypeLeafKind> MemberKind; -  std::vector<uint8_t> RecordBuffer; -  MutableBinaryByteStream Stream; -  BinaryStreamWriter Writer; -  TypeRecordMapping Mapping; - -  /// Private type record hashing implementation details are handled here. -  std::unique_ptr<TypeHasher> Hasher; - -  /// Contains a list of all records indexed by TypeIndex.toArrayIndex(). -  SmallVector<ArrayRef<uint8_t>, 2> SeenRecords; - -  /// Temporary storage that we use to copy a record's data while re-writing -  /// its type indices. -  SmallVector<uint8_t, 256> RemapStorage; - -  TypeIndex nextTypeIndex() const; - -  bool isInFieldList() const; -  MutableArrayRef<uint8_t> getCurrentSubRecordData(); -  MutableArrayRef<uint8_t> getCurrentRecordData(); -  Error writeRecordPrefix(TypeLeafKind Kind); - -  Expected<MutableArrayRef<uint8_t>> -  addPadding(MutableArrayRef<uint8_t> Record); - -public: -  explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true); -  ~TypeSerializer() override; - -  void reset(); - -  BumpPtrAllocator &getAllocator() { return RecordStorage; } - -  ArrayRef<ArrayRef<uint8_t>> records() const; -  TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record); -  TypeIndex insertRecord(const RemappedType &Record); -  Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record); - -  using TypeVisitorCallbacks::visitTypeBegin; -  Error visitTypeBegin(CVType &Record) override; -  Error visitTypeEnd(CVType &Record) override; -  Error visitMemberBegin(CVMemberRecord &Record) override; -  Error visitMemberEnd(CVMemberRecord &Record) override; - -#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \ -  virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \ -    return visitKnownRecordImpl(CVR, Record);                                  \ -  } -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \ -  Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \ -    return visitKnownMemberImpl<Name##Record>(CVR, Record);                    \ -  } -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - -private: -  template <typename RecordKind> -  Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) { -    return Mapping.visitKnownRecord(CVR, Record); -  } - -  template <typename RecordType> -  Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) { -    assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind())); - -    if (auto EC = Writer.writeEnum(CVR.Kind)) -      return EC; - -    if (auto EC = Mapping.visitKnownMember(CVR, Record)) -      return EC; - -    // Get all the data that was just written and is yet to be committed to -    // the current segment.  Then pad it to 4 bytes. -    MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData(); -    auto ExpectedRecord = addPadding(ThisRecord); -    if (!ExpectedRecord) -      return ExpectedRecord.takeError(); -    ThisRecord = *ExpectedRecord; - -    CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size()); -    CVR.Data = ThisRecord; - -    // Both the last subrecord and the total length of this segment should be -    // multiples of 4. -    assert(ThisRecord.size() % 4 == 0); -    assert(CurrentSegment.length() % 4 == 0); - -    return Error::success(); -  } -}; - -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H diff --git a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h index d78fab47db66..59e216abcb11 100644 --- a/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h +++ b/include/llvm/DebugInfo/CodeView/TypeStreamMerger.h @@ -19,7 +19,9 @@ namespace llvm {  namespace codeview {  class TypeIndex; -class TypeTableBuilder; +struct GloballyHashedType; +class GlobalTypeTableBuilder; +class MergingTypeTableBuilder;  /// \brief Merge one set of type records into another.  This method assumes  /// that all records are type records, and there are no Id records present. @@ -34,7 +36,7 @@ class TypeTableBuilder;  ///  /// \returns Error::success() if the operation succeeded, otherwise an  /// appropriate error code. -Error mergeTypeRecords(TypeTableBuilder &Dest, +Error mergeTypeRecords(MergingTypeTableBuilder &Dest,                         SmallVectorImpl<TypeIndex> &SourceToDest,                         const CVTypeArray &Types); @@ -59,7 +61,7 @@ Error mergeTypeRecords(TypeTableBuilder &Dest,  ///  /// \returns Error::success() if the operation succeeded, otherwise an  /// appropriate error code. -Error mergeIdRecords(TypeTableBuilder &Dest, ArrayRef<TypeIndex> Types, +Error mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types,                       SmallVectorImpl<TypeIndex> &SourceToDest,                       const CVTypeArray &Ids); @@ -78,11 +80,27 @@ Error mergeIdRecords(TypeTableBuilder &Dest, ArrayRef<TypeIndex> Types,  ///  /// \returns Error::success() if the operation succeeded, otherwise an  /// appropriate error code. -Error mergeTypeAndIdRecords(TypeTableBuilder &DestIds, -                            TypeTableBuilder &DestTypes, +Error mergeTypeAndIdRecords(MergingTypeTableBuilder &DestIds, +                            MergingTypeTableBuilder &DestTypes,                              SmallVectorImpl<TypeIndex> &SourceToDest,                              const CVTypeArray &IdsAndTypes); +Error mergeTypeAndIdRecords(GlobalTypeTableBuilder &DestIds, +                            GlobalTypeTableBuilder &DestTypes, +                            SmallVectorImpl<TypeIndex> &SourceToDest, +                            const CVTypeArray &IdsAndTypes, +                            ArrayRef<GloballyHashedType> Hashes); + +Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, +                       SmallVectorImpl<TypeIndex> &SourceToDest, +                       const CVTypeArray &Types, +                       ArrayRef<GloballyHashedType> Hashes); + +Error mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types, +                     SmallVectorImpl<TypeIndex> &SourceToDest, +                     const CVTypeArray &Ids, +                     ArrayRef<GloballyHashedType> Hashes); +  } // end namespace codeview  } // end namespace llvm diff --git a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h deleted file mode 100644 index 1069dcd45334..000000000000 --- a/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ /dev/null @@ -1,137 +0,0 @@ -//===- TypeTableBuilder.h ---------------------------------------*- C++ -*-===// -// -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <type_traits> - -namespace llvm { -namespace codeview { - -class TypeTableBuilder { -private: -  TypeIndex handleError(Error EC) const { -    assert(false && "Couldn't write Type!"); -    consumeError(std::move(EC)); -    return TypeIndex(); -  } - -  BumpPtrAllocator &Allocator; -  TypeSerializer Serializer; - -public: -  explicit TypeTableBuilder(BumpPtrAllocator &Allocator, -                            bool WriteUnique = true) -      : Allocator(Allocator), Serializer(Allocator, WriteUnique) {} -  TypeTableBuilder(const TypeTableBuilder &) = delete; -  TypeTableBuilder &operator=(const TypeTableBuilder &) = delete; - -  bool empty() const { return Serializer.records().empty(); } - -  BumpPtrAllocator &getAllocator() const { return Allocator; } - -  template <typename T> TypeIndex writeKnownType(T &Record) { -    static_assert(!std::is_same<T, FieldListRecord>::value, -                  "Can't serialize FieldList!"); - -    CVType Type; -    Type.Type = static_cast<TypeLeafKind>(Record.getKind()); -    if (auto EC = Serializer.visitTypeBegin(Type)) -      return handleError(std::move(EC)); -    if (auto EC = Serializer.visitKnownRecord(Type, Record)) -      return handleError(std::move(EC)); - -    auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type); -    if (!ExpectedIndex) -      return handleError(ExpectedIndex.takeError()); - -    return *ExpectedIndex; -  } - -  TypeIndex writeSerializedRecord(ArrayRef<uint8_t> Record) { -    return Serializer.insertRecordBytes(Record); -  } - -  TypeIndex writeSerializedRecord(const RemappedType &Record) { -    return Serializer.insertRecord(Record); -  } - -  template <typename TFunc> void ForEachRecord(TFunc Func) { -    uint32_t Index = TypeIndex::FirstNonSimpleIndex; - -    for (auto Record : Serializer.records()) { -      Func(TypeIndex(Index), Record); -      ++Index; -    } -  } - -  ArrayRef<ArrayRef<uint8_t>> records() const { return Serializer.records(); } -}; - -class FieldListRecordBuilder { -  TypeTableBuilder &TypeTable; -  BumpPtrAllocator Allocator; -  TypeSerializer TempSerializer; -  CVType Type; - -public: -  explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable) -      : TypeTable(TypeTable), TempSerializer(Allocator, false) { -    Type.Type = TypeLeafKind::LF_FIELDLIST; -  } - -  void begin() { -    TempSerializer.reset(); - -    if (auto EC = TempSerializer.visitTypeBegin(Type)) -      consumeError(std::move(EC)); -  } - -  template <typename T> void writeMemberType(T &Record) { -    CVMemberRecord CVMR; -    CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind()); -    if (auto EC = TempSerializer.visitMemberBegin(CVMR)) -      consumeError(std::move(EC)); -    if (auto EC = TempSerializer.visitKnownMember(CVMR, Record)) -      consumeError(std::move(EC)); -    if (auto EC = TempSerializer.visitMemberEnd(CVMR)) -      consumeError(std::move(EC)); -  } - -  TypeIndex end(bool Write) { -    TypeIndex Index; -    if (auto EC = TempSerializer.visitTypeEnd(Type)) { -      consumeError(std::move(EC)); -      return TypeIndex(); -    } - -    if (Write) { -      for (auto Record : TempSerializer.records()) -        Index = TypeTable.writeSerializedRecord(Record); -    } - -    return Index; -  } -}; - -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H | 
