diff options
Diffstat (limited to 'lib/DebugInfo')
118 files changed, 4169 insertions, 1952 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); } diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 08bc74a81e9a..e7b4b777b43f 100644 --- a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -1,4 +1,4 @@ -//===-- DWARFAbbreviationDeclaration.cpp ----------------------------------===// +//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,18 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> + using namespace llvm; using namespace dwarf; @@ -86,7 +92,6 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, case DW_FORM_line_strp: case DW_FORM_sec_offset: case DW_FORM_strp_sup: - case DW_FORM_ref_sup: ++FixedAttributeSize->NumDwarfOffsets; break; diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 7111ad3f9fc7..85e1eaedfc61 100644 --- a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -1,4 +1,4 @@ -//===--- DWARFAcceleratorTable.cpp ----------------------------------------===// +//===- DWARFAcceleratorTable.cpp ------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,19 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> +#include <utility> -namespace llvm { +using namespace llvm; bool DWARFAcceleratorTable::extract() { uint32_t Offset = 0; @@ -46,7 +53,7 @@ bool DWARFAcceleratorTable::extract() { return true; } -void DWARFAcceleratorTable::dump(raw_ostream &OS) const { +LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const { // Dump the header. OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n' << "Version = " << format("0x%04x", Hdr.Version) << '\n' @@ -131,4 +138,3 @@ void DWARFAcceleratorTable::dump(raw_ostream &OS) const { } } } -} diff --git a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp index 948972f8f136..6e550f2e9ec9 100644 --- a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -18,8 +18,10 @@ using namespace llvm; void DWARFCompileUnit::dump(raw_ostream &OS) { OS << format("0x%08x", getOffset()) << ": Compile Unit:" << " length = " << format("0x%08x", getLength()) - << " version = " << format("0x%04x", getVersion()) - << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) + << " version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << " unit_type = " << dwarf::UnitTypeString(getUnitType()); + OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp index 77f6f65ee131..cbce2dc89deb 100644 --- a/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1,4 +1,4 @@ -//===-- DWARFContext.cpp --------------------------------------------------===// +//===- DWARFContext.cpp ---------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,23 +7,45 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/ELF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + using namespace llvm; using namespace dwarf; using namespace object; @@ -128,8 +150,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, auto CUDIE = CU->getUnitDIE(); if (!CUDIE) continue; - if (auto StmtOffset = - CUDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list)) { + if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) { DataExtractor lineData(getLineSection().Data, isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; @@ -387,7 +408,7 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!UnitDIE) return nullptr; - auto Offset = UnitDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list); + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); if (!Offset) return nullptr; // No line table for this compile unit. @@ -440,23 +461,32 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { return getCompileUnitForOffset(CUOffset); } -static bool getFunctionNameForAddress(DWARFCompileUnit *CU, uint64_t Address, - FunctionNameKind Kind, - std::string &FunctionName) { - if (Kind == FunctionNameKind::None) - return false; +static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU, + uint64_t Address, + FunctionNameKind Kind, + std::string &FunctionName, + uint32_t &StartLine) { // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the - // name of the topmost function in it.SmallVectorImpl<DWARFDie> &InlinedChain + // name of the topmost function in it. SmallVector<DWARFDie, 4> InlinedChain; CU->getInlinedChainForAddress(Address, InlinedChain); - if (InlinedChain.size() == 0) + if (InlinedChain.empty()) return false; - if (const char *Name = InlinedChain[0].getSubroutineName(Kind)) { + + const DWARFDie &DIE = InlinedChain[0]; + bool FoundResult = false; + const char *Name = nullptr; + if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) { FunctionName = Name; - return true; + FoundResult = true; + } + if (auto DeclLineResult = DIE.getDeclLine()) { + StartLine = DeclLineResult; + FoundResult = true; } - return false; + + return FoundResult; } DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, @@ -466,7 +496,9 @@ DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address, DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Result; - getFunctionNameForAddress(CU, Address, Spec.FNKind, Result.FunctionName); + getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, + Result.FunctionName, + Result.StartLine); if (Spec.FLIKind != FileLineInfoKind::None) { if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(), @@ -484,13 +516,16 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, return Lines; std::string FunctionName = "<invalid>"; - getFunctionNameForAddress(CU, Address, Spec.FNKind, FunctionName); + uint32_t StartLine = 0; + getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, FunctionName, + StartLine); // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (Spec.FLIKind == FileLineInfoKind::None) { DILineInfo Result; Result.FunctionName = FunctionName; + Result.StartLine = StartLine; Lines.push_back(std::make_pair(Address, Result)); return Lines; } @@ -511,6 +546,7 @@ DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, Result.FunctionName = FunctionName; Result.Line = Row.Line; Result.Column = Row.Column; + Result.StartLine = StartLine; Lines.push_back(std::make_pair(Row.Address, Result)); } @@ -550,6 +586,8 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, // Get function name if necessary. if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; + if (auto DeclLineResult = FunctionDIE.getDeclLine()) + Frame.StartLine = DeclLineResult; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { // For the topmost frame, initialize the line table of this @@ -578,6 +616,66 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; } +static Error createError(const Twine &Reason, llvm::Error E) { + return make_error<StringError>(Reason + toString(std::move(E)), + inconvertibleErrorCode()); +} + +/// Returns the address of symbol relocation used against. Used for futher +/// relocations computation. Symbol's section load address is taken in account if +/// LoadedObjectInfo interface is provided. +static Expected<uint64_t> getSymbolAddress(const object::ObjectFile &Obj, + const RelocationRef &Reloc, + const LoadedObjectInfo *L) { + uint64_t Ret = 0; + object::section_iterator RSec = Obj.section_end(); + object::symbol_iterator Sym = Reloc.getSymbol(); + + // First calculate the address of the symbol or section as it appears + // in the object file + if (Sym != Obj.symbol_end()) { + Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); + if (!SymAddrOrErr) + return createError("error: failed to compute symbol address: ", + SymAddrOrErr.takeError()); + + // Also remember what section this symbol is in for later + auto SectOrErr = Sym->getSection(); + if (!SectOrErr) + return createError("error: failed to get symbol section: ", + SectOrErr.takeError()); + + RSec = *SectOrErr; + Ret = *SymAddrOrErr; + } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { + RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); + Ret = RSec->getAddress(); + } + + // If we are given load addresses for the sections, we need to adjust: + // SymAddr = (Address of Symbol Or Section in File) - + // (Address of Section in File) + + // (Load Address of Section) + // RSec is now either the section being targeted or the section + // containing the symbol being targeted. In either case, + // we need to perform the same computation. + if (L && RSec != Obj.section_end()) + if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec)) + Ret += SectionLoadAddress - RSec->getAddress(); + return Ret; +} + +static bool isRelocScattered(const object::ObjectFile &Obj, + const RelocationRef &Reloc) { + const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj); + if (!MachObj) + return false; + // MachO also has relocations that point to sections and + // scattered relocations. + auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl()); + return MachObj->isRelocationScattered(RelocInfo); +} + DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), @@ -618,40 +716,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, name = name.substr( name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. - StringRef *SectionData = - StringSwitch<StringRef *>(name) - .Case("debug_info", &InfoSection.Data) - .Case("debug_abbrev", &AbbrevSection) - .Case("debug_loc", &LocSection.Data) - .Case("debug_line", &LineSection.Data) - .Case("debug_aranges", &ARangeSection) - .Case("debug_frame", &DebugFrameSection) - .Case("eh_frame", &EHFrameSection) - .Case("debug_str", &StringSection) - .Case("debug_ranges", &RangeSection) - .Case("debug_macinfo", &MacinfoSection) - .Case("debug_pubnames", &PubNamesSection) - .Case("debug_pubtypes", &PubTypesSection) - .Case("debug_gnu_pubnames", &GnuPubNamesSection) - .Case("debug_gnu_pubtypes", &GnuPubTypesSection) - .Case("debug_info.dwo", &InfoDWOSection.Data) - .Case("debug_abbrev.dwo", &AbbrevDWOSection) - .Case("debug_loc.dwo", &LocDWOSection.Data) - .Case("debug_line.dwo", &LineDWOSection.Data) - .Case("debug_str.dwo", &StringDWOSection) - .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) - .Case("debug_addr", &AddrSection) - .Case("apple_names", &AppleNamesSection.Data) - .Case("apple_types", &AppleTypesSection.Data) - .Case("apple_namespaces", &AppleNamespacesSection.Data) - .Case("apple_namespac", &AppleNamespacesSection.Data) - .Case("apple_objc", &AppleObjCSection.Data) - .Case("debug_cu_index", &CUIndexSection) - .Case("debug_tu_index", &TUIndexSection) - .Case("gdb_index", &GdbIndexSection) - // Any more debug info sections go here. - .Default(nullptr); - if (SectionData) { + if (StringRef *SectionData = MapSectionToMember(name)) { *SectionData = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. @@ -716,73 +781,19 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, if (Section.relocation_begin() != Section.relocation_end()) { uint64_t SectionSize = RelocatedSection->getSize(); for (const RelocationRef &Reloc : Section.relocations()) { - uint64_t Address = Reloc.getOffset(); - uint64_t Type = Reloc.getType(); - uint64_t SymAddr = 0; - uint64_t SectionLoadAddress = 0; - object::symbol_iterator Sym = Reloc.getSymbol(); - object::section_iterator RSec = Obj.section_end(); - - // First calculate the address of the symbol or section as it appears - // in the objct file - if (Sym != Obj.symbol_end()) { - Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); - if (!SymAddrOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SymAddrOrErr.takeError(), OS, ""); - OS.flush(); - errs() << "error: failed to compute symbol address: " - << Buf << '\n'; - continue; - } - SymAddr = *SymAddrOrErr; - // Also remember what section this symbol is in for later - auto SectOrErr = Sym->getSection(); - if (!SectOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SectOrErr.takeError(), OS, ""); - OS.flush(); - errs() << "error: failed to get symbol section: " - << Buf << '\n'; - continue; - } - RSec = *SectOrErr; - } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { - // MachO also has relocations that point to sections and - // scattered relocations. - auto RelocInfo = MObj->getRelocation(Reloc.getRawDataRefImpl()); - if (MObj->isRelocationScattered(RelocInfo)) { - // FIXME: it's not clear how to correctly handle scattered - // relocations. - continue; - } else { - RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); - SymAddr = RSec->getAddress(); - } - } + // FIXME: it's not clear how to correctly handle scattered + // relocations. + if (isRelocScattered(Obj, Reloc)) + continue; - // If we are given load addresses for the sections, we need to adjust: - // SymAddr = (Address of Symbol Or Section in File) - - // (Address of Section in File) + - // (Load Address of Section) - if (L != nullptr && RSec != Obj.section_end()) { - // RSec is now either the section being targeted or the section - // containing the symbol being targeted. In either case, - // we need to perform the same computation. - StringRef SecName; - RSec->getName(SecName); -// llvm::dbgs() << "Name: '" << SecName -// << "', RSec: " << RSec->getRawDataRefImpl() -// << ", Section: " << Section.getRawDataRefImpl() << "\n"; - SectionLoadAddress = L->getSectionLoadAddress(*RSec); - if (SectionLoadAddress != 0) - SymAddr += SectionLoadAddress - RSec->getAddress(); + Expected<uint64_t> SymAddrOrErr = getSymbolAddress(Obj, Reloc, L); + if (!SymAddrOrErr) { + errs() << toString(SymAddrOrErr.takeError()) << '\n'; + continue; } object::RelocVisitor V(Obj); - object::RelocToApply R(V.visit(Type, Reloc, SymAddr)); + object::RelocToApply R(V.visit(Reloc.getType(), Reloc, *SymAddrOrErr)); if (V.error()) { SmallString<32> Name; Reloc.getTypeName(Name); @@ -790,7 +801,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, << Name << "\n"; continue; } - + uint64_t Address = Reloc.getOffset(); if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " @@ -812,4 +823,49 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, } } -void DWARFContextInMemory::anchor() { } +DWARFContextInMemory::DWARFContextInMemory( + const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, uint8_t AddrSize, + bool isLittleEndian) + : IsLittleEndian(isLittleEndian), AddressSize(AddrSize) { + for (const auto &SecIt : Sections) { + if (StringRef *SectionData = MapSectionToMember(SecIt.first())) + *SectionData = SecIt.second->getBuffer(); + } +} + +StringRef *DWARFContextInMemory::MapSectionToMember(StringRef Name) { + return StringSwitch<StringRef *>(Name) + .Case("debug_info", &InfoSection.Data) + .Case("debug_abbrev", &AbbrevSection) + .Case("debug_loc", &LocSection.Data) + .Case("debug_line", &LineSection.Data) + .Case("debug_aranges", &ARangeSection) + .Case("debug_frame", &DebugFrameSection) + .Case("eh_frame", &EHFrameSection) + .Case("debug_str", &StringSection) + .Case("debug_ranges", &RangeSection) + .Case("debug_macinfo", &MacinfoSection) + .Case("debug_pubnames", &PubNamesSection) + .Case("debug_pubtypes", &PubTypesSection) + .Case("debug_gnu_pubnames", &GnuPubNamesSection) + .Case("debug_gnu_pubtypes", &GnuPubTypesSection) + .Case("debug_info.dwo", &InfoDWOSection.Data) + .Case("debug_abbrev.dwo", &AbbrevDWOSection) + .Case("debug_loc.dwo", &LocDWOSection.Data) + .Case("debug_line.dwo", &LineDWOSection.Data) + .Case("debug_str.dwo", &StringDWOSection) + .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) + .Case("debug_addr", &AddrSection) + .Case("apple_names", &AppleNamesSection.Data) + .Case("apple_types", &AppleTypesSection.Data) + .Case("apple_namespaces", &AppleNamespacesSection.Data) + .Case("apple_namespac", &AppleNamespacesSection.Data) + .Case("apple_objc", &AppleObjCSection.Data) + .Case("debug_cu_index", &CUIndexSection) + .Case("debug_tu_index", &TUIndexSection) + .Case("gdb_index", &GdbIndexSection) + // Any more debug info sections go here. + .Default(nullptr); +} + +void DWARFContextInMemory::anchor() {} diff --git a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp index e63e28997ed0..76dd2e4c21bc 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAbbrev.cpp ----------------------------------------------===// +//===- DWARFDebugAbbrev.cpp -----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,6 +10,10 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> + using namespace llvm; DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { diff --git a/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp index 67589cd01e55..ed5d726ae4e2 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugArangeSet.cpp -------------------------------------------===// +//===- DWARFDebugArangeSet.cpp --------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,8 +10,11 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> #include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstring> + using namespace llvm; void DWARFDebugArangeSet::clear() { diff --git a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp index 27a02c4c50d0..0cf71f530446 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// +//===- DWARFDebugAranges.cpp ----------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -11,11 +11,13 @@ #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/DataExtractor.h" #include <algorithm> #include <cassert> +#include <cstdint> #include <set> +#include <vector> + using namespace llvm; void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { @@ -81,7 +83,7 @@ void DWARFDebugAranges::construct() { std::sort(Endpoints.begin(), Endpoints.end()); uint64_t PrevAddress = -1ULL; for (const auto &E : Endpoints) { - if (PrevAddress < E.Address && ValidCUs.size() > 0) { + if (PrevAddress < E.Address && !ValidCUs.empty()) { // If the address range between two endpoints is described by some // CU, first try to extend the last range in Aranges. If we can't // do it, start a new range. diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 32b8320e26c5..b55ed6a46849 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugFrame.h - Parsing of .debug_frame -------------*- C++ -*-===// +//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" @@ -15,6 +14,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataExtractor.h" @@ -465,8 +465,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const { } } -DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) { -} +DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {} DWARFDebugFrame::~DWARFDebugFrame() = default; @@ -485,17 +484,17 @@ static unsigned getSizeForEncoding(const DataExtractor &Data, unsigned format = symbolEncoding & 0x0f; switch (format) { default: llvm_unreachable("Unknown Encoding"); - case dwarf::DW_EH_PE_absptr: - case dwarf::DW_EH_PE_signed: + case DW_EH_PE_absptr: + case DW_EH_PE_signed: return Data.getAddressSize(); - case dwarf::DW_EH_PE_udata2: - case dwarf::DW_EH_PE_sdata2: + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: return 2; - case dwarf::DW_EH_PE_udata4: - case dwarf::DW_EH_PE_sdata4: + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: return 4; - case dwarf::DW_EH_PE_udata8: - case dwarf::DW_EH_PE_sdata8: + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: return 8; } } diff --git a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index c487e1dca7c6..35f673c7acc6 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugInfoEntry.cpp -------------------------------------------===// +//===- DWARFDebugInfoEntry.cpp --------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,20 +7,17 @@ // //===----------------------------------------------------------------------===// -#include "SyntaxHighlighting.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" +#include <cstddef> +#include <cstdint> + using namespace llvm; using namespace dwarf; -using namespace syntax; bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr) { @@ -28,6 +25,7 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, const uint32_t UEndOffset = U.getNextUnitOffset(); return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0); } + bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, const DataExtractor &DebugInfoData, uint32_t UEndOffset, uint32_t D) { diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 494059461fd7..e4670519b797 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugLine.cpp ------------------------------------------------===// +//===- DWARFDebugLine.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,14 +7,23 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstdio> +#include <utility> + using namespace llvm; using namespace dwarf; + typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; DWARFDebugLine::Prologue::Prologue() { clear(); } diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index ae5b9d70a2eb..e2799ab2d243 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugLoc.cpp -------------------------------------------------===// +//===- DWARFDebugLoc.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> using namespace llvm; @@ -71,7 +76,7 @@ void DWARFDebugLoc::parse(DataExtractor data, unsigned AddressSize) { } } if (data.isValidOffset(Offset)) - llvm::errs() << "error: failed to consume entire .debug_loc section\n"; + errs() << "error: failed to consume entire .debug_loc section\n"; } void DWARFDebugLocDWO::parse(DataExtractor data) { @@ -85,8 +90,8 @@ void DWARFDebugLocDWO::parse(DataExtractor data) { data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { if (Kind != dwarf::DW_LLE_startx_length) { - llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind - << " not implemented\n"; + errs() << "error: dumping support for LLE of kind " << (int)Kind + << " not implemented\n"; return; } @@ -123,4 +128,3 @@ void DWARFDebugLocDWO::dump(raw_ostream &OS) const { } } } - diff --git a/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp index 7710a90b5e13..e0a9adde8e58 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugMacro.cpp -----------------------------------------------===// +//===- DWARFDebugMacro.cpp ------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "SyntaxHighlighting.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/Support/Dwarf.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> using namespace llvm; using namespace dwarf; diff --git a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp index 3c1fe93090c6..662e53d9d7e6 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugPubTable.cpp ---------------------------------------------===// +//===- DWARFDebugPubTable.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> using namespace llvm; -using namespace llvm::dwarf; +using namespace dwarf; DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, bool GnuStyle) @@ -54,7 +58,7 @@ void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { OS << format("0x%8.8x ", E.SecOffset); if (GnuStyle) { StringRef EntryLinkage = - dwarf::GDBIndexEntryLinkageString(E.Descriptor.Linkage); + GDBIndexEntryLinkageString(E.Descriptor.Linkage); StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind); OS << format("%-8s", EntryLinkage.data()) << ' ' << format("%-8s", EntryKind.data()) << ' '; diff --git a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp index d5df6885f5e9..f1d82fda8c06 100644 --- a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDebugRangesList.cpp ------------------------------------------===// +//===- DWARFDebugRangesList.cpp -------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,6 +10,9 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> +#include <utility> using namespace llvm; diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp index 89b83b11ab68..4308cc2e2639 100644 --- a/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -1,4 +1,4 @@ -//===-- DWARFDie.cpp ------------------------------------------------------===// +//===- DWARFDie.cpp -------------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,25 +7,33 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "SyntaxHighlighting.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/Debug.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <string> +#include <utility> using namespace llvm; using namespace dwarf; using namespace syntax; -namespace { - static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { +static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { OS << " ("; do { uint64_t Shift = countTrailingZeros(Val); @@ -122,8 +130,6 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, OS << ")\n"; } -} // end anonymous namespace - bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; } @@ -134,7 +140,7 @@ bool DWARFDie::isSubroutineDIE() const { } Optional<DWARFFormValue> -DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { +DWARFDie::find(dwarf::Attribute Attr) const { if (!isValid()) return None; auto AbbrevDecl = getAbbreviationDeclarationPtr(); @@ -143,54 +149,41 @@ DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { return None; } -const char *DWARFDie::getAttributeValueAsString(dwarf::Attribute Attr, - const char *FailValue) const { - auto FormValue = getAttributeValue(Attr); - if (!FormValue) - return FailValue; - Optional<const char *> Result = FormValue->getAsCString(); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsAddress(); - return None; -} - -Optional<int64_t> -DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsSignedConstant(); - return None; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsUnsignedConstant(); - return None; -} - -Optional<uint64_t> -DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsReference(); +Optional<DWARFFormValue> +DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { + if (!isValid()) + return None; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + for (auto Attr : Attrs) { + if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U)) + return Value; + } + } return None; } -Optional<uint64_t> -DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) - return FormValue->getAsSectionOffset(); +Optional<DWARFFormValue> +DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { + if (!isValid()) + return None; + auto Die = *this; + if (auto Value = Die.find(Attrs)) + return Value; + if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) + Die = D; + if (auto Value = Die.find(Attrs)) + return Value; + if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) + Die = D; + if (auto Value = Die.find(Attrs)) + return Value; return None; } - DWARFDie DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { - auto SpecRef = getAttributeValueAsReference(Attr); + auto SpecRef = toReference(find(Attr)); if (SpecRef) { auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef); if (SpecUnit) @@ -201,14 +194,11 @@ DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { - auto Result = getAttributeValueAsSectionOffset(DW_AT_rnglists_base); - if (Result) - return Result; - return getAttributeValueAsSectionOffset(DW_AT_GNU_ranges_base); + return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); } Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { - if (auto FormValue = getAttributeValue(DW_AT_high_pc)) { + if (auto FormValue = find(DW_AT_high_pc)) { if (auto Address = FormValue->getAsAddress()) { // High PC is an address. return Address; @@ -222,7 +212,7 @@ Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { } bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const { - auto LowPcAddr = getAttributeValueAsAddress(DW_AT_low_pc); + auto LowPcAddr = toAddress(find(DW_AT_low_pc)); if (!LowPcAddr) return false; if (auto HighPcAddr = getHighPC(*LowPcAddr)) { @@ -243,7 +233,7 @@ DWARFDie::getAddressRanges() const { return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC)); } // Multiple ranges from .debug_ranges section. - auto RangesOffset = getAttributeValueAsSectionOffset(DW_AT_ranges); + auto RangesOffset = toSectionOffset(find(DW_AT_ranges)); if (RangesOffset) { DWARFDebugRangeList RangeList; if (U->extractRangeList(*RangesOffset, RangeList)) @@ -284,33 +274,26 @@ const char * DWARFDie::getName(DINameKind Kind) const { if (!isValid() || Kind == DINameKind::None) return nullptr; - const char *name = nullptr; // Try to get mangled name only if it was asked for. if (Kind == DINameKind::LinkageName) { - if ((name = getAttributeValueAsString(DW_AT_MIPS_linkage_name, nullptr))) - return name; - if ((name = getAttributeValueAsString(DW_AT_linkage_name, nullptr))) - return name; + if (auto Name = dwarf::toString(findRecursively({DW_AT_MIPS_linkage_name, + DW_AT_linkage_name}), nullptr)) + return Name; } - if ((name = getAttributeValueAsString(DW_AT_name, nullptr))) - return name; - // Try to get name from specification DIE. - DWARFDie SpecDie = getAttributeValueAsReferencedDie(DW_AT_specification); - if (SpecDie && (name = SpecDie.getName(Kind))) - return name; - // Try to get name from abstract origin DIE. - DWARFDie AbsDie = getAttributeValueAsReferencedDie(DW_AT_abstract_origin); - if (AbsDie && (name = AbsDie.getName(Kind))) - return name; + if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr)) + return Name; return nullptr; } +uint64_t DWARFDie::getDeclLine() const { + return toUnsigned(findRecursively(DW_AT_decl_line), 0); +} + void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file).getValueOr(0); - CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line).getValueOr(0); - CallColumn = - getAttributeValueAsUnsignedConstant(DW_AT_call_column).getValueOr(0); + CallFile = toUnsigned(find(DW_AT_call_file), 0); + CallLine = toUnsigned(find(DW_AT_call_line), 0); + CallColumn = toUnsigned(find(DW_AT_call_column), 0); } void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, @@ -340,6 +323,12 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, // Dump all data in the DIE for the attributes. for (const auto &AttrSpec : AbbrevDecl->attributes()) { + if (AttrSpec.Form == DW_FORM_implicit_const) { + // We are dumping .debug_info section , + // implicit_const attribute values are not really stored here, + // but in .debug_abbrev section. So we just skip such attrs. + continue; + } dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, Indent); } @@ -361,7 +350,6 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, } } - void DWARFDie::getInlinedChainForAddress( const uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) const { if (isNULL()) @@ -399,3 +387,53 @@ DWARFDie DWARFDie::getSibling() const { return U->getSibling(Die); return DWARFDie(); } + +iterator_range<DWARFDie::attribute_iterator> +DWARFDie::attributes() const { + return make_range(attribute_iterator(*this, false), + attribute_iterator(*this, true)); +} + +DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) : + Die(D), AttrValue(0), Index(0) { + auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); + assert(AbbrDecl && "Must have abbreviation declaration"); + if (End) { + // This is the end iterator so we set the index to the attribute count. + Index = AbbrDecl->getNumAttributes(); + } else { + // This is the begin iterator so we extract the value for this->Index. + AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); + updateForIndex(*AbbrDecl, 0); + } +} + +void DWARFDie::attribute_iterator::updateForIndex( + const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { + Index = I; + // AbbrDecl must be valid befor calling this function. + auto NumAttrs = AbbrDecl.getNumAttributes(); + if (Index < NumAttrs) { + AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); + // Add the previous byte size of any previous attribute value. + AttrValue.Offset += AttrValue.ByteSize; + AttrValue.Value.setForm(AbbrDecl.getFormByIndex(Index)); + uint32_t ParseOffset = AttrValue.Offset; + auto U = Die.getDwarfUnit(); + assert(U && "Die must have valid DWARF unit"); + bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(), + &ParseOffset, U); + (void)b; + assert(b && "extractValue cannot fail on fully parsed DWARF"); + AttrValue.ByteSize = ParseOffset - AttrValue.Offset; + } else { + assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); + AttrValue.clear(); + } +} + +DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { + if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) + updateForIndex(*AbbrDecl, Index + 1); + return *this; +} diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp index dc9310dc4e89..6de57b999adc 100644 --- a/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -1,4 +1,4 @@ -//===-- DWARFFormValue.cpp ------------------------------------------------===// +//===- DWARFFormValue.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -9,16 +9,21 @@ #include "SyntaxHighlighting.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Debug.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" -#include <cassert> +#include <cinttypes> +#include <cstdint> #include <limits> + using namespace llvm; using namespace dwarf; using namespace syntax; @@ -66,13 +71,16 @@ class FormSizeHelper { public: FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) - : Version(V), AddrSize(A), Format(F) {} + : Version(V), AddrSize(A), Format(F) {} + uint8_t getAddressByteSize() const { return AddrSize; } + uint8_t getRefAddrByteSize() const { if (Version == 2) return AddrSize; return getDwarfOffsetByteSize(); } + uint8_t getDwarfOffsetByteSize() const { switch (Format) { case dwarf::DwarfFormat::DWARF32: @@ -120,14 +128,21 @@ static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { case DW_FORM_flag: case DW_FORM_data1: case DW_FORM_ref1: + case DW_FORM_strx1: + case DW_FORM_addrx1: return 1; case DW_FORM_data2: case DW_FORM_ref2: + case DW_FORM_strx2: + case DW_FORM_addrx2: return 2; case DW_FORM_data4: case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: return 4; case DW_FORM_strp: @@ -136,7 +151,6 @@ static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { case DW_FORM_line_strp: case DW_FORM_sec_offset: case DW_FORM_strp_sup: - case DW_FORM_ref_sup: if (U) return U->getDwarfOffsetByteSize(); return None; @@ -144,6 +158,7 @@ static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { case DW_FORM_data8: case DW_FORM_ref8: case DW_FORM_ref_sig8: + case DW_FORM_ref_sup8: return 8; case DW_FORM_flag_present: @@ -211,7 +226,14 @@ static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_sig8: - case DW_FORM_ref_sup: + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx4: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx4: case DW_FORM_sec_offset: case DW_FORM_strp: case DW_FORM_strp_sup: @@ -339,14 +361,21 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, case DW_FORM_data1: case DW_FORM_ref1: case DW_FORM_flag: + case DW_FORM_strx1: + case DW_FORM_addrx1: Value.uval = data.getU8(offset_ptr); break; case DW_FORM_data2: case DW_FORM_ref2: + case DW_FORM_strx2: + case DW_FORM_addrx2: Value.uval = data.getU16(offset_ptr); break; case DW_FORM_data4: - case DW_FORM_ref4: { + case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: { Value.uval = data.getU32(offset_ptr); if (!U) break; @@ -357,6 +386,7 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, } case DW_FORM_data8: case DW_FORM_ref8: + case DW_FORM_ref_sup8: Value.uval = data.getU64(offset_ptr); break; case DW_FORM_sdata: @@ -378,8 +408,7 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: case DW_FORM_line_strp: - case DW_FORM_strp_sup: - case DW_FORM_ref_sup: { + case DW_FORM_strp_sup: { if (!U) return false; RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); @@ -400,7 +429,9 @@ bool DWARFFormValue::extractValue(const DataExtractor &data, Value.uval = data.getULEB128(offset_ptr); break; default: - return false; + // DWARFFormValue::skipValue() will have caught this and caused all + // DWARF DIEs to fail to be parsed, so this code is not be reachable. + llvm_unreachable("unsupported form"); } } while (indirect); @@ -495,21 +526,18 @@ DWARFFormValue::dump(raw_ostream &OS) const { case DW_FORM_sdata: OS << Value.sval; break; case DW_FORM_udata: OS << Value.uval; break; - case DW_FORM_strp: { + case DW_FORM_strp: OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); dumpString(OS); break; - } - case DW_FORM_GNU_str_index: { + case DW_FORM_GNU_str_index: OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); dumpString(OS); break; - } - case DW_FORM_GNU_strp_alt: { + case DW_FORM_GNU_strp_alt: OS << format("alt indirect string, offset: 0x%" PRIx64 "", uvalue); dumpString(OS); break; - } case DW_FORM_ref_addr: OS << format("0x%016" PRIx64, uvalue); break; @@ -674,4 +702,3 @@ Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const { return None; return Value.uval; } - diff --git a/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp index ebb996162f1b..76354a9b1ddb 100644 --- a/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp +++ b/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp @@ -1,4 +1,4 @@ -//===-- DWARFGdbIndex.cpp -------------------------------------------------===// +//===- DWARFGdbIndex.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,10 +7,16 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <utility> using namespace llvm; diff --git a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp index 88fb20381f95..e0f819383289 100644 --- a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFTypeUnit.cpp -------------------------------------------------===// +//===- DWARFTypeUnit.cpp --------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cinttypes> using namespace llvm; @@ -26,22 +29,24 @@ bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { DWARFDie TD = getDIEForOffset(TypeOffset + getOffset()); - const char *Name = TD.getAttributeValueAsString(llvm::dwarf::DW_AT_name, ""); + const char *Name = TD.getName(DINameKind::ShortName); if (SummarizeTypes) { OS << "name = '" << Name << "'" - << " type_signature = " << format("0x%16" PRIx64, TypeHash) + << " type_signature = " << format("0x%016" PRIx64, TypeHash) << " length = " << format("0x%08x", getLength()) << '\n'; return; } OS << format("0x%08x", getOffset()) << ": Type Unit:" << " length = " << format("0x%08x", getLength()) - << " version = " << format("0x%04x", getVersion()) - << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) + << " version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << " unit_type = " << dwarf::UnitTypeString(getUnitType()); + OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset()) << " addr_size = " << format("0x%02x", getAddressByteSize()) << " name = '" << Name << "'" - << " type_signature = " << format("0x%16" PRIx64, TypeHash) + << " type_signature = " << format("0x%016" PRIx64, TypeHash) << " type_offset = " << format("0x%04x", TypeOffset) << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp index ee2c569b0bce..4ee8e8f46d2e 100644 --- a/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -13,6 +13,9 @@ #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" @@ -20,12 +23,12 @@ #include "llvm/Support/Path.h" #include <algorithm> #include <cassert> +#include <cstddef> #include <cstdint> #include <cstdio> #include <vector> -namespace llvm { - +using namespace llvm; using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { @@ -87,7 +90,15 @@ bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index, bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); Version = debug_info.getU16(offset_ptr); - uint64_t AbbrOffset = debug_info.getU32(offset_ptr); + uint64_t AbbrOffset; + if (Version >= 5) { + UnitType = debug_info.getU8(offset_ptr); + AddrSize = debug_info.getU8(offset_ptr); + AbbrOffset = debug_info.getU32(offset_ptr); + } else { + AbbrOffset = debug_info.getU32(offset_ptr); + AddrSize = debug_info.getU8(offset_ptr); + } if (IndexEntry) { if (AbbrOffset) return false; @@ -99,7 +110,6 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { return false; AbbrOffset = AbbrEntry->Offset; } - AddrSize = debug_info.getU8(offset_ptr); bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); bool VersionOK = DWARFContext::isSupportedVersion(Version); @@ -151,11 +161,11 @@ void DWARFUnit::clear() { } const char *DWARFUnit::getCompilationDir() { - return getUnitDIE().getAttributeValueAsString(DW_AT_comp_dir, nullptr); + return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); } Optional<uint64_t> DWARFUnit::getDWOId() { - return getUnitDIE().getAttributeValueAsUnsignedConstant(DW_AT_GNU_dwo_id); + return toUnsigned(getUnitDIE().find(DW_AT_GNU_dwo_id)); } void DWARFUnit::extractDIEsToVector( @@ -225,17 +235,11 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { DWARFDie UnitDie = getUnitDIE(); - auto BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_low_pc); - if (!BaseAddr) - BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_entry_pc); + auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc})); if (BaseAddr) setBaseAddress(*BaseAddr); - AddrOffsetSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_GNU_addr_base) - .getValueOr(0); - RangeSectionBase = - UnitDie.getAttributeValueAsSectionOffset(DW_AT_rnglists_base) - .getValueOr(0); + AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); + RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for // skeleton CU DIE, so that DWARF users not aware of it are not broken. } @@ -243,8 +247,7 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { return DieArray.size(); } -DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath) - : DWOU(nullptr) { +DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath) { auto Obj = object::ObjectFile::createObjectFile(DWOPath); if (!Obj) { // TODO: Actually report errors helpfully. @@ -266,17 +269,16 @@ bool DWARFUnit::parseDWO() { DWARFDie UnitDie = getUnitDIE(); if (!UnitDie) return false; - const char *DWOFileName = - UnitDie.getAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); + auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); if (!DWOFileName) return false; - const char *CompilationDir = - UnitDie.getAttributeValueAsString(DW_AT_comp_dir, nullptr); + auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); SmallString<16> AbsolutePath; - if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) { - sys::path::append(AbsolutePath, CompilationDir); + if (sys::path::is_relative(*DWOFileName) && CompilationDir && + *CompilationDir) { + sys::path::append(AbsolutePath, *CompilationDir); } - sys::path::append(AbsolutePath, DWOFileName); + sys::path::append(AbsolutePath, *DWOFileName); DWO = llvm::make_unique<DWOHolder>(AbsolutePath); DWARFUnit *DWOCU = DWO->getUnit(); // Verify that compile unit in .dwo file is valid. @@ -374,8 +376,8 @@ DWARFUnit::getInlinedChainForAddress(uint64_t Address, InlinedChain.clear(); } -const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, - DWARFSectionKind Kind) { +const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind) { if (Kind == DW_SECT_INFO) return Context.getCUIndex(); assert(Kind == DW_SECT_TYPES); @@ -413,11 +415,10 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { return DWARFDie(); // Find the next DIE whose depth is the same as the Die's depth. - for (size_t I=getDIEIndex(Die)+1, EndIdx = DieArray.size(); I<EndIdx; ++I) { + for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; + ++I) { if (DieArray[I].getDepth() == Depth) return DWARFDie(this, &DieArray[I]); } return DWARFDie(); } - -} // end namespace llvm diff --git a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp index 96b316957dfd..0981a4dfdfa5 100644 --- a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp +++ b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnitIndex.cpp ------------------------------------------------===// +//===- DWARFUnitIndex.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,16 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" - #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> -namespace llvm { +using namespace llvm; bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, uint32_t *OffsetPtr) { @@ -152,6 +156,7 @@ DWARFUnitIndex::Entry::getOffset(DWARFSectionKind Sec) const { return &Contributions[i]; return nullptr; } + const DWARFUnitIndex::Entry::SectionContribution * DWARFUnitIndex::Entry::getOffset() const { return &Contributions[Index->InfoColumn]; @@ -165,4 +170,3 @@ DWARFUnitIndex::getFromOffset(uint32_t Offset) const { return &Rows[i]; return nullptr; } -} diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp index 4f561d062b12..d4f44e446954 100644 --- a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp +++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp @@ -1,4 +1,4 @@ -//===-- SyntaxHighlighting.cpp ----------------------------------*- C++ -*-===// +//===- SyntaxHighlighting.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -9,6 +9,8 @@ #include "SyntaxHighlighting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + using namespace llvm; using namespace dwarf; using namespace syntax; @@ -18,16 +20,16 @@ static cl::opt<cl::boolOrDefault> cl::desc("use colored syntax highlighting (default=autodetect)"), cl::init(cl::BOU_UNSET)); -WithColor::WithColor(llvm::raw_ostream &OS, enum HighlightColor Type) : OS(OS) { +WithColor::WithColor(raw_ostream &OS, enum HighlightColor Type) : OS(OS) { // Detect color from terminal type unless the user passed the --color option. if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE) { switch (Type) { - case Address: OS.changeColor(llvm::raw_ostream::YELLOW); break; - case String: OS.changeColor(llvm::raw_ostream::GREEN); break; - case Tag: OS.changeColor(llvm::raw_ostream::BLUE); break; - case Attribute: OS.changeColor(llvm::raw_ostream::CYAN); break; - case Enumerator: OS.changeColor(llvm::raw_ostream::MAGENTA); break; - case Macro: OS.changeColor(llvm::raw_ostream::RED); break; + case Address: OS.changeColor(raw_ostream::YELLOW); break; + case String: OS.changeColor(raw_ostream::GREEN); break; + case Tag: OS.changeColor(raw_ostream::BLUE); break; + case Attribute: OS.changeColor(raw_ostream::CYAN); break; + case Enumerator: OS.changeColor(raw_ostream::MAGENTA); break; + case Macro: OS.changeColor(raw_ostream::RED); break; } } } diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/lib/DebugInfo/DWARF/SyntaxHighlighting.h index 16e68351d5e1..277de973dbf0 100644 --- a/lib/DebugInfo/DWARF/SyntaxHighlighting.h +++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.h @@ -1,4 +1,4 @@ -//===-- SyntaxHighlighting.h ------------------------------------*- C++ -*-===// +//===- SyntaxHighlighting.h -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,9 +10,10 @@ #ifndef LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H #define LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H -#include "llvm/Support/raw_ostream.h" - namespace llvm { + +class raw_ostream; + namespace dwarf { namespace syntax { @@ -22,18 +23,20 @@ enum HighlightColor { Address, String, Tag, Attribute, Enumerator, Macro }; /// An RAII object that temporarily switches an output stream to a /// specific color. class WithColor { - llvm::raw_ostream &OS; + raw_ostream &OS; public: /// To be used like this: WithColor(OS, syntax::String) << "text"; - WithColor(llvm::raw_ostream &OS, enum HighlightColor Type); + WithColor(raw_ostream &OS, enum HighlightColor Type); ~WithColor(); - llvm::raw_ostream& get() { return OS; } - operator llvm::raw_ostream& () { return OS; } + raw_ostream& get() { return OS; } + operator raw_ostream& () { return OS; } }; -} -} -} -#endif +} // end namespace syntax +} // end namespace dwarf + +} // end namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H diff --git a/lib/DebugInfo/MSF/CMakeLists.txt b/lib/DebugInfo/MSF/CMakeLists.txt index dcb2a8e0cc9c..6f38de336ee0 100644 --- a/lib/DebugInfo/MSF/CMakeLists.txt +++ b/lib/DebugInfo/MSF/CMakeLists.txt @@ -3,8 +3,6 @@ add_llvm_library(LLVMDebugInfoMSF MSFBuilder.cpp MSFCommon.cpp MSFError.cpp - StreamReader.cpp - StreamWriter.cpp ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/MSF" ) diff --git a/lib/DebugInfo/MSF/MappedBlockStream.cpp b/lib/DebugInfo/MSF/MappedBlockStream.cpp index e52c88a5bfb8..57953cfa338e 100644 --- a/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ b/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -11,8 +11,8 @@ #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MSFError.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" +#include "llvm/Support/BinaryStreamError.h" using namespace llvm; using namespace llvm::msf; @@ -47,22 +47,20 @@ static Interval intersect(const Interval &I1, const Interval &I2) { MappedBlockStream::MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const ReadableStream &MsfData) + BinaryStreamRef MsfData) : BlockSize(BlockSize), NumBlocks(NumBlocks), StreamLayout(Layout), MsfData(MsfData) {} std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { return llvm::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( BlockSize, NumBlocks, Layout, MsfData); } -std::unique_ptr<MappedBlockStream> -MappedBlockStream::createIndexedStream(const MSFLayout &Layout, - const ReadableStream &MsfData, - uint32_t StreamIndex) { +std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream( + const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; SL.Blocks = Layout.StreamMap[StreamIndex]; @@ -73,7 +71,7 @@ MappedBlockStream::createIndexedStream(const MSFLayout &Layout, std::unique_ptr<MappedBlockStream> MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; @@ -82,19 +80,17 @@ MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, std::unique_ptr<MappedBlockStream> MappedBlockStream::createFpmStream(const MSFLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); } Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { + ArrayRef<uint8_t> &Buffer) { // Make sure we aren't trying to read beyond the end of the stream. - if (Size > StreamLayout.Length) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - if (Offset > StreamLayout.Length - Size) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + if (auto EC = checkOffset(Offset, Size)) + return EC; if (tryReadContiguously(Offset, Size, Buffer)) return Error::success(); @@ -168,11 +164,12 @@ Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, return Error::success(); } -Error MappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { +Error MappedBlockStream::readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) { // Make sure we aren't trying to read beyond the end of the stream. - if (Offset >= StreamLayout.Length) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + if (auto EC = checkOffset(Offset, 1)) + return EC; + uint32_t First = Offset / BlockSize; uint32_t Last = First; @@ -197,10 +194,10 @@ Error MappedBlockStream::readLongestContiguousChunk( return Error::success(); } -uint32_t MappedBlockStream::getLength() const { return StreamLayout.Length; } +uint32_t MappedBlockStream::getLength() { return StreamLayout.Length; } bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { + ArrayRef<uint8_t> &Buffer) { if (Size == 0) { Buffer = ArrayRef<uint8_t>(); return true; @@ -241,15 +238,13 @@ bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, } Error MappedBlockStream::readBytes(uint32_t Offset, - MutableArrayRef<uint8_t> Buffer) const { + MutableArrayRef<uint8_t> Buffer) { uint32_t BlockNum = Offset / BlockSize; uint32_t OffsetInBlock = Offset % BlockSize; // Make sure we aren't trying to read beyond the end of the stream. - if (Buffer.size() > StreamLayout.Length) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - if (Offset > StreamLayout.Length - Buffer.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + if (auto EC = checkOffset(Offset, Buffer.size())) + return EC; uint32_t BytesLeft = Buffer.size(); uint32_t BytesWritten = 0; @@ -319,21 +314,21 @@ void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, WritableMappedBlockStream::WritableMappedBlockStream( uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const WritableStream &MsfData) + WritableBinaryStreamRef MsfData) : ReadInterface(BlockSize, NumBlocks, Layout, MsfData), WriteInterface(MsfData) {} std::unique_ptr<WritableMappedBlockStream> WritableMappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const WritableStream &MsfData) { + WritableBinaryStreamRef MsfData) { return llvm::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>( BlockSize, NumBlocks, Layout, MsfData); } std::unique_ptr<WritableMappedBlockStream> WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, - const WritableStream &MsfData, + WritableBinaryStreamRef MsfData, uint32_t StreamIndex) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; @@ -344,7 +339,7 @@ WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, std::unique_ptr<WritableMappedBlockStream> WritableMappedBlockStream::createDirectoryStream( - const MSFLayout &Layout, const WritableStream &MsfData) { + const MSFLayout &Layout, WritableBinaryStreamRef MsfData) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; @@ -353,34 +348,31 @@ WritableMappedBlockStream::createDirectoryStream( std::unique_ptr<WritableMappedBlockStream> WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, - const WritableStream &MsfData) { + WritableBinaryStreamRef MsfData) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); } Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { + ArrayRef<uint8_t> &Buffer) { return ReadInterface.readBytes(Offset, Size, Buffer); } Error WritableMappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { + uint32_t Offset, ArrayRef<uint8_t> &Buffer) { return ReadInterface.readLongestContiguousChunk(Offset, Buffer); } -uint32_t WritableMappedBlockStream::getLength() const { +uint32_t WritableMappedBlockStream::getLength() { return ReadInterface.getLength(); } Error WritableMappedBlockStream::writeBytes(uint32_t Offset, - ArrayRef<uint8_t> Buffer) const { + ArrayRef<uint8_t> Buffer) { // Make sure we aren't trying to write beyond the end of the stream. - if (Buffer.size() > getStreamLength()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - - if (Offset > getStreamLayout().Length - Buffer.size()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); + if (auto EC = checkOffset(Offset, Buffer.size())) + return EC; uint32_t BlockNum = Offset / getBlockSize(); uint32_t OffsetInBlock = Offset % getBlockSize(); @@ -410,6 +402,4 @@ Error WritableMappedBlockStream::writeBytes(uint32_t Offset, return Error::success(); } -Error WritableMappedBlockStream::commit() const { - return WriteInterface.commit(); -} +Error WritableMappedBlockStream::commit() { return WriteInterface.commit(); } diff --git a/lib/DebugInfo/MSF/StreamReader.cpp b/lib/DebugInfo/MSF/StreamReader.cpp deleted file mode 100644 index b85fd14a3b7f..000000000000 --- a/lib/DebugInfo/MSF/StreamReader.cpp +++ /dev/null @@ -1,156 +0,0 @@ -//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/StreamReader.h" - -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" - -using namespace llvm; -using namespace llvm::msf; - -StreamReader::StreamReader(ReadableStreamRef S) : Stream(S), Offset(0) {} - -Error StreamReader::readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer) { - if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) { - if (auto EC = Stream.readBytes(Offset, Size, Buffer)) - return EC; - Offset += Size; - return Error::success(); -} - -Error StreamReader::readInteger(uint8_t &Dest) { - const uint8_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(uint16_t &Dest) { - const support::ulittle16_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(uint32_t &Dest) { - const support::ulittle32_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(uint64_t &Dest) { - const support::ulittle64_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(int8_t &Dest) { - const int8_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(int16_t &Dest) { - const support::little16_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(int32_t &Dest) { - const support::little32_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(int64_t &Dest) { - const support::little64_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readZeroString(StringRef &Dest) { - uint32_t Length = 0; - // First compute the length of the string by reading 1 byte at a time. - uint32_t OriginalOffset = getOffset(); - const char *C; - do { - if (auto EC = readObject(C)) - return EC; - if (*C != '\0') - ++Length; - } while (*C != '\0'); - // Now go back and request a reference for that many bytes. - uint32_t NewOffset = getOffset(); - setOffset(OriginalOffset); - - ArrayRef<uint8_t> Data; - if (auto EC = readBytes(Data, Length)) - return EC; - Dest = StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size()); - - // Now set the offset back to where it was after we calculated the length. - setOffset(NewOffset); - return Error::success(); -} - -Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) { - ArrayRef<uint8_t> Bytes; - if (auto EC = readBytes(Bytes, Length)) - return EC; - Dest = StringRef(reinterpret_cast<const char *>(Bytes.begin()), Bytes.size()); - return Error::success(); -} - -Error StreamReader::readStreamRef(ReadableStreamRef &Ref) { - return readStreamRef(Ref, bytesRemaining()); -} - -Error StreamReader::readStreamRef(ReadableStreamRef &Ref, uint32_t Length) { - if (bytesRemaining() < Length) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - Ref = Stream.slice(Offset, Length); - Offset += Length; - return Error::success(); -} - -Error StreamReader::skip(uint32_t Amount) { - if (Amount > bytesRemaining()) - return make_error<MSFError>(msf_error_code::insufficient_buffer); - Offset += Amount; - return Error::success(); -} - -uint8_t StreamReader::peek() const { - ArrayRef<uint8_t> Buffer; - auto EC = Stream.readBytes(Offset, 1, Buffer); - assert(!EC && "Cannot peek an empty buffer!"); - llvm::consumeError(std::move(EC)); - return Buffer[0]; -} diff --git a/lib/DebugInfo/MSF/StreamWriter.cpp b/lib/DebugInfo/MSF/StreamWriter.cpp deleted file mode 100644 index cdae7c5acc04..000000000000 --- a/lib/DebugInfo/MSF/StreamWriter.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/StreamWriter.h" - -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" - -using namespace llvm; -using namespace llvm::msf; - -StreamWriter::StreamWriter(WritableStreamRef S) : Stream(S), Offset(0) {} - -Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { - if (auto EC = Stream.writeBytes(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamWriter::writeInteger(uint8_t Int) { return writeObject(Int); } - -Error StreamWriter::writeInteger(uint16_t Int) { - return writeObject(support::ulittle16_t(Int)); -} - -Error StreamWriter::writeInteger(uint32_t Int) { - return writeObject(support::ulittle32_t(Int)); -} - -Error StreamWriter::writeInteger(uint64_t Int) { - return writeObject(support::ulittle64_t(Int)); -} - -Error StreamWriter::writeInteger(int8_t Int) { return writeObject(Int); } - -Error StreamWriter::writeInteger(int16_t Int) { - return writeObject(support::little16_t(Int)); -} - -Error StreamWriter::writeInteger(int32_t Int) { - return writeObject(support::little32_t(Int)); -} - -Error StreamWriter::writeInteger(int64_t Int) { - return writeObject(support::little64_t(Int)); -} - -Error StreamWriter::writeZeroString(StringRef Str) { - if (auto EC = writeFixedString(Str)) - return EC; - if (auto EC = writeObject('\0')) - return EC; - - return Error::success(); -} - -Error StreamWriter::writeFixedString(StringRef Str) { - ArrayRef<uint8_t> Bytes(Str.bytes_begin(), Str.bytes_end()); - if (auto EC = Stream.writeBytes(Offset, Bytes)) - return EC; - - Offset += Str.size(); - return Error::success(); -} - -Error StreamWriter::writeStreamRef(ReadableStreamRef Ref) { - if (auto EC = writeStreamRef(Ref, Ref.getLength())) - return EC; - // Don't increment Offset here, it is done by the overloaded call to - // writeStreamRef. - return Error::success(); -} - -Error StreamWriter::writeStreamRef(ReadableStreamRef Ref, uint32_t Length) { - Ref = Ref.slice(0, Length); - - StreamReader SrcReader(Ref); - // This is a bit tricky. If we just call readBytes, we are requiring that it - // return us the entire stream as a contiguous buffer. For large streams this - // will allocate a huge amount of space from the pool. Instead, iterate over - // each contiguous chunk until we've consumed the entire stream. - while (SrcReader.bytesRemaining() > 0) { - ArrayRef<uint8_t> Chunk; - if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) - return EC; - if (auto EC = writeBytes(Chunk)) - return EC; - } - return Error::success(); -} diff --git a/lib/DebugInfo/PDB/CMakeLists.txt b/lib/DebugInfo/PDB/CMakeLists.txt index 599f01eaf74f..f87a0b0a72e2 100644 --- a/lib/DebugInfo/PDB/CMakeLists.txt +++ b/lib/DebugInfo/PDB/CMakeLists.txt @@ -27,31 +27,38 @@ if(LLVM_ENABLE_DIA_SDK) set(LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/DIA") endif() -add_pdb_impl_folder(Raw - Raw/DbiStream.cpp - Raw/DbiStreamBuilder.cpp - Raw/EnumTables.cpp - Raw/GlobalsStream.cpp - Raw/GSI.cpp - Raw/Hash.cpp - Raw/InfoStream.cpp - Raw/InfoStreamBuilder.cpp - Raw/ModInfo.cpp - Raw/ModStream.cpp - Raw/NameHashTable.cpp - Raw/NameMap.cpp - Raw/NameMapBuilder.cpp - Raw/PDBFile.cpp - Raw/PDBFileBuilder.cpp - Raw/PublicsStream.cpp - Raw/RawError.cpp - Raw/RawSession.cpp - Raw/SymbolStream.cpp - Raw/TpiHashing.cpp - Raw/TpiStream.cpp - Raw/TpiStreamBuilder.cpp) +add_pdb_impl_folder(Native + Native/DbiStream.cpp + Native/DbiStreamBuilder.cpp + Native/EnumTables.cpp + Native/GlobalsStream.cpp + Native/GSI.cpp + Native/Hash.cpp + Native/HashTable.cpp + Native/InfoStream.cpp + Native/InfoStreamBuilder.cpp + Native/ModInfo.cpp + Native/ModInfoBuilder.cpp + Native/ModStream.cpp + Native/NativeCompilandSymbol.cpp + Native/NativeEnumModules.cpp + Native/NativeExeSymbol.cpp + Native/NativeRawSymbol.cpp + Native/NamedStreamMap.cpp + Native/NativeSession.cpp + Native/PDBFile.cpp + Native/PDBFileBuilder.cpp + Native/PDBTypeServerHandler.cpp + Native/PublicsStream.cpp + Native/RawError.cpp + Native/StringTable.cpp + Native/StringTableBuilder.cpp + Native/SymbolStream.cpp + Native/TpiHashing.cpp + Native/TpiStream.cpp + Native/TpiStreamBuilder.cpp) -list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Raw") +list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Native") list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") add_llvm_library(LLVMDebugInfoPDB @@ -94,6 +101,7 @@ add_llvm_library(LLVMDebugInfoPDB PDBSymbolUnknown.cpp PDBSymbolUsingNamespace.cpp PDBSymDumper.cpp + UDTLayout.cpp ${PDB_IMPL_SOURCES} ADDITIONAL_HEADER_DIRS diff --git a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp index bba5b0f94dca..5e8c0bdc171d 100644 --- a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp +++ b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp @@ -10,9 +10,13 @@ #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" @@ -178,9 +182,10 @@ void DumpDIAValue(llvm::raw_ostream &OS, int Indent, StringRef Name, } namespace llvm { -raw_ostream &operator<<(raw_ostream &OS, const GUID &Guid) { - const PDB_UniqueId *Id = reinterpret_cast<const PDB_UniqueId *>(&Guid); - OS << *Id; +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const GUID &G) { + StringRef GuidBytes(reinterpret_cast<const char *>(&G), sizeof(G)); + codeview::detail::GuidAdapter A(GuidBytes); + A.format(OS, ""); return OS; } } @@ -715,6 +720,18 @@ uint32_t DIARawSymbol::getVirtualTableShapeId() const { return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualTableShapeId); } +std::unique_ptr<PDBSymbolTypeVTable> +DIARawSymbol::getVirtualBaseTableType() const { + CComPtr<IDiaSymbol> TableType; + if (FAILED(Symbol->get_virtualBaseTableType(&TableType)) || !TableType) + return nullptr; + + auto RawVT = llvm::make_unique<DIARawSymbol>(Session, TableType); + auto Pointer = + llvm::make_unique<PDBSymbolTypePointer>(Session, std::move(RawVT)); + return unique_dyn_cast<PDBSymbolTypeVTable>(Pointer->getPointeeType()); +} + PDB_DataKind DIARawSymbol::getDataKind() const { return PrivateGetDIAValue<DWORD, PDB_DataKind>(Symbol, &IDiaSymbol::get_dataKind); diff --git a/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/lib/DebugInfo/PDB/Native/DbiStream.cpp index 4f4a0cf65785..b9f53578d326 100644 --- a/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -7,21 +7,20 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include <algorithm> #include <cstddef> @@ -35,7 +34,7 @@ using namespace llvm::support; template <typename ContribType> static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, - StreamReader &Reader) { + BinaryStreamReader &Reader) { if (Reader.bytesRemaining() % sizeof(ContribType) != 0) return make_error<RawError>( raw_error_code::corrupt_file, @@ -48,13 +47,12 @@ static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, } DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) - : Pdb(File), Stream(std::move(Stream)), Header(nullptr) { -} + : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {} DbiStream::~DbiStream() = default; Error DbiStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); if (Stream->getLength() < sizeof(DbiStreamHeader)) return make_error<RawError>(raw_error_code::corrupt_file, @@ -127,8 +125,8 @@ Error DbiStream::reload() { return EC; if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize)) return EC; - if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize / - sizeof(ulittle16_t))) + if (auto EC = Reader.readArray( + DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t))) return EC; if (auto EC = initializeSectionContributionData()) @@ -147,7 +145,7 @@ Error DbiStream::reload() { "Found unexpected bytes in DBI Stream."); if (ECSubstream.getLength() > 0) { - StreamReader ECReader(ECSubstream); + BinaryStreamReader ECReader(ECSubstream); if (auto EC = ECNames.load(ECReader)) return EC; } @@ -209,16 +207,16 @@ PDB_Machine DbiStream::getMachineType() const { return static_cast<PDB_Machine>(Machine); } -msf::FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() { +FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() { return SectionHeaders; } -msf::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { +FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { return FpoRecords; } ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; } -msf::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { +FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { return SectionMap; } @@ -237,7 +235,7 @@ Error DbiStream::initializeSectionContributionData() { if (SecContrSubstream.getLength() == 0) return Error::success(); - StreamReader SCReader(SecContrSubstream); + BinaryStreamReader SCReader(SecContrSubstream); if (auto EC = SCReader.readEnum(SectionContribVersion)) return EC; @@ -256,7 +254,7 @@ Error DbiStream::initializeModInfoArray() { // Since each ModInfo in the stream is a variable length, we have to iterate // them to know how many there actually are. - StreamReader Reader(ModInfoSubstream); + BinaryStreamReader Reader(ModInfoSubstream); VarStreamArray<ModInfo> ModInfoArray; if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength())) @@ -286,7 +284,7 @@ Error DbiStream::initializeSectionHeadersData() { "Corrupted section header stream."); size_t NumSections = StreamLen / sizeof(object::coff_section); - msf::StreamReader Reader(*SHS); + BinaryStreamReader Reader(*SHS); if (auto EC = Reader.readArray(SectionHeaders, NumSections)) return make_error<RawError>(raw_error_code::corrupt_file, "Could not read a bitmap."); @@ -318,7 +316,7 @@ Error DbiStream::initializeFpoRecords() { "Corrupted New FPO stream."); size_t NumRecords = StreamLen / sizeof(object::FpoData); - msf::StreamReader Reader(*FS); + BinaryStreamReader Reader(*FS); if (auto EC = Reader.readArray(FpoRecords, NumRecords)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted New FPO stream."); @@ -330,7 +328,7 @@ Error DbiStream::initializeSectionMapData() { if (SecMapSubstream.getLength() == 0) return Error::success(); - StreamReader SMReader(SecMapSubstream); + BinaryStreamReader SMReader(SecMapSubstream); const SecMapHeader *Header; if (auto EC = SMReader.readObject(Header)) return EC; @@ -344,7 +342,7 @@ Error DbiStream::initializeFileInfo() { return Error::success(); const FileInfoSubstreamHeader *FH; - StreamReader FISR(FileInfoSubstream); + BinaryStreamReader FISR(FileInfoSubstream); if (auto EC = FISR.readObject(FH)) return EC; @@ -413,14 +411,14 @@ uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { } Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { - StreamReader Names(NamesBuffer); + BinaryStreamReader Names(NamesBuffer); if (Index >= FileNameOffsets.size()) return make_error<RawError>(raw_error_code::index_out_of_bounds); uint32_t FileOffset = FileNameOffsets[Index]; Names.setOffset(FileOffset); StringRef Name; - if (auto EC = Names.readZeroString(Name)) + if (auto EC = Names.readCString(Name)) return std::move(EC); return Name; } diff --git a/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index 1d5b8d693b1e..a203aea60fe7 100644 --- a/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -7,15 +7,16 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/COFF.h" using namespace llvm; @@ -23,15 +24,13 @@ using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -namespace { -class ModiSubstreamBuilder {}; -} - DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf) : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {} +DbiStreamBuilder::~DbiStreamBuilder() {} + void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } @@ -75,39 +74,37 @@ uint32_t DbiStreamBuilder::calculateSerializedLength() const { calculateSectionMapStreamSize() + calculateDbgStreamsSize(); } -Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) { - auto Entry = llvm::make_unique<ModuleInfo>(); - ModuleInfo *M = Entry.get(); - Entry->Mod = Module; - Entry->Obj = ObjFile; - auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry))); +Expected<ModInfoBuilder &> +DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { + uint32_t Index = ModiList.size(); + auto MIB = llvm::make_unique<ModInfoBuilder>(ModuleName, Index, Msf); + auto M = MIB.get(); + auto Result = ModiMap.insert(std::make_pair(ModuleName, std::move(MIB))); + if (!Result.second) return make_error<RawError>(raw_error_code::duplicate_entry, "The specified module already exists"); - ModuleInfoList.push_back(M); - return Error::success(); + ModiList.push_back(M); + return *M; } Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { - auto ModIter = ModuleInfos.find(Module); - if (ModIter == ModuleInfos.end()) + auto ModIter = ModiMap.find(Module); + if (ModIter == ModiMap.end()) return make_error<RawError>(raw_error_code::no_entry, "The specified module was not found"); uint32_t Index = SourceFileNames.size(); SourceFileNames.insert(std::make_pair(File, Index)); auto &ModEntry = *ModIter; - ModEntry.second->SourceFiles.push_back(File); + ModEntry.second->addSourceFile(File); return Error::success(); } uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { uint32_t Size = 0; - for (const auto &M : ModuleInfoList) { - Size += sizeof(ModuleInfoHeader); - Size += M->Mod.size() + 1; - Size += M->Obj.size() + 1; - } - return alignTo(Size, sizeof(uint32_t)); + for (const auto &M : ModiList) + Size += M->calculateSerializedLength(); + return Size; } uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const { @@ -127,11 +124,11 @@ uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { uint32_t Size = 0; Size += sizeof(ulittle16_t); // NumModules Size += sizeof(ulittle16_t); // NumSourceFiles - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices - Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts + Size += ModiList.size() * sizeof(ulittle16_t); // ModIndices + Size += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts uint32_t NumFileInfos = 0; - for (const auto &M : ModuleInfoList) - NumFileInfos += M->SourceFiles.size(); + for (const auto &M : ModiList) + NumFileInfos += M->source_files().size(); Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets Size += calculateNamesBufferSize(); return alignTo(Size, sizeof(uint32_t)); @@ -149,43 +146,20 @@ uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const { return DbgStreams.size() * sizeof(uint16_t); } -Error DbiStreamBuilder::generateModiSubstream() { - uint32_t Size = calculateModiSubstreamSize(); - auto Data = Allocator.Allocate<uint8_t>(Size); - - ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size)); - - StreamWriter ModiWriter(ModInfoBuffer); - for (const auto &M : ModuleInfoList) { - ModuleInfoHeader Layout = {}; - Layout.ModDiStream = kInvalidStreamIndex; - Layout.NumFiles = M->SourceFiles.size(); - if (auto EC = ModiWriter.writeObject(Layout)) - return EC; - if (auto EC = ModiWriter.writeZeroString(M->Mod)) - return EC; - if (auto EC = ModiWriter.writeZeroString(M->Obj)) - return EC; - } - if (ModiWriter.bytesRemaining() > sizeof(uint32_t)) - return make_error<RawError>(raw_error_code::invalid_format, - "Unexpected bytes in Modi Stream Data"); - return Error::success(); -} - Error DbiStreamBuilder::generateFileInfoSubstream() { uint32_t Size = calculateFileInfoSubstreamSize(); uint32_t NameSize = calculateNamesBufferSize(); auto Data = Allocator.Allocate<uint8_t>(Size); uint32_t NamesOffset = Size - NameSize; - FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size)); + FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size), + llvm::support::little); - WritableStreamRef MetadataBuffer = - WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset); - StreamWriter MetadataWriter(MetadataBuffer); + WritableBinaryStreamRef MetadataBuffer = + WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); + BinaryStreamWriter MetadataWriter(MetadataBuffer); - uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size()); + uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size()); uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules return EC; @@ -195,8 +169,8 @@ Error DbiStreamBuilder::generateFileInfoSubstream() { if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices return EC; } - for (const auto MI : ModuleInfoList) { - FileCount = static_cast<uint16_t>(MI->SourceFiles.size()); + for (const auto &MI : ModiList) { + FileCount = static_cast<uint16_t>(MI->source_files().size()); if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts return EC; } @@ -205,16 +179,16 @@ Error DbiStreamBuilder::generateFileInfoSubstream() { // A side effect of this is that this will actually compute the various // file name offsets, so we can then go back and write the FileNameOffsets // array to the other substream. - NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset); - StreamWriter NameBufferWriter(NamesBuffer); + NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset); + BinaryStreamWriter NameBufferWriter(NamesBuffer); for (auto &Name : SourceFileNames) { Name.second = NameBufferWriter.getOffset(); - if (auto EC = NameBufferWriter.writeZeroString(Name.getKey())) + if (auto EC = NameBufferWriter.writeCString(Name.getKey())) return EC; } - for (const auto MI : ModuleInfoList) { - for (StringRef Name : MI->SourceFiles) { + for (const auto &MI : ModiList) { + for (StringRef Name : MI->source_files()) { auto Result = SourceFileNames.find(Name); if (Result == SourceFileNames.end()) return make_error<RawError>(raw_error_code::no_entry, @@ -240,13 +214,13 @@ Error DbiStreamBuilder::finalize() { if (Header) return Error::success(); - DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); + for (auto &MI : ModiList) + MI->finalize(); - if (auto EC = generateModiSubstream()) - return EC; if (auto EC = generateFileInfoSubstream()) return EC; + DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); H->VersionHeader = *VerHeader; H->VersionSignature = -1; H->Age = Age; @@ -258,7 +232,7 @@ Error DbiStreamBuilder::finalize() { H->ECSubstreamSize = 0; H->FileInfoSize = FileInfoBuffer.getLength(); - H->ModiSubstreamSize = ModInfoBuffer.getLength(); + H->ModiSubstreamSize = calculateModiSubstreamSize(); H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); H->SectionMapSize = calculateSectionMapStreamSize(); @@ -273,6 +247,11 @@ Error DbiStreamBuilder::finalize() { } Error DbiStreamBuilder::finalizeMsfLayout() { + for (auto &MI : ModiList) { + if (auto EC = MI->finalizeMsfLayout()) + return EC; + } + uint32_t Length = calculateSerializedLength(); if (auto EC = Msf.setStreamSize(StreamDBI, Length)) return EC; @@ -358,19 +337,21 @@ std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap( } Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) { + WritableBinaryStreamRef MsfBuffer) { if (auto EC = finalize()) return EC; - auto InfoS = - WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI); + auto DbiS = WritableMappedBlockStream::createIndexedStream(Layout, MsfBuffer, + StreamDBI); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*DbiS); if (auto EC = Writer.writeObject(*Header)) return EC; - if (auto EC = Writer.writeStreamRef(ModInfoBuffer)) - return EC; + for (auto &M : ModiList) { + if (auto EC = M->commit(Writer, Layout, MsfBuffer)) + return EC; + } if (!SectionContribs.empty()) { if (auto EC = Writer.writeEnum(DbiSecContribVer60)) @@ -399,8 +380,8 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, if (Stream.StreamNumber == kInvalidStreamIndex) continue; auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, Stream.StreamNumber); - StreamWriter DbgStreamWriter(*WritableStream); + Layout, MsfBuffer, Stream.StreamNumber); + BinaryStreamWriter DbgStreamWriter(*WritableStream); if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) return EC; } diff --git a/lib/DebugInfo/PDB/Raw/EnumTables.cpp b/lib/DebugInfo/PDB/Native/EnumTables.cpp index fc9270c69947..b3837dc72e5b 100644 --- a/lib/DebugInfo/PDB/Raw/EnumTables.cpp +++ b/lib/DebugInfo/PDB/Native/EnumTables.cpp @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/EnumTables.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/EnumTables.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" using namespace llvm; using namespace llvm::pdb; diff --git a/lib/DebugInfo/PDB/Raw/GSI.cpp b/lib/DebugInfo/PDB/Native/GSI.cpp index 6ecbb5c8cfad..b219fe275f73 100644 --- a/lib/DebugInfo/PDB/Raw/GSI.cpp +++ b/lib/DebugInfo/PDB/Native/GSI.cpp @@ -9,10 +9,10 @@ #include "GSI.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" @@ -28,9 +28,9 @@ static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { return Error::success(); } -Error readGSIHashBuckets( - msf::FixedStreamArray<support::ulittle32_t> &HashBuckets, - const GSIHashHeader *HashHdr, msf::StreamReader &Reader) { +Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, + const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader) { if (auto EC = checkHashHdrVersion(HashHdr)) return EC; @@ -57,7 +57,7 @@ Error readGSIHashBuckets( } Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - msf::StreamReader &Reader) { + BinaryStreamReader &Reader) { if (Reader.readObject(HashHdr)) return make_error<RawError>(raw_error_code::corrupt_file, "Stream does not contain a GSIHashHeader."); @@ -70,9 +70,9 @@ Error readGSIHashHeader(const GSIHashHeader *&HashHdr, return Error::success(); } -Error readGSIHashRecords(msf::FixedStreamArray<PSHashRecord> &HashRecords, +Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, const GSIHashHeader *HashHdr, - msf::StreamReader &Reader) { + BinaryStreamReader &Reader) { if (auto EC = checkHashHdrVersion(HashHdr)) return EC; diff --git a/lib/DebugInfo/PDB/Raw/GSI.h b/lib/DebugInfo/PDB/Native/GSI.h index 82cebd946538..9e63bc83548f 100644 --- a/lib/DebugInfo/PDB/Raw/GSI.h +++ b/lib/DebugInfo/PDB/Native/GSI.h @@ -25,17 +25,15 @@ #ifndef LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H #define LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class StreamReader; -} +class BinaryStreamReader; namespace pdb { @@ -56,14 +54,14 @@ struct GSIHashHeader { support::ulittle32_t NumBuckets; }; -Error readGSIHashBuckets( - msf::FixedStreamArray<support::ulittle32_t> &HashBuckets, - const GSIHashHeader *HashHdr, msf::StreamReader &Reader); +Error readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, + const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader); Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - msf::StreamReader &Reader); -Error readGSIHashRecords(msf::FixedStreamArray<PSHashRecord> &HashRecords, + BinaryStreamReader &Reader); +Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, const GSIHashHeader *HashHdr, - msf::StreamReader &Reader); + BinaryStreamReader &Reader); } } diff --git a/lib/DebugInfo/PDB/Raw/GlobalsStream.cpp b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp index 31afc9200b1b..a2ee0f047c58 100644 --- a/lib/DebugInfo/PDB/Raw/GlobalsStream.cpp +++ b/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "GSI.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -23,7 +23,7 @@ GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream) GlobalsStream::~GlobalsStream() = default; Error GlobalsStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); const GSIHashHeader *HashHdr; if (auto EC = readGSIHashHeader(HashHdr, Reader)) diff --git a/lib/DebugInfo/PDB/Raw/Hash.cpp b/lib/DebugInfo/PDB/Native/Hash.cpp index b9f685ec69d4..2ad3f55dc5c3 100644 --- a/lib/DebugInfo/PDB/Raw/Hash.cpp +++ b/lib/DebugInfo/PDB/Native/Hash.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/Hash.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" diff --git a/lib/DebugInfo/PDB/Native/HashTable.cpp b/lib/DebugInfo/PDB/Native/HashTable.cpp new file mode 100644 index 000000000000..ebf8c9c04db1 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/HashTable.cpp @@ -0,0 +1,302 @@ +//===- HashTable.cpp - PDB Hash Table ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/HashTable.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" + +#include <assert.h> + +using namespace llvm; +using namespace llvm::pdb; + +HashTable::HashTable() : HashTable(8) {} + +HashTable::HashTable(uint32_t Capacity) { Buckets.resize(Capacity); } + +Error HashTable::load(BinaryStreamReader &Stream) { + const Header *H; + if (auto EC = Stream.readObject(H)) + return EC; + if (H->Capacity == 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid Hash Table Capacity"); + if (H->Size > maxLoad(H->Capacity)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid Hash Table Size"); + + Buckets.resize(H->Capacity); + + if (auto EC = readSparseBitVector(Stream, Present)) + return EC; + if (Present.count() != H->Size) + return make_error<RawError>(raw_error_code::corrupt_file, + "Present bit vector does not match size!"); + + if (auto EC = readSparseBitVector(Stream, Deleted)) + return EC; + if (Present.intersects(Deleted)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Present bit vector interesects deleted!"); + + for (uint32_t P : Present) { + if (auto EC = Stream.readInteger(Buckets[P].first)) + return EC; + if (auto EC = Stream.readInteger(Buckets[P].second)) + return EC; + } + + return Error::success(); +} + +uint32_t HashTable::calculateSerializedLength() const { + uint32_t Size = sizeof(Header); + + int NumBitsP = Present.find_last() + 1; + int NumBitsD = Deleted.find_last() + 1; + + // Present bit set number of words, followed by that many actual words. + Size += sizeof(uint32_t); + Size += alignTo(NumBitsP, sizeof(uint32_t)); + + // Deleted bit set number of words, followed by that many actual words. + Size += sizeof(uint32_t); + Size += alignTo(NumBitsD, sizeof(uint32_t)); + + // One (Key, Value) pair for each entry Present. + Size += 2 * sizeof(uint32_t) * size(); + + return Size; +} + +Error HashTable::commit(BinaryStreamWriter &Writer) const { + Header H; + H.Size = size(); + H.Capacity = capacity(); + if (auto EC = Writer.writeObject(H)) + return EC; + + if (auto EC = writeSparseBitVector(Writer, Present)) + return EC; + + if (auto EC = writeSparseBitVector(Writer, Deleted)) + return EC; + + for (const auto &Entry : *this) { + if (auto EC = Writer.writeInteger(Entry.first)) + return EC; + if (auto EC = Writer.writeInteger(Entry.second)) + return EC; + } + return Error::success(); +} + +void HashTable::clear() { + Buckets.resize(8); + Present.clear(); + Deleted.clear(); +} + +uint32_t HashTable::capacity() const { return Buckets.size(); } +uint32_t HashTable::size() const { return Present.count(); } + +HashTableIterator HashTable::begin() const { return HashTableIterator(*this); } +HashTableIterator HashTable::end() const { + return HashTableIterator(*this, 0, true); +} + +HashTableIterator HashTable::find(uint32_t K) { + uint32_t H = K % capacity(); + uint32_t I = H; + Optional<uint32_t> FirstUnused; + do { + if (isPresent(I)) { + if (Buckets[I].first == K) + return HashTableIterator(*this, I, false); + } else { + if (!FirstUnused) + FirstUnused = I; + // Insertion occurs via linear probing from the slot hint, and will be + // inserted at the first empty / deleted location. Therefore, if we are + // probing and find a location that is neither present nor deleted, then + // nothing must have EVER been inserted at this location, and thus it is + // not possible for a matching value to occur later. + if (!isDeleted(I)) + break; + } + I = (I + 1) % capacity(); + } while (I != H); + + // The only way FirstUnused would not be set is if every single entry in the + // table were Present. But this would violate the load factor constraints + // that we impose, so it should never happen. + assert(FirstUnused); + return HashTableIterator(*this, *FirstUnused, true); +} + +void HashTable::set(uint32_t K, uint32_t V) { + auto Entry = find(K); + if (Entry != end()) { + assert(isPresent(Entry.index())); + assert(Buckets[Entry.index()].first == K); + // We're updating, no need to do anything special. + Buckets[Entry.index()].second = V; + return; + } + + auto &B = Buckets[Entry.index()]; + assert(!isPresent(Entry.index())); + assert(Entry.isEnd()); + B.first = K; + B.second = V; + Present.set(Entry.index()); + Deleted.reset(Entry.index()); + + grow(); + + assert(find(K) != end()); +} + +void HashTable::remove(uint32_t K) { + auto Iter = find(K); + // It wasn't here to begin with, just exit. + if (Iter == end()) + return; + + assert(Present.test(Iter.index())); + assert(!Deleted.test(Iter.index())); + Deleted.set(Iter.index()); + Present.reset(Iter.index()); +} + +uint32_t HashTable::get(uint32_t K) { + auto I = find(K); + assert(I != end()); + return (*I).second; +} + +uint32_t HashTable::maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; } + +void HashTable::grow() { + uint32_t S = size(); + if (S < maxLoad(capacity())) + return; + assert(capacity() != UINT32_MAX && "Can't grow Hash table!"); + + uint32_t NewCapacity = + (capacity() <= INT32_MAX) ? capacity() * 2 : UINT32_MAX; + + // Growing requires rebuilding the table and re-hashing every item. Make a + // copy with a larger capacity, insert everything into the copy, then swap + // it in. + HashTable NewMap(NewCapacity); + for (auto I : Present) { + NewMap.set(Buckets[I].first, Buckets[I].second); + } + + Buckets.swap(NewMap.Buckets); + std::swap(Present, NewMap.Present); + std::swap(Deleted, NewMap.Deleted); + assert(capacity() == NewCapacity); + assert(size() == S); +} + +Error HashTable::readSparseBitVector(BinaryStreamReader &Stream, + SparseBitVector<> &V) { + uint32_t NumWords; + if (auto EC = Stream.readInteger(NumWords)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected hash table number of words")); + + for (uint32_t I = 0; I != NumWords; ++I) { + uint32_t Word; + if (auto EC = Stream.readInteger(Word)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected hash table word")); + for (unsigned Idx = 0; Idx < 32; ++Idx) + if (Word & (1U << Idx)) + V.set((I * 32) + Idx); + } + return Error::success(); +} + +Error HashTable::writeSparseBitVector(BinaryStreamWriter &Writer, + SparseBitVector<> &Vec) { + int ReqBits = Vec.find_last() + 1; + uint32_t NumWords = alignTo(ReqBits, sizeof(uint32_t)) / sizeof(uint32_t); + if (auto EC = Writer.writeInteger(NumWords)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not write linear map number of words")); + + uint32_t Idx = 0; + for (uint32_t I = 0; I != NumWords; ++I) { + uint32_t Word = 0; + for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) { + if (Vec.test(Idx)) + Word |= (1 << WordIdx); + } + if (auto EC = Writer.writeInteger(Word)) + return joinErrors(std::move(EC), make_error<RawError>( + raw_error_code::corrupt_file, + "Could not write linear map word")); + } + return Error::success(); +} + +HashTableIterator::HashTableIterator(const HashTable &Map, uint32_t Index, + bool IsEnd) + : Map(&Map), Index(Index), IsEnd(IsEnd) {} + +HashTableIterator::HashTableIterator(const HashTable &Map) : Map(&Map) { + int I = Map.Present.find_first(); + if (I == -1) { + Index = 0; + IsEnd = true; + } else { + Index = static_cast<uint32_t>(I); + IsEnd = false; + } +} + +HashTableIterator &HashTableIterator::operator=(const HashTableIterator &R) { + Map = R.Map; + return *this; +} + +bool HashTableIterator::operator==(const HashTableIterator &R) const { + if (IsEnd && R.IsEnd) + return true; + if (IsEnd != R.IsEnd) + return false; + + return (Map == R.Map) && (Index == R.Index); +} + +const std::pair<uint32_t, uint32_t> &HashTableIterator::operator*() const { + assert(Map->Present.test(Index)); + return Map->Buckets[Index]; +} + +HashTableIterator &HashTableIterator::operator++() { + while (Index < Map->Buckets.size()) { + ++Index; + if (Map->Present.test(Index)) + return *this; + } + + IsEnd = true; + return *this; +} diff --git a/lib/DebugInfo/PDB/Native/InfoStream.cpp b/lib/DebugInfo/PDB/Native/InfoStream.cpp new file mode 100644 index 000000000000..2a1d12e82390 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -0,0 +1,126 @@ +//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- 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/PDB/Native/InfoStream.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +Error InfoStream::reload() { + BinaryStreamReader Reader(*Stream); + + const InfoStreamHeader *H; + if (auto EC = Reader.readObject(H)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "PDB Stream does not contain a header.")); + + switch (H->Version) { + case PdbImplVC70: + case PdbImplVC80: + case PdbImplVC110: + case PdbImplVC140: + break; + default: + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported PDB stream version."); + } + + Version = H->Version; + Signature = H->Signature; + Age = H->Age; + Guid = H->Guid; + + uint32_t Offset = Reader.getOffset(); + if (auto EC = NamedStreams.load(Reader)) + return EC; + uint32_t NewOffset = Reader.getOffset(); + NamedStreamMapByteSize = NewOffset - Offset; + + bool Stop = false; + while (!Stop && !Reader.empty()) { + PdbRaw_FeatureSig Sig; + if (auto EC = Reader.readEnum(Sig)) + return EC; + // Since this value comes from a file, it's possible we have some strange + // value which doesn't correspond to any value. We don't want to warn on + // -Wcovered-switch-default in this case, so switch on the integral value + // instead of the enumeration value. + switch (uint32_t(Sig)) { + case uint32_t(PdbRaw_FeatureSig::VC110): + // No other flags for VC110 PDB. + Stop = true; + LLVM_FALLTHROUGH; + case uint32_t(PdbRaw_FeatureSig::VC140): + Features |= PdbFeatureContainsIdStream; + break; + case uint32_t(PdbRaw_FeatureSig::NoTypeMerge): + Features |= PdbFeatureNoTypeMerging; + break; + case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo): + Features |= PdbFeatureMinimalDebugInfo; + default: + continue; + } + FeatureSignatures.push_back(Sig); + } + return Error::success(); +} + +uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); } + +uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { + uint32_t Result; + if (!NamedStreams.get(Name, Result)) + return 0; + return Result; +} + +iterator_range<StringMapConstIterator<uint32_t>> +InfoStream::named_streams() const { + return NamedStreams.entries(); +} + +PdbRaw_ImplVer InfoStream::getVersion() const { + return static_cast<PdbRaw_ImplVer>(Version); +} + +uint32_t InfoStream::getSignature() const { return Signature; } + +uint32_t InfoStream::getAge() const { return Age; } + +PDB_UniqueId InfoStream::getGuid() const { return Guid; } + +uint32_t InfoStream::getNamedStreamMapByteSize() const { + return NamedStreamMapByteSize; +} + +PdbRaw_Features InfoStream::getFeatures() const { return Features; } + +ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const { + return FeatureSignatures; +} + +const NamedStreamMap &InfoStream::getNamedStreams() const { + return NamedStreams; +} diff --git a/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index 73fbf853b4f7..f019d410328a 100644 --- a/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -7,22 +7,26 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf) - : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0) {} +InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, + NamedStreamMap &NamedStreams) + : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0), + NamedStreams(NamedStreams) {} void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } @@ -32,26 +36,23 @@ void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; } -NameMapBuilder &InfoStreamBuilder::getNamedStreamsBuilder() { - return NamedStreams; -} - -uint32_t InfoStreamBuilder::calculateSerializedLength() const { - return sizeof(InfoStreamHeader) + NamedStreams.calculateSerializedLength(); +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); } Error InfoStreamBuilder::finalizeMsfLayout() { - uint32_t Length = calculateSerializedLength(); + uint32_t Length = sizeof(InfoStreamHeader) + NamedStreams.finalize() + + (Features.size() + 1) * sizeof(uint32_t); if (auto EC = Msf.setStreamSize(StreamPDB, Length)) return EC; return Error::success(); } Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const { + WritableBinaryStreamRef Buffer) const { auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*InfoS); InfoStreamHeader H; H.Age = Age; @@ -61,5 +62,13 @@ Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, if (auto EC = Writer.writeObject(H)) return EC; - return NamedStreams.commit(Writer); + if (auto EC = NamedStreams.commit(Writer)) + return EC; + if (auto EC = Writer.writeInteger(0)) + return EC; + for (auto E : Features) { + if (auto EC = Writer.writeEnum(E)) + return EC; + } + return Error::success(); } diff --git a/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/lib/DebugInfo/PDB/Native/ModInfo.cpp index b34d7700d036..1405286fd088 100644 --- a/lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ b/lib/DebugInfo/PDB/Native/ModInfo.cpp @@ -7,16 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include <cstdint> using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; @@ -26,15 +25,15 @@ ModInfo::ModInfo(const ModInfo &Info) = default; ModInfo::~ModInfo() = default; -Error ModInfo::initialize(ReadableStreamRef Stream, ModInfo &Info) { - StreamReader Reader(Stream); +Error ModInfo::initialize(BinaryStreamRef Stream, ModInfo &Info) { + BinaryStreamReader Reader(Stream); if (auto EC = Reader.readObject(Info.Layout)) return EC; - if (auto EC = Reader.readZeroString(Info.ModuleName)) + if (auto EC = Reader.readCString(Info.ModuleName)) return EC; - if (auto EC = Reader.readZeroString(Info.ObjFileName)) + if (auto EC = Reader.readCString(Info.ObjFileName)) return EC; return Error::success(); } diff --git a/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp b/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp new file mode 100644 index 000000000000..73c45a953520 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/ModInfoBuilder.cpp @@ -0,0 +1,136 @@ +//===- ModInfoBuilder.cpp - PDB Module Info Stream Creation -----*- 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/PDB/Native/ModInfoBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/COFF.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace llvm { +template <> struct BinaryItemTraits<CVSymbol> { + static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); } + + static ArrayRef<uint8_t> bytes(const CVSymbol &Item) { + return Item.RecordData; + } +}; +} + +static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) { + uint32_t Size = sizeof(uint32_t); // Signature + Size += SymbolByteSize; // Symbol Data + Size += 0; // TODO: Layout.LineBytes + Size += 0; // TODO: Layout.C13Bytes + Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) + Size += 0; // GlobalRefs substream bytes + return Size; +} + +ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex, + msf::MSFBuilder &Msf) + : MSF(Msf), ModuleName(ModuleName) { + Layout.Mod = ModIndex; +} + +uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; } + +void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; } + +void ModInfoBuilder::addSymbol(CVSymbol Symbol) { + Symbols.push_back(Symbol); + SymbolByteSize += Symbol.data().size(); +} + +void ModInfoBuilder::addSourceFile(StringRef Path) { + SourceFiles.push_back(Path); +} + +uint32_t ModInfoBuilder::calculateSerializedLength() const { + uint32_t L = sizeof(Layout); + uint32_t M = ModuleName.size() + 1; + uint32_t O = ObjFileName.size() + 1; + return alignTo(L + M + O, sizeof(uint32_t)); +} + +void ModInfoBuilder::finalize() { + Layout.C13Bytes = 0; + Layout.FileNameOffs = 0; // TODO: Fix this + Layout.Flags = 0; // TODO: Fix this + Layout.LineBytes = 0; + (void)Layout.Mod; // Set in constructor + (void)Layout.ModDiStream; // Set in finalizeMsfLayout + Layout.NumFiles = SourceFiles.size(); + Layout.PdbFilePathNI = 0; + Layout.SrcFileNameNI = 0; + + // This value includes both the signature field as well as the record bytes + // from the symbol stream. + Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); +} + +Error ModInfoBuilder::finalizeMsfLayout() { + this->Layout.ModDiStream = kInvalidStreamIndex; + auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize)); + if (!ExpectedSN) + return ExpectedSN.takeError(); + Layout.ModDiStream = *ExpectedSN; + return Error::success(); +} + +Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter, + const msf::MSFLayout &MsfLayout, + WritableBinaryStreamRef MsfBuffer) { + // We write the Modi record to the `ModiWriter`, but we additionally write its + // symbol stream to a brand new stream. + if (auto EC = ModiWriter.writeObject(Layout)) + return EC; + if (auto EC = ModiWriter.writeCString(ModuleName)) + return EC; + if (auto EC = ModiWriter.writeCString(ObjFileName)) + return EC; + if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) + return EC; + + if (Layout.ModDiStream != kInvalidStreamIndex) { + auto NS = WritableMappedBlockStream::createIndexedStream( + MsfLayout, MsfBuffer, Layout.ModDiStream); + WritableBinaryStreamRef Ref(*NS); + BinaryStreamWriter SymbolWriter(Ref); + // Write the symbols. + if (auto EC = + SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC)) + return EC; + BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little); + Records.setItems(Symbols); + BinaryStreamRef RecordsRef(Records); + if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) + return EC; + // TODO: Write C11 Line data + // TODO: Write C13 Line data + // TODO: Figure out what GlobalRefs substream actually is and populate it. + if (auto EC = SymbolWriter.writeInteger<uint32_t>(0)) + return EC; + if (SymbolWriter.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::stream_too_long); + } + return Error::success(); +} diff --git a/lib/DebugInfo/PDB/Raw/ModStream.cpp b/lib/DebugInfo/PDB/Native/ModStream.cpp index 0ffc5b7d44aa..08798cf0ed28 100644 --- a/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/lib/DebugInfo/PDB/Native/ModStream.cpp @@ -7,15 +7,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/ModStream.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/PDB/Raw/ModStream.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/ModInfo.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include <algorithm> #include <cstdint> @@ -31,7 +31,7 @@ ModStream::ModStream(const ModInfo &Module, ModStream::~ModStream() = default; Error ModStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getLineInfoByteSize(); @@ -41,7 +41,7 @@ Error ModStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Module has both C11 and C13 line info"); - ReadableStreamRef S; + BinaryStreamRef S; if (auto EC = Reader.readInteger(Signature)) return EC; @@ -53,7 +53,7 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - StreamReader LineReader(C13LinesSubstream); + BinaryStreamReader LineReader(C13LinesSubstream); if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) return EC; diff --git a/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp new file mode 100644 index 000000000000..c7ba32b82bc6 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -0,0 +1,135 @@ +//===- NamedStreamMap.cpp - PDB Named Stream Map ----------------*- 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/PDB/Native/NamedStreamMap.h" + +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> + +using namespace llvm; +using namespace llvm::pdb; + +NamedStreamMap::NamedStreamMap() = default; + +Error NamedStreamMap::load(BinaryStreamReader &Stream) { + Mapping.clear(); + FinalizedHashTable.clear(); + FinalizedInfo.reset(); + + uint32_t StringBufferSize; + if (auto EC = Stream.readInteger(StringBufferSize)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected string buffer size")); + + BinaryStreamRef StringsBuffer; + if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) + return EC; + + HashTable OffsetIndexMap; + if (auto EC = OffsetIndexMap.load(Stream)) + return EC; + + uint32_t NameOffset; + uint32_t NameIndex; + for (const auto &Entry : OffsetIndexMap) { + std::tie(NameOffset, NameIndex) = Entry; + + // Compute the offset of the start of the string relative to the stream. + BinaryStreamReader NameReader(StringsBuffer); + NameReader.setOffset(NameOffset); + // Pump out our c-string from the stream. + StringRef Str; + if (auto EC = NameReader.readCString(Str)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected name map name")); + + // Add this to a string-map from name to stream number. + Mapping.insert({Str, NameIndex}); + } + + return Error::success(); +} + +Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { + assert(FinalizedInfo.hasValue()); + + // The first field is the number of bytes of string data. + if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) + return EC; + + // Now all of the string data itself. + for (const auto &Item : Mapping) { + if (auto EC = Writer.writeCString(Item.getKey())) + return EC; + } + + // And finally the Offset Index map. + if (auto EC = FinalizedHashTable.commit(Writer)) + return EC; + + return Error::success(); +} + +uint32_t NamedStreamMap::finalize() { + if (FinalizedInfo.hasValue()) + return FinalizedInfo->SerializedLength; + + // Build the finalized hash table. + FinalizedHashTable.clear(); + FinalizedInfo.emplace(); + for (const auto &Item : Mapping) { + FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue()); + FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1; + } + + // Number of bytes of string data. + FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); + // Followed by that many actual bytes of string data. + FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; + // Followed by the mapping from Offset to Index. + FinalizedInfo->SerializedLength += + FinalizedHashTable.calculateSerializedLength(); + return FinalizedInfo->SerializedLength; +} + +iterator_range<StringMapConstIterator<uint32_t>> +NamedStreamMap::entries() const { + return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), + Mapping.end()); +} + +uint32_t NamedStreamMap::size() const { return Mapping.size(); } + +bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { + auto Iter = Mapping.find(Stream); + if (Iter == Mapping.end()) + return false; + StreamNo = Iter->second; + return true; +} + +void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { + FinalizedInfo.reset(); + Mapping[Stream] = StreamNo; +} + +void NamedStreamMap::remove(StringRef Stream) { + FinalizedInfo.reset(); + Mapping.erase(Stream); +} diff --git a/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp new file mode 100644 index 000000000000..9c0cc0bf8233 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp @@ -0,0 +1,43 @@ +//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- 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/PDB/Native/NativeCompilandSymbol.h" + +namespace llvm { +namespace pdb { + +NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, + const ModuleInfoEx &MI) + : NativeRawSymbol(Session), Module(MI) {} + +PDB_SymType NativeCompilandSymbol::getSymTag() const { + return PDB_SymType::Compiland; +} + +bool NativeCompilandSymbol::isEditAndContinueEnabled() const { + return Module.Info.hasECInfo(); +} + +uint32_t NativeCompilandSymbol::getLexicalParentId() const { return 0; } + +// The usage of getObjFileName for getLibraryName and getModuleName for getName +// may seem backwards, but it is consistent with DIA, which is what this API +// was modeled after. We may rename these methods later to try to eliminate +// this potential confusion. + +std::string NativeCompilandSymbol::getLibraryName() const { + return Module.Info.getObjFileName(); +} + +std::string NativeCompilandSymbol::getName() const { + return Module.Info.getModuleName(); +} + +} // namespace pdb +} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp new file mode 100644 index 000000000000..7532110d005c --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp @@ -0,0 +1,52 @@ +//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- 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/PDB/Native/NativeEnumModules.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" + +namespace llvm { +namespace pdb { + +NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, + ArrayRef<ModuleInfoEx> Modules, + uint32_t Index) + : Session(PDBSession), Modules(Modules), Index(Index) {} + +uint32_t NativeEnumModules::getChildCount() const { + return static_cast<uint32_t>(Modules.size()); +} + +std::unique_ptr<PDBSymbol> +NativeEnumModules::getChildAtIndex(uint32_t Index) const { + if (Index >= Modules.size()) + return nullptr; + return std::unique_ptr<PDBSymbol>(new PDBSymbolCompiland(Session, + std::unique_ptr<IPDBRawSymbol>( + new NativeCompilandSymbol(Session, Modules[Index])))); +} + +std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() { + if (Index >= Modules.size()) + return nullptr; + return getChildAtIndex(Index++); +} + +void NativeEnumModules::reset() { Index = 0; } + +NativeEnumModules *NativeEnumModules::clone() const { + return new NativeEnumModules(Session, Modules, Index); +} + +} +} diff --git a/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp new file mode 100644 index 000000000000..ec2a4b87457c --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -0,0 +1,79 @@ +//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- 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/PDB/Native/NativeExeSymbol.h" + +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" + +namespace llvm { +namespace pdb { + +NativeExeSymbol::NativeExeSymbol(NativeSession &Session) + : NativeRawSymbol(Session), File(Session.getPDBFile()) {} + +std::unique_ptr<IPDBEnumSymbols> +NativeExeSymbol::findChildren(PDB_SymType Type) const { + switch (Type) { + case PDB_SymType::Compiland: { + auto Dbi = File.getPDBDbiStream(); + if (Dbi) { + const auto Modules = Dbi->modules(); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumModules(Session, Modules)); + } + consumeError(Dbi.takeError()); + break; + } + default: + break; + } + return nullptr; +} + +uint32_t NativeExeSymbol::getAge() const { + auto IS = File.getPDBInfoStream(); + if (IS) + return IS->getAge(); + consumeError(IS.takeError()); + return 0; +} + +std::string NativeExeSymbol::getSymbolsFileName() const { + return File.getFilePath(); +} + +PDB_UniqueId NativeExeSymbol::getGuid() const { + auto IS = File.getPDBInfoStream(); + if (IS) + return IS->getGuid(); + consumeError(IS.takeError()); + return PDB_UniqueId{{0}}; +} + +bool NativeExeSymbol::hasCTypes() const { + auto Dbi = File.getPDBDbiStream(); + if (Dbi) + return Dbi->hasCTypes(); + consumeError(Dbi.takeError()); + return false; +} + +bool NativeExeSymbol::hasPrivateSymbols() const { + auto Dbi = File.getPDBDbiStream(); + if (Dbi) + return !Dbi->isStripped(); + consumeError(Dbi.takeError()); + return false; +} + +} // namespace pdb +} // namespace llvm diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp new file mode 100644 index 000000000000..3aba35adb53f --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -0,0 +1,706 @@ +//===- NativeRawSymbol.cpp - Native implementation of IPDBRawSymbol -*- 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/PDB/Native/NativeRawSymbol.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::pdb; + +NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession) + : Session(PDBSession) {} + +void NativeRawSymbol::dump(raw_ostream &OS, int Indent) const {} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t RVA) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { + return nullptr; +} + +void NativeRawSymbol::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const { + bytes.clear(); +} + +PDB_MemberAccess NativeRawSymbol::getAccess() const { + return PDB_MemberAccess::Private; +} + +uint32_t NativeRawSymbol::getAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getAge() const { + return 0; +} + +uint32_t NativeRawSymbol::getArrayIndexTypeId() const { + return 0; +} + +void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +uint32_t NativeRawSymbol::getBaseDataOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getBaseDataSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getBaseSymbolId() const { + return 0; +} + +PDB_BuiltinType NativeRawSymbol::getBuiltinType() const { + return PDB_BuiltinType::None; +} + +uint32_t NativeRawSymbol::getBitPosition() const { + return 0; +} + +PDB_CallingConv NativeRawSymbol::getCallingConvention() const { + return PDB_CallingConv::FarStdCall; +} + +uint32_t NativeRawSymbol::getClassParentId() const { + return 0; +} + +std::string NativeRawSymbol::getCompilerName() const { + return 0; +} + +uint32_t NativeRawSymbol::getCount() const { + return 0; +} + +uint32_t NativeRawSymbol::getCountLiveRanges() const { + return 0; +} + +void NativeRawSymbol::getFrontEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +PDB_Lang NativeRawSymbol::getLanguage() const { + return PDB_Lang::Cobol; +} + +uint32_t NativeRawSymbol::getLexicalParentId() const { + return 0; +} + +std::string NativeRawSymbol::getLibraryName() const { + return ""; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { + return codeview::RegisterId::EAX; +} + +uint32_t NativeRawSymbol::getLowerBoundId() const { + return 0; +} + +uint32_t NativeRawSymbol::getMemorySpaceKind() const { + return 0; +} + +std::string NativeRawSymbol::getName() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfAcceleratorPointerTags() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfColumns() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfModifiers() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRegisterIndices() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRows() const { + return 0; +} + +std::string NativeRawSymbol::getObjectFileName() const { + return ""; +} + +uint32_t NativeRawSymbol::getOemId() const { + return 0; +} + +uint32_t NativeRawSymbol::getOemSymbolId() const { + return 0; +} + +uint32_t NativeRawSymbol::getOffsetInUdt() const { + return 0; +} + +PDB_Cpu NativeRawSymbol::getPlatform() const { + return PDB_Cpu::Intel8080; +} + +uint32_t NativeRawSymbol::getRank() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getRegisterId() const { + return codeview::RegisterId::EAX; +} + +uint32_t NativeRawSymbol::getRegisterType() const { + return 0; +} + +uint32_t NativeRawSymbol::getRelativeVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getSamplerSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getSignature() const { + return 0; +} + +uint32_t NativeRawSymbol::getSizeInUdt() const { + return 0; +} + +uint32_t NativeRawSymbol::getSlot() const { + return 0; +} + +std::string NativeRawSymbol::getSourceFileName() const { + return 0; +} + +uint32_t NativeRawSymbol::getStride() const { + return 0; +} + +uint32_t NativeRawSymbol::getSubTypeId() const { + return 0; +} + +std::string NativeRawSymbol::getSymbolsFileName() const { return ""; } + +uint32_t NativeRawSymbol::getSymIndexId() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetRelativeVirtualAddress() const { + return 0; +} + +uint64_t NativeRawSymbol::getTargetVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getTextureSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getTimeStamp() const { + return 0; +} + +uint32_t NativeRawSymbol::getToken() const { + return 0; +} + +uint32_t NativeRawSymbol::getTypeId() const { + return 0; +} + +uint32_t NativeRawSymbol::getUavSlot() const { + return 0; +} + +std::string NativeRawSymbol::getUndecoratedName() const { + return 0; +} + +uint32_t NativeRawSymbol::getUnmodifiedTypeId() const { + return 0; +} + +uint32_t NativeRawSymbol::getUpperBoundId() const { + return 0; +} + +Variant NativeRawSymbol::getValue() const { + return Variant(); +} + +uint32_t NativeRawSymbol::getVirtualBaseDispIndex() const { + return 0; +} + +uint32_t NativeRawSymbol::getVirtualBaseOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getVirtualTableShapeId() const { + return 0; +} + +std::unique_ptr<PDBSymbolTypeVTable> +NativeRawSymbol::getVirtualBaseTableType() const { + return nullptr; +} + +PDB_DataKind NativeRawSymbol::getDataKind() const { + return PDB_DataKind::Unknown; +} + +PDB_SymType NativeRawSymbol::getSymTag() const { + return PDB_SymType::None; +} + +PDB_UniqueId NativeRawSymbol::getGuid() const { + return PDB_UniqueId{{0}}; +} + +int32_t NativeRawSymbol::getOffset() const { + return 0; +} + +int32_t NativeRawSymbol::getThisAdjust() const { + return 0; +} + +int32_t NativeRawSymbol::getVirtualBasePointerOffset() const { + return 0; +} + +PDB_LocType NativeRawSymbol::getLocationType() const { + return PDB_LocType::Null; +} + +PDB_Machine NativeRawSymbol::getMachineType() const { + return PDB_Machine::Invalid; +} + +codeview::ThunkOrdinal NativeRawSymbol::getThunkOrdinal() const { + return codeview::ThunkOrdinal::Standard; +} + +uint64_t NativeRawSymbol::getLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getLiveRangeLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getVirtualAddress() const { + return 0; +} + +PDB_UdtType NativeRawSymbol::getUdtKind() const { + return PDB_UdtType::Struct; +} + +bool NativeRawSymbol::hasConstructor() const { + return false; +} + +bool NativeRawSymbol::hasCustomCallingConvention() const { + return false; +} + +bool NativeRawSymbol::hasFarReturn() const { + return false; +} + +bool NativeRawSymbol::isCode() const { + return false; +} + +bool NativeRawSymbol::isCompilerGenerated() const { + return false; +} + +bool NativeRawSymbol::isConstType() const { + return false; +} + +bool NativeRawSymbol::isEditAndContinueEnabled() const { + return false; +} + +bool NativeRawSymbol::isFunction() const { + return false; +} + +bool NativeRawSymbol::getAddressTaken() const { + return false; +} + +bool NativeRawSymbol::getNoStackOrdering() const { + return false; +} + +bool NativeRawSymbol::hasAlloca() const { + return false; +} + +bool NativeRawSymbol::hasAssignmentOperator() const { + return false; +} + +bool NativeRawSymbol::hasCTypes() const { + return false; +} + +bool NativeRawSymbol::hasCastOperator() const { + return false; +} + +bool NativeRawSymbol::hasDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasEH() const { + return false; +} + +bool NativeRawSymbol::hasEHa() const { + return false; +} + +bool NativeRawSymbol::hasInlAsm() const { + return false; +} + +bool NativeRawSymbol::hasInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasInterruptReturn() const { + return false; +} + +bool NativeRawSymbol::hasFramePointer() const { + return false; +} + +bool NativeRawSymbol::hasLongJump() const { + return false; +} + +bool NativeRawSymbol::hasManagedCode() const { + return false; +} + +bool NativeRawSymbol::hasNestedTypes() const { + return false; +} + +bool NativeRawSymbol::hasNoInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasNoReturnAttribute() const { + return false; +} + +bool NativeRawSymbol::hasOptimizedCodeDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasOverloadedOperator() const { + return false; +} + +bool NativeRawSymbol::hasSEH() const { + return false; +} + +bool NativeRawSymbol::hasSecurityChecks() const { + return false; +} + +bool NativeRawSymbol::hasSetJump() const { + return false; +} + +bool NativeRawSymbol::hasStrictGSCheck() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorGroupSharedLocal() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorPointerTagLiveRange() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorStubFunction() const { + return false; +} + +bool NativeRawSymbol::isAggregated() const { + return false; +} + +bool NativeRawSymbol::isIntroVirtualFunction() const { + return false; +} + +bool NativeRawSymbol::isCVTCIL() const { + return false; +} + +bool NativeRawSymbol::isConstructorVirtualBase() const { + return false; +} + +bool NativeRawSymbol::isCxxReturnUdt() const { + return false; +} + +bool NativeRawSymbol::isDataAligned() const { + return false; +} + +bool NativeRawSymbol::isHLSLData() const { + return false; +} + +bool NativeRawSymbol::isHotpatchable() const { + return false; +} + +bool NativeRawSymbol::isIndirectVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isInterfaceUdt() const { + return false; +} + +bool NativeRawSymbol::isIntrinsic() const { + return false; +} + +bool NativeRawSymbol::isLTCG() const { + return false; +} + +bool NativeRawSymbol::isLocationControlFlowDependent() const { + return false; +} + +bool NativeRawSymbol::isMSILNetmodule() const { + return false; +} + +bool NativeRawSymbol::isMatrixRowMajor() const { + return false; +} + +bool NativeRawSymbol::isManagedCode() const { + return false; +} + +bool NativeRawSymbol::isMSILCode() const { + return false; +} + +bool NativeRawSymbol::isMultipleInheritance() const { + return false; +} + +bool NativeRawSymbol::isNaked() const { + return false; +} + +bool NativeRawSymbol::isNested() const { + return false; +} + +bool NativeRawSymbol::isOptimizedAway() const { + return false; +} + +bool NativeRawSymbol::isPacked() const { + return false; +} + +bool NativeRawSymbol::isPointerBasedOnSymbolValue() const { + return false; +} + +bool NativeRawSymbol::isPointerToDataMember() const { + return false; +} + +bool NativeRawSymbol::isPointerToMemberFunction() const { + return false; +} + +bool NativeRawSymbol::isPureVirtual() const { + return false; +} + +bool NativeRawSymbol::isRValueReference() const { + return false; +} + +bool NativeRawSymbol::isRefUdt() const { + return false; +} + +bool NativeRawSymbol::isReference() const { + return false; +} + +bool NativeRawSymbol::isRestrictedType() const { + return false; +} + +bool NativeRawSymbol::isReturnValue() const { + return false; +} + +bool NativeRawSymbol::isSafeBuffers() const { + return false; +} + +bool NativeRawSymbol::isScoped() const { + return false; +} + +bool NativeRawSymbol::isSdl() const { + return false; +} + +bool NativeRawSymbol::isSingleInheritance() const { + return false; +} + +bool NativeRawSymbol::isSplitted() const { + return false; +} + +bool NativeRawSymbol::isStatic() const { + return false; +} + +bool NativeRawSymbol::hasPrivateSymbols() const { + return false; +} + +bool NativeRawSymbol::isUnalignedType() const { + return false; +} + +bool NativeRawSymbol::isUnreached() const { + return false; +} + +bool NativeRawSymbol::isValueUdt() const { + return false; +} + +bool NativeRawSymbol::isVirtual() const { + return false; +} + +bool NativeRawSymbol::isVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isVirtualInheritance() const { + return false; +} + +bool NativeRawSymbol::isVolatileType() const { + return false; +} + +bool NativeRawSymbol::wasInlined() const { + return false; +} + +std::string NativeRawSymbol::getUnused() const { + return ""; +} diff --git a/lib/DebugInfo/PDB/Native/NativeSession.cpp b/lib/DebugInfo/PDB/Native/NativeSession.cpp new file mode 100644 index 000000000000..7e6843bceb7d --- /dev/null +++ b/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -0,0 +1,146 @@ +//===- NativeSession.cpp - Native implementation of IPDBSession -*- 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/PDB/Native/NativeSession.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <memory> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; + +NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, + std::unique_ptr<BumpPtrAllocator> Allocator) + : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)) {} + +NativeSession::~NativeSession() = default; + +Error NativeSession::createFromPdb(StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return make_error<GenericError>(generic_error_code::invalid_path); + + std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); + auto Stream = llvm::make_unique<MemoryBufferByteStream>( + std::move(Buffer), llvm::support::little); + + auto Allocator = llvm::make_unique<BumpPtrAllocator>(); + auto File = llvm::make_unique<PDBFile>(Path, std::move(Stream), *Allocator); + if (auto EC = File->parseFileHeaders()) + return EC; + if (auto EC = File->parseStreamData()) + return EC; + + Session = + llvm::make_unique<NativeSession>(std::move(File), std::move(Allocator)); + + return Error::success(); +} + +Error NativeSession::createFromExe(StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + return make_error<RawError>(raw_error_code::feature_unsupported); +} + +uint64_t NativeSession::getLoadAddress() const { return 0; } + +void NativeSession::setLoadAddress(uint64_t Address) {} + +std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() const { + auto RawSymbol = + llvm::make_unique<NativeExeSymbol>(const_cast<NativeSession &>(*this)); + auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); + std::unique_ptr<PDBSymbolExe> ExeSymbol( + static_cast<PDBSymbolExe *>(PdbSymbol.release())); + return ExeSymbol; +} + +std::unique_ptr<PDBSymbol> +NativeSession::getSymbolById(uint32_t SymbolId) const { + return nullptr; +} + +std::unique_ptr<PDBSymbol> +NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersByAddress(uint64_t Address, + uint32_t Length) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> +NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland, + StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, + StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +NativeSession::findCompilandsForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<PDBSymbolCompiland> +NativeSession::findOneCompilandForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::getSourceFileById(uint32_t FileId) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { + return nullptr; +} diff --git a/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/lib/DebugInfo/PDB/Native/PDBFile.cpp index 53491518b8c7..943e7fa13ab7 100644 --- a/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -7,24 +7,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/StringTable.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" #include <algorithm> #include <cassert> #include <cstdint> @@ -38,12 +39,18 @@ namespace { typedef FixedStreamArray<support::ulittle32_t> ulittle_array; } // end anonymous namespace -PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer, +PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, BumpPtrAllocator &Allocator) - : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} + : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} PDBFile::~PDBFile() = default; +StringRef PDBFile::getFilePath() const { return FilePath; } + +StringRef PDBFile::getFileDirectory() const { + return sys::path::parent_path(FilePath); +} + uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } uint32_t PDBFile::getFreeBlockMapBlock() const { @@ -106,7 +113,7 @@ Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, } Error PDBFile::parseFileHeaders() { - StreamReader Reader(*Buffer); + BinaryStreamReader Reader(*Buffer); // Initialize SB. const msf::SuperBlock *SB = nullptr; @@ -140,7 +147,7 @@ Error PDBFile::parseFileHeaders() { // See the function fpmPn() for more information: // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer); - StreamReader FpmReader(*FpmStream); + BinaryStreamReader FpmReader(*FpmStream); ArrayRef<uint8_t> FpmBytes; if (auto EC = FpmReader.readBytes(FpmBytes, msf::getFullFpmByteSize(ContainerLayout))) @@ -178,7 +185,7 @@ Error PDBFile::parseStreamData() { // subclass of IPDBStreamData which only accesses the fields that have already // been parsed, we can avoid this and reuse MappedBlockStream. auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer); - StreamReader Reader(*DS); + BinaryStreamReader Reader(*DS); if (auto EC = Reader.readInteger(NumStreams)) return EC; @@ -229,7 +236,8 @@ Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { auto GlobalS = safelyCreateIndexedStream( ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex()); - if (!GlobalS) return GlobalS.takeError(); + if (!GlobalS) + return GlobalS.takeError(); auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS)); if (auto EC = TempGlobals->reload()) return std::move(EC); @@ -241,7 +249,8 @@ Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { Expected<InfoStream &> PDBFile::getPDBInfoStream() { if (!Info) { auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB); - if (!InfoS) return InfoS.takeError(); + if (!InfoS) + return InfoS.takeError(); auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS)); if (auto EC = TempInfo->reload()) return std::move(EC); @@ -253,7 +262,8 @@ Expected<InfoStream &> PDBFile::getPDBInfoStream() { Expected<DbiStream &> PDBFile::getPDBDbiStream() { if (!Dbi) { auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI); - if (!DbiS) return DbiS.takeError(); + if (!DbiS) + return DbiS.takeError(); auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS)); if (auto EC = TempDbi->reload()) return std::move(EC); @@ -265,7 +275,8 @@ Expected<DbiStream &> PDBFile::getPDBDbiStream() { Expected<TpiStream &> PDBFile::getPDBTpiStream() { if (!Tpi) { auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI); - if (!TpiS) return TpiS.takeError(); + if (!TpiS) + return TpiS.takeError(); auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS)); if (auto EC = TempTpi->reload()) return std::move(EC); @@ -277,7 +288,8 @@ Expected<TpiStream &> PDBFile::getPDBTpiStream() { Expected<TpiStream &> PDBFile::getPDBIpiStream() { if (!Ipi) { auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI); - if (!IpiS) return IpiS.takeError(); + if (!IpiS) + return IpiS.takeError(); auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS)); if (auto EC = TempIpi->reload()) return std::move(EC); @@ -294,7 +306,8 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { auto PublicS = safelyCreateIndexedStream( ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); - if (!PublicS) return PublicS.takeError(); + if (!PublicS) + return PublicS.takeError(); auto TempPublics = llvm::make_unique<PublicsStream>(*this, std::move(*PublicS)); if (auto EC = TempPublics->reload()) @@ -313,7 +326,8 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); auto SymbolS = safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum); - if (!SymbolS) return SymbolS.takeError(); + if (!SymbolS) + return SymbolS.takeError(); auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS)); if (auto EC = TempSymbols->reload()) @@ -323,8 +337,8 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { return *Symbols; } -Expected<NameHashTable &> PDBFile::getStringTable() { - if (!StringTable || !StringTableStream) { +Expected<StringTable &> PDBFile::getStringTable() { + if (!Strings || !StringTableStream) { auto IS = getPDBInfoStream(); if (!IS) return IS.takeError(); @@ -333,23 +347,25 @@ Expected<NameHashTable &> PDBFile::getStringTable() { auto NS = safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex); - if (!NS) return NS.takeError(); + if (!NS) + return NS.takeError(); - StreamReader Reader(**NS); - auto N = llvm::make_unique<NameHashTable>(); + BinaryStreamReader Reader(**NS); + auto N = llvm::make_unique<StringTable>(); if (auto EC = N->load(Reader)) return std::move(EC); - StringTable = std::move(N); + Strings = std::move(N); StringTableStream = std::move(*NS); } - return *StringTable; + return *Strings; } bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); } bool PDBFile::hasPDBGlobalsStream() { auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; + if (!DbiS) + return false; return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); } @@ -359,13 +375,15 @@ bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); } bool PDBFile::hasPDBPublicsStream() { auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; + if (!DbiS) + return false; return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); } bool PDBFile::hasPDBSymbolStream() { auto DbiS = getPDBDbiStream(); - if (!DbiS) return false; + if (!DbiS) + return false; return DbiS->getSymRecordStreamIndex() < getNumStreams(); } @@ -373,18 +391,19 @@ bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } bool PDBFile::hasStringTable() { auto IS = getPDBInfoStream(); - if (!IS) return false; + if (!IS) + return false; return IS->getNamedStreamIndex("/names") < getNumStreams(); } -/// Wrapper around MappedBlockStream::createIndexedStream() -/// that checks if a stream with that index actually exists. -/// If it does not, the return value will have an MSFError with -/// code msf_error_code::no_stream. Else, the return value will -/// contain the stream returned by createIndexedStream(). -Expected<std::unique_ptr<MappedBlockStream>> PDBFile::safelyCreateIndexedStream( - const MSFLayout &Layout, const ReadableStream &MsfData, - uint32_t StreamIndex) const { +/// Wrapper around MappedBlockStream::createIndexedStream() that checks if a +/// stream with that index actually exists. If it does not, the return value +/// will have an MSFError with code msf_error_code::no_stream. Else, the return +/// value will contain the stream returned by createIndexedStream(). +Expected<std::unique_ptr<MappedBlockStream>> +PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout, + BinaryStreamRef MsfData, + uint32_t StreamIndex) const { if (StreamIndex >= getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex); diff --git a/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index 6fec0e32a8ae..b3c84903bc7e 100644 --- a/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -7,21 +7,22 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/ADT/BitVector.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/GenericError.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; @@ -44,7 +45,7 @@ MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { if (!Info) - Info = llvm::make_unique<InfoStreamBuilder>(*Msf); + Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); return *Info; } @@ -66,7 +67,26 @@ TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { return *Ipi; } -Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const { +StringTableBuilder &PDBFileBuilder::getStringTableBuilder() { return Strings; } + +Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { + auto ExpectedStream = Msf->addStream(Size); + if (!ExpectedStream) + return ExpectedStream.takeError(); + NamedStreams.set(Name, *ExpectedStream); + return Error::success(); +} + +Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { + uint32_t StringTableSize = Strings.finalize(); + + if (auto EC = addNamedStream("/names", StringTableSize)) + return std::move(EC); + if (auto EC = addNamedStream("/LinkInfo", 0)) + return std::move(EC); + if (auto EC = addNamedStream("/src/headerblock", 0)) + return std::move(EC); + if (Info) { if (auto EC = Info->finalizeMsfLayout()) return std::move(EC); @@ -98,8 +118,9 @@ Error PDBFileBuilder::commit(StringRef Filename) { if (OutFileOrError.getError()) return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, Filename); - FileBufferByteStream Buffer(std::move(*OutFileOrError)); - StreamWriter Writer(Buffer); + FileBufferByteStream Buffer(std::move(*OutFileOrError), + llvm::support::little); + BinaryStreamWriter Writer(Buffer); if (auto EC = Writer.writeObject(*Layout.SB)) return EC; @@ -111,9 +132,8 @@ Error PDBFileBuilder::commit(StringRef Filename) { auto DirStream = WritableMappedBlockStream::createDirectoryStream(Layout, Buffer); - StreamWriter DW(*DirStream); - if (auto EC = - DW.writeInteger(static_cast<uint32_t>(Layout.StreamSizes.size()))) + BinaryStreamWriter DW(*DirStream); + if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) return EC; if (auto EC = DW.writeArray(Layout.StreamSizes)) @@ -124,6 +144,16 @@ Error PDBFileBuilder::commit(StringRef Filename) { return EC; } + uint32_t StringTableStreamNo = 0; + if (!NamedStreams.get("/names", StringTableStreamNo)) + return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); + + auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, + StringTableStreamNo); + BinaryStreamWriter NSWriter(*NS); + if (auto EC = Strings.commit(NSWriter)) + return EC; + if (Info) { if (auto EC = Info->commit(Layout, Buffer)) return EC; diff --git a/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp b/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp new file mode 100644 index 000000000000..629f3e80b0ed --- /dev/null +++ b/lib/DebugInfo/PDB/Native/PDBTypeServerHandler.cpp @@ -0,0 +1,119 @@ +//===- PDBTypeServerHandler.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Handles CodeView LF_TYPESERVER2 records by attempting to locate a matching +// PDB file, then loading the PDB file and visiting all types from the +// referenced PDB using the original supplied visitor. +// +// The net effect of this is that when visiting a PDB containing a TypeServer +// record, the TypeServer record is "replaced" with all of the records in +// the referenced PDB file. If a single instance of PDBTypeServerHandler +// encounters the same TypeServer multiple times (for example reusing one +// PDBTypeServerHandler across multiple visitations of distinct object files or +// PDB files), PDBTypeServerHandler will optionally revisit all the records +// again, or simply consume the record and do nothing. +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static void ignoreErrors(Error EC) { + llvm::handleAllErrors(std::move(EC), [&](ErrorInfoBase &EIB) {}); +} + +PDBTypeServerHandler::PDBTypeServerHandler(bool RevisitAlways) + : RevisitAlways(RevisitAlways) {} + +void PDBTypeServerHandler::addSearchPath(StringRef Path) { + if (Path.empty() || !sys::fs::is_directory(Path)) + return; + + SearchPaths.push_back(Path); +} + +Expected<bool> +PDBTypeServerHandler::handleInternal(PDBFile &File, + TypeVisitorCallbacks &Callbacks) { + auto ExpectedTpi = File.getPDBTpiStream(); + if (!ExpectedTpi) + return ExpectedTpi.takeError(); + CVTypeVisitor Visitor(Callbacks); + + if (auto EC = Visitor.visitTypeStream(ExpectedTpi->types(nullptr))) + return std::move(EC); + + return true; +} + +Expected<bool> PDBTypeServerHandler::handle(TypeServer2Record &TS, + TypeVisitorCallbacks &Callbacks) { + if (Session) { + // If we've already handled this TypeServer and we only want to handle each + // TypeServer once, consume the record without doing anything. + if (!RevisitAlways) + return true; + + return handleInternal(Session->getPDBFile(), Callbacks); + } + + StringRef File = sys::path::filename(TS.Name); + if (File.empty()) + return make_error<CodeViewError>( + cv_error_code::corrupt_record, + "TypeServer2Record does not contain filename!"); + + for (auto Path : SearchPaths) { + sys::path::append(Path, File); + if (!sys::fs::exists(Path)) + continue; + + std::unique_ptr<IPDBSession> ThisSession; + if (auto EC = loadDataForPDB(PDB_ReaderType::Native, Path, ThisSession)) { + // It is not an error if this PDB fails to load, it just means that it + // doesn't match and we should continue searching. + ignoreErrors(std::move(EC)); + continue; + } + + std::unique_ptr<NativeSession> NS( + static_cast<NativeSession *>(ThisSession.release())); + PDBFile &File = NS->getPDBFile(); + auto ExpectedInfo = File.getPDBInfoStream(); + // All PDB Files should have an Info stream. + if (!ExpectedInfo) + return ExpectedInfo.takeError(); + + // Just because a file with a matching name was found and it was an actual + // PDB file doesn't mean it matches. For it to match the InfoStream's GUID + // must match the GUID specified in the TypeServer2 record. + ArrayRef<uint8_t> GuidBytes(ExpectedInfo->getGuid().Guid); + StringRef GuidStr(reinterpret_cast<const char *>(GuidBytes.begin()), + GuidBytes.size()); + if (GuidStr != TS.Guid) + continue; + + Session = std::move(NS); + return handleInternal(File, Callbacks); + } + + // We couldn't find a matching PDB, so let it be handled by someone else. + return false; +} diff --git a/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/lib/DebugInfo/PDB/Native/PublicsStream.cpp index b31f605a078c..58202577672a 100644 --- a/lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ b/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -22,15 +22,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "GSI.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -69,7 +69,7 @@ uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } // we skip over the hash table which we believe contains information about // public symbols. Error PublicsStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); // Check stream size. if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) diff --git a/lib/DebugInfo/PDB/Raw/RawError.cpp b/lib/DebugInfo/PDB/Native/RawError.cpp index f4a5057509eb..548289fff3df 100644 --- a/lib/DebugInfo/PDB/Raw/RawError.cpp +++ b/lib/DebugInfo/PDB/Native/RawError.cpp @@ -1,4 +1,4 @@ -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" @@ -38,6 +38,8 @@ public: return "The entry does not exist."; case raw_error_code::not_writable: return "The PDB does not support writing."; + case raw_error_code::stream_too_long: + return "The stream was longer than expected."; case raw_error_code::invalid_tpi_hash: return "The Type record has an invalid hash value."; } diff --git a/lib/DebugInfo/PDB/Raw/NameHashTable.cpp b/lib/DebugInfo/PDB/Native/StringTable.cpp index 84cccb354bd8..7e28389b8383 100644 --- a/lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ b/lib/DebugInfo/PDB/Native/StringTable.cpp @@ -1,4 +1,4 @@ -//===- NameHashTable.cpp - PDB Name Hash Table ------------------*- C++ -*-===// +//===- StringTable.cpp - PDB String Table -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,33 +7,29 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" +#include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/Hash.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" using namespace llvm; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; -NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {} +StringTable::StringTable() {} -Error NameHashTable::load(StreamReader &Stream) { - struct Header { - support::ulittle32_t Signature; - support::ulittle32_t HashVersion; - support::ulittle32_t ByteSize; - }; +Error StringTable::load(BinaryStreamReader &Stream) { + ByteSize = Stream.getLength(); - const Header *H; + const StringTableHeader *H; if (auto EC = Stream.readObject(H)) return EC; - if (H->Signature != 0xEFFEEFFE) + if (H->Signature != StringTableSignature) return make_error<RawError>(raw_error_code::corrupt_file, "Invalid hash table signature"); if (H->HashVersion != 1 && H->HashVersion != 2) @@ -62,10 +58,19 @@ Error NameHashTable::load(StreamReader &Stream) { if (auto EC = Stream.readInteger(NameCount)) return EC; + + if (Stream.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::stream_too_long, + "Unexpected bytes found in string table"); + return Error::success(); } -StringRef NameHashTable::getStringForID(uint32_t ID) const { +uint32_t StringTable::getByteSize() const { + return ByteSize; +} + +StringRef StringTable::getStringForID(uint32_t ID) const { if (ID == IDs[0]) return StringRef(); @@ -73,14 +78,14 @@ StringRef NameHashTable::getStringForID(uint32_t ID) const { // the starting offset of the string we're looking for. So just seek into // the desired offset and a read a null terminated stream from that offset. StringRef Result; - StreamReader NameReader(NamesBuffer); + BinaryStreamReader NameReader(NamesBuffer); NameReader.setOffset(ID); - if (auto EC = NameReader.readZeroString(Result)) + if (auto EC = NameReader.readCString(Result)) consumeError(std::move(EC)); return Result; } -uint32_t NameHashTable::getIDForString(StringRef Str) const { +uint32_t StringTable::getIDForString(StringRef Str) const { uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); size_t Count = IDs.size(); uint32_t Start = Hash % Count; @@ -99,6 +104,6 @@ uint32_t NameHashTable::getIDForString(StringRef Str) const { return IDs[0]; } -FixedStreamArray<support::ulittle32_t> NameHashTable::name_ids() const { +FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const { return IDs; } diff --git a/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp b/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp new file mode 100644 index 000000000000..e0f8370ab608 --- /dev/null +++ b/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp @@ -0,0 +1,102 @@ +//===- StringTableBuilder.cpp - PDB String Table ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::support::endian; +using namespace llvm::pdb; + +uint32_t StringTableBuilder::insert(StringRef S) { + auto P = Strings.insert({S, StringSize}); + + // If a given string didn't exist in the string table, we want to increment + // the string table size. + if (P.second) + StringSize += S.size() + 1; // +1 for '\0' + return P.first->second; +} + +static uint32_t computeBucketCount(uint32_t NumStrings) { + // The /names stream is basically an on-disk open-addressing hash table. + // Hash collisions are resolved by linear probing. We cannot make + // utilization 100% because it will make the linear probing extremely + // slow. But lower utilization wastes disk space. As a reasonable + // load factor, we choose 80%. We need +1 because slot 0 is reserved. + return (NumStrings + 1) * 1.25; +} + +uint32_t StringTableBuilder::finalize() { + uint32_t Size = 0; + Size += sizeof(StringTableHeader); + Size += StringSize; + Size += sizeof(uint32_t); // Hash table begins with 4-byte size field. + + uint32_t BucketCount = computeBucketCount(Strings.size()); + Size += BucketCount * sizeof(uint32_t); + + Size += + sizeof(uint32_t); // The /names stream ends with the number of strings. + return Size; +} + +Error StringTableBuilder::commit(BinaryStreamWriter &Writer) const { + // Write a header + StringTableHeader H; + H.Signature = StringTableSignature; + H.HashVersion = 1; + H.ByteSize = StringSize; + if (auto EC = Writer.writeObject(H)) + return EC; + + // Write a string table. + uint32_t StringStart = Writer.getOffset(); + for (auto Pair : Strings) { + StringRef S = Pair.first; + uint32_t Offset = Pair.second; + Writer.setOffset(StringStart + Offset); + if (auto EC = Writer.writeCString(S)) + return EC; + } + Writer.setOffset(StringStart + StringSize); + + // Write a hash table. + uint32_t BucketCount = computeBucketCount(Strings.size()); + if (auto EC = Writer.writeInteger(BucketCount)) + return EC; + std::vector<ulittle32_t> Buckets(BucketCount); + + for (auto Pair : Strings) { + StringRef S = Pair.first; + uint32_t Offset = Pair.second; + uint32_t Hash = hashStringV1(S); + + for (uint32_t I = 0; I != BucketCount; ++I) { + uint32_t Slot = (Hash + I) % BucketCount; + if (Slot == 0) + continue; // Skip reserved slot + if (Buckets[Slot] != 0) + continue; + Buckets[Slot] = Offset; + break; + } + } + + if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) + return EC; + if (auto EC = Writer.writeInteger(static_cast<uint32_t>(Strings.size()))) + return EC; + return Error::success(); +} diff --git a/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/lib/DebugInfo/PDB/Native/SymbolStream.cpp index 2f3ac3497f39..9e9ebd11495b 100644 --- a/lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ b/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -7,16 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" - +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -30,7 +29,7 @@ SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) SymbolStream::~SymbolStream() {} Error SymbolStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) return EC; diff --git a/lib/DebugInfo/PDB/Raw/TpiHashing.cpp b/lib/DebugInfo/PDB/Native/TpiHashing.cpp index 6c3ddb3d57af..16904a5a27ed 100644 --- a/lib/DebugInfo/PDB/Raw/TpiHashing.cpp +++ b/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" -#include "llvm/DebugInfo/PDB/Raw/Hash.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" using namespace llvm; using namespace llvm::codeview; diff --git a/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/lib/DebugInfo/PDB/Native/TpiStream.cpp index a1167cd98454..5fef3edf8c2d 100644 --- a/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -7,19 +7,20 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" -#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -53,7 +54,7 @@ Error TpiStream::verifyHashValues() { } Error TpiStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream); if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) return make_error<RawError>(raw_error_code::corrupt_file, @@ -92,11 +93,12 @@ Error TpiStream::reload() { auto HS = MappedBlockStream::createIndexedStream( Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); - StreamReader HSR(*HS); + BinaryStreamReader HSR(*HS); + // There should be a hash value for every type record, or no hashes at all. uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); - if (NumHashValues != NumTypeRecords()) + if (NumHashValues != NumTypeRecords() && NumHashValues != 0) return make_error<RawError>( raw_error_code::corrupt_file, "TPI hash count does not match with the number of type records."); @@ -113,18 +115,19 @@ Error TpiStream::reload() { if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets)) return EC; - HSR.setOffset(Header->HashAdjBuffer.Off); - uint32_t NumHashAdjustments = - Header->HashAdjBuffer.Length / sizeof(TypeIndexOffset); - if (auto EC = HSR.readArray(HashAdjustments, NumHashAdjustments)) - return EC; + if (Header->HashAdjBuffer.Length > 0) { + HSR.setOffset(Header->HashAdjBuffer.Off); + if (auto EC = HashAdjusters.load(HSR)) + return EC; + } HashStream = std::move(HS); // TPI hash table is a parallel array for the type records. // Verify that the hash values match with type records. - if (auto EC = verifyHashValues()) - return EC; + if (NumHashValues > 0) + if (auto EC = verifyHashValues()) + return EC; } return Error::success(); @@ -154,23 +157,17 @@ uint16_t TpiStream::getTypeHashStreamAuxIndex() const { uint32_t TpiStream::NumHashBuckets() const { return Header->NumHashBuckets; } uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } -FixedStreamArray<support::ulittle32_t> -TpiStream::getHashValues() const { +FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const { return HashValues; } -FixedStreamArray<TypeIndexOffset> -TpiStream::getTypeIndexOffsets() const { +FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { return TypeIndexOffsets; } -FixedStreamArray<TypeIndexOffset> -TpiStream::getHashAdjustments() const { - return HashAdjustments; -} +HashTable &TpiStream::getHashAdjusters() { return HashAdjusters; } -iterator_range<CVTypeArray::Iterator> -TpiStream::types(bool *HadError) const { +CVTypeRange TpiStream::types(bool *HadError) const { return make_range(TypeRecords.begin(HadError), TypeRecords.end()); } diff --git a/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index c769321f18c1..375c35b11145 100644 --- a/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp +++ b/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -7,22 +7,22 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include <algorithm> @@ -43,9 +43,22 @@ void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { VerHeader = Version; } -void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) { +void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, + Optional<uint32_t> Hash) { + // If we just crossed an 8KB threshold, add a type index offset. + size_t NewSize = TypeRecordBytes + Record.size(); + constexpr size_t EightKB = 8 * 1024; + if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecords.empty()) { + TypeIndexOffsets.push_back( + {codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex + + TypeRecords.size()), + ulittle32_t(TypeRecordBytes)}); + } + TypeRecordBytes = NewSize; + TypeRecords.push_back(Record); - TypeRecordStream.setItems(TypeRecords); + if (Hash) + TypeHashes.push_back(*Hash); } Error TpiStreamBuilder::finalize() { @@ -55,13 +68,12 @@ Error TpiStreamBuilder::finalize() { TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); uint32_t Count = TypeRecords.size(); - uint32_t HashBufferSize = calculateHashBufferSize(); H->Version = *VerHeader; H->HeaderSize = sizeof(TpiStreamHeader); H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; H->TypeIndexEnd = H->TypeIndexBegin + Count; - H->TypeRecordBytes = TypeRecordStream.getLength(); + H->TypeRecordBytes = TypeRecordBytes; H->HashStreamIndex = HashStreamIndex; H->HashAuxStreamIndex = kInvalidStreamIndex; @@ -72,24 +84,32 @@ Error TpiStreamBuilder::finalize() { // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data // begins at offset 0 of this independent stream. H->HashValueBuffer.Off = 0; - H->HashValueBuffer.Length = HashBufferSize; + H->HashValueBuffer.Length = calculateHashBufferSize(); + + // We never write any adjustments into our PDBs, so this is usually some + // offset with zero length. H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; H->HashAdjBuffer.Length = 0; + H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; - H->IndexOffsetBuffer.Length = 0; + H->IndexOffsetBuffer.Length = calculateIndexOffsetSize(); Header = H; return Error::success(); } -uint32_t TpiStreamBuilder::calculateSerializedLength() const { - return sizeof(TpiStreamHeader) + TypeRecordStream.getLength(); +uint32_t TpiStreamBuilder::calculateSerializedLength() { + return sizeof(TpiStreamHeader) + TypeRecordBytes; } uint32_t TpiStreamBuilder::calculateHashBufferSize() const { - if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue()) - return 0; - return TypeRecords.size() * sizeof(ulittle32_t); + assert((TypeRecords.size() == TypeHashes.size() || TypeHashes.empty()) && + "either all or no type records should have hashes"); + return TypeHashes.size() * sizeof(ulittle32_t); +} + +uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const { + return TypeIndexOffsets.size() * sizeof(TypeIndexOffset); } Error TpiStreamBuilder::finalizeMsfLayout() { @@ -97,48 +117,60 @@ Error TpiStreamBuilder::finalizeMsfLayout() { if (auto EC = Msf.setStreamSize(Idx, Length)) return EC; - uint32_t HashBufferSize = calculateHashBufferSize(); + uint32_t HashStreamSize = + calculateHashBufferSize() + calculateIndexOffsetSize(); - if (HashBufferSize == 0) + if (HashStreamSize == 0) return Error::success(); - auto ExpectedIndex = Msf.addStream(HashBufferSize); + auto ExpectedIndex = Msf.addStream(HashStreamSize); if (!ExpectedIndex) return ExpectedIndex.takeError(); HashStreamIndex = *ExpectedIndex; - ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeRecords.size()); - MutableArrayRef<ulittle32_t> HashBuffer(H, TypeRecords.size()); - for (uint32_t I = 0; I < TypeRecords.size(); ++I) { - HashBuffer[I] = *TypeRecords[I].Hash % MinTpiHashBuckets; + if (!TypeHashes.empty()) { + ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size()); + MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size()); + for (uint32_t I = 0; I < TypeHashes.size(); ++I) { + HashBuffer[I] = TypeHashes[I] % MinTpiHashBuckets; + } + ArrayRef<uint8_t> Bytes( + reinterpret_cast<const uint8_t *>(HashBuffer.data()), + calculateHashBufferSize()); + HashValueStream = + llvm::make_unique<BinaryByteStream>(Bytes, llvm::support::little); } - ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(HashBuffer.data()), - HashBufferSize); - HashValueStream = llvm::make_unique<ByteStream>(Bytes); return Error::success(); } Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) { + WritableBinaryStreamRef Buffer) { if (auto EC = finalize()) return EC; auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*InfoS); if (auto EC = Writer.writeObject(*Header)) return EC; - auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream); - if (auto EC = Writer.writeArray(RecordArray)) - return EC; + for (auto Rec : TypeRecords) + if (auto EC = Writer.writeBytes(Rec)) + return EC; if (HashStreamIndex != kInvalidStreamIndex) { auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, HashStreamIndex); - StreamWriter HW(*HVS); - if (auto EC = HW.writeStreamRef(*HashValueStream)) - return EC; + BinaryStreamWriter HW(*HVS); + if (HashValueStream) { + if (auto EC = HW.writeStreamRef(*HashValueStream)) + return EC; + } + + for (auto &IndexOffset : TypeIndexOffsets) { + if (auto EC = HW.writeObject(IndexOffset)) + return EC; + } } return Error::success(); diff --git a/lib/DebugInfo/PDB/PDB.cpp b/lib/DebugInfo/PDB/PDB.cpp index 0d720591b81d..7e3acc1165f3 100644 --- a/lib/DebugInfo/PDB/PDB.cpp +++ b/lib/DebugInfo/PDB/PDB.cpp @@ -17,7 +17,7 @@ #if LLVM_ENABLE_DIA_SDK #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #endif -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" @@ -27,8 +27,8 @@ using namespace llvm::pdb; Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, std::unique_ptr<IPDBSession> &Session) { // Create the correct concrete instance type based on the value of Type. - if (Type == PDB_ReaderType::Raw) - return RawSession::createFromPdb(Path, Session); + if (Type == PDB_ReaderType::Native) + return NativeSession::createFromPdb(Path, Session); #if LLVM_ENABLE_DIA_SDK return DIASession::createFromPdb(Path, Session); @@ -40,8 +40,8 @@ Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, std::unique_ptr<IPDBSession> &Session) { // Create the correct concrete instance type based on the value of Type. - if (Type == PDB_ReaderType::Raw) - return RawSession::createFromExe(Path, Session); + if (Type == PDB_ReaderType::Native) + return NativeSession::createFromExe(Path, Session); #if LLVM_ENABLE_DIA_SDK return DIASession::createFromExe(Path, Session); diff --git a/lib/DebugInfo/PDB/PDBExtras.cpp b/lib/DebugInfo/PDB/PDBExtras.cpp index b7eee6e53941..dc22a30facab 100644 --- a/lib/DebugInfo/PDB/PDBExtras.cpp +++ b/lib/DebugInfo/PDB/PDBExtras.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" using namespace llvm; using namespace llvm::pdb; @@ -259,6 +260,12 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, return OS; } +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UniqueId &Guid) { + codeview::detail::GuidAdapter A(Guid.Guid); + A.format(OS, ""); + return OS; +} + raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) { switch (Type) { CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS) @@ -269,25 +276,6 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) { return OS; } -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UniqueId &Id) { - static const char *Lookup = "0123456789ABCDEF"; - - static_assert(sizeof(PDB_UniqueId) == 16, "Expected 16-byte GUID"); - ArrayRef<uint8_t> GuidBytes(reinterpret_cast<const uint8_t*>(&Id), 16); - OS << "{"; - for (int i=0; i < 16;) { - uint8_t Byte = GuidBytes[i]; - uint8_t HighNibble = (Byte >> 4) & 0xF; - uint8_t LowNibble = Byte & 0xF; - OS << Lookup[HighNibble] << Lookup[LowNibble]; - ++i; - if (i>=4 && i<=10 && i%2==0) - OS << "-"; - } - OS << "}"; - return OS; -} - raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Machine &Machine) { switch (Machine) { diff --git a/lib/DebugInfo/PDB/PDBSymbol.cpp b/lib/DebugInfo/PDB/PDBSymbol.cpp index 633e11aacf12..74010c2dd7dd 100644 --- a/lib/DebugInfo/PDB/PDBSymbol.cpp +++ b/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" #include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" @@ -53,6 +54,9 @@ PDBSymbol::PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) : Session(PDBSession), RawSymbol(std::move(Symbol)) {} +PDBSymbol::PDBSymbol(PDBSymbol &Symbol) + : Session(Symbol.Session), RawSymbol(std::move(Symbol.RawSymbol)) {} + PDBSymbol::~PDBSymbol() = default; #define FACTORY_SYMTAG_CASE(Tag, Type) \ @@ -99,16 +103,30 @@ PDBSymbol::create(const IPDBSession &PDBSession, } } -#define TRY_DUMP_TYPE(Type) \ - if (const Type *DerivedThis = dyn_cast<Type>(this)) \ - Dumper.dump(OS, Indent, *DerivedThis); - -#define ELSE_TRY_DUMP_TYPE(Type, Dumper) else TRY_DUMP_TYPE(Type, Dumper) - void PDBSymbol::defaultDump(raw_ostream &OS, int Indent) const { RawSymbol->dump(OS, Indent); } +void PDBSymbol::dumpProperties() const { + outs() << "\n"; + defaultDump(outs(), 0); + outs().flush(); +} + +void PDBSymbol::dumpChildStats() const { + TagStats Stats; + getChildStats(Stats); + outs() << "\n"; + for (auto &Stat : Stats) { + outs() << Stat.first << ": " << Stat.second << "\n"; + } + outs().flush(); +} + +std::unique_ptr<PDBSymbol> PDBSymbol::clone() const { + return Session.getSymbolById(getSymIndexId()); +} + PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); } uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); } @@ -141,6 +159,8 @@ PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { std::unique_ptr<IPDBEnumSymbols> PDBSymbol::getChildStats(TagStats &Stats) const { std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren()); + if (!Result) + return nullptr; Stats.clear(); while (auto Child = Result->getNext()) { ++Stats[Child->getSymTag()]; @@ -148,3 +168,7 @@ PDBSymbol::getChildStats(TagStats &Stats) const { Result->reset(); return Result; } + +std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const { + return Session.getSymbolById(Id); +} diff --git a/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp b/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp index cdb167b6191c..3648272e1d0e 100644 --- a/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp @@ -18,7 +18,9 @@ using namespace llvm::pdb; PDBSymbolAnnotation::PDBSymbolAnnotation(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Annotation); +} void PDBSymbolAnnotation::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolBlock.cpp b/lib/DebugInfo/PDB/PDBSymbolBlock.cpp index fd5dc9427abf..7385d3ba1489 100644 --- a/lib/DebugInfo/PDB/PDBSymbolBlock.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolBlock.cpp @@ -19,6 +19,8 @@ using namespace llvm::pdb; PDBSymbolBlock::PDBSymbolBlock(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Block); +} void PDBSymbolBlock::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp index ebff08846cac..854cf42d1bae 100644 --- a/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolCompiland::PDBSymbolCompiland(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Compiland); +} void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp b/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp index 6dbd5228f2cd..e08450e0ad0c 100644 --- a/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolCompilandDetails::PDBSymbolCompilandDetails( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::CompilandDetails); +} void PDBSymbolCompilandDetails::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp b/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp index 9c7f0b1be56f..2f1c43666ae5 100644 --- a/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp @@ -20,7 +20,9 @@ using namespace llvm::pdb; PDBSymbolCompilandEnv::PDBSymbolCompilandEnv( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::CompilandEnv); +} std::string PDBSymbolCompilandEnv::getValue() const { Variant Value = RawSymbol->getValue(); diff --git a/lib/DebugInfo/PDB/PDBSymbolCustom.cpp b/lib/DebugInfo/PDB/PDBSymbolCustom.cpp index 0ea387a0eabb..9ec20bb62d75 100644 --- a/lib/DebugInfo/PDB/PDBSymbolCustom.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolCustom.cpp @@ -20,7 +20,9 @@ using namespace llvm::pdb; PDBSymbolCustom::PDBSymbolCustom(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> CustomSymbol) - : PDBSymbol(PDBSession, std::move(CustomSymbol)) {} + : PDBSymbol(PDBSession, std::move(CustomSymbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Custom); +} void PDBSymbolCustom::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) { RawSymbol->getDataBytes(bytes); diff --git a/lib/DebugInfo/PDB/PDBSymbolData.cpp b/lib/DebugInfo/PDB/PDBSymbolData.cpp index 62bb6f3f41e2..60026689c6f1 100644 --- a/lib/DebugInfo/PDB/PDBSymbolData.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolData.cpp @@ -19,10 +19,8 @@ using namespace llvm::pdb; PDBSymbolData::PDBSymbolData(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> DataSymbol) - : PDBSymbol(PDBSession, std::move(DataSymbol)) {} - -std::unique_ptr<PDBSymbol> PDBSymbolData::getType() const { - return Session.getSymbolById(getTypeId()); + : PDBSymbol(PDBSession, std::move(DataSymbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Data); } void PDBSymbolData::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/lib/DebugInfo/PDB/PDBSymbolExe.cpp index 60101c168a79..7417167b61ad 100644 --- a/lib/DebugInfo/PDB/PDBSymbolExe.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolExe.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include <utility> @@ -18,6 +19,18 @@ using namespace llvm::pdb; PDBSymbolExe::PDBSymbolExe(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Exe); +} void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +uint32_t PDBSymbolExe::getPointerByteSize() const { + auto Pointer = findOneChild<PDBSymbolTypePointer>(); + if (Pointer) + return Pointer->getLength(); + + if (getMachineType() == PDB_Machine::x86) + return 4; + return 8; +} diff --git a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp index 35251c0cc1c1..0734a1f8314a 100644 --- a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp @@ -85,10 +85,8 @@ private: PDBSymbolFunc::PDBSymbolFunc(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} - -std::unique_ptr<PDBSymbolTypeFunctionSig> PDBSymbolFunc::getSignature() const { - return Session.getConcreteSymbolById<PDBSymbolTypeFunctionSig>(getTypeId()); + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Function); } std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> @@ -96,8 +94,15 @@ PDBSymbolFunc::getArguments() const { return llvm::make_unique<FunctionArgEnumerator>(Session, *this); } -std::unique_ptr<PDBSymbolTypeUDT> PDBSymbolFunc::getClassParent() const { - return Session.getConcreteSymbolById<PDBSymbolTypeUDT>(getClassParentId()); -} - void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +bool PDBSymbolFunc::isDestructor() const { + std::string Name = getName(); + if (Name.empty()) + return false; + if (Name[0] == '~') + return true; + if (Name == "__vecDelDtor") + return true; + return false; +} diff --git a/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp b/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp index 77e996f651df..482c95e3a850 100644 --- a/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolFuncDebugEnd::PDBSymbolFuncDebugEnd( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::FuncDebugEnd); +} void PDBSymbolFuncDebugEnd::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp b/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp index 9c653879176b..ae23c7619e2a 100644 --- a/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolFuncDebugStart::PDBSymbolFuncDebugStart( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::FuncDebugStart); +} void PDBSymbolFuncDebugStart::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolLabel.cpp b/lib/DebugInfo/PDB/PDBSymbolLabel.cpp index d2cfd11c35e4..a67a20d8e352 100644 --- a/lib/DebugInfo/PDB/PDBSymbolLabel.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolLabel.cpp @@ -18,6 +18,8 @@ using namespace llvm::pdb; PDBSymbolLabel::PDBSymbolLabel(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Label); +} void PDBSymbolLabel::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp b/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp index 97d668740818..87bb4044216b 100644 --- a/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolPublicSymbol::PDBSymbolPublicSymbol( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::PublicSymbol); +} void PDBSymbolPublicSymbol::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolThunk.cpp b/lib/DebugInfo/PDB/PDBSymbolThunk.cpp index ef8897d12af4..b2648197f9cc 100644 --- a/lib/DebugInfo/PDB/PDBSymbolThunk.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolThunk.cpp @@ -18,6 +18,8 @@ using namespace llvm::pdb; PDBSymbolThunk::PDBSymbolThunk(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Thunk); +} void PDBSymbolThunk::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp index c010cc5d7678..a8054a42d866 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp @@ -19,12 +19,14 @@ using namespace llvm::pdb; PDBSymbolTypeArray::PDBSymbolTypeArray(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} - -std::unique_ptr<PDBSymbol> PDBSymbolTypeArray::getElementType() const { - return Session.getSymbolById(getTypeId()); + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::ArrayType); } void PDBSymbolTypeArray::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +void PDBSymbolTypeArray::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp index 382c397b24d2..0ee18d471624 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolTypeBaseClass::PDBSymbolTypeBaseClass( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::BaseClass); +} void PDBSymbolTypeBaseClass::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp index e5d65bf5d1fd..0bf563af7df5 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp @@ -18,7 +18,9 @@ using namespace llvm::pdb; PDBSymbolTypeBuiltin::PDBSymbolTypeBuiltin( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::BuiltinType); +} void PDBSymbolTypeBuiltin::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp index 1d80c97f9ede..f617d8d0c2df 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolTypeCustom::PDBSymbolTypeCustom(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::CustomType); +} void PDBSymbolTypeCustom::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp index 535d97dcd21e..68ba87c1cdf8 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp @@ -20,7 +20,9 @@ using namespace llvm::pdb; PDBSymbolTypeDimension::PDBSymbolTypeDimension( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Dimension); +} void PDBSymbolTypeDimension::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp index 788f2b732aaa..2addea072c88 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp @@ -21,15 +21,8 @@ using namespace llvm::pdb; PDBSymbolTypeEnum::PDBSymbolTypeEnum(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} - -std::unique_ptr<PDBSymbolTypeUDT> PDBSymbolTypeEnum::getClassParent() const { - return Session.getConcreteSymbolById<PDBSymbolTypeUDT>(getClassParentId()); -} - -std::unique_ptr<PDBSymbolTypeBuiltin> -PDBSymbolTypeEnum::getUnderlyingType() const { - return Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(getTypeId()); + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Enum); } void PDBSymbolTypeEnum::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp index 5831baebb993..ec27985e91d1 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolTypeFriend::PDBSymbolTypeFriend(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Friend); +} void PDBSymbolTypeFriend::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp index c6f586db9e57..4d5cd63f6857 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp @@ -18,7 +18,9 @@ using namespace llvm::pdb; PDBSymbolTypeFunctionArg::PDBSymbolTypeFunctionArg( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::FunctionArg); +} void PDBSymbolTypeFunctionArg::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp index 057ae260885f..473529d1b043 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp @@ -68,10 +68,8 @@ private: PDBSymbolTypeFunctionSig::PDBSymbolTypeFunctionSig( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} - -std::unique_ptr<PDBSymbol> PDBSymbolTypeFunctionSig::getReturnType() const { - return Session.getSymbolById(getTypeId()); + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::FunctionSig); } std::unique_ptr<IPDBEnumSymbols> @@ -79,13 +77,10 @@ PDBSymbolTypeFunctionSig::getArguments() const { return llvm::make_unique<FunctionArgEnumerator>(Session, *this); } -std::unique_ptr<PDBSymbol> PDBSymbolTypeFunctionSig::getClassParent() const { - uint32_t ClassId = getClassParentId(); - if (ClassId == 0) - return nullptr; - return Session.getSymbolById(ClassId); -} - void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +void PDBSymbolTypeFunctionSig::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp index 072d2cfd42fb..86e0ec4f8565 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolTypeManaged::PDBSymbolTypeManaged( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::ManagedType); +} void PDBSymbolTypeManaged::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp b/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp index 699771450a5d..69819811d61f 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp @@ -19,12 +19,14 @@ using namespace llvm::pdb; PDBSymbolTypePointer::PDBSymbolTypePointer( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} - -std::unique_ptr<PDBSymbol> PDBSymbolTypePointer::getPointeeType() const { - return Session.getSymbolById(getTypeId()); + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::PointerType); } void PDBSymbolTypePointer::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +void PDBSymbolTypePointer::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp index 0f283b9e21a4..102b540e0fef 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp @@ -18,7 +18,9 @@ using namespace llvm::pdb; PDBSymbolTypeTypedef::PDBSymbolTypeTypedef( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::Typedef); +} void PDBSymbolTypeTypedef::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp index c71838cc7a6f..15dc15352165 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp @@ -9,7 +9,15 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" #include <utility> @@ -18,6 +26,8 @@ using namespace llvm::pdb; PDBSymbolTypeUDT::PDBSymbolTypeUDT(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::UDT); +} void PDBSymbolTypeUDT::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp index 6b76db5912ce..9a21855f57f0 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp @@ -18,7 +18,9 @@ using namespace llvm::pdb; PDBSymbolTypeVTable::PDBSymbolTypeVTable(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::VTable); +} void PDBSymbolTypeVTable::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp b/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp index ef509d64bf60..a516a4d2c429 100644 --- a/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolTypeVTableShape::PDBSymbolTypeVTableShape( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::VTableShape); +} void PDBSymbolTypeVTableShape::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp b/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp index 6a62d554f42c..020aec9e98a8 100644 --- a/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp @@ -19,7 +19,9 @@ using namespace llvm::pdb; PDBSymbolUsingNamespace::PDBSymbolUsingNamespace( const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) - : PDBSymbol(PDBSession, std::move(Symbol)) {} + : PDBSymbol(PDBSession, std::move(Symbol)) { + assert(RawSymbol->getSymTag() == PDB_SymType::UsingNamespace); +} void PDBSymbolUsingNamespace::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); diff --git a/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/lib/DebugInfo/PDB/Raw/InfoStream.cpp deleted file mode 100644 index f19535d11806..000000000000 --- a/lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ /dev/null @@ -1,77 +0,0 @@ -//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- 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/PDB/Raw/InfoStream.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawTypes.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} - -Error InfoStream::reload() { - StreamReader Reader(*Stream); - - const InfoStreamHeader *H; - if (auto EC = Reader.readObject(H)) - return joinErrors( - std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "PDB Stream does not contain a header.")); - - switch (H->Version) { - case PdbImplVC70: - case PdbImplVC80: - case PdbImplVC110: - case PdbImplVC140: - break; - default: - return make_error<RawError>(raw_error_code::corrupt_file, - "Unsupported PDB stream version."); - } - - Version = H->Version; - Signature = H->Signature; - Age = H->Age; - Guid = H->Guid; - - return NamedStreams.load(Reader); -} - -uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { - uint32_t Result; - if (!NamedStreams.tryGetValue(Name, Result)) - return 0; - return Result; -} - -iterator_range<StringMapConstIterator<uint32_t>> -InfoStream::named_streams() const { - return NamedStreams.entries(); -} - -PdbRaw_ImplVer InfoStream::getVersion() const { - return static_cast<PdbRaw_ImplVer>(Version); -} - -uint32_t InfoStream::getSignature() const { return Signature; } - -uint32_t InfoStream::getAge() const { return Age; } - -PDB_UniqueId InfoStream::getGuid() const { return Guid; } diff --git a/lib/DebugInfo/PDB/Raw/NameMap.cpp b/lib/DebugInfo/PDB/Raw/NameMap.cpp deleted file mode 100644 index 0f55f58da381..000000000000 --- a/lib/DebugInfo/PDB/Raw/NameMap.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===- NameMap.cpp - PDB Name Map -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SparseBitVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/NameMap.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; - -NameMap::NameMap() = default; - -Error NameMap::load(StreamReader &Stream) { - // This is some sort of weird string-set/hash table encoded in the stream. - // It starts with the number of bytes in the table. - uint32_t NumberOfBytes; - if (auto EC = Stream.readInteger(NumberOfBytes)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map length")); - if (Stream.bytesRemaining() < NumberOfBytes) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid name map length"); - - // Following that field is the starting offset of strings in the name table. - uint32_t StringsOffset = Stream.getOffset(); - Stream.setOffset(StringsOffset + NumberOfBytes); - - // This appears to be equivalent to the total number of strings *actually* - // in the name table. - uint32_t HashSize; - if (auto EC = Stream.readInteger(HashSize)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map hash size")); - - // This appears to be an upper bound on the number of strings in the name - // table. - uint32_t MaxNumberOfStrings; - if (auto EC = Stream.readInteger(MaxNumberOfStrings)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map max strings")); - - if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t))) - return make_error<RawError>(raw_error_code::corrupt_file, - "Implausible number of strings"); - - const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8); - - // This appears to be a hash table which uses bitfields to determine whether - // or not a bucket is 'present'. - uint32_t NumPresentWords; - if (auto EC = Stream.readInteger(NumPresentWords)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map num words")); - - if (NumPresentWords > MaxNumberOfWords) - return make_error<RawError>(raw_error_code::corrupt_file, - "Number of present words is too large"); - - SparseBitVector<> Present; - for (uint32_t I = 0; I != NumPresentWords; ++I) { - uint32_t Word; - if (auto EC = Stream.readInteger(Word)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map word")); - for (unsigned Idx = 0; Idx < 32; ++Idx) - if (Word & (1U << Idx)) - Present.set((I * 32) + Idx); - } - - // This appears to be a hash table which uses bitfields to determine whether - // or not a bucket is 'deleted'. - uint32_t NumDeletedWords; - if (auto EC = Stream.readInteger(NumDeletedWords)) - return joinErrors( - std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map num deleted words")); - - if (NumDeletedWords > MaxNumberOfWords) - return make_error<RawError>(raw_error_code::corrupt_file, - "Number of deleted words is too large"); - - SparseBitVector<> Deleted; - for (uint32_t I = 0; I != NumDeletedWords; ++I) { - uint32_t Word; - if (auto EC = Stream.readInteger(Word)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map word")); - for (unsigned Idx = 0; Idx < 32; ++Idx) - if (Word & (1U << Idx)) - Deleted.set((I * 32) + Idx); - } - - for (unsigned I : Present) { - // For all present entries, dump out their mapping. - (void)I; - - // This appears to be an offset relative to the start of the strings. - // It tells us where the null-terminated string begins. - uint32_t NameOffset; - if (auto EC = Stream.readInteger(NameOffset)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map name offset")); - - // This appears to be a stream number into the stream directory. - uint32_t NameIndex; - if (auto EC = Stream.readInteger(NameIndex)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map name index")); - - // Compute the offset of the start of the string relative to the stream. - uint32_t StringOffset = StringsOffset + NameOffset; - uint32_t OldOffset = Stream.getOffset(); - // Pump out our c-string from the stream. - StringRef Str; - Stream.setOffset(StringOffset); - if (auto EC = Stream.readZeroString(Str)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected name map name")); - - Stream.setOffset(OldOffset); - // Add this to a string-map from name to stream number. - Mapping.insert({Str, NameIndex}); - } - - return Error::success(); -} - -iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const { - return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), - Mapping.end()); -} - -bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const { - auto Iter = Mapping.find(Name); - if (Iter == Mapping.end()) - return false; - Value = Iter->second; - return true; -} diff --git a/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp b/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp deleted file mode 100644 index f570d5931b0f..000000000000 --- a/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===- NameMapBuilder.cpp - PDB Name Map Builder ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/NameMap.h" -#include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> - -using namespace llvm; -using namespace llvm::pdb; - -NameMapBuilder::NameMapBuilder() = default; - -void NameMapBuilder::addMapping(StringRef Name, uint32_t Mapping) { - StringDataBytes += Name.size() + 1; - Map.insert({Name, Mapping}); -} - -Expected<std::unique_ptr<NameMap>> NameMapBuilder::build() { - auto Result = llvm::make_unique<NameMap>(); - Result->Mapping = Map; - return std::move(Result); -} - -uint32_t NameMapBuilder::calculateSerializedLength() const { - uint32_t TotalLength = 0; - - TotalLength += sizeof(support::ulittle32_t); // StringDataBytes value - TotalLength += StringDataBytes; // actual string data - - TotalLength += sizeof(support::ulittle32_t); // Hash Size - TotalLength += sizeof(support::ulittle32_t); // Max Number of Strings - TotalLength += sizeof(support::ulittle32_t); // Num Present Words - // One bitmask word for each present entry - TotalLength += Map.size() * sizeof(support::ulittle32_t); - TotalLength += sizeof(support::ulittle32_t); // Num Deleted Words - - // For each present word, which we are treating as equivalent to the number of - // entries in the table, we have a pair of integers. An offset into the - // string data, and a corresponding stream number. - TotalLength += Map.size() * 2 * sizeof(support::ulittle32_t); - - return TotalLength; -} - -Error NameMapBuilder::commit(msf::StreamWriter &Writer) const { - // The first field is the number of bytes of string data. So add - // up the length of all strings plus a null terminator for each - // one. - uint32_t NumBytes = 0; - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - NumBytes += B->getKeyLength() + 1; - } - - if (auto EC = Writer.writeInteger(NumBytes)) // Number of bytes of string data - return EC; - // Now all of the string data itself. - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - if (auto EC = Writer.writeZeroString(B->getKey())) - return EC; - } - - if (auto EC = Writer.writeInteger(Map.size())) // Hash Size - return EC; - - if (auto EC = Writer.writeInteger(Map.size())) // Max Number of Strings - return EC; - - if (auto EC = Writer.writeInteger(Map.size())) // Num Present Words - return EC; - - // For each entry in the mapping, write a bit mask which represents a bucket - // to store it in. We don't use this, so the value we write isn't important - // to us, it just has to be there. - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - if (auto EC = Writer.writeInteger(1U)) - return EC; - } - - if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words - return EC; - - // Mappings of each word. - uint32_t OffsetSoFar = 0; - for (auto B = Map.begin(), E = Map.end(); B != E; ++B) { - // This is a list of key value pairs where the key is the offset into the - // strings buffer, and the value is a stream number. Write each pair. - if (auto EC = Writer.writeInteger(OffsetSoFar)) - return EC; - - if (auto EC = Writer.writeInteger(B->second)) - return EC; - - OffsetSoFar += B->getKeyLength() + 1; - } - - return Error::success(); -} diff --git a/lib/DebugInfo/PDB/Raw/RawSession.cpp b/lib/DebugInfo/PDB/Raw/RawSession.cpp deleted file mode 100644 index cd3a2064c717..000000000000 --- a/lib/DebugInfo/PDB/Raw/RawSession.cpp +++ /dev/null @@ -1,136 +0,0 @@ -//===- RawSession.cpp - Raw implementation of IPDBSession -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/PDB/GenericError.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/MemoryBuffer.h" -#include <algorithm> -#include <memory> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; - -RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile, - std::unique_ptr<BumpPtrAllocator> Allocator) - : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)) {} - -RawSession::~RawSession() = default; - -Error RawSession::createFromPdb(StringRef Path, - std::unique_ptr<IPDBSession> &Session) { - ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = - MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return make_error<GenericError>(generic_error_code::invalid_path); - - std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); - auto Stream = llvm::make_unique<MemoryBufferByteStream>(std::move(Buffer)); - - auto Allocator = llvm::make_unique<BumpPtrAllocator>(); - auto File = llvm::make_unique<PDBFile>(std::move(Stream), *Allocator); - if (auto EC = File->parseFileHeaders()) - return EC; - if (auto EC = File->parseStreamData()) - return EC; - - Session = - llvm::make_unique<RawSession>(std::move(File), std::move(Allocator)); - - return Error::success(); -} - -Error RawSession::createFromExe(StringRef Path, - std::unique_ptr<IPDBSession> &Session) { - return make_error<RawError>(raw_error_code::feature_unsupported); -} - -uint64_t RawSession::getLoadAddress() const { return 0; } - -void RawSession::setLoadAddress(uint64_t Address) {} - -std::unique_ptr<PDBSymbolExe> RawSession::getGlobalScope() const { - return nullptr; -} - -std::unique_ptr<PDBSymbol> RawSession::getSymbolById(uint32_t SymbolId) const { - return nullptr; -} - -std::unique_ptr<PDBSymbol> -RawSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumLineNumbers> -RawSession::findLineNumbers(const PDBSymbolCompiland &Compiland, - const IPDBSourceFile &File) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumLineNumbers> -RawSession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumSourceFiles> -RawSession::findSourceFiles(const PDBSymbolCompiland *Compiland, - StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBSourceFile> -RawSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, - StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> -RawSession::findCompilandsForSourceFile(StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<PDBSymbolCompiland> -RawSession::findOneCompilandForSourceFile(StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumSourceFiles> RawSession::getAllSourceFiles() const { - return nullptr; -} - -std::unique_ptr<IPDBEnumSourceFiles> RawSession::getSourceFilesForCompiland( - const PDBSymbolCompiland &Compiland) const { - return nullptr; -} - -std::unique_ptr<IPDBSourceFile> -RawSession::getSourceFileById(uint32_t FileId) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumDataStreams> RawSession::getDebugStreams() const { - return nullptr; -} diff --git a/lib/DebugInfo/PDB/UDTLayout.cpp b/lib/DebugInfo/PDB/UDTLayout.cpp new file mode 100644 index 000000000000..61cef093d4ce --- /dev/null +++ b/lib/DebugInfo/PDB/UDTLayout.cpp @@ -0,0 +1,335 @@ +//===- UDTLayout.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/PDB/UDTLayout.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) { + const IPDBSession &Session = Symbol.getSession(); + const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol(); + uint32_t TypeId = RawSymbol.getTypeId(); + return Session.getSymbolById(TypeId); +} + +static uint32_t getTypeLength(const PDBSymbol &Symbol) { + auto SymbolType = getSymbolType(Symbol); + const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + + return RawType.getLength(); +} + +StorageItemBase::StorageItemBase(const UDTLayoutBase &Parent, + const PDBSymbol &Symbol, + const std::string &Name, + uint32_t OffsetInParent, uint32_t Size) + : Parent(Parent), Symbol(Symbol), Name(Name), + OffsetInParent(OffsetInParent), SizeOf(Size) { + UsedBytes.resize(SizeOf, true); +} + +uint32_t StorageItemBase::deepPaddingSize() const { + // sizeof(Field) - sizeof(typeof(Field)) is trailing padding. + return SizeOf - getTypeLength(Symbol); +} + +DataMemberLayoutItem::DataMemberLayoutItem( + const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> DataMember) + : StorageItemBase(Parent, *DataMember, DataMember->getName(), + DataMember->getOffset(), getTypeLength(*DataMember)), + DataMember(std::move(DataMember)) { + auto Type = this->DataMember->getType(); + if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { + // UDT data members might have padding in between fields, but otherwise + // a member should occupy its entire storage. + UsedBytes.resize(SizeOf, false); + UdtLayout = llvm::make_unique<ClassLayout>(std::move(UDT)); + } +} + +const PDBSymbolData &DataMemberLayoutItem::getDataMember() { + return *dyn_cast<PDBSymbolData>(&Symbol); +} + +bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } + +const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { + return *UdtLayout; +} + +uint32_t DataMemberLayoutItem::deepPaddingSize() const { + uint32_t Result = StorageItemBase::deepPaddingSize(); + if (UdtLayout) + Result += UdtLayout->deepPaddingSize(); + return Result; +} + +VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VTable) + : StorageItemBase(Parent, *VTable, "<vtbl>", 0, getTypeLength(*VTable)), + VTable(std::move(VTable)) { + auto VTableType = cast<PDBSymbolTypePointer>(this->VTable->getType()); + ElementSize = VTableType->getLength(); + + Shape = + unique_dyn_cast<PDBSymbolTypeVTableShape>(VTableType->getPointeeType()); + if (Shape) + VTableFuncs.resize(Shape->getCount()); +} + +UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, + uint32_t Size) + : SymbolBase(Symbol), Name(Name), SizeOf(Size) { + UsedBytes.resize(Size); + ChildrenPerByte.resize(Size); + initializeChildren(Symbol); +} + +ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) + : UDTLayoutBase(UDT, UDT.getName(), UDT.getLength()), UDT(UDT) {} + +ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) + : ClassLayout(*UDT) { + OwnedStorage = std::move(UDT); +} + +BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBaseClass> Base) + : UDTLayoutBase(*Base, Base->getName(), Base->getLength()), + StorageItemBase(Parent, *Base, Base->getName(), Base->getOffset(), + Base->getLength()), + Base(std::move(Base)) { + IsVirtualBase = this->Base->isVirtualBaseClass(); +} + +uint32_t UDTLayoutBase::shallowPaddingSize() const { + return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t UDTLayoutBase::deepPaddingSize() const { + uint32_t Result = shallowPaddingSize(); + for (auto &Child : ChildStorage) + Result += Child->deepPaddingSize(); + return Result; +} + +void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { + // Handled bases first, followed by VTables, followed by data members, + // followed by functions, followed by other. This ordering is necessary + // so that bases and vtables get initialized before any functions which + // may override them. + + UniquePtrVector<PDBSymbolTypeBaseClass> Bases; + UniquePtrVector<PDBSymbolTypeVTable> VTables; + UniquePtrVector<PDBSymbolData> Members; + auto Children = Sym.findAllChildren(); + while (auto Child = Children->getNext()) { + if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { + if (Base->isVirtualBaseClass()) + VirtualBases.push_back(std::move(Base)); + else + Bases.push_back(std::move(Base)); + } + + else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { + if (Data->getDataKind() == PDB_DataKind::Member) + Members.push_back(std::move(Data)); + else + Other.push_back(std::move(Child)); + } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) + VTables.push_back(std::move(VT)); + else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child)) + Funcs.push_back(std::move(Func)); + else + Other.push_back(std::move(Child)); + } + + for (auto &Base : Bases) { + auto BL = llvm::make_unique<BaseClassLayout>(*this, std::move(Base)); + BaseClasses.push_back(BL.get()); + + addChildToLayout(std::move(BL)); + } + + for (auto &VT : VTables) { + auto VTLayout = llvm::make_unique<VTableLayoutItem>(*this, std::move(VT)); + + VTable = VTLayout.get(); + + addChildToLayout(std::move(VTLayout)); + continue; + } + + for (auto &Data : Members) { + auto DM = llvm::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); + + addChildToLayout(std::move(DM)); + } + + for (auto &Func : Funcs) { + if (!Func->isVirtual()) + continue; + + if (Func->isIntroVirtualFunction()) + addVirtualIntro(*Func); + else + addVirtualOverride(*Func); + } +} + +void UDTLayoutBase::addVirtualIntro(PDBSymbolFunc &Func) { + // Kind of a hack, but we prefer the more common destructor name that people + // are familiar with, e.g. ~ClassName. It seems there are always both and + // the vector deleting destructor overwrites the nice destructor, so just + // ignore the vector deleting destructor. + if (Func.getName() == "__vecDelDtor") + return; + + if (!VTable) { + // FIXME: Handle this. What's most likely happening is we have an intro + // virtual in a derived class where the base also has an intro virtual. + // In this case the vtable lives in the base. What we really need is + // for each UDTLayoutBase to contain a list of all its vtables, and + // then propagate this list up the hierarchy so that derived classes have + // direct access to their bases' vtables. + return; + } + + uint32_t Stride = VTable->getElementSize(); + + uint32_t Index = Func.getVirtualBaseOffset(); + assert(Index % Stride == 0); + Index /= Stride; + + VTable->setFunction(Index, Func); +} + +VTableLayoutItem *UDTLayoutBase::findVTableAtOffset(uint32_t RelativeOffset) { + if (VTable && VTable->getOffsetInParent() == RelativeOffset) + return VTable; + for (auto Base : BaseClasses) { + uint32_t Begin = Base->getOffsetInParent(); + uint32_t End = Begin + Base->getSize(); + if (RelativeOffset < Begin || RelativeOffset >= End) + continue; + + return Base->findVTableAtOffset(RelativeOffset - Begin); + } + + return nullptr; +} + +void UDTLayoutBase::addVirtualOverride(PDBSymbolFunc &Func) { + auto Signature = Func.getSignature(); + auto ThisAdjust = Signature->getThisAdjust(); + // ThisAdjust tells us which VTable we're looking for. Specifically, it's + // the offset into the current class of the VTable we're looking for. So + // look through the base hierarchy until we find one such that + // AbsoluteOffset(VT) == ThisAdjust + VTableLayoutItem *VT = findVTableAtOffset(ThisAdjust); + if (!VT) { + // FIXME: There really should be a vtable here. If there's not it probably + // means that the vtable is in a virtual base, which we don't yet support. + assert(!VirtualBases.empty()); + return; + } + int32_t OverrideIndex = -1; + // Now we've found the VTable. Func will not have a virtual base offset set, + // so instead we need to compare names and signatures. We iterate each item + // in the VTable. All items should already have non null entries because they + // were initialized by the intro virtual, which was guaranteed to come before. + for (auto ItemAndIndex : enumerate(VT->funcs())) { + auto Item = ItemAndIndex.value(); + assert(Item); + // If the name doesn't match, this isn't an override. Note that it's ok + // for the return type to not match (e.g. co-variant return). + if (Item->getName() != Func.getName()) { + if (Item->isDestructor() && Func.isDestructor()) { + OverrideIndex = ItemAndIndex.index(); + break; + } + continue; + } + // Now make sure it's the right overload. Get the signature of the existing + // vtable method and make sure it has the same arglist and the same cv-ness. + auto ExistingSig = Item->getSignature(); + if (ExistingSig->isConstType() != Signature->isConstType()) + continue; + if (ExistingSig->isVolatileType() != Signature->isVolatileType()) + continue; + + // Now compare arguments. Using the raw bytes of the PDB this would be + // trivial + // because there is an ArgListId and they should be identical. But DIA + // doesn't + // expose this, so the best we can do is iterate each argument and confirm + // that + // each one is identical. + if (ExistingSig->getCount() != Signature->getCount()) + continue; + bool IsMatch = true; + auto ExistingEnumerator = ExistingSig->getArguments(); + auto NewEnumerator = Signature->getArguments(); + for (uint32_t I = 0; I < ExistingEnumerator->getChildCount(); ++I) { + auto ExistingArg = ExistingEnumerator->getNext(); + auto NewArg = NewEnumerator->getNext(); + if (ExistingArg->getSymIndexId() != NewArg->getSymIndexId()) { + IsMatch = false; + break; + } + } + if (!IsMatch) + continue; + + // It's a match! Stick the new function into the VTable. + OverrideIndex = ItemAndIndex.index(); + break; + } + if (OverrideIndex == -1) { + // FIXME: This is probably due to one of the other FIXMEs in this file. + return; + } + VT->setFunction(OverrideIndex, Func); +} + +void UDTLayoutBase::addChildToLayout(std::unique_ptr<StorageItemBase> Child) { + uint32_t Begin = Child->getOffsetInParent(); + uint32_t End = Begin + Child->getSize(); + // Due to the empty base optimization, End might point outside the bounds of + // the parent class. If that happens, just clamp the value. + End = std::min(End, getClassSize()); + + UsedBytes.set(Begin, End); + while (Begin != End) { + ChildrenPerByte[Begin].push_back(Child.get()); + ++Begin; + } + + auto Loc = std::upper_bound( + ChildStorage.begin(), ChildStorage.end(), Begin, + [](uint32_t Off, const std::unique_ptr<StorageItemBase> &Item) { + return Off < Item->getOffsetInParent(); + }); + + ChildStorage.insert(Loc, std::move(Child)); +}
\ No newline at end of file diff --git a/lib/DebugInfo/Symbolize/DIPrinter.cpp b/lib/DebugInfo/Symbolize/DIPrinter.cpp index be5c603a38ef..c1e2536d6e20 100644 --- a/lib/DebugInfo/Symbolize/DIPrinter.cpp +++ b/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -78,8 +78,18 @@ void DIPrinter::print(const DILineInfo &Info, bool Inlined) { std::string Filename = Info.FileName; if (Filename == kDILineInfoBadString) Filename = kBadString; - OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n"; - printContext(Filename, Info.Line); + if (!Verbose) { + OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n"; + printContext(Filename, Info.Line); + return; + } + OS << " Filename: " << Filename << "\n"; + if (Info.StartLine) + OS << "Function start line: " << Info.StartLine << "\n"; + OS << " Line: " << Info.Line << "\n"; + OS << " Column: " << Info.Column << "\n"; + if (Info.Discriminator) + OS << " Discriminator: " << Info.Discriminator << "\n"; } DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { diff --git a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp index f6940080089f..f672680cb9ea 100644 --- a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +++ b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp @@ -1,4 +1,4 @@ -//===-- SymbolizableObjectFile.cpp ----------------------------------------===// +//===- SymbolizableObjectFile.cpp -----------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -12,15 +12,29 @@ //===----------------------------------------------------------------------===// #include "SymbolizableObjectFile.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolSize.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" - -namespace llvm { -namespace symbolize { +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> +#include <memory> +#include <string> +#include <system_error> +#include <utility> +#include <vector> +using namespace llvm; using namespace object; +using namespace symbolize; static DILineInfoSpecifier getDILineInfoSpecifier(FunctionNameKind FNKind) { @@ -73,14 +87,17 @@ SymbolizableObjectFile::SymbolizableObjectFile(ObjectFile *Obj, : Module(Obj), DebugInfoContext(std::move(DICtx)) {} namespace { + struct OffsetNamePair { uint32_t Offset; StringRef Name; + bool operator<(const OffsetNamePair &R) const { return Offset < R.Offset; } }; -} + +} // end anonymous namespace std::error_code SymbolizableObjectFile::addCoffExportSymbols( const COFFObjectFile *CoffObj) { @@ -147,7 +164,7 @@ std::error_code SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol, return errorToErrorCode(SymbolNameOrErr.takeError()); StringRef SymbolName = *SymbolNameOrErr; // Mach-O symbol table names have leading underscore, skip it. - if (Module->isMachO() && SymbolName.size() > 0 && SymbolName[0] == '_') + if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_') SymbolName = SymbolName.drop_front(); // FIXME: If a function has alias, there are two entries in symbol table // with same address size. Make sure we choose the correct one. @@ -252,7 +269,3 @@ DIGlobal SymbolizableObjectFile::symbolizeData(uint64_t ModuleOffset) const { Res.Size); return Res; } - -} // namespace symbolize -} // namespace llvm - diff --git a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h index 8583b6a36e63..216cca8de4f5 100644 --- a/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h +++ b/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h @@ -1,4 +1,4 @@ -//===-- SymbolizableObjectFile.h -------------------------------- C++ -----===// +//===- SymbolizableObjectFile.h ---------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -13,14 +13,20 @@ #ifndef LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H #define LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" +#include "llvm/Support/ErrorOr.h" +#include <cstdint> #include <map> +#include <memory> +#include <string> +#include <system_error> namespace llvm { + class DataExtractor; -} -namespace llvm { namespace symbolize { class SymbolizableObjectFile : public SymbolizableModule { @@ -65,6 +71,7 @@ private: // If size is 0, assume that symbol occupies the whole memory range up to // the following symbol. uint64_t Size; + friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) { return s1.Addr < s2.Addr; } @@ -76,7 +83,8 @@ private: std::unique_ptr<DIContext> DICtx); }; -} // namespace symbolize -} // namespace llvm +} // end namespace symbolize + +} // end namespace llvm -#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H +#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H |