diff options
Diffstat (limited to 'include/llvm/DebugInfo')
75 files changed, 2280 insertions, 951 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 diff --git a/include/llvm/DebugInfo/DIContext.h b/include/llvm/DebugInfo/DIContext.h index 936813dc6abc0..abace93786077 100644 --- a/include/llvm/DebugInfo/DIContext.h +++ b/include/llvm/DebugInfo/DIContext.h @@ -17,6 +17,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> #include <memory> @@ -26,9 +27,7 @@ namespace llvm { -class raw_ostream; - -/// DILineInfo - a format-neutral container for source line information. +/// A format-neutral container for source line information. struct DILineInfo { std::string FileName; std::string FunctionName; @@ -46,20 +45,35 @@ struct DILineInfo { FileName == RHS.FileName && FunctionName == RHS.FunctionName && StartLine == RHS.StartLine && Discriminator == RHS.Discriminator; } + bool operator!=(const DILineInfo &RHS) const { return !(*this == RHS); } + bool operator<(const DILineInfo &RHS) const { return std::tie(FileName, FunctionName, Line, Column, StartLine, Discriminator) < std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column, RHS.StartLine, RHS.Discriminator); } + + explicit operator bool() const { return *this != DILineInfo(); } + + void dump(raw_ostream &OS) { + OS << "Line info: "; + if (FileName != "<invalid>") + OS << "file '" << FileName << "', "; + if (FunctionName != "<invalid>") + OS << "function '" << FunctionName << "', "; + OS << "line " << Line << ", "; + OS << "column " << Column << ", "; + OS << "start line " << StartLine << '\n'; + } }; using DILineInfoTable = SmallVector<std::pair<uint64_t, DILineInfo>, 16>; -/// DIInliningInfo - a format-neutral container for inlined code description. +/// A format-neutral container for inlined code description. class DIInliningInfo { SmallVector<DILineInfo, 4> Frames; @@ -85,7 +99,7 @@ public: } }; -/// DIGlobal - container for description of a global variable. +/// Container for description of a global variable. struct DIGlobal { std::string Name; uint64_t Start = 0; @@ -98,8 +112,8 @@ struct DIGlobal { /// preference regarding the type of name resolution the caller wants. enum class DINameKind { None, ShortName, LinkageName }; -/// DILineInfoSpecifier - controls which fields of DILineInfo container -/// should be filled with data. +/// Controls which fields of DILineInfo container should be filled +/// with data. struct DILineInfoSpecifier { enum class FileLineInfoKind { None, Default, AbsoluteFilePath }; using FunctionNameKind = DINameKind; @@ -112,48 +126,54 @@ struct DILineInfoSpecifier { : FLIKind(FLIKind), FNKind(FNKind) {} }; +/// This is just a helper to programmatically construct DIDumpType. +enum DIDumpTypeCounter { +#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ + DIDT_ID_##ENUM_NAME, +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DWARF_SECTION + DIDT_ID_UUID, + DIDT_ID_Count +}; +static_assert(DIDT_ID_Count <= 32, "section types overflow storage"); + /// Selects which debug sections get dumped. -enum DIDumpType { +enum DIDumpType : unsigned { DIDT_Null, - DIDT_All, - DIDT_Abbrev, - DIDT_AbbrevDwo, - DIDT_Aranges, - DIDT_Frames, - DIDT_Info, - DIDT_InfoDwo, - DIDT_Types, - DIDT_TypesDwo, - DIDT_Line, - DIDT_LineDwo, - DIDT_Loc, - DIDT_LocDwo, - DIDT_Macro, - DIDT_Ranges, - DIDT_Pubnames, - DIDT_Pubtypes, - DIDT_GnuPubnames, - DIDT_GnuPubtypes, - DIDT_Str, - DIDT_StrOffsets, - DIDT_StrDwo, - DIDT_StrOffsetsDwo, - DIDT_AppleNames, - DIDT_AppleTypes, - DIDT_AppleNamespaces, - DIDT_AppleObjC, - DIDT_CUIndex, - DIDT_GdbIndex, - DIDT_TUIndex, + DIDT_All = ~0U, +#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME) \ + DIDT_##ENUM_NAME = 1U << DIDT_ID_##ENUM_NAME, +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DWARF_SECTION + DIDT_UUID = 1 << DIDT_ID_UUID, }; /// Container for dump options that control which debug information will be /// dumped. struct DIDumpOptions { - DIDumpType DumpType = DIDT_All; - bool DumpEH = false; - bool SummarizeTypes = false; - bool Brief = false; + unsigned DumpType = DIDT_All; + unsigned RecurseDepth = -1U; + bool ShowAddresses = true; + bool ShowChildren = false; + bool ShowParents = false; + bool ShowForm = false; + bool SummarizeTypes = false; + bool Verbose = false; + + /// Return default option set for printing a single DIE without children. + static DIDumpOptions getForSingleDIE() { + DIDumpOptions Opts; + Opts.RecurseDepth = 0; + return Opts; + } + + /// Return the options with RecurseDepth set to 0 unless explicitly required. + DIDumpOptions noImplicitRecursion() const { + DIDumpOptions Opts = *this; + if (RecurseDepth == -1U && !ShowChildren) + Opts.RecurseDepth = 0; + return Opts; + } }; class DIContext { @@ -170,7 +190,7 @@ public: virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0; - virtual bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) { + virtual bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) { // No verifier? Just say things went well. return true; } @@ -202,22 +222,23 @@ public: /// Calculate the address of the given section. /// The section need not be present in the local address space. The addresses /// need to be consistent with the addresses used to query the DIContext and - /// the output of this function should be deterministic, i.e. repeated calls with - /// the same Sec should give the same address. + /// the output of this function should be deterministic, i.e. repeated calls + /// with the same Sec should give the same address. virtual uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const { return 0; } /// If conveniently available, return the content of the given Section. /// - /// When the section is available in the local address space, in relocated (loaded) - /// form, e.g. because it was relocated by a JIT for execution, this function - /// should provide the contents of said section in `Data`. If the loaded section - /// is not available, or the cost of retrieving it would be prohibitive, this - /// function should return false. In that case, relocations will be read from the - /// local (unrelocated) object file and applied on the fly. Note that this method - /// is used purely for optimzation purposes in the common case of JITting in the - /// local address space, so returning false should always be correct. + /// When the section is available in the local address space, in relocated + /// (loaded) form, e.g. because it was relocated by a JIT for execution, this + /// function should provide the contents of said section in `Data`. If the + /// loaded section is not available, or the cost of retrieving it would be + /// prohibitive, this function should return false. In that case, relocations + /// will be read from the local (unrelocated) object file and applied on the + /// fly. Note that this method is used purely for optimzation purposes in the + /// common case of JITting in the local address space, so returning false + /// should always be correct. virtual bool getLoadedSectionContents(const object::SectionRef &Sec, StringRef &Data) const { return false; diff --git a/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h b/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h index 190a69b757390..84b23398b8ccd 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -28,31 +28,54 @@ class raw_ostream; class DWARFAbbreviationDeclaration { public: struct AttributeSpec { - AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional<int64_t> V) - : Attr(A), Form(F), ByteSizeOrValue(V) {} + AttributeSpec(dwarf::Attribute A, dwarf::Form F, int64_t Value) + : Attr(A), Form(F), Value(Value) { + assert(isImplicitConst()); + } + AttributeSpec(dwarf::Attribute A, dwarf::Form F, Optional<uint8_t> ByteSize) + : Attr(A), Form(F) { + assert(!isImplicitConst()); + this->ByteSize.HasByteSize = ByteSize.hasValue(); + if (this->ByteSize.HasByteSize) + this->ByteSize.ByteSize = *ByteSize; + } dwarf::Attribute Attr; dwarf::Form Form; + private: /// The following field is used for ByteSize for non-implicit_const /// attributes and as value for implicit_const ones, indicated by /// Form == DW_FORM_implicit_const. /// The following cases are distinguished: - /// * Form != DW_FORM_implicit_const and ByteSizeOrValue has a value: - /// ByteSizeOrValue contains the fixed size in bytes - /// for the Form in this object. - /// * Form != DW_FORM_implicit_const and ByteSizeOrValue is None: + /// * Form != DW_FORM_implicit_const and HasByteSize is true: + /// ByteSize contains the fixed size in bytes for the Form in this + /// object. + /// * Form != DW_FORM_implicit_const and HasByteSize is false: /// byte size of Form either varies according to the DWARFUnit /// that it is contained in or the value size varies and must be /// decoded from the debug information in order to determine its size. /// * Form == DW_FORM_implicit_const: - /// ByteSizeOrValue contains value for the implicit_const attribute. - Optional<int64_t> ByteSizeOrValue; - + /// Value contains value for the implicit_const attribute. + struct ByteSizeStorage { + bool HasByteSize; + uint8_t ByteSize; + }; + union { + ByteSizeStorage ByteSize; + int64_t Value; + }; + + public: bool isImplicitConst() const { return Form == dwarf::DW_FORM_implicit_const; } + int64_t getImplicitConstValue() const { + assert(isImplicitConst()); + return Value; + } + /// Get the fixed byte size of this Form if possible. This function might /// use the DWARFUnit to calculate the size of the Form, like for /// DW_AT_address and DW_AT_ref_addr, so this isn't just an accessor for diff --git a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index eb6d0f541c1ed..0bade10f6201b 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -13,7 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include <cstdint> #include <utility> @@ -21,6 +21,9 @@ namespace llvm { class raw_ostream; +/// This implements the Apple accelerator table format, a precursor of the +/// DWARF 5 accelerator table format. +/// TODO: Factor out a common base class for both formats. class DWARFAcceleratorTable { struct Header { uint32_t Magic; @@ -43,13 +46,51 @@ class DWARFAcceleratorTable { struct HeaderData HdrData; DWARFDataExtractor AccelSection; DataExtractor StringSection; + bool IsValid = false; public: + /// An iterator for the entries associated with one key. Each entry can have + /// multiple DWARFFormValues. + class ValueIterator : public std::iterator<std::input_iterator_tag, + ArrayRef<DWARFFormValue>> { + const DWARFAcceleratorTable *AccelTable = nullptr; + SmallVector<DWARFFormValue, 3> AtomForms; ///< The decoded data entry. + + unsigned DataOffset = 0; ///< Offset into the section. + unsigned Data = 0; ///< Current data entry. + unsigned NumData = 0; ///< Number of data entries. + + /// Advance the iterator. + void Next(); + public: + /// Construct a new iterator for the entries at \p DataOffset. + ValueIterator(const DWARFAcceleratorTable &AccelTable, unsigned DataOffset); + /// End marker. + ValueIterator() = default; + + const ArrayRef<DWARFFormValue> operator*() const { + return AtomForms; + } + ValueIterator &operator++() { Next(); return *this; } + ValueIterator operator++(int) { + ValueIterator I = *this; + Next(); + return I; + } + friend bool operator==(const ValueIterator &A, const ValueIterator &B) { + return A.NumData == B.NumData && A.DataOffset == B.DataOffset; + } + friend bool operator!=(const ValueIterator &A, const ValueIterator &B) { + return !(A == B); + } + }; + + DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection, DataExtractor StringSection) : AccelSection(AccelSection), StringSection(StringSection) {} - bool extract(); + llvm::Error extract(); uint32_t getNumBuckets(); uint32_t getNumHashes(); uint32_t getSizeHdr(); @@ -61,12 +102,15 @@ public: /// performing a lookup by name. /// /// \param HashDataOffset an offset into the hash data table - /// \returns DIEOffset the offset into the .debug_info section for the DIE - /// related to the input hash data offset. Currently this function returns - /// only the DIEOffset but it can be modified to return more data regarding - /// the DIE - uint32_t readAtoms(uint32_t &HashDataOffset); + /// \returns <DieOffset, DieTag> + /// DieOffset is the offset into the .debug_info section for the DIE + /// related to the input hash data offset. + /// DieTag is the tag of the DIE + std::pair<uint32_t, dwarf::Tag> readAtoms(uint32_t &HashDataOffset); void dump(raw_ostream &OS) const; + + /// Look up all entries in the accelerator table matching \c Key. + iterator_range<ValueIterator> equal_range(StringRef Key) const; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h index ee2e805050c01..2ddbc4b91ba2e 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -17,6 +17,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" @@ -26,6 +27,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFObject.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" @@ -42,13 +44,18 @@ namespace llvm { class DataExtractor; +class MCRegisterInfo; class MemoryBuffer; class raw_ostream; +/// Used as a return value for a error callback passed to DWARF context. +/// Callback should return Halt if client application wants to stop +/// object parsing, or should return Continue otherwise. +enum class ErrorPolicy { Halt, Continue }; + /// DWARFContext /// This data structure is the top level entity that deals with dwarf debug -/// information parsing. The actual data is supplied through pure virtual -/// methods that a concrete implementation provides. +/// information parsing. The actual data is supplied through DWARFObj. class DWARFContext : public DIContext { DWARFUnitSection<DWARFCompileUnit> CUs; std::deque<DWARFUnitSection<DWARFTypeUnit>> TUs; @@ -62,6 +69,10 @@ class DWARFContext : public DIContext { std::unique_ptr<DWARFDebugFrame> DebugFrame; std::unique_ptr<DWARFDebugFrame> EHFrame; std::unique_ptr<DWARFDebugMacro> Macro; + std::unique_ptr<DWARFAcceleratorTable> AppleNames; + std::unique_ptr<DWARFAcceleratorTable> AppleTypes; + std::unique_ptr<DWARFAcceleratorTable> AppleNamespaces; + std::unique_ptr<DWARFAcceleratorTable> AppleObjC; DWARFUnitSection<DWARFCompileUnit> DWOCUs; std::deque<DWARFUnitSection<DWARFTypeUnit>> DWOTUs; @@ -78,6 +89,9 @@ class DWARFContext : public DIContext { StringMap<std::weak_ptr<DWOFile>> DWOFiles; std::weak_ptr<DWOFile> DWP; bool CheckedForDWP = false; + std::string DWPName; + + std::unique_ptr<MCRegisterInfo> RegInfo; /// Read compile units from the debug_info section (if necessary) /// and store them in CUs. @@ -95,18 +109,34 @@ class DWARFContext : public DIContext { /// and store them in DWOTUs. void parseDWOTypeUnits(); +protected: + std::unique_ptr<const DWARFObject> DObj; + public: - DWARFContext() : DIContext(CK_DWARF) {} + DWARFContext(std::unique_ptr<const DWARFObject> DObj, + std::string DWPName = ""); + ~DWARFContext(); + DWARFContext(DWARFContext &) = delete; DWARFContext &operator=(DWARFContext &) = delete; + const DWARFObject &getDWARFObj() const { return *DObj; } + static bool classof(const DIContext *DICtx) { return DICtx->getKind() == CK_DWARF; } - void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override; + /// Dump a textual representation to \p OS. If any \p DumpOffsets are present, + /// dump only the record at the specified offset. + void dump(raw_ostream &OS, DIDumpOptions DumpOpts, + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets); - bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; + void dump(raw_ostream &OS, DIDumpOptions DumpOpts) override { + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets; + dump(OS, DumpOpts, DumpOffsets); + } + + bool verify(raw_ostream &OS, DIDumpOptions DumpOpts = {}) override; using cu_iterator_range = DWARFUnitSection<DWARFCompileUnit>::iterator_range; using tu_iterator_range = DWARFUnitSection<DWARFTypeUnit>::iterator_range; @@ -212,9 +242,33 @@ public: /// Get a pointer to the parsed DebugMacro object. const DWARFDebugMacro *getDebugMacro(); + /// Get a reference to the parsed accelerator table object. + const DWARFAcceleratorTable &getAppleNames(); + + /// Get a reference to the parsed accelerator table object. + const DWARFAcceleratorTable &getAppleTypes(); + + /// Get a reference to the parsed accelerator table object. + const DWARFAcceleratorTable &getAppleNamespaces(); + + /// Get a reference to the parsed accelerator table object. + const DWARFAcceleratorTable &getAppleObjC(); + /// Get a pointer to a parsed line table corresponding to a compile unit. const DWARFDebugLine::LineTable *getLineTableForUnit(DWARFUnit *cu); + /// Wraps the returned DIEs for a given address. + struct DIEsForAddress { + DWARFCompileUnit *CompileUnit = nullptr; + DWARFDie FunctionDIE; + DWARFDie BlockDIE; + explicit operator bool() const { return CompileUnit != nullptr; } + }; + + /// Get the compilation unit, the function DIE and lexical block DIE for the + /// given address where applicable. + DIEsForAddress getDIEsForAddress(uint64_t Address); + DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; DILineInfoTable getLineInfoForAddressRange(uint64_t Address, uint64_t Size, @@ -222,198 +276,39 @@ public: DIInliningInfo getInliningInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override; - virtual StringRef getFileName() const = 0; - virtual bool isLittleEndian() const = 0; - virtual uint8_t getAddressSize() const = 0; - virtual const DWARFSection &getInfoSection() = 0; - virtual void forEachTypesSections(function_ref<void(DWARFSection &)> F) = 0; - virtual StringRef getAbbrevSection() = 0; - virtual const DWARFSection &getLocSection() = 0; - virtual StringRef getARangeSection() = 0; - virtual StringRef getDebugFrameSection() = 0; - virtual StringRef getEHFrameSection() = 0; - virtual const DWARFSection &getLineSection() = 0; - virtual StringRef getStringSection() = 0; - virtual const DWARFSection& getRangeSection() = 0; - virtual StringRef getMacinfoSection() = 0; - virtual StringRef getPubNamesSection() = 0; - virtual StringRef getPubTypesSection() = 0; - virtual StringRef getGnuPubNamesSection() = 0; - virtual StringRef getGnuPubTypesSection() = 0; - - /// DWARF v5 - /// @{ - virtual const DWARFSection &getStringOffsetSection() = 0; - /// @} - - // Sections for DWARF5 split dwarf proposal. - virtual const DWARFSection &getInfoDWOSection() = 0; - virtual void - forEachTypesDWOSections(function_ref<void(DWARFSection &)> F) = 0; - virtual StringRef getAbbrevDWOSection() = 0; - virtual const DWARFSection &getLineDWOSection() = 0; - virtual const DWARFSection &getLocDWOSection() = 0; - virtual StringRef getStringDWOSection() = 0; - virtual const DWARFSection &getStringOffsetDWOSection() = 0; - virtual const DWARFSection &getRangeDWOSection() = 0; - virtual const DWARFSection &getAddrSection() = 0; - virtual const DWARFSection& getAppleNamesSection() = 0; - virtual const DWARFSection& getAppleTypesSection() = 0; - virtual const DWARFSection& getAppleNamespacesSection() = 0; - virtual const DWARFSection& getAppleObjCSection() = 0; - virtual StringRef getCUIndexSection() = 0; - virtual StringRef getGdbIndexSection() = 0; - virtual StringRef getTUIndexSection() = 0; - + bool isLittleEndian() const { return DObj->isLittleEndian(); } static bool isSupportedVersion(unsigned version) { return version == 2 || version == 3 || version == 4 || version == 5; } std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath); -private: - /// Return the compile unit that includes an offset (relative to .debug_info). - DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); - - /// Return the compile unit which contains instruction with provided - /// address. - DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); -}; - -/// Used as a return value for a error callback passed to DWARF context. -/// Callback should return Halt if client application wants to stop -/// object parsing, or should return Continue otherwise. -enum class ErrorPolicy { Halt, Continue }; - -/// DWARFContextInMemory is the simplest possible implementation of a -/// DWARFContext. It assumes all content is available in memory and stores -/// pointers to it. -class DWARFContextInMemory : public DWARFContext { - virtual void anchor(); - - using TypeSectionMap = MapVector<object::SectionRef, DWARFSection, - std::map<object::SectionRef, unsigned>>; - - StringRef FileName; - bool IsLittleEndian; - uint8_t AddressSize; - DWARFSection InfoSection; - TypeSectionMap TypesSections; - StringRef AbbrevSection; - DWARFSection LocSection; - StringRef ARangeSection; - StringRef DebugFrameSection; - StringRef EHFrameSection; - DWARFSection LineSection; - StringRef StringSection; - DWARFSection RangeSection; - StringRef MacinfoSection; - StringRef PubNamesSection; - StringRef PubTypesSection; - StringRef GnuPubNamesSection; - StringRef GnuPubTypesSection; - - /// DWARF v5 - /// @{ - DWARFSection StringOffsetSection; - /// @} - - // Sections for DWARF5 split dwarf proposal. - DWARFSection InfoDWOSection; - TypeSectionMap TypesDWOSections; - StringRef AbbrevDWOSection; - DWARFSection LineDWOSection; - DWARFSection LocDWOSection; - StringRef StringDWOSection; - DWARFSection StringOffsetDWOSection; - DWARFSection RangeDWOSection; - DWARFSection AddrSection; - DWARFSection AppleNamesSection; - DWARFSection AppleTypesSection; - DWARFSection AppleNamespacesSection; - DWARFSection AppleObjCSection; - StringRef CUIndexSection; - StringRef GdbIndexSection; - StringRef TUIndexSection; - - SmallVector<SmallString<32>, 4> UncompressedSections; - - DWARFSection *mapNameToDWARFSection(StringRef Name); - StringRef *mapSectionToMember(StringRef Name); - - /// If Sec is compressed section, decompresses and updates its contents - /// provided by Data. Otherwise leaves it unchanged. - Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, - StringRef &Data); + const MCRegisterInfo *getRegisterInfo() const { return RegInfo.get(); } /// Function used to handle default error reporting policy. Prints a error /// message and returns Continue, so DWARF context ignores the error. static ErrorPolicy defaultErrorHandler(Error E); + static std::unique_ptr<DWARFContext> + create(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr, + function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler, + std::string DWPName = ""); -public: - DWARFContextInMemory( - const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr, - function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler); - - DWARFContextInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, - uint8_t AddrSize, - bool isLittleEndian = sys::IsLittleEndianHost); - - StringRef getFileName() const override { return FileName; } - bool isLittleEndian() const override { return IsLittleEndian; } - uint8_t getAddressSize() const override { return AddressSize; } - const DWARFSection &getInfoSection() override { return InfoSection; } - void forEachTypesSections(function_ref<void(DWARFSection &)> F) override { - for (auto &P : TypesSections) - F(P.second); - } - StringRef getAbbrevSection() override { return AbbrevSection; } - const DWARFSection &getLocSection() override { return LocSection; } - StringRef getARangeSection() override { return ARangeSection; } - StringRef getDebugFrameSection() override { return DebugFrameSection; } - StringRef getEHFrameSection() override { return EHFrameSection; } - const DWARFSection &getLineSection() override { return LineSection; } - StringRef getStringSection() override { return StringSection; } - const DWARFSection &getRangeSection() override { return RangeSection; } - StringRef getMacinfoSection() override { return MacinfoSection; } - StringRef getPubNamesSection() override { return PubNamesSection; } - StringRef getPubTypesSection() override { return PubTypesSection; } - StringRef getGnuPubNamesSection() override { return GnuPubNamesSection; } - StringRef getGnuPubTypesSection() override { return GnuPubTypesSection; } - const DWARFSection& getAppleNamesSection() override { return AppleNamesSection; } - const DWARFSection& getAppleTypesSection() override { return AppleTypesSection; } - const DWARFSection& getAppleNamespacesSection() override { return AppleNamespacesSection; } - const DWARFSection& getAppleObjCSection() override { return AppleObjCSection; } - - // DWARF v5 - const DWARFSection &getStringOffsetSection() override { - return StringOffsetSection; - } - - // Sections for DWARF5 split dwarf proposal. - const DWARFSection &getInfoDWOSection() override { return InfoDWOSection; } - - void forEachTypesDWOSections(function_ref<void(DWARFSection &)> F) override { - for (auto &P : TypesDWOSections) - F(P.second); - } - - StringRef getAbbrevDWOSection() override { return AbbrevDWOSection; } - const DWARFSection &getLineDWOSection() override { return LineDWOSection; } - const DWARFSection &getLocDWOSection() override { return LocDWOSection; } - StringRef getStringDWOSection() override { return StringDWOSection; } - - const DWARFSection &getStringOffsetDWOSection() override { - return StringOffsetDWOSection; - } + static std::unique_ptr<DWARFContext> + create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool isLittleEndian = sys::IsLittleEndianHost); - const DWARFSection &getRangeDWOSection() override { return RangeDWOSection; } + /// Loads register info for the architecture of the provided object file. + /// Improves readability of dumped DWARF expressions. Requires the caller to + /// have initialized the relevant target descriptions. + Error loadRegisterInfo(const object::ObjectFile &Obj); - const DWARFSection &getAddrSection() override { return AddrSection; } +private: + /// Return the compile unit that includes an offset (relative to .debug_info). + DWARFCompileUnit *getCompileUnitForOffset(uint32_t Offset); - StringRef getCUIndexSection() override { return CUIndexSection; } - StringRef getGdbIndexSection() override { return GdbIndexSection; } - StringRef getTUIndexSection() override { return TUIndexSection; } + /// Return the compile unit which contains instruction with provided + /// address. + DWARFCompileUnit *getCompileUnitForAddress(uint64_t Address); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index ef4360f666218..a379d9c85b385 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -14,18 +14,21 @@ #include "llvm/Support/DataExtractor.h" namespace llvm { +class DWARFObject; /// A DataExtractor (typically for an in-memory copy of an object-file section) /// plus a relocation map for that section, if there is one. class DWARFDataExtractor : public DataExtractor { - const RelocAddrMap *RelocMap = nullptr; + const DWARFObject *Obj = nullptr; + const DWARFSection *Section = nullptr; + public: /// Constructor for the normal case of extracting data from a DWARF section. /// The DWARFSection's lifetime must be at least as long as the extractor's. - DWARFDataExtractor(const DWARFSection &Section, bool IsLittleEndian, - uint8_t AddressSize) - : DataExtractor(Section.Data, IsLittleEndian, AddressSize), - RelocMap(&Section.Relocs) {} + DWARFDataExtractor(const DWARFObject &Obj, const DWARFSection &Section, + bool IsLittleEndian, uint8_t AddressSize) + : DataExtractor(Section.Data, IsLittleEndian, AddressSize), Obj(&Obj), + Section(&Section) {} /// Constructor for cases when there are no relocations. DWARFDataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize) diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index 65571598d7432..d277ec382ba56 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -56,8 +56,9 @@ class DWARFDebugAbbrev { using DWARFAbbreviationDeclarationSetMap = std::map<uint64_t, DWARFAbbreviationDeclarationSet>; - DWARFAbbreviationDeclarationSetMap AbbrDeclSets; + mutable DWARFAbbreviationDeclarationSetMap AbbrDeclSets; mutable DWARFAbbreviationDeclarationSetMap::const_iterator PrevAbbrOffsetPos; + mutable Optional<DataExtractor> Data; public: DWARFDebugAbbrev(); @@ -66,9 +67,11 @@ public: getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const; void dump(raw_ostream &OS) const; + void parse() const; void extract(DataExtractor Data); DWARFAbbreviationDeclarationSetMap::const_iterator begin() const { + parse(); return AbbrDeclSets.begin(); } diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h index e0a779bb81823..a711fb2954447 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -29,13 +29,19 @@ public: DWARFDebugFrame(bool IsEH); ~DWARFDebugFrame(); - /// \brief Dump the section data into the given stream. - void dump(raw_ostream &OS) const; + /// Dump the section data into the given stream. + void dump(raw_ostream &OS, Optional<uint64_t> Offset) const; /// \brief Parse the section from raw data. /// data is assumed to be pointing to the beginning of the section. void parse(DataExtractor Data); + /// Return whether the section has any entries. + bool empty() const { return Entries.empty(); } + + /// Return the entry at the given offset or nullptr. + FrameEntry *getEntryAtOffset(uint64_t Offset) const; + private: std::vector<std::unique_ptr<FrameEntry>> Entries; }; diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index 0c8f98aa62f9e..de8ad4e5ef3cb 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -15,6 +15,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/Support/MD5.h" #include <cstdint> #include <map> #include <string> @@ -22,6 +23,7 @@ namespace llvm { +class DWARFUnit; class raw_ostream; class DWARFDebugLine { @@ -33,6 +35,7 @@ public: uint64_t DirIdx = 0; uint64_t ModTime = 0; uint64_t Length = 0; + MD5::MD5Result Checksum; }; struct Prologue { @@ -45,11 +48,11 @@ public: /// parameters affect interpretation of forms (used in the directory and /// file tables starting with v5). DWARFFormParams FormParams; - /// In v5, size in bytes of a segment selector. - uint8_t SegSelectorSize; /// The number of bytes following the prologue_length field to the beginning /// of the first byte of the statement program itself. uint64_t PrologueLength; + /// In v5, size in bytes of a segment selector. + uint8_t SegSelectorSize; /// The size in bytes of the smallest target machine instruction. Statement /// program opcodes that alter the address register first multiply their /// operands by this value. @@ -65,6 +68,8 @@ public: uint8_t LineRange; /// The number assigned to the first special opcode. uint8_t OpcodeBase; + /// For v5, whether filename entries provide an MD5 checksum. + bool HasMD5; std::vector<uint8_t> StandardOpcodeLengths; std::vector<StringRef> IncludeDirectories; std::vector<FileNameEntry> FileNames; @@ -95,7 +100,8 @@ public: void clear(); void dump(raw_ostream &OS) const; - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr); + bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFUnit *U = nullptr); }; /// Standard .debug_line state machine structure. @@ -217,7 +223,8 @@ public: void clear(); /// Parse prologue and all rows. - bool parse(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr); + bool parse(DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr, + const DWARFUnit *U, raw_ostream *OS = nullptr); using RowVector = std::vector<Row>; using RowIter = RowVector::const_iterator; @@ -234,8 +241,8 @@ public: }; const LineTable *getLineTable(uint32_t Offset) const; - const LineTable *getOrParseLineTable(const DWARFDataExtractor &DebugLineData, - uint32_t Offset); + const LineTable *getOrParseLineTable(DWARFDataExtractor &DebugLineData, + uint32_t Offset, const DWARFUnit *U); private: struct ParsingState { diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index c2b8d0cd73d82..a6d319a90457f 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -10,16 +10,19 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include <cstdint> namespace llvm { - +class DWARFUnit; +class MCRegisterInfo; class raw_ostream; class DWARFDebugLoc { +public: /// A single location within a location list. struct Entry { /// The beginning address of the instruction range. @@ -27,7 +30,7 @@ class DWARFDebugLoc { /// The ending address of the instruction range. uint64_t End; /// The location of the variable within the specified range. - SmallVector<unsigned char, 4> Loc; + SmallVector<char, 4> Loc; }; /// A list of locations that contain one variable. @@ -37,42 +40,72 @@ class DWARFDebugLoc { unsigned Offset; /// All the locations in which the variable is stored. SmallVector<Entry, 2> Entries; + /// Dump this list on OS. + void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, + const MCRegisterInfo *MRI, unsigned Indent) const; }; +private: using LocationLists = SmallVector<LocationList, 4>; /// A list of all the variables in the debug_loc section, each one describing /// the locations in which the variable is stored. LocationLists Locations; + unsigned AddressSize; + + bool IsLittleEndian; + public: /// Print the location lists found within the debug_loc section. - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, + Optional<uint64_t> Offset) const; /// Parse the debug_loc section accessible via the 'data' parameter using the /// address size also given in 'data' to interpret the address ranges. void parse(const DWARFDataExtractor &data); + + /// Return the location list at the given offset or nullptr. + LocationList const *getLocationListAtOffset(uint64_t Offset) const; + + Optional<LocationList> parseOneLocationList(DWARFDataExtractor Data, + uint32_t *Offset); }; class DWARFDebugLocDWO { +public: struct Entry { uint64_t Start; uint32_t Length; - SmallVector<unsigned char, 4> Loc; + SmallVector<char, 4> Loc; }; struct LocationList { unsigned Offset; SmallVector<Entry, 2> Entries; + void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize, + const MCRegisterInfo *RegInfo, unsigned Indent) const; }; +private: using LocationLists = SmallVector<LocationList, 4>; LocationLists Locations; + unsigned AddressSize; + + bool IsLittleEndian; + public: void parse(DataExtractor data); - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS, const MCRegisterInfo *RegInfo, + Optional<uint64_t> Offset) const; + + /// Return the location list at the given offset or nullptr. + LocationList const *getLocationListAtOffset(uint64_t Offset) const; + + static Optional<LocationList> parseOneLocationList(DataExtractor Data, + uint32_t *Offset); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index 135c50761e36a..bfe2fc3ac02d7 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -53,6 +53,9 @@ public: /// Parse the debug_macinfo section accessible via the 'data' parameter. void parse(DataExtractor data); + + /// Return whether the section has any entries. + bool empty() const { return Macros.empty(); } }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h index a309fd104f938..761871dc6255d 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h @@ -69,7 +69,7 @@ private: public: DWARFDebugPubTable(StringRef Data, bool LittleEndian, bool GnuStyle); - void dump(StringRef Name, raw_ostream &OS) const; + void dump(raw_ostream &OS) const; ArrayRef<Set> getData() { return Sets; } }; diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h index bcba14b1630d1..f9ec96366a538 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -18,14 +18,47 @@ namespace llvm { +struct BaseAddress; class raw_ostream; struct DWARFAddressRange { uint64_t LowPC; uint64_t HighPC; uint64_t SectionIndex; + + DWARFAddressRange() = default; + + /// Used for unit testing. + DWARFAddressRange(uint64_t LowPC, uint64_t HighPC, uint64_t SectionIndex = 0) + : LowPC(LowPC), HighPC(HighPC), SectionIndex(SectionIndex) {} + + /// Returns true if LowPC is smaller or equal to HighPC. This accounts for + /// dead-stripped ranges. + bool valid() const { return LowPC <= HighPC; } + + /// Returns true if [LowPC, HighPC) intersects with [RHS.LowPC, RHS.HighPC). + bool intersects(const DWARFAddressRange &RHS) const { + // Empty ranges can't intersect. + if (LowPC == HighPC || RHS.LowPC == RHS.HighPC) + return false; + return (LowPC < RHS.HighPC) && (HighPC > RHS.LowPC); + } + + /// Returns true if [LowPC, HighPC) fully contains [RHS.LowPC, RHS.HighPC). + bool contains(const DWARFAddressRange &RHS) const { + if (LowPC <= RHS.LowPC && RHS.LowPC <= HighPC) + return LowPC <= RHS.HighPC && RHS.HighPC <= HighPC; + return false; + } }; +static inline bool operator<(const DWARFAddressRange &LHS, + const DWARFAddressRange &RHS) { + return std::tie(LHS.LowPC, LHS.HighPC) < std::tie(RHS.LowPC, RHS.HighPC); +} + +raw_ostream &operator<<(raw_ostream &OS, const DWARFAddressRange &R); + /// DWARFAddressRangesVector - represents a set of absolute address ranges. using DWARFAddressRangesVector = std::vector<DWARFAddressRange>; @@ -85,7 +118,8 @@ public: /// getAbsoluteRanges - Returns absolute address ranges defined by this range /// list. Has to be passed base address of the compile unit referencing this /// range list. - DWARFAddressRangesVector getAbsoluteRanges(uint64_t BaseAddress) const; + DWARFAddressRangesVector + getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFDie.h b/include/llvm/DebugInfo/DWARF/DWARFDie.h index b216491b615a2..75fc5995c5b22 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -108,21 +108,19 @@ public: /// /// \returns a valid DWARFDie instance if this object has children or an /// invalid DWARFDie instance if it doesn't. - DWARFDie getFirstChild() const { - if (isValid() && Die->hasChildren()) - return DWARFDie(U, Die + 1); - return DWARFDie(); - } + DWARFDie getFirstChild() const; /// Dump the DIE and all of its attributes to the supplied stream. /// /// \param OS the stream to use for output. - /// \param recurseDepth the depth to recurse to when dumping this DIE and its - /// children. /// \param indent the number of characters to indent each line that is output. - void dump(raw_ostream &OS, unsigned recurseDepth, unsigned indent = 0, + void dump(raw_ostream &OS, unsigned indent = 0, DIDumpOptions DumpOpts = DIDumpOptions()) const; + + /// Convenience zero-argument overload for debugging. + LLVM_DUMP_METHOD void dump() const; + /// Extract the specified attribute from this DIE. /// /// Extract an attribute value from this DIE only. This call doesn't look @@ -304,6 +302,10 @@ inline bool operator!=(const DWARFDie &LHS, const DWARFDie &RHS) { return !(LHS == RHS); } +inline bool operator<(const DWARFDie &LHS, const DWARFDie &RHS) { + return LHS.getOffset() < RHS.getOffset(); +} + class DWARFDie::iterator : public iterator_facade_base<iterator, std::forward_iterator_tag, const DWARFDie> { diff --git a/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/include/llvm/DebugInfo/DWARF/DWARFExpression.h new file mode 100644 index 0000000000000..dcd486f3fb137 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFExpression.h @@ -0,0 +1,151 @@ +//===--- DWARFExpression.h - DWARF Expression handling ----------*- 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_DWARFEXPRESSION_H +#define LLVM_DEBUGINFO_DWARFEXPRESSION_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/DataExtractor.h" + +namespace llvm { +class DWARFUnit; +class MCRegisterInfo; +class raw_ostream; + +class DWARFExpression { +public: + class iterator; + + /// This class represents an Operation in the Expression. Each operation can + /// have up to 2 oprerands. + /// + /// An Operation can be in Error state (check with isError()). This + /// means that it couldn't be decoded successfully and if it is the + /// case, all others fields contain undefined values. + class Operation { + public: + /// Size and signedness of expression operations' operands. + enum Encoding : uint8_t { + Size1 = 0, + Size2 = 1, + Size4 = 2, + Size8 = 3, + SizeLEB = 4, + SizeAddr = 5, + SizeRefAddr = 6, + SizeBlock = 7, ///< Preceding operand contains block size + SignBit = 0x8, + SignedSize1 = SignBit | Size1, + SignedSize2 = SignBit | Size2, + SignedSize4 = SignBit | Size4, + SignedSize8 = SignBit | Size8, + SignedSizeLEB = SignBit | SizeLEB, + SizeNA = 0xFF ///< Unused operands get this encoding. + }; + + enum DwarfVersion : uint8_t { + DwarfNA, ///< Serves as a marker for unused entries + Dwarf2 = 2, + Dwarf3, + Dwarf4 + }; + + /// Description of the encoding of one expression Op. + struct Description { + DwarfVersion Version; ///< Dwarf version where the Op was introduced. + Encoding Op[2]; ///< Encoding for Op operands, or SizeNA. + + Description(DwarfVersion Version = DwarfNA, Encoding Op1 = SizeNA, + Encoding Op2 = SizeNA) + : Version(Version) { + Op[0] = Op1; + Op[1] = Op2; + } + }; + + private: + friend class DWARFExpression::iterator; + uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>. + Description Desc; + bool Error; + uint32_t EndOffset; + uint64_t Operands[2]; + + public: + Description &getDescription() { return Desc; } + uint8_t getCode() { return Opcode; } + uint64_t getRawOperand(unsigned Idx) { return Operands[Idx]; } + uint32_t getEndOffset() { return EndOffset; } + bool extract(DataExtractor Data, uint16_t Version, uint8_t AddressSize, + uint32_t Offset); + bool isError() { return Error; } + bool print(raw_ostream &OS, const DWARFExpression *U, + const MCRegisterInfo *RegInfo, bool isEH); + }; + + /// An iterator to go through the expression operations. + class iterator + : public iterator_facade_base<iterator, std::forward_iterator_tag, Operation> { + friend class DWARFExpression; + DWARFExpression *Expr; + uint32_t Offset; + Operation Op; + iterator(DWARFExpression *Expr, uint32_t Offset) + : Expr(Expr), Offset(Offset) { + Op.Error = + Offset >= Expr->Data.getData().size() || + !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset); + } + + public: + class Operation &operator++() { + Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset; + Op.Error = + Offset >= Expr->Data.getData().size() || + !Op.extract(Expr->Data, Expr->Version, Expr->AddressSize, Offset); + return Op; + } + + class Operation &operator*() { + return Op; + } + + // Comparison operators are provided out of line. + friend bool operator==(const iterator &, const iterator &); + }; + + DWARFExpression(DataExtractor Data, uint16_t Version, uint8_t AddressSize) + : Data(Data), Version(Version), AddressSize(AddressSize) { + assert(AddressSize == 8 || AddressSize == 4); + } + + iterator begin() { return iterator(this, 0); } + iterator end() { return iterator(this, Data.getData().size()); } + + void print(raw_ostream &OS, const MCRegisterInfo *RegInfo); + +private: + DataExtractor Data; + uint16_t Version; + uint8_t AddressSize; +}; + +inline bool operator==(const DWARFExpression::iterator &LHS, + const DWARFExpression::iterator &RHS) { + return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset; +} + +inline bool operator!=(const DWARFExpression::iterator &LHS, + const DWARFExpression::iterator &RHS) { + return !(LHS == RHS); +} +} +#endif diff --git a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index 008dba9b42acd..d32053519ec48 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -14,6 +14,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" #include <cstdint> @@ -101,18 +102,14 @@ public: bool isFormClass(FormClass FC) const; const DWARFUnit *getUnit() const { return U; } - void dump(raw_ostream &OS) const; + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = DIDumpOptions()) const; - /// Extracts a value in \p Data at offset \p *OffsetPtr. - /// - /// The passed DWARFUnit is allowed to be nullptr, in which case some - /// kind of forms that depend on Unit information are disallowed. - /// \param Data The DWARFDataExtractor to use. - /// \param OffsetPtr The offset within \p Data where the data starts. - /// \param U The optional DWARFUnit supplying information for some forms. - /// \returns whether the extraction succeeded. + /// Extracts a value in \p Data at offset \p *OffsetPtr. The information + /// in \p FormParams is needed to interpret some forms. The optional + /// \p Unit allows extracting information if the form refers to other + /// sections (e.g., .debug_str). bool extractValue(const DWARFDataExtractor &Data, uint32_t *OffsetPtr, - const DWARFUnit *U); + DWARFFormParams FormParams, const DWARFUnit *U = nullptr); bool isInlinedCStr() const { return Value.data != nullptr && Value.data == (const uint8_t *)Value.cstr; diff --git a/include/llvm/DebugInfo/DWARF/DWARFObject.h b/include/llvm/DebugInfo/DWARF/DWARFObject.h new file mode 100644 index 0000000000000..167eb2da5ba04 --- /dev/null +++ b/include/llvm/DebugInfo/DWARF/DWARFObject.h @@ -0,0 +1,79 @@ +//===- DWARFObject.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_DWARF_DWARFOBJECT_H +#define LLVM_DEBUGINFO_DWARF_DWARFOBJECT_H + +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/Object/ObjectFile.h" + +namespace llvm { +// This is responsible for low level access to the object file. It +// knows how to find the required sections and compute relocated +// values. +// The default implementations of the get<Section> methods return dummy values. +// This is to allow clients that only need some of those to implement just the +// ones they need. We can't use unreachable for as many cases because the parser +// implementation is eager and will call some of these methods even if the +// result is not used. +class DWARFObject { + DWARFSection Dummy; + +public: + virtual ~DWARFObject() = default; + virtual StringRef getFileName() const { llvm_unreachable("unimplemented"); } + virtual const object::ObjectFile *getFile() const { return nullptr; } + virtual ArrayRef<SectionName> getSectionNames() const { return {}; } + virtual bool isLittleEndian() const = 0; + virtual uint8_t getAddressSize() const { llvm_unreachable("unimplemented"); } + virtual const DWARFSection &getInfoSection() const { return Dummy; } + virtual void + forEachTypesSections(function_ref<void(const DWARFSection &)> F) const {} + virtual StringRef getAbbrevSection() const { return ""; } + virtual const DWARFSection &getLocSection() const { return Dummy; } + virtual StringRef getARangeSection() const { return ""; } + virtual StringRef getDebugFrameSection() const { return ""; } + virtual StringRef getEHFrameSection() const { return ""; } + virtual const DWARFSection &getLineSection() const { return Dummy; } + virtual StringRef getStringSection() const { return ""; } + virtual const DWARFSection &getRangeSection() const { return Dummy; } + virtual StringRef getMacinfoSection() const { return ""; } + virtual StringRef getPubNamesSection() const { return ""; } + virtual StringRef getPubTypesSection() const { return ""; } + virtual StringRef getGnuPubNamesSection() const { return ""; } + virtual StringRef getGnuPubTypesSection() const { return ""; } + virtual const DWARFSection &getStringOffsetSection() const { return Dummy; } + virtual const DWARFSection &getInfoDWOSection() const { return Dummy; } + virtual void + forEachTypesDWOSections(function_ref<void(const DWARFSection &)> F) const {} + virtual StringRef getAbbrevDWOSection() const { return ""; } + virtual const DWARFSection &getLineDWOSection() const { return Dummy; } + virtual const DWARFSection &getLocDWOSection() const { return Dummy; } + virtual StringRef getStringDWOSection() const { return ""; } + virtual const DWARFSection &getStringOffsetDWOSection() const { + return Dummy; + } + virtual const DWARFSection &getRangeDWOSection() const { return Dummy; } + virtual const DWARFSection &getAddrSection() const { return Dummy; } + virtual const DWARFSection &getAppleNamesSection() const { return Dummy; } + virtual const DWARFSection &getAppleTypesSection() const { return Dummy; } + virtual const DWARFSection &getAppleNamespacesSection() const { + return Dummy; + } + virtual const DWARFSection &getAppleObjCSection() const { return Dummy; } + virtual StringRef getCUIndexSection() const { return ""; } + virtual StringRef getGdbIndexSection() const { return ""; } + virtual StringRef getTUIndexSection() const { return ""; } + virtual Optional<RelocAddrEntry> find(const DWARFSection &Sec, + uint64_t Pos) const = 0; +}; + +} // namespace llvm +#endif diff --git a/include/llvm/DebugInfo/DWARF/DWARFSection.h b/include/llvm/DebugInfo/DWARF/DWARFSection.h index 2b8a53a4c93ea..77045f0794ae8 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFSection.h +++ b/include/llvm/DebugInfo/DWARF/DWARFSection.h @@ -11,13 +11,16 @@ #define LLVM_DEBUGINFO_DWARF_DWARFSECTION_H #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" namespace llvm { struct DWARFSection { StringRef Data; - RelocAddrMap Relocs; +}; + +struct SectionName { + StringRef Name; + bool IsNameUnique; }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h index 4a5793ecb8fa6..a7842454f4356 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFTypeUnit.h @@ -42,7 +42,7 @@ public: return DWARFUnit::getHeaderSize() + 12; } - void dump(raw_ostream &OS, bool Brief = false); + void dump(raw_ostream &OS, DIDumpOptions DumpOpts = {}); static const DWARFSectionKind Section = DW_SECT_TYPES; protected: diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 056c1b77c65d1..e9178e03fa8a2 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -47,10 +47,11 @@ public: /// Returns the Unit that contains the given section offset in the /// same section this Unit originated from. virtual DWARFUnit *getUnitForOffset(uint32_t Offset) const = 0; + virtual DWARFUnit *getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) = 0; void parse(DWARFContext &C, const DWARFSection &Section); void parseDWO(DWARFContext &C, const DWARFSection &DWOSection, - DWARFUnitIndex *Index = nullptr); + bool Lazy = false); protected: ~DWARFUnitSectionBase() = default; @@ -59,7 +60,7 @@ protected: const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, const DWARFSection &LS, - bool isLittleEndian, bool isDWO) = 0; + bool isLittleEndian, bool isDWO, bool Lazy) = 0; }; const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, @@ -70,6 +71,7 @@ template<typename UnitType> class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>, public DWARFUnitSectionBase { bool Parsed = false; + std::function<std::unique_ptr<UnitType>(uint32_t)> Parser; public: using UnitVector = SmallVectorImpl<std::unique_ptr<UnitType>>; @@ -82,34 +84,87 @@ public: [](uint32_t LHS, const std::unique_ptr<UnitType> &RHS) { return LHS < RHS->getNextUnitOffset(); }); - if (CU != this->end()) + if (CU != this->end() && (*CU)->getOffset() <= Offset) return CU->get(); return nullptr; } + UnitType *getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) override { + const auto *CUOff = E.getOffset(DW_SECT_INFO); + if (!CUOff) + return nullptr; + + auto Offset = CUOff->Offset; + + auto *CU = std::upper_bound( + this->begin(), this->end(), CUOff->Offset, + [](uint32_t LHS, const std::unique_ptr<UnitType> &RHS) { + return LHS < RHS->getNextUnitOffset(); + }); + if (CU != this->end() && (*CU)->getOffset() <= Offset) + return CU->get(); + + if (!Parser) + return nullptr; + + auto U = Parser(Offset); + if (!U) + U = nullptr; + + auto *NewCU = U.get(); + this->insert(CU, std::move(U)); + return NewCU; + } private: void parseImpl(DWARFContext &Context, const DWARFSection &Section, const DWARFDebugAbbrev *DA, const DWARFSection *RS, StringRef SS, const DWARFSection &SOS, const DWARFSection *AOS, - const DWARFSection &LS, bool LE, bool IsDWO) override { + const DWARFSection &LS, bool LE, bool IsDWO, + bool Lazy) override { if (Parsed) return; - const auto &Index = getDWARFUnitIndex(Context, UnitType::Section); DataExtractor Data(Section.Data, LE, 0); + if (!Parser) { + const DWARFUnitIndex *Index = nullptr; + if (IsDWO) + Index = &getDWARFUnitIndex(Context, UnitType::Section); + Parser = [=, &Context, &Section, &SOS, + &LS](uint32_t Offset) -> std::unique_ptr<UnitType> { + if (!Data.isValidOffset(Offset)) + return nullptr; + auto U = llvm::make_unique<UnitType>( + Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO, *this, + Index ? Index->getFromOffset(Offset) : nullptr); + if (!U->extract(Data, &Offset)) + return nullptr; + return U; + }; + } + if (Lazy) + return; + auto I = this->begin(); uint32_t Offset = 0; while (Data.isValidOffset(Offset)) { - auto U = llvm::make_unique<UnitType>(Context, Section, DA, RS, SS, SOS, - AOS, LS, LE, IsDWO, *this, - Index.getFromOffset(Offset)); - if (!U->extract(Data, &Offset)) + if (I != this->end() && (*I)->getOffset() == Offset) { + ++I; + continue; + } + auto U = Parser(Offset); + if (!U) break; - this->push_back(std::move(U)); - Offset = this->back()->getNextUnitOffset(); + Offset = U->getNextUnitOffset(); + I = std::next(this->insert(I, std::move(U))); } Parsed = true; } }; +/// Represents base address of the CU. +struct BaseAddress { + uint64_t Address; + uint64_t SectionIndex; +}; + class DWARFUnit { DWARFContext &Context; /// Section containing this DWARFUnit. @@ -123,7 +178,7 @@ class DWARFUnit { const DWARFSection &StringOffsetSection; uint64_t StringOffsetSectionBase = 0; const DWARFSection *AddrOffsetSection; - uint32_t AddrOffsetSectionBase; + uint32_t AddrOffsetSectionBase = 0; bool isLittleEndian; bool isDWO; const DWARFUnitSectionBase &UnitSection; @@ -133,9 +188,10 @@ class DWARFUnit { uint32_t Offset; uint32_t Length; - const DWARFAbbreviationDeclarationSet *Abbrevs; + mutable const DWARFAbbreviationDeclarationSet *Abbrevs; + uint64_t AbbrOffset; uint8_t UnitType; - uint64_t BaseAddr; + llvm::Optional<BaseAddress> BaseAddr; /// The compile unit debug information entry items. std::vector<DWARFDebugInfoEntry> DieArray; @@ -197,19 +253,12 @@ public: bool getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const; bool getStringOffsetSectionItem(uint32_t Index, uint64_t &Result) const; - DWARFDataExtractor getDebugInfoExtractor() const { - return DWARFDataExtractor(InfoSection, isLittleEndian, - getAddressByteSize()); - } + DWARFDataExtractor getDebugInfoExtractor() const; DataExtractor getStringExtractor() const { return DataExtractor(StringSection, false, 0); } - const RelocAddrMap *getRelocMap() const { return &InfoSection.Relocs; } - const RelocAddrMap &getStringOffsetsRelocMap() const { - return StringOffsetSection.Relocs; - } bool extract(DataExtractor debug_info, uint32_t* offset_ptr); @@ -232,18 +281,25 @@ public: return FormParams.getDwarfOffsetByteSize(); } - const DWARFAbbreviationDeclarationSet *getAbbreviations() const { - return Abbrevs; - } + const DWARFAbbreviationDeclarationSet *getAbbreviations() const; uint8_t getUnitType() const { return UnitType; } - static bool isValidUnitType(uint8_t UnitType) { - return UnitType == dwarf::DW_UT_compile || UnitType == dwarf::DW_UT_type || - UnitType == dwarf::DW_UT_partial || - UnitType == dwarf::DW_UT_skeleton || - UnitType == dwarf::DW_UT_split_compile || - UnitType == dwarf::DW_UT_split_type; + static bool isMatchingUnitTypeAndTag(uint8_t UnitType, dwarf::Tag Tag) { + switch (UnitType) { + case dwarf::DW_UT_compile: + return Tag == dwarf::DW_TAG_compile_unit; + case dwarf::DW_UT_type: + return Tag == dwarf::DW_TAG_type_unit; + case dwarf::DW_UT_partial: + return Tag == dwarf::DW_TAG_partial_unit; + case dwarf::DW_UT_skeleton: + return Tag == dwarf::DW_TAG_skeleton_unit; + case dwarf::DW_UT_split_compile: + case dwarf::DW_UT_split_type: + return dwarf::isUnitType(Tag); + } + return false; } /// \brief Return the number of bytes for the header of a unit of @@ -266,11 +322,9 @@ public: llvm_unreachable("Invalid UnitType."); } - uint64_t getBaseAddress() const { return BaseAddr; } + llvm::Optional<BaseAddress> getBaseAddress() const { return BaseAddr; } - void setBaseAddress(uint64_t base_addr) { - BaseAddr = base_addr; - } + void setBaseAddress(BaseAddress BaseAddr) { this->BaseAddr = BaseAddr; } DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { extractDIEsIfNeeded(ExtractUnitDIEOnly); @@ -284,6 +338,11 @@ public: void collectAddressRanges(DWARFAddressRangesVector &CURanges); + /// Returns subprogram DIE with address range encompassing the provided + /// address. The pointer is alive as long as parsed compile unit DIEs are not + /// cleared. + DWARFDie getSubroutineForAddress(uint64_t Address); + /// getInlinedChainForAddress - fetches inlined chain for a given address. /// Returns empty chain if there is no subprogram containing address. The /// chain is valid as long as parsed compile unit DIEs are not cleared. @@ -318,6 +377,7 @@ public: DWARFDie getParent(const DWARFDebugInfoEntry *Die); DWARFDie getSibling(const DWARFDebugInfoEntry *Die); + DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die); /// \brief Return the DIE object for a given offset inside the /// unit's DIE vector. @@ -366,11 +426,6 @@ private: /// parseDWO - Parses .dwo file for current compile unit. Returns true if /// it was actually constructed. bool parseDWO(); - - /// getSubroutineForAddress - Returns subprogram DIE with address range - /// encompassing the provided address. The pointer is alive as long as parsed - /// compile unit DIEs are not cleared. - DWARFDie getSubroutineForAddress(uint64_t Address); }; } // end namespace llvm diff --git a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h index 8e2ce023695bf..49ed4bb222f3f 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h +++ b/include/llvm/DebugInfo/DWARF/DWARFUnitIndex.h @@ -83,9 +83,13 @@ public: DWARFUnitIndex(DWARFSectionKind InfoColumnKind) : InfoColumnKind(InfoColumnKind) {} + explicit operator bool() const { return Header.NumBuckets; } + bool parse(DataExtractor IndexData); void dump(raw_ostream &OS) const; + const Entry *getFromOffset(uint32_t Offset) const; + const Entry *getFromHash(uint64_t Offset) const; ArrayRef<DWARFSectionKind> getColumnKinds() const { return makeArrayRef(ColumnKinds.get(), Header.NumColumns); diff --git a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h index c0291a83ed973..0d920abe32315 100644 --- a/include/llvm/DebugInfo/DWARF/DWARFVerifier.h +++ b/include/llvm/DebugInfo/DWARF/DWARFVerifier.h @@ -10,6 +10,10 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" + #include <cstdint> #include <map> #include <set> @@ -22,17 +26,91 @@ class DWARFDie; class DWARFUnit; class DWARFAcceleratorTable; class DWARFDataExtractor; +class DWARFDebugAbbrev; +class DataExtractor; +struct DWARFSection; /// A class that verifies DWARF debug information given a DWARF Context. class DWARFVerifier { +public: + /// A class that keeps the address range information for a single DIE. + struct DieRangeInfo { + DWARFDie Die; + + /// Sorted DWARFAddressRanges. + std::vector<DWARFAddressRange> Ranges; + + /// Sorted DWARFAddressRangeInfo. + std::set<DieRangeInfo> Children; + + DieRangeInfo() = default; + DieRangeInfo(DWARFDie Die) : Die(Die) {} + + /// Used for unit testing. + DieRangeInfo(std::vector<DWARFAddressRange> Ranges) + : Ranges(std::move(Ranges)) {} + + typedef std::vector<DWARFAddressRange>::const_iterator + address_range_iterator; + typedef std::set<DieRangeInfo>::const_iterator die_range_info_iterator; + + /// Inserts the address range. If the range overlaps with an existing + /// range, the range is *not* added and an iterator to the overlapping + /// range is returned. + /// + /// This is used for finding overlapping ranges within the same DIE. + address_range_iterator insert(const DWARFAddressRange &R); + + /// Finds an address range in the sorted vector of ranges. + address_range_iterator findRange(const DWARFAddressRange &R) const { + auto Begin = Ranges.begin(); + auto End = Ranges.end(); + auto Iter = std::upper_bound(Begin, End, R); + if (Iter != Begin) + --Iter; + return Iter; + } + + /// Inserts the address range info. If any of its ranges overlaps with a + /// range in an existing range info, the range info is *not* added and an + /// iterator to the overlapping range info. + /// + /// This is used for finding overlapping children of the same DIE. + die_range_info_iterator insert(const DieRangeInfo &RI); + + /// Return true if ranges in this object contains all ranges within RHS. + bool contains(const DieRangeInfo &RHS) const; + + /// Return true if any range in this object intersects with any range in + /// RHS. + bool intersects(const DieRangeInfo &RHS) const; + }; + +private: raw_ostream &OS; DWARFContext &DCtx; + DIDumpOptions DumpOpts; /// A map that tracks all references (converted absolute references) so we /// can verify each reference points to a valid DIE and not an offset that /// lies between to valid DIEs. std::map<uint64_t, std::set<uint32_t>> ReferenceToDIEOffsets; uint32_t NumDebugLineErrors = 0; - uint32_t NumAppleNamesErrors = 0; + + raw_ostream &error() const; + raw_ostream &warn() const; + raw_ostream ¬e() const; + + /// Verifies the abbreviations section. + /// + /// This function currently checks that: + /// --No abbreviation declaration has more than one attributes with the same + /// name. + /// + /// \param Abbrev Pointer to the abbreviations section we are verifying + /// Abbrev can be a pointer to either .debug_abbrev or debug_abbrev.dwo. + /// + /// \returns The number of errors that occured during verification. + unsigned verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev); /// Verifies the header of a unit in the .debug_info section. /// @@ -58,8 +136,31 @@ class DWARFVerifier { uint32_t *Offset, unsigned UnitIndex, uint8_t &UnitType, bool &isUnitDWARF64); + /// Verifies the header of a unit in the .debug_info section. + /// + /// This function currently verifies: + /// - The debug info attributes. + /// - The debug info form=s. + /// - The presence of a root DIE. + /// - That the root DIE is a unit DIE. + /// - If a unit type is provided, that the unit DIE matches the unit type. + /// - The DIE ranges. + /// + /// \param Unit The DWARF Unit to verifiy. + /// \param UnitType An optional unit type which will be used to verify the + /// type of the unit DIE. + /// + /// \returns true if the content is verified successfully, false otherwise. + bool verifyUnitContents(DWARFUnit Unit, uint8_t UnitType = 0); + + /// Verify that all Die ranges are valid. + /// + /// This function currently checks for: + /// - cases in which lowPC >= highPC + /// + /// \returns Number of errors that occured during verification. + unsigned verifyDieRanges(const DWARFDie &Die, DieRangeInfo &ParentRI); - bool verifyUnitContents(DWARFUnit Unit); /// Verifies the attribute's DWARF attribute and its value. /// /// This function currently checks for: @@ -111,9 +212,40 @@ class DWARFVerifier { /// - invalid file indexes void verifyDebugLineRows(); + /// Verify that an Apple-style accelerator table is valid. + /// + /// This function currently checks that: + /// - The fixed part of the header fits in the section + /// - The size of the section is as large as what the header describes + /// - There is at least one atom + /// - The form for each atom is valid + /// - The tag for each DIE in the table is valid + /// - The buckets have a valid index, or they are empty + /// - Each hashdata offset is valid + /// - Each DIE is valid + /// + /// \param AccelSection pointer to the section containing the acceleration table + /// \param StrData pointer to the string section + /// \param SectionName the name of the table we're verifying + /// + /// \returns The number of errors occured during verification + unsigned verifyAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, const char *SectionName); + public: - DWARFVerifier(raw_ostream &S, DWARFContext &D) - : OS(S), DCtx(D) {} + DWARFVerifier(raw_ostream &S, DWARFContext &D, + DIDumpOptions DumpOpts = DIDumpOptions::getForSingleDIE()) + : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)) {} + /// Verify the information in any of the following sections, if available: + /// .debug_abbrev, debug_abbrev.dwo + /// + /// Any errors are reported to the stream that was this object was + /// constructed with. + /// + /// \returns true if .debug_abbrev and .debug_abbrev.dwo verify successfully, + /// false otherwise. + bool handleDebugAbbrev(); + /// Verify the information in the .debug_info section. /// /// Any errors are reported to the stream that was this object was @@ -130,15 +262,21 @@ public: /// \returns true if the .debug_line verifies successfully, false otherwise. bool handleDebugLine(); - /// Verify the information in the .apple_names accelerator table. + /// Verify the information in accelerator tables, if they exist. /// /// Any errors are reported to the stream that was this object was /// constructed with. /// - /// \returns true if the .apple_names verifies successfully, false otherwise. - bool handleAppleNames(); + /// \returns true if the existing Apple-style accelerator tables verify + /// successfully, false otherwise. + bool handleAccelTables(); }; +static inline bool operator<(const DWARFVerifier::DieRangeInfo &LHS, + const DWARFVerifier::DieRangeInfo &RHS) { + return std::tie(LHS.Ranges, LHS.Die) < std::tie(RHS.Ranges, RHS.Die); +} + } // end namespace llvm #endif // LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H diff --git a/include/llvm/DebugInfo/MSF/MSFBuilder.h b/include/llvm/DebugInfo/MSF/MSFBuilder.h index b2c8f2d1c20da..19e5c31b30764 100644 --- a/include/llvm/DebugInfo/MSF/MSFBuilder.h +++ b/include/llvm/DebugInfo/MSF/MSFBuilder.h @@ -128,7 +128,6 @@ private: uint32_t FreePageMap; uint32_t Unknown1 = 0; uint32_t BlockSize; - uint32_t MininumBlocks; uint32_t BlockMapAddr; BitVector FreeBlocks; std::vector<uint32_t> DirectoryBlocks; diff --git a/include/llvm/DebugInfo/MSF/MSFCommon.h b/include/llvm/DebugInfo/MSF/MSFCommon.h index eca1b8b89ebd8..f28415d4e6034 100644 --- a/include/llvm/DebugInfo/MSF/MSFCommon.h +++ b/include/llvm/DebugInfo/MSF/MSFCommon.h @@ -59,6 +59,25 @@ struct MSFLayout { std::vector<ArrayRef<support::ulittle32_t>> StreamMap; }; +/// \brief Describes the layout of a stream in an MSF layout. A "stream" here +/// is defined as any logical unit of data which may be arranged inside the MSF +/// file as a sequence of (possibly discontiguous) blocks. When we want to read +/// from a particular MSF Stream, we fill out a stream layout structure and the +/// reader uses it to determine which blocks in the underlying MSF file contain +/// the data, so that it can be pieced together in the right order. +class MSFStreamLayout { +public: + uint32_t Length; + std::vector<support::ulittle32_t> Blocks; +}; + +/// \brief Determine the layout of the FPM stream, given the MSF layout. An FPM +/// stream spans 1 or more blocks, each at equally spaced intervals throughout +/// the file. +MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf, + bool IncludeUnusedFpmData = false, + bool AltFpm = false); + inline bool isValidBlockSize(uint32_t Size) { switch (Size) { case 512: @@ -78,7 +97,7 @@ inline uint32_t getMinimumBlockCount() { return 4; } inline uint32_t getFirstUnreservedBlock() { return 3; } inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { - return alignTo(NumBytes, BlockSize) / BlockSize; + return divideCeil(NumBytes, BlockSize); } inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { @@ -89,13 +108,14 @@ inline uint32_t getFpmIntervalLength(const MSFLayout &L) { return L.SB->BlockSize; } -inline uint32_t getNumFpmIntervals(const MSFLayout &L) { - uint32_t Length = getFpmIntervalLength(L); - return alignTo(L.SB->NumBlocks, Length) / Length; -} +inline uint32_t getNumFpmIntervals(const MSFLayout &L, + bool IncludeUnusedFpmData = false) { + if (IncludeUnusedFpmData) + return divideCeil(L.SB->NumBlocks, L.SB->BlockSize); -inline uint32_t getFullFpmByteSize(const MSFLayout &L) { - return alignTo(L.SB->NumBlocks, 8) / 8; + // We want the minimum number of intervals required, where each interval can + // represent BlockSize * 8 blocks. + return divideCeil(L.SB->NumBlocks, 8 * L.SB->BlockSize); } Error validateSuperBlock(const SuperBlock &SB); diff --git a/include/llvm/DebugInfo/MSF/MSFStreamLayout.h b/include/llvm/DebugInfo/MSF/MSFStreamLayout.h deleted file mode 100644 index bdde98f526629..0000000000000 --- a/include/llvm/DebugInfo/MSF/MSFStreamLayout.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- MSFStreamLayout.h - Describes the layout of a stream -----*- 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_MSF_MSFSTREAMLAYOUT_H -#define LLVM_DEBUGINFO_MSF_MSFSTREAMLAYOUT_H - -#include "llvm/Support/Endian.h" - -#include <cstdint> -#include <vector> - -namespace llvm { -namespace msf { - -/// \brief Describes the layout of a stream in an MSF layout. A "stream" here -/// is defined as any logical unit of data which may be arranged inside the MSF -/// file as a sequence of (possibly discontiguous) blocks. When we want to read -/// from a particular MSF Stream, we fill out a stream layout structure and the -/// reader uses it to determine which blocks in the underlying MSF file contain -/// the data, so that it can be pieced together in the right order. -class MSFStreamLayout { -public: - uint32_t Length; - std::vector<support::ulittle32_t> Blocks; -}; -} // namespace msf -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_MSFSTREAMLAYOUT_H diff --git a/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/include/llvm/DebugInfo/MSF/MappedBlockStream.h index 6d88d2be85c9b..f65e52922da77 100644 --- a/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ b/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -12,7 +12,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/DebugInfo/MSF/MSFStreamLayout.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryStream.h" #include "llvm/Support/BinaryStreamRef.h" @@ -122,7 +122,7 @@ public: static std::unique_ptr<WritableMappedBlockStream> createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, - BumpPtrAllocator &Allocator); + BumpPtrAllocator &Allocator, bool AltFpm = false); support::endianness getEndian() const override { return support::little; diff --git a/include/llvm/DebugInfo/PDB/DIA/DIAEnumTables.h b/include/llvm/DebugInfo/PDB/DIA/DIAEnumTables.h new file mode 100644 index 0000000000000..926fcfe696481 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIAEnumTables.h @@ -0,0 +1,37 @@ +//===- DIAEnumTables.h - DIA Tables Enumerator Impl -------------*- 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_PDB_DIA_DIAENUMTABLES_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAENUMTABLES_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBTable.h" + +namespace llvm { +namespace pdb { +class IPDBTable; + +class DIAEnumTables : public IPDBEnumChildren<IPDBTable> { +public: + explicit DIAEnumTables(CComPtr<IDiaEnumTables> DiaEnumerator); + + uint32_t getChildCount() const override; + std::unique_ptr<IPDBTable> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<IPDBTable> getNext() override; + void reset() override; + DIAEnumTables *clone() const override; + +private: + CComPtr<IDiaEnumTables> Enumerator; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIAENUMTABLES_H diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index d37b48540ffa2..2d6c44905ce08 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -96,6 +96,7 @@ public: uint32_t getTypeId() const override; uint32_t getUavSlot() const override; std::string getUndecoratedName() const override; + std::string getUndecoratedNameEx(PDB_UndnameFlags Flags) const override; uint32_t getUnmodifiedTypeId() const override; uint32_t getUpperBoundId() const override; Variant getValue() const override; diff --git a/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 350442556bef8..66bd7a7e9c4e6 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -64,6 +64,7 @@ public: std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override; + std::unique_ptr<IPDBEnumTables> getEnumTables() const override; private: CComPtr<IDiaSession> Session; }; diff --git a/include/llvm/DebugInfo/PDB/DIA/DIATable.h b/include/llvm/DebugInfo/PDB/DIA/DIATable.h new file mode 100644 index 0000000000000..ce93fa0b86c34 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/DIA/DIATable.h @@ -0,0 +1,32 @@ +//===- DIATable.h - DIA implementation of IPDBTable -------------*- 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_PDB_DIA_DIATABLE_H +#define LLVM_DEBUGINFO_PDB_DIA_DIATABLE_H + +#include "DIASupport.h" +#include "llvm/DebugInfo/PDB/IPDBTable.h" + +namespace llvm { +namespace pdb { +class DIATable : public IPDBTable { +public: + explicit DIATable(CComPtr<IDiaTable> DiaTable); + + uint32_t getItemCount() const override; + std::string getName() const override; + PDB_TableType getTableType() const override; + +private: + CComPtr<IDiaTable> Table; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_DIA_DIATABLE_H diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index eefc365187288..18b9423378a02 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -108,6 +108,7 @@ public: virtual uint32_t getTypeId() const = 0; virtual uint32_t getUavSlot() const = 0; virtual std::string getUndecoratedName() const = 0; + virtual std::string getUndecoratedNameEx(PDB_UndnameFlags Flags) const = 0; virtual uint32_t getUnmodifiedTypeId() const = 0; virtual uint32_t getUpperBoundId() const = 0; virtual Variant getValue() const = 0; diff --git a/include/llvm/DebugInfo/PDB/IPDBSession.h b/include/llvm/DebugInfo/PDB/IPDBSession.h index cf195095c8d22..6291289de5bfb 100644 --- a/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -67,6 +67,8 @@ public: getSourceFileById(uint32_t FileId) const = 0; virtual std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const = 0; + + virtual std::unique_ptr<IPDBEnumTables> getEnumTables() const = 0; }; } } diff --git a/include/llvm/DebugInfo/PDB/IPDBTable.h b/include/llvm/DebugInfo/PDB/IPDBTable.h new file mode 100644 index 0000000000000..4561c4e847b2b --- /dev/null +++ b/include/llvm/DebugInfo/PDB/IPDBTable.h @@ -0,0 +1,28 @@ +//===- IPDBTable.h - Base Interface for a PDB Symbol Context ----*- 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_PDB_IPDBTABLE_H +#define LLVM_DEBUGINFO_PDB_IPDBTABLE_H + +#include "PDBTypes.h" + +namespace llvm { +namespace pdb { +class IPDBTable { +public: + virtual ~IPDBTable(); + + virtual std::string getName() const = 0; + virtual uint32_t getItemCount() const = 0; + virtual PDB_TableType getTableType() const = 0; +}; +} +} + +#endif // LLVM_DEBUGINFO_PDB_IPDBTABLE_H diff --git a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h index 63eb34f0326af..ad4a0d1bcb6bf 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -59,11 +59,11 @@ public: uint32_t calculateSerializedLength() const; + void setGlobalsStreamIndex(uint32_t Index); void setPublicsStreamIndex(uint32_t Index); void setSymbolRecordStreamIndex(uint32_t Index); Expected<DbiModuleDescriptorBuilder &> addModuleInfo(StringRef ModuleName); - Error addModuleSourceFile(StringRef Module, StringRef File); Error addModuleSourceFile(DbiModuleDescriptorBuilder &Module, StringRef File); Expected<uint32_t> getSourceFileNameIndex(StringRef FileName); @@ -71,8 +71,9 @@ public: Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef MsfBuffer); - void addSectionContrib(DbiModuleDescriptorBuilder *ModuleDbi, - const llvm::object::coff_section *SecHdr); + void addSectionContrib(const SectionContrib &SC) { + SectionContribs.emplace_back(SC); + } // A helper function to create a Section Map from a COFF section header. static std::vector<SecMapEntry> @@ -105,13 +106,13 @@ private: uint16_t PdbDllRbld; uint16_t Flags; PDB_Machine MachineType; + uint32_t GlobalsStreamIndex = kInvalidStreamIndex; uint32_t PublicsStreamIndex = kInvalidStreamIndex; uint32_t SymRecordStreamIndex = kInvalidStreamIndex; const DbiStreamHeader *Header; - StringMap<std::unique_ptr<DbiModuleDescriptorBuilder>> ModiMap; - std::vector<DbiModuleDescriptorBuilder *> ModiList; + std::vector<std::unique_ptr<DbiModuleDescriptorBuilder>> ModiList; StringMap<uint32_t> SourceFileNames; diff --git a/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h new file mode 100644 index 0000000000000..1a4f89d607dff --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h @@ -0,0 +1,82 @@ +//===- GSIStreamBuilder.h - PDB Publics/Globals Stream Creation -*- 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_PDB_RAW_GSISTREAMBUILDER_H +#define LLVM_DEBUGINFO_PDB_RAW_GSISTREAMBUILDER_H + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { + +template <> struct BinaryItemTraits<codeview::CVSymbol> { + static size_t length(const codeview::CVSymbol &Item) { + return Item.RecordData.size(); + } + static ArrayRef<uint8_t> bytes(const codeview::CVSymbol &Item) { + return Item.RecordData; + } +}; + +namespace msf { +class MSFBuilder; +struct MSFLayout; +} // namespace msf +namespace pdb { +struct GSIHashStreamBuilder; + +class GSIStreamBuilder { + +public: + explicit GSIStreamBuilder(msf::MSFBuilder &Msf); + ~GSIStreamBuilder(); + + GSIStreamBuilder(const GSIStreamBuilder &) = delete; + GSIStreamBuilder &operator=(const GSIStreamBuilder &) = delete; + + Error finalizeMsfLayout(); + + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); + + uint32_t getPublicsStreamIndex() const; + uint32_t getGlobalsStreamIndex() const; + uint32_t getRecordStreamIdx() const { return RecordStreamIdx; } + + void addPublicSymbol(const codeview::PublicSym32 &Pub); + + void addGlobalSymbol(const codeview::ProcRefSym &Sym); + void addGlobalSymbol(const codeview::DataSym &Sym); + void addGlobalSymbol(const codeview::ConstantSym &Sym); + void addGlobalSymbol(const codeview::UDTSym &Sym); + void addGlobalSymbol(const codeview::CVSymbol &Sym); + +private: + uint32_t calculatePublicsHashStreamSize() const; + uint32_t calculateGlobalsHashStreamSize() const; + Error commitSymbolRecordStream(WritableBinaryStreamRef Stream); + Error commitPublicsHashStream(WritableBinaryStreamRef Stream); + Error commitGlobalsHashStream(WritableBinaryStreamRef Stream); + + uint32_t RecordStreamIdx = kInvalidStreamIndex; + msf::MSFBuilder &Msf; + std::unique_ptr<GSIHashStreamBuilder> PSH; + std::unique_ptr<GSIHashStreamBuilder> GSH; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h b/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h index dcea3d3be0ab8..fdc58dc60f7e0 100644 --- a/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h +++ b/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h @@ -1,4 +1,4 @@ -//===- GlobalsStream.h - PDB Index of Symbols by Name ------ ----*- C++ -*-===// +//===- GlobalsStream.h - PDB Index of Symbols by Name -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,27 +16,66 @@ #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Error.h" +#include "llvm/ADT/iterator.h" namespace llvm { namespace pdb { class DbiStream; class PDBFile; +/// Iterator over hash records producing symbol record offsets. Abstracts away +/// the fact that symbol record offsets on disk are off-by-one. +class GSIHashIterator + : public iterator_adaptor_base< + GSIHashIterator, FixedStreamArrayIterator<PSHashRecord>, + std::random_access_iterator_tag, const uint32_t> { +public: + GSIHashIterator() = default; + + template <typename T> + GSIHashIterator(T &&v) + : GSIHashIterator::iterator_adaptor_base(std::forward<T &&>(v)) {} + + uint32_t operator*() const { + uint32_t Off = this->I->Off; + return --Off; + } +}; + +/// From https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp +enum : unsigned { IPHR_HASH = 4096 }; + +/// A readonly view of a hash table used in the globals and publics streams. +/// Most clients will only want to iterate this to get symbol record offsets +/// into the PDB symbol stream. +class GSIHashTable { +public: + const GSIHashHeader *HashHdr; + FixedStreamArray<PSHashRecord> HashRecords; + ArrayRef<uint8_t> HashBitmap; + FixedStreamArray<support::ulittle32_t> HashBuckets; + + Error read(BinaryStreamReader &Reader); + + uint32_t getVerSignature() const { return HashHdr->VerSignature; } + uint32_t getVerHeader() const { return HashHdr->VerHdr; } + uint32_t getHashRecordSize() const { return HashHdr->HrSize; } + uint32_t getNumBuckets() const { return HashHdr->NumBuckets; } + + typedef GSIHashHeader iterator; + GSIHashIterator begin() const { return GSIHashIterator(HashRecords.begin()); } + GSIHashIterator end() const { return GSIHashIterator(HashRecords.end()); } +}; + class GlobalsStream { public: explicit GlobalsStream(std::unique_ptr<msf::MappedBlockStream> Stream); ~GlobalsStream(); - Error commit(); - FixedStreamArray<support::ulittle32_t> getHashBuckets() const { - return HashBuckets; - } - uint32_t getNumBuckets() const { return NumBuckets; } + const GSIHashTable &getGlobalsTable() const { return GlobalsTable; } Error reload(); private: - FixedStreamArray<support::ulittle32_t> HashBuckets; - FixedStreamArray<PSHashRecord> HashRecords; - uint32_t NumBuckets; + GSIHashTable GlobalsTable; std::unique_ptr<msf::MappedBlockStream> Stream; }; } diff --git a/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h b/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h index f413fd1b336ec..6602264d1b747 100644 --- a/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h +++ b/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h @@ -32,6 +32,7 @@ public: ModuleDebugStreamRef(const DbiModuleDescriptor &Module, std::unique_ptr<msf::MappedBlockStream> Stream); ModuleDebugStreamRef(ModuleDebugStreamRef &&Other) = default; + ModuleDebugStreamRef(const ModuleDebugStreamRef &Other) = default; ~ModuleDebugStreamRef(); Error reload(); @@ -51,6 +52,9 @@ public: ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = default; iterator_range<DebugSubsectionIterator> subsections() const; + codeview::DebugSubsectionArray getSubsectionsArray() const { + return Subsections; + } bool hasDebugSubsections() const; diff --git a/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h new file mode 100644 index 0000000000000..41b7b78b8d80a --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeEnumSymbol.h @@ -0,0 +1,60 @@ +//===- NativeEnumSymbol.h - info about enum type ----------------*- 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_PDB_NATIVE_NATIVEENUMSYMBOL_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOL_H + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +namespace llvm { +namespace pdb { + +class NativeEnumSymbol : public NativeRawSymbol, + public codeview::TypeVisitorCallbacks { +public: + NativeEnumSymbol(NativeSession &Session, SymIndexId Id, + const codeview::CVType &CV); + ~NativeEnumSymbol() override; + + std::unique_ptr<NativeRawSymbol> clone() const override; + + std::unique_ptr<IPDBEnumSymbols> + findChildren(PDB_SymType Type) const override; + + Error visitKnownRecord(codeview::CVType &CVR, + codeview::EnumRecord &Record) override; + Error visitKnownMember(codeview::CVMemberRecord &CVM, + codeview::EnumeratorRecord &Record) override; + + PDB_SymType getSymTag() const override; + uint32_t getClassParentId() const override; + uint32_t getUnmodifiedTypeId() const override; + bool hasConstructor() const override; + bool hasAssignmentOperator() const override; + bool hasCastOperator() const override; + uint64_t getLength() const override; + std::string getName() const override; + bool isNested() const override; + bool hasOverloadedOperator() const override; + bool isPacked() const override; + bool isScoped() const override; + uint32_t getTypeId() const override; + +protected: + codeview::CVType CV; + codeview::EnumRecord Record; +}; + +} // namespace pdb +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMSYMBOL_H diff --git a/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h b/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h new file mode 100644 index 0000000000000..e0a5c8d9ad814 --- /dev/null +++ b/include/llvm/DebugInfo/PDB/Native/NativeEnumTypes.h @@ -0,0 +1,51 @@ +//==- NativeEnumTypes.h - Native Type Enumerator impl ------------*- 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_PDB_NATIVE_NATIVEENUMTYPES_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMTYPES_H + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <vector> + +namespace llvm { +namespace pdb { + +class NativeSession; + +class NativeEnumTypes : public IPDBEnumChildren<PDBSymbol> { +public: + NativeEnumTypes(NativeSession &Session, + codeview::LazyRandomTypeCollection &TypeCollection, + codeview::TypeLeafKind Kind); + + uint32_t getChildCount() const override; + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<PDBSymbol> getNext() override; + void reset() override; + NativeEnumTypes *clone() const override; + +private: + NativeEnumTypes(NativeSession &Session, + const std::vector<codeview::TypeIndex> &Matches, + codeview::TypeLeafKind Kind); + + std::vector<codeview::TypeIndex> Matches; + uint32_t Index; + NativeSession &Session; + codeview::TypeLeafKind Kind; +}; + +} // namespace pdb +} // namespace llvm + +#endif diff --git a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h index 2c6548dcce21f..931b93fb7266c 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -101,6 +101,7 @@ public: uint32_t getTypeId() const override; uint32_t getUavSlot() const override; std::string getUndecoratedName() const override; + std::string getUndecoratedNameEx(PDB_UndnameFlags Flags) const override; uint32_t getUnmodifiedTypeId() const override; uint32_t getUpperBoundId() const override; Variant getValue() const override; diff --git a/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/include/llvm/DebugInfo/PDB/Native/NativeSession.h index b16ce231c349c..2e68ced46bfe8 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeSession.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -22,6 +22,7 @@ #include "llvm/Support/Error.h" namespace llvm { +class MemoryBuffer; namespace pdb { class PDBFile; @@ -31,7 +32,7 @@ public: std::unique_ptr<BumpPtrAllocator> Allocator); ~NativeSession() override; - static Error createFromPdb(StringRef Path, + static Error createFromPdb(std::unique_ptr<MemoryBuffer> MB, std::unique_ptr<IPDBSession> &Session); static Error createFromExe(StringRef Path, std::unique_ptr<IPDBSession> &Session); @@ -39,6 +40,12 @@ public: std::unique_ptr<PDBSymbolCompiland> createCompilandSymbol(DbiModuleDescriptor MI); + std::unique_ptr<PDBSymbolTypeEnum> + createEnumSymbol(codeview::TypeIndex Index); + + std::unique_ptr<IPDBEnumSymbols> + createTypeEnumerator(codeview::TypeLeafKind Kind); + SymIndexId findSymbolByTypeIndex(codeview::TypeIndex TI); uint64_t getLoadAddress() const override; @@ -76,6 +83,8 @@ public: std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override; + std::unique_ptr<IPDBEnumTables> getEnumTables() const override; + PDBFile &getPDBFile() { return *Pdb; } const PDBFile &getPDBFile() const { return *Pdb; } diff --git a/include/llvm/DebugInfo/PDB/Native/PDBFile.h b/include/llvm/DebugInfo/PDB/Native/PDBFile.h index 4f6ad115e7dfd..5e39ac3e37b72 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -13,7 +13,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MSFStreamLayout.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" @@ -62,6 +61,7 @@ public: uint64_t getBlockMapOffset() const; uint32_t getNumStreams() const override; + uint32_t getMaxStreamSize() const; uint32_t getStreamByteSize(uint32_t StreamIndex) const override; ArrayRef<support::ulittle32_t> getStreamBlockList(uint32_t StreamIndex) const override; @@ -72,8 +72,6 @@ public: Error setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef<uint8_t> Data) const override; - ArrayRef<uint32_t> getFpmPages() const { return FpmPages; } - ArrayRef<support::ulittle32_t> getStreamSizes() const { return ContainerLayout.StreamSizes; } @@ -86,7 +84,10 @@ public: ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; + std::unique_ptr<msf::MappedBlockStream> createIndexedStream(uint16_t SN); + msf::MSFStreamLayout getStreamLayout(uint32_t StreamIdx) const; + msf::MSFStreamLayout getFpmStreamLayout() const; Error parseFileHeaders(); Error parseStreamData(); @@ -104,7 +105,7 @@ public: bool hasPDBDbiStream() const; bool hasPDBGlobalsStream(); - bool hasPDBInfoStream(); + bool hasPDBInfoStream() const; bool hasPDBIpiStream() const; bool hasPDBPublicsStream(); bool hasPDBSymbolStream(); @@ -124,7 +125,6 @@ private: std::unique_ptr<BinaryStream> Buffer; - std::vector<uint32_t> FpmPages; msf::MSFLayout ContainerLayout; std::unique_ptr<GlobalsStream> Globals; diff --git a/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h index 2dc23f819d3bd..7ed164bee9ee2 100644 --- a/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h +++ b/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h @@ -31,7 +31,7 @@ class MSFBuilder; namespace pdb { class DbiStreamBuilder; class InfoStreamBuilder; -class PublicsStreamBuilder; +class GSIStreamBuilder; class TpiStreamBuilder; class PDBFileBuilder { @@ -49,7 +49,7 @@ public: TpiStreamBuilder &getTpiBuilder(); TpiStreamBuilder &getIpiBuilder(); PDBStringTableBuilder &getStringTableBuilder(); - PublicsStreamBuilder &getPublicsBuilder(); + GSIStreamBuilder &getGsiBuilder(); Error commit(StringRef Filename); @@ -59,12 +59,14 @@ public: private: Expected<msf::MSFLayout> finalizeMsfLayout(); + void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout); + BumpPtrAllocator &Allocator; std::unique_ptr<msf::MSFBuilder> Msf; std::unique_ptr<InfoStreamBuilder> Info; std::unique_ptr<DbiStreamBuilder> Dbi; - std::unique_ptr<PublicsStreamBuilder> Publics; + std::unique_ptr<GSIStreamBuilder> Gsi; std::unique_ptr<TpiStreamBuilder> Tpi; std::unique_ptr<TpiStreamBuilder> Ipi; diff --git a/include/llvm/DebugInfo/PDB/Native/PublicsStream.h b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h index 9ace826bd8f71..2d0222a9071a0 100644 --- a/include/llvm/DebugInfo/PDB/Native/PublicsStream.h +++ b/include/llvm/DebugInfo/PDB/Native/PublicsStream.h @@ -12,6 +12,7 @@ #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" @@ -26,19 +27,14 @@ class PDBFile; class PublicsStream { public: - PublicsStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream); + PublicsStream(std::unique_ptr<msf::MappedBlockStream> Stream); ~PublicsStream(); Error reload(); uint32_t getSymHash() const; - uint32_t getAddrMap() const; - uint32_t getNumBuckets() const { return NumBuckets; } - Expected<const codeview::CVSymbolArray &> getSymbolArray() const; - iterator_range<codeview::CVSymbolArray::Iterator> - getSymbols(bool *HadError) const; - FixedStreamArray<support::ulittle32_t> getHashBuckets() const { - return HashBuckets; - } + uint16_t getThunkTableSection() const; + uint32_t getThunkTableOffset() const; + const GSIHashTable &getPublicsTable() const { return PublicsTable; } FixedStreamArray<support::ulittle32_t> getAddressMap() const { return AddressMap; } @@ -49,22 +45,14 @@ public: return SectionOffsets; } - Error commit(); - private: - PDBFile &Pdb; - std::unique_ptr<msf::MappedBlockStream> Stream; - uint32_t NumBuckets = 0; - ArrayRef<uint8_t> Bitmap; - FixedStreamArray<PSHashRecord> HashRecords; - FixedStreamArray<support::ulittle32_t> HashBuckets; + GSIHashTable PublicsTable; FixedStreamArray<support::ulittle32_t> AddressMap; FixedStreamArray<support::ulittle32_t> ThunkMap; FixedStreamArray<SectionOffset> SectionOffsets; const PublicsStreamHeader *Header; - const GSIHashHeader *HashHdr; }; } } diff --git a/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h b/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h deleted file mode 100644 index 5ab57ebef53d4..0000000000000 --- a/include/llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h +++ /dev/null @@ -1,54 +0,0 @@ -//===- PublicsStreamBuilder.h - PDB Publics Stream Creation -----*- 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_PDB_RAW_PDBPUBLICSTREAMBUILDER_H -#define LLVM_DEBUGINFO_PDB_RAW_PDBPUBLICSTREAMBUILDER_H - -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamRef.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" - -namespace llvm { -namespace msf { -class MSFBuilder; -} -namespace pdb { -class PublicsStream; -struct PublicsStreamHeader; - -class PublicsStreamBuilder { -public: - explicit PublicsStreamBuilder(msf::MSFBuilder &Msf); - ~PublicsStreamBuilder(); - - PublicsStreamBuilder(const PublicsStreamBuilder &) = delete; - PublicsStreamBuilder &operator=(const PublicsStreamBuilder &) = delete; - - Error finalizeMsfLayout(); - uint32_t calculateSerializedLength() const; - - Error commit(BinaryStreamWriter &PublicsWriter); - - uint32_t getStreamIndex() const { return StreamIdx; } - uint32_t getRecordStreamIdx() const { return RecordStreamIdx; } - -private: - uint32_t StreamIdx = kInvalidStreamIndex; - uint32_t RecordStreamIdx = kInvalidStreamIndex; - std::vector<PSHashRecord> HashRecords; - msf::MSFBuilder &Msf; -}; -} // namespace pdb -} // namespace llvm - -#endif diff --git a/include/llvm/DebugInfo/PDB/Native/RawTypes.h b/include/llvm/DebugInfo/PDB/Native/RawTypes.h index b6321cbf45a82..8cc083685265a 100644 --- a/include/llvm/DebugInfo/PDB/Native/RawTypes.h +++ b/include/llvm/DebugInfo/PDB/Native/RawTypes.h @@ -23,6 +23,20 @@ struct SectionOffset { char Padding[2]; }; +/// Header of the hash tables found in the globals and publics sections. +/// Based on GSIHashHdr in +/// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h +struct GSIHashHeader { + enum : unsigned { + HdrSignature = ~0U, + HdrVersion = 0xeffe0000 + 19990810, + }; + support::ulittle32_t VerSignature; + support::ulittle32_t VerHdr; + support::ulittle32_t HrSize; + support::ulittle32_t NumBuckets; +}; + // This is HRFile. struct PSHashRecord { support::ulittle32_t Off; // Offset in the symbol record stream diff --git a/include/llvm/DebugInfo/PDB/Native/SymbolStream.h b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h index 17695f587849e..ae9f7d657b701 100644 --- a/include/llvm/DebugInfo/PDB/Native/SymbolStream.h +++ b/include/llvm/DebugInfo/PDB/Native/SymbolStream.h @@ -31,6 +31,8 @@ public: return SymbolRecords; } + codeview::CVSymbol readRecord(uint32_t Offset) const; + iterator_range<codeview::CVSymbolArray::Iterator> getSymbols(bool *HadError) const; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbol.h b/include/llvm/DebugInfo/PDB/PDBSymbol.h index 9e883d2f99a7a..04373463212b1 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEBUGINFO_PDB_IPDBSYMBOL_H -#define LLVM_DEBUGINFO_PDB_IPDBSYMBOL_H +#ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOL_H +#define LLVM_DEBUGINFO_PDB_PDBSYMBOL_H #include "ConcreteSymbolEnumerator.h" #include "IPDBRawSymbol.h" diff --git a/include/llvm/DebugInfo/PDB/PDBTypes.h b/include/llvm/DebugInfo/PDB/PDBTypes.h index 79ec7ce906d57..a6c6da37d1ccc 100644 --- a/include/llvm/DebugInfo/PDB/PDBTypes.h +++ b/include/llvm/DebugInfo/PDB/PDBTypes.h @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include <cctype> #include <cstddef> #include <cstdint> #include <cstring> @@ -24,6 +25,7 @@ namespace pdb { class IPDBDataStream; class IPDBLineNumber; class IPDBSourceFile; +class IPDBTable; class PDBSymDumper; class PDBSymbol; class PDBSymbolExe; @@ -62,6 +64,7 @@ using IPDBEnumSymbols = IPDBEnumChildren<PDBSymbol>; using IPDBEnumSourceFiles = IPDBEnumChildren<IPDBSourceFile>; using IPDBEnumDataStreams = IPDBEnumChildren<IPDBDataStream>; using IPDBEnumLineNumbers = IPDBEnumChildren<IPDBLineNumber>; +using IPDBEnumTables = IPDBEnumChildren<IPDBTable>; /// Specifies which PDB reader implementation is to be used. Only a value /// of PDB_ReaderType::DIA is currently supported, but Native is in the works. @@ -72,13 +75,16 @@ enum class PDB_ReaderType { /// An enumeration indicating the type of data contained in this table. enum class PDB_TableType { + TableInvalid = 0, Symbols, SourceFiles, LineNumbers, SectionContribs, Segments, InjectedSources, - FrameData + FrameData, + InputAssemblyFiles, + Dbg }; /// Defines flags used for enumerating child symbols. This corresponds to the @@ -241,6 +247,32 @@ enum class PDB_BuiltinType { HResult = 31 }; +/// These values correspond to the flags that can be combined to control the +/// return of an undecorated name for a C++ decorated name, and are documented +/// here: https://msdn.microsoft.com/en-us/library/kszfk0fs.aspx +enum PDB_UndnameFlags: uint32_t { + Undname_Complete = 0x0, + Undname_NoLeadingUnderscores = 0x1, + Undname_NoMsKeywords = 0x2, + Undname_NoFuncReturns = 0x4, + Undname_NoAllocModel = 0x8, + Undname_NoAllocLang = 0x10, + Undname_Reserved1 = 0x20, + Undname_Reserved2 = 0x40, + Undname_NoThisType = 0x60, + Undname_NoAccessSpec = 0x80, + Undname_NoThrowSig = 0x100, + Undname_NoMemberType = 0x200, + Undname_NoReturnUDTModel = 0x400, + Undname_32BitDecode = 0x800, + Undname_NameOnly = 0x1000, + Undname_TypeOnly = 0x2000, + Undname_HaveParams = 0x4000, + Undname_NoECSU = 0x8000, + Undname_NoIdentCharCheck = 0x10000, + Undname_NoPTR64 = 0x20000 +}; + enum class PDB_MemberAccess { Private = 1, Protected = 2, Public = 3 }; struct VersionInfo { diff --git a/include/llvm/DebugInfo/Symbolize/Symbolize.h b/include/llvm/DebugInfo/Symbolize/Symbolize.h index d98d49b24bca2..6480aef109c66 100644 --- a/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -58,9 +58,11 @@ public: } Expected<DILineInfo> symbolizeCode(const std::string &ModuleName, - uint64_t ModuleOffset); + uint64_t ModuleOffset, + StringRef DWPName = ""); Expected<DIInliningInfo> symbolizeInlinedCode(const std::string &ModuleName, - uint64_t ModuleOffset); + uint64_t ModuleOffset, + StringRef DWPName = ""); Expected<DIGlobal> symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset); void flush(); @@ -79,7 +81,7 @@ private: /// only reported once. Subsequent calls to get module info for a module that /// failed to load will return nullptr. Expected<SymbolizableModule *> - getOrCreateModuleInfo(const std::string &ModuleName); + getOrCreateModuleInfo(const std::string &ModuleName, StringRef DWPName = ""); ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj, |