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 0000000000000..bd1743511ed4b --- /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 44040e04388af..9f3a753ad1ae1 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 b7a7e33abadf8..1a4f510c24abe 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 0000000000000..3f06602948668 --- /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 32813d861d909..41c5380767983 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 8c193bb13cb7e..69ce9606a670f 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 0000000000000..7f851a2595dc0 --- /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 0000000000000..d8ac3343c15f9 --- /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 cc0c24301d498..16d78692c839a 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 0000000000000..9030918ebbb32 --- /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 a987b4afd283a..b022108df3d65 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 0000000000000..a85d9270186bf --- /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 1a83882246652..22a333e631a03 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 5b6599d8c1db0..b5479db97a150 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 f3086cf3dbb91..cf267f23967bc 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 b63ced5217b44..f4d8ab0c3c2ed 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 0f856f57a7275..e9fc9b0de8efe 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 965cdfd85f489..9887d901773a0 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 0000000000000..741337533701c --- /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 e0c2226bdbd74..c71281de71455 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 afe8942159e84..c424a09ece890 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 7942c0c0bc215..508bdd395f74e 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 5a6507ee7f5b4..0000000000000 --- 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 0e734a8170bdf..0000000000000 --- 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 d78fab47db668..59e216abcb11c 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 1069dcd453349..0000000000000 --- 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 |