aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-12-20 19:53:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-12-20 19:53:05 +0000
commit0b57cec536236d46e3dba9bd041533462f33dbb7 (patch)
tree56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm-project/llvm/lib/DebugInfo/CodeView
parent718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff)
Notes
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DebugInfo/CodeView')
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp95
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp82
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp289
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp49
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp368
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp251
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp115
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp52
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp96
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp61
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp125
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp160
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp107
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp15
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp96
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp94
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp35
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp33
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp383
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp47
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp106
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp279
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Line.cpp21
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp123
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordName.cpp337
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp154
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp56
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp80
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp679
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp93
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp558
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp59
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp570
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp80
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp106
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp522
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp52
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp513
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp493
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp60
40 files changed, 7494 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
new file mode 100644
index 000000000000..86a6f9eebfa2
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
@@ -0,0 +1,95 @@
+//===- AppendingTypeTableBuilder.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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){
+ return CVType(SeenRecords[Index.toArrayIndex()]);
+}
+
+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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
new file mode 100644
index 000000000000..48b9b0496ffe
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
@@ -0,0 +1,82 @@
+//===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+template <typename T>
+static Error visitKnownRecord(CVSymbol &Record,
+ SymbolVisitorCallbacks &Callbacks) {
+ SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind());
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+static Error finishVisitation(CVSymbol &Record,
+ SymbolVisitorCallbacks &Callbacks) {
+ switch (Record.kind()) {
+ default:
+ if (auto EC = Callbacks.visitUnknownSymbol(Record))
+ return EC;
+ break;
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ }
+
+ if (auto EC = Callbacks.visitSymbolEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {
+ if (auto EC = Callbacks.visitSymbolBegin(Record))
+ return EC;
+ return finishVisitation(Record, Callbacks);
+}
+
+Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) {
+ if (auto EC = Callbacks.visitSymbolBegin(Record, Offset))
+ return EC;
+ return finishVisitation(Record, Callbacks);
+}
+
+Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) {
+ for (auto I : Symbols) {
+ if (auto EC = visitSymbolRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols,
+ uint32_t InitialOffset) {
+ for (auto I : Symbols) {
+ if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew()))
+ return EC;
+ InitialOffset += I.length();
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
new file mode 100644
index 000000000000..ec4773d571c8
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -0,0 +1,289 @@
+//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+
+template <typename T>
+static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
+ TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+template <typename T>
+static Error visitKnownMember(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
+ TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+static Error visitMemberRecord(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
+ if (auto EC = Callbacks.visitMemberBegin(Record))
+ return EC;
+
+ switch (Record.Kind) {
+ default:
+ if (auto EC = Callbacks.visitUnknownMember(Record))
+ return EC;
+ break;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#define TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ }
+
+ if (auto EC = Callbacks.visitMemberEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+namespace {
+
+class CVTypeVisitor {
+public:
+ explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
+
+ Error visitTypeRecord(CVType &Record, TypeIndex Index);
+ Error visitTypeRecord(CVType &Record);
+
+ /// Visits the type records in Data. Sets the error flag on parse failures.
+ Error visitTypeStream(const CVTypeArray &Types);
+ Error visitTypeStream(CVTypeRange Types);
+ Error visitTypeStream(TypeCollection &Types);
+
+ Error visitMemberRecord(CVMemberRecord Record);
+ Error visitFieldListMemberStream(BinaryStreamReader &Stream);
+
+private:
+ Error finishVisitation(CVType &Record);
+
+ /// The interface to the class that gets notified of each visitation.
+ TypeVisitorCallbacks &Callbacks;
+};
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+Error CVTypeVisitor::finishVisitation(CVType &Record) {
+ switch (Record.kind()) {
+ default:
+ if (auto EC = Callbacks.visitUnknownType(Record))
+ return EC;
+ break;
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ TYPE_RECORD(EnumVal, EnumVal, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ }
+
+ if (auto EC = Callbacks.visitTypeEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
+ if (auto EC = Callbacks.visitTypeBegin(Record, Index))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+ if (auto EC = Callbacks.visitTypeBegin(Record))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
+ return ::visitMemberRecord(Record, Callbacks);
+}
+
+/// Visits the type records in Data. Sets the error flag on parse failures.
+Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
+ Optional<TypeIndex> I = Types.getFirst();
+ while (I) {
+ CVType Type = Types.getType(*I);
+ if (auto EC = visitTypeRecord(Type, *I))
+ return EC;
+ I = Types.getNext(*I);
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
+ TypeLeafKind Leaf;
+ while (!Reader.empty()) {
+ if (auto EC = Reader.readEnum(Leaf))
+ return EC;
+
+ CVMemberRecord Record;
+ Record.Kind = Leaf;
+ if (auto EC = ::visitMemberRecord(Record, Callbacks))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+struct FieldListVisitHelper {
+ FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
+ VisitorDataSource Source)
+ : Stream(Data, llvm::support::little), Reader(Stream),
+ Deserializer(Reader),
+ Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
+ if (Source == VDS_BytesPresent) {
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Callbacks);
+ }
+ }
+
+ BinaryByteStream Stream;
+ BinaryStreamReader Reader;
+ FieldListDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ CVTypeVisitor Visitor;
+};
+
+struct VisitHelper {
+ VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
+ : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
+ if (Source == VDS_BytesPresent) {
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Callbacks);
+ }
+ }
+
+ VisitHelper(TypeVisitorCallbackPipeline &Callbacks, VisitorDataSource Source)
+ : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
+ if (Source == VDS_BytesPresent) {
+ Pipeline = Callbacks;
+ Pipeline.addCallbackToPipelineFront(Deserializer);
+ }
+ }
+
+ TypeDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ CVTypeVisitor Visitor;
+};
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeRecord(Record, Index);
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
+ TypeVisitorCallbackPipeline &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeRecord(Record, Index);
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeRecord(Record);
+}
+
+Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(CVTypeRange Types,
+ TypeVisitorCallbacks &Callbacks) {
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(TypeCollection &Types,
+ TypeVisitorCallbacks &Callbacks) {
+ // When the internal visitor calls Types.getType(Index) the interface is
+ // required to return a CVType with the bytes filled out. So we can assume
+ // that the bytes will be present when individual records are visited.
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ FieldListVisitHelper V(Callbacks, Record.Data, Source);
+ return V.Visitor.visitMemberRecord(Record);
+}
+
+Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
+ ArrayRef<uint8_t> Record,
+ TypeVisitorCallbacks &Callbacks) {
+ CVMemberRecord R;
+ R.Data = Record;
+ R.Kind = Kind;
+ return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
+}
+
+Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
+ TypeVisitorCallbacks &Callbacks) {
+ FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
+ return V.Visitor.visitFieldListMemberStream(V.Reader);
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
new file mode 100644
index 000000000000..69390c708f59
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -0,0 +1,49 @@
+//===- CodeViewError.cpp - Error extensions for CodeView --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class CodeViewErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "llvm.codeview"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<cv_error_code>(Condition)) {
+ case cv_error_code::unspecified:
+ return "An unknown CodeView error has occurred.";
+ case cv_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case cv_error_code::corrupt_record:
+ return "The CodeView record is corrupted.";
+ case cv_error_code::no_records:
+ return "There are no records.";
+ case cv_error_code::operation_unsupported:
+ return "The requested operation is not supported.";
+ case cv_error_code::unknown_member_record:
+ return "The member record is of an unknown type.";
+ }
+ llvm_unreachable("Unrecognized cv_error_code");
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<CodeViewErrorCategory> CodeViewErrCategory;
+const std::error_category &llvm::codeview::CVErrorCategory() {
+ return *CodeViewErrCategory;
+}
+
+char CodeViewError::ID;
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
new file mode 100644
index 000000000000..2f49474115a1
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -0,0 +1,368 @@
+//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
+ RecordLimit Limit;
+ Limit.MaxLength = MaxLength;
+ Limit.BeginOffset = getCurrentOffset();
+ Limits.push_back(Limit);
+ resetStreamedLen();
+ return Error::success();
+}
+
+Error CodeViewRecordIO::endRecord() {
+ assert(!Limits.empty() && "Not in a record!");
+ Limits.pop_back();
+ // We would like to assert that we actually read / wrote all the bytes that we
+ // expected to for this record, but unfortunately we can't do this. Some
+ // producers such as MASM over-allocate for certain types of records and
+ // commit the extraneous data, so when reading we can't be sure every byte
+ // will have been read. And when writing we over-allocate temporarily since
+ // we don't know how big the record is until we're finished writing it, so
+ // even though we don't commit the extraneous data, we still can't guarantee
+ // we're at the end of the allocated data.
+
+ if (isStreaming()) {
+ // For streaming mode, add padding to align with 4 byte boundaries for each
+ // record
+ uint32_t Align = getStreamedLen() % 4;
+ if (Align == 0)
+ return Error::success();
+
+ int PaddingBytes = 4 - Align;
+ while (PaddingBytes > 0) {
+ char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ StringRef BytesSR = StringRef(&Pad, sizeof(Pad));
+ Streamer->EmitBytes(BytesSR);
+ --PaddingBytes;
+ }
+ }
+ return Error::success();
+}
+
+uint32_t CodeViewRecordIO::maxFieldLength() const {
+ if (isStreaming())
+ return 0;
+
+ assert(!Limits.empty() && "Not in a record!");
+
+ // The max length of the next field is the minimum of all lengths that would
+ // be allowed by any of the sub-records we're in. In practice, we can only
+ // ever be at most 1 sub-record deep (in a FieldList), but this works for
+ // the general case.
+ uint32_t Offset = getCurrentOffset();
+ Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
+ for (auto X : makeArrayRef(Limits).drop_front()) {
+ Optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
+ if (ThisMin.hasValue())
+ Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
+ }
+ assert(Min.hasValue() && "Every field must have a maximum length!");
+
+ return *Min;
+}
+
+Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
+ if (isReading())
+ return Reader->padToAlignment(Align);
+ return Writer->padToAlignment(Align);
+}
+
+Error CodeViewRecordIO::skipPadding() {
+ assert(!isWriting() && "Cannot skip padding while writing!");
+
+ if (Reader->bytesRemaining() == 0)
+ return Error::success();
+
+ uint8_t Leaf = Reader->peek();
+ if (Leaf < LF_PAD0)
+ return Error::success();
+ // Leaf is greater than 0xf0. We should advance by the number of bytes in
+ // the low 4 bits.
+ unsigned BytesToAdvance = Leaf & 0x0F;
+ return Reader->skip(BytesToAdvance);
+}
+
+Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes,
+ const Twine &Comment) {
+ if (isStreaming()) {
+ emitComment(Comment);
+ Streamer->EmitBinaryData(toStringRef(Bytes));
+ incrStreamedLen(Bytes.size());
+ } else if (isWriting()) {
+ if (auto EC = Writer->writeBytes(Bytes))
+ return EC;
+ } else {
+ if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes,
+ const Twine &Comment) {
+ ArrayRef<uint8_t> BytesRef(Bytes);
+ if (auto EC = mapByteVectorTail(BytesRef, Comment))
+ return EC;
+ if (!isWriting())
+ Bytes.assign(BytesRef.begin(), BytesRef.end());
+
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) {
+ if (isStreaming()) {
+ emitComment(Comment);
+ Streamer->EmitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex()));
+ incrStreamedLen(sizeof(TypeInd.getIndex()));
+ } else if (isWriting()) {
+ if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
+ return EC;
+ } else {
+ uint32_t I;
+ if (auto EC = Reader->readInteger(I))
+ return EC;
+ TypeInd.setIndex(I);
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value,
+ const Twine &Comment) {
+ if (isStreaming()) {
+ if (Value >= 0)
+ emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment);
+ else
+ emitEncodedSignedInteger(Value, Comment);
+ } else if (isWriting()) {
+ if (Value >= 0) {
+ if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))
+ return EC;
+ } else {
+ if (auto EC = writeEncodedSignedInteger(Value))
+ return EC;
+ }
+ } else {
+ APSInt N;
+ if (auto EC = consume(*Reader, N))
+ return EC;
+ Value = N.getExtValue();
+ }
+
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value,
+ const Twine &Comment) {
+ if (isStreaming())
+ emitEncodedUnsignedInteger(Value, Comment);
+ else if (isWriting()) {
+ if (auto EC = writeEncodedUnsignedInteger(Value))
+ return EC;
+ } else {
+ APSInt N;
+ if (auto EC = consume(*Reader, N))
+ return EC;
+ Value = N.getZExtValue();
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) {
+ if (isStreaming()) {
+ if (Value.isSigned())
+ emitEncodedSignedInteger(Value.getSExtValue(), Comment);
+ else
+ emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);
+ } else if (isWriting()) {
+ if (Value.isSigned())
+ return writeEncodedSignedInteger(Value.getSExtValue());
+ return writeEncodedUnsignedInteger(Value.getZExtValue());
+ } else
+ return consume(*Reader, Value);
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) {
+ if (isStreaming()) {
+ auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1);
+ emitComment(Comment);
+ Streamer->EmitBytes(NullTerminatedString);
+ incrStreamedLen(NullTerminatedString.size());
+ } else if (isWriting()) {
+ // Truncate if we attempt to write too much.
+ StringRef S = Value.take_front(maxFieldLength() - 1);
+ if (auto EC = Writer->writeCString(S))
+ return EC;
+ } else {
+ if (auto EC = Reader->readCString(Value))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) {
+ constexpr uint32_t GuidSize = 16;
+
+ if (isStreaming()) {
+ StringRef GuidSR =
+ StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize);
+ emitComment(Comment);
+ Streamer->EmitBytes(GuidSR);
+ incrStreamedLen(GuidSize);
+ return Error::success();
+ }
+
+ if (maxFieldLength() < GuidSize)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ if (isWriting()) {
+ if (auto EC = Writer->writeBytes(Guid.Guid))
+ return EC;
+ } else {
+ ArrayRef<uint8_t> GuidBytes;
+ if (auto EC = Reader->readBytes(GuidBytes, GuidSize))
+ return EC;
+ memcpy(Guid.Guid, GuidBytes.data(), GuidSize);
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value,
+ const Twine &Comment) {
+
+ if (!isReading()) {
+ emitComment(Comment);
+ for (auto V : Value) {
+ if (auto EC = mapStringZ(V))
+ return EC;
+ }
+ uint8_t FinalZero = 0;
+ if (auto EC = mapInteger(FinalZero))
+ return EC;
+ } else {
+ StringRef S;
+ if (auto EC = mapStringZ(S))
+ return EC;
+ while (!S.empty()) {
+ Value.push_back(S);
+ if (auto EC = mapStringZ(S))
+ return EC;
+ };
+ }
+ return Error::success();
+}
+
+void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
+ const Twine &Comment) {
+ assert(Value < 0 && "Encoded integer is not signed!");
+ if (Value >= std::numeric_limits<int8_t>::min()) {
+ Streamer->EmitIntValue(LF_CHAR, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 1);
+ incrStreamedLen(3);
+ } else if (Value >= std::numeric_limits<int16_t>::min()) {
+ Streamer->EmitIntValue(LF_SHORT, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 2);
+ incrStreamedLen(4);
+ } else if (Value >= std::numeric_limits<int32_t>::min()) {
+ Streamer->EmitIntValue(LF_LONG, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 4);
+ incrStreamedLen(6);
+ } else {
+ Streamer->EmitIntValue(LF_QUADWORD, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 4);
+ incrStreamedLen(6);
+ }
+}
+
+void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,
+ const Twine &Comment) {
+ if (Value < LF_NUMERIC) {
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 2);
+ incrStreamedLen(2);
+ } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+ Streamer->EmitIntValue(LF_USHORT, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 2);
+ incrStreamedLen(4);
+ } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+ Streamer->EmitIntValue(LF_ULONG, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 4);
+ incrStreamedLen(6);
+ } else {
+ Streamer->EmitIntValue(LF_UQUADWORD, 2);
+ emitComment(Comment);
+ Streamer->EmitIntValue(Value, 8);
+ incrStreamedLen(6);
+ }
+}
+
+Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
+ assert(Value < 0 && "Encoded integer is not signed!");
+ if (Value >= std::numeric_limits<int8_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
+ return EC;
+ if (auto EC = Writer->writeInteger<int8_t>(Value))
+ return EC;
+ } else if (Value >= std::numeric_limits<int16_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))
+ return EC;
+ if (auto EC = Writer->writeInteger<int16_t>(Value))
+ return EC;
+ } else if (Value >= std::numeric_limits<int32_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))
+ return EC;
+ if (auto EC = Writer->writeInteger<int32_t>(Value))
+ return EC;
+ } else {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))
+ return EC;
+ if (auto EC = Writer->writeInteger(Value))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
+ if (Value < LF_NUMERIC) {
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
+ return EC;
+ } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))
+ return EC;
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
+ return EC;
+ } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))
+ return EC;
+ if (auto EC = Writer->writeInteger<uint32_t>(Value))
+ return EC;
+ } else {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))
+ return EC;
+ if (auto EC = Writer->writeInteger(Value))
+ return EC;
+ }
+
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
new file mode 100644
index 000000000000..799cffb7116e
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
@@ -0,0 +1,251 @@
+#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));
+
+ // Seed the first record with an appropriate record prefix.
+ RecordPrefix Prefix(getTypeLeafKind(RecordKind));
+ CVType Type(&Prefix, sizeof(Prefix));
+ cantFail(Mapping.visitTypeBegin(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);
+
+ // Write the length to the RecordPrefix, making sure it does not include
+ // sizeof(RecordPrefix.Length)
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data());
+ 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 CVType(Data);
+}
+
+std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) {
+ RecordPrefix Prefix(getTypeLeafKind(*Kind));
+ CVType Type(&Prefix, sizeof(Prefix));
+ 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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
new file mode 100644
index 000000000000..3d28bac00c44
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
@@ -0,0 +1,115 @@
+//===- DebugChecksumsSubsection.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+struct FileChecksumEntryHeader {
+ using ulittle32_t = support::ulittle32_t;
+
+ ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
+ uint8_t ChecksumSize; // Number of bytes of checksum.
+ uint8_t ChecksumKind; // FileChecksumKind
+ // Checksum bytes follow.
+};
+
+Error VarStreamArrayExtractor<FileChecksumEntry>::
+operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
+ BinaryStreamReader Reader(Stream);
+
+ const FileChecksumEntryHeader *Header;
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ Item.FileNameOffset = Header->FileNameOffset;
+ Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
+ if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
+ return EC;
+
+ Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
+ return Error::success();
+}
+
+Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+ return EC;
+
+ return Error::success();
+}
+
+Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {
+ BinaryStreamReader Reader(Section);
+ return initialize(Reader);
+}
+
+DebugChecksumsSubsection::DebugChecksumsSubsection(
+ DebugStringTableSubsection &Strings)
+ : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}
+
+void DebugChecksumsSubsection::addChecksum(StringRef FileName,
+ FileChecksumKind Kind,
+ ArrayRef<uint8_t> Bytes) {
+ FileChecksumEntry Entry;
+ if (!Bytes.empty()) {
+ uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
+ ::memcpy(Copy, Bytes.data(), Bytes.size());
+ Entry.Checksum = makeArrayRef(Copy, Bytes.size());
+ }
+
+ Entry.FileNameOffset = Strings.insert(FileName);
+ Entry.Kind = Kind;
+ Checksums.push_back(Entry);
+
+ // This maps the offset of this string in the string table to the offset
+ // of this checksum entry in the checksum buffer.
+ OffsetMap[Entry.FileNameOffset] = SerializedSize;
+ assert(SerializedSize % 4 == 0);
+
+ uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
+ SerializedSize += Len;
+}
+
+uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {
+ return SerializedSize;
+}
+
+Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {
+ for (const auto &FC : Checksums) {
+ FileChecksumEntryHeader Header;
+ Header.ChecksumKind = uint8_t(FC.Kind);
+ Header.ChecksumSize = FC.Checksum.size();
+ Header.FileNameOffset = FC.FileNameOffset;
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
+ return EC;
+ if (auto EC = Writer.padToAlignment(4))
+ return EC;
+ }
+ return Error::success();
+}
+
+uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
+ uint32_t Offset = Strings.getIdForString(FileName);
+ auto Iter = OffsetMap.find(Offset);
+ assert(Iter != OffsetMap.end());
+ return Iter->second;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
new file mode 100644
index 000000000000..b23410409f88
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
@@ -0,0 +1,52 @@
+//===- DebugCrossExSubsection.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugCrossModuleExportsSubsectionRef::initialize(
+ BinaryStreamReader Reader) {
+ if (Reader.bytesRemaining() % sizeof(CrossModuleExport) != 0)
+ return make_error<CodeViewError>(
+ cv_error_code::corrupt_record,
+ "Cross Scope Exports section is an invalid size!");
+
+ uint32_t Size = Reader.bytesRemaining() / sizeof(CrossModuleExport);
+ return Reader.readArray(References, Size);
+}
+
+Error DebugCrossModuleExportsSubsectionRef::initialize(BinaryStreamRef Stream) {
+ BinaryStreamReader Reader(Stream);
+ return initialize(Reader);
+}
+
+void DebugCrossModuleExportsSubsection::addMapping(uint32_t Local,
+ uint32_t Global) {
+ Mappings[Local] = Global;
+}
+
+uint32_t DebugCrossModuleExportsSubsection::calculateSerializedSize() const {
+ return Mappings.size() * sizeof(CrossModuleExport);
+}
+
+Error DebugCrossModuleExportsSubsection::commit(
+ BinaryStreamWriter &Writer) const {
+ for (const auto &M : Mappings) {
+ if (auto EC = Writer.writeInteger(M.first))
+ return EC;
+ if (auto EC = Writer.writeInteger(M.second))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
new file mode 100644
index 000000000000..dbadafd3aaf3
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
@@ -0,0 +1,96 @@
+//===- DebugCrossImpSubsection.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error VarStreamArrayExtractor<CrossModuleImportItem>::
+operator()(BinaryStreamRef Stream, uint32_t &Len,
+ codeview::CrossModuleImportItem &Item) {
+ BinaryStreamReader Reader(Stream);
+ if (Reader.bytesRemaining() < sizeof(CrossModuleImport))
+ return make_error<CodeViewError>(
+ cv_error_code::insufficient_buffer,
+ "Not enough bytes for a Cross Module Import Header!");
+ if (auto EC = Reader.readObject(Item.Header))
+ return EC;
+ if (Reader.bytesRemaining() < Item.Header->Count * sizeof(uint32_t))
+ return make_error<CodeViewError>(
+ cv_error_code::insufficient_buffer,
+ "Not enough to read specified number of Cross Module References!");
+ if (auto EC = Reader.readArray(Item.Imports, Item.Header->Count))
+ return EC;
+ return Error::success();
+}
+
+Error DebugCrossModuleImportsSubsectionRef::initialize(
+ BinaryStreamReader Reader) {
+ return Reader.readArray(References, Reader.bytesRemaining());
+}
+
+Error DebugCrossModuleImportsSubsectionRef::initialize(BinaryStreamRef Stream) {
+ BinaryStreamReader Reader(Stream);
+ return initialize(Reader);
+}
+
+void DebugCrossModuleImportsSubsection::addImport(StringRef Module,
+ uint32_t ImportId) {
+ Strings.insert(Module);
+ std::vector<support::ulittle32_t> Targets = {support::ulittle32_t(ImportId)};
+ auto Result = Mappings.insert(std::make_pair(Module, Targets));
+ if (!Result.second)
+ Result.first->getValue().push_back(Targets[0]);
+}
+
+uint32_t DebugCrossModuleImportsSubsection::calculateSerializedSize() const {
+ uint32_t Size = 0;
+ for (const auto &Item : Mappings) {
+ Size += sizeof(CrossModuleImport);
+ Size += sizeof(support::ulittle32_t) * Item.second.size();
+ }
+ return Size;
+}
+
+Error DebugCrossModuleImportsSubsection::commit(
+ BinaryStreamWriter &Writer) const {
+ using T = decltype(&*Mappings.begin());
+ std::vector<T> Ids;
+ Ids.reserve(Mappings.size());
+
+ for (const auto &M : Mappings)
+ Ids.push_back(&M);
+
+ llvm::sort(Ids, [this](const T &L1, const T &L2) {
+ return Strings.getIdForString(L1->getKey()) <
+ Strings.getIdForString(L2->getKey());
+ });
+
+ for (const auto &Item : Ids) {
+ CrossModuleImport Imp;
+ Imp.ModuleNameOffset = Strings.getIdForString(Item->getKey());
+ Imp.Count = Item->getValue().size();
+ if (auto EC = Writer.writeObject(Imp))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(Item->getValue())))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
new file mode 100644
index 000000000000..be8c32d5b294
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
@@ -0,0 +1,61 @@
+//===- DebugFrameDataSubsection.cpp -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (Reader.bytesRemaining() % sizeof(FrameData) != 0) {
+ if (auto EC = Reader.readObject(RelocPtr))
+ return EC;
+ }
+
+ if (Reader.bytesRemaining() % sizeof(FrameData) != 0)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid frame data record format!");
+
+ uint32_t Count = Reader.bytesRemaining() / sizeof(FrameData);
+ if (auto EC = Reader.readArray(Frames, Count))
+ return EC;
+ return Error::success();
+}
+
+Error DebugFrameDataSubsectionRef::initialize(BinaryStreamRef Section) {
+ BinaryStreamReader Reader(Section);
+ return initialize(Reader);
+}
+
+uint32_t DebugFrameDataSubsection::calculateSerializedSize() const {
+ uint32_t Size = sizeof(FrameData) * Frames.size();
+ if (IncludeRelocPtr)
+ Size += sizeof(uint32_t);
+ return Size;
+}
+
+Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const {
+ if (IncludeRelocPtr) {
+ if (auto EC = Writer.writeInteger<uint32_t>(0))
+ return EC;
+ }
+
+ std::vector<FrameData> SortedFrames(Frames.begin(), Frames.end());
+ std::sort(SortedFrames.begin(), SortedFrames.end(),
+ [](const FrameData &LHS, const FrameData &RHS) {
+ return LHS.RvaStart < RHS.RvaStart;
+ });
+ if (auto EC = Writer.writeArray(makeArrayRef(SortedFrames)))
+ return EC;
+ return Error::success();
+}
+
+void DebugFrameDataSubsection::addFrameData(const FrameData &Frame) {
+ Frames.push_back(Frame);
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
new file mode 100644
index 000000000000..48ec7e4ecdd6
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
@@ -0,0 +1,125 @@
+//===- DebugInlineeLinesSubsection.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error VarStreamArrayExtractor<InlineeSourceLine>::
+operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) {
+ BinaryStreamReader Reader(Stream);
+
+ if (auto EC = Reader.readObject(Item.Header))
+ return EC;
+
+ if (HasExtraFiles) {
+ uint32_t ExtraFileCount;
+ if (auto EC = Reader.readInteger(ExtraFileCount))
+ return EC;
+ if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount))
+ return EC;
+ }
+
+ Len = Reader.getOffset();
+ return Error::success();
+}
+
+DebugInlineeLinesSubsectionRef::DebugInlineeLinesSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::InlineeLines) {}
+
+Error DebugInlineeLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readEnum(Signature))
+ return EC;
+
+ Lines.getExtractor().HasExtraFiles = hasExtraFiles();
+ if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining()))
+ return EC;
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+bool DebugInlineeLinesSubsectionRef::hasExtraFiles() const {
+ return Signature == InlineeLinesSignature::ExtraFiles;
+}
+
+DebugInlineeLinesSubsection::DebugInlineeLinesSubsection(
+ DebugChecksumsSubsection &Checksums, bool HasExtraFiles)
+ : DebugSubsection(DebugSubsectionKind::InlineeLines), Checksums(Checksums),
+ HasExtraFiles(HasExtraFiles) {}
+
+uint32_t DebugInlineeLinesSubsection::calculateSerializedSize() const {
+ // 4 bytes for the signature
+ uint32_t Size = sizeof(InlineeLinesSignature);
+
+ // one header for each entry.
+ Size += Entries.size() * sizeof(InlineeSourceLineHeader);
+ if (HasExtraFiles) {
+ // If extra files are enabled, one count for each entry.
+ Size += Entries.size() * sizeof(uint32_t);
+
+ // And one file id for each file.
+ Size += ExtraFileCount * sizeof(uint32_t);
+ }
+ assert(Size % 4 == 0);
+ return Size;
+}
+
+Error DebugInlineeLinesSubsection::commit(BinaryStreamWriter &Writer) const {
+ InlineeLinesSignature Sig = InlineeLinesSignature::Normal;
+ if (HasExtraFiles)
+ Sig = InlineeLinesSignature::ExtraFiles;
+
+ if (auto EC = Writer.writeEnum(Sig))
+ return EC;
+
+ for (const auto &E : Entries) {
+ if (auto EC = Writer.writeObject(E.Header))
+ return EC;
+
+ if (!HasExtraFiles)
+ continue;
+
+ if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size()))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles)))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+void DebugInlineeLinesSubsection::addExtraFile(StringRef FileName) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ auto &Entry = Entries.back();
+ Entry.ExtraFiles.push_back(ulittle32_t(Offset));
+ ++ExtraFileCount;
+}
+
+void DebugInlineeLinesSubsection::addInlineSite(TypeIndex FuncId,
+ StringRef FileName,
+ uint32_t SourceLine) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ Entries.emplace_back();
+ auto &Entry = Entries.back();
+ Entry.Header.FileID = Offset;
+ Entry.Header.SourceLineNum = SourceLine;
+ Entry.Header.Inlinee = FuncId;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
new file mode 100644
index 000000000000..ea16c0a6c671
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
@@ -0,0 +1,160 @@
+//===- DebugLinesSubsection.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len,
+ LineColumnEntry &Item) {
+ const LineBlockFragmentHeader *BlockHeader;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(BlockHeader))
+ return EC;
+ bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns);
+ uint32_t LineInfoSize =
+ BlockHeader->NumLines *
+ (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
+ if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader);
+ if (LineInfoSize > Size)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ // The value recorded in BlockHeader->BlockSize includes the size of
+ // LineBlockFragmentHeader.
+ Len = BlockHeader->BlockSize;
+ Item.NameIndex = BlockHeader->NameIndex;
+ if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines))
+ return EC;
+ if (HasColumn) {
+ if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines))
+ return EC;
+ }
+ return Error::success();
+}
+
+DebugLinesSubsectionRef::DebugLinesSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::Lines) {}
+
+Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ LinesAndColumns.getExtractor().Header = Header;
+ if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining()))
+ return EC;
+
+ return Error::success();
+}
+
+bool DebugLinesSubsectionRef::hasColumnInfo() const {
+ return !!(Header->Flags & LF_HaveColumns);
+}
+
+DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums,
+ DebugStringTableSubsection &Strings)
+ : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {}
+
+void DebugLinesSubsection::createBlock(StringRef FileName) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ Blocks.emplace_back(Offset);
+}
+
+void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) {
+ Block &B = Blocks.back();
+ LineNumberEntry LNE;
+ LNE.Flags = Line.getRawData();
+ LNE.Offset = Offset;
+ B.Lines.push_back(LNE);
+}
+
+void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset,
+ const LineInfo &Line,
+ uint32_t ColStart,
+ uint32_t ColEnd) {
+ Block &B = Blocks.back();
+ assert(B.Lines.size() == B.Columns.size());
+
+ addLineInfo(Offset, Line);
+ ColumnNumberEntry CNE;
+ CNE.StartColumn = ColStart;
+ CNE.EndColumn = ColEnd;
+ B.Columns.push_back(CNE);
+}
+
+Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const {
+ LineFragmentHeader Header;
+ Header.CodeSize = CodeSize;
+ Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0;
+ Header.RelocOffset = RelocOffset;
+ Header.RelocSegment = RelocSegment;
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ for (const auto &B : Blocks) {
+ LineBlockFragmentHeader BlockHeader;
+ assert(B.Lines.size() == B.Columns.size() || B.Columns.empty());
+
+ BlockHeader.NumLines = B.Lines.size();
+ BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader);
+ BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry);
+ if (hasColumnInfo())
+ BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry);
+ BlockHeader.NameIndex = B.ChecksumBufferOffset;
+ if (auto EC = Writer.writeObject(BlockHeader))
+ return EC;
+
+ if (auto EC = Writer.writeArray(makeArrayRef(B.Lines)))
+ return EC;
+
+ if (hasColumnInfo()) {
+ if (auto EC = Writer.writeArray(makeArrayRef(B.Columns)))
+ return EC;
+ }
+ }
+ return Error::success();
+}
+
+uint32_t DebugLinesSubsection::calculateSerializedSize() const {
+ uint32_t Size = sizeof(LineFragmentHeader);
+ for (const auto &B : Blocks) {
+ Size += sizeof(LineBlockFragmentHeader);
+ Size += B.Lines.size() * sizeof(LineNumberEntry);
+ if (hasColumnInfo())
+ Size += B.Columns.size() * sizeof(ColumnNumberEntry);
+ }
+ return Size;
+}
+
+void DebugLinesSubsection::setRelocationAddress(uint16_t Segment,
+ uint32_t Offset) {
+ RelocOffset = Offset;
+ RelocSegment = Segment;
+}
+
+void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; }
+
+void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; }
+
+bool DebugLinesSubsection::hasColumnInfo() const {
+ return Flags & LF_HaveColumns;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
new file mode 100644
index 000000000000..63342749918d
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
@@ -0,0 +1,107 @@
+//===- DebugStringTableSubsection.cpp - CodeView String Table -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugStringTableSubsectionRef::DebugStringTableSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::StringTable) {}
+
+Error DebugStringTableSubsectionRef::initialize(BinaryStreamRef Contents) {
+ Stream = Contents;
+ return Error::success();
+}
+
+Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) {
+ return Reader.readStreamRef(Stream);
+}
+
+Expected<StringRef>
+DebugStringTableSubsectionRef::getString(uint32_t Offset) const {
+ BinaryStreamReader Reader(Stream);
+ Reader.setOffset(Offset);
+ StringRef Result;
+ if (auto EC = Reader.readCString(Result))
+ return std::move(EC);
+ return Result;
+}
+
+DebugStringTableSubsection::DebugStringTableSubsection()
+ : DebugSubsection(DebugSubsectionKind::StringTable) {}
+
+uint32_t DebugStringTableSubsection::insert(StringRef S) {
+ auto P = StringToId.insert({S, StringSize});
+
+ // If a given string didn't exist in the string table, we want to increment
+ // the string table size and insert it into the reverse lookup.
+ if (P.second) {
+ IdToString.insert({P.first->getValue(), P.first->getKey()});
+ StringSize += S.size() + 1; // +1 for '\0'
+ }
+
+ return P.first->second;
+}
+
+uint32_t DebugStringTableSubsection::calculateSerializedSize() const {
+ return StringSize;
+}
+
+Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
+ uint32_t Begin = Writer.getOffset();
+ uint32_t End = Begin + StringSize;
+
+ // Write a null string at the beginning.
+ if (auto EC = Writer.writeCString(StringRef()))
+ return EC;
+
+ for (auto &Pair : StringToId) {
+ StringRef S = Pair.getKey();
+ uint32_t Offset = Begin + Pair.getValue();
+ Writer.setOffset(Offset);
+ if (auto EC = Writer.writeCString(S))
+ return EC;
+ assert(Writer.getOffset() <= End);
+ }
+
+ Writer.setOffset(End);
+ assert((End - Begin) == StringSize);
+ return Error::success();
+}
+
+uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); }
+
+std::vector<uint32_t> DebugStringTableSubsection::sortedIds() const {
+ std::vector<uint32_t> Result;
+ Result.reserve(IdToString.size());
+ for (const auto &Entry : IdToString)
+ Result.push_back(Entry.first);
+ llvm::sort(Result);
+ return Result;
+}
+
+uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const {
+ auto Iter = StringToId.find(S);
+ assert(Iter != StringToId.end());
+ return Iter->second;
+}
+
+StringRef DebugStringTableSubsection::getStringForId(uint32_t Id) const {
+ auto Iter = IdToString.find(Id);
+ assert(Iter != IdToString.end());
+ return Iter->second;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp
new file mode 100644
index 000000000000..3f93463fe6d6
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp
@@ -0,0 +1,15 @@
+//===- DebugSubsection.cpp -----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+
+using namespace llvm::codeview;
+
+DebugSubsectionRef::~DebugSubsectionRef() {}
+
+DebugSubsection::~DebugSubsection() {}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
new file mode 100644
index 000000000000..0f704f286ee9
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
@@ -0,0 +1,96 @@
+//===- DebugSubsectionRecord.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugSubsectionRecord::DebugSubsectionRecord() = default;
+
+DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
+ BinaryStreamRef Data,
+ CodeViewContainer Container)
+ : Container(Container), Kind(Kind), Data(Data) {}
+
+Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
+ DebugSubsectionRecord &Info,
+ CodeViewContainer Container) {
+ const DebugSubsectionHeader *Header;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ DebugSubsectionKind Kind =
+ static_cast<DebugSubsectionKind>(uint32_t(Header->Kind));
+ if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
+ return EC;
+ Info.Container = Container;
+ Info.Kind = Kind;
+ return Error::success();
+}
+
+uint32_t DebugSubsectionRecord::getRecordLength() const {
+ return sizeof(DebugSubsectionHeader) + Data.getLength();
+}
+
+DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
+
+BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
+
+DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
+ std::shared_ptr<DebugSubsection> Subsection, CodeViewContainer Container)
+ : Subsection(std::move(Subsection)), Container(Container) {}
+
+DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
+ const DebugSubsectionRecord &Contents, CodeViewContainer Container)
+ : Contents(Contents), Container(Container) {}
+
+uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
+ uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
+ : Contents.getRecordData().getLength();
+ // The length of the entire subsection is always padded to 4 bytes,
+ // regardless of the container kind.
+ return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4);
+}
+
+Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) const {
+ assert(Writer.getOffset() % alignOf(Container) == 0 &&
+ "Debug Subsection not properly aligned");
+
+ DebugSubsectionHeader Header;
+ Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind());
+ // The value written into the Header's Length field is only padded to the
+ // container's alignment
+ uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
+ : Contents.getRecordData().getLength();
+ Header.Length = alignTo(DataSize, alignOf(Container));
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+ if (Subsection) {
+ if (auto EC = Subsection->commit(Writer))
+ return EC;
+ } else {
+ if (auto EC = Writer.writeStreamRef(Contents.getRecordData()))
+ return EC;
+ }
+ if (auto EC = Writer.padToAlignment(4))
+ return EC;
+
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
new file mode 100644
index 000000000000..7968b6a2d757
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
@@ -0,0 +1,94 @@
+//===- DebugSubsectionVisitor.cpp -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error llvm::codeview::visitDebugSubsection(
+ const DebugSubsectionRecord &R, DebugSubsectionVisitor &V,
+ const StringsAndChecksumsRef &State) {
+ BinaryStreamReader Reader(R.getRecordData());
+ switch (R.kind()) {
+ case DebugSubsectionKind::Lines: {
+ DebugLinesSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+
+ return V.visitLines(Fragment, State);
+ }
+ case DebugSubsectionKind::FileChecksums: {
+ DebugChecksumsSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+
+ return V.visitFileChecksums(Fragment, State);
+ }
+ case DebugSubsectionKind::InlineeLines: {
+ DebugInlineeLinesSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+ return V.visitInlineeLines(Fragment, State);
+ }
+ case DebugSubsectionKind::CrossScopeExports: {
+ DebugCrossModuleExportsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCrossModuleExports(Section, State);
+ }
+ case DebugSubsectionKind::CrossScopeImports: {
+ DebugCrossModuleImportsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCrossModuleImports(Section, State);
+ }
+ case DebugSubsectionKind::Symbols: {
+ DebugSymbolsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitSymbols(Section, State);
+ }
+ case DebugSubsectionKind::StringTable: {
+ DebugStringTableSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitStringTable(Section, State);
+ }
+ case DebugSubsectionKind::FrameData: {
+ DebugFrameDataSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitFrameData(Section, State);
+ }
+ case DebugSubsectionKind::CoffSymbolRVA: {
+ DebugSymbolRVASubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCOFFSymbolRVAs(Section, State);
+ }
+ default: {
+ DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData());
+ return V.visitUnknown(Fragment);
+ }
+ }
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
new file mode 100644
index 000000000000..52328967357b
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
@@ -0,0 +1,35 @@
+//===- DebugSymbolRVASubsection.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugSymbolRVASubsectionRef::DebugSymbolRVASubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::CoffSymbolRVA) {}
+
+Error DebugSymbolRVASubsectionRef::initialize(BinaryStreamReader &Reader) {
+ return Reader.readArray(RVAs, Reader.bytesRemaining() / sizeof(uint32_t));
+}
+
+DebugSymbolRVASubsection::DebugSymbolRVASubsection()
+ : DebugSubsection(DebugSubsectionKind::CoffSymbolRVA) {}
+
+Error DebugSymbolRVASubsection::commit(BinaryStreamWriter &Writer) const {
+ return Writer.writeArray(makeArrayRef(RVAs));
+}
+
+uint32_t DebugSymbolRVASubsection::calculateSerializedSize() const {
+ return RVAs.size() * sizeof(uint32_t);
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
new file mode 100644
index 000000000000..c833103663e4
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
@@ -0,0 +1,33 @@
+//===- DebugSymbolsSubsection.cpp -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugSymbolsSubsectionRef::initialize(BinaryStreamReader Reader) {
+ return Reader.readArray(Records, Reader.getLength());
+}
+
+uint32_t DebugSymbolsSubsection::calculateSerializedSize() const {
+ return Length;
+}
+
+Error DebugSymbolsSubsection::commit(BinaryStreamWriter &Writer) const {
+ for (const auto &Record : Records) {
+ if (auto EC = Writer.writeBytes(Record.RecordData))
+ return EC;
+ }
+ return Error::success();
+}
+
+void DebugSymbolsSubsection::addSymbol(CVSymbol Symbol) {
+ Records.push_back(Symbol);
+ Length += Symbol.length();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
new file mode 100644
index 000000000000..54e68ae4ea9f
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -0,0 +1,383 @@
+//===- EnumTables.cpp - Enum to string conversion tables ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace codeview;
+
+#define CV_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define CV_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
+#define CV_SYMBOL(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+#undef CV_SYMBOL
+};
+
+static const EnumEntry<TypeLeafKind> TypeLeafNames[] = {
+#define CV_TYPE(name, val) {#name, name},
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+#undef CV_TYPE
+};
+
+static const EnumEntry<uint16_t> RegisterNames_X86[] = {
+#define CV_REGISTERS_X86
+#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name),
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_X86
+};
+
+static const EnumEntry<uint16_t> RegisterNames_ARM64[] = {
+#define CV_REGISTERS_ARM64
+#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name),
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM64
+};
+
+static const EnumEntry<uint32_t> PublicSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Code),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Function),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Managed),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, MSIL),
+};
+
+static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
+};
+
+static const EnumEntry<uint16_t> LocalFlags[] = {
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
+};
+
+static const EnumEntry<uint8_t> FrameCookieKinds[] = {
+ CV_ENUM_CLASS_ENT(FrameCookieKind, Copy),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
+};
+
+static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = {
+ CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp),
+ CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm),
+ CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic),
+ CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link),
+ CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd),
+ 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, D),
+ CV_ENUM_ENT(SourceLanguage, Swift),
+};
+
+static const EnumEntry<uint32_t> CompileSym2FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule),
+};
+
+static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
+};
+
+static const EnumEntry<uint32_t> FileChecksumNames[] = {
+ CV_ENUM_CLASS_ENT(FileChecksumKind, None),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, MD5),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
+};
+
+static const EnumEntry<unsigned> CPUTypeNames[] = {
+ CV_ENUM_CLASS_ENT(CPUType, Intel8080),
+ CV_ENUM_CLASS_ENT(CPUType, Intel8086),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80286),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80386),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80486),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium),
+ CV_ENUM_CLASS_ENT(CPUType, PentiumPro),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium3),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS16),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS32),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS64),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSI),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIV),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSV),
+ CV_ENUM_CLASS_ENT(CPUType, M68000),
+ CV_ENUM_CLASS_ENT(CPUType, M68010),
+ CV_ENUM_CLASS_ENT(CPUType, M68020),
+ CV_ENUM_CLASS_ENT(CPUType, M68030),
+ CV_ENUM_CLASS_ENT(CPUType, M68040),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164A),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21264),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21364),
+ CV_ENUM_CLASS_ENT(CPUType, PPC601),
+ CV_ENUM_CLASS_ENT(CPUType, PPC603),
+ CV_ENUM_CLASS_ENT(CPUType, PPC604),
+ CV_ENUM_CLASS_ENT(CPUType, PPC620),
+ CV_ENUM_CLASS_ENT(CPUType, PPCFP),
+ CV_ENUM_CLASS_ENT(CPUType, PPCBE),
+ CV_ENUM_CLASS_ENT(CPUType, SH3),
+ CV_ENUM_CLASS_ENT(CPUType, SH3E),
+ CV_ENUM_CLASS_ENT(CPUType, SH3DSP),
+ CV_ENUM_CLASS_ENT(CPUType, SH4),
+ CV_ENUM_CLASS_ENT(CPUType, SHMedia),
+ CV_ENUM_CLASS_ENT(CPUType, ARM3),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM6),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
+ CV_ENUM_CLASS_ENT(CPUType, ARM7),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64),
+ CV_ENUM_CLASS_ENT(CPUType, Omni),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
+ CV_ENUM_CLASS_ENT(CPUType, CEE),
+ CV_ENUM_CLASS_ENT(CPUType, AM33),
+ CV_ENUM_CLASS_ENT(CPUType, M32R),
+ CV_ENUM_CLASS_ENT(CPUType, TriCore),
+ CV_ENUM_CLASS_ENT(CPUType, X64),
+ CV_ENUM_CLASS_ENT(CPUType, EBC),
+ CV_ENUM_CLASS_ENT(CPUType, Thumb),
+ CV_ENUM_CLASS_ENT(CPUType, ARMNT),
+ CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
+};
+
+static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedLocalBasePointerMask),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedParamBasePointerMask),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
+};
+
+static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = {
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, None),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, Lines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA),
+};
+
+static const EnumEntry<uint16_t> ExportSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ExportFlags, IsConstant),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsData),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasNoName),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder),
+};
+
+static const EnumEntry<uint8_t> ThunkOrdinalNames[] = {
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland),
+};
+
+static const EnumEntry<uint16_t> TrampolineNames[] = {
+ CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental),
+ CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ ImageSectionCharacteristicNames[] = {
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)};
+
+namespace llvm {
+namespace codeview {
+
+ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() {
+ return makeArrayRef(SymbolTypeNames);
+}
+
+ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames() {
+ return makeArrayRef(TypeLeafNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getRegisterNames(CPUType Cpu) {
+ if (Cpu == CPUType::ARM64) {
+ return makeArrayRef(RegisterNames_ARM64);
+ }
+ return makeArrayRef(RegisterNames_X86);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getPublicSymFlagNames() {
+ return makeArrayRef(PublicSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() {
+ return makeArrayRef(ProcSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() {
+ return makeArrayRef(LocalFlags);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() {
+ return makeArrayRef(FrameCookieKinds);
+}
+
+ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() {
+ return makeArrayRef(SourceLanguages);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() {
+ return makeArrayRef(CompileSym2FlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() {
+ return makeArrayRef(CompileSym3FlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() {
+ return makeArrayRef(FileChecksumNames);
+}
+
+ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() {
+ return makeArrayRef(CPUTypeNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() {
+ return makeArrayRef(FrameProcSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
+ return makeArrayRef(ExportSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+ return makeArrayRef(ModuleSubstreamKindNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
+ return makeArrayRef(ThunkOrdinalNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() {
+ return makeArrayRef(TrampolineNames);
+}
+
+ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
+getImageSectionCharacteristicNames() {
+ return makeArrayRef(ImageSectionCharacteristicNames);
+}
+
+} // end namespace codeview
+} // end namespace llvm
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp
new file mode 100644
index 000000000000..a7a8c7ff82bf
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Formatters.cpp
@@ -0,0 +1,47 @@
+//===- Formatters.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/GUID.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::codeview::detail;
+
+GuidAdapter::GuidAdapter(StringRef Guid)
+ : FormatAdapter(makeArrayRef(Guid.bytes_begin(), Guid.bytes_end())) {}
+
+GuidAdapter::GuidAdapter(ArrayRef<uint8_t> Guid)
+ : FormatAdapter(std::move(Guid)) {}
+
+void GuidAdapter::format(raw_ostream &Stream, StringRef Style) {
+ static const char *Lookup = "0123456789ABCDEF";
+
+ assert(Item.size() == 16 && "Expected 16-byte GUID");
+ Stream << "{";
+ for (int i = 0; i < 16;) {
+ uint8_t Byte = Item[i];
+ uint8_t HighNibble = (Byte >> 4) & 0xF;
+ uint8_t LowNibble = Byte & 0xF;
+ Stream << Lookup[HighNibble] << Lookup[LowNibble];
+ ++i;
+ if (i >= 4 && i <= 10 && i % 2 == 0)
+ Stream << "-";
+ }
+ Stream << "}";
+}
+
+raw_ostream &llvm::codeview::operator<<(raw_ostream &OS, const GUID &Guid) {
+ codeview::detail::GuidAdapter A(Guid.Guid);
+ A.format(OS, "");
+ return OS;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
new file mode 100644
index 000000000000..a7ad1d045f04
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
@@ -0,0 +1,106 @@
+//===- GlobalTypeTableBuilder.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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(SeenRecords[Index.toArrayIndex()]);
+ 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();
+}
+
+TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) {
+ GloballyHashedType GHT =
+ GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
+ return insertRecordAs(GHT, Record.size(),
+ [Record](MutableArrayRef<uint8_t> Data) {
+ assert(Data.size() == Record.size());
+ ::memcpy(Data.data(), Record.data(), Record.size());
+ return Data;
+ });
+}
+
+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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
new file mode 100644
index 000000000000..dc1253b7a39f
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -0,0 +1,279 @@
+//===- LazyRandomTypeCollection.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void error(Error &&EC) {
+ assert(!static_cast<bool>(EC));
+ if (EC)
+ consumeError(std::move(EC));
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
+ PartialOffsetArray()) {}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(
+ const CVTypeArray &Types, uint32_t RecordCountHint,
+ PartialOffsetArray PartialOffsets)
+ : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) {
+ Records.resize(RecordCountHint);
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(RecordCountHint) {
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(
+ makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) {
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
+ uint32_t NumRecords)
+ : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
+
+void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader,
+ uint32_t RecordCountHint) {
+ Count = 0;
+ PartialOffsets = PartialOffsetArray();
+
+ 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) {
+ BinaryStreamReader Reader(Data, support::little);
+ reset(Reader, RecordCountHint);
+}
+
+uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) {
+ error(ensureTypeExists(Index));
+ assert(contains(Index));
+
+ return Records[Index.toArrayIndex()].Offset;
+}
+
+CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
+ assert(!Index.isSimple());
+
+ auto EC = ensureTypeExists(Index);
+ error(std::move(EC));
+ assert(contains(Index));
+
+ return Records[Index.toArrayIndex()].Type;
+}
+
+Optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) {
+ if (Index.isSimple())
+ return None;
+
+ 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);
+
+ // Try to make sure the type exists. Even if it doesn't though, it may be
+ // because we're dumping a symbol stream with no corresponding type stream
+ // present, in which case we still want to be able to print <unknown UDT>
+ // for the type names.
+ if (auto EC = ensureTypeExists(Index)) {
+ consumeError(std::move(EC));
+ return "<unknown UDT>";
+ }
+
+ uint32_t I = Index.toArrayIndex();
+ ensureCapacityFor(Index);
+ if (Records[I].Name.data() == nullptr) {
+ StringRef Result = NameStorage.save(computeTypeName(*this, Index));
+ Records[I].Name = Result;
+ }
+ return Records[I].Name;
+}
+
+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())
+ return false;
+ return true;
+}
+
+uint32_t LazyRandomTypeCollection::size() { return Count; }
+
+uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); }
+
+Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
+ if (contains(TI))
+ return Error::success();
+
+ return visitRangeForType(TI);
+}
+
+void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) {
+ assert(!Index.isSimple());
+ uint32_t MinSize = Index.toArrayIndex() + 1;
+
+ if (MinSize <= capacity())
+ return;
+
+ uint32_t NewCapacity = MinSize * 3 / 2;
+
+ assert(NewCapacity > capacity());
+ Records.resize(NewCapacity);
+}
+
+Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
+ assert(!TI.isSimple());
+ if (PartialOffsets.empty())
+ return fullScanForType(TI);
+
+ auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
+ [](TypeIndex Value, const TypeIndexOffset &IO) {
+ return Value < IO.Type;
+ });
+
+ assert(Next != PartialOffsets.begin());
+ auto Prev = std::prev(Next);
+
+ TypeIndex TIB = Prev->Type;
+ if (contains(TIB)) {
+ // They've asked us to fetch a type index, but the entry we found in the
+ // partial offsets array has already been visited. Since we visit an entire
+ // block every time, that means this record should have been previously
+ // discovered. Ultimately, this means this is a request for a non-existant
+ // type index.
+ return make_error<CodeViewError>("Invalid type index");
+ }
+
+ TypeIndex TIE;
+ if (Next == PartialOffsets.end()) {
+ TIE = TypeIndex::fromArrayIndex(capacity());
+ } else {
+ TIE = Next->Type;
+ }
+
+ visitRange(TIB, Prev->Offset, TIE);
+ return Error::success();
+}
+
+Optional<TypeIndex> LazyRandomTypeCollection::getFirst() {
+ TypeIndex TI = TypeIndex::fromArrayIndex(0);
+ if (auto EC = ensureTypeExists(TI)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+ return TI;
+}
+
+Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) {
+ // We can't be sure how long this type stream is, given that the initial count
+ // given to the constructor is just a hint. So just try to make sure the next
+ // record exists, and if anything goes wrong, we must be at the end.
+ if (auto EC = ensureTypeExists(Prev + 1)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+
+ return Prev + 1;
+}
+
+Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
+ assert(!TI.isSimple());
+ assert(PartialOffsets.empty());
+
+ TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
+ auto Begin = Types.begin();
+
+ if (Count > 0) {
+ // In the case of type streams which we don't know the number of records of,
+ // it's possible to search for a type index triggering a full scan, but then
+ // later additional records are added since we didn't know how many there
+ // would be until we did a full visitation, then you try to access the new
+ // type triggering another full scan. To avoid this, we assume that if the
+ // database has some records, this must be what's going on. We can also
+ // assume that this index must be larger than the largest type index we've
+ // visited, so we start from there and scan forward.
+ uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset;
+ CurrentTI = LargestTypeIndex + 1;
+ Begin = Types.at(Offset);
+ ++Begin;
+ }
+
+ auto End = Types.end();
+ while (Begin != End) {
+ ensureCapacityFor(CurrentTI);
+ LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI);
+ auto Idx = CurrentTI.toArrayIndex();
+ Records[Idx].Type = *Begin;
+ Records[Idx].Offset = Begin.offset();
+ ++Count;
+ ++Begin;
+ ++CurrentTI;
+ }
+ if (CurrentTI <= TI) {
+ return make_error<CodeViewError>("Type Index does not exist!");
+ }
+ return Error::success();
+}
+
+void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset,
+ TypeIndex End) {
+ auto RI = Types.at(BeginOffset);
+ assert(RI != Types.end());
+
+ ensureCapacityFor(End);
+ while (Begin != End) {
+ LargestTypeIndex = std::max(LargestTypeIndex, Begin);
+ auto Idx = Begin.toArrayIndex();
+ Records[Idx].Type = *RI;
+ Records[Idx].Offset = RI.offset();
+ ++Count;
+ ++Begin;
+ ++RI;
+ }
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Line.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Line.cpp
new file mode 100644
index 000000000000..53adc8cac511
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/Line.cpp
@@ -0,0 +1,21 @@
+//===-- Line.cpp ----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/Line.h"
+
+using namespace llvm;
+using namespace codeview;
+
+LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) {
+ LineData = StartLine & StartLineMask;
+ uint32_t LineDelta = EndLine - StartLine;
+ LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask;
+ if (IsStatement) {
+ LineData |= StatementFlag;
+ }
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
new file mode 100644
index 000000000000..4d7cd468f3ee
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
@@ -0,0 +1,123 @@
+//===- MergingTypeTableBuilder.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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(SeenRecords[Index.toArrayIndex()]);
+ 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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordName.cpp
new file mode 100644
index 000000000000..cfaad1581159
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordName.cpp
@@ -0,0 +1,337 @@
+//===- RecordName.cpp ----------------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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 {
+ 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("*");
+
+ // Qualifiers in pointer records apply to the pointer, not the pointee, so
+ // they go on the right.
+ if (Ptr.isConst())
+ Name.append(" const");
+ if (Ptr.isVolatile())
+ Name.append(" volatile");
+ if (Ptr.isUnaligned())
+ Name.append(" __unaligned");
+ if (Ptr.isRestrict())
+ Name.append(" __restrict");
+ }
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+
+ 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();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ 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:
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF:
+ 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;
+ // See UsingNamespaceSym
+ case SymbolKind::S_UNAMESPACE:
+ return 0;
+ 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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
new file mode 100644
index 000000000000..e7f032f9c670
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -0,0 +1,154 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for serializing and deserializing CodeView records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#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"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+
+/// Reinterpret a byte array as an array of characters. Does not interpret as
+/// a C string, as StringRef has several helpers (split) that make that easy.
+StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+ return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+ LeafData.size());
+}
+
+StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+ return getBytesAsCharacters(LeafData).split('\0').first;
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
+ // Used to avoid overload ambiguity on APInt construtor.
+ bool FalseVal = false;
+ uint16_t Short;
+ if (auto EC = Reader.readInteger(Short))
+ return EC;
+
+ if (Short < LF_NUMERIC) {
+ Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ return Error::success();
+ }
+
+ switch (Short) {
+ case LF_CHAR: {
+ int8_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(8, N, true), false);
+ return Error::success();
+ }
+ case LF_SHORT: {
+ int16_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(16, N, true), false);
+ return Error::success();
+ }
+ case LF_USHORT: {
+ uint16_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(16, N, false), true);
+ return Error::success();
+ }
+ case LF_LONG: {
+ int32_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(32, N, true), false);
+ return Error::success();
+ }
+ case LF_ULONG: {
+ uint32_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(32, N, FalseVal), true);
+ return Error::success();
+ }
+ case LF_QUADWORD: {
+ int64_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(64, N, true), false);
+ return Error::success();
+ }
+ case LF_UQUADWORD: {
+ uint64_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(64, N, false), true);
+ return Error::success();
+ }
+ }
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Buffer contains invalid APSInt type");
+}
+
+Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryStreamReader SR(S);
+ auto EC = consume(SR, Num);
+ Data = Data.take_back(SR.bytesRemaining());
+ return EC;
+}
+
+/// Decode a numeric leaf value that is known to be a uint64_t.
+Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
+ uint64_t &Num) {
+ APSInt N;
+ if (auto EC = consume(Reader, N))
+ return EC;
+ if (N.isSigned() || !N.isIntN(64))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Data is not a numeric value!");
+ Num = N.getLimitedValue();
+ return Error::success();
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
+ return Reader.readInteger(Item);
+}
+
+Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryStreamReader SR(S);
+ auto EC = consume(SR, Item);
+ Data = Data.take_back(SR.bytesRemaining());
+ return EC;
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
+ return Reader.readInteger(Item);
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
+ if (Reader.empty())
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Null terminated string buffer is empty!");
+
+ return Reader.readCString(Item);
+}
+
+Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
+ uint32_t Offset) {
+ return readCVRecordFromStream<SymbolKind>(Stream, Offset);
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
new file mode 100644
index 000000000000..654c40a7470d
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
@@ -0,0 +1,56 @@
+#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+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);
+
+ // Write the record prefix first with a dummy length but real kind.
+ RecordPrefix DummyPrefix(uint16_t(Record.getKind()));
+ cantFail(Writer.writeObject(DummyPrefix));
+
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(ScratchBuffer.data());
+ CVType CVT(Prefix, sizeof(RecordPrefix));
+
+ cantFail(Mapping.visitTypeBegin(CVT));
+ cantFail(Mapping.visitKnownRecord(CVT, Record));
+ cantFail(Mapping.visitTypeEnd(CVT));
+
+ addPadding(Writer);
+
+ // Update the size and kind after serialization.
+ 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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
new file mode 100644
index 000000000000..9e204eec8604
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
@@ -0,0 +1,80 @@
+//===- StringsAndChecksums.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StringsAndChecksumsRef::StringsAndChecksumsRef() = default;
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+ const DebugStringTableSubsectionRef &Strings)
+ : Strings(&Strings) {}
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+ const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums)
+ : Strings(&Strings), Checksums(&Checksums) {}
+
+void StringsAndChecksumsRef::initializeStrings(
+ const DebugSubsectionRecord &SR) {
+ assert(SR.kind() == DebugSubsectionKind::StringTable);
+ assert(!Strings && "Found a string table even though we already have one!");
+
+ 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 = std::make_shared<DebugChecksumsSubsectionRef>();
+ *OwnedChecksums = CS;
+ Checksums = OwnedChecksums.get();
+}
+
+void StringsAndChecksumsRef::initializeChecksums(
+ const DebugSubsectionRecord &FCR) {
+ assert(FCR.kind() == DebugSubsectionKind::FileChecksums);
+ if (Checksums)
+ return;
+
+ OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>();
+ consumeError(OwnedChecksums->initialize(FCR.getRecordData()));
+ Checksums = OwnedChecksums.get();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
new file mode 100644
index 000000000000..27cb7e35234b
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -0,0 +1,679 @@
+//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+/// Use this private dumper implementation to keep implementation details about
+/// the visitor out of SymbolDumper.h.
+class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
+public:
+ CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate,
+ ScopedPrinter &W, CPUType CPU, bool PrintRecordBytes)
+ : Types(Types), ObjDelegate(ObjDelegate), W(W), CompilationCPUType(CPU),
+ PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
+
+/// CVSymbolVisitor overrides.
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownRecord(CVSymbol &CVR, Name &Record) override;
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+
+ Error visitSymbolBegin(CVSymbol &Record) override;
+ Error visitSymbolEnd(CVSymbol &Record) override;
+ Error visitUnknownSymbol(CVSymbol &Record) override;
+
+ CPUType getCompilationCPUType() const { return CompilationCPUType; }
+
+private:
+ void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
+ uint32_t RelocationOffset);
+ void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
+ void printTypeIndex(StringRef FieldName, TypeIndex TI);
+
+ TypeCollection &Types;
+ SymbolDumpDelegate *ObjDelegate;
+ ScopedPrinter &W;
+
+ /// Save the machine or CPU type when dumping a compile symbols.
+ CPUType CompilationCPUType = CPUType::X64;
+
+ bool PrintRecordBytes;
+ bool InFunctionScope;
+};
+}
+
+static StringRef getSymbolKindName(SymbolKind Kind) {
+ switch (Kind) {
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: \
+ return #Name;
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ default:
+ break;
+ }
+ return "UnknownSym";
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrRange(
+ const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
+ DictScope S(W, "LocalVariableAddrRange");
+ if (ObjDelegate)
+ ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
+ Range.OffsetStart);
+ W.printHex("ISectStart", Range.ISectStart);
+ W.printHex("Range", Range.Range);
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrGap(
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ for (auto &Gap : Gaps) {
+ ListScope S(W, "LocalVariableAddrGap");
+ W.printHex("GapStartOffset", Gap.GapStartOffset);
+ W.printHex("Range", Gap.Range);
+ }
+}
+
+void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
+ codeview::printTypeIndex(W, FieldName, TI, Types);
+}
+
+Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
+ W.startLine() << getSymbolKindName(CVR.kind());
+ W.getOStream() << " {\n";
+ W.indent();
+ W.printEnum("Kind", unsigned(CVR.kind()), getSymbolTypeNames());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) {
+ if (PrintRecordBytes && ObjDelegate)
+ ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content());
+
+ W.unindent();
+ W.startLine() << "}\n";
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+ StringRef LinkageName;
+ W.printHex("PtrParent", Block.Parent);
+ W.printHex("PtrEnd", Block.End);
+ W.printHex("CodeSize", Block.CodeSize);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(),
+ Block.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Block.Segment);
+ W.printString("BlockName", Block.Name);
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+ W.printString("Name", Thunk.Name);
+ W.printNumber("Parent", Thunk.Parent);
+ W.printNumber("End", Thunk.End);
+ W.printNumber("Next", Thunk.Next);
+ W.printNumber("Off", Thunk.Offset);
+ W.printNumber("Seg", Thunk.Segment);
+ W.printNumber("Len", Thunk.Length);
+ W.printEnum("Ordinal", uint8_t(Thunk.Thunk), getThunkOrdinalNames());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+ W.printEnum("Type", uint16_t(Tramp.Type), getTrampolineNames());
+ W.printNumber("Size", Tramp.Size);
+ W.printNumber("ThunkOff", Tramp.ThunkOffset);
+ W.printNumber("TargetOff", Tramp.TargetOffset);
+ W.printNumber("ThunkSection", Tramp.ThunkSection);
+ W.printNumber("TargetSection", Tramp.TargetSection);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) {
+ W.printNumber("SectionNumber", Section.SectionNumber);
+ W.printNumber("Alignment", Section.Alignment);
+ W.printNumber("Rva", Section.Rva);
+ W.printNumber("Length", Section.Length);
+ W.printFlags("Characteristics", Section.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ W.printString("Name", Section.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ CoffGroupSym &CoffGroup) {
+ W.printNumber("Size", CoffGroup.Size);
+ W.printFlags("Characteristics", CoffGroup.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+ W.printNumber("Offset", CoffGroup.Offset);
+ W.printNumber("Segment", CoffGroup.Segment);
+ W.printString("Name", CoffGroup.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+ W.printNumber("Offset", BPRel.Offset);
+ printTypeIndex("Type", BPRel.Type);
+ W.printString("VarName", BPRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+ printTypeIndex("BuildId", BuildInfo.BuildId);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CallSiteInfo) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ CallSiteInfo.getRelocationOffset(),
+ CallSiteInfo.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", CallSiteInfo.Segment);
+ printTypeIndex("Type", CallSiteInfo.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+ ListScope L(W, "Entries");
+ for (auto Entry : EnvBlock.Fields) {
+ W.printString(Entry);
+ }
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FileStaticSym &FileStatic) {
+ printTypeIndex("Index", FileStatic.Index);
+ W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset);
+ W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames());
+ W.printString("Name", FileStatic.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+ W.printNumber("Ordinal", Export.Ordinal);
+ W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames());
+ W.printString("Name", Export.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+ W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames());
+ W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames());
+ W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames());
+ CompilationCPUType = Compile2.Machine;
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor
+ << '.' << Compile2.VersionFrontendBuild;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor
+ << '.' << Compile2.VersionBackendBuild;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile2.Version);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+ W.printEnum("Language", uint8_t(Compile3.getLanguage()), getSourceLanguageNames());
+ W.printFlags("Flags", uint32_t(Compile3.getFlags()),
+ getCompileSym3FlagNames());
+ W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames());
+ CompilationCPUType = Compile3.Machine;
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor
+ << '.' << Compile3.VersionFrontendBuild << '.'
+ << Compile3.VersionFrontendQFE;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile3.VersionBackendMajor << '.' << Compile3.VersionBackendMinor
+ << '.' << Compile3.VersionBackendBuild << '.'
+ << Compile3.VersionBackendQFE;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile3.Version);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+ printTypeIndex("Type", Constant.Type);
+ W.printNumber("Value", Constant.Value);
+ W.printString("Name", Constant.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.DataOffset, &LinkageName);
+ }
+ printTypeIndex("Type", Data.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+ W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+ W.printNumber("Offset", DefRangeFramePointerRel.Offset);
+ printLocalVariableAddrRange(DefRangeFramePointerRel.Range,
+ DefRangeFramePointerRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+ W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printBoolean("HasSpilledUDTMember",
+ DefRangeRegisterRel.hasSpilledUDTMember());
+ W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
+ W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset);
+ printLocalVariableAddrRange(DefRangeRegisterRel.Range,
+ DefRangeRegisterRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+ W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName);
+ printLocalVariableAddrRange(DefRangeRegister.Range,
+ DefRangeRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegister.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+ W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName);
+ W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfieldRegister.Range,
+ DefRangeSubfieldRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) {
+ if (ObjDelegate) {
+ DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
+ auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
+ if (!ExpectedProgram) {
+ consumeError(ExpectedProgram.takeError());
+ return llvm::make_error<CodeViewError>(
+ "String table offset outside of bounds of String Table!");
+ }
+ W.printString("Program", *ExpectedProgram);
+ }
+ W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfield.Range,
+ DefRangeSubfield.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfield.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSym &DefRange) {
+ if (ObjDelegate) {
+ DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
+ auto ExpectedProgram = Strings.getString(DefRange.Program);
+ if (!ExpectedProgram) {
+ consumeError(ExpectedProgram.takeError());
+ return llvm::make_error<CodeViewError>(
+ "String table offset outside of bounds of String Table!");
+ }
+ W.printString("Program", *ExpectedProgram);
+ }
+ printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
+ printLocalVariableAddrGap(DefRange.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FrameCookieSym &FrameCookie) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ FrameCookie.getRelocationOffset(),
+ FrameCookie.CodeOffset, &LinkageName);
+ }
+ W.printEnum("Register", uint16_t(FrameCookie.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind),
+ getFrameCookieKindNames());
+ W.printHex("Flags", FrameCookie.Flags);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FrameProcSym &FrameProc) {
+ W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes);
+ W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes);
+ W.printHex("OffsetToPadding", FrameProc.OffsetToPadding);
+ W.printHex("BytesOfCalleeSavedRegisters",
+ FrameProc.BytesOfCalleeSavedRegisters);
+ W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler);
+ W.printHex("SectionIdOfExceptionHandler",
+ FrameProc.SectionIdOfExceptionHandler);
+ W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags),
+ getFrameProcSymFlagNames());
+ W.printEnum("LocalFramePtrReg",
+ uint16_t(FrameProc.getLocalFramePtrReg(CompilationCPUType)),
+ getRegisterNames(CompilationCPUType));
+ W.printEnum("ParamFramePtrReg",
+ uint16_t(FrameProc.getParamFramePtrReg(CompilationCPUType)),
+ getRegisterNames(CompilationCPUType));
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ HeapAllocSite.getRelocationOffset(),
+ HeapAllocSite.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", HeapAllocSite.Segment);
+ W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize);
+ printTypeIndex("Type", HeapAllocSite.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ InlineSiteSym &InlineSite) {
+ W.printHex("PtrParent", InlineSite.Parent);
+ W.printHex("PtrEnd", InlineSite.End);
+ printTypeIndex("Inlinee", InlineSite.Inlinee);
+
+ ListScope BinaryAnnotations(W, "BinaryAnnotations");
+ for (auto &Annotation : InlineSite.annotations()) {
+ switch (Annotation.OpCode) {
+ case BinaryAnnotationsOpCode::Invalid:
+ W.printString("(Annotation Padding)");
+ break;
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ W.printHex(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ case BinaryAnnotationsOpCode::ChangeLineEndDelta:
+ case BinaryAnnotationsOpCode::ChangeRangeKind:
+ case BinaryAnnotationsOpCode::ChangeColumnStart:
+ case BinaryAnnotationsOpCode::ChangeColumnEnd:
+ W.printNumber(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
+ W.printNumber(Annotation.Name, Annotation.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ if (ObjDelegate) {
+ W.printHex("ChangeFile",
+ ObjDelegate->getFileNameForFileOffset(Annotation.U1),
+ Annotation.U1);
+ } else {
+ W.printHex("ChangeFile", Annotation.U1);
+ }
+
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
+ W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
+ << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1
+ << "}\n";
+ break;
+ }
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
+ W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
+ << W.hex(Annotation.U2)
+ << ", Length: " << W.hex(Annotation.U1) << "}\n";
+ break;
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+ printTypeIndex("Type", Register.Index);
+ W.printEnum("Seg", uint16_t(Register.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printString("Name", Register.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) {
+ W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames());
+ W.printNumber("Seg", Public.Segment);
+ W.printNumber("Off", Public.Offset);
+ W.printString("Name", Public.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) {
+ W.printNumber("SumName", ProcRef.SumName);
+ W.printNumber("SymOffset", ProcRef.SymOffset);
+ W.printNumber("Mod", ProcRef.Module);
+ W.printString("Name", ProcRef.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(),
+ Label.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Label.Segment);
+ W.printHex("Flags", uint8_t(Label.Flags));
+ W.printFlags("Flags", uint8_t(Label.Flags), getProcSymFlagNames());
+ W.printString("DisplayName", Label.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ printTypeIndex("Type", Local.Type);
+ W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames());
+ W.printString("VarName", Local.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) {
+ W.printHex("Signature", ObjName.Signature);
+ W.printString("ObjectName", ObjName.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ if (InFunctionScope)
+ return llvm::make_error<CodeViewError>(
+ "Visiting a ProcSym while inside function scope!");
+
+ InFunctionScope = true;
+
+ StringRef LinkageName;
+ W.printHex("PtrParent", Proc.Parent);
+ W.printHex("PtrEnd", Proc.End);
+ W.printHex("PtrNext", Proc.Next);
+ W.printHex("CodeSize", Proc.CodeSize);
+ W.printHex("DbgStart", Proc.DbgStart);
+ W.printHex("DbgEnd", Proc.DbgEnd);
+ printTypeIndex("FunctionType", Proc.FunctionType);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
+ Proc.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Proc.Segment);
+ W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags),
+ getProcSymFlagNames());
+ W.printString("DisplayName", Proc.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ InFunctionScope = false;
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers");
+ for (auto FuncID : Caller.Indices)
+ printTypeIndex("FuncID", FuncID);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+ W.printHex("Offset", RegRel.Offset);
+ printTypeIndex("Type", RegRel.Type);
+ W.printEnum("Register", uint16_t(RegRel.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printString("VarName", RegRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.DataOffset, &LinkageName);
+ }
+ printTypeIndex("Type", Data.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+ printTypeIndex("Type", UDT.Type);
+ W.printString("UDTName", UDT.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ UsingNamespaceSym &UN) {
+ W.printString("Namespace", UN.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ AnnotationSym &Annot) {
+ W.printHex("Offset", Annot.CodeOffset);
+ W.printHex("Segment", Annot.Segment);
+
+ ListScope S(W, "Strings");
+ for (StringRef Str : Annot.Strings)
+ W.printString(Str);
+
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
+ W.printNumber("Length", CVR.length());
+ return Error::success();
+}
+
+Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType,
+ PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto Err = Visitor.visitSymbolRecord(Record);
+ CompilationCPUType = Dumper.getCompilationCPUType();
+ return Err;
+}
+
+Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType,
+ PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto Err = Visitor.visitSymbolStream(Symbols);
+ CompilationCPUType = Dumper.getCompilationCPUType();
+ return Err;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
new file mode 100644
index 000000000000..51a5a9e9243e
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
@@ -0,0 +1,93 @@
+//===- SymbolRecordHelpers.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
+ RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
+ return record;
+}
+
+uint32_t llvm::codeview::getScopeEndOffset(const CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ switch (Sym.kind()) {
+ 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: {
+ ProcSym Proc = createRecord<ProcSym>(Sym);
+ return Proc.End;
+ }
+ case SymbolKind::S_BLOCK32: {
+ BlockSym Block = createRecord<BlockSym>(Sym);
+ return Block.End;
+ }
+ case SymbolKind::S_THUNK32: {
+ Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym);
+ return Thunk.End;
+ }
+ case SymbolKind::S_INLINESITE: {
+ InlineSiteSym Site = createRecord<InlineSiteSym>(Sym);
+ return Site.End;
+ }
+ default:
+ assert(false && "Unknown record type");
+ return 0;
+ }
+}
+
+uint32_t
+llvm::codeview::getScopeParentOffset(const llvm::codeview::CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ switch (Sym.kind()) {
+ 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: {
+ ProcSym Proc = createRecord<ProcSym>(Sym);
+ return Proc.Parent;
+ }
+ case SymbolKind::S_BLOCK32: {
+ BlockSym Block = createRecord<BlockSym>(Sym);
+ return Block.Parent;
+ }
+ case SymbolKind::S_THUNK32: {
+ Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym);
+ return Thunk.Parent;
+ }
+ case SymbolKind::S_INLINESITE: {
+ InlineSiteSym Site = createRecord<InlineSiteSym>(Sym);
+ return Site.Parent;
+ }
+ default:
+ assert(false && "Unknown record type");
+ return 0;
+ }
+}
+
+CVSymbolArray
+llvm::codeview::limitSymbolArrayToScope(const CVSymbolArray &Symbols,
+ uint32_t ScopeBegin) {
+ CVSymbol Opener = *Symbols.at(ScopeBegin);
+ assert(symbolOpensScope(Opener.kind()));
+ uint32_t EndOffset = getScopeEndOffset(Opener);
+ CVSymbol Closer = *Symbols.at(EndOffset);
+ EndOffset += Closer.RecordData.size();
+ return Symbols.substream(ScopeBegin, EndOffset);
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
new file mode 100644
index 000000000000..70889839ef48
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
@@ -0,0 +1,558 @@
+//===- SymbolRecordMapping.cpp -----------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+#define error(X) \
+ if (auto EC = X) \
+ return EC;
+
+namespace {
+struct MapGap {
+ Error operator()(CodeViewRecordIO &IO, LocalVariableAddrGap &Gap) const {
+ error(IO.mapInteger(Gap.GapStartOffset));
+ error(IO.mapInteger(Gap.Range));
+ return Error::success();
+ }
+};
+}
+
+static Error mapLocalVariableAddrRange(CodeViewRecordIO &IO,
+ LocalVariableAddrRange &Range) {
+ error(IO.mapInteger(Range.OffsetStart));
+ error(IO.mapInteger(Range.ISectStart));
+ error(IO.mapInteger(Range.Range));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitSymbolBegin(CVSymbol &Record) {
+ error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix)));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) {
+ error(IO.padToAlignment(alignOf(Container)));
+ error(IO.endRecord());
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+
+ error(IO.mapInteger(Block.Parent));
+ error(IO.mapInteger(Block.End));
+ error(IO.mapInteger(Block.CodeSize));
+ error(IO.mapInteger(Block.CodeOffset));
+ error(IO.mapInteger(Block.Segment));
+ error(IO.mapStringZ(Block.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+
+ error(IO.mapInteger(Thunk.Parent));
+ error(IO.mapInteger(Thunk.End));
+ error(IO.mapInteger(Thunk.Next));
+ error(IO.mapInteger(Thunk.Offset));
+ error(IO.mapInteger(Thunk.Segment));
+ error(IO.mapInteger(Thunk.Length));
+ error(IO.mapEnum(Thunk.Thunk));
+ error(IO.mapStringZ(Thunk.Name));
+ error(IO.mapByteVectorTail(Thunk.VariantData));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+
+ error(IO.mapEnum(Tramp.Type));
+ error(IO.mapInteger(Tramp.Size));
+ error(IO.mapInteger(Tramp.ThunkOffset));
+ error(IO.mapInteger(Tramp.TargetOffset));
+ error(IO.mapInteger(Tramp.ThunkSection));
+ error(IO.mapInteger(Tramp.TargetSection));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ SectionSym &Section) {
+ uint8_t Padding = 0;
+
+ error(IO.mapInteger(Section.SectionNumber));
+ error(IO.mapInteger(Section.Alignment));
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(Section.Rva));
+ error(IO.mapInteger(Section.Length));
+ error(IO.mapInteger(Section.Characteristics));
+ error(IO.mapStringZ(Section.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ CoffGroupSym &CoffGroup) {
+
+ error(IO.mapInteger(CoffGroup.Size));
+ error(IO.mapInteger(CoffGroup.Characteristics));
+ error(IO.mapInteger(CoffGroup.Offset));
+ error(IO.mapInteger(CoffGroup.Segment));
+ error(IO.mapStringZ(CoffGroup.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+
+ error(IO.mapInteger(BPRel.Offset));
+ error(IO.mapInteger(BPRel.Type));
+ error(IO.mapStringZ(BPRel.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+
+ error(IO.mapInteger(BuildInfo.BuildId));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CallSiteInfo) {
+ uint16_t Padding = 0;
+
+ error(IO.mapInteger(CallSiteInfo.CodeOffset));
+ error(IO.mapInteger(CallSiteInfo.Segment));
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(CallSiteInfo.Type));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+
+ uint8_t Reserved = 0;
+ error(IO.mapInteger(Reserved));
+ error(IO.mapStringZVectorZ(EnvBlock.Fields));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FileStaticSym &FileStatic) {
+
+ error(IO.mapInteger(FileStatic.Index));
+ error(IO.mapInteger(FileStatic.ModFilenameOffset));
+ error(IO.mapEnum(FileStatic.Flags));
+ error(IO.mapStringZ(FileStatic.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+
+ error(IO.mapInteger(Export.Ordinal));
+ error(IO.mapEnum(Export.Flags));
+ error(IO.mapStringZ(Export.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+
+ error(IO.mapEnum(Compile2.Flags));
+ error(IO.mapEnum(Compile2.Machine));
+ error(IO.mapInteger(Compile2.VersionFrontendMajor));
+ error(IO.mapInteger(Compile2.VersionFrontendMinor));
+ error(IO.mapInteger(Compile2.VersionFrontendBuild));
+ error(IO.mapInteger(Compile2.VersionBackendMajor));
+ error(IO.mapInteger(Compile2.VersionBackendMinor));
+ error(IO.mapInteger(Compile2.VersionBackendBuild));
+ error(IO.mapStringZ(Compile2.Version));
+ error(IO.mapStringZVectorZ(Compile2.ExtraStrings));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+
+ error(IO.mapEnum(Compile3.Flags));
+ error(IO.mapEnum(Compile3.Machine));
+ error(IO.mapInteger(Compile3.VersionFrontendMajor));
+ error(IO.mapInteger(Compile3.VersionFrontendMinor));
+ error(IO.mapInteger(Compile3.VersionFrontendBuild));
+ error(IO.mapInteger(Compile3.VersionFrontendQFE));
+ error(IO.mapInteger(Compile3.VersionBackendMajor));
+ error(IO.mapInteger(Compile3.VersionBackendMinor));
+ error(IO.mapInteger(Compile3.VersionBackendBuild));
+ error(IO.mapInteger(Compile3.VersionBackendQFE));
+ error(IO.mapStringZ(Compile3.Version));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+
+ error(IO.mapInteger(Constant.Type));
+ error(IO.mapEncodedInteger(Constant.Value));
+ error(IO.mapStringZ(Constant.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+
+ error(IO.mapInteger(Data.Type));
+ error(IO.mapInteger(Data.DataOffset));
+ error(IO.mapInteger(Data.Segment));
+ error(IO.mapStringZ(Data.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+
+ error(IO.mapInteger(DefRangeFramePointerRel.Offset));
+ error(mapLocalVariableAddrRange(IO, DefRangeFramePointerRel.Range));
+ error(IO.mapVectorTail(DefRangeFramePointerRel.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+
+ error(IO.mapInteger(DefRangeFramePointerRelFullScope.Offset));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.Register));
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.Flags));
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.BasePointerOffset));
+ error(mapLocalVariableAddrRange(IO, DefRangeRegisterRel.Range));
+ error(IO.mapVectorTail(DefRangeRegisterRel.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+
+ error(IO.mapObject(DefRangeRegister.Hdr.Register));
+ error(IO.mapObject(DefRangeRegister.Hdr.MayHaveNoName));
+ error(mapLocalVariableAddrRange(IO, DefRangeRegister.Range));
+ error(IO.mapVectorTail(DefRangeRegister.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.Register));
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.MayHaveNoName));
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.OffsetInParent));
+ error(mapLocalVariableAddrRange(IO, DefRangeSubfieldRegister.Range));
+ error(IO.mapVectorTail(DefRangeSubfieldRegister.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) {
+
+ error(IO.mapInteger(DefRangeSubfield.Program));
+ error(IO.mapInteger(DefRangeSubfield.OffsetInParent));
+ error(mapLocalVariableAddrRange(IO, DefRangeSubfield.Range));
+ error(IO.mapVectorTail(DefRangeSubfield.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSym &DefRange) {
+
+ error(IO.mapInteger(DefRange.Program));
+ error(mapLocalVariableAddrRange(IO, DefRange.Range));
+ error(IO.mapVectorTail(DefRange.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FrameCookieSym &FrameCookie) {
+
+ error(IO.mapInteger(FrameCookie.CodeOffset));
+ error(IO.mapInteger(FrameCookie.Register));
+ error(IO.mapEnum(FrameCookie.CookieKind));
+ error(IO.mapInteger(FrameCookie.Flags));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FrameProcSym &FrameProc) {
+ error(IO.mapInteger(FrameProc.TotalFrameBytes));
+ error(IO.mapInteger(FrameProc.PaddingFrameBytes));
+ error(IO.mapInteger(FrameProc.OffsetToPadding));
+ error(IO.mapInteger(FrameProc.BytesOfCalleeSavedRegisters));
+ error(IO.mapInteger(FrameProc.OffsetOfExceptionHandler));
+ error(IO.mapInteger(FrameProc.SectionIdOfExceptionHandler));
+ error(IO.mapEnum(FrameProc.Flags));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) {
+
+ error(IO.mapInteger(HeapAllocSite.CodeOffset));
+ error(IO.mapInteger(HeapAllocSite.Segment));
+ error(IO.mapInteger(HeapAllocSite.CallInstructionSize));
+ error(IO.mapInteger(HeapAllocSite.Type));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ InlineSiteSym &InlineSite) {
+
+ error(IO.mapInteger(InlineSite.Parent));
+ error(IO.mapInteger(InlineSite.End));
+ error(IO.mapInteger(InlineSite.Inlinee));
+ error(IO.mapByteVectorTail(InlineSite.AnnotationData));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+
+ error(IO.mapInteger(Register.Index));
+ error(IO.mapEnum(Register.Register));
+ error(IO.mapStringZ(Register.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ PublicSym32 &Public) {
+
+ error(IO.mapEnum(Public.Flags));
+ error(IO.mapInteger(Public.Offset));
+ error(IO.mapInteger(Public.Segment));
+ error(IO.mapStringZ(Public.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ProcRefSym &ProcRef) {
+
+ error(IO.mapInteger(ProcRef.SumName));
+ error(IO.mapInteger(ProcRef.SymOffset));
+ error(IO.mapInteger(ProcRef.Module));
+ error(IO.mapStringZ(ProcRef.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+
+ error(IO.mapInteger(Label.CodeOffset));
+ error(IO.mapInteger(Label.Segment));
+ error(IO.mapEnum(Label.Flags));
+ error(IO.mapStringZ(Label.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ error(IO.mapInteger(Local.Type));
+ error(IO.mapEnum(Local.Flags));
+ error(IO.mapStringZ(Local.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ObjNameSym &ObjName) {
+
+ error(IO.mapInteger(ObjName.Signature));
+ error(IO.mapStringZ(ObjName.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ error(IO.mapInteger(Proc.Parent));
+ error(IO.mapInteger(Proc.End));
+ error(IO.mapInteger(Proc.Next));
+ error(IO.mapInteger(Proc.CodeSize));
+ error(IO.mapInteger(Proc.DbgStart));
+ error(IO.mapInteger(Proc.DbgEnd));
+ error(IO.mapInteger(Proc.FunctionType));
+ error(IO.mapInteger(Proc.CodeOffset));
+ error(IO.mapInteger(Proc.Segment));
+ error(IO.mapEnum(Proc.Flags));
+ error(IO.mapStringZ(Proc.Name));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ error(IO.mapVectorN<uint32_t>(
+ Caller.Indices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+
+ error(IO.mapInteger(RegRel.Offset));
+ error(IO.mapInteger(RegRel.Type));
+ error(IO.mapEnum(RegRel.Register));
+ error(IO.mapStringZ(RegRel.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+
+ error(IO.mapInteger(Data.Type));
+ error(IO.mapInteger(Data.DataOffset));
+ error(IO.mapInteger(Data.Segment));
+ error(IO.mapStringZ(Data.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+
+ error(IO.mapInteger(UDT.Type));
+ error(IO.mapStringZ(UDT.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ UsingNamespaceSym &UN) {
+
+ error(IO.mapStringZ(UN.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ AnnotationSym &Annot) {
+
+ error(IO.mapInteger(Annot.CodeOffset));
+ error(IO.mapInteger(Annot.Segment));
+ error(IO.mapVectorN<uint16_t>(
+ Annot.Strings,
+ [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
+
+ return Error::success();
+}
+
+RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg,
+ CPUType CPU) {
+ assert(unsigned(EncodedReg) < 4);
+ switch (CPU) {
+ // FIXME: Add ARM and AArch64 variants here.
+ default:
+ break;
+ case CPUType::Intel8080:
+ case CPUType::Intel8086:
+ case CPUType::Intel80286:
+ case CPUType::Intel80386:
+ case CPUType::Intel80486:
+ case CPUType::Pentium:
+ case CPUType::PentiumPro:
+ case CPUType::Pentium3:
+ switch (EncodedReg) {
+ case EncodedFramePtrReg::None: return RegisterId::NONE;
+ case EncodedFramePtrReg::StackPtr: return RegisterId::VFRAME;
+ case EncodedFramePtrReg::FramePtr: return RegisterId::EBP;
+ case EncodedFramePtrReg::BasePtr: return RegisterId::EBX;
+ }
+ llvm_unreachable("bad encoding");
+ case CPUType::X64:
+ switch (EncodedReg) {
+ case EncodedFramePtrReg::None: return RegisterId::NONE;
+ case EncodedFramePtrReg::StackPtr: return RegisterId::RSP;
+ case EncodedFramePtrReg::FramePtr: return RegisterId::RBP;
+ case EncodedFramePtrReg::BasePtr: return RegisterId::R13;
+ }
+ llvm_unreachable("bad encoding");
+ }
+ return RegisterId::NONE;
+}
+
+EncodedFramePtrReg codeview::encodeFramePtrReg(RegisterId Reg, CPUType CPU) {
+ switch (CPU) {
+ // FIXME: Add ARM and AArch64 variants here.
+ default:
+ break;
+ case CPUType::Intel8080:
+ case CPUType::Intel8086:
+ case CPUType::Intel80286:
+ case CPUType::Intel80386:
+ case CPUType::Intel80486:
+ case CPUType::Pentium:
+ case CPUType::PentiumPro:
+ case CPUType::Pentium3:
+ switch (Reg) {
+ case RegisterId::VFRAME:
+ return EncodedFramePtrReg::StackPtr;
+ case RegisterId::EBP:
+ return EncodedFramePtrReg::FramePtr;
+ case RegisterId::EBX:
+ return EncodedFramePtrReg::BasePtr;
+ default:
+ break;
+ }
+ break;
+ case CPUType::X64:
+ switch (Reg) {
+ case RegisterId::RSP:
+ return EncodedFramePtrReg::StackPtr;
+ case RegisterId::RBP:
+ return EncodedFramePtrReg::FramePtr;
+ case RegisterId::R13:
+ return EncodedFramePtrReg::BasePtr;
+ default:
+ break;
+ }
+ break;
+ }
+ return EncodedFramePtrReg::None;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
new file mode 100644
index 000000000000..de9bb42b1798
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
@@ -0,0 +1,59 @@
+//===- SymbolSerializer.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
+ CodeViewContainer Container)
+ : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream),
+ Mapping(Writer, Container) {}
+
+Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
+ assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!");
+
+ Writer.setOffset(0);
+
+ if (auto EC = writeRecordPrefix(Record.kind()))
+ return EC;
+
+ CurrentSymbol = Record.kind();
+ if (auto EC = Mapping.visitSymbolBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error SymbolSerializer::visitSymbolEnd(CVSymbol &Record) {
+ assert(CurrentSymbol.hasValue() && "Not in a symbol mapping!");
+
+ if (auto EC = Mapping.visitSymbolEnd(Record))
+ return EC;
+
+ uint32_t RecordEnd = Writer.getOffset();
+ uint16_t Length = RecordEnd - 2;
+ Writer.setOffset(0);
+ if (auto EC = Writer.writeInteger(Length))
+ return EC;
+
+ uint8_t *StableStorage = Storage.Allocate<uint8_t>(RecordEnd);
+ ::memcpy(StableStorage, &RecordBuffer[0], RecordEnd);
+ Record.RecordData = ArrayRef<uint8_t>(StableStorage, RecordEnd);
+ CurrentSymbol.reset();
+
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
new file mode 100644
index 000000000000..d5fea5ee5e29
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -0,0 +1,570 @@
+//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+};
+
+#define ENUM_ENTRY(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+ ENUM_ENTRY(ClassOptions, Packed),
+ ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
+ ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
+ ENUM_ENTRY(ClassOptions, Nested),
+ ENUM_ENTRY(ClassOptions, ContainsNestedClass),
+ ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
+ ENUM_ENTRY(ClassOptions, HasConversionOperator),
+ ENUM_ENTRY(ClassOptions, ForwardReference),
+ ENUM_ENTRY(ClassOptions, Scoped),
+ ENUM_ENTRY(ClassOptions, HasUniqueName),
+ ENUM_ENTRY(ClassOptions, Sealed),
+ ENUM_ENTRY(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+ ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private),
+ ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+ ENUM_ENTRY(MethodOptions, Pseudo),
+ ENUM_ENTRY(MethodOptions, NoInherit),
+ ENUM_ENTRY(MethodOptions, NoConstruct),
+ ENUM_ENTRY(MethodOptions, CompilerGenerated),
+ ENUM_ENTRY(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+ ENUM_ENTRY(MethodKind, Vanilla),
+ ENUM_ENTRY(MethodKind, Virtual),
+ ENUM_ENTRY(MethodKind, Static),
+ ENUM_ENTRY(MethodKind, Friend),
+ ENUM_ENTRY(MethodKind, IntroducingVirtual),
+ ENUM_ENTRY(MethodKind, PureVirtual),
+ ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+ ENUM_ENTRY(PointerKind, Near16),
+ ENUM_ENTRY(PointerKind, Far16),
+ ENUM_ENTRY(PointerKind, Huge16),
+ ENUM_ENTRY(PointerKind, BasedOnSegment),
+ ENUM_ENTRY(PointerKind, BasedOnValue),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
+ ENUM_ENTRY(PointerKind, BasedOnAddress),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
+ ENUM_ENTRY(PointerKind, BasedOnType),
+ ENUM_ENTRY(PointerKind, BasedOnSelf),
+ ENUM_ENTRY(PointerKind, Near32),
+ ENUM_ENTRY(PointerKind, Far32),
+ ENUM_ENTRY(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+ ENUM_ENTRY(PointerMode, Pointer),
+ ENUM_ENTRY(PointerMode, LValueReference),
+ ENUM_ENTRY(PointerMode, PointerToDataMember),
+ ENUM_ENTRY(PointerMode, PointerToMemberFunction),
+ ENUM_ENTRY(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+ ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+ ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile),
+ ENUM_ENTRY(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+ ENUM_ENTRY(CallingConvention, NearC),
+ ENUM_ENTRY(CallingConvention, FarC),
+ ENUM_ENTRY(CallingConvention, NearPascal),
+ ENUM_ENTRY(CallingConvention, FarPascal),
+ ENUM_ENTRY(CallingConvention, NearFast),
+ ENUM_ENTRY(CallingConvention, FarFast),
+ ENUM_ENTRY(CallingConvention, NearStdCall),
+ ENUM_ENTRY(CallingConvention, FarStdCall),
+ ENUM_ENTRY(CallingConvention, NearSysCall),
+ ENUM_ENTRY(CallingConvention, FarSysCall),
+ ENUM_ENTRY(CallingConvention, ThisCall),
+ ENUM_ENTRY(CallingConvention, MipsCall),
+ ENUM_ENTRY(CallingConvention, Generic),
+ ENUM_ENTRY(CallingConvention, AlphaCall),
+ ENUM_ENTRY(CallingConvention, PpcCall),
+ ENUM_ENTRY(CallingConvention, SHCall),
+ ENUM_ENTRY(CallingConvention, ArmCall),
+ ENUM_ENTRY(CallingConvention, AM33Call),
+ ENUM_ENTRY(CallingConvention, TriCall),
+ ENUM_ENTRY(CallingConvention, SH5Call),
+ ENUM_ENTRY(CallingConvention, M32RCall),
+ ENUM_ENTRY(CallingConvention, ClrCall),
+ ENUM_ENTRY(CallingConvention, Inline),
+ ENUM_ENTRY(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+ ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
+ ENUM_ENTRY(FunctionOptions, Constructor),
+ ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+static const EnumEntry<uint16_t> LabelTypeEnum[] = {
+ ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far),
+};
+
+#undef ENUM_ENTRY
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
+ codeview::printTypeIndex(*W, FieldName, TI, TpiTypes);
+}
+
+void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
+ codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes());
+}
+
+Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
+ return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
+}
+
+Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ W->startLine() << getLeafTypeName(Record.kind());
+ W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")";
+ W->getOStream() << " {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.kind()),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ W->startLine() << getLeafTypeName(Record.Kind);
+ W->getOStream() << " {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.Kind),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
+ return EC;
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
+ printItemIndex("Id", String.getId());
+ W->printString("StringData", String.getString());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumArgs", Size);
+ ListScope Arguments(*W, "Arguments");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printTypeIndex("ArgType", Indices[I]);
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
+ auto Indices = Strs.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumStrings", Size);
+ ListScope Arguments(*W, "Strings");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printItemIndex("String", Indices[I]);
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
+ uint16_t Props = static_cast<uint16_t>(Class.getOptions());
+ W->printNumber("MemberCount", Class.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Class.getFieldList());
+ printTypeIndex("DerivedFrom", Class.getDerivationList());
+ printTypeIndex("VShape", Class.getVTableShape());
+ W->printNumber("SizeOf", Class.getSize());
+ W->printString("Name", Class.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Class.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
+ uint16_t Props = static_cast<uint16_t>(Union.getOptions());
+ W->printNumber("MemberCount", Union.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Union.getFieldList());
+ W->printNumber("SizeOf", Union.getSize());
+ W->printString("Name", Union.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Union.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
+ W->printNumber("NumEnumerators", Enum.getMemberCount());
+ W->printFlags("Properties", uint16_t(Enum.getOptions()),
+ makeArrayRef(ClassOptionNames));
+ printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
+ printTypeIndex("FieldListType", Enum.getFieldList());
+ W->printString("Name", Enum.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Enum.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ printTypeIndex("ElementType", AT.getElementType());
+ printTypeIndex("IndexType", AT.getIndexType());
+ W->printNumber("SizeOf", AT.getSize());
+ W->printString("Name", AT.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
+ printTypeIndex("CompleteClass", VFT.getCompleteClass());
+ printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
+ W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+ W->printString("VFTableName", VFT.getName());
+ for (auto N : VFT.getMethodNames())
+ W->printString("MethodName", N);
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
+ printTypeIndex("ClassType", Id.getClassType());
+ printTypeIndex("FunctionType", Id.getFunctionType());
+ W->printString("Name", Id.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
+ printTypeIndex("ReturnType", Proc.getReturnType());
+ W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", Proc.getParameterCount());
+ printTypeIndex("ArgListType", Proc.getArgumentList());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) {
+ printTypeIndex("ReturnType", MF.getReturnType());
+ printTypeIndex("ClassType", MF.getClassType());
+ printTypeIndex("ThisType", MF.getThisType());
+ W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", MF.getParameterCount());
+ printTypeIndex("ArgListType", MF.getArgumentList());
+ W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MethodOverloadListRecord &MethodList) {
+ for (auto &M : MethodList.getMethods()) {
+ ListScope S(*W, "Method");
+ printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
+ printTypeIndex("Type", M.getType());
+ if (M.isIntroducingVirtual())
+ W->printHex("VFTableOffset", M.getVFTableOffset());
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
+ printItemIndex("ParentScope", Func.getParentScope());
+ printTypeIndex("FunctionType", Func.getFunctionType());
+ W->printString("Name", Func.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
+ W->printString("Guid", formatv("{0}", TS.getGuid()).str());
+ W->printNumber("Age", TS.getAge());
+ W->printString("Name", TS.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
+ printTypeIndex("PointeeType", Ptr.getReferentType());
+ W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
+ makeArrayRef(PtrKindNames));
+ W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
+
+ W->printNumber("IsFlat", Ptr.isFlat());
+ W->printNumber("IsConst", Ptr.isConst());
+ W->printNumber("IsVolatile", Ptr.isVolatile());
+ W->printNumber("IsUnaligned", Ptr.isUnaligned());
+ W->printNumber("IsRestrict", Ptr.isRestrict());
+ W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr());
+ W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr());
+ W->printNumber("SizeOf", Ptr.getSize());
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ printTypeIndex("ClassType", MI.getContainingType());
+ W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+ makeArrayRef(PtrMemberRepNames));
+ }
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+ printTypeIndex("ModifiedType", Mod.getModifiedType());
+ W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
+ printTypeIndex("Type", BitField.getType());
+ W->printNumber("BitSize", BitField.getBitSize());
+ W->printNumber("BitOffset", BitField.getBitOffset());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ W->printNumber("VFEntryCount", Shape.getEntryCount());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printItemIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printItemIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ W->printNumber("Module", Line.getModule());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
+ W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+
+ ListScope Arguments(*W, "Arguments");
+ for (auto Arg : Args.getArgs()) {
+ printItemIndex("ArgType", Arg);
+ }
+ return Error::success();
+}
+
+void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) {
+ return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
+ Attrs.getFlags());
+}
+
+void TypeDumpVisitor::printMemberAttributes(MemberAccess Access,
+ MethodKind Kind,
+ MethodOptions Options) {
+ W->printEnum("AccessSpecifier", uint8_t(Access),
+ makeArrayRef(MemberAccessNames));
+ // Data members will be vanilla. Don't try to print a method kind for them.
+ if (Kind != MethodKind::Vanilla)
+ W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
+ if (Options != MethodOptions::None) {
+ W->printFlags("MethodOptions", unsigned(Options),
+ makeArrayRef(MethodOptionNames));
+ }
+}
+
+Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) {
+ W->printHex("UnknownMember", unsigned(Record.Kind));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitUnknownType(CVType &Record) {
+ W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
+ W->printNumber("Length", uint32_t(Record.content().size()));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ printTypeIndex("Type", Nested.getNestedType());
+ W->printString("Name", Nested.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ MethodKind K = Method.getMethodKind();
+ printMemberAttributes(Method.getAccess(), K, Method.getOptions());
+ printTypeIndex("Type", Method.getType());
+ // If virtual, then read the vftable offset.
+ if (Method.isIntroducingVirtual())
+ W->printHex("VFTableOffset", Method.getVFTableOffset());
+ W->printString("Name", Method.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ W->printHex("MethodCount", Method.getNumOverloads());
+ printTypeIndex("MethodListIndex", Method.getMethodList());
+ W->printString("Name", Method.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printHex("FieldOffset", Field.getFieldOffset());
+ W->printString("Name", Field.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printString("Name", Field.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFTable) {
+ printTypeIndex("Type", VFTable.getType());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ W->printNumber("EnumValue", Enum.getValue());
+ W->printString("Name", Enum.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ W->printHex("BaseOffset", Base.getBaseOffset());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Base) {
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ printTypeIndex("VBPtrType", Base.getVBPtrType());
+ W->printHex("VBPtrOffset", Base.getVBPtrOffset());
+ W->printHex("VBTableIndex", Base.getVTableIndex());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) {
+ W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ W->printHex("StartIndex", Precomp.getStartTypeIndex());
+ W->printHex("Count", Precomp.getTypesCount());
+ W->printHex("Signature", Precomp.getSignature());
+ W->printString("PrecompFile", Precomp.getPrecompFilePath());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ W->printHex("Signature", EndPrecomp.getSignature());
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp
new file mode 100644
index 000000000000..2dbc11a84f0b
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeHashing.cpp
@@ -0,0 +1,80 @@
+//===- TypeHashing.cpp -------------------------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#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, 8> EmptyHash = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+static std::array<uint8_t, 8> TombstoneHash = {
+ {0xFF, 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;
+ S.update(RecordData.take_front(sizeof(RecordPrefix)));
+ 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()) {
+ const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI);
+ BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex));
+ } else {
+ if (TI.toArrayIndex() >= Prev.size() ||
+ Prev[TI.toArrayIndex()].empty()) {
+ // There are references to yet-unhashed records. Suspend hashing for
+ // this record until all the other records are processed.
+ return {};
+ }
+ 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().take_back(8)};
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp
new file mode 100644
index 000000000000..604d342448d3
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp
@@ -0,0 +1,106 @@
+//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+struct SimpleTypeEntry {
+ StringRef Name;
+ SimpleTypeKind Kind;
+};
+
+/// The names here all end in "*". If the simple type is a pointer type, we
+/// return the whole name. Otherwise we lop off the last character in our
+/// StringRef.
+static const SimpleTypeEntry SimpleTypeNames[] = {
+ {"void*", SimpleTypeKind::Void},
+ {"<not translated>*", SimpleTypeKind::NotTranslated},
+ {"HRESULT*", SimpleTypeKind::HResult},
+ {"signed char*", SimpleTypeKind::SignedCharacter},
+ {"unsigned char*", SimpleTypeKind::UnsignedCharacter},
+ {"char*", SimpleTypeKind::NarrowCharacter},
+ {"wchar_t*", SimpleTypeKind::WideCharacter},
+ {"char16_t*", SimpleTypeKind::Character16},
+ {"char32_t*", SimpleTypeKind::Character32},
+ {"__int8*", SimpleTypeKind::SByte},
+ {"unsigned __int8*", SimpleTypeKind::Byte},
+ {"short*", SimpleTypeKind::Int16Short},
+ {"unsigned short*", SimpleTypeKind::UInt16Short},
+ {"__int16*", SimpleTypeKind::Int16},
+ {"unsigned __int16*", SimpleTypeKind::UInt16},
+ {"long*", SimpleTypeKind::Int32Long},
+ {"unsigned long*", SimpleTypeKind::UInt32Long},
+ {"int*", SimpleTypeKind::Int32},
+ {"unsigned*", SimpleTypeKind::UInt32},
+ {"__int64*", SimpleTypeKind::Int64Quad},
+ {"unsigned __int64*", SimpleTypeKind::UInt64Quad},
+ {"__int64*", SimpleTypeKind::Int64},
+ {"unsigned __int64*", SimpleTypeKind::UInt64},
+ {"__int128*", SimpleTypeKind::Int128},
+ {"unsigned __int128*", SimpleTypeKind::UInt128},
+ {"__half*", SimpleTypeKind::Float16},
+ {"float*", SimpleTypeKind::Float32},
+ {"float*", SimpleTypeKind::Float32PartialPrecision},
+ {"__float48*", SimpleTypeKind::Float48},
+ {"double*", SimpleTypeKind::Float64},
+ {"long double*", SimpleTypeKind::Float80},
+ {"__float128*", SimpleTypeKind::Float128},
+ {"_Complex float*", SimpleTypeKind::Complex32},
+ {"_Complex double*", SimpleTypeKind::Complex64},
+ {"_Complex long double*", SimpleTypeKind::Complex80},
+ {"_Complex __float128*", SimpleTypeKind::Complex128},
+ {"bool*", SimpleTypeKind::Boolean8},
+ {"__bool16*", SimpleTypeKind::Boolean16},
+ {"__bool32*", SimpleTypeKind::Boolean32},
+ {"__bool64*", SimpleTypeKind::Boolean64},
+};
+} // namespace
+
+StringRef TypeIndex::simpleTypeName(TypeIndex TI) {
+ assert(TI.isNoneType() || TI.isSimple());
+
+ if (TI.isNoneType())
+ return "<no type>";
+
+ if (TI == TypeIndex::NullptrT())
+ return "std::nullptr_t";
+
+ // This is a simple type.
+ for (const auto &SimpleTypeName : SimpleTypeNames) {
+ if (SimpleTypeName.Kind == TI.getSimpleKind()) {
+ if (TI.getSimpleMode() == SimpleTypeMode::Direct)
+ return SimpleTypeName.Name.drop_back(1);
+ // Otherwise, this is a pointer type. We gloss over the distinction
+ // between near, far, 64, 32, etc, and just give a pointer type.
+ return SimpleTypeName.Name;
+ }
+ }
+ return "<unknown simple type>";
+}
+
+void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+ TypeIndex TI, TypeCollection &Types) {
+ StringRef TypeName;
+ if (!TI.isNoneType()) {
+ if (TI.isSimple())
+ TypeName = TypeIndex::simpleTypeName(TI);
+ else
+ TypeName = Types.getTypeName(TI);
+ }
+
+ if (!TypeName.empty())
+ Printer.printHex(FieldName, TypeName, TI.getIndex());
+ else
+ Printer.printHex(FieldName, TI.getIndex());
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
new file mode 100644
index 000000000000..e84e1c9cea78
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -0,0 +1,522 @@
+//===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static inline MethodKind getMethodKind(uint16_t Attrs) {
+ Attrs &= uint16_t(MethodOptions::MethodKindMask);
+ Attrs >>= 2;
+ return MethodKind(Attrs);
+}
+
+static inline bool isIntroVirtual(uint16_t Attrs) {
+ MethodKind MK = getMethodKind(Attrs);
+ return MK == MethodKind::IntroducingVirtual ||
+ MK == MethodKind::PureIntroducingVirtual;
+}
+
+static inline PointerMode getPointerMode(uint32_t Attrs) {
+ return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
+ PointerRecord::PointerModeMask);
+}
+
+static inline bool isMemberPointer(uint32_t Attrs) {
+ PointerMode Mode = getPointerMode(Attrs);
+ return Mode == PointerMode::PointerToDataMember ||
+ Mode == PointerMode::PointerToMemberFunction;
+}
+
+static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
+ uint16_t N = support::endian::read16le(Data.data());
+ if (N < LF_NUMERIC)
+ return 2;
+
+ assert(N <= LF_UQUADWORD);
+
+ constexpr uint32_t Sizes[] = {
+ 1, // LF_CHAR
+ 2, // LF_SHORT
+ 2, // LF_USHORT
+ 4, // LF_LONG
+ 4, // LF_ULONG
+ 4, // LF_REAL32
+ 8, // LF_REAL64
+ 10, // LF_REAL80
+ 16, // LF_REAL128
+ 8, // LF_QUADWORD
+ 8, // LF_UQUADWORD
+ };
+
+ return 2 + Sizes[N - LF_NUMERIC];
+}
+
+static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
+ const char *S = reinterpret_cast<const char *>(Data.data());
+ return strlen(S) + 1;
+}
+
+static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Offset = 0;
+
+ while (!Content.empty()) {
+ // Array of:
+ // 0: Attrs
+ // 2: Padding
+ // 4: TypeIndex
+ // if (isIntroVirtual())
+ // 8: VFTableOffset
+
+ // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
+ // intro virtual.
+ uint32_t Len = 8;
+
+ uint16_t Attrs = support::endian::read16le(Content.data());
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+
+ if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
+ Len += 4;
+ Offset += Len;
+ Content = Content.drop_front(Len);
+ }
+}
+
+static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Encoded Integer
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getEncodedIntegerLength(Data.drop_front(8));
+}
+
+static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: Encoded Integer
+ // <next>: Name
+ uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Encoded Integer
+ // <next>: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Attributes
+ // 4: Type
+ // if (isIntroVirtual)
+ // 8: VFTableOffset
+ // <next>: Name
+ uint32_t Size = 8;
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+
+ uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
+ if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
+ Size += 4;
+
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
+ bool IsIndirect,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Attrs
+ // 4: TypeIndex
+ // 8: TypeIndex
+ // 12: Encoded Integer
+ // <next>: Encoded Integer
+ uint32_t Size = 12;
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
+ Size += getEncodedIntegerLength(Data.drop_front(Size));
+ Size += getEncodedIntegerLength(Data.drop_front(Size));
+ return Size;
+}
+
+static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8;
+}
+
+static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8;
+}
+
+static void handleFieldList(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Offset = 0;
+ uint32_t ThisLen = 0;
+ while (!Content.empty()) {
+ TypeLeafKind Kind =
+ static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
+ switch (Kind) {
+ case LF_BCLASS:
+ ThisLen = handleBaseClass(Content, Offset, Refs);
+ break;
+ case LF_ENUMERATE:
+ ThisLen = handleEnumerator(Content, Offset, Refs);
+ break;
+ case LF_MEMBER:
+ ThisLen = handleDataMember(Content, Offset, Refs);
+ break;
+ case LF_METHOD:
+ ThisLen = handleOverloadedMethod(Content, Offset, Refs);
+ break;
+ case LF_ONEMETHOD:
+ ThisLen = handleOneMethod(Content, Offset, Refs);
+ break;
+ case LF_NESTTYPE:
+ ThisLen = handleNestedType(Content, Offset, Refs);
+ break;
+ case LF_STMEMBER:
+ ThisLen = handleStaticDataMember(Content, Offset, Refs);
+ break;
+ case LF_VBCLASS:
+ case LF_IVBCLASS:
+ ThisLen =
+ handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
+ break;
+ case LF_VFUNCTAB:
+ ThisLen = handleVFPtr(Content, Offset, Refs);
+ break;
+ case LF_INDEX:
+ ThisLen = handleListContinuation(Content, Offset, Refs);
+ break;
+ default:
+ return;
+ }
+ Content = Content.drop_front(ThisLen);
+ Offset += ThisLen;
+ if (!Content.empty()) {
+ uint8_t Pad = Content.front();
+ if (Pad >= LF_PAD0) {
+ uint32_t Skip = Pad & 0x0F;
+ Content = Content.drop_front(Skip);
+ Offset += Skip;
+ }
+ }
+ }
+}
+
+static void handlePointer(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+
+ uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
+ if (isMemberPointer(Attrs))
+ Refs.push_back({TiRefKind::TypeRef, 8, 1});
+}
+
+static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Count;
+ // FIXME: In the future it would be nice if we could avoid hardcoding these
+ // values. One idea is to define some structures representing these types
+ // that would allow the use of offsetof().
+ switch (Kind) {
+ case TypeLeafKind::LF_FUNC_ID:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1});
+ Refs.push_back({TiRefKind::TypeRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_MFUNC_ID:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_STRING_ID:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_SUBSTR_LIST:
+ Count = support::endian::read32le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::IndexRef, 4, Count});
+ break;
+ case TypeLeafKind::LF_BUILDINFO:
+ Count = support::endian::read16le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::IndexRef, 2, Count});
+ break;
+ case TypeLeafKind::LF_UDT_SRC_LINE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ Refs.push_back({TiRefKind::IndexRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_MODIFIER:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_PROCEDURE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ Refs.push_back({TiRefKind::TypeRef, 8, 1});
+ break;
+ case TypeLeafKind::LF_MFUNCTION:
+ Refs.push_back({TiRefKind::TypeRef, 0, 3});
+ Refs.push_back({TiRefKind::TypeRef, 16, 1});
+ break;
+ case TypeLeafKind::LF_ARGLIST:
+ Count = support::endian::read32le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::TypeRef, 4, Count});
+ break;
+ case TypeLeafKind::LF_ARRAY:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_CLASS:
+ case TypeLeafKind::LF_STRUCTURE:
+ case TypeLeafKind::LF_INTERFACE:
+ Refs.push_back({TiRefKind::TypeRef, 4, 3});
+ break;
+ case TypeLeafKind::LF_UNION:
+ Refs.push_back({TiRefKind::TypeRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_ENUM:
+ Refs.push_back({TiRefKind::TypeRef, 4, 2});
+ break;
+ case TypeLeafKind::LF_BITFIELD:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_VFTABLE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_VTSHAPE:
+ break;
+ case TypeLeafKind::LF_METHODLIST:
+ handleMethodOverloadList(Content, Refs);
+ break;
+ case TypeLeafKind::LF_FIELDLIST:
+ handleFieldList(Content, Refs);
+ break;
+ case TypeLeafKind::LF_POINTER:
+ handlePointer(Content, Refs);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Count;
+ // FIXME: In the future it would be nice if we could avoid hardcoding these
+ // values. One idea is to define some structures representing these types
+ // that would allow the use of offsetof().
+ switch (Kind) {
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID:
+ Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
+ break;
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
+ break;
+ case SymbolKind::S_UDT:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
+ break;
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_BUILDINFO:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
+ break;
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_GTHREAD32:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_FILESTATIC:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ 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;
+ case SymbolKind::S_CALLSITEINFO:
+ Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
+ 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
+ break;
+ case SymbolKind::S_INLINESITE:
+ Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
+ break;
+ case SymbolKind::S_HEAPALLOCSITE:
+ Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
+ break;
+
+ // Defranges don't have types, just registers and code offsets.
+ case SymbolKind::S_DEFRANGE_REGISTER:
+ case SymbolKind::S_DEFRANGE_REGISTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ break;
+
+ // No type references.
+ case SymbolKind::S_LABEL32:
+ case SymbolKind::S_OBJNAME:
+ case SymbolKind::S_COMPILE:
+ case SymbolKind::S_COMPILE2:
+ case SymbolKind::S_COMPILE3:
+ case SymbolKind::S_ENVBLOCK:
+ case SymbolKind::S_BLOCK32:
+ case SymbolKind::S_FRAMEPROC:
+ case SymbolKind::S_THUNK32:
+ case SymbolKind::S_FRAMECOOKIE:
+ case SymbolKind::S_UNAMESPACE:
+ break;
+ // Scope ending symbols.
+ case SymbolKind::S_END:
+ case SymbolKind::S_INLINESITE_END:
+ case SymbolKind::S_PROC_ID_END:
+ break;
+ default:
+ return false; // Unknown symbol.
+ }
+ return true;
+}
+
+void llvm::codeview::discoverTypeIndices(const CVType &Type,
+ SmallVectorImpl<TiReference> &Refs) {
+ ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
+}
+
+static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
+ ArrayRef<TiReference> Refs,
+ SmallVectorImpl<TypeIndex> &Indices) {
+ Indices.clear();
+
+ if (Refs.empty())
+ return;
+
+ RecordData = RecordData.drop_front(sizeof(RecordPrefix));
+
+ BinaryStreamReader Reader(RecordData, support::little);
+ for (const auto &Ref : Refs) {
+ Reader.setOffset(Ref.Offset);
+ FixedStreamArray<TypeIndex> Run;
+ cantFail(Reader.readArray(Run, Ref.Count));
+ Indices.append(Run.begin(), Run.end());
+ }
+}
+
+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 =
+ reinterpret_cast<const RecordPrefix *>(RecordData.data());
+ TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
+ ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, 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/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
new file mode 100644
index 000000000000..8e632f3be460
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
@@ -0,0 +1,52 @@
+//===- TypeRecordHelpers.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {
+ RecordT Record;
+ if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {
+ consumeError(std::move(EC));
+ return ClassOptions::None;
+ }
+ return Record.getOptions();
+}
+
+bool llvm::codeview::isUdtForwardRef(CVType CVT) {
+ ClassOptions UdtOptions = ClassOptions::None;
+ switch (CVT.kind()) {
+ case LF_STRUCTURE:
+ case LF_CLASS:
+ case LF_INTERFACE:
+ UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
+ break;
+ case LF_ENUM:
+ UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
+ break;
+ case LF_UNION:
+ UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
+ break;
+ default:
+ return false;
+ }
+ return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
+}
+
+TypeIndex llvm::codeview::getModifiedType(const CVType &CVT) {
+ assert(CVT.kind() == LF_MODIFIER);
+ SmallVector<TypeIndex, 1> Refs;
+ discoverTypeIndices(CVT, Refs);
+ return Refs.front();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
new file mode 100644
index 000000000000..47928c2eef64
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -0,0 +1,513 @@
+//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+#define error(X) \
+ if (auto EC = X) \
+ return EC;
+
+namespace {
+struct MapOneMethodRecord {
+ explicit MapOneMethodRecord(bool IsFromOverloadList)
+ : IsFromOverloadList(IsFromOverloadList) {}
+
+ Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
+ error(IO.mapInteger(Method.Attrs.Attrs, "AccessSpecifier"));
+ if (IsFromOverloadList) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ }
+ error(IO.mapInteger(Method.Type, "Type"));
+ if (Method.isIntroducingVirtual()) {
+ error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset"));
+ } else if (IO.isReading())
+ Method.VFTableOffset = -1;
+
+ if (!IsFromOverloadList)
+ error(IO.mapStringZ(Method.Name, "Name"));
+
+ return Error::success();
+ }
+
+private:
+ bool IsFromOverloadList;
+};
+}
+
+static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
+ StringRef &UniqueName, bool HasUniqueName) {
+ if (IO.isWriting()) {
+ // Try to be smart about what we write here. We can't write anything too
+ // large, so if we're going to go over the limit, truncate both the name
+ // and unique name by the same amount.
+ size_t BytesLeft = IO.maxFieldLength();
+ if (HasUniqueName) {
+ size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
+ StringRef N = Name;
+ StringRef U = UniqueName;
+ if (BytesNeeded > BytesLeft) {
+ size_t BytesToDrop = (BytesNeeded - BytesLeft);
+ size_t DropN = std::min(N.size(), BytesToDrop / 2);
+ size_t DropU = std::min(U.size(), BytesToDrop - DropN);
+
+ N = N.drop_back(DropN);
+ U = U.drop_back(DropU);
+ }
+
+ error(IO.mapStringZ(N));
+ error(IO.mapStringZ(U));
+ } else {
+ // Cap the length of the string at however many bytes we have available,
+ // plus one for the required null terminator.
+ auto N = StringRef(Name).take_front(BytesLeft - 1);
+ error(IO.mapStringZ(N));
+ }
+ } else {
+ // Reading & Streaming mode come after writing mode is executed for each
+ // record. Truncating large names are done during writing, so its not
+ // necessary to do it while reading or streaming.
+ error(IO.mapStringZ(Name, "Name"));
+ if (HasUniqueName)
+ error(IO.mapStringZ(UniqueName, "LinkageName"));
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // FieldList and MethodList records can be any length because they can be
+ // split with continuation records. All other record types cannot be
+ // longer than the maximum record length.
+ Optional<uint32_t> MaxLen;
+ if (CVR.kind() != TypeLeafKind::LF_FIELDLIST &&
+ CVR.kind() != TypeLeafKind::LF_METHODLIST)
+ MaxLen = MaxRecordLength - sizeof(RecordPrefix);
+ error(IO.beginRecord(MaxLen));
+ TypeKind = CVR.kind();
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) {
+ return visitTypeBegin(CVR);
+}
+
+Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Still in a member mapping!");
+
+ error(IO.endRecord());
+
+ TypeKind.reset();
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // The largest possible subrecord is one in which there is a record prefix,
+ // followed by the subrecord, followed by a continuation, and that entire
+ // sequence spaws `MaxRecordLength` bytes. So the record's length is
+ // calculated as follows.
+ constexpr uint32_t ContinuationLength = 8;
+ error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
+ ContinuationLength));
+
+ MemberKind = Record.Kind;
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(MemberKind.hasValue() && "Not in a member mapping!");
+
+ if (IO.isReading()) {
+ if (auto EC = IO.skipPadding())
+ return EC;
+ }
+
+ MemberKind.reset();
+ error(IO.endRecord());
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
+ error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
+ error(IO.mapEnum(Record.Modifiers, "Modifiers"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Record) {
+ error(IO.mapInteger(Record.ReturnType, "ReturnType"));
+ error(IO.mapEnum(Record.CallConv, "CallingConvention"));
+ error(IO.mapEnum(Record.Options, "FunctionOptions"));
+ error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
+ error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &Record) {
+ error(IO.mapInteger(Record.ReturnType, "ReturnType"));
+ error(IO.mapInteger(Record.ClassType, "ClassType"));
+ error(IO.mapInteger(Record.ThisType, "ThisType"));
+ error(IO.mapEnum(Record.CallConv, "CallingConvention"));
+ error(IO.mapEnum(Record.Options, "FunctionOptions"));
+ error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
+ error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
+ error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
+ error(IO.mapVectorN<uint32_t>(
+ Record.ArgIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Argument");
+ },
+ "NumArgs"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ StringListRecord &Record) {
+ error(IO.mapVectorN<uint32_t>(
+ Record.StringIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Strings");
+ },
+ "NumStrings"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
+ error(IO.mapInteger(Record.ReferentType, "PointeeType"));
+ error(IO.mapInteger(Record.Attrs, "Attributes"));
+
+ if (Record.isPointerToMember()) {
+ if (IO.isReading())
+ Record.MemberInfo.emplace();
+
+ MemberPointerInfo &M = *Record.MemberInfo;
+ error(IO.mapInteger(M.ContainingType, "ClassType"));
+ error(IO.mapEnum(M.Representation, "Representation"));
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
+ error(IO.mapInteger(Record.ElementType, "ElementType"));
+ error(IO.mapInteger(Record.IndexType, "IndexType"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
+ assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
+ (CVR.kind() == TypeLeafKind::LF_CLASS) ||
+ (CVR.kind() == TypeLeafKind::LF_INTERFACE));
+
+ error(IO.mapInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEnum(Record.Options, "Properties"));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
+ error(IO.mapInteger(Record.VTableShape, "VShape"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
+ error(IO.mapInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEnum(Record.Options, "Properties"));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
+ error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
+ error(IO.mapEnum(Record.Options, "Properties"));
+ error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
+ error(IO.mapInteger(Record.FieldList, "FieldListType"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapInteger(Record.BitSize, "BitSize"));
+ error(IO.mapInteger(Record.BitOffset, "BitOffset"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Record) {
+ uint16_t Size;
+ if (!IO.isReading()) {
+ ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
+ Size = Slots.size();
+ error(IO.mapInteger(Size, "VFEntryCount"));
+
+ for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
+ uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
+ if ((SlotIndex + 1) < Slots.size()) {
+ Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
+ }
+ error(IO.mapInteger(Byte));
+ }
+ } else {
+ error(IO.mapInteger(Size));
+ for (uint16_t I = 0; I < Size; I += 2) {
+ uint8_t Byte;
+ error(IO.mapInteger(Byte));
+ Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
+ if ((I + 1) < Size)
+ Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
+ }
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
+ error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
+ error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
+ error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
+ uint32_t NamesLen = 0;
+ if (!IO.isReading()) {
+ for (auto Name : Record.MethodNames)
+ NamesLen += Name.size() + 1;
+ }
+ error(IO.mapInteger(NamesLen));
+ error(IO.mapVectorTail(
+ Record.MethodNames,
+ [](CodeViewRecordIO &IO, StringRef &S) {
+ return IO.mapStringZ(S, "MethodName");
+ },
+ "VFTableName"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
+ error(IO.mapInteger(Record.Id, "Id"));
+ error(IO.mapStringZ(Record.String, "StringData"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT, "UDT"));
+ error(IO.mapInteger(Record.SourceFile, "SourceFile"));
+ error(IO.mapInteger(Record.LineNumber, "LineNumber"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT, "UDT"));
+ error(IO.mapInteger(Record.SourceFile, "SourceFile"));
+ error(IO.mapInteger(Record.LineNumber, "LineNumber"));
+ error(IO.mapInteger(Record.Module, "Module"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ParentScope, "ParentScope"));
+ error(IO.mapInteger(Record.FunctionType, "FunctionType"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ClassType, "ClassType"));
+ error(IO.mapInteger(Record.FunctionType, "FunctionType"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ BuildInfoRecord &Record) {
+ error(IO.mapVectorN<uint16_t>(
+ Record.ArgIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Argument");
+ },
+ "NumArgs"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MethodOverloadListRecord &Record) {
+ // TODO: Split the list into multiple records if it's longer than 64KB, using
+ // a subrecord of TypeRecordKind::Index to chain the records together.
+ error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ FieldListRecord &Record) {
+ error(IO.mapByteVectorTail(Record.Data));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &Record) {
+ error(IO.mapGuid(Record.Guid, "Guid"));
+ error(IO.mapInteger(Record.Age, "Age"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
+ error(IO.mapEnum(Record.Mode, "Mode"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Record) {
+ error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
+ error(IO.mapInteger(Record.Type, "BaseType"));
+ error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Record) {
+ error(IO.mapInteger(Record.Attrs.Attrs));
+
+ // FIXME: Handle full APInt such as __int128.
+ error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Record) {
+ error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Record) {
+ error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
+ error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Record) {
+ const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
+ MapOneMethodRecord Mapper(IsFromOverloadList);
+ return Mapper(IO, Record);
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Record) {
+
+ error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Record) {
+
+ error(IO.mapInteger(Record.Attrs.Attrs, "AccessSpecifier"));
+ error(IO.mapInteger(Record.BaseType, "BaseType"));
+ error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
+ error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
+ error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.Type, "Type"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
+ error(IO.mapInteger(Precomp.TypesCount, "Count"));
+ error(IO.mapInteger(Precomp.Signature, "Signature"));
+ error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
+ return Error::success();
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
new file mode 100644
index 000000000000..aba0e96d606e
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -0,0 +1,493 @@
+//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/Error.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static inline size_t slotForIndex(TypeIndex Idx) {
+ assert(!Idx.isSimple() && "simple type indices have no slots");
+ return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+}
+
+namespace {
+
+/// Implementation of CodeView type stream merging.
+///
+/// A CodeView type stream is a series of records that reference each other
+/// through type indices. A type index is either "simple", meaning it is less
+/// than 0x1000 and refers to a builtin type, or it is complex, meaning it
+/// refers to a prior type record in the current stream. The type index of a
+/// record is equal to the number of records before it in the stream plus
+/// 0x1000.
+///
+/// Type records are only allowed to use type indices smaller than their own, so
+/// a type stream is effectively a topologically sorted DAG. Cycles occuring in
+/// the type graph of the source program are resolved with forward declarations
+/// of composite types. This class implements the following type stream merging
+/// algorithm, which relies on this DAG structure:
+///
+/// - Begin with a new empty stream, and a new empty hash table that maps from
+/// type record contents to new type index.
+/// - For each new type stream, maintain a map from source type index to
+/// destination type index.
+/// - For each record, copy it and rewrite its type indices to be valid in the
+/// destination type stream.
+/// - If the new type record is not already present in the destination stream
+/// hash table, append it to the destination type stream, assign it the next
+/// type index, and update the two hash tables.
+/// - If the type record already exists in the destination stream, discard it
+/// and update the type index map to forward the source type index to the
+/// existing destination type index.
+///
+/// As an additional complication, type stream merging actually produces two
+/// streams: an item (or IPI) stream and a type stream, as this is what is
+/// actually stored in the final PDB. We choose which records go where by
+/// looking at the record kind.
+class TypeStreamMerger {
+public:
+ explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest)
+ : IndexMap(SourceToDest) {
+ // When dealing with precompiled headers objects, all data in SourceToDest
+ // belongs to the precompiled headers object, and is assumed to be already
+ // remapped to the target PDB. Any forthcoming type that will be merged in
+ // might potentially back-reference this data. We also don't want to resolve
+ // twice the types in the precompiled object.
+ CurIndex += SourceToDest.size();
+ }
+
+ static const TypeIndex Untranslated;
+
+ // Local hashing entry points
+ Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
+ MergingTypeTableBuilder &DestTypes,
+ const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S);
+ Error mergeIdRecords(MergingTypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ const CVTypeArray &Ids);
+ Error mergeTypeRecords(MergingTypeTableBuilder &Dest,
+ const CVTypeArray &Types);
+
+ // Global hashing entry points
+ Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds,
+ GlobalTypeTableBuilder &DestTypes,
+ const CVTypeArray &IdsAndTypes,
+ ArrayRef<GloballyHashedType> Hashes,
+ Optional<uint32_t> &S);
+ Error mergeIdRecords(GlobalTypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ const CVTypeArray &Ids,
+ ArrayRef<GloballyHashedType> Hashes);
+ Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types,
+ ArrayRef<GloballyHashedType> Hashes,
+ Optional<uint32_t> &S);
+
+private:
+ Error doit(const CVTypeArray &Types);
+
+ Error remapAllTypes(const CVTypeArray &Types);
+
+ Error remapType(const CVType &Type);
+
+ void addMapping(TypeIndex Idx);
+
+ inline bool remapTypeIndex(TypeIndex &Idx) {
+ // If we're mapping a pure index stream, then IndexMap only contains
+ // mappings from OldIdStream -> NewIdStream, in which case we will need to
+ // use the 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 (!hasTypeStream())
+ return remapIndex(Idx, TypeLookup);
+
+ assert(TypeLookup.empty());
+ return remapIndex(Idx, IndexMap);
+ }
+ inline bool remapItemIndex(TypeIndex &Idx) {
+ assert(hasIdStream());
+ return remapIndex(Idx, IndexMap);
+ }
+
+ bool hasTypeStream() const {
+ return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream);
+ }
+
+ bool hasIdStream() const {
+ return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream);
+ }
+
+ ArrayRef<uint8_t> remapIndices(const CVType &OriginalType,
+ MutableArrayRef<uint8_t> Storage);
+
+ inline bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) {
+ if (LLVM_LIKELY(remapIndexSimple(Idx, Map)))
+ return true;
+
+ return remapIndexFallback(Idx, Map);
+ }
+
+ inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef<TypeIndex> Map) const {
+ // Simple types are unchanged.
+ if (Idx.isSimple())
+ return true;
+
+ // Check if this type index refers to a record we've already translated
+ // successfully. If it refers to a type later in the stream or a record we
+ // had to defer, defer it until later pass.
+ unsigned MapPos = slotForIndex(Idx);
+ if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated))
+ return false;
+
+ Idx = Map[MapPos];
+ return true;
+ }
+
+ bool remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map);
+
+ Error errorCorruptRecord() const {
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+ }
+
+ Expected<bool> shouldRemapType(const CVType &Type);
+
+ Optional<Error> LastError;
+
+ bool UseGlobalHashes = false;
+
+ bool IsSecondPass = false;
+
+ unsigned NumBadIndices = 0;
+
+ TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
+
+ 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.
+ ArrayRef<TypeIndex> TypeLookup;
+
+ /// 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;
+
+ Optional<uint32_t> PCHSignature;
+};
+
+} // end anonymous namespace
+
+const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
+
+static bool isIdRecord(TypeLeafKind K) {
+ switch (K) {
+ case TypeLeafKind::LF_FUNC_ID:
+ case TypeLeafKind::LF_MFUNC_ID:
+ case TypeLeafKind::LF_STRING_ID:
+ case TypeLeafKind::LF_SUBSTR_LIST:
+ case TypeLeafKind::LF_BUILDINFO:
+ case TypeLeafKind::LF_UDT_SRC_LINE:
+ case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void TypeStreamMerger::addMapping(TypeIndex Idx) {
+ if (!IsSecondPass) {
+ assert(IndexMap.size() == slotForIndex(CurIndex) &&
+ "visitKnownRecord should add one index map entry");
+ IndexMap.push_back(Idx);
+ } else {
+ assert(slotForIndex(CurIndex) < IndexMap.size());
+ IndexMap[slotForIndex(CurIndex)] = Idx;
+ }
+}
+
+bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx,
+ ArrayRef<TypeIndex> Map) {
+ size_t MapPos = slotForIndex(Idx);
+
+ // If this is the second pass and this index isn't in the map, then it points
+ // outside the current type stream, and this is a corrupt record.
+ if (IsSecondPass && MapPos >= Map.size()) {
+ // FIXME: Print a more useful error. We can give the current record and the
+ // index that we think its pointing to.
+ if (LastError)
+ LastError = joinErrors(std::move(*LastError), errorCorruptRecord());
+ else
+ LastError = errorCorruptRecord();
+ }
+
+ ++NumBadIndices;
+
+ // This type index is invalid. Remap this to "not translated by cvpack",
+ // and return failure.
+ Idx = Untranslated;
+ return false;
+}
+
+// Local hashing entry points
+Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest,
+ const CVTypeArray &Types) {
+ DestTypeStream = &Dest;
+ UseGlobalHashes = false;
+
+ return doit(Types);
+}
+
+Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ const CVTypeArray &Ids) {
+ DestIdStream = &Dest;
+ TypeLookup = TypeSourceToDest;
+ UseGlobalHashes = false;
+
+ return doit(Ids);
+}
+
+Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds,
+ MergingTypeTableBuilder &DestTypes,
+ const CVTypeArray &IdsAndTypes,
+ Optional<uint32_t> &S) {
+ DestIdStream = &DestIds;
+ DestTypeStream = &DestTypes;
+ UseGlobalHashes = false;
+ auto Err = doit(IdsAndTypes);
+ S = PCHSignature;
+ return Err;
+}
+
+// Global hashing entry points
+Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
+ const CVTypeArray &Types,
+ ArrayRef<GloballyHashedType> Hashes,
+ Optional<uint32_t> &S) {
+ DestGlobalTypeStream = &Dest;
+ UseGlobalHashes = true;
+ GlobalHashes = Hashes;
+ auto Err = doit(Types);
+ S = PCHSignature;
+ return Err;
+}
+
+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,
+ Optional<uint32_t> &S) {
+ DestGlobalIdStream = &DestIds;
+ DestGlobalTypeStream = &DestTypes;
+ UseGlobalHashes = true;
+ GlobalHashes = Hashes;
+ auto Err = doit(IdsAndTypes);
+ S = PCHSignature;
+ return Err;
+}
+
+Error TypeStreamMerger::doit(const CVTypeArray &Types) {
+ if (auto EC = remapAllTypes(Types))
+ return EC;
+
+ // If we found bad indices but no other errors, try doing another pass and see
+ // if we can resolve the indices that weren't in the map on the first pass.
+ // This may require multiple passes, but we should always make progress. MASM
+ // is the only known CodeView producer that makes type streams that aren't
+ // topologically sorted. The standard library contains MASM-produced objects,
+ // so this is important to handle correctly, but we don't have to be too
+ // efficient. MASM type streams are usually very small.
+ while (!LastError && NumBadIndices > 0) {
+ unsigned BadIndicesRemaining = NumBadIndices;
+ IsSecondPass = true;
+ NumBadIndices = 0;
+ CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
+
+ if (auto EC = remapAllTypes(Types))
+ return EC;
+
+ assert(NumBadIndices <= BadIndicesRemaining &&
+ "second pass found more bad indices");
+ if (!LastError && NumBadIndices == BadIndicesRemaining) {
+ return llvm::make_error<CodeViewError>(
+ cv_error_code::corrupt_record, "Input type graph contains cycles");
+ }
+ }
+
+ if (LastError)
+ return std::move(*LastError);
+ return Error::success();
+}
+
+Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) {
+ BinaryStreamRef Stream = Types.getUnderlyingStream();
+ ArrayRef<uint8_t> Buffer;
+ cantFail(Stream.readBytes(0, Stream.getLength(), Buffer));
+
+ return forEachCodeViewRecord<CVType>(
+ Buffer, [this](const CVType &T) { return remapType(T); });
+}
+
+Error TypeStreamMerger::remapType(const CVType &Type) {
+ auto R = shouldRemapType(Type);
+ if (!R)
+ return R.takeError();
+
+ TypeIndex DestIdx = Untranslated;
+ if (*R) {
+ auto DoSerialize =
+ [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> {
+ return remapIndices(Type, Storage);
+ };
+ if (LLVM_LIKELY(UseGlobalHashes)) {
+ GlobalTypeTableBuilder &Dest =
+ isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream;
+ GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()];
+ DestIdx = Dest.insertRecordAs(H, Type.RecordData.size(), DoSerialize);
+ } else {
+ MergingTypeTableBuilder &Dest =
+ isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream;
+
+ RemapStorage.resize(Type.RecordData.size());
+ ArrayRef<uint8_t> Result = DoSerialize(RemapStorage);
+ if (!Result.empty())
+ DestIdx = Dest.insertRecordBytes(Result);
+ }
+ }
+ addMapping(DestIdx);
+
+ ++CurIndex;
+ assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) &&
+ "visitKnownRecord should add one index map entry");
+ return Error::success();
+}
+
+ArrayRef<uint8_t>
+TypeStreamMerger::remapIndices(const CVType &OriginalType,
+ MutableArrayRef<uint8_t> Storage) {
+ SmallVector<TiReference, 4> Refs;
+ discoverTypeIndices(OriginalType.RecordData, Refs);
+ if (Refs.empty())
+ return OriginalType.RecordData;
+
+ ::memcpy(Storage.data(), OriginalType.RecordData.data(),
+ OriginalType.RecordData.size());
+
+ uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix);
+
+ for (auto &Ref : Refs) {
+ TypeIndex *DestTIs =
+ reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset);
+
+ for (size_t I = 0; I < Ref.Count; ++I) {
+ TypeIndex &TI = DestTIs[I];
+ bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI)
+ : remapTypeIndex(TI);
+ if (LLVM_UNLIKELY(!Success))
+ return {};
+ }
+ }
+ return Storage;
+}
+
+Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest,
+ SmallVectorImpl<TypeIndex> &SourceToDest,
+ const CVTypeArray &Types) {
+ TypeStreamMerger M(SourceToDest);
+ return M.mergeTypeRecords(Dest, Types);
+}
+
+Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ SmallVectorImpl<TypeIndex> &SourceToDest,
+ const CVTypeArray &Ids) {
+ TypeStreamMerger M(SourceToDest);
+ return M.mergeIdRecords(Dest, TypeSourceToDest, Ids);
+}
+
+Error llvm::codeview::mergeTypeAndIdRecords(
+ MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes,
+ SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes,
+ Optional<uint32_t> &PCHSignature) {
+ TypeStreamMerger M(SourceToDest);
+ return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHSignature);
+}
+
+Error llvm::codeview::mergeTypeAndIdRecords(
+ GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes,
+ SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes,
+ ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) {
+ TypeStreamMerger M(SourceToDest);
+ return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes,
+ PCHSignature);
+}
+
+Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest,
+ SmallVectorImpl<TypeIndex> &SourceToDest,
+ const CVTypeArray &Types,
+ ArrayRef<GloballyHashedType> Hashes,
+ Optional<uint32_t> &PCHSignature) {
+ TypeStreamMerger M(SourceToDest);
+ return M.mergeTypeRecords(Dest, Types, Hashes, PCHSignature);
+}
+
+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);
+}
+
+Expected<bool> TypeStreamMerger::shouldRemapType(const CVType &Type) {
+ // For object files containing precompiled types, we need to extract the
+ // signature, through EndPrecompRecord. This is done here for performance
+ // reasons, to avoid re-parsing the Types stream.
+ if (Type.kind() == LF_ENDPRECOMP) {
+ EndPrecompRecord EP;
+ if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type),
+ EP))
+ return joinErrors(std::move(EC), errorCorruptRecord());
+ if (PCHSignature.hasValue())
+ return errorCorruptRecord();
+ PCHSignature.emplace(EP.getSignature());
+ return false;
+ }
+ return true;
+}
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp
new file mode 100644
index 000000000000..e13068b5b1eb
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp
@@ -0,0 +1,60 @@
+//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+TypeTableCollection::TypeTableCollection(ArrayRef<ArrayRef<uint8_t>> Records)
+ : NameStorage(Allocator), Records(Records) {
+ Names.resize(Records.size());
+}
+
+Optional<TypeIndex> TypeTableCollection::getFirst() {
+ if (empty())
+ return None;
+ return TypeIndex::fromArrayIndex(0);
+}
+
+Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) {
+ assert(contains(Prev));
+ ++Prev;
+ if (Prev.toArrayIndex() == size())
+ return None;
+ return Prev;
+}
+
+CVType TypeTableCollection::getType(TypeIndex Index) {
+ assert(Index.toArrayIndex() < Records.size());
+ return CVType(Records[Index.toArrayIndex()]);
+}
+
+StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
+ if (Index.isNoneType() || Index.isSimple())
+ return TypeIndex::simpleTypeName(Index);
+
+ uint32_t I = Index.toArrayIndex();
+ if (Names[I].data() == nullptr) {
+ StringRef Result = NameStorage.save(computeTypeName(*this, Index));
+ Names[I] = Result;
+ }
+ return Names[I];
+}
+
+bool TypeTableCollection::contains(TypeIndex Index) {
+ return Index.toArrayIndex() <= size();
+}
+
+uint32_t TypeTableCollection::size() { return Records.size(); }
+
+uint32_t TypeTableCollection::capacity() { return Records.size(); }