diff options
Diffstat (limited to 'gnu/llvm/lib/DebugInfo/CodeView')
21 files changed, 1356 insertions, 119 deletions
diff --git a/gnu/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp b/gnu/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp new file mode 100644 index 00000000000..8828671d9be --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp @@ -0,0 +1,101 @@ +//===- AppendingTypeTableBuilder.cpp --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex AppendingTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +AppendingTypeTableBuilder::AppendingTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) {} + +AppendingTypeTableBuilder::~AppendingTypeTableBuilder() = default; + +Optional<TypeIndex> AppendingTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> AppendingTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType AppendingTypeTableBuilder::getType(TypeIndex Index) { + CVType Type; + Type.RecordData = SeenRecords[Index.toArrayIndex()]; + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(Type.RecordData.data()); + Type.Type = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); + return Type; +} + +StringRef AppendingTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool AppendingTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t AppendingTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t AppendingTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> AppendingTypeTableBuilder::records() const { + return SeenRecords; +} + +void AppendingTypeTableBuilder::reset() { SeenRecords.clear(); } + +TypeIndex +AppendingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { + TypeIndex NewTI = nextTypeIndex(); + uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size()); + memcpy(Stable, Record.data(), Record.size()); + Record = ArrayRef<uint8_t>(Stable, Record.size()); + SeenRecords.push_back(Record); + return NewTI; +} + +TypeIndex +AppendingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/gnu/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index b94bb0c80c7..0515788d85e 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/gnu/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -1,6 +1,8 @@ add_llvm_library(LLVMDebugInfoCodeView + AppendingTypeTableBuilder.cpp CodeViewError.cpp CodeViewRecordIO.cpp + ContinuationRecordBuilder.cpp CVSymbolVisitor.cpp CVTypeVisitor.cpp DebugChecksumsSubsection.cpp @@ -17,9 +19,13 @@ add_llvm_library(LLVMDebugInfoCodeView DebugSymbolsSubsection.cpp EnumTables.cpp Formatters.cpp + GlobalTypeTableBuilder.cpp LazyRandomTypeCollection.cpp Line.cpp + MergingTypeTableBuilder.cpp + RecordName.cpp RecordSerialization.cpp + SimpleTypeSerializer.cpp StringsAndChecksums.cpp SymbolRecordMapping.cpp SymbolDumper.cpp @@ -27,9 +33,8 @@ add_llvm_library(LLVMDebugInfoCodeView TypeDumpVisitor.cpp TypeIndex.cpp TypeIndexDiscovery.cpp - TypeName.cpp + TypeHashing.cpp TypeRecordMapping.cpp - TypeSerializer.cpp TypeStreamMerger.cpp TypeTableCollection.cpp diff --git a/gnu/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/gnu/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp index e0c7ef58c30..44a67743169 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp @@ -11,7 +11,6 @@ #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; diff --git a/gnu/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/gnu/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index 79b9fdefd40..a4182a3b2fa 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -9,7 +9,6 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" diff --git a/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp new file mode 100644 index 00000000000..f180fc6990f --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp @@ -0,0 +1,259 @@ +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +struct ContinuationRecord { + ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)}; + ulittle16_t Size{0}; + ulittle32_t IndexRef{0xB0C0B0C0}; +}; + +struct SegmentInjection { + SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; } + + ContinuationRecord Cont; + RecordPrefix Prefix; +}; +} // namespace + +static void addPadding(BinaryStreamWriter &Writer) { + uint32_t Align = Writer.getOffset() % 4; + if (Align == 0) + return; + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + cantFail(Writer.writeInteger(Pad)); + --PaddingBytes; + } +} + +static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST); +static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST); + +static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord); +static constexpr uint32_t MaxSegmentLength = + MaxRecordLength - ContinuationLength; + +static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) { + return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST + : LF_METHODLIST; +} + +ContinuationRecordBuilder::ContinuationRecordBuilder() + : SegmentWriter(Buffer), Mapping(SegmentWriter) {} + +ContinuationRecordBuilder::~ContinuationRecordBuilder() {} + +void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) { + assert(!Kind.hasValue()); + Kind = RecordKind; + Buffer.clear(); + SegmentWriter.setOffset(0); + SegmentOffsets.clear(); + SegmentOffsets.push_back(0); + assert(SegmentWriter.getOffset() == 0); + assert(SegmentWriter.getLength() == 0); + + const SegmentInjection *FLI = + (RecordKind == ContinuationRecordKind::FieldList) + ? &InjectFieldList + : &InjectMethodOverloadList; + const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI); + InjectedSegmentBytes = + ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection)); + + CVType Type; + Type.Type = getTypeLeafKind(RecordKind); + cantFail(Mapping.visitTypeBegin(Type)); + + // Seed the first trecord with an appropriate record prefix. + RecordPrefix Prefix; + Prefix.RecordLen = 0; + Prefix.RecordKind = Type.Type; + cantFail(SegmentWriter.writeObject(Prefix)); +} + +template <typename RecordType> +void ContinuationRecordBuilder::writeMemberType(RecordType &Record) { + assert(Kind.hasValue()); + + uint32_t OriginalOffset = SegmentWriter.getOffset(); + CVMemberRecord CVMR; + CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind()); + + // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind + // at the beginning. + cantFail(SegmentWriter.writeEnum(CVMR.Kind)); + + // Let the Mapping handle the rest. + cantFail(Mapping.visitMemberBegin(CVMR)); + cantFail(Mapping.visitKnownMember(CVMR, Record)); + cantFail(Mapping.visitMemberEnd(CVMR)); + + // Make sure it's padded to 4 bytes. + addPadding(SegmentWriter); + assert(getCurrentSegmentLength() % 4 == 0); + + // The maximum length of a single segment is 64KB minus the size to insert a + // continuation. So if we are over that, inject a continuation between the + // previous member and the member that was just written, then end the previous + // segment after the continuation and begin a new one with the just-written + // member. + if (getCurrentSegmentLength() > MaxSegmentLength) { + // We need to inject some bytes before the member we just wrote but after + // the previous member. Save off the length of the member we just wrote so + // that we can do some sanity checking on it. + uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset; + (void) MemberLength; + insertSegmentEnd(OriginalOffset); + // Since this member now becomes a new top-level record, it should have + // gotten a RecordPrefix injected, and that RecordPrefix + the member we + // just wrote should now constitute the entirety of the current "new" + // segment. + assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix)); + } + + assert(getCurrentSegmentLength() % 4 == 0); + assert(getCurrentSegmentLength() <= MaxSegmentLength); +} + +uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const { + return SegmentWriter.getOffset() - SegmentOffsets.back(); +} + +void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) { + uint32_t SegmentBegin = SegmentOffsets.back(); + (void)SegmentBegin; + assert(Offset > SegmentBegin); + assert(Offset - SegmentBegin <= MaxSegmentLength); + + // We need to make space for the continuation record. For now we can't fill + // out the length or the TypeIndex of the back-reference, but we need the + // space to at least be there. + Buffer.insert(Offset, InjectedSegmentBytes); + + uint32_t NewSegmentBegin = Offset + ContinuationLength; + uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back(); + (void) SegmentLength; + + assert(SegmentLength % 4 == 0); + assert(SegmentLength <= MaxRecordLength); + SegmentOffsets.push_back(NewSegmentBegin); + + // Seek to the end so that we can keep writing against the new segment. + SegmentWriter.setOffset(SegmentWriter.getLength()); + assert(SegmentWriter.bytesRemaining() == 0); +} + +CVType ContinuationRecordBuilder::createSegmentRecord( + uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) { + assert(OffEnd - OffBegin <= USHRT_MAX); + + MutableArrayRef<uint8_t> Data = Buffer.data(); + Data = Data.slice(OffBegin, OffEnd - OffBegin); + + CVType Type; + Type.Type = getTypeLeafKind(*Kind); + Type.RecordData = Data; + + // Write the length to the RecordPrefix, making sure it does not include + // sizeof(RecordPrefix.Length) + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data()); + assert(Prefix->RecordKind == Type.Type); + Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen); + + if (RefersTo.hasValue()) { + auto Continuation = Data.take_back(ContinuationLength); + ContinuationRecord *CR = + reinterpret_cast<ContinuationRecord *>(Continuation.data()); + assert(CR->Kind == TypeLeafKind::LF_INDEX); + assert(CR->IndexRef == 0xB0C0B0C0); + CR->IndexRef = RefersTo->getIndex(); + } + + return Type; +} + +std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) { + CVType Type; + Type.Type = getTypeLeafKind(*Kind); + cantFail(Mapping.visitTypeEnd(Type)); + + // We're now done, and we have a series of segments each beginning at an + // offset specified in the SegmentOffsets array. We now need to iterate + // over each segment and post-process them in the following two ways: + // 1) Each top-level record has a RecordPrefix whose type is either + // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0. + // Those should all be set to the correct length now. + // 2) Each continuation record has an IndexRef field which we set to the + // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex + // they want this sequence to start from, we can go through and update + // each one. + // + // Logically, the sequence of records we've built up looks like this: + // + // SegmentOffsets[0]: <Length> (Initially: uninitialized) + // SegmentOffsets[0]+2: LF_FIELDLIST + // SegmentOffsets[0]+4: Member[0] + // SegmentOffsets[0]+?: ... + // SegmentOffsets[0]+?: Member[4] + // SegmentOffsets[1]-8: LF_INDEX + // SegmentOffsets[1]-6: 0 + // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) + // + // SegmentOffsets[1]: <Length> (Initially: uninitialized) + // SegmentOffsets[1]+2: LF_FIELDLIST + // SegmentOffsets[1]+4: Member[0] + // SegmentOffsets[1]+?: ... + // SegmentOffsets[1]+?: Member[s] + // SegmentOffsets[2]-8: LF_INDEX + // SegmentOffsets[2]-6: 0 + // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) + // + // ... + // + // SegmentOffsets[N]: <Length> (Initially: uninitialized) + // SegmentOffsets[N]+2: LF_FIELDLIST + // SegmentOffsets[N]+4: Member[0] + // SegmentOffsets[N]+?: ... + // SegmentOffsets[N]+?: Member[t] + // + // And this is the way we have laid them out in the serialization buffer. But + // we cannot actually commit them to the underlying stream this way, due to + // the topological sorting requirement of a type stream (specifically, + // TypeIndex references can only point backwards, not forwards). So the + // sequence that we return to the caller contains the records in reverse + // order, which is the proper order for committing the serialized records. + + std::vector<CVType> Types; + Types.reserve(SegmentOffsets.size()); + + auto SO = makeArrayRef(SegmentOffsets); + + uint32_t End = SegmentWriter.getOffset(); + + Optional<TypeIndex> RefersTo; + for (uint32_t Offset : reverse(SO)) { + Types.push_back(createSegmentRecord(Offset, End, RefersTo)); + + End = Offset; + RefersTo = Index++; + } + + Kind.reset(); + return Types; +} + +// Explicitly instantiate the member function for each known type so that we can +// implement this in the cpp file. +#define TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \ + Name##Record &Record); +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" diff --git a/gnu/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/gnu/llvm/lib/DebugInfo/CodeView/EnumTables.cpp index 4cfb55a31b3..d8301cab165 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -33,55 +33,9 @@ static const EnumEntry<TypeLeafKind> TypeLeafNames[] = { }; static const EnumEntry<uint16_t> RegisterNames[] = { - CV_ENUM_CLASS_ENT(RegisterId, Unknown), - CV_ENUM_CLASS_ENT(RegisterId, VFrame), - CV_ENUM_CLASS_ENT(RegisterId, AL), - CV_ENUM_CLASS_ENT(RegisterId, CL), - CV_ENUM_CLASS_ENT(RegisterId, DL), - CV_ENUM_CLASS_ENT(RegisterId, BL), - CV_ENUM_CLASS_ENT(RegisterId, AH), - CV_ENUM_CLASS_ENT(RegisterId, CH), - CV_ENUM_CLASS_ENT(RegisterId, DH), - CV_ENUM_CLASS_ENT(RegisterId, BH), - CV_ENUM_CLASS_ENT(RegisterId, AX), - CV_ENUM_CLASS_ENT(RegisterId, CX), - CV_ENUM_CLASS_ENT(RegisterId, DX), - CV_ENUM_CLASS_ENT(RegisterId, BX), - CV_ENUM_CLASS_ENT(RegisterId, SP), - CV_ENUM_CLASS_ENT(RegisterId, BP), - CV_ENUM_CLASS_ENT(RegisterId, SI), - CV_ENUM_CLASS_ENT(RegisterId, DI), - CV_ENUM_CLASS_ENT(RegisterId, EAX), - CV_ENUM_CLASS_ENT(RegisterId, ECX), - CV_ENUM_CLASS_ENT(RegisterId, EDX), - CV_ENUM_CLASS_ENT(RegisterId, EBX), - CV_ENUM_CLASS_ENT(RegisterId, ESP), - CV_ENUM_CLASS_ENT(RegisterId, EBP), - CV_ENUM_CLASS_ENT(RegisterId, ESI), - CV_ENUM_CLASS_ENT(RegisterId, EDI), - CV_ENUM_CLASS_ENT(RegisterId, ES), - CV_ENUM_CLASS_ENT(RegisterId, CS), - CV_ENUM_CLASS_ENT(RegisterId, SS), - CV_ENUM_CLASS_ENT(RegisterId, DS), - CV_ENUM_CLASS_ENT(RegisterId, FS), - CV_ENUM_CLASS_ENT(RegisterId, GS), - CV_ENUM_CLASS_ENT(RegisterId, IP), - CV_ENUM_CLASS_ENT(RegisterId, RAX), - CV_ENUM_CLASS_ENT(RegisterId, RBX), - CV_ENUM_CLASS_ENT(RegisterId, RCX), - CV_ENUM_CLASS_ENT(RegisterId, RDX), - CV_ENUM_CLASS_ENT(RegisterId, RSI), - CV_ENUM_CLASS_ENT(RegisterId, RDI), - CV_ENUM_CLASS_ENT(RegisterId, RBP), - CV_ENUM_CLASS_ENT(RegisterId, RSP), - CV_ENUM_CLASS_ENT(RegisterId, R8), - CV_ENUM_CLASS_ENT(RegisterId, R9), - CV_ENUM_CLASS_ENT(RegisterId, R10), - CV_ENUM_CLASS_ENT(RegisterId, R11), - CV_ENUM_CLASS_ENT(RegisterId, R12), - CV_ENUM_CLASS_ENT(RegisterId, R13), - CV_ENUM_CLASS_ENT(RegisterId, R14), - CV_ENUM_CLASS_ENT(RegisterId, R15), +#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER }; static const EnumEntry<uint32_t> PublicSymFlagNames[] = { @@ -132,7 +86,7 @@ static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = { CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB), CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java), CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL), - CV_ENUM_ENT(SourceLanguage, HLSL), + CV_ENUM_ENT(SourceLanguage, HLSL), CV_ENUM_ENT(SourceLanguage, D), }; static const EnumEntry<uint32_t> CompileSym2FlagNames[] = { diff --git a/gnu/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp b/gnu/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp new file mode 100644 index 00000000000..3ecd684c1e3 --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp @@ -0,0 +1,127 @@ +//===- GlobalTypeTableBuilder.cpp -----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) { + SeenRecords.reserve(4096); +} + +GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default; + +Optional<TypeIndex> GlobalTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType GlobalTypeTableBuilder::getType(TypeIndex Index) { + CVType Type; + Type.RecordData = SeenRecords[Index.toArrayIndex()]; + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(Type.RecordData.data()); + Type.Type = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); + return Type; +} + +StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool GlobalTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const { + return SeenRecords; +} + +ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const { + return SeenHashes; +} + +void GlobalTypeTableBuilder::reset() { + HashedRecords.clear(); + SeenRecords.clear(); +} + +static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, + ArrayRef<uint8_t> Data) { + uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); + memcpy(Stable, Data.data(), Data.size()); + return makeArrayRef(Stable, Data.size()); +} + +TypeIndex GlobalTypeTableBuilder::insertRecordAs(GloballyHashedType Hash, + CreateRecord Create) { + auto Result = HashedRecords.try_emplace(Hash, nextTypeIndex()); + + if (Result.second) { + ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Create()); + SeenRecords.push_back(RecordData); + SeenHashes.push_back(Hash); + } + + // Update the caller's copy of Record to point a stable copy. + return Result.first->second; +} + +TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) { + GloballyHashedType GHT = + GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); + return insertRecordAs(GHT, [Record]() { return Record; }); +} + +TypeIndex +GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/gnu/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp index 5aaf3f1453a..ca8007411ca 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -13,7 +13,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/TypeName.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" @@ -58,21 +58,27 @@ LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t NumRecords) : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {} -void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) { +void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader, + uint32_t RecordCountHint) { Count = 0; PartialOffsets = PartialOffsetArray(); - BinaryStreamReader Reader(Data, support::little); - error(Reader.readArray(Types, Reader.getLength())); + error(Reader.readArray(Types, Reader.bytesRemaining())); // Clear and then resize, to make sure existing data gets destroyed. Records.clear(); Records.resize(RecordCountHint); } +void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) { + BinaryStreamReader Reader(Data, support::little); + reset(Reader, RecordCountHint); +} + void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data, uint32_t RecordCountHint) { - reset(toStringRef(Data), RecordCountHint); + BinaryStreamReader Reader(Data, support::little); + reset(Reader, RecordCountHint); } uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { @@ -83,12 +89,23 @@ uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { } CVType LazyRandomTypeCollection::getType(TypeIndex Index) { - error(ensureTypeExists(Index)); + auto EC = ensureTypeExists(Index); + error(std::move(EC)); assert(contains(Index)); return Records[Index.toArrayIndex()].Type; } +Optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) { + if (auto EC = ensureTypeExists(Index)) { + consumeError(std::move(EC)); + return None; + } + + assert(contains(Index)); + return Records[Index.toArrayIndex()].Type; +} + StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { if (Index.isNoneType() || Index.isSimple()) return TypeIndex::simpleTypeName(Index); @@ -112,6 +129,9 @@ StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { } bool LazyRandomTypeCollection::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + if (Records.size() <= Index.toArrayIndex()) return false; if (!Records[Index.toArrayIndex()].Type.valid()) diff --git a/gnu/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp b/gnu/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp new file mode 100644 index 00000000000..8aee4aa2e2a --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp @@ -0,0 +1,128 @@ +//===- MergingTypeTableBuilder.cpp ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex MergingTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +MergingTypeTableBuilder::MergingTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) { + SeenRecords.reserve(4096); +} + +MergingTypeTableBuilder::~MergingTypeTableBuilder() = default; + +Optional<TypeIndex> MergingTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> MergingTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType MergingTypeTableBuilder::getType(TypeIndex Index) { + CVType Type; + Type.RecordData = SeenRecords[Index.toArrayIndex()]; + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(Type.RecordData.data()); + Type.Type = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); + return Type; +} + +StringRef MergingTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool MergingTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t MergingTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t MergingTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> MergingTypeTableBuilder::records() const { + return SeenRecords; +} + +void MergingTypeTableBuilder::reset() { + HashedRecords.clear(); + SeenRecords.clear(); +} + +static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, + ArrayRef<uint8_t> Data) { + uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); + memcpy(Stable, Data.data(), Data.size()); + return makeArrayRef(Stable, Data.size()); +} + +TypeIndex MergingTypeTableBuilder::insertRecordAs(hash_code Hash, + ArrayRef<uint8_t> &Record) { + assert(Record.size() < UINT32_MAX && "Record too big"); + assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!"); + + LocallyHashedType WeakHash{Hash, Record}; + auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex()); + + if (Result.second) { + ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Record); + Result.first->first.RecordData = RecordData; + SeenRecords.push_back(RecordData); + } + + // Update the caller's copy of Record to point a stable copy. + TypeIndex ActualTI = Result.first->second; + Record = SeenRecords[ActualTI.toArrayIndex()]; + return ActualTI; +} + +TypeIndex +MergingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { + return insertRecordAs(hash_value(Record), Record); +} + +TypeIndex +MergingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/gnu/llvm/lib/DebugInfo/CodeView/RecordName.cpp new file mode 100644 index 00000000000..15fb1724d23 --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/RecordName.cpp @@ -0,0 +1,320 @@ +//===- RecordName.cpp ----------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/RecordName.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +class TypeNameComputer : public TypeVisitorCallbacks { + /// The type collection. Used to calculate names of nested types. + TypeCollection &Types; + TypeIndex CurrentTypeIndex = TypeIndex::None(); + + /// Name of the current type. Only valid before visitTypeEnd. + SmallString<256> Name; + +public: + explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} + + StringRef name() const { return Name; } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(CVType &Record) override; + Error visitTypeBegin(CVType &Record, TypeIndex Index) override; + Error visitTypeEnd(CVType &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; +} // namespace + +Error TypeNameComputer::visitTypeBegin(CVType &Record) { + llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); + return Error::success(); +} + +Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + CurrentTypeIndex = Index; + return Error::success(); +} + +Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = "<field list>"; + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, + StringIdRecord &String) { + Name = String.getString(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + Name = "("; + for (uint32_t I = 0; I < Size; ++I) { + assert(Indices[I] < CurrentTypeIndex); + + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append(", "); + } + Name.push_back(')'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + StringListRecord &Strings) { + auto Indices = Strings.getIndices(); + uint32_t Size = Indices.size(); + Name = "\""; + for (uint32_t I = 0; I < Size; ++I) { + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append("\" \""); + } + Name.push_back('\"'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + Name = Class.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + StringRef Ret = Types.getTypeName(Proc.getReturnType()); + StringRef Params = Types.getTypeName(Proc.getArgumentList()); + Name = formatv("{0} {1}", Ret, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef Ret = Types.getTypeName(MF.getReturnType()); + StringRef Class = Types.getTypeName(MF.getClassType()); + StringRef Params = Types.getTypeName(MF.getArgumentList()); + Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); + StringRef Class = Types.getTypeName(MI.getContainingType()); + Name = formatv("{0} {1}::*", Pointee, Class); + } else { + if (Ptr.isConst()) + Name.append("const "); + if (Ptr.isVolatile()) + Name.append("volatile "); + if (Ptr.isUnaligned()) + Name.append("__unaligned "); + + Name.append(Types.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + Name.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + Name.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + Name.append("*"); + } + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); + + SmallString<256> TypeName; + if (Mods & uint16_t(ModifierOptions::Const)) + Name.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + Name.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + Name.append("__unaligned "); + Name.append(Types.getTypeName(Mod.getModifiedType())); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { + return Error::success(); +} + +std::string llvm::codeview::computeTypeName(TypeCollection &Types, + TypeIndex Index) { + TypeNameComputer Computer(Types); + CVType Record = Types.getType(Index); + if (auto EC = visitTypeRecord(Record, Index, Computer)) { + consumeError(std::move(EC)); + return "<unknown UDT>"; + } + return Computer.name(); +} + +static int getSymbolNameOffset(CVSymbol Sym) { + switch (Sym.kind()) { + // See ProcSym + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: + return 35; + // See Thunk32Sym + case SymbolKind::S_THUNK32: + return 21; + // See SectionSym + case SymbolKind::S_SECTION: + return 16; + // See CoffGroupSym + case SymbolKind::S_COFFGROUP: + return 14; + // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym + case SymbolKind::S_PUB32: + case SymbolKind::S_FILESTATIC: + case SymbolKind::S_REGREL32: + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + case SymbolKind::S_LMANDATA: + case SymbolKind::S_GMANDATA: + case SymbolKind::S_LTHREAD32: + case SymbolKind::S_GTHREAD32: + return 10; + // See RegisterSym and LocalSym + case SymbolKind::S_REGISTER: + case SymbolKind::S_LOCAL: + return 6; + // See BlockSym + case SymbolKind::S_BLOCK32: + return 18; + // See LabelSym + case SymbolKind::S_LABEL32: + return 7; + // See ObjNameSym, ExportSym, and UDTSym + case SymbolKind::S_OBJNAME: + case SymbolKind::S_EXPORT: + case SymbolKind::S_UDT: + return 4; + // See BPRelativeSym + case SymbolKind::S_BPREL32: + return 8; + default: + return -1; + } +} + +StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { + if (Sym.kind() == SymbolKind::S_CONSTANT) { + // S_CONSTANT is preceded by an APSInt, which has a variable length. So we + // have to do a full deserialization. + BinaryStreamReader Reader(Sym.content(), llvm::support::little); + // The container doesn't matter for single records. + SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); + ConstantSym Const(SymbolKind::S_CONSTANT); + cantFail(Mapping.visitSymbolBegin(Sym)); + cantFail(Mapping.visitKnownRecord(Sym, Const)); + cantFail(Mapping.visitSymbolEnd(Sym)); + return Const.Name; + } + + int Offset = getSymbolNameOffset(Sym); + if (Offset == -1) + return StringRef(); + + StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); + return StringData.split('\0').first; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp b/gnu/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp index 6446670f60d..bff9a619a84 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/BinaryByteStream.h" @@ -147,3 +148,8 @@ Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { return Reader.readCString(Item); } + +Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, + uint32_t Offset) { + return readCVRecordFromStream<SymbolKind>(Stream, Offset); +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/gnu/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp new file mode 100644 index 00000000000..d28b7c3c2d8 --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp @@ -0,0 +1,62 @@ +#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" + +using namespace llvm; +using namespace llvm::codeview; + +static void writeRecordPrefix(BinaryStreamWriter &Writer, TypeLeafKind Kind) { + RecordPrefix Prefix; + Prefix.RecordKind = Kind; + Prefix.RecordLen = 0; + cantFail(Writer.writeObject(Prefix)); +} + +static void addPadding(BinaryStreamWriter &Writer) { + uint32_t Align = Writer.getOffset() % 4; + if (Align == 0) + return; + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + cantFail(Writer.writeInteger(Pad)); + --PaddingBytes; + } +} + +SimpleTypeSerializer::SimpleTypeSerializer() : ScratchBuffer(MaxRecordLength) {} + +SimpleTypeSerializer::~SimpleTypeSerializer() {} + +template <typename T> +ArrayRef<uint8_t> SimpleTypeSerializer::serialize(T &Record) { + BinaryStreamWriter Writer(ScratchBuffer, support::little); + TypeRecordMapping Mapping(Writer); + + CVType CVT; + CVT.Type = static_cast<TypeLeafKind>(Record.getKind()); + + writeRecordPrefix(Writer, CVT.Type); + + cantFail(Mapping.visitTypeBegin(CVT)); + cantFail(Mapping.visitKnownRecord(CVT, Record)); + cantFail(Mapping.visitTypeEnd(CVT)); + + addPadding(Writer); + + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(ScratchBuffer.data()); + + Prefix->RecordKind = CVT.kind(); + Prefix->RecordLen = Writer.getOffset() - sizeof(uint16_t); + + return {ScratchBuffer.data(), Writer.getOffset()}; +} + +// Explicitly instantiate the member function for each known type so that we can +// implement this in the cpp file. +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + template ArrayRef<uint8_t> llvm::codeview::SimpleTypeSerializer::serialize( \ + Name##Record &Record); +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" diff --git a/gnu/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/gnu/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp index 306af1d1ef6..85d9dbb8c7d 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp @@ -35,14 +35,36 @@ void StringsAndChecksumsRef::initializeStrings( assert(SR.kind() == DebugSubsectionKind::StringTable); assert(!Strings && "Found a string table even though we already have one!"); - OwnedStrings = llvm::make_unique<DebugStringTableSubsectionRef>(); + OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); consumeError(OwnedStrings->initialize(SR.getRecordData())); Strings = OwnedStrings.get(); } +void StringsAndChecksumsRef::reset() { + resetStrings(); + resetChecksums(); +} + +void StringsAndChecksumsRef::resetStrings() { + OwnedStrings.reset(); + Strings = nullptr; +} + +void StringsAndChecksumsRef::resetChecksums() { + OwnedChecksums.reset(); + Checksums = nullptr; +} + +void StringsAndChecksumsRef::setStrings( + const DebugStringTableSubsectionRef &StringsRef) { + OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); + *OwnedStrings = StringsRef; + Strings = OwnedStrings.get(); +} + void StringsAndChecksumsRef::setChecksums( const DebugChecksumsSubsectionRef &CS) { - OwnedChecksums = llvm::make_unique<DebugChecksumsSubsectionRef>(); + OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); *OwnedChecksums = CS; Checksums = OwnedChecksums.get(); } @@ -53,7 +75,7 @@ void StringsAndChecksumsRef::initializeChecksums( if (Checksums) return; - OwnedChecksums = llvm::make_unique<DebugChecksumsSubsectionRef>(); + OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); consumeError(OwnedChecksums->initialize(FCR.getRecordData())); Checksums = OwnedChecksums.get(); } diff --git a/gnu/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/gnu/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp index 62e73acc72d..df75f52661e 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" @@ -317,7 +316,8 @@ Error CVSymbolDumperImpl::visitKnownRecord( Error CVSymbolDumperImpl::visitKnownRecord( CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { - W.printNumber("BaseRegister", DefRangeRegisterRel.Hdr.Register); + W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register), + getRegisterNames()); W.printBoolean("HasSpilledUDTMember", DefRangeRegisterRel.hasSpilledUDTMember()); W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); @@ -330,7 +330,8 @@ Error CVSymbolDumperImpl::visitKnownRecord( Error CVSymbolDumperImpl::visitKnownRecord( CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { - W.printNumber("Register", DefRangeRegister.Hdr.Register); + W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register), + getRegisterNames()); W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); printLocalVariableAddrRange(DefRangeRegister.Range, DefRangeRegister.getRelocationOffset()); @@ -340,7 +341,8 @@ Error CVSymbolDumperImpl::visitKnownRecord( Error CVSymbolDumperImpl::visitKnownRecord( CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { - W.printNumber("Register", DefRangeSubfieldRegister.Hdr.Register); + W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register), + getRegisterNames()); W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent); printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, @@ -393,7 +395,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, FrameCookie.getRelocationOffset(), FrameCookie.CodeOffset, &LinkageName); } - W.printHex("Register", FrameCookie.Register); + W.printEnum("Register", uint16_t(FrameCookie.Register), getRegisterNames()); W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind), getFrameCookieKindNames()); W.printHex("Flags", FrameCookie.Flags); diff --git a/gnu/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/gnu/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp index 9a2e776feb7..0071ecc8568 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp @@ -21,8 +21,7 @@ using namespace llvm::codeview; SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator, CodeViewContainer Container) - : Storage(Allocator), RecordBuffer(MaxRecordLength), - Stream(RecordBuffer, support::little), Writer(Stream), + : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream), Mapping(Writer, Container) {} Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) { diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index e18a35ca1f3..e7998b8732f 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -15,7 +15,6 @@ #include "llvm/DebugInfo/CodeView/TypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp new file mode 100644 index 00000000000..f5b28b2a207 --- /dev/null +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp @@ -0,0 +1,74 @@ +//===- TypeHashing.cpp -------------------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeHashing.h" + +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/Support/SHA1.h" + +using namespace llvm; +using namespace llvm::codeview; + +LocallyHashedType DenseMapInfo<LocallyHashedType>::Empty{0, {}}; +LocallyHashedType DenseMapInfo<LocallyHashedType>::Tombstone{hash_code(-1), {}}; + +static std::array<uint8_t, 20> EmptyHash; +static std::array<uint8_t, 20> TombstoneHash = { + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +GloballyHashedType DenseMapInfo<GloballyHashedType>::Empty{EmptyHash}; +GloballyHashedType DenseMapInfo<GloballyHashedType>::Tombstone{TombstoneHash}; + +LocallyHashedType LocallyHashedType::hashType(ArrayRef<uint8_t> RecordData) { + return {llvm::hash_value(RecordData), RecordData}; +} + +GloballyHashedType +GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData, + ArrayRef<GloballyHashedType> PreviousTypes, + ArrayRef<GloballyHashedType> PreviousIds) { + SmallVector<TiReference, 4> Refs; + discoverTypeIndices(RecordData, Refs); + SHA1 S; + S.init(); + uint32_t Off = 0; + RecordData = RecordData.drop_front(sizeof(RecordPrefix)); + for (const auto &Ref : Refs) { + // Hash any data that comes before this TiRef. + uint32_t PreLen = Ref.Offset - Off; + ArrayRef<uint8_t> PreData = RecordData.slice(Off, PreLen); + S.update(PreData); + auto Prev = (Ref.Kind == TiRefKind::IndexRef) ? PreviousIds : PreviousTypes; + + auto RefData = RecordData.slice(Ref.Offset, Ref.Count * sizeof(TypeIndex)); + // For each type index referenced, add in the previously computed hash + // value of that type. + ArrayRef<TypeIndex> Indices( + reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count); + for (TypeIndex TI : Indices) { + ArrayRef<uint8_t> BytesToHash; + if (TI.isSimple() || TI.isNoneType() || TI.toArrayIndex() >= Prev.size()) { + const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI); + BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex)); + } else { + BytesToHash = Prev[TI.toArrayIndex()].Hash; + } + S.update(BytesToHash); + } + + Off = Ref.Offset + Ref.Count * sizeof(TypeIndex); + } + + // Don't forget to add in any trailing bytes. + auto TrailingBytes = RecordData.drop_front(Off); + S.update(TrailingBytes); + + return {S.final()}; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 0d935c4472a..d283e9e6d2f 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -392,9 +392,13 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, case SymbolKind::S_LOCAL: Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type break; + case SymbolKind::S_REGISTER: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type; + break; case SymbolKind::S_CONSTANT: Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type break; + case SymbolKind::S_BPREL32: case SymbolKind::S_REGREL32: Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type break; @@ -403,6 +407,7 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, break; case SymbolKind::S_CALLERS: case SymbolKind::S_CALLEES: + case SymbolKind::S_INLINEES: // The record is a count followed by an array of type indices. Count = *reinterpret_cast<const ulittle32_t *>(Content.data()); Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees @@ -411,8 +416,7 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee break; case SymbolKind::S_HEAPALLOCSITE: - // FIXME: It's not clear if this is a type or item reference. - Refs.push_back({TiRefKind::IndexRef, 8, 1}); // signature + Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated break; // Defranges don't have types, just registers and code offsets. @@ -433,6 +437,8 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, case SymbolKind::S_ENVBLOCK: case SymbolKind::S_BLOCK32: case SymbolKind::S_FRAMEPROC: + case SymbolKind::S_THUNK32: + case SymbolKind::S_FRAMECOOKIE: break; // Scope ending symbols. case SymbolKind::S_END: @@ -450,17 +456,17 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type, ::discoverTypeIndices(Type.content(), Type.kind(), Refs); } -void llvm::codeview::discoverTypeIndices(const CVType &Type, - SmallVectorImpl<TypeIndex> &Indices) { - +static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData, + ArrayRef<TiReference> Refs, + SmallVectorImpl<TypeIndex> &Indices) { Indices.clear(); - SmallVector<TiReference, 4> Refs; - discoverTypeIndices(Type, Refs); if (Refs.empty()) return; - BinaryStreamReader Reader(Type.content(), support::little); + RecordData = RecordData.drop_front(sizeof(RecordPrefix)); + + BinaryStreamReader Reader(RecordData, support::little); for (const auto &Ref : Refs) { Reader.setOffset(Ref.Offset); FixedStreamArray<TypeIndex> Run; @@ -469,6 +475,18 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type, } } +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl<TypeIndex> &Indices) { + return discoverTypeIndices(Type.RecordData, Indices); +} + +void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, + SmallVectorImpl<TypeIndex> &Indices) { + SmallVector<TiReference, 4> Refs; + discoverTypeIndices(RecordData, Refs); + resolveTypeIndexReferences(RecordData, Refs, Indices); +} + void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) { const RecordPrefix *P = @@ -477,8 +495,26 @@ void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); } -bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym, - SmallVectorImpl<TiReference> &Refs) { +bool llvm::codeview::discoverTypeIndicesInSymbol( + const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) { SymbolKind K = Sym.kind(); return ::discoverTypeIndices(Sym.content(), K, Refs); } + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) { + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(RecordData.data()); + SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind)); + return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, + Refs); +} + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) { + SmallVector<TiReference, 2> Refs; + if (!discoverTypeIndicesInSymbol(RecordData, Refs)) + return false; + resolveTypeIndexReferences(RecordData, Refs, Indices); + return true; +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp index 114f6fd2897..9b8a6053da8 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -426,7 +426,8 @@ Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, OneMethodRecord &Record) { - MapOneMethodRecord Mapper(false); + const bool IsFromOverloadList = (TypeKind == LF_METHODLIST); + MapOneMethodRecord Mapper(IsFromOverloadList); return Mapper(IO, Record); } diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index bff3516203a..6a94952c175 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -10,13 +10,12 @@ #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/Support/Error.h" -#include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace llvm::codeview; @@ -64,12 +63,27 @@ public: static const TypeIndex Untranslated; - Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes, + // Local hashing entry points + Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds, + MergingTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes); - Error mergeIdRecords(TypeTableBuilder &Dest, + Error mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids); - Error mergeTypeRecords(TypeTableBuilder &Dest, const CVTypeArray &Types); + Error mergeTypeRecords(MergingTypeTableBuilder &Dest, + const CVTypeArray &Types); + + // Global hashing entry points + Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, + GlobalTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes); + Error mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes); + Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes); private: Error doit(const CVTypeArray &Types); @@ -83,6 +97,16 @@ private: bool remapTypeIndex(TypeIndex &Idx); bool remapItemIndex(TypeIndex &Idx); + bool hasTypeStream() const { + return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream); + } + + bool hasIdStream() const { + return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream); + } + + ArrayRef<uint8_t> serializeRemapped(const RemappedType &Record); + bool remapIndices(RemappedType &Record, ArrayRef<TiReference> Refs); bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map); @@ -96,25 +120,23 @@ private: return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); } - Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record, - bool RemapSuccess) { - TypeIndex DestIdx = Untranslated; - if (RemapSuccess) - DestIdx = Dest.writeSerializedRecord(Record); - addMapping(DestIdx); - return Error::success(); - } - Optional<Error> LastError; + bool UseGlobalHashes = false; + bool IsSecondPass = false; unsigned NumBadIndices = 0; TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; - TypeTableBuilder *DestIdStream = nullptr; - TypeTableBuilder *DestTypeStream = nullptr; + MergingTypeTableBuilder *DestIdStream = nullptr; + MergingTypeTableBuilder *DestTypeStream = nullptr; + + GlobalTypeTableBuilder *DestGlobalIdStream = nullptr; + GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr; + + ArrayRef<GloballyHashedType> GlobalHashes; // If we're only mapping id records, this array contains the mapping for // type records. @@ -123,10 +145,35 @@ private: /// Map from source type index to destination type index. Indexed by source /// type index minus 0x1000. SmallVectorImpl<TypeIndex> &IndexMap; + + /// Temporary storage that we use to copy a record's data while re-writing + /// its type indices. + SmallVector<uint8_t, 256> RemapStorage; }; } // end anonymous namespace +ArrayRef<uint8_t> +TypeStreamMerger::serializeRemapped(const RemappedType &Record) { + TypeIndex TI; + ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData; + if (Record.Mappings.empty()) + return OriginalData; + + // At least one type index was remapped. We copy the full record bytes, + // re-write each type index, then return that. + RemapStorage.resize(OriginalData.size()); + ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size()); + uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix); + for (const auto &M : Record.Mappings) { + // First 4 bytes of every record are the record prefix, but the mapping + // offset is relative to the content which starts after. + *(TypeIndex *)(ContentBegin + M.first) = M.second; + } + auto RemapRef = makeArrayRef(RemapStorage); + return RemapRef; +} + const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); static bool isIdRecord(TypeLeafKind K) { @@ -191,7 +238,7 @@ bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) { // special mapping from OldTypeStream -> NewTypeStream which was computed // externally. Regardless, we use this special map if and only if we are // doing an id-only mapping. - if (DestTypeStream == nullptr) + if (!hasTypeStream()) return remapIndex(Idx, TypeLookup); assert(TypeLookup.empty()); @@ -199,31 +246,69 @@ bool TypeStreamMerger::remapTypeIndex(TypeIndex &Idx) { } bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) { - assert(DestIdStream); + assert(hasIdStream()); return remapIndex(Idx, IndexMap); } -Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest, +// Local hashing entry points +Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest, const CVTypeArray &Types) { DestTypeStream = &Dest; + UseGlobalHashes = false; return doit(Types); } -Error TypeStreamMerger::mergeIdRecords(TypeTableBuilder &Dest, +Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids) { DestIdStream = &Dest; TypeLookup = TypeSourceToDest; + UseGlobalHashes = false; return doit(Ids); } -Error TypeStreamMerger::mergeTypesAndIds(TypeTableBuilder &DestIds, - TypeTableBuilder &DestTypes, +Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds, + MergingTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes) { DestIdStream = &DestIds; DestTypeStream = &DestTypes; + UseGlobalHashes = false; + return doit(IdsAndTypes); +} + +// Global hashing entry points +Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest, + const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes) { + DestGlobalTypeStream = &Dest; + UseGlobalHashes = true; + GlobalHashes = Hashes; + + return doit(Types); +} + +Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes) { + DestGlobalIdStream = &Dest; + TypeLookup = TypeSourceToDest; + UseGlobalHashes = true; + GlobalHashes = Hashes; + + return doit(Ids); +} + +Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, + GlobalTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes) { + DestGlobalIdStream = &DestIds; + DestGlobalTypeStream = &DestTypes; + UseGlobalHashes = true; + GlobalHashes = Hashes; return doit(IdsAndTypes); } @@ -268,14 +353,30 @@ Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) { } Error TypeStreamMerger::remapType(const CVType &Type) { - RemappedType R(Type); - SmallVector<TiReference, 32> Refs; - discoverTypeIndices(Type.RecordData, Refs); - bool MappedAllIndices = remapIndices(R, Refs); - TypeTableBuilder &Dest = - isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; - if (auto EC = writeRecord(Dest, R, MappedAllIndices)) - return EC; + auto DoSerialize = [this, Type]() -> ArrayRef<uint8_t> { + RemappedType R(Type); + SmallVector<TiReference, 32> Refs; + discoverTypeIndices(Type.RecordData, Refs); + if (!remapIndices(R, Refs)) + return {}; + return serializeRemapped(R); + }; + + TypeIndex DestIdx = Untranslated; + if (UseGlobalHashes) { + GlobalTypeTableBuilder &Dest = + isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream; + GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()]; + DestIdx = Dest.insertRecordAs(H, DoSerialize); + } else { + MergingTypeTableBuilder &Dest = + isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; + + auto Data = DoSerialize(); + if (!Data.empty()) + DestIdx = Dest.insertRecordBytes(Data); + } + addMapping(DestIdx); ++CurIndex; assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) && @@ -306,14 +407,14 @@ bool TypeStreamMerger::remapIndices(RemappedType &Record, return Success; } -Error llvm::codeview::mergeTypeRecords(TypeTableBuilder &Dest, +Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Types) { TypeStreamMerger M(SourceToDest); return M.mergeTypeRecords(Dest, Types); } -Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest, +Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Ids) { @@ -322,8 +423,33 @@ Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest, } Error llvm::codeview::mergeTypeAndIdRecords( - TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes, + MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes) { TypeStreamMerger M(SourceToDest); return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes); } + +Error llvm::codeview::mergeTypeAndIdRecords( + GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, + SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes); +} + +Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypeRecords(Dest, Types, Hashes); +} + +Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> Types, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes) { + TypeStreamMerger M(SourceToDest); + return M.mergeIdRecords(Dest, Types, Ids, Hashes); +} diff --git a/gnu/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/gnu/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp index 4eca5aeaa0a..cf951baa511 100644 --- a/gnu/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp +++ b/gnu/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp @@ -10,9 +10,7 @@ #include "llvm/DebugInfo/CodeView/TypeTableCollection.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeName.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/Support/BinaryByteStream.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" #include "llvm/Support/BinaryStreamReader.h" using namespace llvm; |
