diff options
Diffstat (limited to 'lib/DebugInfo/CodeView')
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); } |