aboutsummaryrefslogtreecommitdiff
path: root/lib/DebugInfo/CodeView
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/CodeView')
-rw-r--r--lib/DebugInfo/CodeView/CMakeLists.txt3
-rw-r--r--lib/DebugInfo/CodeView/CVSymbolVisitor.cpp11
-rw-r--r--lib/DebugInfo/CodeView/CVTypeDumper.cpp10
-rw-r--r--lib/DebugInfo/CodeView/CVTypeVisitor.cpp77
-rw-r--r--lib/DebugInfo/CodeView/CodeViewError.cpp2
-rw-r--r--lib/DebugInfo/CodeView/CodeViewRecordIO.cpp36
-rw-r--r--lib/DebugInfo/CodeView/Formatters.cpp37
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstream.cpp12
-rw-r--r--lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp36
-rw-r--r--lib/DebugInfo/CodeView/RecordSerialization.cpp22
-rw-r--r--lib/DebugInfo/CodeView/SymbolDumper.cpp4
-rw-r--r--lib/DebugInfo/CodeView/SymbolSerializer.cpp52
-rw-r--r--lib/DebugInfo/CodeView/TypeDatabase.cpp6
-rw-r--r--lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp20
-rw-r--r--lib/DebugInfo/CodeView/TypeDumpVisitor.cpp46
-rw-r--r--lib/DebugInfo/CodeView/TypeRecord.cpp213
-rw-r--r--lib/DebugInfo/CodeView/TypeRecordMapping.cpp26
-rw-r--r--lib/DebugInfo/CodeView/TypeSerializer.cpp13
-rw-r--r--lib/DebugInfo/CodeView/TypeStreamMerger.cpp416
19 files changed, 674 insertions, 368 deletions
diff --git a/lib/DebugInfo/CodeView/CMakeLists.txt b/lib/DebugInfo/CodeView/CMakeLists.txt
index f9bff86b41c8..6e9214d72adc 100644
--- a/lib/DebugInfo/CodeView/CMakeLists.txt
+++ b/lib/DebugInfo/CodeView/CMakeLists.txt
@@ -5,16 +5,17 @@ add_llvm_library(LLVMDebugInfoCodeView
CVTypeDumper.cpp
CVTypeVisitor.cpp
EnumTables.cpp
+ Formatters.cpp
Line.cpp
ModuleSubstream.cpp
ModuleSubstreamVisitor.cpp
RecordSerialization.cpp
SymbolRecordMapping.cpp
SymbolDumper.cpp
+ SymbolSerializer.cpp
TypeDatabase.cpp
TypeDatabaseVisitor.cpp
TypeDumpVisitor.cpp
- TypeRecord.cpp
TypeRecordMapping.cpp
TypeSerializer.cpp
TypeStreamMerger.cpp
diff --git a/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
index 75cfd0dd184e..4c78caf03477 100644
--- a/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
+++ b/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
@@ -11,20 +11,11 @@
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/BinaryByteStream.h"
using namespace llvm;
using namespace llvm::codeview;
-template <typename T>
-static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
- if (Data.size() < sizeof(*Res))
- return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
- Res = reinterpret_cast<const T *>(Data.data());
- Data = Data.drop_front(sizeof(*Res));
- return Error::success();
-}
-
CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
diff --git a/lib/DebugInfo/CodeView/CVTypeDumper.cpp b/lib/DebugInfo/CodeView/CVTypeDumper.cpp
index fcd239cce0dd..bcc8218d9446 100644
--- a/lib/DebugInfo/CodeView/CVTypeDumper.cpp
+++ b/lib/DebugInfo/CodeView/CVTypeDumper.cpp
@@ -14,7 +14,7 @@
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/BinaryByteStream.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -28,6 +28,8 @@ Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
Pipeline.addCallbackToPipeline(Dumper);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
CVType RecordCopy = Record;
if (auto EC = Visitor.visitTypeRecord(RecordCopy))
@@ -45,6 +47,8 @@ Error CVTypeDumper::dump(const CVTypeArray &Types,
Pipeline.addCallbackToPipeline(Dumper);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
if (auto EC = Visitor.visitTypeStream(Types))
return EC;
@@ -52,9 +56,9 @@ Error CVTypeDumper::dump(const CVTypeArray &Types,
}
Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) {
- msf::ByteStream Stream(Data);
+ BinaryByteStream Stream(Data, llvm::support::little);
CVTypeArray Types;
- msf::StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readArray(Types, Reader.getLength()))
return EC;
diff --git a/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
index 5171e24f3aac..0069ee3cc904 100644
--- a/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
+++ b/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -10,9 +10,14 @@
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.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/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -21,7 +26,8 @@ CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
template <typename T>
-static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
+static Error visitKnownRecord(CVTypeVisitor &Visitor, CVType &Record,
+ TypeVisitorCallbacks &Callbacks) {
TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type);
T KnownRecord(RK);
if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
@@ -39,7 +45,58 @@ static Error visitKnownMember(CVMemberRecord &Record,
return Error::success();
}
+static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
+ class StealTypeServerVisitor : public TypeVisitorCallbacks {
+ public:
+ explicit StealTypeServerVisitor(TypeServer2Record &TR) : TR(TR) {}
+
+ Error visitKnownRecord(CVType &CVR, TypeServer2Record &Record) override {
+ TR = Record;
+ return Error::success();
+ }
+
+ private:
+ TypeServer2Record &TR;
+ };
+
+ TypeServer2Record R(TypeRecordKind::TypeServer2);
+ TypeDeserializer Deserializer;
+ StealTypeServerVisitor Thief(R);
+ TypeVisitorCallbackPipeline Pipeline;
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Thief);
+ CVTypeVisitor Visitor(Pipeline);
+ if (auto EC = Visitor.visitTypeRecord(Record))
+ return std::move(EC);
+
+ return R;
+}
+
+void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
+ Handlers.push_back(&Handler);
+}
+
Error CVTypeVisitor::visitTypeRecord(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 Error::success();
+
+ // Otherwise keep searching for a handler, eventually falling out and
+ // using the default record handler.
+ }
+ }
+
if (auto EC = Callbacks.visitTypeBegin(Record))
return EC;
@@ -50,7 +107,7 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
break;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
- if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
+ if (auto EC = visitKnownRecord<Name##Record>(*this, Record, Callbacks)) \
return EC; \
break; \
}
@@ -109,7 +166,15 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
return Error::success();
}
-Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
+Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
FieldListDeserializer Deserializer(Reader);
TypeVisitorCallbackPipeline Pipeline;
Pipeline.addCallbackToPipeline(Deserializer);
@@ -130,7 +195,7 @@ Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) {
}
Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
- msf::ByteStream S(Data);
- msf::StreamReader SR(S);
+ BinaryByteStream S(Data, llvm::support::little);
+ BinaryStreamReader SR(S);
return visitFieldListMemberStream(SR);
}
diff --git a/lib/DebugInfo/CodeView/CodeViewError.cpp b/lib/DebugInfo/CodeView/CodeViewError.cpp
index 55c10c076eef..8de266b836b4 100644
--- a/lib/DebugInfo/CodeView/CodeViewError.cpp
+++ b/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -31,6 +31,8 @@ public:
"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:
diff --git a/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
index 9bd85cf9dc68..282e3103adc9 100644
--- a/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
+++ b/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -10,8 +10,8 @@
#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
-#include "llvm/DebugInfo/MSF/StreamWriter.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -145,10 +145,10 @@ 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->writeZeroString(S))
+ if (auto EC = Writer->writeCString(S))
return EC;
} else {
- if (auto EC = Reader->readZeroString(Value))
+ if (auto EC = Reader->readCString(Value))
return EC;
}
return Error::success();
@@ -176,7 +176,7 @@ Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value) {
if (auto EC = mapStringZ(V))
return EC;
}
- if (auto EC = Writer->writeInteger(uint8_t(0)))
+ if (auto EC = Writer->writeInteger<uint8_t>(0))
return EC;
} else {
StringRef S;
@@ -194,22 +194,22 @@ Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value) {
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(static_cast<uint16_t>(LF_CHAR)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
return EC;
- if (auto EC = Writer->writeInteger(static_cast<int8_t>(Value)))
+ if (auto EC = Writer->writeInteger<int8_t>(Value))
return EC;
} else if (Value >= std::numeric_limits<int16_t>::min()) {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_SHORT)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))
return EC;
- if (auto EC = Writer->writeInteger(static_cast<int16_t>(Value)))
+ if (auto EC = Writer->writeInteger<int16_t>(Value))
return EC;
} else if (Value >= std::numeric_limits<int32_t>::min()) {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_LONG)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))
return EC;
- if (auto EC = Writer->writeInteger(static_cast<int32_t>(Value)))
+ if (auto EC = Writer->writeInteger<int32_t>(Value))
return EC;
} else {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_QUADWORD)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))
return EC;
if (auto EC = Writer->writeInteger(Value))
return EC;
@@ -219,20 +219,20 @@ Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
if (Value < LF_NUMERIC) {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value)))
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
return EC;
} else if (Value <= std::numeric_limits<uint16_t>::max()) {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_USHORT)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))
return EC;
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value)))
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
return EC;
} else if (Value <= std::numeric_limits<uint32_t>::max()) {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_ULONG)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))
return EC;
- if (auto EC = Writer->writeInteger(static_cast<uint32_t>(Value)))
+ if (auto EC = Writer->writeInteger<uint32_t>(Value))
return EC;
} else {
- if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_UQUADWORD)))
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))
return EC;
if (auto EC = Writer->writeInteger(Value))
return EC;
diff --git a/lib/DebugInfo/CodeView/Formatters.cpp b/lib/DebugInfo/CodeView/Formatters.cpp
new file mode 100644
index 000000000000..ef00bd8570fa
--- /dev/null
+++ b/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/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/lib/DebugInfo/CodeView/ModuleSubstream.cpp
index 768ebaa1c980..69a7c59116cf 100644
--- a/lib/DebugInfo/CodeView/ModuleSubstream.cpp
+++ b/lib/DebugInfo/CodeView/ModuleSubstream.cpp
@@ -9,22 +9,20 @@
#include "llvm/DebugInfo/CodeView/ModuleSubstream.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
+#include "llvm/Support/BinaryStreamReader.h"
using namespace llvm;
using namespace llvm::codeview;
-using namespace llvm::msf;
ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {}
-ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind,
- ReadableStreamRef Data)
+ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, BinaryStreamRef Data)
: Kind(Kind), Data(Data) {}
-Error ModuleSubstream::initialize(ReadableStreamRef Stream,
+Error ModuleSubstream::initialize(BinaryStreamRef Stream,
ModuleSubstream &Info) {
const ModuleSubsectionHeader *Header;
- StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readObject(Header))
return EC;
@@ -42,4 +40,4 @@ uint32_t ModuleSubstream::getRecordLength() const {
ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; }
-ReadableStreamRef ModuleSubstream::getRecordData() const { return Data; }
+BinaryStreamRef ModuleSubstream::getRecordData() const { return Data; }
diff --git a/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
index 524793277980..e490a78cadbc 100644
--- a/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
+++ b/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp
@@ -8,54 +8,52 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
-#include "llvm/DebugInfo/MSF/StreamRef.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
using namespace llvm;
using namespace llvm::codeview;
-using namespace llvm::msf;
-Error IModuleSubstreamVisitor::visitSymbols(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitSymbols(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::Symbols, Data);
}
-Error IModuleSubstreamVisitor::visitLines(ReadableStreamRef Data,
+Error IModuleSubstreamVisitor::visitLines(BinaryStreamRef Data,
const LineSubstreamHeader *Header,
const LineInfoArray &Lines) {
return visitUnknown(ModuleSubstreamKind::Lines, Data);
}
-Error IModuleSubstreamVisitor::visitStringTable(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitStringTable(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::StringTable, Data);
}
Error IModuleSubstreamVisitor::visitFileChecksums(
- ReadableStreamRef Data, const FileChecksumArray &Checksums) {
+ BinaryStreamRef Data, const FileChecksumArray &Checksums) {
return visitUnknown(ModuleSubstreamKind::FileChecksums, Data);
}
-Error IModuleSubstreamVisitor::visitFrameData(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitFrameData(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::FrameData, Data);
}
-Error IModuleSubstreamVisitor::visitInlineeLines(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitInlineeLines(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::InlineeLines, Data);
}
-Error IModuleSubstreamVisitor::visitCrossScopeImports(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitCrossScopeImports(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data);
}
-Error IModuleSubstreamVisitor::visitCrossScopeExports(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitCrossScopeExports(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data);
}
-Error IModuleSubstreamVisitor::visitILLines(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitILLines(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::ILLines, Data);
}
-Error IModuleSubstreamVisitor::visitFuncMDTokenMap(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitFuncMDTokenMap(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data);
}
-Error IModuleSubstreamVisitor::visitTypeMDTokenMap(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitTypeMDTokenMap(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data);
}
-Error IModuleSubstreamVisitor::visitMergedAssemblyInput(
- ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitMergedAssemblyInput(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data);
}
-Error IModuleSubstreamVisitor::visitCoffSymbolRVA(ReadableStreamRef Data) {
+Error IModuleSubstreamVisitor::visitCoffSymbolRVA(BinaryStreamRef Data) {
return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data);
}
@@ -65,7 +63,7 @@ Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R,
case ModuleSubstreamKind::Symbols:
return V.visitSymbols(R.getRecordData());
case ModuleSubstreamKind::Lines: {
- StreamReader Reader(R.getRecordData());
+ BinaryStreamReader Reader(R.getRecordData());
const LineSubstreamHeader *Header;
if (auto EC = Reader.readObject(Header))
return EC;
@@ -78,7 +76,7 @@ Error llvm::codeview::visitModuleSubstream(const ModuleSubstream &R,
case ModuleSubstreamKind::StringTable:
return V.visitStringTable(R.getRecordData());
case ModuleSubstreamKind::FileChecksums: {
- StreamReader Reader(R.getRecordData());
+ BinaryStreamReader Reader(R.getRecordData());
FileChecksumArray Checksums;
if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
return EC;
diff --git a/lib/DebugInfo/CodeView/RecordSerialization.cpp b/lib/DebugInfo/CodeView/RecordSerialization.cpp
index 6f29caa9bbfc..6446670f60d8 100644
--- a/lib/DebugInfo/CodeView/RecordSerialization.cpp
+++ b/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -16,7 +16,7 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/BinaryByteStream.h"
using namespace llvm;
using namespace llvm::codeview;
@@ -33,7 +33,7 @@ StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
return getBytesAsCharacters(LeafData).split('\0').first;
}
-Error llvm::codeview::consume(msf::StreamReader &Reader, APSInt &Num) {
+Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
// Used to avoid overload ambiguity on APInt construtor.
bool FalseVal = false;
uint16_t Short;
@@ -103,15 +103,15 @@ Error llvm::codeview::consume(msf::StreamReader &Reader, APSInt &Num) {
Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
- msf::ByteStream S(Bytes);
- msf::StreamReader SR(S);
+ 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(msf::StreamReader &Reader,
+Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
uint64_t &Num) {
APSInt N;
if (auto EC = consume(Reader, N))
@@ -123,27 +123,27 @@ Error llvm::codeview::consume_numeric(msf::StreamReader &Reader,
return Error::success();
}
-Error llvm::codeview::consume(msf::StreamReader &Reader, uint32_t &Item) {
+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());
- msf::ByteStream S(Bytes);
- msf::StreamReader SR(S);
+ 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(msf::StreamReader &Reader, int32_t &Item) {
+Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
return Reader.readInteger(Item);
}
-Error llvm::codeview::consume(msf::StreamReader &Reader, StringRef &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.readZeroString(Item);
+ return Reader.readCString(Item);
}
diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp
index fd54fba13c76..134471e81cac 100644
--- a/lib/DebugInfo/CodeView/SymbolDumper.cpp
+++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -468,8 +468,8 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
for (auto &Annotation : InlineSite.annotations()) {
switch (Annotation.OpCode) {
case BinaryAnnotationsOpCode::Invalid:
- return llvm::make_error<CodeViewError>(
- "Invalid binary annotation opcode!");
+ W.printString("(Annotation Padding)");
+ break;
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeLength:
diff --git a/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/lib/DebugInfo/CodeView/SymbolSerializer.cpp
new file mode 100644
index 000000000000..251cc431f52b
--- /dev/null
+++ b/lib/DebugInfo/CodeView/SymbolSerializer.cpp
@@ -0,0 +1,52 @@
+//===- 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)
+ : Storage(Allocator), RecordBuffer(MaxRecordLength), Stream(RecordBuffer, llvm::support::little),
+ Writer(Stream), Mapping(Writer) { }
+
+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/lib/DebugInfo/CodeView/TypeDatabase.cpp b/lib/DebugInfo/CodeView/TypeDatabase.cpp
index c7f72551dc8b..f9ded6ce2a86 100644
--- a/lib/DebugInfo/CodeView/TypeDatabase.cpp
+++ b/lib/DebugInfo/CodeView/TypeDatabase.cpp
@@ -71,7 +71,7 @@ TypeIndex TypeDatabase::getNextTypeIndex() const {
}
/// Records the name of a type, and reserves its type index.
-void TypeDatabase::recordType(StringRef Name, CVType Data) {
+void TypeDatabase::recordType(StringRef Name, const CVType &Data) {
CVUDTNames.push_back(Name);
TypeRecords.push_back(Data);
}
@@ -106,6 +106,10 @@ StringRef TypeDatabase::getTypeName(TypeIndex Index) const {
return "<unknown UDT>";
}
+const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const {
+ return TypeRecords[Index.getIndex() - TypeIndex::FirstNonSimpleIndex];
+}
+
bool TypeDatabase::containsTypeIndex(TypeIndex Index) const {
uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex;
return I < CVUDTNames.size();
diff --git a/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp b/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp
index d9d563902182..c234afd2288b 100644
--- a/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp
+++ b/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp
@@ -83,6 +83,22 @@ Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
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 = TypeDB.getTypeName(Indices[I]);
+ TypeName.append(ArgTypeName);
+ if (I + 1 != Size)
+ TypeName.append("\" \"");
+ }
+ TypeName.push_back('\"');
+ Name = TypeDB.saveTypeName(TypeName);
+ return Error::success();
+}
+
Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
Name = Class.getName();
return Error::success();
@@ -283,6 +299,10 @@ 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/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
index 033585ba8cc9..870d95221e7d 100644
--- a/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -1,5 +1,4 @@
-//===-- TypeDumpVisitor.cpp - CodeView type info dumper -----------*- C++
-//-*-===//
+//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,13 +12,15 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
using namespace llvm;
@@ -145,6 +146,10 @@ static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
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) {
@@ -163,9 +168,14 @@ void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB);
}
+void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
+ CVTypeDumper::printTypeIndex(*W, FieldName, TI, getSourceDB());
+}
+
Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
W->startLine() << getLeafTypeName(Record.Type);
- W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex())
+ W->getOStream() << " ("
+ << HexNumber(getSourceDB().getNextTypeIndex().getIndex())
<< ")";
W->getOStream() << " {\n";
W->indent();
@@ -211,7 +221,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
}
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
- printTypeIndex("Id", String.getId());
+ printItemIndex("Id", String.getId());
W->printString("StringData", String.getString());
return Error::success();
}
@@ -227,6 +237,17 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
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) {
+ printTypeIndex("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());
@@ -329,14 +350,14 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
}
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
- printTypeIndex("ParentScope", Func.getParentScope());
+ printItemIndex("ParentScope", Func.getParentScope());
printTypeIndex("FunctionType", Func.getFunctionType());
W->printString("Name", Func.getName());
return Error::success();
}
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
- W->printBinary("Signature", TS.getGuid());
+ W->printString("Guid", formatv("{0}", fmt_guid(TS.getGuid())).str());
W->printNumber("Age", TS.getAge());
W->printString("Name", TS.getName());
return Error::success();
@@ -390,7 +411,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
UdtSourceLineRecord &Line) {
printTypeIndex("UDT", Line.getUDT());
- printTypeIndex("SourceFile", Line.getSourceFile());
+ printItemIndex("SourceFile", Line.getSourceFile());
W->printNumber("LineNumber", Line.getLineNumber());
return Error::success();
}
@@ -398,7 +419,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
UdtModSourceLineRecord &Line) {
printTypeIndex("UDT", Line.getUDT());
- printTypeIndex("SourceFile", Line.getSourceFile());
+ printItemIndex("SourceFile", Line.getSourceFile());
W->printNumber("LineNumber", Line.getLineNumber());
W->printNumber("Module", Line.getModule());
return Error::success();
@@ -409,7 +430,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
ListScope Arguments(*W, "Arguments");
for (auto Arg : Args.getArgs()) {
- printTypeIndex("ArgType", Arg);
+ printItemIndex("ArgType", Arg);
}
return Error::success();
}
@@ -530,3 +551,8 @@ Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
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/lib/DebugInfo/CodeView/TypeRecord.cpp b/lib/DebugInfo/CodeView/TypeRecord.cpp
deleted file mode 100644
index b951c068ca86..000000000000
--- a/lib/DebugInfo/CodeView/TypeRecord.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-//===-- TypeRecord.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/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
-#include "llvm/DebugInfo/MSF/StreamReader.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-
-//===----------------------------------------------------------------------===//
-// Type index remapping
-//===----------------------------------------------------------------------===//
-
-static bool remapIndex(ArrayRef<TypeIndex> IndexMap, TypeIndex &Idx) {
- // Simple types are unchanged.
- if (Idx.isSimple())
- return true;
- unsigned MapPos = Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
- if (MapPos < IndexMap.size()) {
- Idx = IndexMap[MapPos];
- return true;
- }
-
- // This type index is invalid. Remap this to "not translated by cvpack",
- // and return failure.
- Idx = TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct);
- return false;
-}
-
-bool ModifierRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, ModifiedType);
-}
-
-bool ProcedureRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ReturnType);
- Success &= remapIndex(IndexMap, ArgumentList);
- return Success;
-}
-
-bool MemberFunctionRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ReturnType);
- Success &= remapIndex(IndexMap, ClassType);
- Success &= remapIndex(IndexMap, ThisType);
- Success &= remapIndex(IndexMap, ArgumentList);
- return Success;
-}
-
-bool MemberFuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ClassType);
- Success &= remapIndex(IndexMap, FunctionType);
- return Success;
-}
-
-bool ArgListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- for (TypeIndex &Str : StringIndices)
- Success &= remapIndex(IndexMap, Str);
- return Success;
-}
-
-bool MemberPointerInfo::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, ContainingType);
-}
-
-bool PointerRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ReferentType);
- if (isPointerToMember())
- Success &= MemberInfo->remapTypeIndices(IndexMap);
- return Success;
-}
-
-bool NestedTypeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool ArrayRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ElementType);
- Success &= remapIndex(IndexMap, IndexType);
- return Success;
-}
-
-bool TagRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, FieldList);
-}
-
-bool ClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= TagRecord::remapTypeIndices(IndexMap);
- Success &= remapIndex(IndexMap, DerivationList);
- Success &= remapIndex(IndexMap, VTableShape);
- return Success;
-}
-
-bool EnumRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= TagRecord::remapTypeIndices(IndexMap);
- Success &= remapIndex(IndexMap, UnderlyingType);
- return Success;
-}
-
-bool BitFieldRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool VFTableShapeRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return true;
-}
-
-bool TypeServer2Record::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return true;
-}
-
-bool StringIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Id);
-}
-
-bool FuncIdRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, ParentScope);
- Success &= remapIndex(IndexMap, FunctionType);
- return Success;
-}
-
-bool UdtSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, UDT);
- Success &= remapIndex(IndexMap, SourceFile);
- return Success;
-}
-
-bool UdtModSourceLineRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, UDT);
- Success &= remapIndex(IndexMap, SourceFile);
- return Success;
-}
-
-bool BuildInfoRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- for (TypeIndex &Arg : ArgIndices)
- Success &= remapIndex(IndexMap, Arg);
- return Success;
-}
-
-bool VFTableRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, CompleteClass);
- Success &= remapIndex(IndexMap, OverriddenVFTable);
- return Success;
-}
-
-bool OneMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, Type);
- return Success;
-}
-
-bool MethodOverloadListRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- for (OneMethodRecord &Meth : Methods)
- if ((Success = Meth.remapTypeIndices(IndexMap)))
- return Success;
- return Success;
-}
-
-bool OverloadedMethodRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, MethodList);
-}
-
-bool DataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool StaticDataMemberRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool EnumeratorRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return true;
-}
-
-bool VFPtrRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool BaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, Type);
-}
-
-bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- bool Success = true;
- Success &= remapIndex(IndexMap, BaseType);
- Success &= remapIndex(IndexMap, VBPtrType);
- return Success;
-}
-
-bool ListContinuationRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
- return remapIndex(IndexMap, ContinuationIndex);
-}
diff --git a/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index f46e08d55429..114f6fd2897e 100644
--- a/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -67,12 +67,9 @@ static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
error(IO.mapStringZ(N));
error(IO.mapStringZ(U));
} else {
- size_t BytesNeeded = Name.size() + 1;
- StringRef N = Name;
- if (BytesNeeded > BytesLeft) {
- size_t BytesToDrop = std::min(N.size(), BytesToDrop);
- N = N.drop_back(BytesToDrop);
- }
+ // 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 {
@@ -174,6 +171,15 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
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); }));
@@ -368,6 +374,14 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
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();
}
diff --git a/lib/DebugInfo/CodeView/TypeSerializer.cpp b/lib/DebugInfo/CodeView/TypeSerializer.cpp
index f24fcff86274..fd4d1853fa54 100644
--- a/lib/DebugInfo/CodeView/TypeSerializer.cpp
+++ b/lib/DebugInfo/CodeView/TypeSerializer.cpp
@@ -9,7 +9,7 @@
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
-#include "llvm/DebugInfo/MSF/StreamWriter.h"
+#include "llvm/Support/BinaryStreamWriter.h"
#include <string.h>
@@ -85,7 +85,8 @@ TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage)
: RecordStorage(Storage), LastTypeIndex(),
- RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream),
+ 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,
@@ -203,15 +204,15 @@ Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
- msf::MutableByteStream CS(SavedSegment);
- msf::StreamWriter CW(CS);
+ 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)))
+ if (auto EC = CW.writeInteger<uint16_t>(0))
return EC;
- if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0)))
+ if (auto EC = CW.writeInteger<uint32_t>(0xB0C0B0C0))
return EC;
FieldListSegments.push_back(SavedSegment);
diff --git a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
index ed6cf5743a12..aad20ae6dda1 100644
--- a/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
+++ b/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -52,12 +52,19 @@ namespace {
/// - 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:
- TypeStreamMerger(TypeTableBuilder &DestStream)
- : DestStream(DestStream), FieldListBuilder(DestStream) {
- assert(!hadError());
- }
+ TypeStreamMerger(TypeTableBuilder &DestIdStream,
+ TypeTableBuilder &DestTypeStream, TypeServerHandler *Handler)
+ : DestIdStream(DestIdStream), DestTypeStream(DestTypeStream),
+ FieldListBuilder(DestTypeStream), Handler(Handler) {}
+
+ static const TypeIndex Untranslated;
/// TypeVisitorCallbacks overrides.
#define TYPE_RECORD(EnumName, EnumVal, Name) \
@@ -74,42 +81,65 @@ public:
Error visitTypeEnd(CVType &Record) override;
Error visitMemberEnd(CVMemberRecord &Record) override;
- bool mergeStream(const CVTypeArray &Types);
+ Error mergeStream(const CVTypeArray &Types);
private:
+ void addMapping(TypeIndex Idx);
+
+ bool remapIndex(TypeIndex &Idx);
+
+ 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);
+ }
+
template <typename RecordType>
- Error visitKnownRecordImpl(RecordType &Record) {
- FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
- IndexMap.push_back(DestStream.writeKnownType(Record));
+ Error writeRecord(RecordType &R, bool RemapSuccess) {
+ TypeIndex DestIdx = Untranslated;
+ if (RemapSuccess)
+ DestIdx = DestTypeStream.writeKnownType(R);
+ addMapping(DestIdx);
return Error::success();
}
- Error visitKnownRecordImpl(FieldListRecord &Record) {
- CVTypeVisitor Visitor(*this);
-
- if (auto EC = Visitor.visitFieldListMemberStream(Record.Data))
- return EC;
+ template <typename RecordType>
+ Error writeIdRecord(RecordType &R, bool RemapSuccess) {
+ TypeIndex DestIdx = Untranslated;
+ if (RemapSuccess)
+ DestIdx = DestIdStream.writeKnownType(R);
+ addMapping(DestIdx);
return Error::success();
}
template <typename RecordType>
- Error visitKnownMemberRecordImpl(RecordType &Record) {
- FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);
- FieldListBuilder.writeMemberType(Record);
+ Error writeMember(RecordType &R, bool RemapSuccess) {
+ if (RemapSuccess)
+ FieldListBuilder.writeMemberType(R);
+ else
+ HadUntranslatedMember = true;
return Error::success();
}
- bool hadError() { return FoundBadTypeIndex; }
+ Optional<Error> LastError;
+
+ bool IsSecondPass = false;
+
+ bool HadUntranslatedMember = false;
- bool FoundBadTypeIndex = false;
+ unsigned NumBadIndices = 0;
BumpPtrAllocator Allocator;
- TypeTableBuilder &DestStream;
+ TypeTableBuilder &DestIdStream;
+ TypeTableBuilder &DestTypeStream;
FieldListRecordBuilder FieldListBuilder;
+ TypeServerHandler *Handler;
- bool IsInFieldList{false};
- size_t BeginIndexMapSize = 0;
+ TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex};
/// Map from source type index to destination type index. Indexed by source
/// type index minus 0x1000.
@@ -118,70 +148,346 @@ private:
} // end anonymous namespace
+const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated);
+
Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) {
- if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
- assert(!IsInFieldList);
- IsInFieldList = true;
- FieldListBuilder.begin();
- } else
- BeginIndexMapSize = IndexMap.size();
return Error::success();
}
Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) {
- if (Rec.Type == TypeLeafKind::LF_FIELDLIST) {
- TypeIndex Index = FieldListBuilder.end();
- IndexMap.push_back(Index);
- IsInFieldList = false;
- }
+ CurIndex = TypeIndex(CurIndex.getIndex() + 1);
+ if (!IsSecondPass)
+ assert(IndexMap.size() == slotForIndex(CurIndex) &&
+ "visitKnownRecord should add one index map entry");
return Error::success();
}
Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) {
- assert(IndexMap.size() == BeginIndexMapSize + 1);
return Error::success();
}
-#define TYPE_RECORD(EnumName, EnumVal, Name) \
- Error TypeStreamMerger::visitKnownRecord(CVType &CVR, \
- Name##Record &Record) { \
- return visitKnownRecordImpl(Record); \
+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;
}
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- Error TypeStreamMerger::visitKnownMember(CVMemberRecord &CVR, \
- Name##Record &Record) { \
- return visitKnownMemberRecordImpl(Record); \
+}
+
+bool TypeStreamMerger::remapIndex(TypeIndex &Idx) {
+ // 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 < IndexMap.size() && IndexMap[MapPos] != Untranslated) {
+ Idx = IndexMap[MapPos];
+ return true;
}
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+ // 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 >= IndexMap.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;
+}
+
+//----------------------------------------------------------------------------//
+// Item records
+//----------------------------------------------------------------------------//
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, FuncIdRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ParentScope);
+ Success &= remapIndex(R.FunctionType);
+ return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFuncIdRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ClassType);
+ Success &= remapIndex(R.FunctionType);
+ return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, StringIdRecord &R) {
+ return writeIdRecord(R, remapIndex(R.Id));
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, StringListRecord &R) {
+ bool Success = true;
+ for (TypeIndex &Str : R.StringIndices)
+ Success &= remapIndex(Str);
+ return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, BuildInfoRecord &R) {
+ bool Success = true;
+ for (TypeIndex &Arg : R.ArgIndices)
+ Success &= remapIndex(Arg);
+ return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, UdtSourceLineRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.UDT);
+ Success &= remapIndex(R.SourceFile);
+ // FIXME: Translate UdtSourceLineRecord into UdtModSourceLineRecords in the
+ // IPI stream.
+ return writeIdRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, UdtModSourceLineRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.UDT);
+ Success &= remapIndex(R.SourceFile);
+ return writeIdRecord(R, Success);
+}
+
+//----------------------------------------------------------------------------//
+// Type records
+//----------------------------------------------------------------------------//
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, ModifierRecord &R) {
+ return writeRecord(R, remapIndex(R.ModifiedType));
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, ProcedureRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ReturnType);
+ Success &= remapIndex(R.ArgumentList);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, MemberFunctionRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ReturnType);
+ Success &= remapIndex(R.ClassType);
+ Success &= remapIndex(R.ThisType);
+ Success &= remapIndex(R.ArgumentList);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &Type, ArgListRecord &R) {
+ bool Success = true;
+ for (TypeIndex &Arg : R.ArgIndices)
+ Success &= remapIndex(Arg);
+ if (auto EC = writeRecord(R, Success))
+ return EC;
+ return Error::success();
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, PointerRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ReferentType);
+ if (R.isPointerToMember())
+ Success &= remapIndex(R.MemberInfo->ContainingType);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, ArrayRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.ElementType);
+ Success &= remapIndex(R.IndexType);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, ClassRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.FieldList);
+ Success &= remapIndex(R.DerivationList);
+ Success &= remapIndex(R.VTableShape);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, UnionRecord &R) {
+ return writeRecord(R, remapIndex(R.FieldList));
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, EnumRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.FieldList);
+ Success &= remapIndex(R.UnderlyingType);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, BitFieldRecord &R) {
+ return writeRecord(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableShapeRecord &R) {
+ return writeRecord(R, true);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, TypeServer2Record &R) {
+ return writeRecord(R, true);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, LabelRecord &R) {
+ return writeRecord(R, true);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, VFTableRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.CompleteClass);
+ Success &= remapIndex(R.OverriddenVFTable);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &,
+ MethodOverloadListRecord &R) {
+ bool Success = true;
+ for (OneMethodRecord &Meth : R.Methods)
+ Success &= remapIndex(Meth.Type);
+ return writeRecord(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownRecord(CVType &, FieldListRecord &R) {
+ // Visit the members inside the field list.
+ HadUntranslatedMember = false;
+ FieldListBuilder.begin();
+ CVTypeVisitor Visitor(*this);
+ if (auto EC = Visitor.visitFieldListMemberStream(R.Data))
+ return EC;
+
+ // Write the record if we translated all field list members.
+ TypeIndex DestIdx = Untranslated;
+ if (!HadUntranslatedMember)
+ DestIdx = FieldListBuilder.end();
+ else
+ FieldListBuilder.reset();
+ addMapping(DestIdx);
+
+ return Error::success();
+}
+
+//----------------------------------------------------------------------------//
+// Member records
+//----------------------------------------------------------------------------//
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ NestedTypeRecord &R) {
+ return writeMember(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, OneMethodRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.Type);
+ return writeMember(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ OverloadedMethodRecord &R) {
+ return writeMember(R, remapIndex(R.MethodList));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ DataMemberRecord &R) {
+ return writeMember(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ StaticDataMemberRecord &R) {
+ return writeMember(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ EnumeratorRecord &R) {
+ return writeMember(R, true);
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, VFPtrRecord &R) {
+ return writeMember(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &, BaseClassRecord &R) {
+ return writeMember(R, remapIndex(R.Type));
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ VirtualBaseClassRecord &R) {
+ bool Success = true;
+ Success &= remapIndex(R.BaseType);
+ Success &= remapIndex(R.VBPtrType);
+ return writeMember(R, Success);
+}
+
+Error TypeStreamMerger::visitKnownMember(CVMemberRecord &,
+ ListContinuationRecord &R) {
+ return writeMember(R, remapIndex(R.ContinuationIndex));
+}
Error TypeStreamMerger::visitUnknownType(CVType &Rec) {
// We failed to translate a type. Translate this index as "not translated".
- IndexMap.push_back(
- TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
- return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+ addMapping(TypeIndex(SimpleTypeKind::NotTranslated));
+ return errorCorruptRecord();
}
-bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
+Error TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
assert(IndexMap.empty());
TypeVisitorCallbackPipeline Pipeline;
+ LastError = Error::success();
TypeDeserializer Deserializer;
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(*this);
CVTypeVisitor Visitor(Pipeline);
+ if (Handler)
+ Visitor.addTypeServerHandler(*Handler);
+
+ if (auto EC = Visitor.visitTypeStream(Types))
+ return EC;
+
+ // If we found bad indices but no other errors, try doing another pass and see
+ // if we can resolve the indices that weren't in the map on the first pass.
+ // This may require multiple passes, but we should always make progress. MASM
+ // is the only known CodeView producer that makes type streams that aren't
+ // topologically sorted. The standard library contains MASM-produced objects,
+ // so this is important to handle correctly, but we don't have to be too
+ // efficient. MASM type streams are usually very small.
+ while (!*LastError && NumBadIndices > 0) {
+ unsigned BadIndicesRemaining = NumBadIndices;
+ IsSecondPass = true;
+ NumBadIndices = 0;
+ CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex);
+ if (auto EC = Visitor.visitTypeStream(Types))
+ return EC;
- if (auto EC = Visitor.visitTypeStream(Types)) {
- consumeError(std::move(EC));
- return false;
+ 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");
+ }
}
+
IndexMap.clear();
- return !hadError();
+
+ Error Ret = std::move(*LastError);
+ LastError.reset();
+ return Ret;
}
-bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
- const CVTypeArray &Types) {
- return TypeStreamMerger(DestStream).mergeStream(Types);
+Error llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestIdStream,
+ TypeTableBuilder &DestTypeStream,
+ TypeServerHandler *Handler,
+ const CVTypeArray &Types) {
+ return TypeStreamMerger(DestIdStream, DestTypeStream, Handler)
+ .mergeStream(Types);
}