summaryrefslogtreecommitdiff
path: root/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/CodeView')
-rw-r--r--lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp101
-rw-r--r--lib/DebugInfo/CodeView/CMakeLists.txt9
-rw-r--r--lib/DebugInfo/CodeView/CVSymbolVisitor.cpp1
-rw-r--r--lib/DebugInfo/CodeView/CVTypeVisitor.cpp1
-rw-r--r--lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp259
-rw-r--r--lib/DebugInfo/CodeView/EnumTables.cpp54
-rw-r--r--lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp127
-rw-r--r--lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp32
-rw-r--r--lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp128
-rw-r--r--lib/DebugInfo/CodeView/RecordName.cpp (renamed from lib/DebugInfo/CodeView/TypeName.cpp)81
-rw-r--r--lib/DebugInfo/CodeView/RecordSerialization.cpp6
-rw-r--r--lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp62
-rw-r--r--lib/DebugInfo/CodeView/StringsAndChecksums.cpp28
-rw-r--r--lib/DebugInfo/CodeView/SymbolDumper.cpp12
-rw-r--r--lib/DebugInfo/CodeView/SymbolSerializer.cpp3
-rw-r--r--lib/DebugInfo/CodeView/TypeDumpVisitor.cpp1
-rw-r--r--lib/DebugInfo/CodeView/TypeHashing.cpp74
-rw-r--r--lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp56
-rw-r--r--lib/DebugInfo/CodeView/TypeRecordMapping.cpp3
-rw-r--r--lib/DebugInfo/CodeView/TypeSerializer.cpp389
-rw-r--r--lib/DebugInfo/CodeView/TypeStreamMerger.cpp194
-rw-r--r--lib/DebugInfo/CodeView/TypeTableCollection.cpp4
22 files changed, 1115 insertions, 510 deletions
diff --git a/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
new file mode 100644
index 000000000000..8828671d9be9
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt
index b94bb0c80c79..0515788d85ef 100644
--- a/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/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/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
index e0c7ef58c304..44a67743169e 100644
--- a/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
+++ b/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/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
index 79b9fdefd40e..a4182a3b2fa1 100644
--- a/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
+++ b/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/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
new file mode 100644
index 000000000000..f180fc6990fc
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/EnumTables.cpp b/lib/DebugInfo/CodeView/EnumTables.cpp
index 4cfb55a31b35..d8301cab1657 100644
--- a/lib/DebugInfo/CodeView/EnumTables.cpp
+++ b/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/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
new file mode 100644
index 000000000000..3ecd684c1e39
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
index 5aaf3f1453a8..ca8007411cad 100644
--- a/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
+++ b/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/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp b/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
new file mode 100644
index 000000000000..8aee4aa2e2ae
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/TypeName.cpp b/lib/DebugInfo/CodeView/RecordName.cpp
index 2eb8b81862f3..15fb1724d23d 100644
--- a/lib/DebugInfo/CodeView/TypeName.cpp
+++ b/lib/DebugInfo/CodeView/RecordName.cpp
@@ -1,4 +1,4 @@
-//===- TypeName.cpp ------------------------------------------- *- C++ --*-===//
+//===- RecordName.cpp ----------------------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,10 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/DebugInfo/CodeView/TypeName.h"
+#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"
@@ -241,3 +243,78 @@ std::string llvm::codeview::computeTypeName(TypeCollection &Types,
}
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/lib/DebugInfo/CodeView/RecordSerialization.cpp b/lib/DebugInfo/CodeView/RecordSerialization.cpp
index 6446670f60d8..bff9a619a846 100644
--- a/lib/DebugInfo/CodeView/RecordSerialization.cpp
+++ b/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/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
new file mode 100644
index 000000000000..d28b7c3c2d83
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
index 306af1d1ef6b..85d9dbb8c7df 100644
--- a/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
+++ b/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/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp
index 62e73acc72d6..df75f52661e1 100644
--- a/lib/DebugInfo/CodeView/SymbolDumper.cpp
+++ b/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/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/lib/DebugInfo/CodeView/SymbolSerializer.cpp
index 9a2e776feb75..0071ecc85685 100644
--- a/lib/DebugInfo/CodeView/SymbolSerializer.cpp
+++ b/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/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
index e18a35ca1f38..e7998b8732fe 100644
--- a/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/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/lib/DebugInfo/CodeView/TypeHashing.cpp b/lib/DebugInfo/CodeView/TypeHashing.cpp
new file mode 100644
index 000000000000..f5b28b2a2070
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index 0d935c4472ae..d283e9e6d2f1 100644
--- a/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/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/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index 114f6fd2897e..9b8a6053da84 100644
--- a/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/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/lib/DebugInfo/CodeView/TypeSerializer.cpp b/lib/DebugInfo/CodeView/TypeSerializer.cpp
deleted file mode 100644
index 003c13b4a20d..000000000000
--- a/lib/DebugInfo/CodeView/TypeSerializer.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-//===- TypeSerialzier.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/TypeSerializer.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/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;
-
-namespace {
-
-struct HashedType {
- uint64_t Hash;
- const uint8_t *Data;
- unsigned Size; // FIXME: Go to uint16_t?
- TypeIndex Index;
-};
-
-/// Wrapper around a poitner to a HashedType. Hash and equality operations are
-/// based on data in the pointee.
-struct HashedTypePtr {
- HashedTypePtr() = default;
- HashedTypePtr(HashedType *Ptr) : Ptr(Ptr) {}
-
- HashedType *Ptr = nullptr;
-};
-
-} // end anonymous namespace
-
-namespace llvm {
-
-template <> struct DenseMapInfo<HashedTypePtr> {
- static inline HashedTypePtr getEmptyKey() { return HashedTypePtr(nullptr); }
-
- static inline HashedTypePtr getTombstoneKey() {
- return HashedTypePtr(reinterpret_cast<HashedType *>(1));
- }
-
- static unsigned getHashValue(HashedTypePtr Val) {
- assert(Val.Ptr != getEmptyKey().Ptr && Val.Ptr != getTombstoneKey().Ptr);
- return Val.Ptr->Hash;
- }
-
- static bool isEqual(HashedTypePtr LHSP, HashedTypePtr RHSP) {
- HashedType *LHS = LHSP.Ptr;
- HashedType *RHS = RHSP.Ptr;
- if (RHS == getEmptyKey().Ptr || RHS == getTombstoneKey().Ptr)
- return LHS == RHS;
- if (LHS->Hash != RHS->Hash || LHS->Size != RHS->Size)
- return false;
- return ::memcmp(LHS->Data, RHS->Data, LHS->Size) == 0;
- }
-};
-
-} // end namespace llvm
-
-/// Private implementation so that we don't leak our DenseMap instantiations to
-/// users.
-class llvm::codeview::TypeHasher {
-private:
- /// Storage for type record provided by the caller. Records will outlive the
- /// hasher object, so they should be allocated here.
- BumpPtrAllocator &RecordStorage;
-
- /// Storage for hash keys. These only need to live as long as the hashing
- /// operation.
- BumpPtrAllocator KeyStorage;
-
- /// Hash table. We really want a DenseMap<ArrayRef<uint8_t>, TypeIndex> here,
- /// but DenseMap is inefficient when the keys are long (like type records)
- /// because it recomputes the hash value of every key when it grows. This
- /// value type stores the hash out of line in KeyStorage, so that table
- /// entries are small and easy to rehash.
- DenseSet<HashedTypePtr> HashedRecords;
-
-public:
- TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {}
-
- void reset() { HashedRecords.clear(); }
-
- /// Takes the bytes of type record, inserts them into the hash table, saves
- /// them, and returns a pointer to an identical stable type record along with
- /// its type index in the destination stream.
- TypeIndex getOrCreateRecord(ArrayRef<uint8_t> &Record, TypeIndex TI);
-};
-
-TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record,
- TypeIndex TI) {
- assert(Record.size() < UINT32_MAX && "Record too big");
- assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
-
- // Compute the hash up front so we can store it in the key.
- HashedType TempHashedType = {hash_value(Record), Record.data(),
- unsigned(Record.size()), TI};
- auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType));
- HashedType *&Hashed = Result.first->Ptr;
-
- if (Result.second) {
- // This was a new type record. We need stable storage for both the key and
- // the record. The record should outlive the hashing operation.
- Hashed = KeyStorage.Allocate<HashedType>();
- *Hashed = TempHashedType;
-
- uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
- memcpy(Stable, Record.data(), Record.size());
- Hashed->Data = Stable;
- assert(Hashed->Size == Record.size());
- }
-
- // Update the caller's copy of Record to point a stable copy.
- Record = ArrayRef<uint8_t>(Hashed->Data, Hashed->Size);
- return Hashed->Index;
-}
-
-TypeIndex TypeSerializer::nextTypeIndex() const {
- return TypeIndex::fromArrayIndex(SeenRecords.size());
-}
-
-bool TypeSerializer::isInFieldList() const {
- return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
-}
-
-MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
- assert(isInFieldList());
- return getCurrentRecordData().drop_front(CurrentSegment.length());
-}
-
-MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
- return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
-}
-
-Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
- RecordPrefix Prefix;
- Prefix.RecordKind = Kind;
- Prefix.RecordLen = 0;
- if (auto EC = Writer.writeObject(Prefix))
- return EC;
- return Error::success();
-}
-
-Expected<MutableArrayRef<uint8_t>>
-TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
- uint32_t Align = Record.size() % 4;
- if (Align == 0)
- return Record;
-
- int PaddingBytes = 4 - Align;
- int N = PaddingBytes;
- while (PaddingBytes > 0) {
- uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
- if (auto EC = Writer.writeInteger(Pad))
- return std::move(EC);
- --PaddingBytes;
- }
- return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
-}
-
-TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash)
- : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2),
- Stream(RecordBuffer, support::little), Writer(Stream),
- Mapping(Writer) {
- // RecordBuffer needs to be able to hold enough data so that if we are 1
- // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
- // we won't overflow.
- if (Hash)
- Hasher = llvm::make_unique<TypeHasher>(Storage);
-}
-
-TypeSerializer::~TypeSerializer() = default;
-
-ArrayRef<ArrayRef<uint8_t>> TypeSerializer::records() const {
- return SeenRecords;
-}
-
-void TypeSerializer::reset() {
- if (Hasher)
- Hasher->reset();
- Writer.setOffset(0);
- CurrentSegment = RecordSegment();
- FieldListSegments.clear();
- TypeKind.reset();
- MemberKind.reset();
- SeenRecords.clear();
-}
-
-TypeIndex TypeSerializer::insertRecordBytes(ArrayRef<uint8_t> &Record) {
- assert(!TypeKind.hasValue() && "Already in a type mapping!");
- assert(Writer.getOffset() == 0 && "Stream has data already!");
-
- if (Hasher) {
- TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex());
- if (nextTypeIndex() == ActualTI)
- SeenRecords.push_back(Record);
- return ActualTI;
- }
-
- 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 TypeSerializer::insertRecord(const RemappedType &Record) {
- assert(!TypeKind.hasValue() && "Already in a type mapping!");
- assert(Writer.getOffset() == 0 && "Stream has data already!");
-
- TypeIndex TI;
- ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData;
- if (Record.Mappings.empty()) {
- // This record did not remap any type indices. Just write it.
- return insertRecordBytes(OriginalData);
- }
-
- // At least one type index was remapped. Before we can hash it we have to
- // copy the full record bytes, re-write each type index, then hash the copy.
- // We do this in temporary storage since only the DenseMap can decide whether
- // this record already exists, and if it does we don't want the memory to
- // stick around.
- 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 insertRecordBytes(RemapRef);
-}
-
-Error TypeSerializer::visitTypeBegin(CVType &Record) {
- assert(!TypeKind.hasValue() && "Already in a type mapping!");
- assert(Writer.getOffset() == 0 && "Stream has data already!");
-
- if (auto EC = writeRecordPrefix(Record.kind()))
- return EC;
-
- TypeKind = Record.kind();
- if (auto EC = Mapping.visitTypeBegin(Record))
- return EC;
-
- return Error::success();
-}
-
-Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
- assert(TypeKind.hasValue() && "Not in a type mapping!");
- if (auto EC = Mapping.visitTypeEnd(Record))
- return std::move(EC);
-
- // Update the record's length and fill out the CVType members to point to
- // the stable memory holding the record's data.
- auto ThisRecordData = getCurrentRecordData();
- auto ExpectedData = addPadding(ThisRecordData);
- if (!ExpectedData)
- return ExpectedData.takeError();
- ThisRecordData = *ExpectedData;
-
- RecordPrefix *Prefix =
- reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
- Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
-
- Record.Type = *TypeKind;
- Record.RecordData = ThisRecordData;
-
- // insertRecordBytes assumes we're not in a mapping, so do this first.
- TypeKind.reset();
- Writer.setOffset(0);
-
- TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData);
-
- // Write out each additional segment in reverse order, and update each
- // record's continuation index to point to the previous one.
- for (auto X : reverse(FieldListSegments)) {
- auto CIBytes = X.take_back(sizeof(uint32_t));
- support::ulittle32_t *CI =
- reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
- assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
- *CI = InsertedTypeIndex.getIndex();
- InsertedTypeIndex = insertRecordBytes(X);
- }
-
- FieldListSegments.clear();
- CurrentSegment.SubRecords.clear();
-
- return InsertedTypeIndex;
-}
-
-Error TypeSerializer::visitTypeEnd(CVType &Record) {
- auto ExpectedIndex = visitTypeEndGetIndex(Record);
- if (!ExpectedIndex)
- return ExpectedIndex.takeError();
- return Error::success();
-}
-
-Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
- assert(isInFieldList() && "Not in a field list!");
- assert(!MemberKind.hasValue() && "Already in a member record!");
- MemberKind = Record.Kind;
-
- if (auto EC = Mapping.visitMemberBegin(Record))
- return EC;
-
- return Error::success();
-}
-
-Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
- if (auto EC = Mapping.visitMemberEnd(Record))
- return EC;
-
- // Check if this subrecord makes the current segment not fit in 64K minus
- // the space for a continuation record (8 bytes). If the segment does not
- // fit, insert a continuation record.
- if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
- MutableArrayRef<uint8_t> Data = getCurrentRecordData();
- SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
- uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
- auto CopyData = Data.take_front(CopySize);
- auto LeftOverData = Data.drop_front(CopySize);
- assert(LastSubRecord.Size == LeftOverData.size());
-
- // Allocate stable storage for the record and copy the old record plus
- // continuation over.
- uint16_t LengthWithSize = CopySize + ContinuationLength;
- assert(LengthWithSize <= MaxRecordLength);
- RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
- Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
-
- uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
- auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
- MutableBinaryByteStream CS(SavedSegment, support::little);
- BinaryStreamWriter CW(CS);
- if (auto EC = CW.writeBytes(CopyData))
- return EC;
- if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
- return EC;
- if (auto EC = CW.writeInteger<uint16_t>(0))
- return EC;
- if (auto EC = CW.writeInteger<uint32_t>(0xB0C0B0C0))
- return EC;
- FieldListSegments.push_back(SavedSegment);
-
- // Write a new placeholder record prefix to mark the start of this new
- // top-level record.
- Writer.setOffset(0);
- if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
- return EC;
-
- // Then move over the subrecord that overflowed the old segment to the
- // beginning of this segment. Note that we have to use memmove here
- // instead of Writer.writeBytes(), because the new and old locations
- // could overlap.
- ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
- LeftOverData.size());
- // And point the segment writer at the end of that subrecord.
- Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
-
- CurrentSegment.SubRecords.clear();
- CurrentSegment.SubRecords.push_back(LastSubRecord);
- }
-
- // Update the CVMemberRecord since we may have shifted around or gotten
- // padded.
- Record.Data = getCurrentSubRecordData();
-
- MemberKind.reset();
- return Error::success();
-}
diff --git a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
index bff3516203a0..6a94952c175b 100644
--- a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
+++ b/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/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/lib/DebugInfo/CodeView/TypeTableCollection.cpp
index 4eca5aeaa0ae..cf951baa5111 100644
--- a/lib/DebugInfo/CodeView/TypeTableCollection.cpp
+++ b/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;