aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/CodeView')
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp64
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp345
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp71
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp256
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp108
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp51
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp91
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp44
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp122
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp158
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp80
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp16
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp83
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp126
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp31
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp34
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp385
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/Formatters.cpp37
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp229
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/Line.cpp22
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp149
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp689
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp465
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp54
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp213
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp330
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp557
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp27
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp371
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp481
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp371
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp350
-rw-r--r--contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp83
33 files changed, 6493 insertions, 0 deletions
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
new file mode 100644
index 000000000000..d058f4864975
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
@@ -0,0 +1,64 @@
+//===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+#include "llvm/Support/BinaryByteStream.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.Type);
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {
+ if (auto EC = Callbacks.visitSymbolBegin(Record))
+ return EC;
+
+ switch (Record.Type) {
+ 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::visitSymbolStream(const CVSymbolArray &Symbols) {
+ for (auto I : Symbols) {
+ if (auto EC = visitSymbolRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
new file mode 100644
index 000000000000..f0debd9e9702
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -0,0 +1,345 @@
+//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.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.Type);
+ 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 Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
+ TypeServer2Record R(TypeRecordKind::TypeServer2);
+ if (auto EC = TypeDeserializer::deserializeAs(Record, R))
+ return std::move(EC);
+ return R;
+}
+
+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);
+
+ void addTypeServerHandler(TypeServerHandler &Handler);
+
+ 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:
+ Expected<bool> handleTypeServer(CVType &Record);
+ Error finishVisitation(CVType &Record);
+
+ /// The interface to the class that gets notified of each visitation.
+ TypeVisitorCallbacks &Callbacks;
+
+ TinyPtrVector<TypeServerHandler *> Handlers;
+};
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
+ Handlers.push_back(&Handler);
+}
+
+Expected<bool> CVTypeVisitor::handleTypeServer(CVType &Record) {
+ if (Record.Type == TypeLeafKind::LF_TYPESERVER2 && !Handlers.empty()) {
+ auto TS = deserializeTypeServerRecord(Record);
+ if (!TS)
+ return TS.takeError();
+
+ for (auto Handler : Handlers) {
+ auto ExpectedResult = Handler->handle(*TS, Callbacks);
+ // If there was an error, return the error.
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+
+ // If the handler processed the record, return success.
+ if (*ExpectedResult)
+ return true;
+
+ // Otherwise keep searching for a handler, eventually falling out and
+ // using the default record handler.
+ }
+ }
+ return false;
+}
+
+Error CVTypeVisitor::finishVisitation(CVType &Record) {
+ switch (Record.Type) {
+ 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) {
+ auto ExpectedResult = handleTypeServer(Record);
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+ if (*ExpectedResult)
+ return Error::success();
+
+ if (auto EC = Callbacks.visitTypeBegin(Record, Index))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+ auto ExpectedResult = handleTypeServer(Record);
+ if (!ExpectedResult)
+ return ExpectedResult.takeError();
+ if (*ExpectedResult)
+ return Error::success();
+
+ 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);
+ }
+ }
+
+ TypeDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ CVTypeVisitor Visitor;
+};
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, Source);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeRecord(Record, Index);
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, Source);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeRecord(Record);
+}
+
+Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, Source);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(CVTypeRange Types,
+ TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(TypeCollection &Types,
+ TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS) {
+ // 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);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ 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/lib/DebugInfo/CodeView/CodeViewError.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
new file mode 100644
index 000000000000..8de266b836b4
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -0,0 +1,71 @@
+//===- CodeViewError.cpp - Error extensions for CodeView --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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 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");
+ }
+};
+} // end anonymous namespace
+
+static ManagedStatic<CodeViewErrorCategory> Category;
+
+char CodeViewError::ID = 0;
+
+CodeViewError::CodeViewError(cv_error_code C) : CodeViewError(C, "") {}
+
+CodeViewError::CodeViewError(const std::string &Context)
+ : CodeViewError(cv_error_code::unspecified, Context) {}
+
+CodeViewError::CodeViewError(cv_error_code C, const std::string &Context)
+ : Code(C) {
+ ErrMsg = "CodeView Error: ";
+ std::error_code EC = convertToErrorCode();
+ if (Code != cv_error_code::unspecified)
+ ErrMsg += EC.message() + " ";
+ if (!Context.empty())
+ ErrMsg += Context;
+}
+
+void CodeViewError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; }
+
+const std::string &CodeViewError::getErrorMessage() const { return ErrMsg; }
+
+std::error_code CodeViewError::convertToErrorCode() const {
+ return std::error_code(static_cast<int>(Code), *Category);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
new file mode 100644
index 000000000000..711144fc2faa
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -0,0 +1,256 @@
+//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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);
+ 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.
+ return Error::success();
+}
+
+uint32_t CodeViewRecordIO::maxFieldLength() const {
+ 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) {
+ 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) {
+ ArrayRef<uint8_t> BytesRef(Bytes);
+ if (auto EC = mapByteVectorTail(BytesRef))
+ return EC;
+ if (!isWriting())
+ Bytes.assign(BytesRef.begin(), BytesRef.end());
+
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd) {
+ if (isWriting()) {
+ if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
+ return EC;
+ return Error::success();
+ }
+
+ uint32_t I;
+ if (auto EC = Reader->readInteger(I))
+ return EC;
+ TypeInd.setIndex(I);
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value) {
+ 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) {
+ 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) {
+ if (isWriting()) {
+ if (Value.isSigned())
+ return writeEncodedSignedInteger(Value.getSExtValue());
+ return writeEncodedUnsignedInteger(Value.getZExtValue());
+ }
+
+ return consume(*Reader, Value);
+}
+
+Error CodeViewRecordIO::mapStringZ(StringRef &Value) {
+ 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(StringRef &Guid) {
+ constexpr uint32_t GuidSize = 16;
+ if (maxFieldLength() < GuidSize)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ if (isWriting()) {
+ assert(Guid.size() == 16 && "Invalid Guid Size!");
+ if (auto EC = Writer->writeFixedString(Guid))
+ return EC;
+ } else {
+ if (auto EC = Reader->readFixedString(Guid, 16))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value) {
+ if (isWriting()) {
+ for (auto V : Value) {
+ if (auto EC = mapStringZ(V))
+ return EC;
+ }
+ if (auto EC = Writer->writeInteger<uint8_t>(0))
+ 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();
+}
+
+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/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
new file mode 100644
index 000000000000..c31b8d1c96d5
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
@@ -0,0 +1,108 @@
+//===- DebugChecksumsSubsection.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+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 llvm::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.getStringId(FileName);
+ auto Iter = OffsetMap.find(Offset);
+ assert(Iter != OffsetMap.end());
+ return Iter->second;
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
new file mode 100644
index 000000000000..21e2cc56075b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
@@ -0,0 +1,51 @@
+//===- DebugCrossExSubsection.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+
+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/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
new file mode 100644
index 000000000000..2c4a0b779342
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
@@ -0,0 +1,91 @@
+//===- DebugCrossImpSubsection.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace llvm {
+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);
+
+ std::sort(Ids.begin(), Ids.end(), [this](const T &L1, const T &L2) {
+ return Strings.getStringId(L1->getKey()) <
+ Strings.getStringId(L2->getKey());
+ });
+
+ for (const auto &Item : Ids) {
+ CrossModuleImport Imp;
+ Imp.ModuleNameOffset = Strings.getStringId(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/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
new file mode 100644
index 000000000000..fd558aa9cc8a
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
@@ -0,0 +1,44 @@
+//===- DebugFrameDataSubsection.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) {
+ 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();
+}
+
+uint32_t DebugFrameDataSubsection::calculateSerializedSize() const {
+ return 4 + sizeof(FrameData) * Frames.size();
+}
+
+Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const {
+ if (auto EC = Writer.writeInteger<uint32_t>(0))
+ return EC;
+
+ if (auto EC = Writer.writeArray(makeArrayRef(Frames)))
+ return EC;
+ return Error::success();
+}
+
+void DebugFrameDataSubsection::addFrameData(const FrameData &Frame) {
+ Frames.push_back(Frame);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
new file mode 100644
index 000000000000..e7719d05dbdc
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
@@ -0,0 +1,122 @@
+//===- DebugInlineeLinesSubsection.cpp ------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+
+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/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
new file mode 100644
index 000000000000..fbcad61d60a6
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
@@ -0,0 +1,158 @@
+//===- DebugLinesSubsection.cpp -------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len,
+ LineColumnEntry &Item) {
+ using namespace codeview;
+ 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/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
new file mode 100644
index 000000000000..6e647c4b976b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
@@ -0,0 +1,80 @@
+//===- DebugStringTableSubsection.cpp - CodeView String Table ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+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 = Strings.insert({S, StringSize});
+
+ // If a given string didn't exist in the string table, we want to increment
+ // the string table size.
+ if (P.second)
+ 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;
+
+ for (auto &Pair : Strings) {
+ 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);
+ return Error::success();
+}
+
+uint32_t DebugStringTableSubsection::size() const { return Strings.size(); }
+
+uint32_t DebugStringTableSubsection::getStringId(StringRef S) const {
+ auto Iter = Strings.find(S);
+ assert(Iter != Strings.end());
+ return Iter->second;
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp
new file mode 100644
index 000000000000..67b428bfa713
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsection.cpp
@@ -0,0 +1,16 @@
+//===- DebugSubsection.cpp -----------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+
+using namespace llvm::codeview;
+
+DebugSubsectionRef::~DebugSubsectionRef() {}
+
+DebugSubsection::~DebugSubsection() {}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
new file mode 100644
index 000000000000..e9124e68fe82
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
@@ -0,0 +1,83 @@
+//===- DebugSubsectionRecord.cpp -----------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugSubsectionRecord::DebugSubsectionRecord()
+ : Container(CodeViewContainer::ObjectFile),
+ Kind(DebugSubsectionKind::None) {}
+
+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::unique_ptr<DebugSubsection> Subsection, CodeViewContainer Container)
+ : Subsection(std::move(Subsection)), Container(Container) {}
+
+uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
+ // The length of the entire subsection is always padded to 4 bytes, regardless
+ // of the container kind.
+ uint32_t Size = sizeof(DebugSubsectionHeader) +
+ alignTo(Subsection->calculateSerializedSize(), 4);
+ return Size;
+}
+
+Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) const {
+ assert(Writer.getOffset() % alignOf(Container) == 0 &&
+ "Debug Subsection not properly aligned");
+
+ DebugSubsectionHeader Header;
+ Header.Kind = uint32_t(Subsection->kind());
+ // The value written into the Header's Length field is only padded to the
+ // container's alignment
+ Header.Length =
+ alignTo(Subsection->calculateSerializedSize(), alignOf(Container));
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+ if (auto EC = Subsection->commit(Writer))
+ return EC;
+ if (auto EC = Writer.padToAlignment(4))
+ return EC;
+
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
new file mode 100644
index 000000000000..8550107741ce
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
@@ -0,0 +1,126 @@
+//===- DebugSubsectionVisitor.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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;
+
+DebugSubsectionState::DebugSubsectionState() {}
+
+DebugSubsectionState::DebugSubsectionState(
+ const DebugStringTableSubsectionRef &Strings)
+ : Strings(&Strings) {}
+
+DebugSubsectionState::DebugSubsectionState(
+ const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums)
+ : Strings(&Strings), Checksums(&Checksums) {}
+
+void DebugSubsectionState::initializeStrings(const DebugSubsectionRecord &SR) {
+ assert(SR.kind() == DebugSubsectionKind::StringTable);
+ assert(!Strings && "Found a string table even though we already have one!");
+
+ OwnedStrings = llvm::make_unique<DebugStringTableSubsectionRef>();
+ consumeError(OwnedStrings->initialize(SR.getRecordData()));
+ Strings = OwnedStrings.get();
+}
+
+void DebugSubsectionState::initializeChecksums(
+ const DebugSubsectionRecord &FCR) {
+ assert(FCR.kind() == DebugSubsectionKind::FileChecksums);
+ if (Checksums)
+ return;
+
+ OwnedChecksums = llvm::make_unique<DebugChecksumsSubsectionRef>();
+ consumeError(OwnedChecksums->initialize(FCR.getRecordData()));
+ Checksums = OwnedChecksums.get();
+}
+
+Error llvm::codeview::visitDebugSubsection(const DebugSubsectionRecord &R,
+ DebugSubsectionVisitor &V,
+ const DebugSubsectionState &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/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
new file mode 100644
index 000000000000..5f91b68f3ad8
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
@@ -0,0 +1,31 @@
+//===- DebugSymbolRVASubsection.cpp ------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
+
+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/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
new file mode 100644
index 000000000000..dc8ba8c929ae
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
@@ -0,0 +1,34 @@
+//===- DebugSymbolsSubsection.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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();
+} \ No newline at end of file
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
new file mode 100644
index 000000000000..01d8ccf2d31e
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -0,0 +1,385 @@
+//===- EnumTables.cpp - Enum to string conversion tables --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+
+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[] = {
+ CV_ENUM_CLASS_ENT(RegisterId, Unknown),
+ CV_ENUM_CLASS_ENT(RegisterId, VFrame),
+ CV_ENUM_CLASS_ENT(RegisterId, AL),
+ CV_ENUM_CLASS_ENT(RegisterId, CL),
+ CV_ENUM_CLASS_ENT(RegisterId, DL),
+ CV_ENUM_CLASS_ENT(RegisterId, BL),
+ CV_ENUM_CLASS_ENT(RegisterId, AH),
+ CV_ENUM_CLASS_ENT(RegisterId, CH),
+ CV_ENUM_CLASS_ENT(RegisterId, DH),
+ CV_ENUM_CLASS_ENT(RegisterId, BH),
+ CV_ENUM_CLASS_ENT(RegisterId, AX),
+ CV_ENUM_CLASS_ENT(RegisterId, CX),
+ CV_ENUM_CLASS_ENT(RegisterId, DX),
+ CV_ENUM_CLASS_ENT(RegisterId, BX),
+ CV_ENUM_CLASS_ENT(RegisterId, SP),
+ CV_ENUM_CLASS_ENT(RegisterId, BP),
+ CV_ENUM_CLASS_ENT(RegisterId, SI),
+ CV_ENUM_CLASS_ENT(RegisterId, DI),
+ CV_ENUM_CLASS_ENT(RegisterId, EAX),
+ CV_ENUM_CLASS_ENT(RegisterId, ECX),
+ CV_ENUM_CLASS_ENT(RegisterId, EDX),
+ CV_ENUM_CLASS_ENT(RegisterId, EBX),
+ CV_ENUM_CLASS_ENT(RegisterId, ESP),
+ CV_ENUM_CLASS_ENT(RegisterId, EBP),
+ CV_ENUM_CLASS_ENT(RegisterId, ESI),
+ CV_ENUM_CLASS_ENT(RegisterId, EDI),
+ CV_ENUM_CLASS_ENT(RegisterId, ES),
+ CV_ENUM_CLASS_ENT(RegisterId, CS),
+ CV_ENUM_CLASS_ENT(RegisterId, SS),
+ CV_ENUM_CLASS_ENT(RegisterId, DS),
+ CV_ENUM_CLASS_ENT(RegisterId, FS),
+ CV_ENUM_CLASS_ENT(RegisterId, GS),
+ CV_ENUM_CLASS_ENT(RegisterId, IP),
+ CV_ENUM_CLASS_ENT(RegisterId, RAX),
+ CV_ENUM_CLASS_ENT(RegisterId, RBX),
+ CV_ENUM_CLASS_ENT(RegisterId, RCX),
+ CV_ENUM_CLASS_ENT(RegisterId, RDX),
+ CV_ENUM_CLASS_ENT(RegisterId, RSI),
+ CV_ENUM_CLASS_ENT(RegisterId, RDI),
+ CV_ENUM_CLASS_ENT(RegisterId, RBP),
+ CV_ENUM_CLASS_ENT(RegisterId, RSP),
+ CV_ENUM_CLASS_ENT(RegisterId, R8),
+ CV_ENUM_CLASS_ENT(RegisterId, R9),
+ CV_ENUM_CLASS_ENT(RegisterId, R10),
+ CV_ENUM_CLASS_ENT(RegisterId, R11),
+ CV_ENUM_CLASS_ENT(RegisterId, R12),
+ CV_ENUM_CLASS_ENT(RegisterId, R13),
+ CV_ENUM_CLASS_ENT(RegisterId, R14),
+ CV_ENUM_CLASS_ENT(RegisterId, R15),
+};
+
+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),
+};
+
+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, 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, 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() {
+ return makeArrayRef(RegisterNames);
+}
+
+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);
+}
+}
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/Formatters.cpp b/contrib/llvm/lib/DebugInfo/CodeView/Formatters.cpp
new file mode 100644
index 000000000000..ef00bd8570fa
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/Formatters.cpp
@@ -0,0 +1,37 @@
+//===- Formatters.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+
+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(llvm::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 << "}";
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
new file mode 100644
index 000000000000..39eb4099ce9e
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -0,0 +1,229 @@
+//===- LazyRandomTypeCollection.cpp ---------------------------- *- C++--*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+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)
+ : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database),
+ PartialOffsets(PartialOffsets) {
+ KnownOffsets.resize(Database.capacity());
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(RecordCountHint) {
+ reset(Data);
+}
+
+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(StringRef Data) {
+ reset(makeArrayRef(Data.bytes_begin(), Data.bytes_end()));
+}
+
+void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data) {
+ PartialOffsets = PartialOffsetArray();
+
+ BinaryStreamReader Reader(Data, support::little);
+ error(Reader.readArray(Types, Reader.getLength()));
+
+ KnownOffsets.resize(Database.capacity());
+}
+
+CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
+ error(ensureTypeExists(Index));
+ return Database.getTypeRecord(Index);
+}
+
+StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
+ if (!Index.isSimple()) {
+ // 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.
+ consumeError(ensureTypeExists(Index));
+ }
+
+ return Database.getTypeName(Index);
+}
+
+bool LazyRandomTypeCollection::contains(TypeIndex Index) {
+ return Database.contains(Index);
+}
+
+uint32_t LazyRandomTypeCollection::size() { return Database.size(); }
+
+uint32_t LazyRandomTypeCollection::capacity() { return Database.capacity(); }
+
+Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
+ if (!Database.contains(TI)) {
+ if (auto EC = visitRangeForType(TI))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
+ 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 (Database.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(Database.capacity());
+ } else {
+ TIE = Next->Type;
+ }
+
+ if (auto EC = visitRange(TIB, Prev->Offset, TIE))
+ return EC;
+ 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(PartialOffsets.empty());
+
+ TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
+ uint32_t Offset = 0;
+ auto Begin = Types.begin();
+
+ if (!Database.empty()) {
+ // 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. So we ask the
+ // database for the largest type index less than the one we're searching for
+ // and only do the forward scan from there.
+ auto Prev = Database.largestTypeIndexLessThan(TI);
+ assert(Prev.hasValue() && "Empty database with valid types?");
+ Offset = KnownOffsets[Prev->toArrayIndex()];
+ CurrentTI = *Prev;
+ ++CurrentTI;
+ Begin = Types.at(Offset);
+ ++Begin;
+ Offset = Begin.offset();
+ }
+
+ auto End = Types.end();
+ while (Begin != End) {
+ if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin))
+ return EC;
+
+ Offset += Begin.getRecordLength();
+ ++Begin;
+ ++CurrentTI;
+ }
+ if (CurrentTI <= TI) {
+ return make_error<CodeViewError>("Type Index does not exist!");
+ }
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitRange(TypeIndex Begin,
+ uint32_t BeginOffset,
+ TypeIndex End) {
+
+ auto RI = Types.at(BeginOffset);
+ assert(RI != Types.end());
+
+ while (Begin != End) {
+ if (auto EC = visitOneRecord(Begin, BeginOffset, *RI))
+ return EC;
+
+ BeginOffset += RI.getRecordLength();
+ ++Begin;
+ ++RI;
+ }
+
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset,
+ CVType &Record) {
+ assert(!Database.contains(TI));
+ if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor))
+ return EC;
+ // Keep the KnownOffsets array the same size as the Database's capacity. Since
+ // we don't always know how many records are in the type stream, we need to be
+ // prepared for the database growing and receicing a type index that can't fit
+ // in our current buffer.
+ if (KnownOffsets.size() < Database.capacity())
+ KnownOffsets.resize(Database.capacity());
+ KnownOffsets[TI.toArrayIndex()] = Offset;
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp b/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp
new file mode 100644
index 000000000000..4cb766b5fd26
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/Line.cpp
@@ -0,0 +1,22 @@
+//===-- Line.cpp ----------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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/lib/DebugInfo/CodeView/RecordSerialization.cpp b/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
new file mode 100644
index 000000000000..6446670f60d8
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -0,0 +1,149 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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/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);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
new file mode 100644
index 000000000000..66045933ce9b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -0,0 +1,689 @@
+//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/ADT/DenseMap.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, bool PrintRecordBytes)
+ : Types(Types), ObjDelegate(ObjDelegate), W(W),
+ 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;
+
+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;
+
+ bool PrintRecordBytes;
+ bool InFunctionScope;
+};
+}
+
+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) {
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) {
+ if (PrintRecordBytes && ObjDelegate)
+ ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+ DictScope S(W, "BlockStart");
+
+ 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) {
+ DictScope S(W, "Thunk32");
+ 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) {
+ DictScope S(W, "Trampoline");
+ 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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "COFF Group");
+ 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) {
+ DictScope S(W, "BPRelativeSym");
+
+ W.printNumber("Offset", BPRel.Offset);
+ printTypeIndex("Type", BPRel.Type);
+ W.printString("VarName", BPRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+ DictScope S(W, "BuildInfo");
+
+ W.printNumber("BuildId", BuildInfo.BuildId);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CallSiteInfo) {
+ DictScope S(W, "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) {
+ DictScope S(W, "EnvBlock");
+
+ ListScope L(W, "Entries");
+ for (auto Entry : EnvBlock.Fields) {
+ W.printString(Entry);
+ }
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FileStaticSym &FileStatic) {
+ DictScope S(W, "FileStatic");
+ W.printNumber("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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "CompilerFlags2");
+
+ W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames());
+ W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames());
+ W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames());
+ 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) {
+ DictScope S(W, "CompilerFlags3");
+
+ W.printEnum("Language", Compile3.getLanguage(), getSourceLanguageNames());
+ W.printFlags("Flags", Compile3.getFlags(), getCompileSym3FlagNames());
+ W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames());
+ 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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "DataSym");
+
+ W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames());
+ 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) {
+ DictScope S(W, "DefRangeFramePointerRelFullScope");
+ W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+ DictScope S(W, "DefRangeFramePointerRel");
+
+ W.printNumber("Offset", DefRangeFramePointerRel.Offset);
+ printLocalVariableAddrRange(DefRangeFramePointerRel.Range,
+ DefRangeFramePointerRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+ DictScope S(W, "DefRangeRegisterRel");
+
+ W.printNumber("BaseRegister", DefRangeRegisterRel.Hdr.Register);
+ 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) {
+ DictScope S(W, "DefRangeRegister");
+
+ W.printNumber("Register", DefRangeRegister.Hdr.Register);
+ W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName);
+ printLocalVariableAddrRange(DefRangeRegister.Range,
+ DefRangeRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegister.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+ DictScope S(W, "DefRangeSubfieldRegister");
+
+ W.printNumber("Register", DefRangeSubfieldRegister.Hdr.Register);
+ 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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "FrameCookie");
+
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ FrameCookie.getRelocationOffset(),
+ FrameCookie.CodeOffset, &LinkageName);
+ }
+ W.printHex("Register", FrameCookie.Register);
+ W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind),
+ getFrameCookieKindNames());
+ W.printHex("Flags", FrameCookie.Flags);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FrameProcSym &FrameProc) {
+ DictScope S(W, "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());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) {
+ DictScope S(W, "HeapAllocationSite");
+
+ 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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "RegisterSym");
+ W.printNumber("Type", Register.Index);
+ W.printEnum("Seg", uint16_t(Register.Register), getRegisterNames());
+ W.printString("Name", Register.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) {
+ DictScope S(W, "PublicSym");
+ W.printNumber("Type", Public.Index);
+ 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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "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) {
+ DictScope S(W, "ObjectName");
+
+ W.printHex("Signature", ObjName.Signature);
+ W.printString("ObjectName", ObjName.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ DictScope S(W, "ProcStart");
+
+ if (InFunctionScope)
+ return llvm::make_error<CodeViewError>(
+ "Visiting a ProcSym while inside function scope!");
+
+ InFunctionScope = true;
+
+ StringRef LinkageName;
+ W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames());
+ 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) {
+ if (CVR.kind() == SymbolKind::S_END)
+ DictScope S(W, "BlockEnd");
+ else if (CVR.kind() == SymbolKind::S_PROC_ID_END)
+ DictScope S(W, "ProcEnd");
+ else if (CVR.kind() == SymbolKind::S_INLINESITE_END)
+ DictScope S(W, "InlineSiteEnd");
+
+ 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) {
+ DictScope S(W, "RegRelativeSym");
+
+ W.printHex("Offset", RegRel.Offset);
+ printTypeIndex("Type", RegRel.Type);
+ W.printHex("Register", RegRel.Register);
+ W.printString("VarName", RegRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+ DictScope S(W, "ThreadLocalDataSym");
+
+ 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) {
+ DictScope S(W, "UDT");
+ printTypeIndex("Type", UDT.Type);
+ W.printString("UDTName", UDT.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
+ DictScope S(W, "UnknownSym");
+ W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames());
+ 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, PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ return Visitor.visitSymbolRecord(Record);
+}
+
+Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ return Visitor.visitSymbolStream(Symbols);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
new file mode 100644
index 000000000000..ea46841a70f6
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
@@ -0,0 +1,465 @@
+//===- SymbolRecordMapping.cpp -----------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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.mapInteger(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.mapInteger(Public.Index));
+ 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.mapInteger(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();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
new file mode 100644
index 000000000000..9f2d619d1a1c
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolSerializer.cpp
@@ -0,0 +1,54 @@
+//===- SymbolSerializer.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
+ CodeViewContainer Container)
+ : Storage(Allocator), RecordBuffer(MaxRecordLength),
+ Stream(RecordBuffer, llvm::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/lib/DebugInfo/CodeView/TypeDatabase.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
new file mode 100644
index 000000000000..af05d2dc294b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
@@ -0,0 +1,213 @@
+//===- TypeDatabase.cpp --------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeDatabase.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},
+};
+
+TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) {
+ CVUDTNames.resize(Capacity);
+ TypeRecords.resize(Capacity);
+ ValidRecords.resize(Capacity);
+}
+
+TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) {
+ LargestTypeIndex = getAppendIndex();
+ if (LargestTypeIndex.toArrayIndex() >= capacity())
+ grow();
+ recordType(Name, LargestTypeIndex, Data);
+ return LargestTypeIndex;
+}
+
+void TypeDatabase::recordType(StringRef Name, TypeIndex Index,
+ const CVType &Data) {
+ LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex);
+
+ if (LargestTypeIndex.toArrayIndex() >= capacity())
+ grow(Index);
+
+ uint32_t AI = Index.toArrayIndex();
+
+ assert(!contains(Index));
+ assert(AI < capacity());
+
+ CVUDTNames[AI] = Name;
+ TypeRecords[AI] = Data;
+ ValidRecords.set(AI);
+ ++Count;
+}
+
+/// Saves the name in a StringSet and creates a stable StringRef.
+StringRef TypeDatabase::saveTypeName(StringRef TypeName) {
+ return TypeNameStorage.save(TypeName);
+}
+
+StringRef TypeDatabase::getTypeName(TypeIndex Index) const {
+ if (Index.isNoneType())
+ return "<no type>";
+
+ if (Index.isSimple()) {
+ // This is a simple type.
+ for (const auto &SimpleTypeName : SimpleTypeNames) {
+ if (SimpleTypeName.Kind == Index.getSimpleKind()) {
+ if (Index.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>";
+ }
+
+ if (contains(Index))
+ return CVUDTNames[Index.toArrayIndex()];
+
+ return "<unknown UDT>";
+}
+
+const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const {
+ assert(contains(Index));
+ return TypeRecords[Index.toArrayIndex()];
+}
+
+CVType &TypeDatabase::getTypeRecord(TypeIndex Index) {
+ assert(contains(Index));
+ return TypeRecords[Index.toArrayIndex()];
+}
+
+bool TypeDatabase::contains(TypeIndex Index) const {
+ uint32_t AI = Index.toArrayIndex();
+ if (AI >= capacity())
+ return false;
+
+ return ValidRecords.test(AI);
+}
+
+uint32_t TypeDatabase::size() const { return Count; }
+
+uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); }
+
+CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); }
+
+StringRef TypeDatabase::getTypeName(TypeIndex Index) {
+ return static_cast<const TypeDatabase *>(this)->getTypeName(Index);
+}
+
+bool TypeDatabase::contains(TypeIndex Index) {
+ return static_cast<const TypeDatabase *>(this)->contains(Index);
+}
+
+uint32_t TypeDatabase::size() {
+ return static_cast<const TypeDatabase *>(this)->size();
+}
+
+uint32_t TypeDatabase::capacity() {
+ return static_cast<const TypeDatabase *>(this)->capacity();
+}
+
+void TypeDatabase::grow() { grow(LargestTypeIndex + 1); }
+
+void TypeDatabase::grow(TypeIndex NewIndex) {
+ uint32_t NewSize = NewIndex.toArrayIndex() + 1;
+
+ if (NewSize <= capacity())
+ return;
+
+ uint32_t NewCapacity = NewSize * 3 / 2;
+
+ TypeRecords.resize(NewCapacity);
+ CVUDTNames.resize(NewCapacity);
+ ValidRecords.resize(NewCapacity);
+}
+
+bool TypeDatabase::empty() const { return size() == 0; }
+
+Optional<TypeIndex> TypeDatabase::largestTypeIndexLessThan(TypeIndex TI) const {
+ uint32_t AI = TI.toArrayIndex();
+ int N = ValidRecords.find_prev(AI);
+ if (N == -1)
+ return None;
+ return TypeIndex::fromArrayIndex(N);
+}
+
+TypeIndex TypeDatabase::getAppendIndex() const {
+ if (empty())
+ return TypeIndex::fromArrayIndex(0);
+
+ return LargestTypeIndex + 1;
+}
+
+Optional<TypeIndex> TypeDatabase::getFirst() {
+ int N = ValidRecords.find_first();
+ if (N == -1)
+ return None;
+ return TypeIndex::fromArrayIndex(N);
+}
+
+Optional<TypeIndex> TypeDatabase::getNext(TypeIndex Prev) {
+ int N = ValidRecords.find_next(Prev.toArrayIndex());
+ if (N == -1)
+ return None;
+ return TypeIndex::fromArrayIndex(N);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp
new file mode 100644
index 000000000000..8d97f8b1cb40
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp
@@ -0,0 +1,330 @@
+//===- TypeDatabaseVisitor.cpp -------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+
+#include "llvm/ADT/SmallString.h"
+
+using namespace llvm;
+
+using namespace llvm::codeview;
+
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record) {
+ assert(!IsInFieldList);
+ // Reset Name to the empty string. If the visitor sets it, we know it.
+ Name = "";
+
+ if (Record.Type == LF_FIELDLIST) {
+ // Record that we're in a field list so that members do not get assigned
+ // type indices.
+ IsInFieldList = true;
+ }
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ if (auto EC = visitTypeBegin(Record))
+ return EC;
+
+ CurrentTypeIndex = Index;
+ return Error::success();
+}
+
+StringRef TypeDatabaseVisitor::getTypeName(TypeIndex Index) const {
+ return TypeDB->getTypeName(Index);
+}
+
+StringRef TypeDatabaseVisitor::saveTypeName(StringRef Name) {
+ return TypeDB->saveTypeName(Name);
+}
+
+Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) {
+ if (CVR.Type == LF_FIELDLIST) {
+ assert(IsInFieldList);
+ IsInFieldList = false;
+ }
+ assert(!IsInFieldList);
+
+ // Record every type that is not a field list member, even if Name is empty.
+ // CVUDTNames is indexed by type index, and must have one entry for every
+ // type. Field list members are not recorded, and are only referenced by
+ // their containing field list record.
+ if (CurrentTypeIndex)
+ TypeDB->recordType(Name, *CurrentTypeIndex, CVR);
+ else
+ TypeDB->appendType(Name, CVR);
+
+ CurrentTypeIndex.reset();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ assert(IsInFieldList);
+ // Reset Name to the empty string. If the visitor sets it, we know it.
+ Name = "";
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ assert(IsInFieldList);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ Name = "<field list>";
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
+ StringIdRecord &String) {
+ // Put this in the database so it gets printed with LF_UDT_SRC_LINE.
+ Name = String.getString();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ SmallString<256> TypeName("(");
+ for (uint32_t I = 0; I < Size; ++I) {
+ StringRef ArgTypeName = getTypeName(Indices[I]);
+ TypeName.append(ArgTypeName);
+ if (I + 1 != Size)
+ TypeName.append(", ");
+ }
+ TypeName.push_back(')');
+ Name = saveTypeName(TypeName);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ StringListRecord &Strings) {
+ auto Indices = Strings.getIndices();
+ uint32_t Size = Indices.size();
+ SmallString<256> TypeName("\"");
+ for (uint32_t I = 0; I < Size; ++I) {
+ StringRef ArgTypeName = getTypeName(Indices[I]);
+ TypeName.append(ArgTypeName);
+ if (I + 1 != Size)
+ TypeName.append("\" \"");
+ }
+ TypeName.push_back('\"');
+ Name = saveTypeName(TypeName);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
+ Name = Class.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
+ Name = Union.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ Name = AT.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
+ Name = VFT.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Id) {
+ Name = Id.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Proc) {
+ StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
+ StringRef ArgListTypeName = getTypeName(Proc.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ArgListTypeName);
+ Name = saveTypeName(TypeName);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &MF) {
+ StringRef ReturnTypeName = getTypeName(MF.getReturnType());
+ StringRef ClassTypeName = getTypeName(MF.getClassType());
+ StringRef ArgListTypeName = getTypeName(MF.getArgumentList());
+ SmallString<256> TypeName(ReturnTypeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassTypeName);
+ TypeName.append("::");
+ TypeName.append(ArgListTypeName);
+ Name = saveTypeName(TypeName);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
+ Name = Func.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &TS) {
+ Name = TS.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ StringRef PointeeName = getTypeName(Ptr.getReferentType());
+ StringRef ClassName = getTypeName(MI.getContainingType());
+ SmallString<256> TypeName(PointeeName);
+ TypeName.push_back(' ');
+ TypeName.append(ClassName);
+ TypeName.append("::*");
+ Name = saveTypeName(TypeName);
+ } else {
+ SmallString<256> TypeName;
+ if (Ptr.isConst())
+ TypeName.append("const ");
+ if (Ptr.isVolatile())
+ TypeName.append("volatile ");
+ if (Ptr.isUnaligned())
+ TypeName.append("__unaligned ");
+
+ TypeName.append(getTypeName(Ptr.getReferentType()));
+
+ if (Ptr.getMode() == PointerMode::LValueReference)
+ TypeName.append("&");
+ else if (Ptr.getMode() == PointerMode::RValueReference)
+ TypeName.append("&&");
+ else if (Ptr.getMode() == PointerMode::Pointer)
+ TypeName.append("*");
+
+ if (!TypeName.empty())
+ Name = saveTypeName(TypeName);
+ }
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+
+ StringRef ModifiedName = getTypeName(Mod.getModifiedType());
+ SmallString<256> TypeName;
+ if (Mods & uint16_t(ModifierOptions::Const))
+ TypeName.append("const ");
+ if (Mods & uint16_t(ModifierOptions::Volatile))
+ TypeName.append("volatile ");
+ if (Mods & uint16_t(ModifierOptions::Unaligned))
+ TypeName.append("__unaligned ");
+ TypeName.append(ModifiedName);
+ Name = saveTypeName(TypeName);
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ Name =
+ saveTypeName("<vftable " + utostr(Shape.getEntryCount()) + " methods>");
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ Name = Nested.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ Name = Method.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ Name = Field.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &VBase) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(
+ CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &SourceLine) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(
+ CVType &CVR, MethodOverloadListRecord &Overloads) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
+ return Error::success();
+}
+
+Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFP) {
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
new file mode 100644
index 000000000000..04b0384d8190
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -0,0 +1,557 @@
+//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+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.Type);
+ W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")";
+ W->getOStream() << " {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.Type),
+ 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}", fmt_guid(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->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
+ 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("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();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp
new file mode 100644
index 000000000000..20ba6470cd5b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndex.cpp
@@ -0,0 +1,27 @@
+//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+ TypeIndex TI, TypeCollection &Types) {
+ StringRef TypeName;
+ if (!TI.isNoneType())
+ TypeName = Types.getTypeName(TI);
+ if (!TypeName.empty())
+ Printer.printHex(FieldName, TypeName, TI.getIndex());
+ else
+ Printer.printHex(FieldName, TI.getIndex());
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
new file mode 100644
index 000000000000..11e2e215303c
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -0,0 +1,371 @@
+//===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/DebugInfo/CodeView/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::PointerToDataMember;
+}
+
+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 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;
+ }
+}
+
+void llvm::codeview::discoverTypeIndices(const CVType &Type,
+ SmallVectorImpl<TiReference> &Refs) {
+ ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
+}
+
+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);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
new file mode 100644
index 000000000000..114f6fd2897e
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -0,0 +1,481 @@
+//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/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));
+ if (IsFromOverloadList) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding));
+ }
+ error(IO.mapInteger(Method.Type));
+ if (Method.isIntroducingVirtual()) {
+ error(IO.mapInteger(Method.VFTableOffset));
+ } else if (!IO.isWriting())
+ Method.VFTableOffset = -1;
+
+ if (!IsFromOverloadList)
+ error(IO.mapStringZ(Method.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 {
+ error(IO.mapStringZ(Name));
+ if (HasUniqueName)
+ error(IO.mapStringZ(UniqueName));
+ }
+
+ 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.Type != TypeLeafKind::LF_FIELDLIST &&
+ CVR.Type != TypeLeafKind::LF_METHODLIST)
+ MaxLen = MaxRecordLength - sizeof(RecordPrefix);
+ error(IO.beginRecord(MaxLen));
+ TypeKind = CVR.Type;
+ return Error::success();
+}
+
+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.isWriting()) {
+ 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));
+ error(IO.mapEnum(Record.Modifiers));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Record) {
+ error(IO.mapInteger(Record.ReturnType));
+ error(IO.mapEnum(Record.CallConv));
+ error(IO.mapEnum(Record.Options));
+ error(IO.mapInteger(Record.ParameterCount));
+ error(IO.mapInteger(Record.ArgumentList));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &Record) {
+ error(IO.mapInteger(Record.ReturnType));
+ error(IO.mapInteger(Record.ClassType));
+ error(IO.mapInteger(Record.ThisType));
+ error(IO.mapEnum(Record.CallConv));
+ error(IO.mapEnum(Record.Options));
+ error(IO.mapInteger(Record.ParameterCount));
+ error(IO.mapInteger(Record.ArgumentList));
+ error(IO.mapInteger(Record.ThisPointerAdjustment));
+
+ 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); }));
+
+ 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); }));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
+ error(IO.mapInteger(Record.ReferentType));
+ error(IO.mapInteger(Record.Attrs));
+
+ if (Record.isPointerToMember()) {
+ if (!IO.isWriting())
+ Record.MemberInfo.emplace();
+
+ MemberPointerInfo &M = *Record.MemberInfo;
+ error(IO.mapInteger(M.ContainingType));
+ error(IO.mapEnum(M.Representation));
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
+ error(IO.mapInteger(Record.ElementType));
+ error(IO.mapInteger(Record.IndexType));
+ error(IO.mapEncodedInteger(Record.Size));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
+ assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) ||
+ (CVR.Type == TypeLeafKind::LF_CLASS) ||
+ (CVR.Type == TypeLeafKind::LF_INTERFACE));
+
+ error(IO.mapInteger(Record.MemberCount));
+ error(IO.mapEnum(Record.Options));
+ error(IO.mapInteger(Record.FieldList));
+ error(IO.mapInteger(Record.DerivationList));
+ error(IO.mapInteger(Record.VTableShape));
+ error(IO.mapEncodedInteger(Record.Size));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
+ error(IO.mapInteger(Record.MemberCount));
+ error(IO.mapEnum(Record.Options));
+ error(IO.mapInteger(Record.FieldList));
+ error(IO.mapEncodedInteger(Record.Size));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
+ error(IO.mapInteger(Record.MemberCount));
+ error(IO.mapEnum(Record.Options));
+ error(IO.mapInteger(Record.UnderlyingType));
+ error(IO.mapInteger(Record.FieldList));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
+ error(IO.mapInteger(Record.Type));
+ error(IO.mapInteger(Record.BitSize));
+ error(IO.mapInteger(Record.BitOffset));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Record) {
+ uint16_t Size;
+ if (IO.isWriting()) {
+ ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
+ Size = Slots.size();
+ error(IO.mapInteger(Size));
+
+ 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));
+ error(IO.mapInteger(Record.OverriddenVFTable));
+ error(IO.mapInteger(Record.VFPtrOffset));
+ uint32_t NamesLen = 0;
+ if (IO.isWriting()) {
+ 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); }));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
+ error(IO.mapInteger(Record.Id));
+ error(IO.mapStringZ(Record.String));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT));
+ error(IO.mapInteger(Record.SourceFile));
+ error(IO.mapInteger(Record.LineNumber));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT));
+ error(IO.mapInteger(Record.SourceFile));
+ error(IO.mapInteger(Record.LineNumber));
+ error(IO.mapInteger(Record.Module));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ParentScope));
+ error(IO.mapInteger(Record.FunctionType));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ClassType));
+ error(IO.mapInteger(Record.FunctionType));
+ error(IO.mapStringZ(Record.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); }));
+
+ 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)));
+
+ 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));
+ error(IO.mapInteger(Record.Age));
+ error(IO.mapStringZ(Record.Name));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
+ error(IO.mapEnum(Record.Mode));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Record) {
+ error(IO.mapInteger(Record.Attrs.Attrs));
+ error(IO.mapInteger(Record.Type));
+ error(IO.mapEncodedInteger(Record.Offset));
+
+ 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));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Record) {
+ error(IO.mapInteger(Record.Attrs.Attrs));
+ error(IO.mapInteger(Record.Type));
+ error(IO.mapEncodedInteger(Record.FieldOffset));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Record) {
+ error(IO.mapInteger(Record.NumOverloads));
+ error(IO.mapInteger(Record.MethodList));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Record) {
+ MapOneMethodRecord Mapper(false);
+ return Mapper(IO, Record);
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(Record.Type));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Record) {
+
+ error(IO.mapInteger(Record.Attrs.Attrs));
+ error(IO.mapInteger(Record.Type));
+ error(IO.mapStringZ(Record.Name));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Record) {
+
+ error(IO.mapInteger(Record.Attrs.Attrs));
+ error(IO.mapInteger(Record.BaseType));
+ error(IO.mapInteger(Record.VBPtrType));
+ error(IO.mapEncodedInteger(Record.VBPtrOffset));
+ error(IO.mapEncodedInteger(Record.VTableIndex));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(Record.Type));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(Record.ContinuationIndex));
+
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp
new file mode 100644
index 000000000000..93c1198e36ce
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp
@@ -0,0 +1,371 @@
+//===- TypeSerialzier.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+#include <string.h>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+struct HashedType {
+ uint64_t Hash;
+ const uint8_t *Data;
+ unsigned Size; // FIXME: Go to uint16_t?
+ TypeIndex Index;
+};
+
+/// Wrapper around a poitner to a HashedType. Hash and equality operations are
+/// based on data in the pointee.
+struct HashedTypePtr {
+ HashedTypePtr() = default;
+ HashedTypePtr(HashedType *Ptr) : Ptr(Ptr) {}
+ HashedType *Ptr = nullptr;
+};
+} // namespace
+
+namespace llvm {
+template <> struct DenseMapInfo<HashedTypePtr> {
+ static inline HashedTypePtr getEmptyKey() { return HashedTypePtr(nullptr); }
+ static inline HashedTypePtr getTombstoneKey() {
+ return HashedTypePtr(reinterpret_cast<HashedType *>(1));
+ }
+ static unsigned getHashValue(HashedTypePtr Val) {
+ assert(Val.Ptr != getEmptyKey().Ptr && Val.Ptr != getTombstoneKey().Ptr);
+ return Val.Ptr->Hash;
+ }
+ static bool isEqual(HashedTypePtr LHSP, HashedTypePtr RHSP) {
+ HashedType *LHS = LHSP.Ptr;
+ HashedType *RHS = RHSP.Ptr;
+ if (RHS == getEmptyKey().Ptr || RHS == getTombstoneKey().Ptr)
+ return LHS == RHS;
+ if (LHS->Hash != RHS->Hash || LHS->Size != RHS->Size)
+ return false;
+ return ::memcmp(LHS->Data, RHS->Data, LHS->Size) == 0;
+ }
+};
+}
+
+/// Private implementation so that we don't leak our DenseMap instantiations to
+/// users.
+class llvm::codeview::TypeHasher {
+private:
+ /// Storage for type record provided by the caller. Records will outlive the
+ /// hasher object, so they should be allocated here.
+ BumpPtrAllocator &RecordStorage;
+
+ /// Storage for hash keys. These only need to live as long as the hashing
+ /// operation.
+ BumpPtrAllocator KeyStorage;
+
+ /// Hash table. We really want a DenseMap<ArrayRef<uint8_t>, TypeIndex> here,
+ /// but DenseMap is inefficient when the keys are long (like type records)
+ /// because it recomputes the hash value of every key when it grows. This
+ /// value type stores the hash out of line in KeyStorage, so that table
+ /// entries are small and easy to rehash.
+ DenseSet<HashedTypePtr> HashedRecords;
+
+public:
+ TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {}
+
+ void reset() { HashedRecords.clear(); }
+
+ /// Takes the bytes of type record, inserts them into the hash table, saves
+ /// them, and returns a pointer to an identical stable type record along with
+ /// its type index in the destination stream.
+ TypeIndex getOrCreateRecord(ArrayRef<uint8_t> &Record, TypeIndex TI);
+};
+
+TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record,
+ TypeIndex TI) {
+ assert(Record.size() < UINT32_MAX && "Record too big");
+ assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
+
+ // Compute the hash up front so we can store it in the key.
+ HashedType TempHashedType = {hash_value(Record), Record.data(),
+ unsigned(Record.size()), TI};
+ auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType));
+ HashedType *&Hashed = Result.first->Ptr;
+
+ if (Result.second) {
+ // This was a new type record. We need stable storage for both the key and
+ // the record. The record should outlive the hashing operation.
+ Hashed = KeyStorage.Allocate<HashedType>();
+ *Hashed = TempHashedType;
+
+ uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
+ memcpy(Stable, Record.data(), Record.size());
+ Hashed->Data = Stable;
+ assert(Hashed->Size == Record.size());
+ }
+
+ // Update the caller's copy of Record to point a stable copy.
+ Record = ArrayRef<uint8_t>(Hashed->Data, Hashed->Size);
+ return Hashed->Index;
+}
+
+TypeIndex TypeSerializer::nextTypeIndex() const {
+ return TypeIndex::fromArrayIndex(SeenRecords.size());
+}
+
+bool TypeSerializer::isInFieldList() const {
+ return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
+ assert(isInFieldList());
+ return getCurrentRecordData().drop_front(CurrentSegment.length());
+}
+
+MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
+ return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
+}
+
+Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
+ RecordPrefix Prefix;
+ Prefix.RecordKind = Kind;
+ Prefix.RecordLen = 0;
+ if (auto EC = Writer.writeObject(Prefix))
+ return EC;
+ return Error::success();
+}
+
+Expected<MutableArrayRef<uint8_t>>
+TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
+ uint32_t Align = Record.size() % 4;
+ if (Align == 0)
+ return Record;
+
+ int PaddingBytes = 4 - Align;
+ int N = PaddingBytes;
+ while (PaddingBytes > 0) {
+ uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ if (auto EC = Writer.writeInteger(Pad))
+ return std::move(EC);
+ --PaddingBytes;
+ }
+ return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
+}
+
+TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash)
+ : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2),
+ Stream(RecordBuffer, llvm::support::little), Writer(Stream),
+ Mapping(Writer) {
+ // RecordBuffer needs to be able to hold enough data so that if we are 1
+ // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
+ // we won't overflow.
+ if (Hash)
+ Hasher = make_unique<TypeHasher>(Storage);
+}
+
+TypeSerializer::~TypeSerializer() = default;
+
+ArrayRef<ArrayRef<uint8_t>> TypeSerializer::records() const {
+ return SeenRecords;
+}
+
+void TypeSerializer::reset() {
+ if (Hasher)
+ Hasher->reset();
+ Writer.setOffset(0);
+ CurrentSegment = RecordSegment();
+ FieldListSegments.clear();
+ TypeKind.reset();
+ MemberKind.reset();
+ SeenRecords.clear();
+}
+
+TypeIndex TypeSerializer::insertRecordBytes(ArrayRef<uint8_t> &Record) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+ if (Hasher) {
+ TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex());
+ if (nextTypeIndex() == ActualTI)
+ SeenRecords.push_back(Record);
+ return ActualTI;
+ }
+
+ TypeIndex NewTI = nextTypeIndex();
+ uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
+ memcpy(Stable, Record.data(), Record.size());
+ Record = ArrayRef<uint8_t>(Stable, Record.size());
+ SeenRecords.push_back(Record);
+ return NewTI;
+}
+
+TypeIndex TypeSerializer::insertRecord(const RemappedType &Record) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+ TypeIndex TI;
+ ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData;
+ if (Record.Mappings.empty()) {
+ // This record did not remap any type indices. Just write it.
+ return insertRecordBytes(OriginalData);
+ }
+
+ // At least one type index was remapped. Before we can hash it we have to
+ // copy the full record bytes, re-write each type index, then hash the copy.
+ // We do this in temporary storage since only the DenseMap can decide whether
+ // this record already exists, and if it does we don't want the memory to
+ // stick around.
+ RemapStorage.resize(OriginalData.size());
+ ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size());
+ uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix);
+ for (const auto &M : Record.Mappings) {
+ // First 4 bytes of every record are the record prefix, but the mapping
+ // offset is relative to the content which starts after.
+ *(TypeIndex *)(ContentBegin + M.first) = M.second;
+ }
+ auto RemapRef = makeArrayRef(RemapStorage);
+ return insertRecordBytes(RemapRef);
+}
+
+Error TypeSerializer::visitTypeBegin(CVType &Record) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(Writer.getOffset() == 0 && "Stream has data already!");
+
+ if (auto EC = writeRecordPrefix(Record.kind()))
+ return EC;
+
+ TypeKind = Record.kind();
+ if (auto EC = Mapping.visitTypeBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ if (auto EC = Mapping.visitTypeEnd(Record))
+ return std::move(EC);
+
+ // Update the record's length and fill out the CVType members to point to
+ // the stable memory holding the record's data.
+ auto ThisRecordData = getCurrentRecordData();
+ auto ExpectedData = addPadding(ThisRecordData);
+ if (!ExpectedData)
+ return ExpectedData.takeError();
+ ThisRecordData = *ExpectedData;
+
+ RecordPrefix *Prefix =
+ reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
+ Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
+
+ Record.Type = *TypeKind;
+ Record.RecordData = ThisRecordData;
+
+ // insertRecordBytes assumes we're not in a mapping, so do this first.
+ TypeKind.reset();
+ Writer.setOffset(0);
+
+ TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData);
+
+ // Write out each additional segment in reverse order, and update each
+ // record's continuation index to point to the previous one.
+ for (auto X : reverse(FieldListSegments)) {
+ auto CIBytes = X.take_back(sizeof(uint32_t));
+ support::ulittle32_t *CI =
+ reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
+ assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
+ *CI = InsertedTypeIndex.getIndex();
+ InsertedTypeIndex = insertRecordBytes(X);
+ }
+
+ FieldListSegments.clear();
+ CurrentSegment.SubRecords.clear();
+
+ return InsertedTypeIndex;
+}
+
+Error TypeSerializer::visitTypeEnd(CVType &Record) {
+ auto ExpectedIndex = visitTypeEndGetIndex(Record);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ return Error::success();
+}
+
+Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
+ assert(isInFieldList() && "Not in a field list!");
+ assert(!MemberKind.hasValue() && "Already in a member record!");
+ MemberKind = Record.Kind;
+
+ if (auto EC = Mapping.visitMemberBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
+ if (auto EC = Mapping.visitMemberEnd(Record))
+ return EC;
+
+ // Check if this subrecord makes the current segment not fit in 64K minus
+ // the space for a continuation record (8 bytes). If the segment does not
+ // fit, insert a continuation record.
+ if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
+ MutableArrayRef<uint8_t> Data = getCurrentRecordData();
+ SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
+ uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
+ auto CopyData = Data.take_front(CopySize);
+ auto LeftOverData = Data.drop_front(CopySize);
+ assert(LastSubRecord.Size == LeftOverData.size());
+
+ // Allocate stable storage for the record and copy the old record plus
+ // continuation over.
+ uint16_t LengthWithSize = CopySize + ContinuationLength;
+ assert(LengthWithSize <= MaxRecordLength);
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
+ Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
+
+ uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
+ auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
+ MutableBinaryByteStream CS(SavedSegment, llvm::support::little);
+ BinaryStreamWriter CW(CS);
+ if (auto EC = CW.writeBytes(CopyData))
+ return EC;
+ if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
+ return EC;
+ if (auto EC = CW.writeInteger<uint16_t>(0))
+ return EC;
+ if (auto EC = CW.writeInteger<uint32_t>(0xB0C0B0C0))
+ return EC;
+ FieldListSegments.push_back(SavedSegment);
+
+ // Write a new placeholder record prefix to mark the start of this new
+ // top-level record.
+ Writer.setOffset(0);
+ if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
+ return EC;
+
+ // Then move over the subrecord that overflowed the old segment to the
+ // beginning of this segment. Note that we have to use memmove here
+ // instead of Writer.writeBytes(), because the new and old locations
+ // could overlap.
+ ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
+ LeftOverData.size());
+ // And point the segment writer at the end of that subrecord.
+ Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
+
+ CurrentSegment.SubRecords.clear();
+ CurrentSegment.SubRecords.push_back(LastSubRecord);
+ }
+
+ // Update the CVMemberRecord since we may have shifted around or gotten
+ // padded.
+ Record.Data = getCurrentSubRecordData();
+
+ MemberKind.reset();
+ return Error::success();
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
new file mode 100644
index 000000000000..71a0966df036
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -0,0 +1,350 @@
+//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.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/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+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 TypeVisitorCallbacks {
+public:
+ explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest,
+ TypeServerHandler *Handler)
+ : Handler(Handler), IndexMap(SourceToDest) {
+ SourceToDest.clear();
+ }
+
+ static const TypeIndex Untranslated;
+
+ Error visitTypeBegin(CVType &Record) override;
+ Error visitTypeEnd(CVType &Record) override;
+
+ Error mergeTypesAndIds(TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
+ const CVTypeArray &IdsAndTypes);
+ Error mergeIdRecords(TypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ const CVTypeArray &Ids);
+ Error mergeTypeRecords(TypeTableBuilder &Dest, const CVTypeArray &Types);
+
+private:
+ Error doit(const CVTypeArray &Types);
+
+ void addMapping(TypeIndex Idx);
+
+ bool remapTypeIndex(TypeIndex &Idx);
+ bool remapItemIndex(TypeIndex &Idx);
+
+ bool remapIndices(RemappedType &Record, ArrayRef<TiReference> Refs) {
+ auto OriginalData = Record.OriginalRecord.content();
+ bool Success = true;
+ for (auto &Ref : Refs) {
+ uint32_t Offset = Ref.Offset;
+ ArrayRef<uint8_t> Bytes =
+ OriginalData.slice(Ref.Offset, sizeof(TypeIndex));
+ ArrayRef<TypeIndex> TIs(reinterpret_cast<const TypeIndex *>(Bytes.data()),
+ Ref.Count);
+ for (auto TI : TIs) {
+ TypeIndex NewTI = TI;
+ bool ThisSuccess = (Ref.Kind == TiRefKind::IndexRef)
+ ? remapItemIndex(NewTI)
+ : remapTypeIndex(NewTI);
+ if (ThisSuccess && NewTI != TI)
+ Record.Mappings.emplace_back(Offset, NewTI);
+ Offset += sizeof(TypeIndex);
+ Success &= ThisSuccess;
+ }
+ }
+ return Success;
+ }
+
+ bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map);
+
+ size_t slotForIndex(TypeIndex Idx) const {
+ assert(!Idx.isSimple() && "simple type indices have no slots");
+ return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
+ }
+
+ Error errorCorruptRecord() const {
+ return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+ }
+
+ Error writeRecord(TypeTableBuilder &Dest, const RemappedType &Record,
+ bool RemapSuccess) {
+ TypeIndex DestIdx = Untranslated;
+ if (RemapSuccess)
+ DestIdx = Dest.writeSerializedRecord(Record);
+ addMapping(DestIdx);
+ return Error::success();
+ }
+
+ Error writeTypeRecord(const CVType &Record) {
+ TypeIndex DestIdx =
+ DestTypeStream->writeSerializedRecord(Record.RecordData);
+ addMapping(DestIdx);
+ return Error::success();
+ }
+
+ Error writeTypeRecord(const RemappedType &Record, bool RemapSuccess) {
+ return writeRecord(*DestTypeStream, Record, RemapSuccess);
+ }
+
+ Error writeIdRecord(const RemappedType &Record, bool RemapSuccess) {
+ return writeRecord(*DestIdStream, Record, RemapSuccess);
+ }
+
+ Optional<Error> LastError;
+
+ bool IsSecondPass = false;
+
+ unsigned NumBadIndices = 0;
+
+ TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
+
+ TypeTableBuilder *DestIdStream = nullptr;
+ TypeTableBuilder *DestTypeStream = nullptr;
+ TypeServerHandler *Handler = nullptr;
+
+ // 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;
+};
+
+} // end anonymous namespace
+
+const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
+
+Error TypeStreamMerger::visitTypeBegin(CVType &Rec) {
+ RemappedType R(Rec);
+ SmallVector<TiReference, 32> Refs;
+ discoverTypeIndices(Rec.RecordData, Refs);
+ bool Success = remapIndices(R, Refs);
+ switch (Rec.kind()) {
+ 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 writeIdRecord(R, Success);
+ default:
+ return writeTypeRecord(R, Success);
+ }
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitTypeEnd(CVType &Rec) {
+ ++CurIndex;
+ if (!IsSecondPass)
+ assert(IndexMap.size() == slotForIndex(CurIndex) &&
+ "visitKnownRecord should add one index map entry");
+ return Error::success();
+}
+
+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::remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) {
+ // 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 (MapPos < Map.size() && Map[MapPos] != Untranslated) {
+ Idx = Map[MapPos];
+ return true;
+ }
+
+ // 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.
+ LastError = joinErrors(std::move(*LastError), errorCorruptRecord());
+ }
+
+ ++NumBadIndices;
+
+ // This type index is invalid. Remap this to "not translated by cvpack",
+ // and return failure.
+ Idx = Untranslated;
+ return false;
+}
+
+bool TypeStreamMerger::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 (DestTypeStream == nullptr)
+ return remapIndex(Idx, TypeLookup);
+
+ assert(TypeLookup.empty());
+ return remapIndex(Idx, IndexMap);
+}
+
+bool TypeStreamMerger::remapItemIndex(TypeIndex &Idx) {
+ assert(DestIdStream);
+ return remapIndex(Idx, IndexMap);
+}
+
+Error TypeStreamMerger::mergeTypeRecords(TypeTableBuilder &Dest,
+ const CVTypeArray &Types) {
+ DestTypeStream = &Dest;
+
+ return doit(Types);
+}
+
+Error TypeStreamMerger::mergeIdRecords(TypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ const CVTypeArray &Ids) {
+ DestIdStream = &Dest;
+ TypeLookup = TypeSourceToDest;
+
+ return doit(Ids);
+}
+
+Error TypeStreamMerger::mergeTypesAndIds(TypeTableBuilder &DestIds,
+ TypeTableBuilder &DestTypes,
+ const CVTypeArray &IdsAndTypes) {
+ DestIdStream = &DestIds;
+ DestTypeStream = &DestTypes;
+
+ return doit(IdsAndTypes);
+}
+
+Error TypeStreamMerger::doit(const CVTypeArray &Types) {
+ LastError = Error::success();
+
+ // We don't want to deserialize records. I guess this flag is poorly named,
+ // but it really means "Don't deserialize records before switching on the
+ // concrete type.
+ // FIXME: We can probably get even more speed here if we don't use the visitor
+ // pipeline here, but instead write the switch ourselves. I don't think it
+ // would buy us much since it's already pretty fast, but it's probably worth
+ // a few cycles.
+ if (auto EC =
+ codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler))
+ 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 =
+ codeview::visitTypeStream(Types, *this, VDS_BytesExternal, Handler))
+ 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");
+ }
+ }
+
+ Error Ret = std::move(*LastError);
+ LastError.reset();
+ return Ret;
+}
+
+Error llvm::codeview::mergeTypeRecords(TypeTableBuilder &Dest,
+ SmallVectorImpl<TypeIndex> &SourceToDest,
+ TypeServerHandler *Handler,
+ const CVTypeArray &Types) {
+ TypeStreamMerger M(SourceToDest, Handler);
+ return M.mergeTypeRecords(Dest, Types);
+}
+
+Error llvm::codeview::mergeIdRecords(TypeTableBuilder &Dest,
+ ArrayRef<TypeIndex> TypeSourceToDest,
+ SmallVectorImpl<TypeIndex> &SourceToDest,
+ const CVTypeArray &Ids) {
+ TypeStreamMerger M(SourceToDest, nullptr);
+ return M.mergeIdRecords(Dest, TypeSourceToDest, Ids);
+}
+
+Error llvm::codeview::mergeTypeAndIdRecords(
+ TypeTableBuilder &DestIds, TypeTableBuilder &DestTypes,
+ SmallVectorImpl<TypeIndex> &SourceToDest, TypeServerHandler *Handler,
+ const CVTypeArray &IdsAndTypes) {
+
+ TypeStreamMerger M(SourceToDest, Handler);
+ return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes);
+}
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp
new file mode 100644
index 000000000000..8d974d522f28
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp
@@ -0,0 +1,83 @@
+//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void error(Error &&EC) {
+ assert(!static_cast<bool>(EC));
+ if (EC)
+ consumeError(std::move(EC));
+}
+
+TypeTableCollection::TypeTableCollection(ArrayRef<ArrayRef<uint8_t>> Records)
+ : Records(Records), Database(Records.size()) {}
+
+Optional<TypeIndex> TypeTableCollection::getFirst() {
+ if (empty())
+ return None;
+ return TypeIndex::fromArrayIndex(0);
+}
+
+Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) {
+ ++Prev;
+ assert(Prev.toArrayIndex() <= size());
+ if (Prev.toArrayIndex() == size())
+ return None;
+ return Prev;
+}
+
+void TypeTableCollection::ensureTypeExists(TypeIndex Index) {
+ assert(hasCapacityFor(Index));
+
+ if (Database.contains(Index))
+ return;
+
+ BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little);
+
+ CVType Type;
+ uint32_t Len;
+ VarStreamArrayExtractor<CVType> Extract;
+ error(Extract(Bytes, Len, Type));
+
+ TypeDatabaseVisitor DBV(Database);
+ error(codeview::visitTypeRecord(Type, Index, DBV));
+ assert(Database.contains(Index));
+}
+
+CVType TypeTableCollection::getType(TypeIndex Index) {
+ ensureTypeExists(Index);
+ return Database.getTypeRecord(Index);
+}
+
+StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
+ if (!Index.isSimple())
+ ensureTypeExists(Index);
+ return Database.getTypeName(Index);
+}
+
+bool TypeTableCollection::contains(TypeIndex Index) {
+ return Database.contains(Index);
+}
+
+uint32_t TypeTableCollection::size() { return Records.size(); }
+
+uint32_t TypeTableCollection::capacity() { return Records.size(); }
+
+bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const {
+ return Index.toArrayIndex() < Records.size();
+}