diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo')
79 files changed, 6124 insertions, 4135 deletions
diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ByteStream.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ByteStream.cpp deleted file mode 100644 index 2c43bc6..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/ByteStream.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===- ByteStream.cpp - Reads stream data from a byte sequence ------------===// -// -// 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/ByteStream.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src, - ArrayRef<uint8_t> Dest) { - return make_error<CodeViewError>(cv_error_code::operation_unsupported, - "ByteStream is immutable."); -} - -static Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Src, - MutableArrayRef<uint8_t> Dest) { - if (Dest.size() < Src.size()) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - if (Offset > Src.size() - Dest.size()) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - - ::memcpy(Dest.data() + Offset, Src.data(), Src.size()); - return Error::success(); -} - -template <bool Writable> -Error ByteStream<Writable>::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { - if (Offset > Data.size()) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - if (Data.size() < Size + Offset) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - Buffer = Data.slice(Offset, Size); - return Error::success(); -} - -template <bool Writable> -Error ByteStream<Writable>::readLongestContiguousChunk( - uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { - if (Offset >= Data.size()) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - Buffer = Data.slice(Offset); - return Error::success(); -} - -template <bool Writable> -Error ByteStream<Writable>::writeBytes(uint32_t Offset, - ArrayRef<uint8_t> Buffer) const { - return ::writeBytes(Offset, Buffer, Data); -} - -template <bool Writable> uint32_t ByteStream<Writable>::getLength() const { - return Data.size(); -} - -template <bool Writable> Error ByteStream<Writable>::commit() const { - return Error::success(); -} - -template <bool Writable> StringRef ByteStream<Writable>::str() const { - const char *CharData = reinterpret_cast<const char *>(Data.data()); - return StringRef(CharData, Data.size()); -} - -namespace llvm { -namespace codeview { -template class ByteStream<true>; -template class ByteStream<false>; -} -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp new file mode 100644 index 0000000..75cfd0d --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp @@ -0,0 +1,73 @@ +//===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" +#include "llvm/DebugInfo/MSF/ByteStream.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) {} + +template <typename T> +static Error visitKnownRecord(CVSymbol &Record, + SymbolVisitorCallbacks &Callbacks) { + SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.Type); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; + return Error::success(); +} + +Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) { + if (auto EC = Callbacks.visitSymbolBegin(Record)) + return EC; + + switch (Record.Type) { + default: + if (auto EC = Callbacks.visitUnknownSymbol(Record)) + return EC; + break; +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \ + return EC; \ + break; \ + } +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + SYMBOL_RECORD(EnumVal, EnumVal, AliasName) +#include "llvm/DebugInfo/CodeView/CVSymbolTypes.def" + } + + if (auto EC = Callbacks.visitSymbolEnd(Record)) + return EC; + + return Error::success(); +} + +Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) { + for (auto I : Symbols) { + if (auto EC = visitSymbolRecord(I)) + return EC; + } + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp new file mode 100644 index 0000000..fcd239c --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp @@ -0,0 +1,73 @@ +//===-- CVTypeDumper.cpp - CodeView type info dumper ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) { + TypeDatabaseVisitor DBV(TypeDB); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + Pipeline.addCallbackToPipeline(Dumper); + + CVTypeVisitor Visitor(Pipeline); + + CVType RecordCopy = Record; + if (auto EC = Visitor.visitTypeRecord(RecordCopy)) + return EC; + return Error::success(); +} + +Error CVTypeDumper::dump(const CVTypeArray &Types, + TypeVisitorCallbacks &Dumper) { + TypeDatabaseVisitor DBV(TypeDB); + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(DBV); + Pipeline.addCallbackToPipeline(Dumper); + + CVTypeVisitor Visitor(Pipeline); + + if (auto EC = Visitor.visitTypeStream(Types)) + return EC; + return Error::success(); +} + +Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) { + msf::ByteStream Stream(Data); + CVTypeArray Types; + msf::StreamReader Reader(Stream); + if (auto EC = Reader.readArray(Types, Reader.getLength())) + return EC; + + return dump(Types, Dumper); +} + +void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeDatabase &DB) { + StringRef TypeName; + if (!TI.isNoneType()) + TypeName = DB.getTypeName(TI); + if (!TypeName.empty()) + Printer.printHex(FieldName, TypeName, TI.getIndex()); + else + Printer.printHex(FieldName, TI.getIndex()); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index 09f7221..5171e24 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -9,115 +9,128 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" + using namespace llvm; using namespace llvm::codeview; +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + 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)); +static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Type); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; return Error::success(); } -CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) - : Callbacks(Callbacks) {} +template <typename T> +static Error visitKnownMember(CVMemberRecord &Record, + TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord)) + return EC; + return Error::success(); +} -Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) { - ArrayRef<uint8_t> LeafData = Record.Data; +Error CVTypeVisitor::visitTypeRecord(CVType &Record) { if (auto EC = Callbacks.visitTypeBegin(Record)) return EC; + switch (Record.Type) { default: if (auto EC = Callbacks.visitUnknownType(Record)) return EC; break; - case LF_FIELDLIST: - if (auto EC = Callbacks.visitFieldListBegin(Record)) - return EC; - if (auto EC = visitFieldList(Record)) - return EC; - if (auto EC = Callbacks.visitFieldListEnd(Record)) - return EC; - break; #define TYPE_RECORD(EnumName, EnumVal, Name) \ case EnumName: { \ - TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \ - auto Result = Name##Record::deserialize(RK, LeafData); \ - if (Result.getError()) \ - return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \ - if (auto EC = Callbacks.visit##Name(*Result)) \ + if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \ return EC; \ break; \ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ TYPE_RECORD(EnumVal, EnumVal, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" } + if (auto EC = Callbacks.visitTypeEnd(Record)) return EC; - return Error::success(); -} -/// Visits the type records in Data. Sets the error flag on parse failures. -Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { - for (const auto &I : Types) { - if (auto EC = visitTypeRecord(I)) - return EC; - } return Error::success(); } -Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) { - if (Data.empty()) - return Error::success(); - uint8_t Leaf = Data.front(); - if (Leaf < LF_PAD0) - return Error::success(); - // Leaf is greater than 0xf0. We should advance by the number of bytes in - // the low 4 bits. - unsigned BytesToAdvance = Leaf & 0x0F; - if (Data.size() < BytesToAdvance) { - return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid padding bytes!"); - } - Data = Data.drop_front(BytesToAdvance); - return Error::success(); -} +static Error visitMemberRecord(CVMemberRecord &Record, + TypeVisitorCallbacks &Callbacks) { + if (auto EC = Callbacks.visitMemberBegin(Record)) + return EC; -/// Visits individual member records of a field list record. Member records do -/// not describe their own length, and need special handling. -Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) { - ArrayRef<uint8_t> RecordData = Record.Data; - while (!RecordData.empty()) { - const ulittle16_t *LeafPtr; - if (auto EC = takeObject(RecordData, LeafPtr)) + switch (Record.Kind) { + default: + if (auto EC = Callbacks.visitUnknownMember(Record)) return EC; - TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); - switch (Leaf) { - default: - // Field list records do not describe their own length, so we cannot - // continue parsing past an unknown member type. - if (auto EC = Callbacks.visitUnknownMember(Record)) - return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); + break; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ case EnumName: { \ - TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \ - auto Result = Name##Record::deserialize(RK, RecordData); \ - if (Result.getError()) \ - return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \ - if (auto EC = Callbacks.visit##Name(*Result)) \ + if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \ return EC; \ break; \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ MEMBER_RECORD(EnumVal, EnumVal, AliasName) +#define TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" - } - if (auto EC = skipPadding(RecordData)) + } + + if (auto EC = Callbacks.visitMemberEnd(Record)) + return EC; + + return Error::success(); +} + +Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) { + return ::visitMemberRecord(Record, Callbacks); +} + +/// Visits the type records in Data. Sets the error flag on parse failures. +Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { + for (auto I : Types) { + if (auto EC = visitTypeRecord(I)) return EC; } return Error::success(); } + +Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { + FieldListDeserializer Deserializer(Reader); + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Callbacks); + + TypeLeafKind Leaf; + while (!Reader.empty()) { + if (auto EC = Reader.readEnum(Leaf)) + return EC; + + CVMemberRecord Record; + Record.Kind = Leaf; + if (auto EC = ::visitMemberRecord(Record, Pipeline)) + return EC; + } + + return Error::success(); +} + +Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) { + msf::ByteStream S(Data); + msf::StreamReader SR(S); + return visitFieldListMemberStream(SR); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp index aad1d8b..55c10c0 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewError.cpp @@ -20,7 +20,7 @@ namespace { // deal with the Error value directly, rather than converting to error_code. class CodeViewErrorCategory : public std::error_category { public: - const char *name() const LLVM_NOEXCEPT override { return "llvm.codeview"; } + const char *name() const noexcept override { return "llvm.codeview"; } std::string message(int Condition) const override { switch (static_cast<cv_error_code>(Condition)) { @@ -33,6 +33,8 @@ public: return "The CodeView record is corrupted."; case cv_error_code::operation_unsupported: return "The requested operation is not supported."; + case cv_error_code::unknown_member_record: + return "The member record is of an unknown type."; } llvm_unreachable("Unrecognized cv_error_code"); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp new file mode 100644 index 0000000..9bd85cf --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -0,0 +1,242 @@ +//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) { + RecordLimit Limit; + Limit.MaxLength = MaxLength; + Limit.BeginOffset = getCurrentOffset(); + Limits.push_back(Limit); + return Error::success(); +} + +Error CodeViewRecordIO::endRecord() { + assert(!Limits.empty() && "Not in a record!"); + Limits.pop_back(); + return Error::success(); +} + +uint32_t CodeViewRecordIO::maxFieldLength() const { + assert(!Limits.empty() && "Not in a record!"); + + // The max length of the next field is the minimum of all lengths that would + // be allowed by any of the sub-records we're in. In practice, we can only + // ever be at most 1 sub-record deep (in a FieldList), but this works for + // the general case. + uint32_t Offset = getCurrentOffset(); + Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset); + for (auto X : makeArrayRef(Limits).drop_front()) { + Optional<uint32_t> ThisMin = X.bytesRemaining(Offset); + if (ThisMin.hasValue()) + Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin; + } + assert(Min.hasValue() && "Every field must have a maximum length!"); + + return *Min; +} + +Error CodeViewRecordIO::skipPadding() { + assert(!isWriting() && "Cannot skip padding while writing!"); + + if (Reader->bytesRemaining() == 0) + return Error::success(); + + uint8_t Leaf = Reader->peek(); + if (Leaf < LF_PAD0) + return Error::success(); + // Leaf is greater than 0xf0. We should advance by the number of bytes in + // the low 4 bits. + unsigned BytesToAdvance = Leaf & 0x0F; + return Reader->skip(BytesToAdvance); +} + +Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes) { + if (isWriting()) { + if (auto EC = Writer->writeBytes(Bytes)) + return EC; + } else { + if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining())) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes) { + ArrayRef<uint8_t> BytesRef(Bytes); + if (auto EC = mapByteVectorTail(BytesRef)) + return EC; + if (!isWriting()) + Bytes.assign(BytesRef.begin(), BytesRef.end()); + + return Error::success(); +} + +Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd) { + if (isWriting()) { + if (auto EC = Writer->writeInteger(TypeInd.getIndex())) + return EC; + return Error::success(); + } + + uint32_t I; + if (auto EC = Reader->readInteger(I)) + return EC; + TypeInd.setIndex(I); + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value) { + if (isWriting()) { + if (Value >= 0) { + if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value))) + return EC; + } else { + if (auto EC = writeEncodedSignedInteger(Value)) + return EC; + } + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getExtValue(); + } + + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value) { + if (isWriting()) { + if (auto EC = writeEncodedUnsignedInteger(Value)) + return EC; + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getZExtValue(); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value) { + if (isWriting()) { + if (Value.isSigned()) + return writeEncodedSignedInteger(Value.getSExtValue()); + return writeEncodedUnsignedInteger(Value.getZExtValue()); + } + + return consume(*Reader, Value); +} + +Error CodeViewRecordIO::mapStringZ(StringRef &Value) { + if (isWriting()) { + // Truncate if we attempt to write too much. + StringRef S = Value.take_front(maxFieldLength() - 1); + if (auto EC = Writer->writeZeroString(S)) + return EC; + } else { + if (auto EC = Reader->readZeroString(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapGuid(StringRef &Guid) { + constexpr uint32_t GuidSize = 16; + if (maxFieldLength() < GuidSize) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + if (isWriting()) { + assert(Guid.size() == 16 && "Invalid Guid Size!"); + if (auto EC = Writer->writeFixedString(Guid)) + return EC; + } else { + if (auto EC = Reader->readFixedString(Guid, 16)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value) { + if (isWriting()) { + for (auto V : Value) { + if (auto EC = mapStringZ(V)) + return EC; + } + if (auto EC = Writer->writeInteger(uint8_t(0))) + return EC; + } else { + StringRef S; + if (auto EC = mapStringZ(S)) + return EC; + while (!S.empty()) { + Value.push_back(S); + if (auto EC = mapStringZ(S)) + return EC; + }; + } + return Error::success(); +} + +Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { + assert(Value < 0 && "Encoded integer is not signed!"); + if (Value >= std::numeric_limits<int8_t>::min()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_CHAR))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<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))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<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))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<int32_t>(Value))) + return EC; + } else { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_QUADWORD))) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { + if (Value < LF_NUMERIC) { + if (auto EC = Writer->writeInteger(static_cast<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))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<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))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<uint32_t>(Value))) + return EC; + } else { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_UQUADWORD))) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp index d59271b..0e20bcb 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -24,6 +24,12 @@ static const EnumEntry<SymbolKind> SymbolTypeNames[] = { #undef CV_SYMBOL }; +static const EnumEntry<TypeLeafKind> TypeLeafNames[] = { +#define CV_TYPE(name, val) {#name, name}, +#include "llvm/DebugInfo/CodeView/TypeRecords.def" +#undef CV_TYPE +}; + static const EnumEntry<uint16_t> RegisterNames[] = { CV_ENUM_CLASS_ENT(RegisterId, Unknown), CV_ENUM_CLASS_ENT(RegisterId, VFrame), @@ -324,6 +330,10 @@ ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() { return makeArrayRef(SymbolTypeNames); } +ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames() { + return makeArrayRef(TypeLeafNames); +} + ArrayRef<EnumEntry<uint16_t>> getRegisterNames() { return makeArrayRef(RegisterNames); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp deleted file mode 100644 index 5f229e3..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ /dev/null @@ -1,132 +0,0 @@ -//===-- FieldListRecordBuilder.cpp ----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -FieldListRecordBuilder::FieldListRecordBuilder() - : ListRecordBuilder(TypeRecordKind::FieldList) {} - -void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getBaseType()); - Builder.writeEncodedUnsignedInteger(Record.getBaseOffset()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::Enumerator); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - // FIXME: Handle full APInt such as __int128. - Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getType()); - Builder.writeEncodedUnsignedInteger(Record.getFieldOffset()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeOverloadedMethod( - const OverloadedMethodRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod); - Builder.writeUInt16(Record.getNumOverloads()); - Builder.writeTypeIndex(Record.getMethodList()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - uint16_t Flags = static_cast<uint16_t>(Record.getAccess()); - Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift; - Flags |= static_cast<uint16_t>(Record.getOptions()); - - Builder.writeTypeRecordKind(TypeRecordKind::OneMethod); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getType()); - if (Record.isIntroducingVirtual()) { - assert(Record.getVFTableOffset() >= 0); - Builder.writeInt32(Record.getVFTableOffset()); - } else { - assert(Record.getVFTableOffset() == -1); - } - - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Record.getNestedType()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeStaticDataMember( - const StaticDataMemberRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getType()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeVirtualBaseClass( - const VirtualBaseClassRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getBaseType()); - Builder.writeTypeIndex(Record.getVBPtrType()); - Builder.writeEncodedInteger(Record.getVBPtrOffset()); - Builder.writeEncodedUnsignedInteger(Record.getVTableIndex()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::VFPtr); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Record.getType()); - - finishSubRecord(); -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp deleted file mode 100644 index eb79e8a..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===-- ListRecordBuilder.cpp ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" - -using namespace llvm; -using namespace codeview; - -ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) - : Kind(Kind), Builder(Kind) {} - -void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) { - TypeRecordBuilder &Builder = getBuilder(); - - assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit"); - - Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); - Builder.writeUInt16(0); - Builder.writeTypeIndex(R.getContinuationIndex()); - - // End the current segment manually so that nothing comes after the - // continuation. - ContinuationOffsets.push_back(Builder.size()); - SubrecordStart = Builder.size(); -} - -void ListRecordBuilder::finishSubRecord() { - // The type table inserts a 16 bit size field before each list, so factor that - // into our alignment padding. - uint32_t Remainder = - (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4; - if (Remainder != 0) { - for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0; - --PaddingBytesLeft) { - Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft); - } - } - - // Check if this subrecord makes the current segment not fit in 64K minus the - // space for a continuation record (8 bytes). If the segment does not fit, - // back up and insert a continuation record, sliding the current subrecord - // down. - if (getLastContinuationSize() > 65535 - 8) { - assert(SubrecordStart != 0 && "can't slide from the start!"); - SmallString<128> SubrecordCopy( - Builder.str().slice(SubrecordStart, Builder.size())); - assert(SubrecordCopy.size() < 65530 && "subrecord is too large to slide!"); - Builder.truncate(SubrecordStart); - - // Write a placeholder continuation record. - Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); - Builder.writeUInt16(0); - Builder.writeUInt32(0); - ContinuationOffsets.push_back(Builder.size()); - assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size"); - assert(getLastContinuationSize() < 65535 && "segment too big"); - - // Start a new list record of the appropriate kind, and copy the previous - // subrecord into place. - Builder.writeTypeRecordKind(Kind); - Builder.writeBytes(SubrecordCopy); - } - - SubrecordStart = Builder.size(); -} - -TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) { - // Get the continuation segments as a reversed vector of StringRefs for - // convenience. - SmallVector<StringRef, 1> Segments; - StringRef Data = str(); - size_t LastEnd = 0; - for (size_t SegEnd : ContinuationOffsets) { - Segments.push_back(Data.slice(LastEnd, SegEnd)); - LastEnd = SegEnd; - } - Segments.push_back(Data.slice(LastEnd, Builder.size())); - - // Pop the last record off and emit it directly. - StringRef LastRec = Segments.pop_back_val(); - TypeIndex ContinuationIndex = Table.writeRecord(LastRec); - - // Emit each record with a continuation in reverse order, so that each one - // references the previous record. - for (StringRef Rec : reverse(Segments)) { - assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) == - unsigned(Kind)); - ulittle32_t *ContinuationPtr = - reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1; - *ContinuationPtr = ContinuationIndex.getIndex(); - ContinuationIndex = Table.writeRecord(Rec); - } - return ContinuationIndex; -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp deleted file mode 100644 index 8b9e73b..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" - -using namespace llvm; -using namespace codeview; - -TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) { - assert(Data.size() <= UINT16_MAX); - auto I = HashedRecords.find(Data); - if (I != HashedRecords.end()) { - return I->second; - } - - // The record provided by the user lacks the 2 byte size field prefix and is - // not padded to 4 bytes. Ultimately, that is what gets emitted in the object - // file, so pad it out now. - const int SizeOfRecLen = 2; - const int Align = 4; - int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align); - assert(TotalSize - SizeOfRecLen <= UINT16_MAX); - char *Mem = - reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align)); - *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen); - memcpy(Mem + SizeOfRecLen, Data.data(), Data.size()); - for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I) - Mem[I] = LF_PAD0 + (TotalSize - I); - - TypeIndex TI(static_cast<uint32_t>(Records.size()) + - TypeIndex::FirstNonSimpleIndex); - - // Use only the data supplied by the user as a key to the hash table, so that - // future lookups will succeed. - HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI)); - Records.push_back(StringRef(Mem, TotalSize)); - - return TI; -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp deleted file mode 100644 index ae089a3..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===-- MethodListRecordBuilder.cpp ---------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -MethodListRecordBuilder::MethodListRecordBuilder() - : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {} - -void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind, - MethodOptions Options, TypeIndex Type, - int32_t VTableSlotOffset) { - TypeRecordBuilder &Builder = getBuilder(); - - uint16_t Flags = static_cast<uint16_t>(Access); - Flags |= static_cast<uint16_t>(Kind) << MethodKindShift; - Flags |= static_cast<uint16_t>(Options); - - Builder.writeUInt16(Flags); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Type); - switch (Kind) { - case MethodKind::IntroducingVirtual: - case MethodKind::PureIntroducingVirtual: - assert(VTableSlotOffset >= 0); - Builder.writeInt32(VTableSlotOffset); - break; - - default: - assert(VTableSlotOffset == -1); - break; - } - - // TODO: Fail if too big? -} - -void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) { - writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), - Method.getType(), Method.getVTableSlotOffset()); -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp index 2e31ed6..768ebaa 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -9,17 +9,20 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} -ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, StreamRef Data) +ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, + ReadableStreamRef Data) : Kind(Kind), Data(Data) {} -Error ModuleSubstream::initialize(StreamRef Stream, ModuleSubstream &Info) { +Error ModuleSubstream::initialize(ReadableStreamRef Stream, + ModuleSubstream &Info) { const ModuleSubsectionHeader *Header; StreamReader Reader(Stream); if (auto EC = Reader.readObject(Header)) @@ -39,4 +42,4 @@ uint32_t ModuleSubstream::getRecordLength() const { ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; } -StreamRef ModuleSubstream::getRecordData() const { return Data; } +ReadableStreamRef ModuleSubstream::getRecordData() const { return Data; } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp index 6f237ee..5247932 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -8,50 +8,54 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamRef.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; -Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) { +Error IModuleSubstreamVisitor::visitSymbols(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::Symbols, Data); } -Error IModuleSubstreamVisitor::visitLines(StreamRef Data, +Error IModuleSubstreamVisitor::visitLines(ReadableStreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines) { return visitUnknown(ModuleSubstreamKind::Lines, Data); } -Error IModuleSubstreamVisitor::visitStringTable(StreamRef Data) { +Error IModuleSubstreamVisitor::visitStringTable(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::StringTable, Data); } Error IModuleSubstreamVisitor::visitFileChecksums( - StreamRef Data, const FileChecksumArray &Checksums) { + ReadableStreamRef Data, const FileChecksumArray &Checksums) { return visitUnknown(ModuleSubstreamKind::FileChecksums, Data); } -Error IModuleSubstreamVisitor::visitFrameData(StreamRef Data) { +Error IModuleSubstreamVisitor::visitFrameData(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::FrameData, Data); } -Error IModuleSubstreamVisitor::visitInlineeLines(StreamRef Data) { +Error IModuleSubstreamVisitor::visitInlineeLines(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::InlineeLines, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeImports(StreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeImports(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeExports(StreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeExports(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data); } -Error IModuleSubstreamVisitor::visitILLines(StreamRef Data) { +Error IModuleSubstreamVisitor::visitILLines(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::ILLines, Data); } -Error IModuleSubstreamVisitor::visitFuncMDTokenMap(StreamRef Data) { +Error IModuleSubstreamVisitor::visitFuncMDTokenMap(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitTypeMDTokenMap(StreamRef Data) { +Error IModuleSubstreamVisitor::visitTypeMDTokenMap(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitMergedAssemblyInput(StreamRef Data) { +Error IModuleSubstreamVisitor::visitMergedAssemblyInput( + ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data); } -Error IModuleSubstreamVisitor::visitCoffSymbolRVA(StreamRef Data) { +Error IModuleSubstreamVisitor::visitCoffSymbolRVA(ReadableStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp b/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp index ab9206a..6f29caa 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp @@ -14,7 +14,9 @@ #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" using namespace llvm; using namespace llvm::codeview; @@ -31,141 +33,117 @@ StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { return getBytesAsCharacters(LeafData).split('\0').first; } -std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) { +Error llvm::codeview::consume(msf::StreamReader &Reader, APSInt &Num) { // Used to avoid overload ambiguity on APInt construtor. bool FalseVal = false; - if (Data.size() < 2) - return std::make_error_code(std::errc::illegal_byte_sequence); - uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data()); - Data = Data.drop_front(2); + uint16_t Short; + if (auto EC = Reader.readInteger(Short)) + return EC; + if (Short < LF_NUMERIC) { Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), /*isUnsigned=*/true); - return std::error_code(); + return Error::success(); } + switch (Short) { - case LF_CHAR: - if (Data.size() < 1) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/8, - *reinterpret_cast<const int8_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(1); - return std::error_code(); - case LF_SHORT: - if (Data.size() < 2) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast<const little16_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(2); - return std::error_code(); - case LF_USHORT: - if (Data.size() < 2) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/16, - *reinterpret_cast<const ulittle16_t *>(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(2); - return std::error_code(); - case LF_LONG: - if (Data.size() < 4) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast<const little32_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(4); - return std::error_code(); - case LF_ULONG: - if (Data.size() < 4) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/32, - *reinterpret_cast<const ulittle32_t *>(Data.data()), - /*isSigned=*/FalseVal), - /*isUnsigned=*/true); - Data = Data.drop_front(4); - return std::error_code(); - case LF_QUADWORD: - if (Data.size() < 8) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast<const little64_t *>(Data.data()), - /*isSigned=*/true), - /*isUnsigned=*/false); - Data = Data.drop_front(8); - return std::error_code(); - case LF_UQUADWORD: - if (Data.size() < 8) - return std::make_error_code(std::errc::illegal_byte_sequence); - Num = APSInt(APInt(/*numBits=*/64, - *reinterpret_cast<const ulittle64_t *>(Data.data()), - /*isSigned=*/false), - /*isUnsigned=*/true); - Data = Data.drop_front(8); - return std::error_code(); + case LF_CHAR: { + int8_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(8, N, true), false); + return Error::success(); + } + case LF_SHORT: { + int16_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(16, N, true), false); + return Error::success(); + } + case LF_USHORT: { + uint16_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(16, N, false), true); + return Error::success(); } - return std::make_error_code(std::errc::illegal_byte_sequence); + case LF_LONG: { + int32_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(32, N, true), false); + return Error::success(); + } + case LF_ULONG: { + uint32_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(32, N, FalseVal), true); + return Error::success(); + } + case LF_QUADWORD: { + int64_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(64, N, true), false); + return Error::success(); + } + case LF_UQUADWORD: { + uint64_t N; + if (auto EC = Reader.readInteger(N)) + return EC; + Num = APSInt(APInt(64, N, false), true); + return Error::success(); + } + } + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Buffer contains invalid APSInt type"); } -std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) { +Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); - auto EC = consume(Bytes, Num); - Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); + msf::ByteStream S(Bytes); + msf::StreamReader 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. -std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data, - uint64_t &Num) { +Error llvm::codeview::consume_numeric(msf::StreamReader &Reader, + uint64_t &Num) { APSInt N; - if (auto EC = consume(Data, N)) + if (auto EC = consume(Reader, N)) return EC; if (N.isSigned() || !N.isIntN(64)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Data is not a numeric value!"); Num = N.getLimitedValue(); - return std::error_code(); + return Error::success(); } -std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, - uint32_t &Item) { - const support::ulittle32_t *IntPtr; - if (auto EC = consumeObject(Data, IntPtr)) - return EC; - Item = *IntPtr; - return std::error_code(); +Error llvm::codeview::consume(msf::StreamReader &Reader, uint32_t &Item) { + return Reader.readInteger(Item); } -std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) { +Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); - auto EC = consume(Bytes, Item); - Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); + msf::ByteStream S(Bytes); + msf::StreamReader SR(S); + auto EC = consume(SR, Item); + Data = Data.take_back(SR.bytesRemaining()); return EC; } -std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, - int32_t &Item) { - const support::little32_t *IntPtr; - if (auto EC = consumeObject(Data, IntPtr)) - return EC; - Item = *IntPtr; - return std::error_code(); +Error llvm::codeview::consume(msf::StreamReader &Reader, int32_t &Item) { + return Reader.readInteger(Item); } -std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, - StringRef &Item) { - if (Data.empty()) - return std::make_error_code(std::errc::illegal_byte_sequence); - - StringRef Rest; - std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0'); - // We expect this to be null terminated. If it was not, it is an error. - if (Data.size() == Item.size()) - return std::make_error_code(std::errc::illegal_byte_sequence); +Error llvm::codeview::consume(msf::StreamReader &Reader, StringRef &Item) { + if (Reader.empty()) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Null terminated string buffer is empty!"); - Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end()); - return std::error_code(); + return Reader.readZeroString(Item); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp index 6763c3d..fd54fba 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -11,11 +11,15 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" #include <system_error> @@ -26,29 +30,30 @@ using namespace llvm::codeview; namespace { /// Use this private dumper implementation to keep implementation details about /// the visitor out of SymbolDumper.h. -class CVSymbolDumperImpl : public CVSymbolVisitor<CVSymbolDumperImpl> { +class CVSymbolDumperImpl : public SymbolVisitorCallbacks { public: - CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate, + CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate, ScopedPrinter &W, bool PrintRecordBytes) - : CVSymbolVisitor(ObjDelegate), CVTD(CVTD), ObjDelegate(ObjDelegate), - W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} + : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W), + PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} /// CVSymbolVisitor overrides. #define SYMBOL_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(SymbolKind Kind, Name &Record); + Error visitKnownRecord(CVSymbol &CVR, Name &Record) override; #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/CVSymbolTypes.def" - void visitSymbolBegin(SymbolKind Kind, ArrayRef<uint8_t> Data); - void visitSymbolEnd(SymbolKind Kind, ArrayRef<uint8_t> OriginalSymData); - void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data); + Error visitSymbolBegin(CVSymbol &Record) override; + Error visitSymbolEnd(CVSymbol &Record) override; + Error visitUnknownSymbol(CVSymbol &Record) override; private: void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, uint32_t RelocationOffset); void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); + void printTypeIndex(StringRef FieldName, TypeIndex TI); - CVTypeDumper &CVTD; + TypeDatabase &TypeDB; SymbolDumpDelegate *ObjDelegate; ScopedPrinter &W; @@ -76,376 +81,395 @@ void CVSymbolDumperImpl::printLocalVariableAddrGap( } } -void CVSymbolDumperImpl::visitSymbolBegin(SymbolKind Kind, - ArrayRef<uint8_t> Data) {} +void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { + CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB); +} + +Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { + return Error::success(); +} -void CVSymbolDumperImpl::visitSymbolEnd(SymbolKind Kind, - ArrayRef<uint8_t> OriginalSymData) { +Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) { if (PrintRecordBytes && ObjDelegate) - ObjDelegate->printBinaryBlockWithRelocs("SymData", OriginalSymData); + ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content()); + return Error::success(); } -void CVSymbolDumperImpl::visitBlockSym(SymbolKind Kind, BlockSym &Block) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { DictScope S(W, "BlockStart"); StringRef LinkageName; - W.printHex("PtrParent", Block.Header.PtrParent); - W.printHex("PtrEnd", Block.Header.PtrEnd); - W.printHex("CodeSize", Block.Header.CodeSize); + W.printHex("PtrParent", Block.Parent); + W.printHex("PtrEnd", Block.End); + W.printHex("CodeSize", Block.CodeSize); if (ObjDelegate) { ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(), - Block.Header.CodeOffset, &LinkageName); + Block.CodeOffset, &LinkageName); } - W.printHex("Segment", Block.Header.Segment); + W.printHex("Segment", Block.Segment); W.printString("BlockName", Block.Name); W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitThunk32Sym(SymbolKind Kind, Thunk32Sym &Thunk) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { DictScope S(W, "Thunk32"); - W.printNumber("Parent", Thunk.Header.Parent); - W.printNumber("End", Thunk.Header.End); - W.printNumber("Next", Thunk.Header.Next); - W.printNumber("Off", Thunk.Header.Off); - W.printNumber("Seg", Thunk.Header.Seg); - W.printNumber("Len", Thunk.Header.Len); - W.printEnum("Ordinal", Thunk.Header.Ord, getThunkOrdinalNames()); -} - -void CVSymbolDumperImpl::visitTrampolineSym(SymbolKind Kind, - TrampolineSym &Tramp) { + W.printNumber("Parent", Thunk.Parent); + W.printNumber("End", Thunk.End); + W.printNumber("Next", Thunk.Next); + W.printNumber("Off", Thunk.Offset); + W.printNumber("Seg", Thunk.Segment); + W.printNumber("Len", Thunk.Length); + W.printEnum("Ordinal", uint8_t(Thunk.Thunk), getThunkOrdinalNames()); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + TrampolineSym &Tramp) { DictScope S(W, "Trampoline"); - W.printEnum("Type", Tramp.Header.Type, getTrampolineNames()); - W.printNumber("Size", Tramp.Header.Size); - W.printNumber("ThunkOff", Tramp.Header.ThunkOff); - W.printNumber("TargetOff", Tramp.Header.TargetOff); - W.printNumber("ThunkSection", Tramp.Header.ThunkSection); - W.printNumber("TargetSection", Tramp.Header.TargetSection); + W.printEnum("Type", uint16_t(Tramp.Type), getTrampolineNames()); + W.printNumber("Size", Tramp.Size); + W.printNumber("ThunkOff", Tramp.ThunkOffset); + W.printNumber("TargetOff", Tramp.TargetOffset); + W.printNumber("ThunkSection", Tramp.ThunkSection); + W.printNumber("TargetSection", Tramp.TargetSection); + return Error::success(); } -void CVSymbolDumperImpl::visitSectionSym(SymbolKind Kind, SectionSym &Section) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) { DictScope S(W, "Section"); - W.printNumber("SectionNumber", Section.Header.SectionNumber); - W.printNumber("Alignment", Section.Header.Alignment); - W.printNumber("Reserved", Section.Header.Reserved); - W.printNumber("Rva", Section.Header.Rva); - W.printNumber("Length", Section.Header.Length); - W.printFlags("Characteristics", Section.Header.Characteristics, + W.printNumber("SectionNumber", Section.SectionNumber); + W.printNumber("Alignment", Section.Alignment); + W.printNumber("Rva", Section.Rva); + W.printNumber("Length", Section.Length); + W.printFlags("Characteristics", Section.Characteristics, getImageSectionCharacteristicNames(), COFF::SectionCharacteristics(0x00F00000)); W.printString("Name", Section.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitCoffGroupSym(SymbolKind Kind, +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CoffGroup) { DictScope S(W, "COFF Group"); - W.printNumber("Size", CoffGroup.Header.Size); - W.printFlags("Characteristics", CoffGroup.Header.Characteristics, + W.printNumber("Size", CoffGroup.Size); + W.printFlags("Characteristics", CoffGroup.Characteristics, getImageSectionCharacteristicNames(), COFF::SectionCharacteristics(0x00F00000)); - W.printNumber("Offset", CoffGroup.Header.Offset); - W.printNumber("Segment", CoffGroup.Header.Segment); + W.printNumber("Offset", CoffGroup.Offset); + W.printNumber("Segment", CoffGroup.Segment); W.printString("Name", CoffGroup.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitBPRelativeSym(SymbolKind Kind, - BPRelativeSym &BPRel) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + BPRelativeSym &BPRel) { DictScope S(W, "BPRelativeSym"); - W.printNumber("Offset", BPRel.Header.Offset); - CVTD.printTypeIndex("Type", BPRel.Header.Type); + W.printNumber("Offset", BPRel.Offset); + printTypeIndex("Type", BPRel.Type); W.printString("VarName", BPRel.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitBuildInfoSym(SymbolKind Kind, +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BuildInfoSym &BuildInfo) { DictScope S(W, "BuildInfo"); - W.printNumber("BuildId", BuildInfo.Header.BuildId); + W.printNumber("BuildId", BuildInfo.BuildId); + return Error::success(); } -void CVSymbolDumperImpl::visitCallSiteInfoSym(SymbolKind Kind, - CallSiteInfoSym &CallSiteInfo) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + CallSiteInfoSym &CallSiteInfo) { DictScope S(W, "CallSiteInfo"); StringRef LinkageName; if (ObjDelegate) { - ObjDelegate->printRelocatedField( - "CodeOffset", CallSiteInfo.getRelocationOffset(), - CallSiteInfo.Header.CodeOffset, &LinkageName); + ObjDelegate->printRelocatedField("CodeOffset", + CallSiteInfo.getRelocationOffset(), + CallSiteInfo.CodeOffset, &LinkageName); } - W.printHex("Segment", CallSiteInfo.Header.Segment); - W.printHex("Reserved", CallSiteInfo.Header.Reserved); - CVTD.printTypeIndex("Type", CallSiteInfo.Header.Type); + W.printHex("Segment", CallSiteInfo.Segment); + printTypeIndex("Type", CallSiteInfo.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitEnvBlockSym(SymbolKind Kind, - EnvBlockSym &EnvBlock) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + EnvBlockSym &EnvBlock) { DictScope S(W, "EnvBlock"); - W.printNumber("Reserved", EnvBlock.Header.Reserved); ListScope L(W, "Entries"); for (auto Entry : EnvBlock.Fields) { W.printString(Entry); } + return Error::success(); } -void CVSymbolDumperImpl::visitFileStaticSym(SymbolKind Kind, - FileStaticSym &FileStatic) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + FileStaticSym &FileStatic) { DictScope S(W, "FileStatic"); - W.printNumber("Index", FileStatic.Header.Index); - W.printNumber("ModFilenameOffset", FileStatic.Header.ModFilenameOffset); - W.printFlags("Flags", uint16_t(FileStatic.Header.Flags), getLocalFlagNames()); + W.printNumber("Index", FileStatic.Index); + W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset); + W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames()); W.printString("Name", FileStatic.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitExportSym(SymbolKind Kind, ExportSym &Export) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { DictScope S(W, "Export"); - W.printNumber("Ordinal", Export.Header.Ordinal); - W.printFlags("Flags", Export.Header.Flags, getExportSymFlagNames()); + W.printNumber("Ordinal", Export.Ordinal); + W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames()); W.printString("Name", Export.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitCompile2Sym(SymbolKind Kind, - Compile2Sym &Compile2) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + Compile2Sym &Compile2) { DictScope S(W, "CompilerFlags2"); - W.printEnum("Language", Compile2.Header.getLanguage(), - getSourceLanguageNames()); - W.printFlags("Flags", Compile2.Header.flags & ~0xff, - getCompileSym2FlagNames()); - W.printEnum("Machine", unsigned(Compile2.Header.Machine), getCPUTypeNames()); + W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames()); + W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames()); + W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); std::string FrontendVersion; { raw_string_ostream Out(FrontendVersion); - Out << Compile2.Header.VersionFrontendMajor << '.' - << Compile2.Header.VersionFrontendMinor << '.' - << Compile2.Header.VersionFrontendBuild; + Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor + << '.' << Compile2.VersionFrontendBuild; } std::string BackendVersion; { raw_string_ostream Out(BackendVersion); - Out << Compile2.Header.VersionBackendMajor << '.' - << Compile2.Header.VersionBackendMinor << '.' - << Compile2.Header.VersionBackendBuild; + Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor + << '.' << Compile2.VersionBackendBuild; } W.printString("FrontendVersion", FrontendVersion); W.printString("BackendVersion", BackendVersion); W.printString("VersionName", Compile2.Version); + return Error::success(); } -void CVSymbolDumperImpl::visitCompile3Sym(SymbolKind Kind, - Compile3Sym &Compile3) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + Compile3Sym &Compile3) { DictScope S(W, "CompilerFlags3"); - W.printEnum("Language", Compile3.Header.getLanguage(), - getSourceLanguageNames()); - W.printFlags("Flags", Compile3.Header.flags & ~0xff, - getCompileSym3FlagNames()); - W.printEnum("Machine", unsigned(Compile3.Header.Machine), getCPUTypeNames()); + W.printEnum("Language", Compile3.getLanguage(), getSourceLanguageNames()); + W.printFlags("Flags", Compile3.getFlags(), getCompileSym3FlagNames()); + W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); std::string FrontendVersion; { raw_string_ostream Out(FrontendVersion); - Out << Compile3.Header.VersionFrontendMajor << '.' - << Compile3.Header.VersionFrontendMinor << '.' - << Compile3.Header.VersionFrontendBuild << '.' - << Compile3.Header.VersionFrontendQFE; + Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor + << '.' << Compile3.VersionFrontendBuild << '.' + << Compile3.VersionFrontendQFE; } std::string BackendVersion; { raw_string_ostream Out(BackendVersion); - Out << Compile3.Header.VersionBackendMajor << '.' - << Compile3.Header.VersionBackendMinor << '.' - << Compile3.Header.VersionBackendBuild << '.' - << Compile3.Header.VersionBackendQFE; + Out << Compile3.VersionBackendMajor << '.' << Compile3.VersionBackendMinor + << '.' << Compile3.VersionBackendBuild << '.' + << Compile3.VersionBackendQFE; } W.printString("FrontendVersion", FrontendVersion); W.printString("BackendVersion", BackendVersion); W.printString("VersionName", Compile3.Version); + return Error::success(); } -void CVSymbolDumperImpl::visitConstantSym(SymbolKind Kind, - ConstantSym &Constant) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ConstantSym &Constant) { DictScope S(W, "Constant"); - CVTD.printTypeIndex("Type", Constant.Header.Type); + printTypeIndex("Type", Constant.Type); W.printNumber("Value", Constant.Value); W.printString("Name", Constant.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitDataSym(SymbolKind Kind, DataSym &Data) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { DictScope S(W, "DataSym"); - W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); + W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames()); StringRef LinkageName; if (ObjDelegate) { ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), - Data.Header.DataOffset, &LinkageName); + Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Header.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeFramePointerRelFullScopeSym( - SymbolKind Kind, +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { DictScope S(W, "DefRangeFramePointerRelFullScope"); - W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset); + W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeFramePointerRelSym( - SymbolKind Kind, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { DictScope S(W, "DefRangeFramePointerRel"); - W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset); - printLocalVariableAddrRange(DefRangeFramePointerRel.Header.Range, + W.printNumber("Offset", DefRangeFramePointerRel.Offset); + printLocalVariableAddrRange(DefRangeFramePointerRel.Range, DefRangeFramePointerRel.getRelocationOffset()); printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeRegisterRelSym( - SymbolKind Kind, DefRangeRegisterRelSym &DefRangeRegisterRel) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { DictScope S(W, "DefRangeRegisterRel"); - W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister); + W.printNumber("BaseRegister", DefRangeRegisterRel.Hdr.Register); W.printBoolean("HasSpilledUDTMember", DefRangeRegisterRel.hasSpilledUDTMember()); W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); - W.printNumber("BasePointerOffset", - DefRangeRegisterRel.Header.BasePointerOffset); - printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range, + W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset); + printLocalVariableAddrRange(DefRangeRegisterRel.Range, DefRangeRegisterRel.getRelocationOffset()); printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeRegisterSym( - SymbolKind Kind, DefRangeRegisterSym &DefRangeRegister) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { DictScope S(W, "DefRangeRegister"); - W.printNumber("Register", DefRangeRegister.Header.Register); - W.printNumber("MayHaveNoName", DefRangeRegister.Header.MayHaveNoName); - printLocalVariableAddrRange(DefRangeRegister.Header.Range, + W.printNumber("Register", DefRangeRegister.Hdr.Register); + W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); + printLocalVariableAddrRange(DefRangeRegister.Range, DefRangeRegister.getRelocationOffset()); printLocalVariableAddrGap(DefRangeRegister.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeSubfieldRegisterSym( - SymbolKind Kind, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { DictScope S(W, "DefRangeSubfieldRegister"); - W.printNumber("Register", DefRangeSubfieldRegister.Header.Register); - W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Header.MayHaveNoName); - W.printNumber("OffsetInParent", - DefRangeSubfieldRegister.Header.OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfieldRegister.Header.Range, + W.printNumber("Register", DefRangeSubfieldRegister.Hdr.Register); + W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); + W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent); + printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, DefRangeSubfieldRegister.getRelocationOffset()); printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeSubfieldSym( - SymbolKind Kind, DefRangeSubfieldSym &DefRangeSubfield) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) { DictScope S(W, "DefRangeSubfield"); if (ObjDelegate) { StringRef StringTable = ObjDelegate->getStringTable(); - auto ProgramStringTableOffset = DefRangeSubfield.Header.Program; + auto ProgramStringTableOffset = DefRangeSubfield.Program; if (ProgramStringTableOffset >= StringTable.size()) - return parseError(); + return llvm::make_error<CodeViewError>( + "String table offset outside of bounds of String Table!"); StringRef Program = StringTable.drop_front(ProgramStringTableOffset).split('\0').first; W.printString("Program", Program); } - W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfield.Header.Range, + W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); + printLocalVariableAddrRange(DefRangeSubfield.Range, DefRangeSubfield.getRelocationOffset()); printLocalVariableAddrGap(DefRangeSubfield.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitDefRangeSym(SymbolKind Kind, - DefRangeSym &DefRange) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + DefRangeSym &DefRange) { DictScope S(W, "DefRange"); if (ObjDelegate) { StringRef StringTable = ObjDelegate->getStringTable(); - auto ProgramStringTableOffset = DefRange.Header.Program; + auto ProgramStringTableOffset = DefRange.Program; if (ProgramStringTableOffset >= StringTable.size()) - return parseError(); + return llvm::make_error<CodeViewError>( + "String table offset outside of bounds of String Table!"); StringRef Program = StringTable.drop_front(ProgramStringTableOffset).split('\0').first; W.printString("Program", Program); } - printLocalVariableAddrRange(DefRange.Header.Range, - DefRange.getRelocationOffset()); + printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); printLocalVariableAddrGap(DefRange.Gaps); + return Error::success(); } -void CVSymbolDumperImpl::visitFrameCookieSym(SymbolKind Kind, - FrameCookieSym &FrameCookie) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + FrameCookieSym &FrameCookie) { DictScope S(W, "FrameCookie"); StringRef LinkageName; if (ObjDelegate) { - ObjDelegate->printRelocatedField( - "CodeOffset", FrameCookie.getRelocationOffset(), - FrameCookie.Header.CodeOffset, &LinkageName); + ObjDelegate->printRelocatedField("CodeOffset", + FrameCookie.getRelocationOffset(), + FrameCookie.CodeOffset, &LinkageName); } - W.printHex("Register", FrameCookie.Header.Register); - W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind), + W.printHex("Register", FrameCookie.Register); + W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind), getFrameCookieKindNames()); - W.printHex("Flags", FrameCookie.Header.Flags); + W.printHex("Flags", FrameCookie.Flags); + return Error::success(); } -void CVSymbolDumperImpl::visitFrameProcSym(SymbolKind Kind, +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FrameProc) { DictScope S(W, "FrameProc"); - W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes); - W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes); - W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding); + W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes); + W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes); + W.printHex("OffsetToPadding", FrameProc.OffsetToPadding); W.printHex("BytesOfCalleeSavedRegisters", - FrameProc.Header.BytesOfCalleeSavedRegisters); - W.printHex("OffsetOfExceptionHandler", - FrameProc.Header.OffsetOfExceptionHandler); + FrameProc.BytesOfCalleeSavedRegisters); + W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler); W.printHex("SectionIdOfExceptionHandler", - FrameProc.Header.SectionIdOfExceptionHandler); - W.printFlags("Flags", FrameProc.Header.Flags, getFrameProcSymFlagNames()); + FrameProc.SectionIdOfExceptionHandler); + W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags), + getFrameProcSymFlagNames()); + return Error::success(); } -void CVSymbolDumperImpl::visitHeapAllocationSiteSym( - SymbolKind Kind, HeapAllocationSiteSym &HeapAllocSite) { +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) { DictScope S(W, "HeapAllocationSite"); StringRef LinkageName; if (ObjDelegate) { - ObjDelegate->printRelocatedField( - "CodeOffset", HeapAllocSite.getRelocationOffset(), - HeapAllocSite.Header.CodeOffset, &LinkageName); + ObjDelegate->printRelocatedField("CodeOffset", + HeapAllocSite.getRelocationOffset(), + HeapAllocSite.CodeOffset, &LinkageName); } - W.printHex("Segment", HeapAllocSite.Header.Segment); - W.printHex("CallInstructionSize", HeapAllocSite.Header.CallInstructionSize); - CVTD.printTypeIndex("Type", HeapAllocSite.Header.Type); + W.printHex("Segment", HeapAllocSite.Segment); + W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); + printTypeIndex("Type", HeapAllocSite.Type); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind, - InlineSiteSym &InlineSite) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + InlineSiteSym &InlineSite) { DictScope S(W, "InlineSite"); - W.printHex("PtrParent", InlineSite.Header.PtrParent); - W.printHex("PtrEnd", InlineSite.Header.PtrEnd); - CVTD.printTypeIndex("Inlinee", InlineSite.Header.Inlinee); + W.printHex("PtrParent", InlineSite.Parent); + W.printHex("PtrEnd", InlineSite.End); + printTypeIndex("Inlinee", InlineSite.Inlinee); ListScope BinaryAnnotations(W, "BinaryAnnotations"); for (auto &Annotation : InlineSite.annotations()) { switch (Annotation.OpCode) { case BinaryAnnotationsOpCode::Invalid: - return parseError(); + return llvm::make_error<CodeViewError>( + "Invalid binary annotation opcode!"); case BinaryAnnotationsOpCode::CodeOffset: case BinaryAnnotationsOpCode::ChangeCodeOffset: case BinaryAnnotationsOpCode::ChangeCodeLength: @@ -486,157 +510,180 @@ void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind, } } } + return Error::success(); } -void CVSymbolDumperImpl::visitRegisterSym(SymbolKind Kind, - RegisterSym &Register) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + RegisterSym &Register) { DictScope S(W, "RegisterSym"); - W.printNumber("Type", Register.Header.Index); - W.printEnum("Seg", uint16_t(Register.Header.Register), getRegisterNames()); + W.printNumber("Type", Register.Index); + W.printEnum("Seg", uint16_t(Register.Register), getRegisterNames()); W.printString("Name", Register.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitPublicSym32(SymbolKind Kind, - PublicSym32 &Public) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { DictScope S(W, "PublicSym"); - W.printNumber("Type", Public.Header.Index); - W.printNumber("Seg", Public.Header.Seg); - W.printNumber("Off", Public.Header.Off); + W.printNumber("Type", Public.Index); + W.printNumber("Seg", Public.Segment); + W.printNumber("Off", Public.Offset); W.printString("Name", Public.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitProcRefSym(SymbolKind Kind, ProcRefSym &ProcRef) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) { DictScope S(W, "ProcRef"); - W.printNumber("SumName", ProcRef.Header.SumName); - W.printNumber("SymOffset", ProcRef.Header.SymOffset); - W.printNumber("Mod", ProcRef.Header.Mod); + W.printNumber("SumName", ProcRef.SumName); + W.printNumber("SymOffset", ProcRef.SymOffset); + W.printNumber("Mod", ProcRef.Module); W.printString("Name", ProcRef.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitLabelSym(SymbolKind Kind, LabelSym &Label) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { DictScope S(W, "Label"); StringRef LinkageName; if (ObjDelegate) { ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(), - Label.Header.CodeOffset, &LinkageName); + Label.CodeOffset, &LinkageName); } - W.printHex("Segment", Label.Header.Segment); - W.printHex("Flags", Label.Header.Flags); - W.printFlags("Flags", Label.Header.Flags, getProcSymFlagNames()); + W.printHex("Segment", Label.Segment); + W.printHex("Flags", uint8_t(Label.Flags)); + W.printFlags("Flags", uint8_t(Label.Flags), getProcSymFlagNames()); W.printString("DisplayName", Label.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitLocalSym(SymbolKind Kind, LocalSym &Local) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { DictScope S(W, "Local"); - CVTD.printTypeIndex("Type", Local.Header.Type); - W.printFlags("Flags", uint16_t(Local.Header.Flags), getLocalFlagNames()); + printTypeIndex("Type", Local.Type); + W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); W.printString("VarName", Local.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitObjNameSym(SymbolKind Kind, ObjNameSym &ObjName) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) { DictScope S(W, "ObjectName"); - W.printHex("Signature", ObjName.Header.Signature); + W.printHex("Signature", ObjName.Signature); W.printString("ObjectName", ObjName.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitProcSym(SymbolKind Kind, ProcSym &Proc) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { DictScope S(W, "ProcStart"); if (InFunctionScope) - return parseError(); + return llvm::make_error<CodeViewError>( + "Visiting a ProcSym while inside function scope!"); InFunctionScope = true; StringRef LinkageName; - W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); - W.printHex("PtrParent", Proc.Header.PtrParent); - W.printHex("PtrEnd", Proc.Header.PtrEnd); - W.printHex("PtrNext", Proc.Header.PtrNext); - W.printHex("CodeSize", Proc.Header.CodeSize); - W.printHex("DbgStart", Proc.Header.DbgStart); - W.printHex("DbgEnd", Proc.Header.DbgEnd); - CVTD.printTypeIndex("FunctionType", Proc.Header.FunctionType); + W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames()); + W.printHex("PtrParent", Proc.Parent); + W.printHex("PtrEnd", Proc.End); + W.printHex("PtrNext", Proc.Next); + W.printHex("CodeSize", Proc.CodeSize); + W.printHex("DbgStart", Proc.DbgStart); + W.printHex("DbgEnd", Proc.DbgEnd); + printTypeIndex("FunctionType", Proc.FunctionType); if (ObjDelegate) { ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(), - Proc.Header.CodeOffset, &LinkageName); + Proc.CodeOffset, &LinkageName); } - W.printHex("Segment", Proc.Header.Segment); - W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags), + W.printHex("Segment", Proc.Segment); + W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags), getProcSymFlagNames()); W.printString("DisplayName", Proc.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitScopeEndSym(SymbolKind Kind, - ScopeEndSym &ScopeEnd) { - if (Kind == SymbolKind::S_END) +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ScopeEndSym &ScopeEnd) { + if (CVR.kind() == SymbolKind::S_END) DictScope S(W, "BlockEnd"); - else if (Kind == SymbolKind::S_PROC_ID_END) + else if (CVR.kind() == SymbolKind::S_PROC_ID_END) DictScope S(W, "ProcEnd"); - else if (Kind == SymbolKind::S_INLINESITE_END) + else if (CVR.kind() == SymbolKind::S_INLINESITE_END) DictScope S(W, "InlineSiteEnd"); InFunctionScope = false; + return Error::success(); } -void CVSymbolDumperImpl::visitCallerSym(SymbolKind Kind, CallerSym &Caller) { - ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers"); +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { + ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); for (auto FuncID : Caller.Indices) - CVTD.printTypeIndex("FuncID", FuncID); + printTypeIndex("FuncID", FuncID); + return Error::success(); } -void CVSymbolDumperImpl::visitRegRelativeSym(SymbolKind Kind, - RegRelativeSym &RegRel) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + RegRelativeSym &RegRel) { DictScope S(W, "RegRelativeSym"); - W.printHex("Offset", RegRel.Header.Offset); - CVTD.printTypeIndex("Type", RegRel.Header.Type); - W.printHex("Register", RegRel.Header.Register); + W.printHex("Offset", RegRel.Offset); + printTypeIndex("Type", RegRel.Type); + W.printHex("Register", RegRel.Register); W.printString("VarName", RegRel.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitThreadLocalDataSym(SymbolKind Kind, - ThreadLocalDataSym &Data) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ThreadLocalDataSym &Data) { DictScope S(W, "ThreadLocalDataSym"); StringRef LinkageName; if (ObjDelegate) { ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), - Data.Header.DataOffset, &LinkageName); + Data.DataOffset, &LinkageName); } - CVTD.printTypeIndex("Type", Data.Header.Type); + printTypeIndex("Type", Data.Type); W.printString("DisplayName", Data.Name); if (!LinkageName.empty()) W.printString("LinkageName", LinkageName); + return Error::success(); } -void CVSymbolDumperImpl::visitUDTSym(SymbolKind Kind, UDTSym &UDT) { +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { DictScope S(W, "UDT"); - CVTD.printTypeIndex("Type", UDT.Header.Type); + printTypeIndex("Type", UDT.Type); W.printString("UDTName", UDT.Name); + return Error::success(); } -void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind, - ArrayRef<uint8_t> Data) { +Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { DictScope S(W, "UnknownSym"); - W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); - W.printNumber("Length", uint32_t(Data.size())); + W.printEnum("Kind", uint16_t(CVR.kind()), getSymbolTypeNames()); + W.printNumber("Length", CVR.length()); + return Error::success(); } -bool CVSymbolDumper::dump(const CVRecord<SymbolKind> &Record) { - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); - Dumper.visitSymbolRecord(Record); - return !Dumper.hadError(); +Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) { + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(ObjDelegate.get()); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + return Visitor.visitSymbolRecord(Record); } -bool CVSymbolDumper::dump(const CVSymbolArray &Symbols) { - CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); - Dumper.visitSymbolStream(Symbols); - return !Dumper.hadError(); +Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(ObjDelegate.get()); + CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + return Visitor.visitSymbolStream(Symbols); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp new file mode 100644 index 0000000..bb17314 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp @@ -0,0 +1,464 @@ +//===- SymbolRecordMapping.cpp -----------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" + +using namespace llvm; +using namespace llvm::codeview; + +#define error(X) \ + if (auto EC = X) \ + return EC; + +namespace { +struct MapGap { + Error operator()(CodeViewRecordIO &IO, LocalVariableAddrGap &Gap) const { + error(IO.mapInteger(Gap.GapStartOffset)); + error(IO.mapInteger(Gap.Range)); + return Error::success(); + } +}; +} + +static Error mapLocalVariableAddrRange(CodeViewRecordIO &IO, + LocalVariableAddrRange &Range) { + error(IO.mapInteger(Range.OffsetStart)); + error(IO.mapInteger(Range.ISectStart)); + error(IO.mapInteger(Range.Range)); + return Error::success(); +} + +Error SymbolRecordMapping::visitSymbolBegin(CVSymbol &Record) { + error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix))); + return Error::success(); +} + +Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) { + error(IO.endRecord()); + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { + + error(IO.mapInteger(Block.Parent)); + error(IO.mapInteger(Block.End)); + error(IO.mapInteger(Block.CodeSize)); + error(IO.mapInteger(Block.CodeOffset)); + error(IO.mapInteger(Block.Segment)); + error(IO.mapStringZ(Block.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { + + error(IO.mapInteger(Thunk.Parent)); + error(IO.mapInteger(Thunk.End)); + error(IO.mapInteger(Thunk.Next)); + error(IO.mapInteger(Thunk.Offset)); + error(IO.mapInteger(Thunk.Segment)); + error(IO.mapInteger(Thunk.Length)); + error(IO.mapEnum(Thunk.Thunk)); + error(IO.mapStringZ(Thunk.Name)); + error(IO.mapByteVectorTail(Thunk.VariantData)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + TrampolineSym &Tramp) { + + error(IO.mapEnum(Tramp.Type)); + error(IO.mapInteger(Tramp.Size)); + error(IO.mapInteger(Tramp.ThunkOffset)); + error(IO.mapInteger(Tramp.TargetOffset)); + error(IO.mapInteger(Tramp.ThunkSection)); + error(IO.mapInteger(Tramp.TargetSection)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + SectionSym &Section) { + uint8_t Padding = 0; + + error(IO.mapInteger(Section.SectionNumber)); + error(IO.mapInteger(Section.Alignment)); + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Section.Rva)); + error(IO.mapInteger(Section.Length)); + error(IO.mapInteger(Section.Characteristics)); + error(IO.mapStringZ(Section.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + CoffGroupSym &CoffGroup) { + + error(IO.mapInteger(CoffGroup.Size)); + error(IO.mapInteger(CoffGroup.Characteristics)); + error(IO.mapInteger(CoffGroup.Offset)); + error(IO.mapInteger(CoffGroup.Segment)); + error(IO.mapStringZ(CoffGroup.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + BPRelativeSym &BPRel) { + + error(IO.mapInteger(BPRel.Offset)); + error(IO.mapInteger(BPRel.Type)); + error(IO.mapStringZ(BPRel.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + BuildInfoSym &BuildInfo) { + + error(IO.mapInteger(BuildInfo.BuildId)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + CallSiteInfoSym &CallSiteInfo) { + uint16_t Padding = 0; + + error(IO.mapInteger(CallSiteInfo.CodeOffset)); + error(IO.mapInteger(CallSiteInfo.Segment)); + error(IO.mapInteger(Padding)); + error(IO.mapInteger(CallSiteInfo.Type)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + EnvBlockSym &EnvBlock) { + + uint8_t Reserved = 0; + error(IO.mapInteger(Reserved)); + error(IO.mapStringZVectorZ(EnvBlock.Fields)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + FileStaticSym &FileStatic) { + + error(IO.mapInteger(FileStatic.Index)); + error(IO.mapInteger(FileStatic.ModFilenameOffset)); + error(IO.mapEnum(FileStatic.Flags)); + error(IO.mapStringZ(FileStatic.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { + + error(IO.mapInteger(Export.Ordinal)); + error(IO.mapEnum(Export.Flags)); + error(IO.mapStringZ(Export.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + Compile2Sym &Compile2) { + + error(IO.mapEnum(Compile2.Flags)); + error(IO.mapEnum(Compile2.Machine)); + error(IO.mapInteger(Compile2.VersionFrontendMajor)); + error(IO.mapInteger(Compile2.VersionFrontendMinor)); + error(IO.mapInteger(Compile2.VersionFrontendBuild)); + error(IO.mapInteger(Compile2.VersionBackendMajor)); + error(IO.mapInteger(Compile2.VersionBackendMinor)); + error(IO.mapInteger(Compile2.VersionBackendBuild)); + error(IO.mapStringZ(Compile2.Version)); + error(IO.mapStringZVectorZ(Compile2.ExtraStrings)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + Compile3Sym &Compile3) { + + error(IO.mapEnum(Compile3.Flags)); + error(IO.mapEnum(Compile3.Machine)); + error(IO.mapInteger(Compile3.VersionFrontendMajor)); + error(IO.mapInteger(Compile3.VersionFrontendMinor)); + error(IO.mapInteger(Compile3.VersionFrontendBuild)); + error(IO.mapInteger(Compile3.VersionFrontendQFE)); + error(IO.mapInteger(Compile3.VersionBackendMajor)); + error(IO.mapInteger(Compile3.VersionBackendMinor)); + error(IO.mapInteger(Compile3.VersionBackendBuild)); + error(IO.mapInteger(Compile3.VersionBackendQFE)); + error(IO.mapStringZ(Compile3.Version)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + ConstantSym &Constant) { + + error(IO.mapInteger(Constant.Type)); + error(IO.mapEncodedInteger(Constant.Value)); + error(IO.mapStringZ(Constant.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { + + error(IO.mapInteger(Data.Type)); + error(IO.mapInteger(Data.DataOffset)); + error(IO.mapInteger(Data.Segment)); + error(IO.mapStringZ(Data.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { + + error(IO.mapInteger(DefRangeFramePointerRel.Offset)); + error(mapLocalVariableAddrRange(IO, DefRangeFramePointerRel.Range)); + error(IO.mapVectorTail(DefRangeFramePointerRel.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, + DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { + + error(IO.mapInteger(DefRangeFramePointerRelFullScope.Offset)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { + + error(IO.mapObject(DefRangeRegisterRel.Hdr.Register)); + error(IO.mapObject(DefRangeRegisterRel.Hdr.Flags)); + error(IO.mapObject(DefRangeRegisterRel.Hdr.BasePointerOffset)); + error(mapLocalVariableAddrRange(IO, DefRangeRegisterRel.Range)); + error(IO.mapVectorTail(DefRangeRegisterRel.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { + + error(IO.mapObject(DefRangeRegister.Hdr.Register)); + error(IO.mapObject(DefRangeRegister.Hdr.MayHaveNoName)); + error(mapLocalVariableAddrRange(IO, DefRangeRegister.Range)); + error(IO.mapVectorTail(DefRangeRegister.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { + + error(IO.mapObject(DefRangeSubfieldRegister.Hdr.Register)); + error(IO.mapObject(DefRangeSubfieldRegister.Hdr.MayHaveNoName)); + error(IO.mapObject(DefRangeSubfieldRegister.Hdr.OffsetInParent)); + error(mapLocalVariableAddrRange(IO, DefRangeSubfieldRegister.Range)); + error(IO.mapVectorTail(DefRangeSubfieldRegister.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) { + + error(IO.mapInteger(DefRangeSubfield.Program)); + error(IO.mapInteger(DefRangeSubfield.OffsetInParent)); + error(mapLocalVariableAddrRange(IO, DefRangeSubfield.Range)); + error(IO.mapVectorTail(DefRangeSubfield.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + DefRangeSym &DefRange) { + + error(IO.mapInteger(DefRange.Program)); + error(mapLocalVariableAddrRange(IO, DefRange.Range)); + error(IO.mapVectorTail(DefRange.Gaps, MapGap())); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + FrameCookieSym &FrameCookie) { + + error(IO.mapInteger(FrameCookie.CodeOffset)); + error(IO.mapInteger(FrameCookie.Register)); + error(IO.mapInteger(FrameCookie.CookieKind)); + error(IO.mapInteger(FrameCookie.Flags)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + FrameProcSym &FrameProc) { + error(IO.mapInteger(FrameProc.TotalFrameBytes)); + error(IO.mapInteger(FrameProc.PaddingFrameBytes)); + error(IO.mapInteger(FrameProc.OffsetToPadding)); + error(IO.mapInteger(FrameProc.BytesOfCalleeSavedRegisters)); + error(IO.mapInteger(FrameProc.OffsetOfExceptionHandler)); + error(IO.mapInteger(FrameProc.SectionIdOfExceptionHandler)); + error(IO.mapEnum(FrameProc.Flags)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord( + CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) { + + error(IO.mapInteger(HeapAllocSite.CodeOffset)); + error(IO.mapInteger(HeapAllocSite.Segment)); + error(IO.mapInteger(HeapAllocSite.CallInstructionSize)); + error(IO.mapInteger(HeapAllocSite.Type)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + InlineSiteSym &InlineSite) { + + error(IO.mapInteger(InlineSite.Parent)); + error(IO.mapInteger(InlineSite.End)); + error(IO.mapInteger(InlineSite.Inlinee)); + error(IO.mapByteVectorTail(InlineSite.AnnotationData)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + RegisterSym &Register) { + + error(IO.mapInteger(Register.Index)); + error(IO.mapEnum(Register.Register)); + error(IO.mapStringZ(Register.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + PublicSym32 &Public) { + + error(IO.mapInteger(Public.Index)); + error(IO.mapInteger(Public.Offset)); + error(IO.mapInteger(Public.Segment)); + error(IO.mapStringZ(Public.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + ProcRefSym &ProcRef) { + + error(IO.mapInteger(ProcRef.SumName)); + error(IO.mapInteger(ProcRef.SymOffset)); + error(IO.mapInteger(ProcRef.Module)); + error(IO.mapStringZ(ProcRef.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { + + error(IO.mapInteger(Label.CodeOffset)); + error(IO.mapInteger(Label.Segment)); + error(IO.mapEnum(Label.Flags)); + error(IO.mapStringZ(Label.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { + error(IO.mapInteger(Local.Type)); + error(IO.mapEnum(Local.Flags)); + error(IO.mapStringZ(Local.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + ObjNameSym &ObjName) { + + error(IO.mapInteger(ObjName.Signature)); + error(IO.mapStringZ(ObjName.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { + error(IO.mapInteger(Proc.Parent)); + error(IO.mapInteger(Proc.End)); + error(IO.mapInteger(Proc.Next)); + error(IO.mapInteger(Proc.CodeSize)); + error(IO.mapInteger(Proc.DbgStart)); + error(IO.mapInteger(Proc.DbgEnd)); + error(IO.mapInteger(Proc.FunctionType)); + error(IO.mapInteger(Proc.CodeOffset)); + error(IO.mapInteger(Proc.Segment)); + error(IO.mapEnum(Proc.Flags)); + error(IO.mapStringZ(Proc.Name)); + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + ScopeEndSym &ScopeEnd) { + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { + error(IO.mapVectorN<uint32_t>( + Caller.Indices, + [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + RegRelativeSym &RegRel) { + + error(IO.mapInteger(RegRel.Offset)); + error(IO.mapInteger(RegRel.Type)); + error(IO.mapInteger(RegRel.Register)); + error(IO.mapStringZ(RegRel.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + ThreadLocalDataSym &Data) { + + error(IO.mapInteger(Data.Type)); + error(IO.mapInteger(Data.DataOffset)); + error(IO.mapInteger(Data.Segment)); + error(IO.mapStringZ(Data.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { + + error(IO.mapInteger(UDT.Type)); + error(IO.mapStringZ(UDT.Name)); + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp new file mode 100644 index 0000000..c7f7255 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp @@ -0,0 +1,114 @@ +//===- TypeDatabase.cpp --------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +struct SimpleTypeEntry { + StringRef Name; + SimpleTypeKind Kind; +}; +} + +/// The names here all end in "*". If the simple type is a pointer type, we +/// return the whole name. Otherwise we lop off the last character in our +/// StringRef. +static const SimpleTypeEntry SimpleTypeNames[] = { + {"void*", SimpleTypeKind::Void}, + {"<not translated>*", SimpleTypeKind::NotTranslated}, + {"HRESULT*", SimpleTypeKind::HResult}, + {"signed char*", SimpleTypeKind::SignedCharacter}, + {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, + {"char*", SimpleTypeKind::NarrowCharacter}, + {"wchar_t*", SimpleTypeKind::WideCharacter}, + {"char16_t*", SimpleTypeKind::Character16}, + {"char32_t*", SimpleTypeKind::Character32}, + {"__int8*", SimpleTypeKind::SByte}, + {"unsigned __int8*", SimpleTypeKind::Byte}, + {"short*", SimpleTypeKind::Int16Short}, + {"unsigned short*", SimpleTypeKind::UInt16Short}, + {"__int16*", SimpleTypeKind::Int16}, + {"unsigned __int16*", SimpleTypeKind::UInt16}, + {"long*", SimpleTypeKind::Int32Long}, + {"unsigned long*", SimpleTypeKind::UInt32Long}, + {"int*", SimpleTypeKind::Int32}, + {"unsigned*", SimpleTypeKind::UInt32}, + {"__int64*", SimpleTypeKind::Int64Quad}, + {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, + {"__int64*", SimpleTypeKind::Int64}, + {"unsigned __int64*", SimpleTypeKind::UInt64}, + {"__int128*", SimpleTypeKind::Int128}, + {"unsigned __int128*", SimpleTypeKind::UInt128}, + {"__half*", SimpleTypeKind::Float16}, + {"float*", SimpleTypeKind::Float32}, + {"float*", SimpleTypeKind::Float32PartialPrecision}, + {"__float48*", SimpleTypeKind::Float48}, + {"double*", SimpleTypeKind::Float64}, + {"long double*", SimpleTypeKind::Float80}, + {"__float128*", SimpleTypeKind::Float128}, + {"_Complex float*", SimpleTypeKind::Complex32}, + {"_Complex double*", SimpleTypeKind::Complex64}, + {"_Complex long double*", SimpleTypeKind::Complex80}, + {"_Complex __float128*", SimpleTypeKind::Complex128}, + {"bool*", SimpleTypeKind::Boolean8}, + {"__bool16*", SimpleTypeKind::Boolean16}, + {"__bool32*", SimpleTypeKind::Boolean32}, + {"__bool64*", SimpleTypeKind::Boolean64}, +}; + +/// Gets the type index for the next type record. +TypeIndex TypeDatabase::getNextTypeIndex() const { + return TypeIndex(TypeIndex::FirstNonSimpleIndex + CVUDTNames.size()); +} + +/// Records the name of a type, and reserves its type index. +void TypeDatabase::recordType(StringRef Name, CVType Data) { + CVUDTNames.push_back(Name); + TypeRecords.push_back(Data); +} + +/// Saves the name in a StringSet and creates a stable StringRef. +StringRef TypeDatabase::saveTypeName(StringRef TypeName) { + return TypeNameStorage.save(TypeName); +} + +StringRef TypeDatabase::getTypeName(TypeIndex Index) const { + if (Index.isNoneType()) + return "<no type>"; + + if (Index.isSimple()) { + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Kind == Index.getSimpleKind()) { + if (Index.getSimpleMode() == SimpleTypeMode::Direct) + return SimpleTypeName.Name.drop_back(1); + // Otherwise, this is a pointer type. We gloss over the distinction + // between near, far, 64, 32, etc, and just give a pointer type. + return SimpleTypeName.Name; + } + } + return "<unknown simple type>"; + } + + uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; + if (I < CVUDTNames.size()) + return CVUDTNames[I]; + + return "<unknown UDT>"; +} + +bool TypeDatabase::containsTypeIndex(TypeIndex Index) const { + uint32_t I = Index.getIndex() - TypeIndex::FirstNonSimpleIndex; + return I < CVUDTNames.size(); +} + +uint32_t TypeDatabase::size() const { return CVUDTNames.size(); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp new file mode 100644 index 0000000..d9d5639 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp @@ -0,0 +1,289 @@ +//===- TypeDatabaseVisitor.cpp -------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" + +#include "llvm/ADT/SmallString.h" + +using namespace llvm; + +using namespace llvm::codeview; + +Error TypeDatabaseVisitor::visitTypeBegin(CVRecord<TypeLeafKind> &Record) { + assert(!IsInFieldList); + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + + if (Record.Type == LF_FIELDLIST) { + // Record that we're in a field list so that members do not get assigned + // type indices. + IsInFieldList = true; + } + return Error::success(); +} + +Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) { + if (CVR.Type == LF_FIELDLIST) { + assert(IsInFieldList); + IsInFieldList = false; + } + assert(!IsInFieldList); + + // Record every type that is not a field list member, even if Name is empty. + // CVUDTNames is indexed by type index, and must have one entry for every + // type. Field list members are not recorded, and are only referenced by + // their containing field list record. + TypeDB.recordType(Name, CVR); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitMemberBegin(CVMemberRecord &Record) { + assert(IsInFieldList); + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + return Error::success(); +} + +Error TypeDatabaseVisitor::visitMemberEnd(CVMemberRecord &Record) { + assert(IsInFieldList); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = "<field list>"; + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, + StringIdRecord &String) { + // Put this in the database so it gets printed with LF_UDT_SRC_LINE. + Name = String.getString(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + SmallString<256> TypeName("("); + for (uint32_t I = 0; I < Size; ++I) { + StringRef ArgTypeName = 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(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + ProcedureRecord &Proc) { + StringRef ReturnTypeName = TypeDB.getTypeName(Proc.getReturnType()); + StringRef ArgListTypeName = TypeDB.getTypeName(Proc.getArgumentList()); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ArgListTypeName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef ReturnTypeName = TypeDB.getTypeName(MF.getReturnType()); + StringRef ClassTypeName = TypeDB.getTypeName(MF.getClassType()); + StringRef ArgListTypeName = TypeDB.getTypeName(MF.getArgumentList()); + SmallString<256> TypeName(ReturnTypeName); + TypeName.push_back(' '); + TypeName.append(ClassTypeName); + TypeName.append("::"); + TypeName.append(ArgListTypeName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef PointeeName = TypeDB.getTypeName(Ptr.getReferentType()); + StringRef ClassName = TypeDB.getTypeName(MI.getContainingType()); + SmallString<256> TypeName(PointeeName); + TypeName.push_back(' '); + TypeName.append(ClassName); + TypeName.append("::*"); + Name = TypeDB.saveTypeName(TypeName); + } else { + SmallString<256> TypeName; + if (Ptr.isConst()) + TypeName.append("const "); + if (Ptr.isVolatile()) + TypeName.append("volatile "); + if (Ptr.isUnaligned()) + TypeName.append("__unaligned "); + + TypeName.append(TypeDB.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + TypeName.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + TypeName.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + TypeName.append("*"); + + if (!TypeName.empty()) + Name = TypeDB.saveTypeName(TypeName); + } + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); + + StringRef ModifiedName = TypeDB.getTypeName(Mod.getModifiedType()); + SmallString<256> TypeName; + if (Mods & uint16_t(ModifierOptions::Const)) + TypeName.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + TypeName.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + TypeName.append("__unaligned "); + TypeName.append(ModifiedName); + Name = TypeDB.saveTypeName(TypeName); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = TypeDB.saveTypeName("<vftable " + utostr(Shape.getEntryCount()) + + " methods>"); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { + Name = Nested.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Method) { + Name = Method.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { + Name = Method.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Field) { + Name = Field.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { + Name = Field.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &VBase) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord( + CVType &CVR, MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFP) { + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index 345e2a49..033585b 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -1,4 +1,5 @@ -//===-- TypeDumper.cpp - CodeView type info dumper --------------*- C++ -*-===// +//===-- TypeDumpVisitor.cpp - CodeView type info dumper -----------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -7,63 +8,23 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" + #include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.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/ByteStream.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/Support/ScopedPrinter.h" using namespace llvm; using namespace llvm::codeview; -/// The names here all end in "*". If the simple type is a pointer type, we -/// return the whole name. Otherwise we lop off the last character in our -/// StringRef. -static const EnumEntry<SimpleTypeKind> SimpleTypeNames[] = { - {"void*", SimpleTypeKind::Void}, - {"<not translated>*", SimpleTypeKind::NotTranslated}, - {"HRESULT*", SimpleTypeKind::HResult}, - {"signed char*", SimpleTypeKind::SignedCharacter}, - {"unsigned char*", SimpleTypeKind::UnsignedCharacter}, - {"char*", SimpleTypeKind::NarrowCharacter}, - {"wchar_t*", SimpleTypeKind::WideCharacter}, - {"char16_t*", SimpleTypeKind::Character16}, - {"char32_t*", SimpleTypeKind::Character32}, - {"__int8*", SimpleTypeKind::SByte}, - {"unsigned __int8*", SimpleTypeKind::Byte}, - {"short*", SimpleTypeKind::Int16Short}, - {"unsigned short*", SimpleTypeKind::UInt16Short}, - {"__int16*", SimpleTypeKind::Int16}, - {"unsigned __int16*", SimpleTypeKind::UInt16}, - {"long*", SimpleTypeKind::Int32Long}, - {"unsigned long*", SimpleTypeKind::UInt32Long}, - {"int*", SimpleTypeKind::Int32}, - {"unsigned*", SimpleTypeKind::UInt32}, - {"__int64*", SimpleTypeKind::Int64Quad}, - {"unsigned __int64*", SimpleTypeKind::UInt64Quad}, - {"__int64*", SimpleTypeKind::Int64}, - {"unsigned __int64*", SimpleTypeKind::UInt64}, - {"__int128*", SimpleTypeKind::Int128}, - {"unsigned __int128*", SimpleTypeKind::UInt128}, - {"__half*", SimpleTypeKind::Float16}, - {"float*", SimpleTypeKind::Float32}, - {"float*", SimpleTypeKind::Float32PartialPrecision}, - {"__float48*", SimpleTypeKind::Float48}, - {"double*", SimpleTypeKind::Float64}, - {"long double*", SimpleTypeKind::Float80}, - {"__float128*", SimpleTypeKind::Float128}, - {"_Complex float*", SimpleTypeKind::Complex32}, - {"_Complex double*", SimpleTypeKind::Complex64}, - {"_Complex long double*", SimpleTypeKind::Complex80}, - {"_Complex __float128*", SimpleTypeKind::Complex128}, - {"bool*", SimpleTypeKind::Boolean8}, - {"__bool16*", SimpleTypeKind::Boolean16}, - {"__bool32*", SimpleTypeKind::Boolean32}, - {"__bool64*", SimpleTypeKind::Boolean64}, -}; - static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { #define CV_TYPE(enum, val) {#enum, enum}, #include "llvm/DebugInfo/CodeView/TypeRecords.def" @@ -88,10 +49,8 @@ static const EnumEntry<uint16_t> ClassOptionNames[] = { }; static const EnumEntry<uint8_t> MemberAccessNames[] = { - ENUM_ENTRY(MemberAccess, None), - ENUM_ENTRY(MemberAccess, Private), - ENUM_ENTRY(MemberAccess, Protected), - ENUM_ENTRY(MemberAccess, Public), + ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private), + ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public), }; static const EnumEntry<uint16_t> MethodOptionNames[] = { @@ -149,8 +108,7 @@ static const EnumEntry<uint16_t> PtrMemberRepNames[] = { }; static const EnumEntry<uint16_t> TypeModifierNames[] = { - ENUM_ENTRY(ModifierOptions, Const), - ENUM_ENTRY(ModifierOptions, Volatile), + ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile), ENUM_ENTRY(ModifierOptions, Unaligned), }; @@ -195,34 +153,46 @@ static StringRef getLeafTypeName(TypeLeafKind LT) { case ename: \ return #name; #include "llvm/DebugInfo/CodeView/TypeRecords.def" - case LF_FIELDLIST: - return "FieldList"; default: break; } return "UnknownLeaf"; } -Error CVTypeDumper::visitTypeBegin(const CVRecord<TypeLeafKind> &Record) { - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; +void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { + CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB); +} - W->startLine() << getLeafTypeName(Record.Type) << " (" - << HexNumber(getNextTypeIndex()) << ") {\n"; +Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { + W->startLine() << getLeafTypeName(Record.Type); + W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex()) + << ")"; + W->getOStream() << " {\n"; W->indent(); W->printEnum("TypeLeafKind", unsigned(Record.Type), makeArrayRef(LeafTypeNames)); return Error::success(); } -Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) { - if (Record.Type == LF_FIELDLIST) - Name = "<field list>"; +Error TypeDumpVisitor::visitTypeEnd(CVType &Record) { + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); - // Always record some name for every type, even if Name is empty. CVUDTNames - // is indexed by type index, and must have one entry for every type. - recordType(Name); + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); +} +Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) { + W->startLine() << getLeafTypeName(Record.Kind); + W->getOStream() << " {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.Kind), + makeArrayRef(LeafTypeNames)); + return Error::success(); +} + +Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) { if (PrintRecordBytes) W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); @@ -231,33 +201,33 @@ Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) { return Error::success(); } -Error CVTypeDumper::visitStringId(StringIdRecord &String) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + CVTypeVisitor Visitor(*this); + if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) + return EC; + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { printTypeIndex("Id", String.getId()); W->printString("StringData", String.getString()); - // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. - Name = String.getString(); return Error::success(); } -Error CVTypeDumper::visitArgList(ArgListRecord &Args) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); W->printNumber("NumArgs", Size); ListScope Arguments(*W, "Arguments"); - SmallString<256> TypeName("("); for (uint32_t I = 0; I < Size; ++I) { printTypeIndex("ArgType", Indices[I]); - StringRef ArgTypeName = getTypeName(Indices[I]); - TypeName.append(ArgTypeName); - if (I + 1 != Size) - TypeName.append(", "); } - TypeName.push_back(')'); - Name = saveName(TypeName); return Error::success(); } -Error CVTypeDumper::visitClass(ClassRecord &Class) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { uint16_t Props = static_cast<uint16_t>(Class.getOptions()); W->printNumber("MemberCount", Class.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -268,11 +238,10 @@ Error CVTypeDumper::visitClass(ClassRecord &Class) { W->printString("Name", Class.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) W->printString("LinkageName", Class.getUniqueName()); - Name = Class.getName(); return Error::success(); } -Error CVTypeDumper::visitUnion(UnionRecord &Union) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { uint16_t Props = static_cast<uint16_t>(Union.getOptions()); W->printNumber("MemberCount", Union.getMemberCount()); W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); @@ -281,11 +250,10 @@ Error CVTypeDumper::visitUnion(UnionRecord &Union) { W->printString("Name", Union.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) W->printString("LinkageName", Union.getUniqueName()); - Name = Union.getName(); return Error::success(); } -Error CVTypeDumper::visitEnum(EnumRecord &Enum) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { uint16_t Props = static_cast<uint16_t>(Enum.getOptions()); W->printNumber("NumEnumerators", Enum.getMemberCount()); W->printFlags("Properties", uint16_t(Enum.getOptions()), @@ -295,39 +263,35 @@ Error CVTypeDumper::visitEnum(EnumRecord &Enum) { W->printString("Name", Enum.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) W->printString("LinkageName", Enum.getUniqueName()); - Name = Enum.getName(); return Error::success(); } -Error CVTypeDumper::visitArray(ArrayRecord &AT) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { printTypeIndex("ElementType", AT.getElementType()); printTypeIndex("IndexType", AT.getIndexType()); W->printNumber("SizeOf", AT.getSize()); W->printString("Name", AT.getName()); - Name = AT.getName(); return Error::success(); } -Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { printTypeIndex("CompleteClass", VFT.getCompleteClass()); printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); W->printString("VFTableName", VFT.getName()); for (auto N : VFT.getMethodNames()) W->printString("MethodName", N); - Name = VFT.getName(); return Error::success(); } -Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { printTypeIndex("ClassType", Id.getClassType()); printTypeIndex("FunctionType", Id.getFunctionType()); W->printString("Name", Id.getName()); - Name = Id.getName(); return Error::success(); } -Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { printTypeIndex("ReturnType", Proc.getReturnType()); W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), makeArrayRef(CallingConventions)); @@ -335,17 +299,10 @@ Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) { makeArrayRef(FunctionOptionEnum)); W->printNumber("NumParameters", Proc.getParameterCount()); printTypeIndex("ArgListType", Proc.getArgumentList()); - - StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); - StringRef ArgListTypeName = getTypeName(Proc.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ArgListTypeName); - Name = saveName(TypeName); return Error::success(); } -Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { printTypeIndex("ReturnType", MF.getReturnType()); printTypeIndex("ClassType", MF.getClassType()); printTypeIndex("ThisType", MF.getThisType()); @@ -356,24 +313,14 @@ Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) { W->printNumber("NumParameters", MF.getParameterCount()); printTypeIndex("ArgListType", MF.getArgumentList()); W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); - - StringRef ReturnTypeName = getTypeName(MF.getReturnType()); - StringRef ClassTypeName = getTypeName(MF.getClassType()); - StringRef ArgListTypeName = getTypeName(MF.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ClassTypeName); - TypeName.append("::"); - TypeName.append(ArgListTypeName); - Name = saveName(TypeName); return Error::success(); } -Error CVTypeDumper::visitMethodOverloadList( - MethodOverloadListRecord &MethodList) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { ListScope S(*W, "Method"); - printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions()); + printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); printTypeIndex("Type", M.getType()); if (M.isIntroducingVirtual()) W->printHex("VFTableOffset", M.getVFTableOffset()); @@ -381,23 +328,21 @@ Error CVTypeDumper::visitMethodOverloadList( return Error::success(); } -Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { printTypeIndex("ParentScope", Func.getParentScope()); printTypeIndex("FunctionType", Func.getFunctionType()); W->printString("Name", Func.getName()); - Name = Func.getName(); return Error::success(); } -Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { W->printBinary("Signature", TS.getGuid()); W->printNumber("Age", TS.getAge()); W->printString("Name", TS.getName()); - Name = TS.getName(); return Error::success(); } -Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), @@ -416,76 +361,42 @@ Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { printTypeIndex("ClassType", MI.getContainingType()); W->printEnum("Representation", uint16_t(MI.getRepresentation()), makeArrayRef(PtrMemberRepNames)); - - StringRef PointeeName = getTypeName(Ptr.getReferentType()); - StringRef ClassName = getTypeName(MI.getContainingType()); - SmallString<256> TypeName(PointeeName); - TypeName.push_back(' '); - TypeName.append(ClassName); - TypeName.append("::*"); - Name = saveName(TypeName); - } else { - SmallString<256> TypeName; - if (Ptr.isConst()) - TypeName.append("const "); - if (Ptr.isVolatile()) - TypeName.append("volatile "); - if (Ptr.isUnaligned()) - TypeName.append("__unaligned "); - - TypeName.append(getTypeName(Ptr.getReferentType())); - - if (Ptr.getMode() == PointerMode::LValueReference) - TypeName.append("&"); - else if (Ptr.getMode() == PointerMode::RValueReference) - TypeName.append("&&"); - else if (Ptr.getMode() == PointerMode::Pointer) - TypeName.append("*"); - - if (!TypeName.empty()) - Name = saveName(TypeName); } + return Error::success(); } -Error CVTypeDumper::visitModifier(ModifierRecord &Mod) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); printTypeIndex("ModifiedType", Mod.getModifiedType()); W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); - StringRef ModifiedName = getTypeName(Mod.getModifiedType()); - SmallString<256> TypeName; - if (Mods & uint16_t(ModifierOptions::Const)) - TypeName.append("const "); - if (Mods & uint16_t(ModifierOptions::Volatile)) - TypeName.append("volatile "); - if (Mods & uint16_t(ModifierOptions::Unaligned)) - TypeName.append("__unaligned "); - TypeName.append(ModifiedName); - Name = saveName(TypeName); return Error::success(); } -Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) { printTypeIndex("Type", BitField.getType()); W->printNumber("BitSize", BitField.getBitSize()); W->printNumber("BitOffset", BitField.getBitOffset()); return Error::success(); } -Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { W->printNumber("VFEntryCount", Shape.getEntryCount()); return Error::success(); } -Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); return Error::success(); } -Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); W->printNumber("LineNumber", Line.getLineNumber()); @@ -493,7 +404,7 @@ Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { return Error::success(); } -Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) { +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size())); ListScope Arguments(*W, "Arguments"); @@ -503,13 +414,14 @@ Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) { return Error::success(); } -void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) { +void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) { return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), Attrs.getFlags()); } -void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind, - MethodOptions Options) { +void TypeDumpVisitor::printMemberAttributes(MemberAccess Access, + MethodKind Kind, + MethodOptions Options) { W->printEnum("AccessSpecifier", uint8_t(Access), makeArrayRef(MemberAccessNames)); // Data members will be vanilla. Don't try to print a method kind for them. @@ -521,87 +433,80 @@ void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind, } } -Error CVTypeDumper::visitUnknownMember(const CVRecord<TypeLeafKind> &Record) { - W->printHex("UnknownMember", unsigned(Record.Type)); +Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) { + W->printHex("UnknownMember", unsigned(Record.Kind)); return Error::success(); } -Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) { - DictScope S(*W, "UnknownType"); - W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames)); - W->printNumber("Length", uint32_t(Record.Data.size())); +Error TypeDumpVisitor::visitUnknownType(CVType &Record) { + W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames)); + W->printNumber("Length", uint32_t(Record.content().size())); return Error::success(); } -Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) { - DictScope S(*W, "NestedType"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { printTypeIndex("Type", Nested.getNestedType()); W->printString("Name", Nested.getName()); - Name = Nested.getName(); return Error::success(); } -Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) { - DictScope S(*W, "OneMethod"); - MethodKind K = Method.getKind(); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Method) { + MethodKind K = Method.getMethodKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); printTypeIndex("Type", Method.getType()); // If virtual, then read the vftable offset. if (Method.isIntroducingVirtual()) W->printHex("VFTableOffset", Method.getVFTableOffset()); W->printString("Name", Method.getName()); - Name = Method.getName(); return Error::success(); } -Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) { - DictScope S(*W, "OverloadedMethod"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); W->printString("Name", Method.getName()); - Name = Method.getName(); return Error::success(); } -Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) { - DictScope S(*W, "DataMember"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); W->printHex("FieldOffset", Field.getFieldOffset()); W->printString("Name", Field.getName()); - Name = Field.getName(); return Error::success(); } -Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) { - DictScope S(*W, "StaticDataMember"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); W->printString("Name", Field.getName()); - Name = Field.getName(); return Error::success(); } -Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) { - DictScope S(*W, "VFPtr"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFTable) { printTypeIndex("Type", VFTable.getType()); return Error::success(); } -Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) { - DictScope S(*W, "Enumerator"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); W->printNumber("EnumValue", Enum.getValue()); W->printString("Name", Enum.getName()); - Name = Enum.getName(); return Error::success(); } -Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { - DictScope S(*W, "BaseClass"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("BaseType", Base.getBaseType()); @@ -609,8 +514,8 @@ Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { return Error::success(); } -Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { - DictScope S(*W, "VirtualBaseClass"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Base) { printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("BaseType", Base.getBaseType()); @@ -620,77 +525,8 @@ Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { return Error::success(); } -Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) { - DictScope S(*W, "ListContinuation"); +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); return Error::success(); } - -StringRef CVTypeDumper::getTypeName(TypeIndex TI) { - if (TI.isNoneType()) - return "<no type>"; - - if (TI.isSimple()) { - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Value == TI.getSimpleKind()) { - if (TI.getSimpleMode() == SimpleTypeMode::Direct) - return SimpleTypeName.Name.drop_back(1); - // Otherwise, this is a pointer type. We gloss over the distinction - // between near, far, 64, 32, etc, and just give a pointer type. - return SimpleTypeName.Name; - } - } - return "<unknown simple type>"; - } - - // User-defined type. - StringRef UDTName; - unsigned UDTIndex = TI.getIndex() - 0x1000; - if (UDTIndex < CVUDTNames.size()) - return CVUDTNames[UDTIndex]; - - return "<unknown UDT>"; -} - -void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { - StringRef TypeName; - if (!TI.isNoneType()) - TypeName = getTypeName(TI); - if (!TypeName.empty()) - W->printHex(FieldName, TypeName, TI.getIndex()); - else - W->printHex(FieldName, TI.getIndex()); -} - -Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) { - assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); - - if (auto EC = Visitor.visitTypeRecord(Record)) - return EC; - return Error::success(); -} - -Error CVTypeDumper::dump(const CVTypeArray &Types) { - assert(W && "printer should not be null"); - CVTypeVisitor Visitor(*this); - if (auto EC = Visitor.visitTypeStream(Types)) - return EC; - return Error::success(); -} - -Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) { - ByteStream<> Stream(Data); - CVTypeArray Types; - StreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - return EC; - - return dump(Types); -} - -void CVTypeDumper::setPrinter(ScopedPrinter *P) { - static ScopedPrinter NullP(llvm::nulls()); - W = P ? P : &NullP; -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp index f63371e..b951c06 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -8,374 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.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 record deserialization -//===----------------------------------------------------------------------===// - -ErrorOr<MemberPointerInfo> -MemberPointerInfo::deserialize(ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - - TypeIndex T = L->ClassType; - uint16_t R = L->Representation; - PointerToMemberRepresentation PMR = - static_cast<PointerToMemberRepresentation>(R); - return MemberPointerInfo(T, PMR); -} - -ErrorOr<ModifierRecord> ModifierRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - - TypeIndex M = L->ModifiedType; - uint16_t O = L->Modifiers; - ModifierOptions MO = static_cast<ModifierOptions>(O); - return ModifierRecord(M, MO); -} - -ErrorOr<ProcedureRecord> ProcedureRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - return ProcedureRecord(L->ReturnType, L->CallConv, L->Options, - L->NumParameters, L->ArgListType); -} - -ErrorOr<MemberFunctionRecord> -MemberFunctionRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - CV_DESERIALIZE(Data, L); - return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType, - L->CallConv, L->Options, L->NumParameters, - L->ArgListType, L->ThisAdjustment); -} - -ErrorOr<MemberFuncIdRecord> -MemberFuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name); -} - -ErrorOr<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList) - return std::make_error_code(std::errc::illegal_byte_sequence); - - const Layout *L = nullptr; - ArrayRef<TypeIndex> Indices; - CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); - return ArgListRecord(Kind, Indices); -} - -ErrorOr<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - - PointerKind PtrKind = L->getPtrKind(); - PointerMode Mode = L->getPtrMode(); - uint32_t Opts = L->Attrs; - PointerOptions Options = static_cast<PointerOptions>(Opts); - uint8_t Size = L->getPtrSize(); - - if (L->isPointerToMember()) { - auto E = MemberPointerInfo::deserialize(Data); - if (E.getError()) - return std::make_error_code(std::errc::illegal_byte_sequence); - return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E); - } - - return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size); -} - -ErrorOr<NestedTypeRecord> -NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return NestedTypeRecord(L->Type, Name); -} - -ErrorOr<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - uint64_t Size; - StringRef Name; - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name); - return ArrayRecord(L->ElementType, L->IndexType, Size, Name); -} - -ErrorOr<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - uint64_t Size = 0; - StringRef Name; - StringRef UniqueName; - uint16_t Props; - const Layout *L = nullptr; - - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - Props = L->Properties; - uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift; - WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue); - uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; - HfaKind Hfa = static_cast<HfaKind>(HfaMask); - - ClassOptions Options = static_cast<ClassOptions>(Props); - return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList, - L->DerivedFrom, L->VShape, Size, Name, UniqueName); -} - -ErrorOr<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - uint64_t Size = 0; - StringRef Name; - StringRef UniqueName; - uint16_t Props; - - const Layout *L = nullptr; - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - Props = L->Properties; - - uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; - HfaKind Hfa = static_cast<HfaKind>(HfaMask); - ClassOptions Options = static_cast<ClassOptions>(Props); - return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name, - UniqueName); -} - -ErrorOr<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - StringRef UniqueName; - CV_DESERIALIZE(Data, L, Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - uint16_t P = L->Properties; - ClassOptions Options = static_cast<ClassOptions>(P); - return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, - UniqueName, L->UnderlyingType); -} - -ErrorOr<BitFieldRecord> BitFieldRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - CV_DESERIALIZE(Data, L); - return BitFieldRecord(L->Type, L->BitSize, L->BitOffset); -} - -ErrorOr<VFTableShapeRecord> -VFTableShapeRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - - std::vector<VFTableSlotKind> Slots; - uint16_t Count = L->VFEntryCount; - while (Count > 0) { - if (Data.empty()) - return std::make_error_code(std::errc::illegal_byte_sequence); - - // Process up to 2 nibbles at a time (if there are at least 2 remaining) - uint8_t Value = Data[0] & 0x0F; - Slots.push_back(static_cast<VFTableSlotKind>(Value)); - if (--Count > 0) { - Value = (Data[0] & 0xF0) >> 4; - Slots.push_back(static_cast<VFTableSlotKind>(Value)); - --Count; - } - Data = Data.slice(1); - } - - return VFTableShapeRecord(Slots); -} - -ErrorOr<TypeServer2Record> -TypeServer2Record::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name); -} - -ErrorOr<StringIdRecord> StringIdRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return StringIdRecord(L->id, Name); -} - -ErrorOr<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return FuncIdRecord(L->ParentScope, L->FunctionType, Name); -} - -ErrorOr<UdtSourceLineRecord> -UdtSourceLineRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - CV_DESERIALIZE(Data, L); - return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber); -} - -ErrorOr<BuildInfoRecord> BuildInfoRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - ArrayRef<TypeIndex> Indices; - CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); - return BuildInfoRecord(Indices); -} - -ErrorOr<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - std::vector<StringRef> Names; - CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names)); - return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset, - Name, Names); -} - -ErrorOr<OneMethodRecord> OneMethodRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - int32_t VFTableOffset = -1; - - CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(VFTableOffset, - L->Attrs.isIntroducedVirtual()), - Name); - - MethodOptions Options = L->Attrs.getFlags(); - MethodKind MethKind = L->Attrs.getMethodKind(); - MemberAccess Access = L->Attrs.getAccess(); - OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset, - Name); - // Validate the vftable offset. - if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) - return std::make_error_code(std::errc::illegal_byte_sequence); - return Method; -} - -ErrorOr<MethodOverloadListRecord> -MethodOverloadListRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - std::vector<OneMethodRecord> Methods; - while (!Data.empty()) { - const Layout *L = nullptr; - int32_t VFTableOffset = -1; - CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD( - VFTableOffset, L->Attrs.isIntroducedVirtual())); - - MethodOptions Options = L->Attrs.getFlags(); - MethodKind MethKind = L->Attrs.getMethodKind(); - MemberAccess Access = L->Attrs.getAccess(); - - Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset, - StringRef()); - - // Validate the vftable offset. - auto &Method = Methods.back(); - if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) - return std::make_error_code(std::errc::illegal_byte_sequence); - } - return MethodOverloadListRecord(Methods); -} - -ErrorOr<OverloadedMethodRecord> -OverloadedMethodRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return OverloadedMethodRecord(L->MethodCount, L->MethList, Name); -} - -ErrorOr<DataMemberRecord> -DataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - uint64_t Offset; - StringRef Name; - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name); - return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name); -} - -ErrorOr<StaticDataMemberRecord> -StaticDataMemberRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Data, L, Name); - return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name); -} - -ErrorOr<EnumeratorRecord> -EnumeratorRecord::deserialize(TypeRecordKind Kind, ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - APSInt Value; - StringRef Name; - CV_DESERIALIZE(Data, L, Value, Name); - return EnumeratorRecord(L->Attrs.getAccess(), Value, Name); -} - -ErrorOr<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - if (auto EC = consumeObject(Data, L)) - return EC; - return VFPtrRecord(L->Type); -} - -ErrorOr<BaseClassRecord> BaseClassRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - uint64_t Offset; - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset)); - return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset); -} - -ErrorOr<VirtualBaseClassRecord> -VirtualBaseClassRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - uint64_t Offset; - uint64_t Index; - CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index)); - return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, L->VBPtrType, - Offset, Index); -} - -ErrorOr<ListContinuationRecord> -ListContinuationRecord::deserialize(TypeRecordKind Kind, - ArrayRef<uint8_t> &Data) { - const Layout *L = nullptr; - CV_DESERIALIZE(Data, L); - return ListContinuationRecord(L->ContinuationIndex); -} - -//===----------------------------------------------------------------------===// // Type index remapping //===----------------------------------------------------------------------===// @@ -437,7 +78,7 @@ bool PointerRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ReferentType); if (isPointerToMember()) - Success &= MemberInfo.remapTypeIndices(IndexMap); + Success &= MemberInfo->remapTypeIndices(IndexMap); return Success; } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp deleted file mode 100644 index 112612c..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===-- TypeRecordBuilder.cpp ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) - : Stream(Buffer), Writer(Stream) { - writeTypeRecordKind(Kind); -} - -StringRef TypeRecordBuilder::str() { - return StringRef(Buffer.data(), Buffer.size()); -} - -void TypeRecordBuilder::writeUInt8(uint8_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt16(int16_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt16(uint16_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt32(int32_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt32(uint32_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt64(int64_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt64(uint64_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeEncodedInteger(int64_t Value) { - if (Value >= 0) { - writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)); - } else { - writeEncodedSignedInteger(Value); - } -} - -void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) { - if (Value >= std::numeric_limits<int8_t>::min() && - Value <= std::numeric_limits<int8_t>::max()) { - writeUInt16(LF_CHAR); - writeInt16(static_cast<int8_t>(Value)); - } else if (Value >= std::numeric_limits<int16_t>::min() && - Value <= std::numeric_limits<int16_t>::max()) { - writeUInt16(LF_SHORT); - writeInt16(static_cast<int16_t>(Value)); - } else if (Value >= std::numeric_limits<int32_t>::min() && - Value <= std::numeric_limits<int32_t>::max()) { - writeUInt16(LF_LONG); - writeInt32(static_cast<int32_t>(Value)); - } else { - writeUInt16(LF_QUADWORD); - writeInt64(Value); - } -} - -void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) { - if (Value < LF_CHAR) { - writeUInt16(static_cast<uint16_t>(Value)); - } else if (Value <= std::numeric_limits<uint16_t>::max()) { - writeUInt16(LF_USHORT); - writeUInt16(static_cast<uint16_t>(Value)); - } else if (Value <= std::numeric_limits<uint32_t>::max()) { - writeUInt16(LF_ULONG); - writeUInt32(static_cast<uint32_t>(Value)); - } else { - writeUInt16(LF_UQUADWORD); - writeUInt64(Value); - } -} - -void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) { - // Microsoft's linker seems to have trouble with symbol names longer than - // 0xffd8 bytes. - Value = Value.substr(0, 0xffd8); - Stream.write(Value.data(), Value.size()); - writeUInt8(0); -} - -void TypeRecordBuilder::writeGuid(StringRef Guid) { - assert(Guid.size() == 16); - Stream.write(Guid.data(), 16); -} - -void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) { - writeUInt32(TypeInd.getIndex()); -} - -void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) { - writeUInt16(static_cast<uint16_t>(Kind)); -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp new file mode 100644 index 0000000..f46e08d --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -0,0 +1,467 @@ +//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" + +using namespace llvm; +using namespace llvm::codeview; + +#define error(X) \ + if (auto EC = X) \ + return EC; + +namespace { +struct MapOneMethodRecord { + explicit MapOneMethodRecord(bool IsFromOverloadList) + : IsFromOverloadList(IsFromOverloadList) {} + + Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const { + error(IO.mapInteger(Method.Attrs.Attrs)); + if (IsFromOverloadList) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + } + error(IO.mapInteger(Method.Type)); + if (Method.isIntroducingVirtual()) { + error(IO.mapInteger(Method.VFTableOffset)); + } else if (!IO.isWriting()) + Method.VFTableOffset = -1; + + if (!IsFromOverloadList) + error(IO.mapStringZ(Method.Name)); + + return Error::success(); + } + +private: + bool IsFromOverloadList; +}; +} + +static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name, + StringRef &UniqueName, bool HasUniqueName) { + if (IO.isWriting()) { + // Try to be smart about what we write here. We can't write anything too + // large, so if we're going to go over the limit, truncate both the name + // and unique name by the same amount. + size_t BytesLeft = IO.maxFieldLength(); + if (HasUniqueName) { + size_t BytesNeeded = Name.size() + UniqueName.size() + 2; + StringRef N = Name; + StringRef U = UniqueName; + if (BytesNeeded > BytesLeft) { + size_t BytesToDrop = (BytesNeeded - BytesLeft); + size_t DropN = std::min(N.size(), BytesToDrop / 2); + size_t DropU = std::min(U.size(), BytesToDrop - DropN); + + N = N.drop_back(DropN); + U = U.drop_back(DropU); + } + + error(IO.mapStringZ(N)); + error(IO.mapStringZ(U)); + } else { + 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); + } + error(IO.mapStringZ(N)); + } + } else { + error(IO.mapStringZ(Name)); + if (HasUniqueName) + error(IO.mapStringZ(UniqueName)); + } + + return Error::success(); +} + +Error TypeRecordMapping::visitTypeBegin(CVType &CVR) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(!MemberKind.hasValue() && "Already in a member mapping!"); + + // FieldList and MethodList records can be any length because they can be + // split with continuation records. All other record types cannot be + // longer than the maximum record length. + Optional<uint32_t> MaxLen; + if (CVR.Type != TypeLeafKind::LF_FIELDLIST && + CVR.Type != TypeLeafKind::LF_METHODLIST) + MaxLen = MaxRecordLength - sizeof(RecordPrefix); + error(IO.beginRecord(MaxLen)); + TypeKind = CVR.Type; + return Error::success(); +} + +Error TypeRecordMapping::visitTypeEnd(CVType &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(!MemberKind.hasValue() && "Still in a member mapping!"); + + error(IO.endRecord()); + + TypeKind.reset(); + return Error::success(); +} + +Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(!MemberKind.hasValue() && "Already in a member mapping!"); + + // The largest possible subrecord is one in which there is a record prefix, + // followed by the subrecord, followed by a continuation, and that entire + // sequence spaws `MaxRecordLength` bytes. So the record's length is + // calculated as follows. + constexpr uint32_t ContinuationLength = 8; + error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) - + ContinuationLength)); + + MemberKind = Record.Kind; + return Error::success(); +} + +Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(MemberKind.hasValue() && "Not in a member mapping!"); + + if (!IO.isWriting()) { + if (auto EC = IO.skipPadding()) + return EC; + } + + MemberKind.reset(); + error(IO.endRecord()); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) { + error(IO.mapInteger(Record.ModifiedType)); + error(IO.mapEnum(Record.Modifiers)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + ProcedureRecord &Record) { + error(IO.mapInteger(Record.ReturnType)); + error(IO.mapEnum(Record.CallConv)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.ParameterCount)); + error(IO.mapInteger(Record.ArgumentList)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &Record) { + error(IO.mapInteger(Record.ReturnType)); + error(IO.mapInteger(Record.ClassType)); + error(IO.mapInteger(Record.ThisType)); + error(IO.mapEnum(Record.CallConv)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.ParameterCount)); + error(IO.mapInteger(Record.ArgumentList)); + error(IO.mapInteger(Record.ThisPointerAdjustment)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { + error(IO.mapVectorN<uint32_t>( + Record.StringIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) { + error(IO.mapInteger(Record.ReferentType)); + error(IO.mapInteger(Record.Attrs)); + + if (Record.isPointerToMember()) { + if (!IO.isWriting()) + Record.MemberInfo.emplace(); + + MemberPointerInfo &M = *Record.MemberInfo; + error(IO.mapInteger(M.ContainingType)); + error(IO.mapEnum(M.Representation)); + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) { + error(IO.mapInteger(Record.ElementType)); + error(IO.mapInteger(Record.IndexType)); + error(IO.mapEncodedInteger(Record.Size)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { + assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) || + (CVR.Type == TypeLeafKind::LF_CLASS) || + (CVR.Type == TypeLeafKind::LF_INTERFACE)); + + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.FieldList)); + error(IO.mapInteger(Record.DerivationList)); + error(IO.mapInteger(Record.VTableShape)); + error(IO.mapEncodedInteger(Record.Size)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.FieldList)); + error(IO.mapEncodedInteger(Record.Size)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) { + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.UnderlyingType)); + error(IO.mapInteger(Record.FieldList)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) { + error(IO.mapInteger(Record.Type)); + error(IO.mapInteger(Record.BitSize)); + error(IO.mapInteger(Record.BitOffset)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Record) { + uint16_t Size; + if (IO.isWriting()) { + ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); + Size = Slots.size(); + error(IO.mapInteger(Size)); + + for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { + uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; + if ((SlotIndex + 1) < Slots.size()) { + Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); + } + error(IO.mapInteger(Byte)); + } + } else { + error(IO.mapInteger(Size)); + for (uint16_t I = 0; I < Size; I += 2) { + uint8_t Byte; + error(IO.mapInteger(Byte)); + Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF)); + if ((I + 1) < Size) + Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4)); + } + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) { + error(IO.mapInteger(Record.CompleteClass)); + error(IO.mapInteger(Record.OverriddenVFTable)); + error(IO.mapInteger(Record.VFPtrOffset)); + uint32_t NamesLen = 0; + if (IO.isWriting()) { + for (auto Name : Record.MethodNames) + NamesLen += Name.size() + 1; + } + error(IO.mapInteger(NamesLen)); + error(IO.mapVectorTail( + Record.MethodNames, + [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); })); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) { + error(IO.mapInteger(Record.Id)); + error(IO.mapStringZ(Record.String)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT)); + error(IO.mapInteger(Record.SourceFile)); + error(IO.mapInteger(Record.LineNumber)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT)); + error(IO.mapInteger(Record.SourceFile)); + error(IO.mapInteger(Record.LineNumber)); + error(IO.mapInteger(Record.Module)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) { + error(IO.mapInteger(Record.ParentScope)); + error(IO.mapInteger(Record.FunctionType)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Record) { + error(IO.mapInteger(Record.ClassType)); + error(IO.mapInteger(Record.FunctionType)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + BuildInfoRecord &Record) { + error(IO.mapVectorN<uint16_t>( + Record.ArgIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Record) { + // TODO: Split the list into multiple records if it's longer than 64KB, using + // a subrecord of TypeRecordKind::Index to chain the records together. + error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true))); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + FieldListRecord &Record) { + error(IO.mapByteVectorTail(Record.Data)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + TypeServer2Record &Record) { + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapEncodedInteger(Record.Offset)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + + // FIXME: Handle full APInt such as __int128. + error(IO.mapEncodedInteger(Record.Value)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapEncodedInteger(Record.FieldOffset)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Record) { + error(IO.mapInteger(Record.NumOverloads)); + error(IO.mapInteger(Record.MethodList)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Record) { + MapOneMethodRecord Mapper(false); + return Mapper(IO, Record); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.Type)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Record) { + + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Record) { + + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.BaseType)); + error(IO.mapInteger(Record.VBPtrType)); + error(IO.mapEncodedInteger(Record.VBPtrOffset)); + error(IO.mapEncodedInteger(Record.VTableIndex)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.Type)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.ContinuationIndex)); + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp new file mode 100644 index 0000000..f24fcff --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -0,0 +1,243 @@ +//===- TypeSerialzier.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeSerializer.h" + +#include "llvm/DebugInfo/MSF/StreamWriter.h" + +#include <string.h> + +using namespace llvm; +using namespace llvm::codeview; + +bool TypeSerializer::isInFieldList() const { + return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST; +} + +TypeIndex TypeSerializer::calcNextTypeIndex() const { + if (LastTypeIndex.isNoneType()) + return TypeIndex(TypeIndex::FirstNonSimpleIndex); + else + return TypeIndex(LastTypeIndex.getIndex() + 1); +} + +TypeIndex TypeSerializer::incrementTypeIndex() { + TypeIndex Previous = LastTypeIndex; + LastTypeIndex = calcNextTypeIndex(); + return Previous; +} + +MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() { + assert(isInFieldList()); + return getCurrentRecordData().drop_front(CurrentSegment.length()); +} + +MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() { + return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset()); +} + +Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) { + RecordPrefix Prefix; + Prefix.RecordKind = Kind; + Prefix.RecordLen = 0; + if (auto EC = Writer.writeObject(Prefix)) + return EC; + return Error::success(); +} + +TypeIndex +TypeSerializer::insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record) { + assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!"); + + StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size()); + + TypeIndex NextTypeIndex = calcNextTypeIndex(); + auto Result = HashedRecords.try_emplace(S, NextTypeIndex); + if (Result.second) { + LastTypeIndex = NextTypeIndex; + SeenRecords.push_back(Record); + } + return Result.first->getValue(); +} + +Expected<MutableArrayRef<uint8_t>> +TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) { + uint32_t Align = Record.size() % 4; + if (Align == 0) + return Record; + + int PaddingBytes = 4 - Align; + int N = PaddingBytes; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + if (auto EC = Writer.writeInteger(Pad)) + return std::move(EC); + --PaddingBytes; + } + return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N); +} + +TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage) + : RecordStorage(Storage), LastTypeIndex(), + RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream), + Mapping(Writer) { + // RecordBuffer needs to be able to hold enough data so that if we are 1 + // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes, + // we won't overflow. +} + +ArrayRef<MutableArrayRef<uint8_t>> TypeSerializer::records() const { + return SeenRecords; +} + +TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; } + +TypeIndex TypeSerializer::insertRecordBytes(MutableArrayRef<uint8_t> Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + return insertRecordBytesPrivate(Record); +} + +Error TypeSerializer::visitTypeBegin(CVType &Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + if (auto EC = writeRecordPrefix(Record.kind())) + return EC; + + TypeKind = Record.kind(); + if (auto EC = Mapping.visitTypeBegin(Record)) + return EC; + + return Error::success(); +} + +Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + if (auto EC = Mapping.visitTypeEnd(Record)) + return std::move(EC); + + // Update the record's length and fill out the CVType members to point to + // the stable memory holding the record's data. + auto ThisRecordData = getCurrentRecordData(); + auto ExpectedData = addPadding(ThisRecordData); + if (!ExpectedData) + return ExpectedData.takeError(); + ThisRecordData = *ExpectedData; + + RecordPrefix *Prefix = + reinterpret_cast<RecordPrefix *>(ThisRecordData.data()); + Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t); + + uint8_t *Copy = RecordStorage.Allocate<uint8_t>(ThisRecordData.size()); + ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size()); + ThisRecordData = MutableArrayRef<uint8_t>(Copy, ThisRecordData.size()); + Record = CVType(*TypeKind, ThisRecordData); + TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData); + + // Write out each additional segment in reverse order, and update each + // record's continuation index to point to the previous one. + for (auto X : reverse(FieldListSegments)) { + auto CIBytes = X.take_back(sizeof(uint32_t)); + support::ulittle32_t *CI = + reinterpret_cast<support::ulittle32_t *>(CIBytes.data()); + assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder"); + *CI = InsertedTypeIndex.getIndex(); + InsertedTypeIndex = insertRecordBytesPrivate(X); + } + + TypeKind.reset(); + Writer.setOffset(0); + FieldListSegments.clear(); + CurrentSegment.SubRecords.clear(); + + return InsertedTypeIndex; +} + +Error TypeSerializer::visitTypeEnd(CVType &Record) { + auto ExpectedIndex = visitTypeEndGetIndex(Record); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + return Error::success(); +} + +Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) { + assert(isInFieldList() && "Not in a field list!"); + assert(!MemberKind.hasValue() && "Already in a member record!"); + MemberKind = Record.Kind; + + if (auto EC = Mapping.visitMemberBegin(Record)) + return EC; + + return Error::success(); +} + +Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) { + if (auto EC = Mapping.visitMemberEnd(Record)) + return EC; + + // Check if this subrecord makes the current segment not fit in 64K minus + // the space for a continuation record (8 bytes). If the segment does not + // fit, insert a continuation record. + if (Writer.getOffset() > MaxRecordLength - ContinuationLength) { + MutableArrayRef<uint8_t> Data = getCurrentRecordData(); + SubRecord LastSubRecord = CurrentSegment.SubRecords.back(); + uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size; + auto CopyData = Data.take_front(CopySize); + auto LeftOverData = Data.drop_front(CopySize); + assert(LastSubRecord.Size == LeftOverData.size()); + + // Allocate stable storage for the record and copy the old record plus + // continuation over. + uint16_t LengthWithSize = CopySize + ContinuationLength; + assert(LengthWithSize <= MaxRecordLength); + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data()); + Prefix->RecordLen = LengthWithSize - sizeof(uint16_t); + + uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize); + auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize); + msf::MutableByteStream CS(SavedSegment); + msf::StreamWriter CW(CS); + if (auto EC = CW.writeBytes(CopyData)) + return EC; + if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX)) + return EC; + if (auto EC = CW.writeInteger(uint16_t(0))) + return EC; + if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0))) + return EC; + FieldListSegments.push_back(SavedSegment); + + // Write a new placeholder record prefix to mark the start of this new + // top-level record. + Writer.setOffset(0); + if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST)) + return EC; + + // Then move over the subrecord that overflowed the old segment to the + // beginning of this segment. Note that we have to use memmove here + // instead of Writer.writeBytes(), because the new and old locations + // could overlap. + ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(), + LeftOverData.size()); + // And point the segment writer at the end of that subrecord. + Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix)); + + CurrentSegment.SubRecords.clear(); + CurrentSegment.SubRecords.push_back(LastSubRecord); + } + + // Update the CVMemberRecord since we may have shifted around or gotten + // padded. + Record.Data = getCurrentSubRecordData(); + + MemberKind.reset(); + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index ebfda24..ed6cf57 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -11,10 +11,11 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" @@ -53,37 +54,61 @@ namespace { /// existing destination type index. class TypeStreamMerger : public TypeVisitorCallbacks { public: - TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) { + TypeStreamMerger(TypeTableBuilder &DestStream) + : DestStream(DestStream), FieldListBuilder(DestStream) { assert(!hadError()); } /// TypeVisitorCallbacks overrides. #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visit##Name(Name##Record &Record) override; + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - TYPE_RECORD(EnumName, EnumVal, Name) + Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override; #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" - Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override; + Error visitUnknownType(CVType &Record) override; - Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override; - Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override; - - Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) override; + Error visitTypeBegin(CVType &Record) override; + Error visitTypeEnd(CVType &Record) override; + Error visitMemberEnd(CVMemberRecord &Record) override; bool mergeStream(const CVTypeArray &Types); private: + template <typename RecordType> + Error visitKnownRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + IndexMap.push_back(DestStream.writeKnownType(Record)); + return Error::success(); + } + + Error visitKnownRecordImpl(FieldListRecord &Record) { + CVTypeVisitor Visitor(*this); + + if (auto EC = Visitor.visitFieldListMemberStream(Record.Data)) + return EC; + return Error::success(); + } + + template <typename RecordType> + Error visitKnownMemberRecordImpl(RecordType &Record) { + FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); + FieldListBuilder.writeMemberType(Record); + return Error::success(); + } + bool hadError() { return FoundBadTypeIndex; } bool FoundBadTypeIndex = false; - FieldListRecordBuilder FieldBuilder; + BumpPtrAllocator Allocator; TypeTableBuilder &DestStream; + FieldListRecordBuilder FieldListBuilder; + bool IsInFieldList{false}; size_t BeginIndexMapSize = 0; /// Map from source type index to destination type index. Indexed by source @@ -93,39 +118,45 @@ private: } // end anonymous namespace -Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) { - BeginIndexMapSize = IndexMap.size(); +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(const CVRecord<TypeLeafKind> &Rec) { - assert(IndexMap.size() == BeginIndexMapSize + 1); +Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) { + if (Rec.Type == TypeLeafKind::LF_FIELDLIST) { + TypeIndex Index = FieldListBuilder.end(); + IndexMap.push_back(Index); + IsInFieldList = false; + } return Error::success(); } -Error TypeStreamMerger::visitFieldListEnd(const CVRecord<TypeLeafKind> &Rec) { - IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); - FieldBuilder.reset(); +Error TypeStreamMerger::visitMemberEnd(CVMemberRecord &Rec) { + assert(IndexMap.size() == BeginIndexMapSize + 1); return Error::success(); } #define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ - FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ - IndexMap.push_back(DestStream.write##Name(Record)); \ - return Error::success(); \ + Error TypeStreamMerger::visitKnownRecord(CVType &CVR, \ + Name##Record &Record) { \ + return visitKnownRecordImpl(Record); \ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ - FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ - FieldBuilder.write##Name(Record); \ - return Error::success(); \ + Error TypeStreamMerger::visitKnownMember(CVMemberRecord &CVR, \ + Name##Record &Record) { \ + return visitKnownMemberRecordImpl(Record); \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" -Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) { +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)); @@ -134,7 +165,14 @@ Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) { bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) { assert(IndexMap.empty()); - CVTypeVisitor Visitor(*this); + TypeVisitorCallbackPipeline Pipeline; + + TypeDeserializer Deserializer; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(*this); + + CVTypeVisitor Visitor(Pipeline); + if (auto EC = Visitor.visitTypeStream(Types)) { consumeError(std::move(EC)); return false; diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp deleted file mode 100644 index 647538e..0000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ /dev/null @@ -1,303 +0,0 @@ -//===-- TypeTableBuilder.cpp ----------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace codeview; - -TypeTableBuilder::TypeTableBuilder() {} - -TypeTableBuilder::~TypeTableBuilder() {} - -TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getModifiedType()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers())); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReturnType()); - Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); - Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); - Builder.writeUInt16(Record.getParameterCount()); - Builder.writeTypeIndex(Record.getArgumentList()); - - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReturnType()); - Builder.writeTypeIndex(Record.getClassType()); - Builder.writeTypeIndex(Record.getThisType()); - Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); - Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); - Builder.writeUInt16(Record.getParameterCount()); - Builder.writeTypeIndex(Record.getArgumentList()); - Builder.writeInt32(Record.getThisPointerAdjustment()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt32(Record.getIndices().size()); - for (TypeIndex TI : Record.getIndices()) { - Builder.writeTypeIndex(TI); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReferentType()); - uint32_t flags = static_cast<uint32_t>(Record.getOptions()) | - (Record.getSize() << PointerRecord::PointerSizeShift) | - (static_cast<uint32_t>(Record.getMode()) - << PointerRecord::PointerModeShift) | - (static_cast<uint32_t>(Record.getPointerKind()) - << PointerRecord::PointerKindShift); - Builder.writeUInt32(flags); - - if (Record.isPointerToMember()) { - const MemberPointerInfo &M = Record.getMemberInfo(); - Builder.writeTypeIndex(M.getContainingType()); - Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation())); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getElementType()); - Builder.writeTypeIndex(Record.getIndexType()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - Builder.writeNullTerminatedString(Record.getName()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { - assert((Record.getKind() == TypeRecordKind::Struct) || - (Record.getKind() == TypeRecordKind::Class) || - (Record.getKind() == TypeRecordKind::Interface)); - - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt16(Record.getMemberCount()); - uint16_t Flags = - static_cast<uint16_t>(Record.getOptions()) | - (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) | - (static_cast<uint16_t>(Record.getWinRTKind()) - << ClassRecord::WinRTKindShift); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getFieldList()); - Builder.writeTypeIndex(Record.getDerivationList()); - Builder.writeTypeIndex(Record.getVTableShape()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - Builder.writeNullTerminatedString(Record.getName()); - if ((Record.getOptions() & ClassOptions::HasUniqueName) != - ClassOptions::None) { - Builder.writeNullTerminatedString(Record.getUniqueName()); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { - TypeRecordBuilder Builder(TypeRecordKind::Union); - Builder.writeUInt16(Record.getMemberCount()); - uint16_t Flags = - static_cast<uint16_t>(Record.getOptions()) | - (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getFieldList()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - Builder.writeNullTerminatedString(Record.getName()); - if ((Record.getOptions() & ClassOptions::HasUniqueName) != - ClassOptions::None) { - Builder.writeNullTerminatedString(Record.getUniqueName()); - } - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt16(Record.getMemberCount()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions())); - Builder.writeTypeIndex(Record.getUnderlyingType()); - Builder.writeTypeIndex(Record.getFieldList()); - Builder.writeNullTerminatedString(Record.getName()); - if ((Record.getOptions() & ClassOptions::HasUniqueName) != - ClassOptions::None) { - Builder.writeNullTerminatedString(Record.getUniqueName()); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getType()); - Builder.writeUInt8(Record.getBitSize()); - Builder.writeUInt8(Record.getBitOffset()); - - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); - - Builder.writeUInt16(Slots.size()); - for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { - uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; - if ((SlotIndex + 1) < Slots.size()) { - Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); - } - Builder.writeUInt8(Byte); - } - - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeVFTable(const VFTableRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getCompleteClass()); - Builder.writeTypeIndex(Record.getOverriddenVTable()); - Builder.writeUInt32(Record.getVFPtrOffset()); - - // Sum up the lengths of the null-terminated names. - size_t NamesLen = Record.getName().size() + 1; - for (StringRef MethodName : Record.getMethodNames()) - NamesLen += MethodName.size() + 1; - - Builder.writeUInt32(NamesLen); - Builder.writeNullTerminatedString(Record.getName()); - for (StringRef MethodName : Record.getMethodNames()) - Builder.writeNullTerminatedString(MethodName); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) { - TypeRecordBuilder Builder(TypeRecordKind::StringId); - Builder.writeTypeIndex(Record.getId()); - Builder.writeNullTerminatedString(Record.getString()); - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getUDT()); - Builder.writeTypeIndex(Record.getSourceFile()); - Builder.writeUInt32(Record.getLineNumber()); - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getUDT()); - Builder.writeTypeIndex(Record.getSourceFile()); - Builder.writeUInt32(Record.getLineNumber()); - Builder.writeUInt16(Record.getModule()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getParentScope()); - Builder.writeTypeIndex(Record.getFunctionType()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getClassType()); - Builder.writeTypeIndex(Record.getFunctionType()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - assert(Record.getArgs().size() <= UINT16_MAX); - Builder.writeUInt16(Record.getArgs().size()); - for (TypeIndex Arg : Record.getArgs()) - Builder.writeTypeIndex(Arg); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) { - return writeRecord(Builder.str()); -} - -TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { - return FieldList.writeListRecord(*this); -} - -TypeIndex TypeTableBuilder::writeMethodOverloadList( - const MethodOverloadListRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - for (const OneMethodRecord &Method : Record.getMethods()) { - uint16_t Flags = static_cast<uint16_t>(Method.getAccess()); - Flags |= static_cast<uint16_t>(Method.getKind()) - << MemberAttributes::MethodKindShift; - Flags |= static_cast<uint16_t>(Method.getOptions()); - Builder.writeUInt16(Flags); - Builder.writeUInt16(0); // padding - Builder.writeTypeIndex(Method.getType()); - if (Method.isIntroducingVirtual()) { - assert(Method.getVFTableOffset() >= 0); - Builder.writeInt32(Method.getVFTableOffset()); - } else { - assert(Method.getVFTableOffset() == -1); - } - } - - // TODO: Split the list into multiple records if it's longer than 64KB, using - // a subrecord of TypeRecordKind::Index to chain the records together. - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeGuid(Record.getGuid()); - Builder.writeUInt32(Record.getAge()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 9314c9e..08bc74a 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -16,9 +18,11 @@ using namespace dwarf; void DWARFAbbreviationDeclaration::clear() { Code = 0; - Tag = 0; + Tag = DW_TAG_null; + CodeByteSize = 0; HasChildren = false; AttributeSpecs.clear(); + FixedAttributeSize.reset(); } DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { @@ -26,72 +30,190 @@ DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { } bool -DWARFAbbreviationDeclaration::extract(DataExtractor Data, uint32_t* OffsetPtr) { +DWARFAbbreviationDeclaration::extract(DataExtractor Data, + uint32_t* OffsetPtr) { clear(); + const uint32_t Offset = *OffsetPtr; Code = Data.getULEB128(OffsetPtr); if (Code == 0) { return false; } - Tag = Data.getULEB128(OffsetPtr); + CodeByteSize = *OffsetPtr - Offset; + Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr)); + if (Tag == DW_TAG_null) { + clear(); + return false; + } uint8_t ChildrenByte = Data.getU8(OffsetPtr); HasChildren = (ChildrenByte == DW_CHILDREN_yes); + // Assign a value to our optional FixedAttributeSize member variable. If + // this member variable still has a value after the while loop below, then + // all attribute data in this abbreviation declaration has a fixed byte size. + FixedAttributeSize = FixedSizeInfo(); + // Read all of the abbreviation attributes and forms. while (true) { - uint32_t CurOffset = *OffsetPtr; - uint16_t Attr = Data.getULEB128(OffsetPtr); - if (CurOffset == *OffsetPtr) { - clear(); - return false; - } - CurOffset = *OffsetPtr; - uint16_t Form = Data.getULEB128(OffsetPtr); - if (CurOffset == *OffsetPtr) { + auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); + auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); + if (A && F) { + Optional<int64_t> V; + bool IsImplicitConst = (F == DW_FORM_implicit_const); + if (IsImplicitConst) + V = Data.getSLEB128(OffsetPtr); + else if (auto Size = DWARFFormValue::getFixedByteSize(F)) + V = *Size; + AttributeSpecs.push_back(AttributeSpec(A, F, V)); + if (IsImplicitConst) + continue; + // If this abbrevation still has a fixed byte size, then update the + // FixedAttributeSize as needed. + if (FixedAttributeSize) { + if (V) + FixedAttributeSize->NumBytes += *V; + else { + switch (F) { + case DW_FORM_addr: + ++FixedAttributeSize->NumAddrs; + break; + + case DW_FORM_ref_addr: + ++FixedAttributeSize->NumRefAddrs; + break; + + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: + ++FixedAttributeSize->NumDwarfOffsets; + break; + + default: + // Indicate we no longer have a fixed byte size for this + // abbreviation by clearing the FixedAttributeSize optional value + // so it doesn't have a value. + FixedAttributeSize.reset(); + break; + } + } + } + } else if (A == 0 && F == 0) { + // We successfully reached the end of this abbreviation declaration + // since both attribute and form are zero. + break; + } else { + // Attribute and form pairs must either both be non-zero, in which case + // they are added to the abbreviation declaration, or both be zero to + // terminate the abbrevation declaration. In this case only one was + // zero which is an error. clear(); return false; } - if (Attr == 0 && Form == 0) - break; - AttributeSpecs.push_back(AttributeSpec(Attr, Form)); - } - - if (Tag == 0) { - clear(); - return false; } return true; } void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { - const char *tagString = TagString(getTag()); + auto tagString = TagString(getTag()); OS << '[' << getCode() << "] "; - if (tagString) + if (!tagString.empty()) OS << tagString; else OS << format("DW_TAG_Unknown_%x", getTag()); OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; for (const AttributeSpec &Spec : AttributeSpecs) { OS << '\t'; - const char *attrString = AttributeString(Spec.Attr); - if (attrString) + auto attrString = AttributeString(Spec.Attr); + if (!attrString.empty()) OS << attrString; else OS << format("DW_AT_Unknown_%x", Spec.Attr); OS << '\t'; - const char *formString = FormEncodingString(Spec.Form); - if (formString) + auto formString = FormEncodingString(Spec.Form); + if (!formString.empty()) OS << formString; else OS << format("DW_FORM_Unknown_%x", Spec.Form); + if (Spec.isImplicitConst()) + OS << '\t' << *Spec.ByteSizeOrValue; OS << '\n'; } OS << '\n'; } -uint32_t -DWARFAbbreviationDeclaration::findAttributeIndex(uint16_t attr) const { +Optional<uint32_t> +DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const { for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) { - if (AttributeSpecs[i].Attr == attr) + if (AttributeSpecs[i].Attr == Attr) return i; } - return -1U; + return None; +} + +Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( + const uint32_t DIEOffset, const dwarf::Attribute Attr, + const DWARFUnit &U) const { + Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr); + if (!MatchAttrIndex) + return None; + + auto DebugInfoData = U.getDebugInfoExtractor(); + + // Add the byte size of ULEB that for the abbrev Code so we can start + // skipping the attribute data. + uint32_t Offset = DIEOffset + CodeByteSize; + uint32_t AttrIndex = 0; + for (const auto &Spec : AttributeSpecs) { + if (*MatchAttrIndex == AttrIndex) { + // We have arrived at the attribute to extract, extract if from Offset. + DWARFFormValue FormValue(Spec.Form); + if (Spec.isImplicitConst()) { + FormValue.setSValue(*Spec.ByteSizeOrValue); + return FormValue; + } + if (FormValue.extractValue(DebugInfoData, &Offset, &U)) + return FormValue; + } + // March Offset along until we get to the attribute we want. + if (auto FixedSize = Spec.getByteSize(U)) + Offset += *FixedSize; + else + DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U); + ++AttrIndex; + } + return None; +} + +size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize( + const DWARFUnit &U) const { + size_t ByteSize = NumBytes; + if (NumAddrs) + ByteSize += NumAddrs * U.getAddressByteSize(); + if (NumRefAddrs) + ByteSize += NumRefAddrs * U.getRefAddrByteSize(); + if (NumDwarfOffsets) + ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize(); + return ByteSize; +} + +Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( + const DWARFUnit &U) const { + if (isImplicitConst()) + return 0; + if (ByteSizeOrValue) + return ByteSizeOrValue; + Optional<int64_t> S; + auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, &U); + if (FixedByteSize) + S = *FixedByteSize; + return S; +} + +Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( + const DWARFUnit &U) const { + if (FixedAttributeSize) + return FixedAttributeSize->getByteSize(U); + return None; } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 8ae0543..7111ad3 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -39,7 +39,7 @@ bool DWARFAcceleratorTable::extract() { for (unsigned i = 0; i < NumAtoms; ++i) { uint16_t AtomType = AccelSection.getU16(&Offset); - uint16_t AtomForm = AccelSection.getU16(&Offset); + auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); } @@ -61,12 +61,14 @@ void DWARFAcceleratorTable::dump(raw_ostream &OS) const { SmallVector<DWARFFormValue, 3> AtomForms; for (const auto &Atom: HdrData.Atoms) { OS << format("Atom[%d] Type: ", i++); - if (const char *TypeString = dwarf::AtomTypeString(Atom.first)) + auto TypeString = dwarf::AtomTypeString(Atom.first); + if (!TypeString.empty()) OS << TypeString; else OS << format("DW_ATOM_Unknown_0x%x", Atom.first); OS << " Form: "; - if (const char *FormString = dwarf::FormEncodingString(Atom.second)) + auto FormString = dwarf::FormEncodingString(Atom.second); + if (!FormString.empty()) OS << FormString; else OS << format("DW_FORM_Unknown_0x%x", Atom.second); @@ -118,7 +120,7 @@ void DWARFAcceleratorTable::dump(raw_ostream &OS) const { for (auto &Atom : AtomForms) { OS << format("{Atom[%d]: ", i++); if (Atom.extractValue(AccelSection, &DataOffset, nullptr)) - Atom.dump(OS, nullptr); + Atom.dump(OS); else OS << "Error extracting the value"; OS << "} "; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp index 39a7c77..948972f 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -22,12 +24,11 @@ void DWARFCompileUnit::dump(raw_ostream &OS) { << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; - if (const DWARFDebugInfoEntryMinimal *CU = getUnitDIE(false)) - CU->dump(OS, this, -1U); + if (DWARFDie CUDie = getUnitDIE(false)) + CUDie.dump(OS, -1U); else OS << "<compile unit can't be parsed!>\n\n"; } // VTable anchor. -DWARFCompileUnit::~DWARFCompileUnit() { -} +DWARFCompileUnit::~DWARFCompileUnit() = default; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index e8ea71b..77f6f65 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -12,7 +12,9 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Object/Decompressor.h" #include "llvm/Object/MachO.h" #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Compression.h" @@ -32,37 +34,6 @@ typedef DWARFDebugLine::LineTable DWARFLineTable; typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind; -static void dumpPubSection(raw_ostream &OS, StringRef Name, StringRef Data, - bool LittleEndian, bool GnuStyle) { - OS << "\n." << Name << " contents:\n"; - DataExtractor pubNames(Data, LittleEndian, 0); - uint32_t offset = 0; - while (pubNames.isValidOffset(offset)) { - OS << "length = " << format("0x%08x", pubNames.getU32(&offset)); - OS << " version = " << format("0x%04x", pubNames.getU16(&offset)); - OS << " unit_offset = " << format("0x%08x", pubNames.getU32(&offset)); - OS << " unit_size = " << format("0x%08x", pubNames.getU32(&offset)) << '\n'; - if (GnuStyle) - OS << "Offset Linkage Kind Name\n"; - else - OS << "Offset Name\n"; - - while (offset < Data.size()) { - uint32_t dieRef = pubNames.getU32(&offset); - if (dieRef == 0) - break; - OS << format("0x%8.8x ", dieRef); - if (GnuStyle) { - PubIndexEntryDescriptor desc(pubNames.getU8(&offset)); - OS << format("%-8s", dwarf::GDBIndexEntryLinkageString(desc.Linkage)) - << ' ' << format("%-8s", dwarf::GDBIndexEntryKindString(desc.Kind)) - << ' '; - } - OS << '\"' << pubNames.getCStr(&offset) << "\"\n"; - } - } -} - static void dumpAccelSection(raw_ostream &OS, StringRef Name, const DWARFSection& Section, StringRef StringSection, bool LittleEndian) { @@ -75,7 +46,8 @@ static void dumpAccelSection(raw_ostream &OS, StringRef Name, Accel.dump(OS); } -void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { +void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, + bool SummarizeTypes) { if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) { OS << ".debug_abbrev contents:\n"; getDebugAbbrev()->dump(OS); @@ -104,7 +76,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { OS << "\n.debug_types contents:\n"; for (const auto &TUS : type_unit_sections()) for (const auto &TU : TUS) - TU->dump(OS); + TU->dump(OS, SummarizeTypes); } if ((DumpType == DIDT_All || DumpType == DIDT_TypesDwo) && @@ -112,7 +84,7 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { OS << "\n.debug_types.dwo contents:\n"; for (const auto &DWOTUS : dwo_type_unit_sections()) for (const auto &DWOTU : DWOTUS) - DWOTU->dump(OS); + DWOTU->dump(OS, SummarizeTypes); } if (DumpType == DIDT_All || DumpType == DIDT_Loc) { @@ -153,16 +125,16 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { OS << "\n.debug_line contents:\n"; for (const auto &CU : compile_units()) { savedAddressByteSize = CU->getAddressByteSize(); - const auto *CUDIE = CU->getUnitDIE(); - if (CUDIE == nullptr) + auto CUDIE = CU->getUnitDIE(); + if (!CUDIE) continue; - unsigned stmtOffset = CUDIE->getAttributeValueAsSectionOffset( - CU.get(), DW_AT_stmt_list, -1U); - if (stmtOffset != -1U) { + if (auto StmtOffset = + CUDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list)) { DataExtractor lineData(getLineSection().Data, isLittleEndian(), savedAddressByteSize); DWARFDebugLine::LineTable LineTable; - LineTable.parse(lineData, &getLineSection().Relocs, &stmtOffset); + uint32_t Offset = *StmtOffset; + LineTable.parse(lineData, &getLineSection().Relocs, &Offset); LineTable.dump(OS); } } @@ -228,20 +200,22 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { } if (DumpType == DIDT_All || DumpType == DIDT_Pubnames) - dumpPubSection(OS, "debug_pubnames", getPubNamesSection(), - isLittleEndian(), false); + DWARFDebugPubTable(getPubNamesSection(), isLittleEndian(), false) + .dump("debug_pubnames", OS); if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes) - dumpPubSection(OS, "debug_pubtypes", getPubTypesSection(), - isLittleEndian(), false); + DWARFDebugPubTable(getPubTypesSection(), isLittleEndian(), false) + .dump("debug_pubtypes", OS); if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames) - dumpPubSection(OS, "debug_gnu_pubnames", getGnuPubNamesSection(), - isLittleEndian(), true /* GnuStyle */); + DWARFDebugPubTable(getGnuPubNamesSection(), isLittleEndian(), + true /* GnuStyle */) + .dump("debug_gnu_pubnames", OS); if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes) - dumpPubSection(OS, "debug_gnu_pubtypes", getGnuPubTypesSection(), - isLittleEndian(), true /* GnuStyle */); + DWARFDebugPubTable(getGnuPubTypesSection(), isLittleEndian(), + true /* GnuStyle */) + .dump("debug_gnu_pubtypes", OS); if ((DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) && !getStringOffsetDWOSection().empty()) { @@ -256,6 +230,12 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH) { } } + if ((DumpType == DIDT_All || DumpType == DIDT_GdbIndex) && + !getGdbIndexSection().empty()) { + OS << "\n.gnu_index contents:\n"; + getGdbIndex().dump(OS); + } + if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) dumpAccelSection(OS, "apple_names", getAppleNamesSection(), getStringSection(), isLittleEndian()); @@ -295,6 +275,16 @@ const DWARFUnitIndex &DWARFContext::getTUIndex() { return *TUIndex; } +DWARFGdbIndex &DWARFContext::getGdbIndex() { + if (GdbIndex) + return *GdbIndex; + + DataExtractor GdbIndexData(getGdbIndexSection(), true /*LE*/, 0); + GdbIndex = llvm::make_unique<DWARFGdbIndex>(); + GdbIndex->parse(GdbIndexData); + return *GdbIndex; +} + const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { if (Abbrev) return Abbrev.get(); @@ -393,16 +383,15 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) { if (!Line) Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); - const auto *UnitDIE = U->getUnitDIE(); - if (UnitDIE == nullptr) + auto UnitDIE = U->getUnitDIE(); + if (!UnitDIE) return nullptr; - unsigned stmtOffset = - UnitDIE->getAttributeValueAsSectionOffset(U, DW_AT_stmt_list, -1U); - if (stmtOffset == -1U) + auto Offset = UnitDIE.getAttributeValueAsSectionOffset(DW_AT_stmt_list); + if (!Offset) return nullptr; // No line table for this compile unit. - stmtOffset += U->getLineTableOffset(); + uint32_t stmtOffset = *Offset + U->getLineTableOffset(); // See if the line table is cached. if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) return lt; @@ -458,14 +447,12 @@ static bool getFunctionNameForAddress(DWARFCompileUnit *CU, uint64_t Address, return false; // 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. - const DWARFDebugInfoEntryInlinedChain &InlinedChain = - CU->getInlinedChainForAddress(Address); - if (InlinedChain.DIEs.size() == 0) + // name of the topmost function in it.SmallVectorImpl<DWARFDie> &InlinedChain + SmallVector<DWARFDie, 4> InlinedChain; + CU->getInlinedChainForAddress(Address, InlinedChain); + if (InlinedChain.size() == 0) return false; - const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain.DIEs[0]; - if (const char *Name = - TopFunctionDIE.getSubroutineName(InlinedChain.U, Kind)) { + if (const char *Name = InlinedChain[0].getSubroutineName(Kind)) { FunctionName = Name; return true; } @@ -540,9 +527,9 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; const DWARFLineTable *LineTable = nullptr; - const DWARFDebugInfoEntryInlinedChain &InlinedChain = - CU->getInlinedChainForAddress(Address); - if (InlinedChain.DIEs.size() == 0) { + SmallVector<DWARFDie, 4> InlinedChain; + CU->getInlinedChainForAddress(Address, InlinedChain); + if (InlinedChain.size() == 0) { // If there is no DIE for address (e.g. it is in unavailable .dwo file), // try to at least get file/line info from symbol table. if (Spec.FLIKind != FileLineInfoKind::None) { @@ -557,12 +544,11 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, } uint32_t CallFile = 0, CallLine = 0, CallColumn = 0; - for (uint32_t i = 0, n = InlinedChain.DIEs.size(); i != n; i++) { - const DWARFDebugInfoEntryMinimal &FunctionDIE = InlinedChain.DIEs[i]; + for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) { + DWARFDie &FunctionDIE = InlinedChain[i]; DILineInfo Frame; // Get function name if necessary. - if (const char *Name = - FunctionDIE.getSubroutineName(InlinedChain.U, Spec.FNKind)) + if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind)) Frame.FunctionName = Name; if (Spec.FLIKind != FileLineInfoKind::None) { if (i == 0) { @@ -584,8 +570,7 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, } // Get call file/line/column of a current DIE. if (i + 1 < n) { - FunctionDIE.getCallerFrame(InlinedChain.U, CallFile, CallLine, - CallColumn); + FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn); } } InliningInfo.addFrame(Frame); @@ -593,66 +578,6 @@ DWARFContext::getInliningInfoForAddress(uint64_t Address, return InliningInfo; } -static bool consumeCompressedGnuHeader(StringRef &data, - uint64_t &OriginalSize) { - // Consume "ZLIB" prefix. - if (!data.startswith("ZLIB")) - return false; - data = data.substr(4); - // Consume uncompressed section size (big-endian 8 bytes). - DataExtractor extractor(data, false, 8); - uint32_t Offset = 0; - OriginalSize = extractor.getU64(&Offset); - if (Offset == 0) - return false; - data = data.substr(Offset); - return true; -} - -static bool consumeCompressedZLibHeader(StringRef &Data, uint64_t &OriginalSize, - bool IsLE, bool Is64Bit) { - using namespace ELF; - uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); - if (Data.size() < HdrSize) - return false; - - DataExtractor Extractor(Data, IsLE, 0); - uint32_t Offset = 0; - if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) - : sizeof(Elf32_Word)) != - ELFCOMPRESS_ZLIB) - return false; - - // Skip Elf64_Chdr::ch_reserved field. - if (Is64Bit) - Offset += sizeof(Elf64_Word); - - OriginalSize = Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Xword) - : sizeof(Elf32_Word)); - Data = Data.substr(HdrSize); - return true; -} - -static bool tryDecompress(StringRef &Name, StringRef &Data, - SmallString<32> &Out, bool ZLibStyle, bool IsLE, - bool Is64Bit) { - if (!zlib::isAvailable()) - return false; - - uint64_t OriginalSize; - bool Result = - ZLibStyle ? consumeCompressedZLibHeader(Data, OriginalSize, IsLE, Is64Bit) - : consumeCompressedGnuHeader(Data, OriginalSize); - - if (!Result || zlib::uncompress(Data, Out, OriginalSize) != zlib::StatusOK) - return false; - - // gnu-style names are started from "z", consume that. - if (!ZLibStyle) - Name = Name.substr(1); - return true; -} - DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), @@ -676,18 +601,23 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); - name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. - - bool ZLibStyleCompressed = Section.isCompressed(); - if (ZLibStyleCompressed || name.startswith("zdebug_")) { + if (Decompressor::isCompressed(Section)) { + Expected<Decompressor> Decompressor = + Decompressor::create(name, data, IsLittleEndian, AddressSize == 8); + if (!Decompressor) + continue; SmallString<32> Out; - if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian, - AddressSize == 8)) + if (auto Err = Decompressor->decompress(Out)) continue; UncompressedSections.emplace_back(std::move(Out)); data = UncompressedSections.back(); } + // Compressed sections names in GNU style starts from ".z", + // at this point section is decompressed and we drop compression prefix. + name = name.substr( + name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes. + StringRef *SectionData = StringSwitch<StringRef *>(name) .Case("debug_info", &InfoSection.Data) @@ -718,6 +648,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, .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) { diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index 9b6a9a7..32b8320 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -12,31 +12,36 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Dwarf.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 <string> -#include <utility> #include <vector> using namespace llvm; using namespace dwarf; - /// \brief Abstract frame entry defining the common interface concrete /// entries implement. class llvm::FrameEntry { public: enum FrameKind {FK_CIE, FK_FDE}; + FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length) : Kind(K), Offset(Offset), Length(Length) {} - virtual ~FrameEntry() { - } + virtual ~FrameEntry() = default; FrameKind getKind() const { return Kind; } virtual uint64_t getOffset() const { return Offset; } @@ -95,7 +100,6 @@ protected: } }; - // See DWARF standard v3, section 7.23 const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0; const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f; @@ -194,6 +198,7 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset, } namespace { + /// \brief DWARF Common Information Entry (CIE) class CIE : public FrameEntry { public: @@ -215,14 +220,16 @@ public: FDEPointerEncoding(FDEPointerEncoding), LSDAPointerEncoding(LSDAPointerEncoding) {} - ~CIE() override {} + ~CIE() override = default; StringRef getAugmentationString() const { return Augmentation; } uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; } int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; } + uint32_t getFDEPointerEncoding() const { return FDEPointerEncoding; } + uint32_t getLSDAPointerEncoding() const { return LSDAPointerEncoding; } @@ -274,7 +281,6 @@ private: uint32_t LSDAPointerEncoding; }; - /// \brief DWARF Frame Description Entry (FDE) class FDE : public FrameEntry { public: @@ -288,7 +294,7 @@ public: InitialLocation(InitialLocation), AddressRange(AddressRange), LinkedCIE(Cie) {} - ~FDE() override {} + ~FDE() override = default; CIE *getLinkedCIE() const { return LinkedCIE; } @@ -336,7 +342,7 @@ static ArrayRef<OperandType[2]> getOperandTypes() { do { \ OpTypes[OP][0] = OPTYPE0; \ OpTypes[OP][1] = OPTYPE1; \ - } while (0) + } while (false) #define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) #define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) @@ -373,6 +379,7 @@ static ArrayRef<OperandType[2]> getOperandTypes() { #undef DECLARE_OP0 #undef DECLARE_OP1 #undef DECLARE_OP2 + return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1); } @@ -387,13 +394,15 @@ static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx, OperandType Type = OpTypes[Opcode][OperandIdx]; switch (Type) { - case OT_Unset: + case OT_Unset: { OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to"; - if (const char *OpcodeName = CallFrameString(Opcode)) + auto OpcodeName = CallFrameString(Opcode); + if (!OpcodeName.empty()) OS << " " << OpcodeName; else OS << format(" Opcode %x", Opcode); break; + } case OT_None: break; case OT_Address: @@ -459,8 +468,7 @@ void FrameEntry::dumpInstructions(raw_ostream &OS) const { DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) { } -DWARFDebugFrame::~DWARFDebugFrame() { -} +DWARFDebugFrame::~DWARFDebugFrame() = default; static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, uint32_t Offset, int Length) { @@ -611,12 +619,14 @@ void DWARFDebugFrame::parse(DataExtractor Data) { } } - auto Cie = make_unique<CIE>(StartOffset, Length, Version, - AugmentationString, AddressSize, - SegmentDescriptorSize, CodeAlignmentFactor, - DataAlignmentFactor, ReturnAddressRegister, - AugmentationData, FDEPointerEncoding, - LSDAPointerEncoding); + auto Cie = llvm::make_unique<CIE>(StartOffset, Length, Version, + AugmentationString, AddressSize, + SegmentDescriptorSize, + CodeAlignmentFactor, + DataAlignmentFactor, + ReturnAddressRegister, + AugmentationData, FDEPointerEncoding, + LSDAPointerEncoding); CIEs[StartOffset] = Cie.get(); Entries.emplace_back(std::move(Cie)); } else { @@ -668,7 +678,6 @@ void DWARFDebugFrame::parse(DataExtractor Data) { } } - void DWARFDebugFrame::dump(raw_ostream &OS) const { OS << "\n"; for (const auto &Entry : Entries) { @@ -677,4 +686,3 @@ void DWARFDebugFrame::dump(raw_ostream &OS) const { OS << "\n"; } } - diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index 62d5e66..c487e1d 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -22,170 +22,17 @@ using namespace llvm; using namespace dwarf; using namespace syntax; -// Small helper to extract a DIE pointed by a reference -// attribute. It looks up the Unit containing the DIE and calls -// DIE.extractFast with the right unit. Returns new unit on success, -// nullptr otherwise. -static const DWARFUnit *findUnitAndExtractFast(DWARFDebugInfoEntryMinimal &DIE, - const DWARFUnit *Unit, - uint32_t *Offset) { - Unit = Unit->getUnitSection().getUnitForOffset(*Offset); - return (Unit && DIE.extractFast(Unit, Offset)) ? Unit : nullptr; -} - -void DWARFDebugInfoEntryMinimal::dump(raw_ostream &OS, DWARFUnit *u, - unsigned recurseDepth, - unsigned indent) const { - DataExtractor debug_info_data = u->getDebugInfoExtractor(); - uint32_t offset = Offset; - - if (debug_info_data.isValidOffset(offset)) { - uint32_t abbrCode = debug_info_data.getULEB128(&offset); - WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); - - if (abbrCode) { - if (AbbrevDecl) { - const char *tagString = TagString(getTag()); - if (tagString) - WithColor(OS, syntax::Tag).get().indent(indent) << tagString; - else - WithColor(OS, syntax::Tag).get().indent(indent) << - format("DW_TAG_Unknown_%x", getTag()); - - OS << format(" [%u] %c\n", abbrCode, - AbbrevDecl->hasChildren() ? '*' : ' '); - - // Dump all data in the DIE for the attributes. - for (const auto &AttrSpec : AbbrevDecl->attributes()) { - dumpAttribute(OS, u, &offset, AttrSpec.Attr, AttrSpec.Form, indent); - } - - const DWARFDebugInfoEntryMinimal *child = getFirstChild(); - if (recurseDepth > 0 && child) { - while (child) { - child->dump(OS, u, recurseDepth-1, indent+2); - child = child->getSibling(); - } - } - } else { - OS << "Abbreviation code not found in 'debug_abbrev' class for code: " - << abbrCode << '\n'; - } - } else { - OS.indent(indent) << "NULL\n"; - } - } -} - -static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { - OS << " ("; - do { - uint64_t Shift = countTrailingZeros(Val); - assert(Shift < 64 && "undefined behavior"); - uint64_t Bit = 1ULL << Shift; - if (const char *PropName = ApplePropertyString(Bit)) - OS << PropName; - else - OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit); - if (!(Val ^= Bit)) - break; - OS << ", "; - } while (true); - OS << ")"; -} - -static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges, - unsigned AddressSize, unsigned Indent) { - if (Ranges.empty()) - return; - - for (const auto &Range: Ranges) { - OS << '\n'; - OS.indent(Indent); - OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", - AddressSize*2, Range.first, - AddressSize*2, Range.second); - } -} - -void DWARFDebugInfoEntryMinimal::dumpAttribute(raw_ostream &OS, - DWARFUnit *u, - uint32_t *offset_ptr, - uint16_t attr, uint16_t form, - unsigned indent) const { - const char BaseIndent[] = " "; - OS << BaseIndent; - OS.indent(indent+2); - const char *attrString = AttributeString(attr); - if (attrString) - WithColor(OS, syntax::Attribute) << attrString; - else - WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", attr); - - const char *formString = FormEncodingString(form); - if (formString) - OS << " [" << formString << ']'; - else - OS << format(" [DW_FORM_Unknown_%x]", form); - - DWARFFormValue formValue(form); - - if (!formValue.extractValue(u->getDebugInfoExtractor(), offset_ptr, u)) - return; - - OS << "\t("; - - const char *Name = nullptr; - std::string File; - auto Color = syntax::Enumerator; - if (attr == DW_AT_decl_file || attr == DW_AT_call_file) { - Color = syntax::String; - if (const auto *LT = u->getContext().getLineTableForUnit(u)) - if (LT->getFileNameByIndex( - formValue.getAsUnsignedConstant().getValue(), - u->getCompilationDir(), - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { - File = '"' + File + '"'; - Name = File.c_str(); - } - } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) - Name = AttributeValueString(attr, *Val); - - if (Name) - WithColor(OS, Color) << Name; - else if (attr == DW_AT_decl_line || attr == DW_AT_call_line) - OS << *formValue.getAsUnsignedConstant(); - else - formValue.dump(OS, u); - - // We have dumped the attribute raw value. For some attributes - // having both the raw value and the pretty-printed value is - // interesting. These attributes are handled below. - if (attr == DW_AT_specification || attr == DW_AT_abstract_origin) { - Optional<uint64_t> Ref = formValue.getAsReference(u); - if (Ref.hasValue()) { - uint32_t RefOffset = Ref.getValue(); - DWARFDebugInfoEntryMinimal DIE; - if (const DWARFUnit *RefU = findUnitAndExtractFast(DIE, u, &RefOffset)) - if (const char *Name = DIE.getName(RefU, DINameKind::LinkageName)) - OS << " \"" << Name << '\"'; - } - } else if (attr == DW_AT_APPLE_property_attribute) { - if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) - dumpApplePropertyAttribute(OS, *OptVal); - } else if (attr == DW_AT_ranges) { - dumpRanges(OS, getAddressRanges(u), u->getAddressByteSize(), - sizeof(BaseIndent)+indent+4); - } - - OS << ")\n"; -} - -bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U, +bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr) { + DataExtractor DebugInfoData = U.getDebugInfoExtractor(); + 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) { Offset = *OffsetPtr; - DataExtractor DebugInfoData = U->getDebugInfoExtractor(); - uint32_t UEndOffset = U->getNextUnitOffset(); + Depth = D; if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset)) return false; uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); @@ -194,267 +41,32 @@ bool DWARFDebugInfoEntryMinimal::extractFast(const DWARFUnit *U, AbbrevDecl = nullptr; return true; } - AbbrevDecl = U->getAbbreviations()->getAbbreviationDeclaration(AbbrCode); + AbbrevDecl = U.getAbbreviations()->getAbbreviationDeclaration(AbbrCode); if (nullptr == AbbrevDecl) { // Restore the original offset. *OffsetPtr = Offset; return false; } - ArrayRef<uint8_t> FixedFormSizes = DWARFFormValue::getFixedFormSizes( - U->getAddressByteSize(), U->getVersion()); - assert(FixedFormSizes.size() > 0); + // See if all attributes in this DIE have fixed byte sizes. If so, we can + // just add this size to the offset to skip to the next DIE. + if (Optional<size_t> FixedSize = AbbrevDecl->getFixedAttributesByteSize(U)) { + *OffsetPtr += *FixedSize; + return true; + } // Skip all data in the .debug_info for the attributes for (const auto &AttrSpec : AbbrevDecl->attributes()) { - uint16_t Form = AttrSpec.Form; - - uint8_t FixedFormSize = - (Form < FixedFormSizes.size()) ? FixedFormSizes[Form] : 0; - if (FixedFormSize) - *OffsetPtr += FixedFormSize; - else if (!DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U)) { - // Restore the original offset. + // Check if this attribute has a fixed byte size. + if (auto FixedSize = AttrSpec.getByteSize(U)) { + // Attribute byte size if fixed, just add the size to the offset. + *OffsetPtr += *FixedSize; + } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData, + OffsetPtr, &U)) { + // We failed to skip this attribute's value, restore the original offset + // and return the failure status. *OffsetPtr = Offset; return false; } } return true; } - -bool DWARFDebugInfoEntryMinimal::isSubprogramDIE() const { - return getTag() == DW_TAG_subprogram; -} - -bool DWARFDebugInfoEntryMinimal::isSubroutineDIE() const { - uint32_t Tag = getTag(); - return Tag == DW_TAG_subprogram || - Tag == DW_TAG_inlined_subroutine; -} - -bool DWARFDebugInfoEntryMinimal::getAttributeValue( - const DWARFUnit *U, const uint16_t Attr, DWARFFormValue &FormValue) const { - if (!AbbrevDecl) - return false; - - uint32_t AttrIdx = AbbrevDecl->findAttributeIndex(Attr); - if (AttrIdx == -1U) - return false; - - DataExtractor DebugInfoData = U->getDebugInfoExtractor(); - uint32_t DebugInfoOffset = getOffset(); - - // Skip the abbreviation code so we are at the data for the attributes - DebugInfoData.getULEB128(&DebugInfoOffset); - - // Skip preceding attribute values. - for (uint32_t i = 0; i < AttrIdx; ++i) { - DWARFFormValue::skipValue(AbbrevDecl->getFormByIndex(i), - DebugInfoData, &DebugInfoOffset, U); - } - - FormValue = DWARFFormValue(AbbrevDecl->getFormByIndex(AttrIdx)); - return FormValue.extractValue(DebugInfoData, &DebugInfoOffset, U); -} - -const char *DWARFDebugInfoEntryMinimal::getAttributeValueAsString( - const DWARFUnit *U, const uint16_t Attr, const char *FailValue) const { - DWARFFormValue FormValue; - if (!getAttributeValue(U, Attr, FormValue)) - return FailValue; - Optional<const char *> Result = FormValue.getAsCString(U); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsAddress( - const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { - DWARFFormValue FormValue; - if (!getAttributeValue(U, Attr, FormValue)) - return FailValue; - Optional<uint64_t> Result = FormValue.getAsAddress(U); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsUnsignedConstant( - const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { - DWARFFormValue FormValue; - if (!getAttributeValue(U, Attr, FormValue)) - return FailValue; - Optional<uint64_t> Result = FormValue.getAsUnsignedConstant(); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsReference( - const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { - DWARFFormValue FormValue; - if (!getAttributeValue(U, Attr, FormValue)) - return FailValue; - Optional<uint64_t> Result = FormValue.getAsReference(U); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -uint64_t DWARFDebugInfoEntryMinimal::getAttributeValueAsSectionOffset( - const DWARFUnit *U, const uint16_t Attr, uint64_t FailValue) const { - DWARFFormValue FormValue; - if (!getAttributeValue(U, Attr, FormValue)) - return FailValue; - Optional<uint64_t> Result = FormValue.getAsSectionOffset(); - return Result.hasValue() ? Result.getValue() : FailValue; -} - -uint64_t -DWARFDebugInfoEntryMinimal::getRangesBaseAttribute(const DWARFUnit *U, - uint64_t FailValue) const { - uint64_t Result = - getAttributeValueAsSectionOffset(U, DW_AT_ranges_base, -1ULL); - if (Result != -1ULL) - return Result; - return getAttributeValueAsSectionOffset(U, DW_AT_GNU_ranges_base, FailValue); -} - -bool DWARFDebugInfoEntryMinimal::getLowAndHighPC(const DWARFUnit *U, - uint64_t &LowPC, - uint64_t &HighPC) const { - LowPC = getAttributeValueAsAddress(U, DW_AT_low_pc, -1ULL); - if (LowPC == -1ULL) - return false; - HighPC = getAttributeValueAsAddress(U, DW_AT_high_pc, -1ULL); - if (HighPC == -1ULL) { - // Since DWARF4, DW_AT_high_pc may also be of class constant, in which case - // it represents function size. - HighPC = getAttributeValueAsUnsignedConstant(U, DW_AT_high_pc, -1ULL); - if (HighPC != -1ULL) - HighPC += LowPC; - } - return (HighPC != -1ULL); -} - -DWARFAddressRangesVector -DWARFDebugInfoEntryMinimal::getAddressRanges(const DWARFUnit *U) const { - if (isNULL()) - return DWARFAddressRangesVector(); - // Single range specified by low/high PC. - uint64_t LowPC, HighPC; - if (getLowAndHighPC(U, LowPC, HighPC)) { - return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC)); - } - // Multiple ranges from .debug_ranges section. - uint32_t RangesOffset = - getAttributeValueAsSectionOffset(U, DW_AT_ranges, -1U); - if (RangesOffset != -1U) { - DWARFDebugRangeList RangeList; - if (U->extractRangeList(RangesOffset, RangeList)) - return RangeList.getAbsoluteRanges(U->getBaseAddress()); - } - return DWARFAddressRangesVector(); -} - -void DWARFDebugInfoEntryMinimal::collectChildrenAddressRanges( - const DWARFUnit *U, DWARFAddressRangesVector& Ranges) const { - if (isNULL()) - return; - if (isSubprogramDIE()) { - const auto &DIERanges = getAddressRanges(U); - Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end()); - } - - const DWARFDebugInfoEntryMinimal *Child = getFirstChild(); - while (Child) { - Child->collectChildrenAddressRanges(U, Ranges); - Child = Child->getSibling(); - } -} - -bool DWARFDebugInfoEntryMinimal::addressRangeContainsAddress( - const DWARFUnit *U, const uint64_t Address) const { - for (const auto& R : getAddressRanges(U)) { - if (R.first <= Address && Address < R.second) - return true; - } - return false; -} - -const char * -DWARFDebugInfoEntryMinimal::getSubroutineName(const DWARFUnit *U, - DINameKind Kind) const { - if (!isSubroutineDIE()) - return nullptr; - return getName(U, Kind); -} - -const char * -DWARFDebugInfoEntryMinimal::getName(const DWARFUnit *U, - DINameKind Kind) const { - if (Kind == DINameKind::None) - return nullptr; - // Try to get mangled name only if it was asked for. - if (Kind == DINameKind::LinkageName) { - if (const char *name = - getAttributeValueAsString(U, DW_AT_MIPS_linkage_name, nullptr)) - return name; - if (const char *name = - getAttributeValueAsString(U, DW_AT_linkage_name, nullptr)) - return name; - } - if (const char *name = getAttributeValueAsString(U, DW_AT_name, nullptr)) - return name; - // Try to get name from specification DIE. - uint32_t spec_ref = - getAttributeValueAsReference(U, DW_AT_specification, -1U); - if (spec_ref != -1U) { - DWARFDebugInfoEntryMinimal spec_die; - if (const DWARFUnit *RefU = findUnitAndExtractFast(spec_die, U, &spec_ref)) { - if (const char *name = spec_die.getName(RefU, Kind)) - return name; - } - } - // Try to get name from abstract origin DIE. - uint32_t abs_origin_ref = - getAttributeValueAsReference(U, DW_AT_abstract_origin, -1U); - if (abs_origin_ref != -1U) { - DWARFDebugInfoEntryMinimal abs_origin_die; - if (const DWARFUnit *RefU = findUnitAndExtractFast(abs_origin_die, U, - &abs_origin_ref)) { - if (const char *name = abs_origin_die.getName(RefU, Kind)) - return name; - } - } - return nullptr; -} - -void DWARFDebugInfoEntryMinimal::getCallerFrame(const DWARFUnit *U, - uint32_t &CallFile, - uint32_t &CallLine, - uint32_t &CallColumn) const { - CallFile = getAttributeValueAsUnsignedConstant(U, DW_AT_call_file, 0); - CallLine = getAttributeValueAsUnsignedConstant(U, DW_AT_call_line, 0); - CallColumn = getAttributeValueAsUnsignedConstant(U, DW_AT_call_column, 0); -} - -DWARFDebugInfoEntryInlinedChain -DWARFDebugInfoEntryMinimal::getInlinedChainForAddress( - const DWARFUnit *U, const uint64_t Address) const { - DWARFDebugInfoEntryInlinedChain InlinedChain; - InlinedChain.U = U; - if (isNULL()) - return InlinedChain; - for (const DWARFDebugInfoEntryMinimal *DIE = this; DIE; ) { - // Append current DIE to inlined chain only if it has correct tag - // (e.g. it is not a lexical block). - if (DIE->isSubroutineDIE()) { - InlinedChain.DIEs.push_back(*DIE); - } - // Try to get child which also contains provided address. - const DWARFDebugInfoEntryMinimal *Child = DIE->getFirstChild(); - while (Child) { - if (Child->addressRangeContainsAddress(U, Address)) { - // Assume there is only one such child. - break; - } - Child = Child->getSibling(); - } - DIE = Child; - } - // Reverse the obtained chain to make the root of inlined chain last. - std::reverse(InlinedChain.DIEs.begin(), InlinedChain.DIEs.end()); - return InlinedChain; -} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index 30cb833..4940594 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -42,8 +42,8 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { << format(" opcode_base: %u\n", OpcodeBase); for (uint32_t i = 0; i < StandardOpcodeLengths.size(); ++i) - OS << format("standard_opcode_lengths[%s] = %u\n", LNStandardString(i + 1), - StandardOpcodeLengths[i]); + OS << format("standard_opcode_lengths[%s] = %u\n", + LNStandardString(i + 1).data(), StandardOpcodeLengths[i]); if (!IncludeDirectories.empty()) for (uint32_t i = 0; i < IncludeDirectories.size(); ++i) @@ -624,12 +624,17 @@ bool DWARFDebugLine::LineTable::lookupAddressRange( return true; } -bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, - const char *CompDir, - FileLineInfoKind Kind, - std::string &Result) const { - if (FileIndex == 0 || FileIndex > Prologue.FileNames.size() || - Kind == FileLineInfoKind::None) +bool +DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const { + return FileIndex != 0 && FileIndex <= Prologue.FileNames.size(); +} + +bool +DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex, + const char *CompDir, + FileLineInfoKind Kind, + std::string &Result) const { + if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) return false; const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1]; const char *FileName = Entry.Name; @@ -673,5 +678,6 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress( return false; Result.Line = Row.Line; Result.Column = Row.Column; + Result.Discriminator = Row.Discriminator; return true; } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index a7b46b8..ae5b9d7 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -82,9 +82,9 @@ void DWARFDebugLocDWO::parse(DataExtractor data) { Loc.Offset = Offset; dwarf::LocationListEntry Kind; while ((Kind = static_cast<dwarf::LocationListEntry>( - data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list_entry) { + data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) { - if (Kind != dwarf::DW_LLE_start_length_entry) { + if (Kind != dwarf::DW_LLE_startx_length) { llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind << " not implemented\n"; return; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp new file mode 100644 index 0000000..3c1fe93 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -0,0 +1,65 @@ +//===-- DWARFDebugPubTable.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::dwarf; + +DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian, + bool GnuStyle) + : GnuStyle(GnuStyle) { + DataExtractor PubNames(Data, LittleEndian, 0); + uint32_t Offset = 0; + while (PubNames.isValidOffset(Offset)) { + Sets.push_back({}); + Set &SetData = Sets.back(); + + SetData.Length = PubNames.getU32(&Offset); + SetData.Version = PubNames.getU16(&Offset); + SetData.Offset = PubNames.getU32(&Offset); + SetData.Size = PubNames.getU32(&Offset); + + while (Offset < Data.size()) { + uint32_t DieRef = PubNames.getU32(&Offset); + if (DieRef == 0) + break; + uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0; + const char *Name = PubNames.getCStr(&Offset); + SetData.Entries.push_back( + {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name}); + } + } +} + +void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const { + OS << "\n." << Name << " contents: a\n"; + for (const Set &S : Sets) { + OS << "length = " << format("0x%08x", S.Length); + OS << " version = " << format("0x%04x", S.Version); + OS << " unit_offset = " << format("0x%08x", S.Offset); + OS << " unit_size = " << format("0x%08x", S.Size) << '\n'; + OS << (GnuStyle ? "Offset Linkage Kind Name\n" + : "Offset Name\n"); + + for (const Entry &E : S.Entries) { + OS << format("0x%8.8x ", E.SecOffset); + if (GnuStyle) { + StringRef EntryLinkage = + dwarf::GDBIndexEntryLinkageString(E.Descriptor.Linkage); + StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind); + OS << format("%-8s", EntryLinkage.data()) << ' ' + << format("%-8s", EntryKind.data()) << ' '; + } + OS << '\"' << E.Name << "\"\n"; + } + } +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp new file mode 100644 index 0000000..89b83b1 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -0,0 +1,401 @@ +//===-- DWARFDie.cpp ------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "SyntaxHighlighting.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.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" + +using namespace llvm; +using namespace dwarf; +using namespace syntax; + +namespace { + static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) { + OS << " ("; + do { + uint64_t Shift = countTrailingZeros(Val); + assert(Shift < 64 && "undefined behavior"); + uint64_t Bit = 1ULL << Shift; + auto PropName = ApplePropertyString(Bit); + if (!PropName.empty()) + OS << PropName; + else + OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit); + if (!(Val ^= Bit)) + break; + OS << ", "; + } while (true); + OS << ")"; +} + +static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges, + unsigned AddressSize, unsigned Indent) { + if (Ranges.empty()) + return; + + for (const auto &Range: Ranges) { + OS << '\n'; + OS.indent(Indent); + OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", + AddressSize*2, Range.first, + AddressSize*2, Range.second); + } +} + +static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, + uint32_t *OffsetPtr, dwarf::Attribute Attr, + dwarf::Form Form, unsigned Indent) { + if (!Die.isValid()) + return; + const char BaseIndent[] = " "; + OS << BaseIndent; + OS.indent(Indent+2); + auto attrString = AttributeString(Attr); + if (!attrString.empty()) + WithColor(OS, syntax::Attribute) << attrString; + else + WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr); + + auto formString = FormEncodingString(Form); + if (!formString.empty()) + OS << " [" << formString << ']'; + else + OS << format(" [DW_FORM_Unknown_%x]", Form); + + DWARFUnit *U = Die.getDwarfUnit(); + DWARFFormValue formValue(Form); + + if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U)) + return; + + OS << "\t("; + + StringRef Name; + std::string File; + auto Color = syntax::Enumerator; + if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { + Color = syntax::String; + if (const auto *LT = U->getContext().getLineTableForUnit(U)) + if (LT->getFileNameByIndex(formValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) { + File = '"' + File + '"'; + Name = File; + } + } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant()) + Name = AttributeValueString(Attr, *Val); + + if (!Name.empty()) + WithColor(OS, Color) << Name; + else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) + OS << *formValue.getAsUnsignedConstant(); + else + formValue.dump(OS); + + // We have dumped the attribute raw value. For some attributes + // having both the raw value and the pretty-printed value is + // interesting. These attributes are handled below. + if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) { + if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName(DINameKind::LinkageName)) + OS << " \"" << Name << '\"'; + } else if (Attr == DW_AT_APPLE_property_attribute) { + if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant()) + dumpApplePropertyAttribute(OS, *OptVal); + } else if (Attr == DW_AT_ranges) { + dumpRanges(OS, Die.getAddressRanges(), U->getAddressByteSize(), + sizeof(BaseIndent)+Indent+4); + } + + OS << ")\n"; +} + +} // end anonymous namespace + +bool DWARFDie::isSubprogramDIE() const { + return getTag() == DW_TAG_subprogram; +} + +bool DWARFDie::isSubroutineDIE() const { + auto Tag = getTag(); + return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine; +} + +Optional<DWARFFormValue> +DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { + if (!isValid()) + return None; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) + return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U); + 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(); + return None; +} + +Optional<uint64_t> +DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const { + if (auto FormValue = getAttributeValue(Attr)) + return FormValue->getAsSectionOffset(); + return None; +} + + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { + auto SpecRef = getAttributeValueAsReference(Attr); + if (SpecRef) { + auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef); + if (SpecUnit) + return SpecUnit->getDIEForOffset(*SpecRef); + } + return DWARFDie(); +} + +Optional<uint64_t> +DWARFDie::getRangesBaseAttribute() const { + auto Result = getAttributeValueAsSectionOffset(DW_AT_rnglists_base); + if (Result) + return Result; + return getAttributeValueAsSectionOffset(DW_AT_GNU_ranges_base); +} + +Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { + if (auto FormValue = getAttributeValue(DW_AT_high_pc)) { + if (auto Address = FormValue->getAsAddress()) { + // High PC is an address. + return Address; + } + if (auto Offset = FormValue->getAsUnsignedConstant()) { + // High PC is an offset from LowPC. + return LowPC + *Offset; + } + } + return None; +} + +bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC) const { + auto LowPcAddr = getAttributeValueAsAddress(DW_AT_low_pc); + if (!LowPcAddr) + return false; + if (auto HighPcAddr = getHighPC(*LowPcAddr)) { + LowPC = *LowPcAddr; + HighPC = *HighPcAddr; + return true; + } + return false; +} + +DWARFAddressRangesVector +DWARFDie::getAddressRanges() const { + if (isNULL()) + return DWARFAddressRangesVector(); + // Single range specified by low/high PC. + uint64_t LowPC, HighPC; + if (getLowAndHighPC(LowPC, HighPC)) { + return DWARFAddressRangesVector(1, std::make_pair(LowPC, HighPC)); + } + // Multiple ranges from .debug_ranges section. + auto RangesOffset = getAttributeValueAsSectionOffset(DW_AT_ranges); + if (RangesOffset) { + DWARFDebugRangeList RangeList; + if (U->extractRangeList(*RangesOffset, RangeList)) + return RangeList.getAbsoluteRanges(U->getBaseAddress()); + } + return DWARFAddressRangesVector(); +} + +void +DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const { + if (isNULL()) + return; + if (isSubprogramDIE()) { + const auto &DIERanges = getAddressRanges(); + Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end()); + } + + for (auto Child: children()) + Child.collectChildrenAddressRanges(Ranges); +} + +bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { + for (const auto& R : getAddressRanges()) { + if (R.first <= Address && Address < R.second) + return true; + } + return false; +} + +const char * +DWARFDie::getSubroutineName(DINameKind Kind) const { + if (!isSubroutineDIE()) + return nullptr; + return getName(Kind); +} + +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 ((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; + return nullptr; +} + +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); +} + +void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, + unsigned Indent) const { + if (!isValid()) + return; + DataExtractor debug_info_data = U->getDebugInfoExtractor(); + const uint32_t Offset = getOffset(); + uint32_t offset = Offset; + + if (debug_info_data.isValidOffset(offset)) { + uint32_t abbrCode = debug_info_data.getULEB128(&offset); + WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset); + + if (abbrCode) { + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + auto tagString = TagString(getTag()); + if (!tagString.empty()) + WithColor(OS, syntax::Tag).get().indent(Indent) << tagString; + else + WithColor(OS, syntax::Tag).get().indent(Indent) + << format("DW_TAG_Unknown_%x", getTag()); + + OS << format(" [%u] %c\n", abbrCode, + AbbrevDecl->hasChildren() ? '*' : ' '); + + // Dump all data in the DIE for the attributes. + for (const auto &AttrSpec : AbbrevDecl->attributes()) { + dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form, + Indent); + } + + DWARFDie child = getFirstChild(); + if (RecurseDepth > 0 && child) { + while (child) { + child.dump(OS, RecurseDepth-1, Indent+2); + child = child.getSibling(); + } + } + } else { + OS << "Abbreviation code not found in 'debug_abbrev' class for code: " + << abbrCode << '\n'; + } + } else { + OS.indent(Indent) << "NULL\n"; + } + } +} + + +void DWARFDie::getInlinedChainForAddress( + const uint64_t Address, SmallVectorImpl<DWARFDie> &InlinedChain) const { + if (isNULL()) + return; + DWARFDie DIE(*this); + while (DIE) { + // Append current DIE to inlined chain only if it has correct tag + // (e.g. it is not a lexical block). + if (DIE.isSubroutineDIE()) + InlinedChain.push_back(DIE); + + // Try to get child which also contains provided address. + DWARFDie Child = DIE.getFirstChild(); + while (Child) { + if (Child.addressRangeContainsAddress(Address)) { + // Assume there is only one such child. + break; + } + Child = Child.getSibling(); + } + DIE = Child; + } + // Reverse the obtained chain to make the root of inlined chain last. + std::reverse(InlinedChain.begin(), InlinedChain.end()); +} + +DWARFDie DWARFDie::getParent() const { + if (isValid()) + return U->getParent(Die); + return DWARFDie(); +} + +DWARFDie DWARFDie::getSibling() const { + if (isValid()) + return U->getSibling(Die); + return DWARFDie(); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 3dc5842..dc9310d 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -23,60 +23,6 @@ using namespace llvm; using namespace dwarf; using namespace syntax; -namespace { -uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) { - // FIXME: Support DWARF64. - return (Version == 2) ? AddrSize : 4; -} - -template <uint8_t AddrSize, uint8_t RefAddrSize> -ArrayRef<uint8_t> makeFixedFormSizesArrayRef() { - static const uint8_t sizes[] = { - 0, // 0x00 unused - AddrSize, // 0x01 DW_FORM_addr - 0, // 0x02 unused - 0, // 0x03 DW_FORM_block2 - 0, // 0x04 DW_FORM_block4 - 2, // 0x05 DW_FORM_data2 - 4, // 0x06 DW_FORM_data4 - 8, // 0x07 DW_FORM_data8 - 0, // 0x08 DW_FORM_string - 0, // 0x09 DW_FORM_block - 0, // 0x0a DW_FORM_block1 - 1, // 0x0b DW_FORM_data1 - 1, // 0x0c DW_FORM_flag - 0, // 0x0d DW_FORM_sdata - 4, // 0x0e DW_FORM_strp - 0, // 0x0f DW_FORM_udata - RefAddrSize, // 0x10 DW_FORM_ref_addr - 1, // 0x11 DW_FORM_ref1 - 2, // 0x12 DW_FORM_ref2 - 4, // 0x13 DW_FORM_ref4 - 8, // 0x14 DW_FORM_ref8 - 0, // 0x15 DW_FORM_ref_udata - 0, // 0x16 DW_FORM_indirect - 4, // 0x17 DW_FORM_sec_offset - 0, // 0x18 DW_FORM_exprloc - 0, // 0x19 DW_FORM_flag_present - }; - return makeArrayRef(sizes); -} -} - -ArrayRef<uint8_t> DWARFFormValue::getFixedFormSizes(uint8_t AddrSize, - uint16_t Version) { - uint8_t RefAddrSize = getRefAddrSize(AddrSize, Version); - if (AddrSize == 4 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<4, 4>(); - if (AddrSize == 4 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<4, 8>(); - if (AddrSize == 8 && RefAddrSize == 4) - return makeFixedFormSizesArrayRef<8, 4>(); - if (AddrSize == 8 && RefAddrSize == 8) - return makeFixedFormSizesArrayRef<8, 8>(); - return None; -} - static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Unknown, // 0x0 DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr @@ -108,6 +54,217 @@ static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; +namespace { + +/// A helper class that can be used in DWARFFormValue.cpp functions that need +/// to know the byte size of DW_FORM values that vary in size depending on the +/// DWARF version, address byte size, or DWARF32 or DWARF64. +class FormSizeHelper { + uint16_t Version; + uint8_t AddrSize; + llvm::dwarf::DwarfFormat Format; + +public: + FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat 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: + return 4; + case dwarf::DwarfFormat::DWARF64: + return 8; + } + llvm_unreachable("Invalid Format value"); + } +}; + +} // end anonymous namespace + +template <class T> +static Optional<uint8_t> getFixedByteSize(dwarf::Form Form, const T *U) { + switch (Form) { + case DW_FORM_addr: + if (U) + return U->getAddressByteSize(); + return None; + + case DW_FORM_block: // ULEB128 length L followed by L bytes. + case DW_FORM_block1: // 1 byte length L followed by L bytes. + case DW_FORM_block2: // 2 byte length L followed by L bytes. + case DW_FORM_block4: // 4 byte length L followed by L bytes. + case DW_FORM_string: // C-string with null terminator. + case DW_FORM_sdata: // SLEB128. + case DW_FORM_udata: // ULEB128. + case DW_FORM_ref_udata: // ULEB128. + case DW_FORM_indirect: // ULEB128. + case DW_FORM_exprloc: // ULEB128 length L followed by L bytes. + case DW_FORM_strx: // ULEB128. + case DW_FORM_addrx: // ULEB128. + case DW_FORM_loclistx: // ULEB128. + case DW_FORM_rnglistx: // ULEB128. + case DW_FORM_GNU_addr_index: // ULEB128. + case DW_FORM_GNU_str_index: // ULEB128. + return None; + + case DW_FORM_ref_addr: + if (U) + return U->getRefAddrByteSize(); + return None; + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_ref1: + return 1; + + case DW_FORM_data2: + case DW_FORM_ref2: + return 2; + + case DW_FORM_data4: + case DW_FORM_ref4: + return 4; + + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + 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; + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return 8; + + case DW_FORM_flag_present: + return 0; + + case DW_FORM_data16: + return 16; + + case DW_FORM_implicit_const: + // The implicit value is stored in the abbreviation as a SLEB128, and + // there no data in debug info. + return 0; + + default: + llvm_unreachable("Handle this form in this switch statement"); + } + return None; +} + +template <class T> +static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, + uint32_t *OffsetPtr, const T *U) { + bool Indirect = false; + do { + switch (Form) { + // Blocks of inlined data that have a length field and the data bytes + // inlined in the .debug_info. + case DW_FORM_exprloc: + case DW_FORM_block: { + uint64_t size = DebugInfoData.getULEB128(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block1: { + uint8_t size = DebugInfoData.getU8(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block2: { + uint16_t size = DebugInfoData.getU16(OffsetPtr); + *OffsetPtr += size; + return true; + } + case DW_FORM_block4: { + uint32_t size = DebugInfoData.getU32(OffsetPtr); + *OffsetPtr += size; + return true; + } + + // Inlined NULL terminated C-strings. + case DW_FORM_string: + DebugInfoData.getCStr(OffsetPtr); + return true; + + case DW_FORM_addr: + case DW_FORM_ref_addr: + case DW_FORM_flag_present: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_ref_sup: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_strp_sup: + case DW_FORM_line_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + if (Optional<uint8_t> FixedSize = ::getFixedByteSize(Form, U)) { + *OffsetPtr += *FixedSize; + return true; + } + return false; + + // signed or unsigned LEB 128 values. + case DW_FORM_sdata: + DebugInfoData.getSLEB128(OffsetPtr); + return true; + + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_strx: + case DW_FORM_addrx: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + DebugInfoData.getULEB128(OffsetPtr); + return true; + + case DW_FORM_indirect: + Indirect = true; + Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr)); + break; + + default: + return false; + } + } while (Indirect); + return true; +} + +Optional<uint8_t> DWARFFormValue::getFixedByteSize(dwarf::Form Form, + const DWARFUnit *U) { + return ::getFixedByteSize(Form, U); +} + +Optional<uint8_t> +DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return ::getFixedByteSize(Form, &FSH); +} + bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -123,6 +280,10 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: return (FC == FC_String); + case DW_FORM_implicit_const: + return (FC == FC_Constant); + default: + break; } // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset. // Don't check for DWARF version here, as some producers may still do this @@ -131,8 +292,10 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { FC == FC_SectionOffset; } -bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, +bool DWARFFormValue::extractValue(const DataExtractor &data, + uint32_t *offset_ptr, const DWARFUnit *cu) { + U = cu; bool indirect = false; bool is_block = false; Value.data = nullptr; @@ -143,16 +306,15 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, switch (Form) { case DW_FORM_addr: case DW_FORM_ref_addr: { - if (!cu) + if (!U) return false; uint16_t AddrSize = (Form == DW_FORM_addr) - ? cu->getAddressByteSize() - : getRefAddrSize(cu->getAddressByteSize(), cu->getVersion()); - RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr); - if (AI != cu->getRelocMap()->end()) { - const std::pair<uint8_t, int64_t> &R = AI->second; - Value.uval = data.getUnsigned(offset_ptr, AddrSize) + R.second; + ? U->getAddressByteSize() + : U->getRefAddrByteSize(); + RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); + if (AI != U->getRelocMap()->end()) { + Value.uval = data.getUnsigned(offset_ptr, AddrSize) + AI->second.second; } else Value.uval = data.getUnsigned(offset_ptr, AddrSize); break; @@ -186,10 +348,10 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, case DW_FORM_data4: case DW_FORM_ref4: { Value.uval = data.getU32(offset_ptr); - if (!cu) + if (!U) break; - RelocAddrMap::const_iterator AI = cu->getRelocMap()->find(*offset_ptr-4); - if (AI != cu->getRelocMap()->end()) + RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr-4); + if (AI != U->getRelocMap()->end()) Value.uval += AI->second.second; break; } @@ -208,20 +370,22 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, Value.cstr = data.getCStr(offset_ptr); break; case DW_FORM_indirect: - Form = data.getULEB128(offset_ptr); + Form = static_cast<dwarf::Form>(data.getULEB128(offset_ptr)); indirect = true; break; - case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_sec_offset: case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: { - // FIXME: This is 64-bit for DWARF64. - Value.uval = data.getU32(offset_ptr); - if (!cu) - break; - RelocAddrMap::const_iterator AI = - cu->getRelocMap()->find(*offset_ptr - 4); - if (AI != cu->getRelocMap()->end()) + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: + case DW_FORM_ref_sup: { + if (!U) + return false; + RelocAddrMap::const_iterator AI = U->getRelocMap()->find(*offset_ptr); + uint8_t Size = U->getDwarfOffsetByteSize(); + Value.uval = data.getUnsigned(offset_ptr, Size); + if (AI != U->getRelocMap()->end()) Value.uval += AI->second.second; break; } @@ -252,123 +416,26 @@ bool DWARFFormValue::extractValue(DataExtractor data, uint32_t *offset_ptr, return true; } -bool -DWARFFormValue::skipValue(DataExtractor debug_info_data, uint32_t* offset_ptr, - const DWARFUnit *cu) const { - return DWARFFormValue::skipValue(Form, debug_info_data, offset_ptr, cu); +bool DWARFFormValue::skipValue(DataExtractor DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) const { + return DWARFFormValue::skipValue(Form, DebugInfoData, offset_ptr, U); } -bool -DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, - uint32_t *offset_ptr, const DWARFUnit *cu) { - return skipValue(form, debug_info_data, offset_ptr, cu->getVersion(), - cu->getAddressByteSize()); +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, + uint32_t *offset_ptr, const DWARFUnit *U) { + return skipFormValue(form, DebugInfoData, offset_ptr, U); } -bool DWARFFormValue::skipValue(uint16_t form, DataExtractor debug_info_data, - uint32_t *offset_ptr, uint16_t Version, - uint8_t AddrSize) { - bool indirect = false; - do { - switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info - case DW_FORM_exprloc: - case DW_FORM_block: { - uint64_t size = debug_info_data.getULEB128(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block1: { - uint8_t size = debug_info_data.getU8(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block2: { - uint16_t size = debug_info_data.getU16(offset_ptr); - *offset_ptr += size; - return true; - } - case DW_FORM_block4: { - uint32_t size = debug_info_data.getU32(offset_ptr); - *offset_ptr += size; - return true; - } - - // Inlined NULL terminated C-strings - case DW_FORM_string: - debug_info_data.getCStr(offset_ptr); - return true; - - // Compile unit address sized values - case DW_FORM_addr: - *offset_ptr += AddrSize; - return true; - case DW_FORM_ref_addr: - *offset_ptr += getRefAddrSize(AddrSize, Version); - return true; - - // 0 byte values - implied from the form. - case DW_FORM_flag_present: - return true; - - // 1 byte values - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - *offset_ptr += 1; - return true; - - // 2 byte values - case DW_FORM_data2: - case DW_FORM_ref2: - *offset_ptr += 2; - return true; - - // 4 byte values - case DW_FORM_data4: - case DW_FORM_ref4: - *offset_ptr += 4; - return true; - // 8 byte values - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - *offset_ptr += 8; - return true; - - // signed or unsigned LEB 128 values - // case DW_FORM_APPLE_db_str: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: - debug_info_data.getULEB128(offset_ptr); - return true; - - case DW_FORM_indirect: - indirect = true; - form = debug_info_data.getULEB128(offset_ptr); - break; - - // FIXME: 4 for DWARF32, 8 for DWARF64. - case DW_FORM_sec_offset: - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - *offset_ptr += 4; - return true; - - default: - return false; - } - } while (indirect); - return true; +bool DWARFFormValue::skipValue(dwarf::Form form, DataExtractor DebugInfoData, + uint32_t *offset_ptr, uint16_t Version, + uint8_t AddrSize, + llvm::dwarf::DwarfFormat Format) { + FormSizeHelper FSH(Version, AddrSize, Format); + return skipFormValue(form, DebugInfoData, offset_ptr, &FSH); } void -DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { +DWARFFormValue::dump(raw_ostream &OS) const { uint64_t uvalue = Value.uval; bool cu_relative_offset = false; @@ -377,7 +444,9 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { case DW_FORM_GNU_addr_index: { OS << format(" indexed (%8.8x) address = ", (uint32_t)uvalue); uint64_t Address; - if (cu->getAddrOffsetSectionItem(uvalue, Address)) + if (U == nullptr) + OS << "<invalid dwarf unit>"; + else if (U->getAddrOffsetSectionItem(uvalue, Address)) OS << format("0x%016" PRIx64, Address); else OS << "<no .debug_addr section>"; @@ -428,17 +497,17 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { case DW_FORM_udata: OS << Value.uval; break; case DW_FORM_strp: { OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue); - dumpString(OS, cu); + dumpString(OS); break; } case DW_FORM_GNU_str_index: { OS << format(" indexed (%8.8x) string = ", (uint32_t)uvalue); - dumpString(OS, cu); + dumpString(OS); break; } case DW_FORM_GNU_strp_alt: { OS << format("alt indirect string, offset: 0x%" PRIx64 "", uvalue); - dumpString(OS, cu); + dumpString(OS); break; } case DW_FORM_ref_addr: @@ -487,13 +556,13 @@ DWARFFormValue::dump(raw_ostream &OS, const DWARFUnit *cu) const { if (cu_relative_offset) { OS << " => {"; WithColor(OS, syntax::Address).get() - << format("0x%8.8" PRIx64, uvalue + (cu ? cu->getOffset() : 0)); + << format("0x%8.8" PRIx64, uvalue + (U ? U->getOffset() : 0)); OS << "}"; } } -void DWARFFormValue::dumpString(raw_ostream &OS, const DWARFUnit *U) const { - Optional<const char *> DbgStr = getAsCString(U); +void DWARFFormValue::dumpString(raw_ostream &OS) const { + Optional<const char *> DbgStr = getAsCString(); if (DbgStr.hasValue()) { raw_ostream &COS = WithColor(OS, syntax::String); COS << '"'; @@ -502,7 +571,7 @@ void DWARFFormValue::dumpString(raw_ostream &OS, const DWARFUnit *U) const { } } -Optional<const char *> DWARFFormValue::getAsCString(const DWARFUnit *U) const { +Optional<const char *> DWARFFormValue::getAsCString() const { if (!isFormClass(FC_String)) return None; if (Form == DW_FORM_string) @@ -523,7 +592,7 @@ Optional<const char *> DWARFFormValue::getAsCString(const DWARFUnit *U) const { return None; } -Optional<uint64_t> DWARFFormValue::getAsAddress(const DWARFUnit *U) const { +Optional<uint64_t> DWARFFormValue::getAsAddress() const { if (!isFormClass(FC_Address)) return None; if (Form == DW_FORM_GNU_addr_index) { @@ -536,7 +605,7 @@ Optional<uint64_t> DWARFFormValue::getAsAddress(const DWARFUnit *U) const { return Value.uval; } -Optional<uint64_t> DWARFFormValue::getAsReference(const DWARFUnit *U) const { +Optional<uint64_t> DWARFFormValue::getAsReference() const { if (!isFormClass(FC_Reference)) return None; switch (Form) { @@ -549,8 +618,9 @@ Optional<uint64_t> DWARFFormValue::getAsReference(const DWARFUnit *U) const { return None; return Value.uval + U->getOffset(); case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: return Value.uval; - // FIXME: Add proper support for DW_FORM_ref_sig8 and DW_FORM_GNU_ref_alt. default: return None; } @@ -593,3 +663,15 @@ Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { return makeArrayRef(Value.data, Value.uval); } +Optional<uint64_t> DWARFFormValue::getAsCStringOffset() const { + if (!isFormClass(FC_String) && Form == DW_FORM_string) + return None; + return Value.uval; +} + +Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const { + if (!isFormClass(FC_Reference)) + return None; + return Value.uval; +} + diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp new file mode 100644 index 0000000..ebb9961 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp @@ -0,0 +1,176 @@ +//===-- DWARFGdbIndex.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +// .gdb_index section format reference: +// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html + +void DWARFGdbIndex::dumpCUList(raw_ostream &OS) const { + OS << format("\n CU list offset = 0x%x, has %" PRId64 " entries:", + CuListOffset, (uint64_t)CuList.size()) + << '\n'; + uint32_t I = 0; + for (const CompUnitEntry &CU : CuList) + OS << format(" %d: Offset = 0x%llx, Length = 0x%llx\n", I++, CU.Offset, + CU.Length); +} + +void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const { + OS << format("\n Address area offset = 0x%x, has %" PRId64 " entries:", + AddressAreaOffset, (uint64_t)AddressArea.size()) + << '\n'; + for (const AddressEntry &Addr : AddressArea) + OS << format( + " Low address = 0x%llx, High address = 0x%llx, CU index = %d\n", + Addr.LowAddress, Addr.HighAddress, Addr.CuIndex); +} + +void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const { + OS << format("\n Symbol table offset = 0x%x, size = %" PRId64 + ", filled slots:", + SymbolTableOffset, (uint64_t)SymbolTable.size()) + << '\n'; + uint32_t I = -1; + for (const SymTableEntry &E : SymbolTable) { + ++I; + if (!E.NameOffset && !E.VecOffset) + continue; + + OS << format(" %d: Name offset = 0x%x, CU vector offset = 0x%x\n", I, + E.NameOffset, E.VecOffset); + + StringRef Name = ConstantPoolStrings.substr( + ConstantPoolOffset - StringPoolOffset + E.NameOffset); + + auto CuVector = std::find_if( + ConstantPoolVectors.begin(), ConstantPoolVectors.end(), + [&](const std::pair<uint32_t, SmallVector<uint32_t, 0>> &V) { + return V.first == E.VecOffset; + }); + assert(CuVector != ConstantPoolVectors.end() && "Invalid symbol table"); + uint32_t CuVectorId = CuVector - ConstantPoolVectors.begin(); + OS << format(" String name: %s, CU vector index: %d\n", Name.data(), + CuVectorId); + } +} + +void DWARFGdbIndex::dumpConstantPool(raw_ostream &OS) const { + OS << format("\n Constant pool offset = 0x%x, has %" PRId64 " CU vectors:", + ConstantPoolOffset, (uint64_t)ConstantPoolVectors.size()); + uint32_t I = 0; + for (const auto &V : ConstantPoolVectors) { + OS << format("\n %d(0x%x): ", I++, V.first); + for (uint32_t Val : V.second) + OS << format("0x%x ", Val); + } + OS << '\n'; +} + +void DWARFGdbIndex::dump(raw_ostream &OS) { + if (HasError) { + OS << "\n<error parsing>\n"; + return; + } + + if (HasContent) { + OS << " Version = " << Version << '\n'; + dumpCUList(OS); + dumpAddressArea(OS); + dumpSymbolTable(OS); + dumpConstantPool(OS); + } +} + +bool DWARFGdbIndex::parseImpl(DataExtractor Data) { + uint32_t Offset = 0; + + // Only version 7 is supported at this moment. + Version = Data.getU32(&Offset); + if (Version != 7) + return false; + + CuListOffset = Data.getU32(&Offset); + uint32_t CuTypesOffset = Data.getU32(&Offset); + AddressAreaOffset = Data.getU32(&Offset); + SymbolTableOffset = Data.getU32(&Offset); + ConstantPoolOffset = Data.getU32(&Offset); + + if (Offset != CuListOffset) + return false; + + uint32_t CuListSize = (CuTypesOffset - CuListOffset) / 16; + CuList.reserve(CuListSize); + for (uint32_t i = 0; i < CuListSize; ++i) { + uint64_t CuOffset = Data.getU64(&Offset); + uint64_t CuLength = Data.getU64(&Offset); + CuList.push_back({CuOffset, CuLength}); + } + + // CU Types are no longer needed as DWARF skeleton type units never made it + // into the standard. + uint32_t CuTypesListSize = (AddressAreaOffset - CuTypesOffset) / 24; + if (CuTypesListSize != 0) + return false; + + uint32_t AddressAreaSize = (SymbolTableOffset - AddressAreaOffset) / 20; + AddressArea.reserve(AddressAreaSize); + for (uint32_t i = 0; i < AddressAreaSize; ++i) { + uint64_t LowAddress = Data.getU64(&Offset); + uint64_t HighAddress = Data.getU64(&Offset); + uint32_t CuIndex = Data.getU32(&Offset); + AddressArea.push_back({LowAddress, HighAddress, CuIndex}); + } + + // The symbol table. This is an open addressed hash table. The size of the + // hash table is always a power of 2. + // Each slot in the hash table consists of a pair of offset_type values. The + // first value is the offset of the symbol's name in the constant pool. The + // second value is the offset of the CU vector in the constant pool. + // If both values are 0, then this slot in the hash table is empty. This is ok + // because while 0 is a valid constant pool index, it cannot be a valid index + // for both a string and a CU vector. + uint32_t SymTableSize = (ConstantPoolOffset - SymbolTableOffset) / 8; + SymbolTable.reserve(SymTableSize); + uint32_t CuVectorsTotal = 0; + for (uint32_t i = 0; i < SymTableSize; ++i) { + uint32_t NameOffset = Data.getU32(&Offset); + uint32_t CuVecOffset = Data.getU32(&Offset); + SymbolTable.push_back({NameOffset, CuVecOffset}); + if (NameOffset || CuVecOffset) + ++CuVectorsTotal; + } + + // The constant pool. CU vectors are stored first, followed by strings. + // The first value is the number of CU indices in the vector. Each subsequent + // value is the index and symbol attributes of a CU in the CU list. + for (uint32_t i = 0; i < CuVectorsTotal; ++i) { + ConstantPoolVectors.emplace_back(0, SmallVector<uint32_t, 0>()); + auto &Vec = ConstantPoolVectors.back(); + Vec.first = Offset - ConstantPoolOffset; + + uint32_t Num = Data.getU32(&Offset); + for (uint32_t j = 0; j < Num; ++j) + Vec.second.push_back(Data.getU32(&Offset)); + } + + ConstantPoolStrings = Data.getData().drop_front(Offset); + StringPoolOffset = Offset; + return true; +} + +void DWARFGdbIndex::parse(DataExtractor Data) { + HasContent = !Data.getData().empty(); + HasError = HasContent && !parseImpl(Data); +} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp index 766e8ac..88fb203 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -22,19 +24,29 @@ bool DWARFTypeUnit::extractImpl(DataExtractor debug_info, return TypeOffset < getLength(); } -void DWARFTypeUnit::dump(raw_ostream &OS) { +void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) { + DWARFDie TD = getDIEForOffset(TypeOffset + getOffset()); + const char *Name = TD.getAttributeValueAsString(llvm::dwarf::DW_AT_name, ""); + + if (SummarizeTypes) { + OS << "name = '" << Name << "'" + << " type_signature = " << format("0x%16" 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()) << " addr_size = " << format("0x%02x", getAddressByteSize()) + << " name = '" << Name << "'" << " type_signature = " << format("0x%16" PRIx64, TypeHash) << " type_offset = " << format("0x%04x", TypeOffset) - << " (next unit at " << format("0x%08x", getNextUnitOffset()) - << ")\n"; + << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n"; - if (const DWARFDebugInfoEntryMinimal *TU = getUnitDIE(false)) - TU->dump(OS, this, -1U); + if (DWARFDie TU = getUnitDIE(false)) + TU.dump(OS, -1U); else OS << "<type unit can't be parsed!>\n\n"; } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index 13c2b50..ee2c569 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -7,14 +7,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstdint> #include <cstdio> +#include <vector> namespace llvm { + using namespace dwarf; void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) { @@ -49,8 +60,7 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, clear(); } -DWARFUnit::~DWARFUnit() { -} +DWARFUnit::~DWARFUnit() = default; bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { @@ -121,7 +131,7 @@ bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. - assert(DieArray.size() > 0); + assert(!DieArray.empty()); DataExtractor RangesData(RangeSection, isLittleEndian, AddrSize); uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; return RangeList.extract(RangesData, &ActualRangeListOffset); @@ -141,53 +151,16 @@ void DWARFUnit::clear() { } const char *DWARFUnit::getCompilationDir() { - extractDIEsIfNeeded(true); - if (DieArray.empty()) - return nullptr; - return DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr); + return getUnitDIE().getAttributeValueAsString(DW_AT_comp_dir, nullptr); } -uint64_t DWARFUnit::getDWOId() { - extractDIEsIfNeeded(true); - const uint64_t FailValue = -1ULL; - if (DieArray.empty()) - return FailValue; - return DieArray[0] - .getAttributeValueAsUnsignedConstant(this, DW_AT_GNU_dwo_id, FailValue); -} - -void DWARFUnit::setDIERelations() { - if (DieArray.size() <= 1) - return; - - std::vector<DWARFDebugInfoEntryMinimal *> ParentChain; - DWARFDebugInfoEntryMinimal *SiblingChain = nullptr; - for (auto &DIE : DieArray) { - if (SiblingChain) { - SiblingChain->setSibling(&DIE); - } - if (const DWARFAbbreviationDeclaration *AbbrDecl = - DIE.getAbbreviationDeclarationPtr()) { - // Normal DIE. - if (AbbrDecl->hasChildren()) { - ParentChain.push_back(&DIE); - SiblingChain = nullptr; - } else { - SiblingChain = &DIE; - } - } else { - // NULL entry terminates the sibling chain. - SiblingChain = ParentChain.back(); - ParentChain.pop_back(); - } - } - assert(SiblingChain == nullptr || SiblingChain == &DieArray[0]); - assert(ParentChain.empty()); +Optional<uint64_t> DWARFUnit::getDWOId() { + return getUnitDIE().getAttributeValueAsUnsignedConstant(DW_AT_GNU_dwo_id); } void DWARFUnit::extractDIEsToVector( bool AppendCUDie, bool AppendNonCUDies, - std::vector<DWARFDebugInfoEntryMinimal> &Dies) const { + std::vector<DWARFDebugInfoEntry> &Dies) const { if (!AppendCUDie && !AppendNonCUDies) return; @@ -195,11 +168,13 @@ void DWARFUnit::extractDIEsToVector( // next compilation unit header. uint32_t DIEOffset = Offset + getHeaderSize(); uint32_t NextCUOffset = getNextUnitOffset(); - DWARFDebugInfoEntryMinimal DIE; + DWARFDebugInfoEntry DIE; + DataExtractor DebugInfoData = getDebugInfoExtractor(); uint32_t Depth = 0; bool IsCUDie = true; - while (DIEOffset < NextCUOffset && DIE.extractFast(this, &DIEOffset)) { + while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset, + Depth)) { if (IsCUDie) { if (AppendCUDie) Dies.push_back(DIE); @@ -237,11 +212,11 @@ void DWARFUnit::extractDIEsToVector( } size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { - if ((CUDieOnly && DieArray.size() > 0) || + if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1) return 0; // Already parsed. - bool HasCUDie = DieArray.size() > 0; + bool HasCUDie = !DieArray.empty(); extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); if (DieArray.empty()) @@ -249,25 +224,27 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { // If CU DIE was just parsed, copy several attribute values from it. if (!HasCUDie) { - uint64_t BaseAddr = - DieArray[0].getAttributeValueAsAddress(this, DW_AT_low_pc, -1ULL); - if (BaseAddr == -1ULL) - BaseAddr = DieArray[0].getAttributeValueAsAddress(this, DW_AT_entry_pc, 0); - setBaseAddress(BaseAddr); - AddrOffsetSectionBase = DieArray[0].getAttributeValueAsSectionOffset( - this, DW_AT_GNU_addr_base, 0); - RangeSectionBase = DieArray[0].getAttributeValueAsSectionOffset( - this, DW_AT_ranges_base, 0); + DWARFDie UnitDie = getUnitDIE(); + auto BaseAddr = UnitDie.getAttributeValueAsAddress(DW_AT_low_pc); + if (!BaseAddr) + BaseAddr = UnitDie.getAttributeValueAsAddress(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); // 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. } - setDIERelations(); return DieArray.size(); } DWARFUnit::DWOHolder::DWOHolder(StringRef DWOPath) - : DWOFile(), DWOContext(), DWOU(nullptr) { + : DWOU(nullptr) { auto Obj = object::ObjectFile::createObjectFile(DWOPath); if (!Obj) { // TODO: Actually report errors helpfully. @@ -286,15 +263,15 @@ bool DWARFUnit::parseDWO() { return false; if (DWO.get()) return false; - extractDIEsIfNeeded(true); - if (DieArray.empty()) + DWARFDie UnitDie = getUnitDIE(); + if (!UnitDie) return false; const char *DWOFileName = - DieArray[0].getAttributeValueAsString(this, DW_AT_GNU_dwo_name, nullptr); + UnitDie.getAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr); if (!DWOFileName) return false; const char *CompilationDir = - DieArray[0].getAttributeValueAsString(this, DW_AT_comp_dir, nullptr); + UnitDie.getAttributeValueAsString(DW_AT_comp_dir, nullptr); SmallString<16> AbsolutePath; if (sys::path::is_relative(DWOFileName) && CompilationDir != nullptr) { sys::path::append(AbsolutePath, CompilationDir); @@ -309,8 +286,8 @@ bool DWARFUnit::parseDWO() { } // Share .debug_addr and .debug_ranges section with compile unit in .dwo DWOCU->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase); - uint32_t DWORangesBase = DieArray[0].getRangesBaseAttribute(this, 0); - DWOCU->setRangesSection(RangeSection, DWORangesBase); + auto DWORangesBase = UnitDie.getRangesBaseAttribute(); + DWOCU->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); return true; } @@ -323,7 +300,7 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) { // contents which will cause just the internal pointers to be swapped // so that when temporary vector goes out of scope, it will destroy the // contents. - std::vector<DWARFDebugInfoEntryMinimal> TmpArray; + std::vector<DWARFDebugInfoEntry> TmpArray; DieArray.swap(TmpArray); // Save at least the compile unit DIE if (KeepCUDie) @@ -332,11 +309,11 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) { } void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { - const auto *U = getUnitDIE(); - if (U == nullptr) + DWARFDie UnitDie = getUnitDIE(); + if (!UnitDie) return; // First, check if unit DIE describes address ranges for the whole unit. - const auto &CUDIERanges = U->getAddressRanges(this); + const auto &CUDIERanges = UnitDie.getAddressRanges(); if (!CUDIERanges.empty()) { CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end()); return; @@ -349,7 +326,7 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { // up parsing the DWARF and then throwing them all away to keep memory usage // down. const bool ClearDIEs = extractDIEsIfNeeded(false) > 1; - DieArray[0].collectChildrenAddressRanges(this, CURanges); + getUnitDIE().collectChildrenAddressRanges(CURanges); // Collect address ranges from DIEs in .dwo if necessary. bool DWOCreated = parseDWO(); @@ -364,36 +341,37 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { clearDIEs(true); } -const DWARFDebugInfoEntryMinimal * +DWARFDie DWARFUnit::getSubprogramForAddress(uint64_t Address) { extractDIEsIfNeeded(false); - for (const DWARFDebugInfoEntryMinimal &DIE : DieArray) { + for (const DWARFDebugInfoEntry &D : DieArray) { + DWARFDie DIE(this, &D); if (DIE.isSubprogramDIE() && - DIE.addressRangeContainsAddress(this, Address)) { - return &DIE; + DIE.addressRangeContainsAddress(Address)) { + return DIE; } } - return nullptr; + return DWARFDie(); } -DWARFDebugInfoEntryInlinedChain -DWARFUnit::getInlinedChainForAddress(uint64_t Address) { +void +DWARFUnit::getInlinedChainForAddress(uint64_t Address, + SmallVectorImpl<DWARFDie> &InlinedChain) { // First, find a subprogram that contains the given address (the root // of inlined chain). - const DWARFUnit *ChainCU = nullptr; - const DWARFDebugInfoEntryMinimal *SubprogramDIE; + DWARFDie SubprogramDIE; // Try to look for subprogram DIEs in the DWO file. parseDWO(); - if (DWO) { - if ((SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address))) - ChainCU = DWO->getUnit(); - } else if ((SubprogramDIE = getSubprogramForAddress(Address))) - ChainCU = this; + if (DWO) + SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address); + else + SubprogramDIE = getSubprogramForAddress(Address); // Get inlined chain rooted at this subprogram DIE. - if (!SubprogramDIE) - return DWARFDebugInfoEntryInlinedChain(); - return SubprogramDIE->getInlinedChainForAddress(ChainCU, Address); + if (SubprogramDIE) + SubprogramDIE.getInlinedChainForAddress(Address, InlinedChain); + else + InlinedChain.clear(); } const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, @@ -403,4 +381,43 @@ const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context, assert(Kind == DW_SECT_TYPES); return Context.getTUIndex(); } + +DWARFDie DWARFUnit::getParent(const DWARFDebugInfoEntry *Die) { + if (!Die) + return DWARFDie(); + const uint32_t Depth = Die->getDepth(); + // Unit DIEs always have a depth of zero and never have parents. + if (Depth == 0) + return DWARFDie(); + // Depth of 1 always means parent is the compile/type unit. + if (Depth == 1) + return getUnitDIE(); + // Look for previous DIE with a depth that is one less than the Die's depth. + const uint32_t ParentDepth = Depth - 1; + for (uint32_t I = getDIEIndex(Die) - 1; I > 0; --I) { + if (DieArray[I].getDepth() == ParentDepth) + return DWARFDie(this, &DieArray[I]); + } + return DWARFDie(); } + +DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) { + if (!Die) + return DWARFDie(); + uint32_t Depth = Die->getDepth(); + // Unit DIEs always have a depth of zero and never have siblings. + if (Depth == 0) + return DWARFDie(); + // NULL DIEs don't have siblings. + if (Die->getAbbreviationDeclarationPtr() == nullptr) + 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) { + if (DieArray[I].getDepth() == Depth) + return DWARFDie(this, &DieArray[I]); + } + return DWARFDie(); +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp b/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp index 16b086b..5b1b5d8 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -1,4 +1,3 @@ -//===- MSFBuilder.cpp - MSF Directory & Metadata Builder --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFError.h" using namespace llvm; -using namespace llvm::pdb; -using namespace llvm::pdb::msf; +using namespace llvm::msf; using namespace llvm::support; namespace { @@ -21,12 +19,14 @@ const uint32_t kFreePageMap0Block = 1; const uint32_t kFreePageMap1Block = 2; const uint32_t kNumReservedPages = 3; +const uint32_t kDefaultFreePageMap = kFreePageMap0Block; const uint32_t kDefaultBlockMapAddr = kNumReservedPages; } -MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, +MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, BumpPtrAllocator &Allocator) - : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize), + : Allocator(Allocator), IsGrowable(CanGrow), + FreePageMap(kDefaultFreePageMap), BlockSize(BlockSize), MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr), FreeBlocks(MinBlockCount, true) { FreeBlocks[kSuperBlockBlock] = false; @@ -35,48 +35,49 @@ MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, FreeBlocks[BlockMapAddr] = false; } -Expected<MsfBuilder> MsfBuilder::create(BumpPtrAllocator &Allocator, +Expected<MSFBuilder> MSFBuilder::create(BumpPtrAllocator &Allocator, uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow) { - if (!msf::isValidBlockSize(BlockSize)) - return make_error<RawError>(raw_error_code::unspecified, + if (!isValidBlockSize(BlockSize)) + return make_error<MSFError>(msf_error_code::invalid_format, "The requested block size is unsupported"); - return MsfBuilder(BlockSize, + return MSFBuilder(BlockSize, std::max(MinBlockCount, msf::getMinimumBlockCount()), CanGrow, Allocator); } -Error MsfBuilder::setBlockMapAddr(uint32_t Addr) { +Error MSFBuilder::setBlockMapAddr(uint32_t Addr) { if (Addr == BlockMapAddr) return Error::success(); if (Addr >= FreeBlocks.size()) { if (!IsGrowable) - return make_error<RawError>(raw_error_code::unspecified, + return make_error<MSFError>(msf_error_code::insufficient_buffer, "Cannot grow the number of blocks"); - FreeBlocks.resize(Addr + 1); + FreeBlocks.resize(Addr + 1, true); } if (!isBlockFree(Addr)) - return make_error<RawError>(raw_error_code::unspecified, - "Attempt to reuse an allocated block"); + return make_error<MSFError>( + msf_error_code::block_in_use, + "Requested block map address is already in use"); FreeBlocks[BlockMapAddr] = true; FreeBlocks[Addr] = false; BlockMapAddr = Addr; return Error::success(); } -void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; } +void MSFBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; } -void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } +void MSFBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } -Error MsfBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) { +Error MSFBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) { for (auto B : DirectoryBlocks) FreeBlocks[B] = true; for (auto B : DirBlocks) { if (!isBlockFree(B)) { - return make_error<RawError>(raw_error_code::unspecified, + return make_error<MSFError>(msf_error_code::unspecified, "Attempt to reuse an allocated block"); } FreeBlocks[B] = false; @@ -86,7 +87,7 @@ Error MsfBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) { return Error::success(); } -Error MsfBuilder::allocateBlocks(uint32_t NumBlocks, +Error MSFBuilder::allocateBlocks(uint32_t NumBlocks, MutableArrayRef<uint32_t> Blocks) { if (NumBlocks == 0) return Error::success(); @@ -94,7 +95,7 @@ Error MsfBuilder::allocateBlocks(uint32_t NumBlocks, uint32_t NumFreeBlocks = FreeBlocks.count(); if (NumFreeBlocks < NumBlocks) { if (!IsGrowable) - return make_error<RawError>(raw_error_code::unspecified, + return make_error<MSFError>(msf_error_code::insufficient_buffer, "There are no free Blocks in the file"); uint32_t AllocBlocks = NumBlocks - NumFreeBlocks; FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true); @@ -113,32 +114,33 @@ Error MsfBuilder::allocateBlocks(uint32_t NumBlocks, return Error::success(); } -uint32_t MsfBuilder::getNumUsedBlocks() const { +uint32_t MSFBuilder::getNumUsedBlocks() const { return getTotalBlockCount() - getNumFreeBlocks(); } -uint32_t MsfBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } +uint32_t MSFBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } -uint32_t MsfBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } +uint32_t MSFBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } -bool MsfBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } +bool MSFBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } -Error MsfBuilder::addStream(uint32_t Size, ArrayRef<uint32_t> Blocks) { +Expected<uint32_t> MSFBuilder::addStream(uint32_t Size, + ArrayRef<uint32_t> Blocks) { // Add a new stream mapped to the specified blocks. Verify that the specified // blocks are both necessary and sufficient for holding the requested number // of bytes, and verify that all requested blocks are free. uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); if (ReqBlocks != Blocks.size()) - return make_error<RawError>( - raw_error_code::unspecified, + return make_error<MSFError>( + msf_error_code::invalid_format, "Incorrect number of blocks for requested stream size"); for (auto Block : Blocks) { if (Block >= FreeBlocks.size()) FreeBlocks.resize(Block + 1, true); if (!FreeBlocks.test(Block)) - return make_error<RawError>( - raw_error_code::unspecified, + return make_error<MSFError>( + msf_error_code::unspecified, "Attempt to re-use an already allocated block"); } // Mark all the blocks occupied by the new stream as not free. @@ -146,20 +148,20 @@ Error MsfBuilder::addStream(uint32_t Size, ArrayRef<uint32_t> Blocks) { FreeBlocks.reset(Block); } StreamData.push_back(std::make_pair(Size, Blocks)); - return Error::success(); + return StreamData.size() - 1; } -Error MsfBuilder::addStream(uint32_t Size) { +Expected<uint32_t> MSFBuilder::addStream(uint32_t Size) { uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); std::vector<uint32_t> NewBlocks; NewBlocks.resize(ReqBlocks); if (auto EC = allocateBlocks(ReqBlocks, NewBlocks)) - return EC; + return std::move(EC); StreamData.push_back(std::make_pair(Size, NewBlocks)); - return Error::success(); + return StreamData.size() - 1; } -Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { +Error MSFBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { uint32_t OldSize = getStreamSize(Idx); if (OldSize == Size) return Error::success(); @@ -192,17 +194,17 @@ Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { return Error::success(); } -uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); } +uint32_t MSFBuilder::getNumStreams() const { return StreamData.size(); } -uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const { +uint32_t MSFBuilder::getStreamSize(uint32_t StreamIdx) const { return StreamData[StreamIdx].first; } -ArrayRef<uint32_t> MsfBuilder::getStreamBlocks(uint32_t StreamIdx) const { +ArrayRef<uint32_t> MSFBuilder::getStreamBlocks(uint32_t StreamIdx) const { return StreamData[StreamIdx].second; } -uint32_t MsfBuilder::computeDirectoryByteSize() const { +uint32_t MSFBuilder::computeDirectoryByteSize() const { // The directory has the following layout, where each item is a ulittle32_t: // NumStreams // StreamSizes[NumStreams] @@ -218,18 +220,19 @@ uint32_t MsfBuilder::computeDirectoryByteSize() const { return Size; } -Expected<Layout> MsfBuilder::build() { - Layout L; - L.SB = Allocator.Allocate<SuperBlock>(); - std::memcpy(L.SB->MagicBytes, Magic, sizeof(Magic)); - L.SB->BlockMapAddr = BlockMapAddr; - L.SB->BlockSize = BlockSize; - L.SB->NumDirectoryBytes = computeDirectoryByteSize(); - L.SB->FreeBlockMapBlock = FreePageMap; - L.SB->Unknown1 = Unknown1; - - uint32_t NumDirectoryBlocks = - bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize); +Expected<MSFLayout> MSFBuilder::build() { + SuperBlock *SB = Allocator.Allocate<SuperBlock>(); + MSFLayout L; + L.SB = SB; + + std::memcpy(SB->MagicBytes, Magic, sizeof(Magic)); + SB->BlockMapAddr = BlockMapAddr; + SB->BlockSize = BlockSize; + SB->NumDirectoryBytes = computeDirectoryByteSize(); + SB->FreeBlockMapBlock = FreePageMap; + SB->Unknown1 = Unknown1; + + uint32_t NumDirectoryBlocks = bytesToBlocks(SB->NumDirectoryBytes, BlockSize); if (NumDirectoryBlocks > DirectoryBlocks.size()) { // Our hint wasn't enough to satisfy the entire directory. Allocate // remaining pages. @@ -249,9 +252,9 @@ Expected<Layout> MsfBuilder::build() { } // Don't set the number of blocks in the file until after allocating Blocks - // for - // the directory, since the allocation might cause the file to need to grow. - L.SB->NumBlocks = FreeBlocks.size(); + // for the directory, since the allocation might cause the file to need to + // grow. + SB->NumBlocks = FreeBlocks.size(); ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks); std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp b/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp index 5d97f33..fdab788 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp @@ -1,4 +1,4 @@ -//===- MsfCommon.cpp - Common types and functions for MSF files -*- C++ -*-===// +//===- MSFCommon.cpp - Common types and functions for MSF files -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,25 +7,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFError.h" using namespace llvm; -using namespace llvm::pdb::msf; +using namespace llvm::msf; -Error llvm::pdb::msf::validateSuperBlock(const SuperBlock &SB) { +Error llvm::msf::validateSuperBlock(const SuperBlock &SB) { // Check the magic bytes. if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, + return make_error<MSFError>(msf_error_code::invalid_format, "MSF magic header doesn't match"); if (!isValidBlockSize(SB.BlockSize)) - return make_error<RawError>(raw_error_code::corrupt_file, + return make_error<MSFError>(msf_error_code::invalid_format, "Unsupported block size."); // We don't support directories whose sizes aren't a multiple of four bytes. if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, + return make_error<MSFError>(msf_error_code::invalid_format, "Directory size is not multiple of 4."); // The number of blocks which comprise the directory is a simple function of @@ -37,12 +37,21 @@ Error llvm::pdb::msf::validateSuperBlock(const SuperBlock &SB) { // block numbers. It is unclear what would happen if the number of blocks // couldn't fit on a single block. if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t)) - return make_error<RawError>(raw_error_code::corrupt_file, + return make_error<MSFError>(msf_error_code::invalid_format, "Too many directory blocks."); if (SB.BlockMapAddr == 0) - return make_error<RawError>(raw_error_code::corrupt_file, + return make_error<MSFError>(msf_error_code::invalid_format, "Block 0 is reserved"); + if (SB.BlockMapAddr >= SB.NumBlocks) + return make_error<MSFError>(msf_error_code::invalid_format, + "Block map address is invalid."); + + if (SB.FreeBlockMapBlock != 1 && SB.FreeBlockMapBlock != 2) + return make_error<MSFError>( + msf_error_code::invalid_format, + "The free block map isn't at block 1 or block 2."); + return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/MSF/MSFError.cpp b/contrib/llvm/lib/DebugInfo/MSF/MSFError.cpp new file mode 100644 index 0000000..1b8294e --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/MSF/MSFError.cpp @@ -0,0 +1,70 @@ +//===- MSFError.cpp - Error extensions for MSF files ------------*- 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/MSF/MSFError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::msf; + +namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class MSFErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.msf"; } + + std::string message(int Condition) const override { + switch (static_cast<msf_error_code>(Condition)) { + case msf_error_code::unspecified: + return "An unknown error has occurred."; + case msf_error_code::insufficient_buffer: + return "The buffer is not large enough to read the requested number of " + "bytes."; + case msf_error_code::not_writable: + return "The specified stream is not writable."; + case msf_error_code::no_stream: + return "The specified stream does not exist."; + case msf_error_code::invalid_format: + return "The data is in an unexpected format."; + case msf_error_code::block_in_use: + return "The block is already in use."; + } + llvm_unreachable("Unrecognized msf_error_code"); + } +}; +} // end anonymous namespace + +static ManagedStatic<MSFErrorCategory> Category; + +char MSFError::ID = 0; + +MSFError::MSFError(msf_error_code C) : MSFError(C, "") {} + +MSFError::MSFError(const std::string &Context) + : MSFError(msf_error_code::unspecified, Context) {} + +MSFError::MSFError(msf_error_code C, const std::string &Context) : Code(C) { + ErrMsg = "MSF Error: "; + std::error_code EC = convertToErrorCode(); + if (Code != msf_error_code::unspecified) + ErrMsg += EC.message() + " "; + if (!Context.empty()) + ErrMsg += Context; +} + +void MSFError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +const std::string &MSFError::getErrorMessage() const { return ErrMsg; } + +std::error_code MSFError::convertToErrorCode() const { + return std::error_code(static_cast<int>(Code), *Category); +} diff --git a/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp b/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp new file mode 100644 index 0000000..e52c88a --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -0,0 +1,415 @@ +//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// +// +// 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/MappedBlockStream.h" + +#include "llvm/DebugInfo/MSF/IMSFFile.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/DebugInfo/MSF/MSFStreamLayout.h" + +using namespace llvm; +using namespace llvm::msf; + +namespace { +template <typename Base> class MappedBlockStreamImpl : public Base { +public: + template <typename... Args> + MappedBlockStreamImpl(Args &&... Params) + : Base(std::forward<Args>(Params)...) {} +}; +} + +static void initializeFpmStreamLayout(const MSFLayout &Layout, + MSFStreamLayout &FpmLayout) { + uint32_t NumFpmIntervals = msf::getNumFpmIntervals(Layout); + support::ulittle32_t FpmBlock = Layout.SB->FreeBlockMapBlock; + assert(FpmBlock == 1 || FpmBlock == 2); + while (NumFpmIntervals > 0) { + FpmLayout.Blocks.push_back(FpmBlock); + FpmBlock += msf::getFpmIntervalLength(Layout); + --NumFpmIntervals; + } + FpmLayout.Length = msf::getFullFpmByteSize(Layout); +} + +typedef std::pair<uint32_t, uint32_t> Interval; +static Interval intersect(const Interval &I1, const Interval &I2) { + return std::make_pair(std::max(I1.first, I2.first), + std::min(I1.second, I2.second)); +} + +MappedBlockStream::MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, + const MSFStreamLayout &Layout, + const ReadableStream &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) { + 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) { + assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); + MSFStreamLayout SL; + SL.Blocks = Layout.StreamMap[StreamIndex]; + SL.Length = Layout.StreamSizes[StreamIndex]; + return llvm::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( + Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); +} + +std::unique_ptr<MappedBlockStream> +MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, + const ReadableStream &MsfData) { + MSFStreamLayout SL; + SL.Blocks = Layout.DirectoryBlocks; + SL.Length = Layout.SB->NumDirectoryBytes; + return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); +} + +std::unique_ptr<MappedBlockStream> +MappedBlockStream::createFpmStream(const MSFLayout &Layout, + const ReadableStream &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 { + // 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 (tryReadContiguously(Offset, Size, Buffer)) + return Error::success(); + + auto CacheIter = CacheMap.find(Offset); + if (CacheIter != CacheMap.end()) { + // Try to find an alloc that was large enough for this request. + for (auto &Entry : CacheIter->second) { + if (Entry.size() >= Size) { + Buffer = Entry.slice(0, Size); + return Error::success(); + } + } + } + + // We couldn't find a buffer that started at the correct offset (the most + // common scenario). Try to see if there is a buffer that starts at some + // other offset but overlaps the desired range. + for (auto &CacheItem : CacheMap) { + Interval RequestExtent = std::make_pair(Offset, Offset + Size); + + // We already checked this one on the fast path above. + if (CacheItem.first == Offset) + continue; + // If the initial extent of the cached item is beyond the ending extent + // of the request, there is no overlap. + if (CacheItem.first >= Offset + Size) + continue; + + // We really only have to check the last item in the list, since we append + // in order of increasing length. + if (CacheItem.second.empty()) + continue; + + auto CachedAlloc = CacheItem.second.back(); + // If the initial extent of the request is beyond the ending extent of + // the cached item, there is no overlap. + Interval CachedExtent = + std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); + if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) + continue; + + Interval Intersection = intersect(CachedExtent, RequestExtent); + // Only use this if the entire request extent is contained in the cached + // extent. + if (Intersection != RequestExtent) + continue; + + uint32_t CacheRangeOffset = + AbsoluteDifference(CachedExtent.first, Intersection.first); + Buffer = CachedAlloc.slice(CacheRangeOffset, Size); + return Error::success(); + } + + // Otherwise allocate a large enough buffer in the pool, memcpy the data + // into it, and return an ArrayRef to that. Do not touch existing pool + // allocations, as existing clients may be holding a pointer which must + // not be invalidated. + uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8)); + if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size))) + return EC; + + if (CacheIter != CacheMap.end()) { + CacheIter->second.emplace_back(WriteBuffer, Size); + } else { + std::vector<CacheEntry> List; + List.emplace_back(WriteBuffer, Size); + CacheMap.insert(std::make_pair(Offset, List)); + } + Buffer = ArrayRef<uint8_t>(WriteBuffer, Size); + return Error::success(); +} + +Error MappedBlockStream::readLongestContiguousChunk( + uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { + // 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); + uint32_t First = Offset / BlockSize; + uint32_t Last = First; + + while (Last < NumBlocks - 1) { + if (StreamLayout.Blocks[Last] != StreamLayout.Blocks[Last + 1] - 1) + break; + ++Last; + } + + uint32_t OffsetInFirstBlock = Offset % BlockSize; + uint32_t BytesFromFirstBlock = BlockSize - OffsetInFirstBlock; + uint32_t BlockSpan = Last - First + 1; + uint32_t ByteSpan = BytesFromFirstBlock + (BlockSpan - 1) * BlockSize; + + ArrayRef<uint8_t> BlockData; + uint32_t MsfOffset = blockToOffset(StreamLayout.Blocks[First], BlockSize); + if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) + return EC; + + BlockData = BlockData.drop_front(OffsetInFirstBlock); + Buffer = ArrayRef<uint8_t>(BlockData.data(), ByteSpan); + return Error::success(); +} + +uint32_t MappedBlockStream::getLength() const { return StreamLayout.Length; } + +bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) const { + if (Size == 0) { + Buffer = ArrayRef<uint8_t>(); + return true; + } + // Attempt to fulfill the request with a reference directly into the stream. + // This can work even if the request crosses a block boundary, provided that + // all subsequent blocks are contiguous. For example, a 10k read with a 4k + // block size can be filled with a reference if, from the starting offset, + // 3 blocks in a row are contiguous. + uint32_t BlockNum = Offset / BlockSize; + uint32_t OffsetInBlock = Offset % BlockSize; + uint32_t BytesFromFirstBlock = std::min(Size, BlockSize - OffsetInBlock); + uint32_t NumAdditionalBlocks = + llvm::alignTo(Size - BytesFromFirstBlock, BlockSize) / BlockSize; + + uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; + uint32_t E = StreamLayout.Blocks[BlockNum]; + for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { + if (StreamLayout.Blocks[I + BlockNum] != E) + return false; + } + + // Read out the entire block where the requested offset starts. Then drop + // bytes from the beginning so that the actual starting byte lines up with + // the requested starting byte. Then, since we know this is a contiguous + // cross-block span, explicitly resize the ArrayRef to cover the entire + // request length. + ArrayRef<uint8_t> BlockData; + uint32_t FirstBlockAddr = StreamLayout.Blocks[BlockNum]; + uint32_t MsfOffset = blockToOffset(FirstBlockAddr, BlockSize); + if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) { + consumeError(std::move(EC)); + return false; + } + BlockData = BlockData.drop_front(OffsetInBlock); + Buffer = ArrayRef<uint8_t>(BlockData.data(), Size); + return true; +} + +Error MappedBlockStream::readBytes(uint32_t Offset, + MutableArrayRef<uint8_t> Buffer) const { + 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); + + uint32_t BytesLeft = Buffer.size(); + uint32_t BytesWritten = 0; + uint8_t *WriteBuffer = Buffer.data(); + while (BytesLeft > 0) { + uint32_t StreamBlockAddr = StreamLayout.Blocks[BlockNum]; + + ArrayRef<uint8_t> BlockData; + uint32_t Offset = blockToOffset(StreamBlockAddr, BlockSize); + if (auto EC = MsfData.readBytes(Offset, BlockSize, BlockData)) + return EC; + + const uint8_t *ChunkStart = BlockData.data() + OffsetInBlock; + uint32_t BytesInChunk = std::min(BytesLeft, BlockSize - OffsetInBlock); + ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); + + BytesWritten += BytesInChunk; + BytesLeft -= BytesInChunk; + ++BlockNum; + OffsetInBlock = 0; + } + + return Error::success(); +} + +uint32_t MappedBlockStream::getNumBytesCopied() const { + return static_cast<uint32_t>(Pool.getBytesAllocated()); +} + +void MappedBlockStream::invalidateCache() { CacheMap.shrink_and_clear(); } + +void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, + ArrayRef<uint8_t> Data) const { + // If this write overlapped a read which previously came from the pool, + // someone may still be holding a pointer to that alloc which is now invalid. + // Compute the overlapping range and update the cache entry, so any + // outstanding buffers are automatically updated. + for (const auto &MapEntry : CacheMap) { + // If the end of the written extent precedes the beginning of the cached + // extent, ignore this map entry. + if (Offset + Data.size() < MapEntry.first) + continue; + for (const auto &Alloc : MapEntry.second) { + // If the end of the cached extent precedes the beginning of the written + // extent, ignore this alloc. + if (MapEntry.first + Alloc.size() < Offset) + continue; + + // If we get here, they are guaranteed to overlap. + Interval WriteInterval = std::make_pair(Offset, Offset + Data.size()); + Interval CachedInterval = + std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); + // If they overlap, we need to write the new data into the overlapping + // range. + auto Intersection = intersect(WriteInterval, CachedInterval); + assert(Intersection.first <= Intersection.second); + + uint32_t Length = Intersection.second - Intersection.first; + uint32_t SrcOffset = + AbsoluteDifference(WriteInterval.first, Intersection.first); + uint32_t DestOffset = + AbsoluteDifference(CachedInterval.first, Intersection.first); + ::memcpy(Alloc.data() + DestOffset, Data.data() + SrcOffset, Length); + } + } +} + +WritableMappedBlockStream::WritableMappedBlockStream( + uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, + const WritableStream &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) { + return llvm::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>( + BlockSize, NumBlocks, Layout, MsfData); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, + const WritableStream &MsfData, + uint32_t StreamIndex) { + assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); + MSFStreamLayout SL; + SL.Blocks = Layout.StreamMap[StreamIndex]; + SL.Length = Layout.StreamSizes[StreamIndex]; + return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createDirectoryStream( + const MSFLayout &Layout, const WritableStream &MsfData) { + MSFStreamLayout SL; + SL.Blocks = Layout.DirectoryBlocks; + SL.Length = Layout.SB->NumDirectoryBytes; + return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, + const WritableStream &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 { + return ReadInterface.readBytes(Offset, Size, Buffer); +} + +Error WritableMappedBlockStream::readLongestContiguousChunk( + uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { + return ReadInterface.readLongestContiguousChunk(Offset, Buffer); +} + +uint32_t WritableMappedBlockStream::getLength() const { + return ReadInterface.getLength(); +} + +Error WritableMappedBlockStream::writeBytes(uint32_t Offset, + ArrayRef<uint8_t> Buffer) const { + // 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); + + uint32_t BlockNum = Offset / getBlockSize(); + uint32_t OffsetInBlock = Offset % getBlockSize(); + + uint32_t BytesLeft = Buffer.size(); + uint32_t BytesWritten = 0; + while (BytesLeft > 0) { + uint32_t StreamBlockAddr = getStreamLayout().Blocks[BlockNum]; + uint32_t BytesToWriteInChunk = + std::min(BytesLeft, getBlockSize() - OffsetInBlock); + + const uint8_t *Chunk = Buffer.data() + BytesWritten; + ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk); + uint32_t MsfOffset = blockToOffset(StreamBlockAddr, getBlockSize()); + MsfOffset += OffsetInBlock; + if (auto EC = WriteInterface.writeBytes(MsfOffset, ChunkData)) + return EC; + + BytesLeft -= BytesToWriteInChunk; + BytesWritten += BytesToWriteInChunk; + ++BlockNum; + OffsetInBlock = 0; + } + + ReadInterface.fixCacheAfterWrite(Offset, Buffer); + + return Error::success(); +} + +Error WritableMappedBlockStream::commit() const { + return WriteInterface.commit(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/StreamReader.cpp b/contrib/llvm/lib/DebugInfo/MSF/StreamReader.cpp index 64e4548..b85fd14 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/StreamReader.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/StreamReader.cpp @@ -7,15 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" +#include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/DebugInfo/MSF/StreamRef.h" using namespace llvm; -using namespace llvm::codeview; +using namespace llvm::msf; -StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {} +StreamReader::StreamReader(ReadableStreamRef S) : Stream(S), Offset(0) {} Error StreamReader::readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer) { if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) @@ -31,6 +31,14 @@ Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t 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)) @@ -47,6 +55,46 @@ Error StreamReader::readInteger(uint32_t &Dest) { 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. @@ -80,14 +128,29 @@ Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) { return Error::success(); } -Error StreamReader::readStreamRef(StreamRef &Ref) { +Error StreamReader::readStreamRef(ReadableStreamRef &Ref) { return readStreamRef(Ref, bytesRemaining()); } -Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) { +Error StreamReader::readStreamRef(ReadableStreamRef &Ref, uint32_t Length) { if (bytesRemaining() < Length) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + 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/contrib/llvm/lib/DebugInfo/CodeView/StreamWriter.cpp b/contrib/llvm/lib/DebugInfo/MSF/StreamWriter.cpp index f61c6b5..cdae7c5 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/StreamWriter.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/StreamWriter.cpp @@ -7,16 +7,16 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/MSF/StreamWriter.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamRef.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::codeview; +using namespace llvm::msf; -StreamWriter::StreamWriter(StreamRef S) : Stream(S), Offset(0) {} +StreamWriter::StreamWriter(WritableStreamRef S) : Stream(S), Offset(0) {} Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { if (auto EC = Stream.writeBytes(Offset, Buffer)) @@ -25,6 +25,8 @@ Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { return Error::success(); } +Error StreamWriter::writeInteger(uint8_t Int) { return writeObject(Int); } + Error StreamWriter::writeInteger(uint16_t Int) { return writeObject(support::ulittle16_t(Int)); } @@ -33,6 +35,24 @@ 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; @@ -51,14 +71,15 @@ Error StreamWriter::writeFixedString(StringRef Str) { return Error::success(); } -Error StreamWriter::writeStreamRef(StreamRef Ref) { +Error StreamWriter::writeStreamRef(ReadableStreamRef Ref) { if (auto EC = writeStreamRef(Ref, Ref.getLength())) return EC; - Offset += Ref.getLength(); + // Don't increment Offset here, it is done by the overloaded call to + // writeStreamRef. return Error::success(); } -Error StreamWriter::writeStreamRef(StreamRef Ref, uint32_t Length) { +Error StreamWriter::writeStreamRef(ReadableStreamRef Ref, uint32_t Length) { Ref = Ref.slice(0, Length); StreamReader SrcReader(Ref); diff --git a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp index 1d72a92..0da877b 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIAError.cpp @@ -10,7 +10,7 @@ using namespace llvm::pdb; // deal with the Error value directly, rather than converting to error_code. class DIAErrorCategory : public std::error_category { public: - const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.dia"; } + const char *name() const noexcept override { return "llvm.pdb.dia"; } std::string message(int Condition) const override { switch (static_cast<dia_error_code>(Condition)) { @@ -38,21 +38,20 @@ char DIAError::ID = 0; DIAError::DIAError(dia_error_code C) : DIAError(C, "") {} -DIAError::DIAError(const std::string &Context) +DIAError::DIAError(StringRef Context) : DIAError(dia_error_code::unspecified, Context) {} -DIAError::DIAError(dia_error_code C, const std::string &Context) : Code(C) { +DIAError::DIAError(dia_error_code C, StringRef Context) : Code(C) { ErrMsg = "DIA Error: "; std::error_code EC = convertToErrorCode(); - if (Code != dia_error_code::unspecified) - ErrMsg += EC.message() + " "; + ErrMsg += EC.message() + " "; if (!Context.empty()) ErrMsg += Context; } void DIAError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } -const std::string &DIAError::getErrorMessage() const { return ErrMsg; } +StringRef DIAError::getErrorMessage() const { return ErrMsg; } std::error_code DIAError::convertToErrorCode() const { return std::error_code(static_cast<int>(Code), *Category); diff --git a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp index fa224af..6ecf335 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -20,31 +20,36 @@ #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::pdb; -namespace { - -Error ErrorFromHResult(HRESULT Result) { +static Error ErrorFromHResult(HRESULT Result, StringRef Context) { switch (Result) { case E_PDB_NOT_FOUND: - return make_error<GenericError>(generic_error_code::invalid_path); + return make_error<GenericError>(generic_error_code::invalid_path, Context); case E_PDB_FORMAT: - return make_error<DIAError>(dia_error_code::invalid_file_format); + return make_error<DIAError>(dia_error_code::invalid_file_format, Context); case E_INVALIDARG: - return make_error<DIAError>(dia_error_code::invalid_parameter); + return make_error<DIAError>(dia_error_code::invalid_parameter, Context); case E_UNEXPECTED: - return make_error<DIAError>(dia_error_code::already_loaded); + return make_error<DIAError>(dia_error_code::already_loaded, Context); case E_PDB_INVALID_SIG: case E_PDB_INVALID_AGE: - return make_error<DIAError>(dia_error_code::debug_info_mismatch); - default: - return make_error<DIAError>(dia_error_code::unspecified); + return make_error<DIAError>(dia_error_code::debug_info_mismatch, Context); + default: { + std::string S; + raw_string_ostream OS(S); + OS << "HRESULT: " << format_hex(static_cast<DWORD>(Result), 10, true) + << ": " << Context; + return make_error<DIAError>(dia_error_code::unspecified, OS.str()); + } } } -Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { +static Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, IID_IDiaDataSource, reinterpret_cast<LPVOID *>(&DiaDataSource)))) @@ -55,12 +60,11 @@ Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { #if !defined(_MSC_VER) return llvm::make_error<GenericError>( "DIA is only supported when using MSVC."); -#endif - +#else const wchar_t *msdia_dll = nullptr; -#if _MSC_VER == 1900 +#if _MSC_VER >= 1900 && _MSC_VER < 2000 msdia_dll = L"msdia140.dll"; // VS2015 -#elif _MSC_VER == 1800 +#elif _MSC_VER >= 1800 msdia_dll = L"msdia120.dll"; // VS2013 #else #error "Unknown Visual Studio version." @@ -69,10 +73,9 @@ Error LoadDIA(CComPtr<IDiaDataSource> &DiaDataSource) { HRESULT HR; if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, reinterpret_cast<LPVOID *>(&DiaDataSource)))) - return ErrorFromHResult(HR); + return ErrorFromHResult(HR, "Calling NoRegCoCreate"); return Error::success(); -} - +#endif } DIASession::DIASession(CComPtr<IDiaSession> DiaSession) : Session(DiaSession) {} @@ -93,10 +96,10 @@ Error DIASession::createFromPdb(StringRef Path, const wchar_t *Path16Str = reinterpret_cast<const wchar_t*>(Path16.data()); HRESULT HR; if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) - return ErrorFromHResult(HR); + return ErrorFromHResult(HR, "Calling loadDataFromPdb"); if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) - return ErrorFromHResult(HR); + return ErrorFromHResult(HR, "Calling openSession"); Session.reset(new DIASession(DiaSession)); return Error::success(); @@ -118,10 +121,10 @@ Error DIASession::createFromExe(StringRef Path, const wchar_t *Path16Str = reinterpret_cast<const wchar_t *>(Path16.data()); HRESULT HR; if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) - return ErrorFromHResult(HR); + return ErrorFromHResult(HR, "Calling loadDataForExe"); if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) - return ErrorFromHResult(HR); + return ErrorFromHResult(HR, "Calling openSession"); Session.reset(new DIASession(DiaSession)); return Error::success(); diff --git a/contrib/llvm/lib/DebugInfo/PDB/GenericError.cpp b/contrib/llvm/lib/DebugInfo/PDB/GenericError.cpp index 34e1799..789f3b8 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/GenericError.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/GenericError.cpp @@ -20,7 +20,7 @@ namespace { // deal with the Error value directly, rather than converting to error_code. class GenericErrorCategory : public std::error_category { public: - const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb"; } + const char *name() const noexcept override { return "llvm.pdb"; } std::string message(int Condition) const override { switch (static_cast<generic_error_code>(Condition)) { @@ -45,11 +45,10 @@ char GenericError::ID = 0; GenericError::GenericError(generic_error_code C) : GenericError(C, "") {} -GenericError::GenericError(const std::string &Context) +GenericError::GenericError(StringRef Context) : GenericError(generic_error_code::unspecified, Context) {} -GenericError::GenericError(generic_error_code C, const std::string &Context) - : Code(C) { +GenericError::GenericError(generic_error_code C, StringRef Context) : Code(C) { ErrMsg = "PDB Error: "; std::error_code EC = convertToErrorCode(); if (Code != generic_error_code::unspecified) @@ -60,7 +59,7 @@ GenericError::GenericError(generic_error_code C, const std::string &Context) void GenericError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } -const std::string &GenericError::getErrorMessage() const { return ErrMsg; } +StringRef GenericError::getErrorMessage() const { return ErrMsg; } std::error_code GenericError::convertToErrorCode() const { return std::error_code(static_cast<int>(Code), *Category); diff --git a/contrib/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp b/contrib/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp index 46b422f..8cb1fbe 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/IPDBSourceFile.cpp @@ -1,4 +1,4 @@ -//===- IPDBSourceFile.cpp - base interface for a PDB source file *- C++ -*-===// +//===- IPDBSourceFile.cpp - base interface for a PDB source file ----------===// // // The LLVM Compiler Infrastructure // @@ -8,15 +8,17 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" - #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <string> using namespace llvm; using namespace llvm::pdb; -IPDBSourceFile::~IPDBSourceFile() {} +IPDBSourceFile::~IPDBSourceFile() = default; void IPDBSourceFile::dump(raw_ostream &OS, int Indent) const { OS.indent(Indent); diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp index 69a908e..0d72059 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDB.cpp @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" -#if HAVE_DIA_SDK +#if LLVM_ENABLE_DIA_SDK #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #endif #include "llvm/DebugInfo/PDB/Raw/RawSession.h" @@ -30,7 +30,7 @@ Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, if (Type == PDB_ReaderType::Raw) return RawSession::createFromPdb(Path, Session); -#if HAVE_DIA_SDK +#if LLVM_ENABLE_DIA_SDK return DIASession::createFromPdb(Path, Session); #else return llvm::make_error<GenericError>("DIA is not installed on the system"); @@ -43,7 +43,7 @@ Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, if (Type == PDB_ReaderType::Raw) return RawSession::createFromExe(Path, Session); -#if HAVE_DIA_SDK +#if LLVM_ENABLE_DIA_SDK return DIASession::createFromExe(Path, Session); #else return llvm::make_error<GenericError>("DIA is not installed on the system"); diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp index 7732302..94b81ec 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDBContext.cpp @@ -29,8 +29,8 @@ PDBContext::PDBContext(const COFFObjectFile &Object, Session->setLoadAddress(ImageBase.get()); } -void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType, - bool DumpEH) {} +void PDBContext::dump(raw_ostream &OS, DIDumpType DumpType, bool DumpEH, + bool SummarizeTypes) {} DILineInfo PDBContext::getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier) { diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp index a347c67..541fcda 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp @@ -15,15 +15,14 @@ #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" using namespace llvm; using namespace llvm::pdb; -IPDBSession::~IPDBSession() {} +IPDBSession::~IPDBSession() = default; -IPDBDataStream::~IPDBDataStream() {} +IPDBDataStream::~IPDBDataStream() = default; -IPDBRawSymbol::~IPDBRawSymbol() {} +IPDBRawSymbol::~IPDBRawSymbol() = default; -IPDBLineNumber::~IPDBLineNumber() {} +IPDBLineNumber::~IPDBLineNumber() = default; diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp index 9450a98..2f81931 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDBSymDumper.cpp @@ -20,7 +20,7 @@ using namespace llvm::pdb; PDBSymDumper::PDBSymDumper(bool ShouldRequireImpl) : RequireImpl(ShouldRequireImpl) {} -PDBSymDumper::~PDBSymDumper() {} +PDBSymDumper::~PDBSymDumper() = default; void PDBSymDumper::dump(const PDBSymbolAnnotation &Symbol) { PDB_SYMDUMP_UNREACHABLE(PDBSymbolAnnotation) diff --git a/contrib/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp b/contrib/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp index 78b3afc..633e11a 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/PDBSymbol.h" - #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" #include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" @@ -42,12 +42,9 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" #include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" #include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include <memory> -#include <utility> - +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include <algorithm> #include <memory> -#include <utility> using namespace llvm; using namespace llvm::pdb; @@ -56,7 +53,7 @@ PDBSymbol::PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) : Session(PDBSession), RawSymbol(std::move(Symbol)) {} -PDBSymbol::~PDBSymbol() {} +PDBSymbol::~PDBSymbol() = default; #define FACTORY_SYMTAG_CASE(Tag, Type) \ case PDB_SymType::Tag: \ diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp index 3c0586c..4f4a0cf 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// +#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/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" - -#include "llvm/DebugInfo/CodeView/StreamArray.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" @@ -22,49 +22,17 @@ #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstddef> +#include <cstdint> using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; -namespace { -// Some of the values are stored in bitfields. Since this needs to be portable -// across compilers and architectures (big / little endian in particular) we -// can't use the actual structures below, but must instead do the shifting -// and masking ourselves. The struct definitions are provided for reference. - -// struct DbiFlags { -// uint16_t IncrementalLinking : 1; // True if linked incrementally -// uint16_t IsStripped : 1; // True if private symbols were stripped. -// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes. -// uint16_t Reserved : 13; -//}; -const uint16_t FlagIncrementalMask = 0x0001; -const uint16_t FlagStrippedMask = 0x0002; -const uint16_t FlagHasCTypesMask = 0x0004; - -// struct DbiBuildNo { -// uint16_t MinorVersion : 8; -// uint16_t MajorVersion : 7; -// uint16_t NewVersionFormat : 1; -//}; -const uint16_t BuildMinorMask = 0x00FF; -const uint16_t BuildMinorShift = 0; - -const uint16_t BuildMajorMask = 0x7F00; -const uint16_t BuildMajorShift = 8; - -struct FileInfoSubstreamHeader { - ulittle16_t NumModules; // Total # of modules, should match number of - // records in the ModuleInfo substream. - ulittle16_t NumSourceFiles; // Total # of source files. This value is not - // accurate because PDB actually supports more - // than 64k source files, so we ignore it and - // compute the value from other stream fields. -}; -} - template <typename ContribType> static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, StreamReader &Reader) { @@ -81,15 +49,14 @@ static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)), Header(nullptr) { - static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!"); } -DbiStream::~DbiStream() {} +DbiStream::~DbiStream() = default; Error DbiStream::reload() { StreamReader Reader(*Stream); - if (Stream->getLength() < sizeof(HeaderInfo)) + if (Stream->getLength() < sizeof(DbiStreamHeader)) return make_error<RawError>(raw_error_code::corrupt_file, "DBI Stream does not contain a header."); if (auto EC = Reader.readObject(Header)) @@ -116,7 +83,7 @@ Error DbiStream::reload() { "DBI Age does not match PDB Age."); if (Stream->getLength() != - sizeof(HeaderInfo) + Header->ModiSubstreamSize + + sizeof(DbiStreamHeader) + Header->ModiSubstreamSize + Header->SecContrSubstreamSize + Header->SectionMapSize + Header->FileInfoSize + Header->TypeServerSize + Header->OptionalDbgHdrSize + Header->ECSubstreamSize) @@ -142,14 +109,11 @@ Error DbiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "DBI type server substream not aligned."); - // Since each ModInfo in the stream is a variable length, we have to iterate - // them to know how many there actually are. - VarStreamArray<ModInfo> ModInfoArray; - if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize)) + if (auto EC = + Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize)) + return EC; + if (auto EC = initializeModInfoArray()) return EC; - for (auto &Info : ModInfoArray) { - ModuleInfos.emplace_back(Info); - } if (auto EC = Reader.readStreamRef(SecContrSubstream, Header->SecContrSubstreamSize)) @@ -209,25 +173,27 @@ uint16_t DbiStream::getGlobalSymbolStreamIndex() const { uint16_t DbiStream::getFlags() const { return Header->Flags; } bool DbiStream::isIncrementallyLinked() const { - return (Header->Flags & FlagIncrementalMask) != 0; + return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0; } bool DbiStream::hasCTypes() const { - return (Header->Flags & FlagHasCTypesMask) != 0; + return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0; } bool DbiStream::isStripped() const { - return (Header->Flags & FlagStrippedMask) != 0; + return (Header->Flags & DbiFlags::FlagStrippedMask) != 0; } uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } uint16_t DbiStream::getBuildMajorVersion() const { - return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift; + return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >> + DbiBuildNo::BuildMajorShift; } uint16_t DbiStream::getBuildMinorVersion() const { - return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift; + return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >> + DbiBuildNo::BuildMinorShift; } uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } @@ -243,21 +209,20 @@ PDB_Machine DbiStream::getMachineType() const { return static_cast<PDB_Machine>(Machine); } -codeview::FixedStreamArray<object::coff_section> -DbiStream::getSectionHeaders() { +msf::FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() { return SectionHeaders; } -codeview::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { +msf::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() { return FpoRecords; } ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; } -codeview::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { +msf::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { return SectionMap; } -void llvm::pdb::DbiStream::visitSectionContributions( +void DbiStream::visitSectionContributions( ISectionContribVisitor &Visitor) const { if (SectionContribVersion == DbiSecContribVer60) { for (auto &SC : SectionContribs) @@ -285,6 +250,24 @@ Error DbiStream::initializeSectionContributionData() { "Unsupported DBI Section Contribution version"); } +Error DbiStream::initializeModInfoArray() { + if (ModInfoSubstream.getLength() == 0) + return Error::success(); + + // 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); + + VarStreamArray<ModInfo> ModInfoArray; + if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength())) + return EC; + for (auto &Info : ModInfoArray) { + ModuleInfos.emplace_back(Info); + } + + return Error::success(); +} + // Initializes this->SectionHeaders. Error DbiStream::initializeSectionHeadersData() { if (DbgStreams.size() == 0) @@ -294,22 +277,21 @@ Error DbiStream::initializeSectionHeadersData() { if (StreamNum >= Pdb.getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); - auto SHS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); - if (!SHS) - return SHS.takeError(); + auto SHS = MappedBlockStream::createIndexedStream( + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); - size_t StreamLen = (*SHS)->getLength(); + size_t StreamLen = SHS->getLength(); if (StreamLen % sizeof(object::coff_section)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted section header stream."); size_t NumSections = StreamLen / sizeof(object::coff_section); - codeview::StreamReader Reader(**SHS); + msf::StreamReader Reader(*SHS); if (auto EC = Reader.readArray(SectionHeaders, NumSections)) return make_error<RawError>(raw_error_code::corrupt_file, "Could not read a bitmap."); - SectionHeaderStream = std::move(*SHS); + SectionHeaderStream = std::move(SHS); return Error::success(); } @@ -321,27 +303,26 @@ Error DbiStream::initializeFpoRecords() { uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO); // This means there is no FPO data. - if (StreamNum == InvalidStreamIndex) + if (StreamNum == kInvalidStreamIndex) return Error::success(); if (StreamNum >= Pdb.getNumStreams()) return make_error<RawError>(raw_error_code::no_stream); - auto FS = MappedBlockStream::createIndexedStream(StreamNum, Pdb); - if (!FS) - return FS.takeError(); + auto FS = MappedBlockStream::createIndexedStream( + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum); - size_t StreamLen = (*FS)->getLength(); + size_t StreamLen = FS->getLength(); if (StreamLen % sizeof(object::FpoData)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted New FPO stream."); size_t NumRecords = StreamLen / sizeof(object::FpoData); - codeview::StreamReader Reader(**FS); + msf::StreamReader Reader(*FS); if (auto EC = Reader.readArray(FpoRecords, NumRecords)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupted New FPO stream."); - FpoStream = std::move(*FS); + FpoStream = std::move(FS); return Error::success(); } @@ -359,18 +340,6 @@ Error DbiStream::initializeSectionMapData() { } Error DbiStream::initializeFileInfo() { - // The layout of the FileInfoSubstream is like this: - // struct { - // ulittle16_t NumModules; - // ulittle16_t NumSourceFiles; - // ulittle16_t ModIndices[NumModules]; - // ulittle16_t ModFileCounts[NumModules]; - // ulittle32_t FileNameOffsets[NumSourceFiles]; - // char Names[][NumSourceFiles]; - // }; - // with the caveat that `NumSourceFiles` cannot be trusted, so - // it is computed by summing `ModFileCounts`. - // if (FileInfoSubstream.getLength() == 0) return Error::success(); @@ -437,7 +406,10 @@ Error DbiStream::initializeFileInfo() { } uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { - return DbgStreams[static_cast<uint16_t>(Type)]; + uint16_t T = static_cast<uint16_t>(Type); + if (T >= DbgStreams.size()) + return kInvalidStreamIndex; + return DbgStreams[T]; } Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { @@ -452,11 +424,3 @@ Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const { return std::move(EC); return Name; } - -Error DbiStream::commit() { - StreamWriter Writer(*Stream); - if (auto EC = Writer.writeObject(*Header)) - return EC; - - return Error::success(); -} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp index 34ff8ae..1d5b8d6 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp @@ -9,18 +9,28 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.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/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/COFF.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; -DbiStreamBuilder::DbiStreamBuilder() - : Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0), - MachineType(PDB_Machine::x86) {} +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) {} void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } @@ -36,24 +46,207 @@ void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } +void DbiStreamBuilder::setSectionContribs(ArrayRef<SectionContrib> Arr) { + SectionContribs = Arr; +} + +void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) { + SectionMap = SecMap; +} + +Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, + ArrayRef<uint8_t> Data) { + if (DbgStreams[(int)Type].StreamNumber) + return make_error<RawError>(raw_error_code::duplicate_entry, + "The specified stream type already exists"); + auto ExpectedIndex = Msf.addStream(Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + uint32_t Index = std::move(*ExpectedIndex); + DbgStreams[(int)Type].Data = Data; + DbgStreams[(int)Type].StreamNumber = Index; + return Error::success(); +} + uint32_t DbiStreamBuilder::calculateSerializedLength() const { // For now we only support serializing the header. - return sizeof(DbiStream::HeaderInfo); -} - -Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) { - if (!VerHeader.hasValue()) - return make_error<RawError>(raw_error_code::unspecified, - "Missing DBI Stream Version"); - - auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File); - if (!DbiS) - return DbiS.takeError(); - auto DS = std::move(*DbiS); - DbiStream::HeaderInfo *H = - static_cast<DbiStream::HeaderInfo *>(DS->getAllocator().Allocate( - sizeof(DbiStream::HeaderInfo), - llvm::AlignOf<DbiStream::HeaderInfo>::Alignment)); + return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + + calculateModiSubstreamSize() + calculateSectionContribsStreamSize() + + 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))); + if (!Result.second) + return make_error<RawError>(raw_error_code::duplicate_entry, + "The specified module already exists"); + ModuleInfoList.push_back(M); + return Error::success(); +} + +Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { + auto ModIter = ModuleInfos.find(Module); + if (ModIter == ModuleInfos.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); + 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)); +} + +uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const { + if (SectionContribs.empty()) + return 0; + return sizeof(enum PdbRaw_DbiSecContribVer) + + sizeof(SectionContribs[0]) * SectionContribs.size(); +} + +uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const { + if (SectionMap.empty()) + return 0; + return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size(); +} + +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 + uint32_t NumFileInfos = 0; + for (const auto &M : ModuleInfoList) + NumFileInfos += M->SourceFiles.size(); + Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets + Size += calculateNamesBufferSize(); + return alignTo(Size, sizeof(uint32_t)); +} + +uint32_t DbiStreamBuilder::calculateNamesBufferSize() const { + uint32_t Size = 0; + for (const auto &F : SourceFileNames) { + Size += F.getKeyLength() + 1; // Names[I]; + } + return Size; +} + +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)); + + WritableStreamRef MetadataBuffer = + WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset); + StreamWriter MetadataWriter(MetadataBuffer); + + uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size()); + uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); + if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules + return EC; + if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles + return EC; + for (uint16_t I = 0; I < ModiCount; ++I) { + if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices + return EC; + } + for (const auto MI : ModuleInfoList) { + FileCount = static_cast<uint16_t>(MI->SourceFiles.size()); + if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts + return EC; + } + + // Before writing the FileNameOffsets array, write the NamesBuffer array. + // 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); + for (auto &Name : SourceFileNames) { + Name.second = NameBufferWriter.getOffset(); + if (auto EC = NameBufferWriter.writeZeroString(Name.getKey())) + return EC; + } + + for (const auto MI : ModuleInfoList) { + for (StringRef Name : MI->SourceFiles) { + auto Result = SourceFileNames.find(Name); + if (Result == SourceFileNames.end()) + return make_error<RawError>(raw_error_code::no_entry, + "The source file was not found."); + if (auto EC = MetadataWriter.writeInteger(Result->second)) + return EC; + } + } + + if (NameBufferWriter.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::invalid_format, + "The names buffer contained unexpected data."); + + if (MetadataWriter.bytesRemaining() > sizeof(uint32_t)) + return make_error<RawError>( + raw_error_code::invalid_format, + "The metadata buffer contained unexpected data."); + + return Error::success(); +} + +Error DbiStreamBuilder::finalize() { + if (Header) + return Error::success(); + + DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); + + if (auto EC = generateModiSubstream()) + return EC; + if (auto EC = generateFileInfoSubstream()) + return EC; + H->VersionHeader = *VerHeader; H->VersionSignature = -1; H->Age = Age; @@ -64,18 +257,156 @@ Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) { H->MachineType = static_cast<uint16_t>(MachineType); H->ECSubstreamSize = 0; - H->FileInfoSize = 0; - H->ModiSubstreamSize = 0; - H->OptionalDbgHdrSize = 0; - H->SecContrSubstreamSize = 0; - H->SectionMapSize = 0; + H->FileInfoSize = FileInfoBuffer.getLength(); + H->ModiSubstreamSize = ModInfoBuffer.getLength(); + H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); + H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); + H->SectionMapSize = calculateSectionMapStreamSize(); H->TypeServerSize = 0; - H->SymRecordStreamIndex = DbiStream::InvalidStreamIndex; - H->PublicSymbolStreamIndex = DbiStream::InvalidStreamIndex; - H->MFCTypeServerIndex = DbiStream::InvalidStreamIndex; - H->GlobalSymbolStreamIndex = DbiStream::InvalidStreamIndex; - - auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS)); - Dbi->Header = H; - return std::move(Dbi); + H->SymRecordStreamIndex = kInvalidStreamIndex; + H->PublicSymbolStreamIndex = kInvalidStreamIndex; + H->MFCTypeServerIndex = kInvalidStreamIndex; + H->GlobalSymbolStreamIndex = kInvalidStreamIndex; + + Header = H; + return Error::success(); +} + +Error DbiStreamBuilder::finalizeMsfLayout() { + uint32_t Length = calculateSerializedLength(); + if (auto EC = Msf.setStreamSize(StreamDBI, Length)) + return EC; + return Error::success(); +} + +static uint16_t toSecMapFlags(uint32_t Flags) { + uint16_t Ret = 0; + if (Flags & COFF::IMAGE_SCN_MEM_READ) + Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read); + if (Flags & COFF::IMAGE_SCN_MEM_WRITE) + Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write); + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute); + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute); + if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT)) + Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit); + + // This seems always 1. + Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector); + + return Ret; +} + +// A utility function to create Section Contributions +// for a given input sections. +std::vector<SectionContrib> DbiStreamBuilder::createSectionContribs( + ArrayRef<object::coff_section> SecHdrs) { + std::vector<SectionContrib> Ret; + + // Create a SectionContrib for each input section. + for (auto &Sec : SecHdrs) { + Ret.emplace_back(); + auto &Entry = Ret.back(); + memset(&Entry, 0, sizeof(Entry)); + + Entry.Off = Sec.PointerToRawData; + Entry.Size = Sec.SizeOfRawData; + Entry.Characteristics = Sec.Characteristics; + } + return Ret; +} + +// A utility function to create a Section Map for a given list of COFF sections. +// +// A Section Map seem to be a copy of a COFF section list in other format. +// I don't know why a PDB file contains both a COFF section header and +// a Section Map, but it seems it must be present in a PDB. +std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap( + ArrayRef<llvm::object::coff_section> SecHdrs) { + std::vector<SecMapEntry> Ret; + int Idx = 0; + + auto Add = [&]() -> SecMapEntry & { + Ret.emplace_back(); + auto &Entry = Ret.back(); + memset(&Entry, 0, sizeof(Entry)); + + Entry.Frame = Idx + 1; + + // We don't know the meaning of these fields yet. + Entry.SecName = UINT16_MAX; + Entry.ClassName = UINT16_MAX; + + return Entry; + }; + + for (auto &Hdr : SecHdrs) { + auto &Entry = Add(); + Entry.Flags = toSecMapFlags(Hdr.Characteristics); + Entry.SecByteLength = Hdr.VirtualSize; + ++Idx; + } + + // The last entry is for absolute symbols. + auto &Entry = Add(); + Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) | + static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress); + Entry.SecByteLength = UINT32_MAX; + + return Ret; +} + +Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, + const msf::WritableStream &Buffer) { + if (auto EC = finalize()) + return EC; + + auto InfoS = + WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI); + + StreamWriter Writer(*InfoS); + if (auto EC = Writer.writeObject(*Header)) + return EC; + + if (auto EC = Writer.writeStreamRef(ModInfoBuffer)) + return EC; + + if (!SectionContribs.empty()) { + if (auto EC = Writer.writeEnum(DbiSecContribVer60)) + return EC; + if (auto EC = Writer.writeArray(SectionContribs)) + return EC; + } + + if (!SectionMap.empty()) { + ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size()); + SecMapHeader SMHeader = {Size, Size}; + if (auto EC = Writer.writeObject(SMHeader)) + return EC; + if (auto EC = Writer.writeArray(SectionMap)) + return EC; + } + + if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) + return EC; + + for (auto &Stream : DbgStreams) + if (auto EC = Writer.writeInteger(Stream.StreamNumber)) + return EC; + + for (auto &Stream : DbgStreams) { + if (Stream.StreamNumber == kInvalidStreamIndex) + continue; + auto WritableStream = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, Stream.StreamNumber); + StreamWriter DbgStreamWriter(*WritableStream); + if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) + return EC; + } + + if (Writer.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::invalid_format, + "Unexpected bytes found in DBI Stream"); + return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.cpp new file mode 100644 index 0000000..6ecbb5c --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.cpp @@ -0,0 +1,93 @@ +//===- GSI.cpp - Common Functions for GlobalsStream and PublicsStream ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/Support/Error.h" + +namespace llvm { +namespace pdb { + +static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { + if (HashHdr->VerHdr != GSIHashHeader::HdrVersion) + return make_error<RawError>( + raw_error_code::feature_unsupported, + "Encountered unsupported globals stream version."); + + return Error::success(); +} + +Error readGSIHashBuckets( + msf::FixedStreamArray<support::ulittle32_t> &HashBuckets, + const GSIHashHeader *HashHdr, msf::StreamReader &Reader) { + if (auto EC = checkHashHdrVersion(HashHdr)) + return EC; + + // Before the actual hash buckets, there is a bitmap of length determined by + // IPHR_HASH. + ArrayRef<uint8_t> Bitmap; + size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); + uint32_t NumBitmapEntries = BitmapSizeInBits / 8; + if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a bitmap.")); + uint32_t NumBuckets = 0; + for (uint8_t B : Bitmap) + NumBuckets += countPopulation(B); + + // Hash buckets follow. + if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Hash buckets corrupted.")); + + return Error::success(); +} + +Error readGSIHashHeader(const GSIHashHeader *&HashHdr, + msf::StreamReader &Reader) { + if (Reader.readObject(HashHdr)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Stream does not contain a GSIHashHeader."); + + if (HashHdr->VerSignature != GSIHashHeader::HdrSignature) + return make_error<RawError>( + raw_error_code::feature_unsupported, + "GSIHashHeader signature (0xffffffff) not found."); + + return Error::success(); +} + +Error readGSIHashRecords(msf::FixedStreamArray<PSHashRecord> &HashRecords, + const GSIHashHeader *HashHdr, + msf::StreamReader &Reader) { + if (auto EC = checkHashHdrVersion(HashHdr)) + return EC; + + // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have. + // Verify that we can read them all. + if (HashHdr->HrSize % sizeof(PSHashRecord)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid HR array size."); + uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); + if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Error reading hash records.")); + + return Error::success(); +} +} +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.h b/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.h new file mode 100644 index 0000000..82cebd9 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/GSI.h @@ -0,0 +1,70 @@ +//===- GSI.h - Common Declarations for GlobalsStream and PublicsStream ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The data structures defined in this file are based on the reference +// implementation which is available at +// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h +// +// When you are reading the reference source code, you'd find the +// information below useful. +// +// - ppdb1->m_fMinimalDbgInfo seems to be always true. +// - SMALLBUCKETS macro is defined. +// +// The reference doesn't compile, so I learned just by reading code. +// It's not guaranteed to be correct. +// +//===----------------------------------------------------------------------===// + +#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/Support/Endian.h" +#include "llvm/Support/Error.h" + +namespace llvm { + +namespace msf { +class StreamReader; +} + +namespace pdb { + +/// From https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp +static const unsigned IPHR_HASH = 4096; + +/// Header of the hash tables found in the globals and publics sections. +/// Based on GSIHashHeader in +/// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h +struct GSIHashHeader { + enum : unsigned { + HdrSignature = ~0U, + HdrVersion = 0xeffe0000 + 19990810, + }; + support::ulittle32_t VerSignature; + support::ulittle32_t VerHdr; + support::ulittle32_t HrSize; + support::ulittle32_t NumBuckets; +}; + +Error readGSIHashBuckets( + msf::FixedStreamArray<support::ulittle32_t> &HashBuckets, + const GSIHashHeader *HashHdr, msf::StreamReader &Reader); +Error readGSIHashHeader(const GSIHashHeader *&HashHdr, + msf::StreamReader &Reader); +Error readGSIHashRecords(msf::FixedStreamArray<PSHashRecord> &HashRecords, + const GSIHashHeader *HashHdr, + msf::StreamReader &Reader); +} +} + +#endif diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/GlobalsStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/GlobalsStream.cpp new file mode 100644 index 0000000..31afc92 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/GlobalsStream.cpp @@ -0,0 +1,42 @@ +//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---- ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GSI.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h" +#include "llvm/Support/Error.h" +#include <algorithm> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; + +GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +GlobalsStream::~GlobalsStream() = default; + +Error GlobalsStream::reload() { + StreamReader Reader(*Stream); + + const GSIHashHeader *HashHdr; + if (auto EC = readGSIHashHeader(HashHdr, Reader)) + return EC; + + if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) + return EC; + + if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader)) + return EC; + NumBuckets = HashBuckets.size(); + + return Error::success(); +} + +Error GlobalsStream::commit() { return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp index 23cb557..b9f685e 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/Hash.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/JamCRC.h" using namespace llvm; using namespace llvm::support; @@ -73,59 +74,13 @@ uint32_t pdb::hashStringV2(StringRef Str) { Hash ^= (Hash >> 6); } - return Hash * 1664525L + 1013904223L; + return Hash * 1664525U + 1013904223U; } -static const uint32_t V8HashTable[] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, - 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, - 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, - 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, - 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, - 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, - 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, - 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, - 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, - 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, - 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, - 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, - 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, - 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, - 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, - 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, - 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, - 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, -}; - // Corresponds to `SigForPbCb` in langapi/shared/crc32.h. uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) { - uint32_t Hash = 0; - for (uint8_t Byte : Buf) - Hash = (Hash >> 8) ^ V8HashTable[(Hash & 0xff) ^ Byte]; - return Hash; + JamCRC JC(/*Init=*/0U); + JC.update(makeArrayRef<char>(reinterpret_cast<const char *>(Buf.data()), + Buf.size())); + return JC.getCRC(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp deleted file mode 100644 index 9bd16ea..0000000 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===- IndexedStreamData.cpp - Standard PDB Stream Data ---------*- 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/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" - -using namespace llvm; -using namespace llvm::pdb; - -IndexedStreamData::IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File) - : StreamIdx(StreamIdx), File(File) {} - -uint32_t IndexedStreamData::getLength() { - return File.getStreamByteSize(StreamIdx); -} - -ArrayRef<support::ulittle32_t> IndexedStreamData::getStreamBlocks() { - return File.getStreamBlockList(StreamIdx); -} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp index c33a764..f19535d 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -10,24 +10,25 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.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() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); - const HeaderInfo *H; + const InfoStreamHeader *H; if (auto EC = Reader.readObject(H)) return joinErrors( std::move(EC), @@ -74,17 +75,3 @@ uint32_t InfoStream::getSignature() const { return Signature; } uint32_t InfoStream::getAge() const { return Age; } PDB_UniqueId InfoStream::getGuid() const { return Guid; } - -Error InfoStream::commit() { - StreamWriter Writer(*Stream); - - HeaderInfo H; - H.Age = Age; - H.Signature = Signature; - H.Version = Version; - H.Guid = Guid; - if (auto EC = Writer.writeObject(H)) - return EC; - - return NamedStreams.commit(Writer); -} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp index 7be9cc3..73fbf85 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp @@ -9,16 +9,20 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.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/MappedBlockStream.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; -InfoStreamBuilder::InfoStreamBuilder() {} +InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf) + : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Sig(-1), Age(0) {} void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } @@ -33,35 +37,29 @@ NameMapBuilder &InfoStreamBuilder::getNamedStreamsBuilder() { } uint32_t InfoStreamBuilder::calculateSerializedLength() const { - return sizeof(InfoStream::HeaderInfo) + - NamedStreams.calculateSerializedLength(); + return sizeof(InfoStreamHeader) + NamedStreams.calculateSerializedLength(); } -Expected<std::unique_ptr<InfoStream>> InfoStreamBuilder::build(PDBFile &File) { - if (!Ver.hasValue()) - return make_error<RawError>(raw_error_code::unspecified, - "Missing PDB Stream Version"); - if (!Sig.hasValue()) - return make_error<RawError>(raw_error_code::unspecified, - "Missing PDB Stream Signature"); - if (!Age.hasValue()) - return make_error<RawError>(raw_error_code::unspecified, - "Missing PDB Stream Age"); - if (!Guid.hasValue()) - return make_error<RawError>(raw_error_code::unspecified, - "Missing PDB Stream Guid"); +Error InfoStreamBuilder::finalizeMsfLayout() { + uint32_t Length = calculateSerializedLength(); + if (auto EC = Msf.setStreamSize(StreamPDB, Length)) + return EC; + return Error::success(); +} + +Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, + const msf::WritableStream &Buffer) const { + auto InfoS = + WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB); + StreamWriter Writer(*InfoS); + + InfoStreamHeader H; + H.Age = Age; + H.Signature = Sig; + H.Version = Ver; + H.Guid = Guid; + if (auto EC = Writer.writeObject(H)) + return EC; - auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, File); - if (!InfoS) - return InfoS.takeError(); - auto Info = llvm::make_unique<InfoStream>(std::move(*InfoS)); - Info->Version = *Ver; - Info->Signature = *Sig; - Info->Age = *Age; - Info->Guid = *Guid; - auto NS = NamedStreams.build(); - if (!NS) - return NS.takeError(); - Info->NamedStreams = **NS; - return std::move(Info); + return NamedStreams.commit(Writer); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp deleted file mode 100644 index 92b2048..0000000 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ /dev/null @@ -1,310 +0,0 @@ -//===- MappedBlockStream.cpp - Reads stream data from a PDBFile -----------===// -// -// 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/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" - -using namespace llvm; -using namespace llvm::pdb; - -namespace { -// This exists so that we can use make_unique while still keeping the -// constructor of MappedBlockStream private, forcing users to go through -// the `create` interface. -class MappedBlockStreamImpl : public MappedBlockStream { -public: - MappedBlockStreamImpl(std::unique_ptr<IPDBStreamData> Data, - const IPDBFile &File) - : MappedBlockStream(std::move(Data), File) {} -}; -} - -typedef std::pair<uint32_t, uint32_t> Interval; -static Interval intersect(const Interval &I1, const Interval &I2) { - return std::make_pair(std::max(I1.first, I2.first), - std::min(I1.second, I2.second)); -} - -MappedBlockStream::MappedBlockStream(std::unique_ptr<IPDBStreamData> Data, - const IPDBFile &Pdb) - : Pdb(Pdb), Data(std::move(Data)) {} - -Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { - // Make sure we aren't trying to read beyond the end of the stream. - if (Size > Data->getLength()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - if (Offset > Data->getLength() - Size) - return make_error<RawError>(raw_error_code::insufficient_buffer); - - if (tryReadContiguously(Offset, Size, Buffer)) - return Error::success(); - - auto CacheIter = CacheMap.find(Offset); - if (CacheIter != CacheMap.end()) { - // Try to find an alloc that was large enough for this request. - for (auto &Entry : CacheIter->second) { - if (Entry.size() >= Size) { - Buffer = Entry.slice(0, Size); - return Error::success(); - } - } - } - - // We couldn't find a buffer that started at the correct offset (the most - // common scenario). Try to see if there is a buffer that starts at some - // other offset but overlaps the desired range. - for (auto &CacheItem : CacheMap) { - Interval RequestExtent = std::make_pair(Offset, Offset + Size); - - // We already checked this one on the fast path above. - if (CacheItem.first == Offset) - continue; - // If the initial extent of the cached item is beyond the ending extent - // of the request, there is no overlap. - if (CacheItem.first >= Offset + Size) - continue; - - // We really only have to check the last item in the list, since we append - // in order of increasing length. - if (CacheItem.second.empty()) - continue; - - auto CachedAlloc = CacheItem.second.back(); - // If the initial extent of the request is beyond the ending extent of - // the cached item, there is no overlap. - Interval CachedExtent = - std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); - if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) - continue; - - Interval Intersection = intersect(CachedExtent, RequestExtent); - // Only use this if the entire request extent is contained in the cached - // extent. - if (Intersection != RequestExtent) - continue; - - uint32_t CacheRangeOffset = - AbsoluteDifference(CachedExtent.first, Intersection.first); - Buffer = CachedAlloc.slice(CacheRangeOffset, Size); - return Error::success(); - } - - // Otherwise allocate a large enough buffer in the pool, memcpy the data - // into it, and return an ArrayRef to that. Do not touch existing pool - // allocations, as existing clients may be holding a pointer which must - // not be invalidated. - uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8)); - if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size))) - return EC; - - if (CacheIter != CacheMap.end()) { - CacheIter->second.emplace_back(WriteBuffer, Size); - } else { - std::vector<CacheEntry> List; - List.emplace_back(WriteBuffer, Size); - CacheMap.insert(std::make_pair(Offset, List)); - } - Buffer = ArrayRef<uint8_t>(WriteBuffer, Size); - return Error::success(); -} - -Error MappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { - // Make sure we aren't trying to read beyond the end of the stream. - if (Offset >= Data->getLength()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - uint32_t First = Offset / Pdb.getBlockSize(); - uint32_t Last = First; - - auto BlockList = Data->getStreamBlocks(); - while (Last < Pdb.getBlockCount() - 1) { - if (BlockList[Last] != BlockList[Last + 1] - 1) - break; - ++Last; - } - - uint32_t OffsetInFirstBlock = Offset % Pdb.getBlockSize(); - uint32_t BytesFromFirstBlock = Pdb.getBlockSize() - OffsetInFirstBlock; - uint32_t BlockSpan = Last - First + 1; - uint32_t ByteSpan = - BytesFromFirstBlock + (BlockSpan - 1) * Pdb.getBlockSize(); - auto Result = Pdb.getBlockData(BlockList[First], Pdb.getBlockSize()); - if (!Result) - return Result.takeError(); - Buffer = Result->drop_front(OffsetInFirstBlock); - Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan); - return Error::success(); -} - -uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } - -Error MappedBlockStream::commit() const { return Error::success(); } - -bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) const { - // Attempt to fulfill the request with a reference directly into the stream. - // This can work even if the request crosses a block boundary, provided that - // all subsequent blocks are contiguous. For example, a 10k read with a 4k - // block size can be filled with a reference if, from the starting offset, - // 3 blocks in a row are contiguous. - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - uint32_t BytesFromFirstBlock = - std::min(Size, Pdb.getBlockSize() - OffsetInBlock); - uint32_t NumAdditionalBlocks = - llvm::alignTo(Size - BytesFromFirstBlock, Pdb.getBlockSize()) / - Pdb.getBlockSize(); - - auto BlockList = Data->getStreamBlocks(); - uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; - uint32_t E = BlockList[BlockNum]; - for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { - if (BlockList[I + BlockNum] != E) - return false; - } - - uint32_t FirstBlockAddr = BlockList[BlockNum]; - auto Result = Pdb.getBlockData(FirstBlockAddr, Pdb.getBlockSize()); - if (!Result) { - consumeError(Result.takeError()); - return false; - } - auto Data = Result->drop_front(OffsetInBlock); - Buffer = ArrayRef<uint8_t>(Data.data(), Size); - return true; -} - -Error MappedBlockStream::readBytes(uint32_t Offset, - MutableArrayRef<uint8_t> Buffer) const { - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - - // Make sure we aren't trying to read beyond the end of the stream. - if (Buffer.size() > Data->getLength()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - if (Offset > Data->getLength() - Buffer.size()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - - uint32_t BytesLeft = Buffer.size(); - uint32_t BytesWritten = 0; - uint8_t *WriteBuffer = Buffer.data(); - auto BlockList = Data->getStreamBlocks(); - while (BytesLeft > 0) { - uint32_t StreamBlockAddr = BlockList[BlockNum]; - - auto Result = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize()); - if (!Result) - return Result.takeError(); - - auto Data = *Result; - const uint8_t *ChunkStart = Data.data() + OffsetInBlock; - uint32_t BytesInChunk = - std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock); - ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); - - BytesWritten += BytesInChunk; - BytesLeft -= BytesInChunk; - ++BlockNum; - OffsetInBlock = 0; - } - - return Error::success(); -} - -Error MappedBlockStream::writeBytes(uint32_t Offset, - ArrayRef<uint8_t> Buffer) const { - // Make sure we aren't trying to write beyond the end of the stream. - if (Buffer.size() > Data->getLength()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - - if (Offset > Data->getLength() - Buffer.size()) - return make_error<RawError>(raw_error_code::insufficient_buffer); - - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - - uint32_t BytesLeft = Buffer.size(); - auto BlockList = Data->getStreamBlocks(); - uint32_t BytesWritten = 0; - while (BytesLeft > 0) { - uint32_t StreamBlockAddr = BlockList[BlockNum]; - uint32_t BytesToWriteInChunk = - std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock); - - const uint8_t *Chunk = Buffer.data() + BytesWritten; - ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk); - if (auto EC = Pdb.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData)) - return EC; - - BytesLeft -= BytesToWriteInChunk; - BytesWritten += BytesToWriteInChunk; - ++BlockNum; - OffsetInBlock = 0; - } - - // If this write overlapped a read which previously came from the pool, - // someone may still be holding a pointer to that alloc which is now invalid. - // Compute the overlapping range and update the cache entry, so any - // outstanding buffers are automatically updated. - for (const auto &MapEntry : CacheMap) { - // If the end of the written extent precedes the beginning of the cached - // extent, ignore this map entry. - if (Offset + BytesWritten < MapEntry.first) - continue; - for (const auto &Alloc : MapEntry.second) { - // If the end of the cached extent precedes the beginning of the written - // extent, ignore this alloc. - if (MapEntry.first + Alloc.size() < Offset) - continue; - - // If we get here, they are guaranteed to overlap. - Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten); - Interval CachedInterval = - std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); - // If they overlap, we need to write the new data into the overlapping - // range. - auto Intersection = intersect(WriteInterval, CachedInterval); - assert(Intersection.first <= Intersection.second); - - uint32_t Length = Intersection.second - Intersection.first; - uint32_t SrcOffset = - AbsoluteDifference(WriteInterval.first, Intersection.first); - uint32_t DestOffset = - AbsoluteDifference(CachedInterval.first, Intersection.first); - ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length); - } - } - - return Error::success(); -} - -uint32_t MappedBlockStream::getNumBytesCopied() const { - return static_cast<uint32_t>(Pool.getBytesAllocated()); -} - -Expected<std::unique_ptr<MappedBlockStream>> -MappedBlockStream::createIndexedStream(uint32_t StreamIdx, - const IPDBFile &File) { - if (StreamIdx >= File.getNumStreams()) - return make_error<RawError>(raw_error_code::no_stream); - - auto Data = llvm::make_unique<IndexedStreamData>(StreamIdx, File); - return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File); -} - -Expected<std::unique_ptr<MappedBlockStream>> -MappedBlockStream::createDirectoryStream(const PDBFile &File) { - auto Data = llvm::make_unique<DirectoryStreamData>(File); - return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File); -} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp index bae135f..b34d770 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp @@ -7,76 +7,27 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" - -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawTypes.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; -namespace { - -struct SCBytes { - ulittle16_t Section; - char Padding1[2]; - little32_t Offset; - little32_t Size; - ulittle32_t Characteristics; - ulittle16_t ModuleIndex; - char Padding2[2]; - ulittle32_t DataCrc; - ulittle32_t RelocCrc; -}; - -// struct Flags { -// uint16_t fWritten : 1; // True if ModInfo is dirty -// uint16_t fECEnabled : 1; // Is EC symbolic info present? (What is EC?) -// uint16_t unused : 6; // Reserved -// uint16_t iTSM : 8; // Type Server Index for this module -//}; -const uint16_t HasECFlagMask = 0x2; - -const uint16_t TypeServerIndexMask = 0xFF00; -const uint16_t TypeServerIndexShift = 8; -} +ModInfo::ModInfo() = default; + +ModInfo::ModInfo(const ModInfo &Info) = default; -struct ModInfo::FileLayout { - ulittle32_t Mod; // Currently opened module. This field is a - // pointer in the reference implementation, but - // that won't work on 64-bit systems, and anyway - // it doesn't make sense to read a pointer from a - // file. For now it is unused, so just ignore it. - SCBytes SC; // First section contribution of this module. - ulittle16_t Flags; // See Flags definition. - ulittle16_t ModDiStream; // Stream Number of module debug info - ulittle32_t SymBytes; // Size of local symbol debug info in above stream - ulittle32_t LineBytes; // Size of line number debug info in above stream - ulittle32_t C13Bytes; // Size of C13 line number info in above stream - ulittle16_t NumFiles; // Number of files contributing to this module - char Padding1[2]; // Padding so the next field is 4-byte aligned. - ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets. - // This field is a pointer in the reference - // implementation, but as with `Mod`, we ignore it - // for now since it is unused. - ulittle32_t SrcFileNameNI; // Name Index for src file name - ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB - // Null terminated Module name - // Null terminated Obj File Name -}; - -ModInfo::ModInfo() : Layout(nullptr) {} - -ModInfo::ModInfo(const ModInfo &Info) - : ModuleName(Info.ModuleName), ObjFileName(Info.ObjFileName), - Layout(Info.Layout) {} - -ModInfo::~ModInfo() {} - -Error ModInfo::initialize(codeview::StreamRef Stream, ModInfo &Info) { - codeview::StreamReader Reader(Stream); +ModInfo::~ModInfo() = default; + +Error ModInfo::initialize(ReadableStreamRef Stream, ModInfo &Info) { + StreamReader Reader(Stream); if (auto EC = Reader.readObject(Info.Layout)) return EC; @@ -88,10 +39,13 @@ Error ModInfo::initialize(codeview::StreamRef Stream, ModInfo &Info) { return Error::success(); } -bool ModInfo::hasECInfo() const { return (Layout->Flags & HasECFlagMask) != 0; } +bool ModInfo::hasECInfo() const { + return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0; +} uint16_t ModInfo::getTypeServerIndex() const { - return (Layout->Flags & TypeServerIndexMask) >> TypeServerIndexShift; + return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >> + ModInfoFlags::TypeServerIndexShift; } uint16_t ModInfo::getModuleStreamIndex() const { return Layout->ModDiStream; } @@ -121,7 +75,7 @@ StringRef ModInfo::getObjFileName() const { return ObjFileName; } uint32_t ModInfo::getRecordLength() const { uint32_t M = ModuleName.str().size() + 1; uint32_t O = ObjFileName.str().size() + 1; - uint32_t Size = sizeof(FileLayout) + M + O; - Size = llvm::alignTo(Size, 4); + uint32_t Size = sizeof(ModuleInfoHeader) + M + O; + Size = alignTo(Size, 4); return Size; } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp index 3415fcd..0ffc5b7 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -7,39 +7,43 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/ModStream.h" - -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.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/Support/Error.h" +#include <algorithm> +#include <cstdint> using namespace llvm; +using namespace llvm::msf; using namespace llvm::pdb; ModStream::ModStream(const ModInfo &Module, std::unique_ptr<MappedBlockStream> Stream) : Mod(Module), Stream(std::move(Stream)) {} -ModStream::~ModStream() {} +ModStream::~ModStream() = default; Error ModStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getLineInfoByteSize(); uint32_t C13Size = Mod.getC13LineInfoByteSize(); if (C11Size > 0 && C13Size > 0) - return llvm::make_error<RawError>(raw_error_code::corrupt_file, - "Module has both C11 and C13 line info"); + return make_error<RawError>(raw_error_code::corrupt_file, + "Module has both C11 and C13 line info"); - codeview::StreamRef S; + ReadableStreamRef S; - uint32_t SymbolSubstreamSig = 0; - if (auto EC = Reader.readInteger(SymbolSubstreamSig)) + if (auto EC = Reader.readInteger(Signature)) return EC; if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) return EC; @@ -49,7 +53,7 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - codeview::StreamReader LineReader(C13LinesSubstream); + StreamReader LineReader(C13LinesSubstream); if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) return EC; @@ -59,8 +63,8 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize)) return EC; if (Reader.bytesRemaining() > 0) - return llvm::make_error<RawError>(raw_error_code::corrupt_file, - "Unexpected bytes in module stream."); + return make_error<RawError>(raw_error_code::corrupt_file, + "Unexpected bytes in module stream."); return Error::success(); } @@ -69,14 +73,13 @@ iterator_range<codeview::CVSymbolArray::Iterator> ModStream::symbols(bool *HadError) const { // It's OK if the stream is empty. if (SymbolsSubstream.getUnderlyingStream().getLength() == 0) - return llvm::make_range(SymbolsSubstream.end(), SymbolsSubstream.end()); - return llvm::make_range(SymbolsSubstream.begin(HadError), - SymbolsSubstream.end()); + return make_range(SymbolsSubstream.end(), SymbolsSubstream.end()); + return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end()); } iterator_range<codeview::ModuleSubstreamArray::Iterator> ModStream::lines(bool *HadError) const { - return llvm::make_range(LineInfo.begin(HadError), LineInfo.end()); + return make_range(LineInfo.begin(HadError), LineInfo.end()); } Error ModStream::commit() { return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp index ae4ebf2..84cccb35 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -10,18 +10,19 @@ #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/Hash.h" #include "llvm/DebugInfo/PDB/Raw/RawError.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) {} -Error NameHashTable::load(codeview::StreamReader &Stream) { +Error NameHashTable::load(StreamReader &Stream) { struct Header { support::ulittle32_t Signature; support::ulittle32_t HashVersion; @@ -72,7 +73,7 @@ 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; - codeview::StreamReader NameReader(NamesBuffer); + StreamReader NameReader(NamesBuffer); NameReader.setOffset(ID); if (auto EC = NameReader.readZeroString(Result)) consumeError(std::move(EC)); @@ -98,7 +99,6 @@ uint32_t NameHashTable::getIDForString(StringRef Str) const { return IDs[0]; } -codeview::FixedStreamArray<support::ulittle32_t> -NameHashTable::name_ids() const { +FixedStreamArray<support::ulittle32_t> NameHashTable::name_ids() const { return IDs; } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp index b8a4eb7..0f55f58 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp @@ -7,20 +7,24 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/ADT/SparseBitVector.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.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::codeview; +using namespace llvm::msf; using namespace llvm::pdb; -NameMap::NameMap() {} - -Error NameMap::load(codeview::StreamReader &Stream) { +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; @@ -145,63 +149,9 @@ Error NameMap::load(codeview::StreamReader &Stream) { return Error::success(); } -Error NameMap::commit(codeview::StreamWriter &Writer) { - // 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 = Mapping.begin(), E = Mapping.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 = Mapping.begin(), E = Mapping.end(); B != E; ++B) { - if (auto EC = Writer.writeZeroString(B->getKey())) - return EC; - } - - if (auto EC = Writer.writeInteger(Mapping.size())) // Hash Size - return EC; - - if (auto EC = Writer.writeInteger(Mapping.size())) // Max Number of Strings - return EC; - - if (auto EC = Writer.writeInteger(Mapping.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 = Mapping.begin(), E = Mapping.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 = Mapping.begin(), E = Mapping.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(); -} - iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const { - return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), - Mapping.end()); + return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), + Mapping.end()); } bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const { diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp index 41c6c2c..f570d59 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/NameMapBuilder.cpp @@ -7,15 +7,19 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h" - +#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() {} +NameMapBuilder::NameMapBuilder() = default; void NameMapBuilder::addMapping(StringRef Name, uint32_t Mapping) { StringDataBytes += Name.size() + 1; @@ -48,3 +52,57 @@ uint32_t NameMapBuilder::calculateSerializedLength() const { 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/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp index 9501675..5349151 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -7,68 +7,84 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" - #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/StreamArray.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.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/DirectoryStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.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/Support/Endian.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; namespace { typedef FixedStreamArray<support::ulittle32_t> ulittle_array; -} +} // end anonymous namespace -PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer) - : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {} +PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer, + BumpPtrAllocator &Allocator) + : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} -PDBFile::~PDBFile() {} +PDBFile::~PDBFile() = default; -uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; } +uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } -uint32_t PDBFile::getFreeBlockMapBlock() const { return SB->FreeBlockMapBlock; } +uint32_t PDBFile::getFreeBlockMapBlock() const { + return ContainerLayout.SB->FreeBlockMapBlock; +} -uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; } +uint32_t PDBFile::getBlockCount() const { + return ContainerLayout.SB->NumBlocks; +} -uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; } +uint32_t PDBFile::getNumDirectoryBytes() const { + return ContainerLayout.SB->NumDirectoryBytes; +} -uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; } +uint32_t PDBFile::getBlockMapIndex() const { + return ContainerLayout.SB->BlockMapAddr; +} -uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; } +uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } uint32_t PDBFile::getNumDirectoryBlocks() const { - return msf::bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); + return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, + ContainerLayout.SB->BlockSize); } uint64_t PDBFile::getBlockMapOffset() const { - return (uint64_t)SB->BlockMapAddr * SB->BlockSize; + return (uint64_t)ContainerLayout.SB->BlockMapAddr * + ContainerLayout.SB->BlockSize; } -uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); } +uint32_t PDBFile::getNumStreams() const { + return ContainerLayout.StreamSizes.size(); +} uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { - return StreamSizes[StreamIndex]; + return ContainerLayout.StreamSizes[StreamIndex]; } ArrayRef<support::ulittle32_t> PDBFile::getStreamBlockList(uint32_t StreamIndex) const { - return StreamMap[StreamIndex]; + return ContainerLayout.StreamMap[StreamIndex]; } uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } @@ -85,41 +101,72 @@ Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, ArrayRef<uint8_t> Data) const { - if (Offset >= getBlockSize()) - return make_error<RawError>( - raw_error_code::invalid_block_address, - "setBlockData attempted to write out of block bounds."); - if (Data.size() > getBlockSize() - Offset) - return make_error<RawError>( - raw_error_code::invalid_block_address, - "setBlockData attempted to write out of block bounds."); - - uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); - StreamBlockOffset += Offset; - return Buffer->writeBytes(StreamBlockOffset, Data); + return make_error<RawError>(raw_error_code::not_writable, + "PDBFile is immutable"); } Error PDBFile::parseFileHeaders() { StreamReader Reader(*Buffer); + // Initialize SB. + const msf::SuperBlock *SB = nullptr; if (auto EC = Reader.readObject(SB)) { consumeError(std::move(EC)); return make_error<RawError>(raw_error_code::corrupt_file, "Does not contain superblock"); } - if (auto EC = setSuperBlock(SB)) + if (auto EC = msf::validateSuperBlock(*SB)) + return EC; + + if (Buffer->getLength() % SB->BlockSize != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "File size is not a multiple of block size"); + ContainerLayout.SB = SB; + + // Initialize Free Page Map. + ContainerLayout.FreePageMap.resize(SB->NumBlocks); + // The Fpm exists either at block 1 or block 2 of the MSF. However, this + // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and + // thusly an equal number of total blocks in the file. For a block size + // of 4KiB (very common), this would yield 32KiB total blocks in file, for a + // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so + // the Fpm is split across the file at `getBlockSize()` intervals. As a + // result, every block whose index is of the form |{1,2} + getBlockSize() * k| + // for any non-negative integer k is an Fpm block. In theory, we only really + // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but + // current versions of the MSF format already expect the Fpm to be arranged + // at getBlockSize() intervals, so we have to be compatible. + // 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); + ArrayRef<uint8_t> FpmBytes; + if (auto EC = FpmReader.readBytes(FpmBytes, + msf::getFullFpmByteSize(ContainerLayout))) return EC; + uint32_t BlocksRemaining = getBlockCount(); + uint32_t BI = 0; + for (auto Byte : FpmBytes) { + uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U); + for (uint32_t I = 0; I < BlocksThisByte; ++I) { + if (Byte & (1 << I)) + ContainerLayout.FreePageMap[BI] = true; + --BlocksRemaining; + ++BI; + } + } Reader.setOffset(getBlockMapOffset()); - if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks())) + if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks, + getNumDirectoryBlocks())) return EC; return Error::success(); } Error PDBFile::parseStreamData() { - assert(SB); + assert(ContainerLayout.SB); if (DirectoryStream) return Error::success(); @@ -130,21 +177,20 @@ Error PDBFile::parseStreamData() { // is exactly what we are attempting to parse. By specifying a custom // subclass of IPDBStreamData which only accesses the fields that have already // been parsed, we can avoid this and reuse MappedBlockStream. - auto DS = MappedBlockStream::createDirectoryStream(*this); - if (!DS) - return DS.takeError(); - StreamReader Reader(**DS); + auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer); + StreamReader Reader(*DS); if (auto EC = Reader.readInteger(NumStreams)) return EC; - if (auto EC = Reader.readArray(StreamSizes, NumStreams)) + if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams)) return EC; for (uint32_t I = 0; I < NumStreams; ++I) { uint32_t StreamSize = getStreamByteSize(I); // FIXME: What does StreamSize ~0U mean? uint64_t NumExpectedStreamBlocks = - StreamSize == UINT32_MAX ? 0 : msf::bytesToBlocks(StreamSize, - SB->BlockSize); + StreamSize == UINT32_MAX + ? 0 + : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize); // For convenience, we store the block array contiguously. This is because // if someone calls setStreamMap(), it is more convenient to be able to call @@ -156,29 +202,46 @@ Error PDBFile::parseStreamData() { if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) return EC; for (uint32_t Block : Blocks) { - uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize; + uint64_t BlockEndOffset = + (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize; if (BlockEndOffset > getFileSize()) return make_error<RawError>(raw_error_code::corrupt_file, "Stream block map is corrupt."); } - StreamMap.push_back(Blocks); + ContainerLayout.StreamMap.push_back(Blocks); } // We should have read exactly SB->NumDirectoryBytes bytes. assert(Reader.bytesRemaining() == 0); - DirectoryStream = std::move(*DS); + DirectoryStream = std::move(DS); return Error::success(); } -llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { - return DirectoryBlocks; +ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { + return ContainerLayout.DirectoryBlocks; +} + +Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { + if (!Globals) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto GlobalS = safelyCreateIndexedStream( + ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex()); + if (!GlobalS) return GlobalS.takeError(); + auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS)); + if (auto EC = TempGlobals->reload()) + return std::move(EC); + Globals = std::move(TempGlobals); + } + return *Globals; } Expected<InfoStream &> PDBFile::getPDBInfoStream() { if (!Info) { - auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this); - if (!InfoS) - return InfoS.takeError(); + auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB); + if (!InfoS) return InfoS.takeError(); auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS)); if (auto EC = TempInfo->reload()) return std::move(EC); @@ -189,9 +252,8 @@ Expected<InfoStream &> PDBFile::getPDBInfoStream() { Expected<DbiStream &> PDBFile::getPDBDbiStream() { if (!Dbi) { - auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this); - if (!DbiS) - return DbiS.takeError(); + auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI); + if (!DbiS) return DbiS.takeError(); auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS)); if (auto EC = TempDbi->reload()) return std::move(EC); @@ -202,9 +264,8 @@ Expected<DbiStream &> PDBFile::getPDBDbiStream() { Expected<TpiStream &> PDBFile::getPDBTpiStream() { if (!Tpi) { - auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this); - if (!TpiS) - return TpiS.takeError(); + auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI); + if (!TpiS) return TpiS.takeError(); auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS)); if (auto EC = TempTpi->reload()) return std::move(EC); @@ -215,9 +276,8 @@ Expected<TpiStream &> PDBFile::getPDBTpiStream() { Expected<TpiStream &> PDBFile::getPDBIpiStream() { if (!Ipi) { - auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this); - if (!IpiS) - return IpiS.takeError(); + auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI); + if (!IpiS) return IpiS.takeError(); auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS)); if (auto EC = TempIpi->reload()) return std::move(EC); @@ -232,12 +292,9 @@ Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { if (!DbiS) return DbiS.takeError(); - uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex(); - - auto PublicS = - MappedBlockStream::createIndexedStream(PublicsStreamNum, *this); - if (!PublicS) - return PublicS.takeError(); + auto PublicS = safelyCreateIndexedStream( + ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); + if (!PublicS) return PublicS.takeError(); auto TempPublics = llvm::make_unique<PublicsStream>(*this, std::move(*PublicS)); if (auto EC = TempPublics->reload()) @@ -254,11 +311,10 @@ Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { return DbiS.takeError(); uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); - auto SymbolS = - MappedBlockStream::createIndexedStream(SymbolStreamNum, *this); - if (!SymbolS) - return SymbolS.takeError(); + safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum); + if (!SymbolS) return SymbolS.takeError(); + auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS)); if (auto EC = TempSymbols->reload()) return std::move(EC); @@ -275,14 +331,9 @@ Expected<NameHashTable &> PDBFile::getStringTable() { uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names"); - if (NameStreamIndex == 0) - return make_error<RawError>(raw_error_code::no_stream); - if (NameStreamIndex >= getNumStreams()) - return make_error<RawError>(raw_error_code::no_stream); - - auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this); - if (!NS) - return NS.takeError(); + auto NS = + safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex); + if (!NS) return NS.takeError(); StreamReader Reader(**NS); auto N = llvm::make_unique<NameHashTable>(); @@ -294,72 +345,47 @@ Expected<NameHashTable &> PDBFile::getStringTable() { return *StringTable; } -Error PDBFile::setSuperBlock(const msf::SuperBlock *Block) { - if (auto EC = msf::validateSuperBlock(*Block)) - return EC; - - if (Buffer->getLength() % SB->BlockSize != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "File size is not a multiple of block size"); +bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); } - SB = Block; - return Error::success(); +bool PDBFile::hasPDBGlobalsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) return false; + return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); } -Error PDBFile::commit() { - StreamWriter Writer(*Buffer); - - if (auto EC = Writer.writeObject(*SB)) - return EC; - Writer.setOffset(getBlockMapOffset()); - if (auto EC = Writer.writeArray(DirectoryBlocks)) - return EC; - - auto DS = MappedBlockStream::createDirectoryStream(*this); - if (!DS) - return DS.takeError(); - auto DirStream = std::move(*DS); - StreamWriter DW(*DirStream); - if (auto EC = DW.writeInteger(this->getNumStreams())) - return EC; - - if (auto EC = DW.writeArray(StreamSizes)) - return EC; - - for (const auto &Blocks : StreamMap) { - if (auto EC = DW.writeArray(Blocks)) - return EC; - } - - if (Info) { - if (auto EC = Info->commit()) - return EC; - } +bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); } - if (Dbi) { - if (auto EC = Dbi->commit()) - return EC; - } +bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); } - if (Symbols) { - if (auto EC = Symbols->commit()) - return EC; - } +bool PDBFile::hasPDBPublicsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) return false; + return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); +} - if (Publics) { - if (auto EC = Publics->commit()) - return EC; - } +bool PDBFile::hasPDBSymbolStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) return false; + return DbiS->getSymRecordStreamIndex() < getNumStreams(); +} - if (Tpi) { - if (auto EC = Tpi->commit()) - return EC; - } +bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } - if (Ipi) { - if (auto EC = Ipi->commit()) - return EC; - } +bool PDBFile::hasStringTable() { + auto IS = getPDBInfoStream(); + if (!IS) return false; + return IS->getNamedStreamIndex("/names") < getNumStreams(); +} - return Buffer->commit(); +/// 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 { + if (StreamIndex >= getNumStreams()) + return make_error<RawError>(raw_error_code::no_stream); + return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp index 9063fd6..6fec0e3 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp @@ -11,92 +11,138 @@ #include "llvm/ADT/BitVector.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.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" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; -PDBFileBuilder::PDBFileBuilder( - std::unique_ptr<codeview::StreamInterface> FileBuffer) - : File(llvm::make_unique<PDBFile>(std::move(FileBuffer))) {} +PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) + : Allocator(Allocator) {} -Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) { - auto ExpectedMsf = - MsfBuilder::create(File->Allocator, Super.BlockSize, Super.NumBlocks); +Error PDBFileBuilder::initialize(uint32_t BlockSize) { + auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); if (!ExpectedMsf) return ExpectedMsf.takeError(); - - auto &MsfResult = *ExpectedMsf; - if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr)) - return EC; - Msf = llvm::make_unique<MsfBuilder>(std::move(MsfResult)); - Msf->setFreePageMap(Super.FreeBlockMapBlock); - Msf->setUnknown1(Super.Unknown1); + Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); return Error::success(); } -MsfBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } +MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { if (!Info) - Info = llvm::make_unique<InfoStreamBuilder>(); + Info = llvm::make_unique<InfoStreamBuilder>(*Msf); return *Info; } DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { if (!Dbi) - Dbi = llvm::make_unique<DbiStreamBuilder>(); + Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf); return *Dbi; } -Expected<std::unique_ptr<PDBFile>> PDBFileBuilder::build() { +TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { + if (!Tpi) + Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); + return *Tpi; +} + +TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { + if (!Ipi) + Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); + return *Ipi; +} + +Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const { if (Info) { - uint32_t Length = Info->calculateSerializedLength(); - if (auto EC = Msf->setStreamSize(StreamPDB, Length)) + if (auto EC = Info->finalizeMsfLayout()) return std::move(EC); } if (Dbi) { - uint32_t Length = Dbi->calculateSerializedLength(); - if (auto EC = Msf->setStreamSize(StreamDBI, Length)) + if (auto EC = Dbi->finalizeMsfLayout()) return std::move(EC); } + if (Tpi) { + if (auto EC = Tpi->finalizeMsfLayout()) + return std::move(EC); + } + if (Ipi) { + if (auto EC = Ipi->finalizeMsfLayout()) + return std::move(EC); + } + + return Msf->build(); +} - auto ExpectedLayout = Msf->build(); +Error PDBFileBuilder::commit(StringRef Filename) { + auto ExpectedLayout = finalizeMsfLayout(); if (!ExpectedLayout) return ExpectedLayout.takeError(); + auto &Layout = *ExpectedLayout; - const msf::Layout &L = *ExpectedLayout; - File->StreamMap = L.StreamMap; - File->StreamSizes = L.StreamSizes; - File->DirectoryBlocks = L.DirectoryBlocks; - File->SB = L.SB; + uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; + auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); + if (OutFileOrError.getError()) + return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, + Filename); + FileBufferByteStream Buffer(std::move(*OutFileOrError)); + StreamWriter Writer(Buffer); + + if (auto EC = Writer.writeObject(*Layout.SB)) + return EC; + uint32_t BlockMapOffset = + msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); + Writer.setOffset(BlockMapOffset); + if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) + return EC; + + auto DirStream = + WritableMappedBlockStream::createDirectoryStream(Layout, Buffer); + StreamWriter DW(*DirStream); + if (auto EC = + DW.writeInteger(static_cast<uint32_t>(Layout.StreamSizes.size()))) + return EC; + + if (auto EC = DW.writeArray(Layout.StreamSizes)) + return EC; + + for (const auto &Blocks : Layout.StreamMap) { + if (auto EC = DW.writeArray(Blocks)) + return EC; + } if (Info) { - auto ExpectedInfo = Info->build(*File); - if (!ExpectedInfo) - return ExpectedInfo.takeError(); - File->Info = std::move(*ExpectedInfo); + if (auto EC = Info->commit(Layout, Buffer)) + return EC; } if (Dbi) { - auto ExpectedDbi = Dbi->build(*File); - if (!ExpectedDbi) - return ExpectedDbi.takeError(); - File->Dbi = std::move(*ExpectedDbi); + if (auto EC = Dbi->commit(Layout, Buffer)) + return EC; } - if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge()) - return llvm::make_error<RawError>( - raw_error_code::corrupt_file, - "PDB Stream Age doesn't match Dbi Stream Age!"); + if (Tpi) { + if (auto EC = Tpi->commit(Layout, Buffer)) + return EC; + } + + if (Ipi) { + if (auto EC = Ipi->commit(Layout, Buffer)) + return EC; + } - return std::move(File); + return Buffer.commit(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp index af3d2d0..b31f605 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp @@ -22,30 +22,25 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" - -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.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/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" - -#include "llvm/ADT/BitVector.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> using namespace llvm; +using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; - -static const unsigned IPHR_HASH = 4096; - // This is PSGSIHDR struct defined in // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h struct PublicsStream::HeaderInfo { @@ -59,23 +54,11 @@ struct PublicsStream::HeaderInfo { ulittle32_t NumSections; }; -// This is GSIHashHdr. -struct PublicsStream::GSIHashHeader { - enum : unsigned { - HdrSignature = ~0U, - HdrVersion = 0xeffe0000 + 19990810, - }; - ulittle32_t VerSignature; - ulittle32_t VerHdr; - ulittle32_t HrSize; - ulittle32_t NumBuckets; -}; - PublicsStream::PublicsStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)) {} -PublicsStream::~PublicsStream() {} +PublicsStream::~PublicsStream() = default; uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } @@ -86,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() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); // Check stream size. if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) @@ -98,40 +81,15 @@ Error PublicsStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Publics Stream does not contain a header."); - if (Reader.readObject(HashHdr)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Publics Stream does not contain a header."); + if (auto EC = readGSIHashHeader(HashHdr, Reader)) + return EC; - // An array of HashRecord follows. Read them. - if (HashHdr->HrSize % sizeof(PSHashRecord)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid HR array size."); - uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); - if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read an HR array")); + if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) + return EC; - // A bitmap of a fixed length follows. - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 8; - if (auto EC = Reader.readBytes(Bitmap, NumBitmapEntries)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read a bitmap.")); - for (uint8_t B : Bitmap) - NumBuckets += countPopulation(B); - - // We don't yet understand the following data structures completely, - // but we at least know the types and sizes. Here we are trying - // to read the stream till end so that we at least can detect - // corrupted streams. - - // Hash buckets follow. - if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Hash buckets corrupted.")); + if (auto EC = readGSIHashBuckets(HashBuckets, HashHdr, Reader)) + return EC; + NumBuckets = HashBuckets.size(); // Something called "address map" follows. uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); @@ -163,7 +121,7 @@ PublicsStream::getSymbols(bool *HadError) const { auto SymbolS = Pdb.getPDBSymbolStream(); if (SymbolS.takeError()) { codeview::CVSymbolArray::Iterator Iter; - return llvm::make_range(Iter, Iter); + return make_range(Iter, Iter); } SymbolStream &SS = SymbolS.get(); diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp index eb169f7..f4a5057 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp @@ -11,7 +11,7 @@ namespace { // deal with the Error value directly, rather than converting to error_code. class RawErrorCategory : public std::error_category { public: - const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.raw"; } + const char *name() const noexcept override { return "llvm.pdb.raw"; } std::string message(int Condition) const override { switch (static_cast<raw_error_code>(Condition)) { @@ -19,6 +19,8 @@ public: return "An unknown error has occurred."; case raw_error_code::feature_unsupported: return "The feature is unsupported by the implementation."; + case raw_error_code::invalid_format: + return "The record is in an unexpected format."; case raw_error_code::corrupt_file: return "The PDB file is corrupt."; case raw_error_code::insufficient_buffer: @@ -30,6 +32,10 @@ public: return "The specified item does not exist in the array."; case raw_error_code::invalid_block_address: return "The specified block address is not valid."; + case raw_error_code::duplicate_entry: + return "The entry already exists."; + case raw_error_code::no_entry: + return "The entry does not exist."; case raw_error_code::not_writable: return "The PDB does not support writing."; case raw_error_code::invalid_tpi_hash: diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp index 455d331..cd3a206 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp @@ -7,10 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" - -#include "llvm/DebugInfo/CodeView/ByteStream.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#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" @@ -18,59 +16,51 @@ #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; -namespace { -// We need a class which behaves like an immutable ByteStream, but whose data -// is backed by an llvm::MemoryBuffer. It also needs to own the underlying -// MemoryBuffer, so this simple adapter is a good way to achieve that. -class InputByteStream : public codeview::ByteStream<false> { -public: - explicit InputByteStream(std::unique_ptr<MemoryBuffer> Buffer) - : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(), - Buffer->getBuffer().bytes_end())), - MemBuffer(std::move(Buffer)) {} - - std::unique_ptr<MemoryBuffer> MemBuffer; -}; -} - -RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile) - : Pdb(std::move(PdbFile)) {} +RawSession::RawSession(std::unique_ptr<PDBFile> PdbFile, + std::unique_ptr<BumpPtrAllocator> Allocator) + : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)) {} -RawSession::~RawSession() {} +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 llvm::make_error<GenericError>(generic_error_code::invalid_path); + return make_error<GenericError>(generic_error_code::invalid_path); std::unique_ptr<MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); - auto Stream = llvm::make_unique<InputByteStream>(std::move(Buffer)); + auto Stream = llvm::make_unique<MemoryBufferByteStream>(std::move(Buffer)); - std::unique_ptr<PDBFile> File(new PDBFile(std::move(Stream))); + 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.reset(new RawSession(std::move(File))); + 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 llvm::make_error<RawError>(raw_error_code::feature_unsupported); + return make_error<RawError>(raw_error_code::feature_unsupported); } uint64_t RawSession::getLoadAddress() const { return 0; } @@ -103,26 +93,26 @@ RawSession::findLineNumbersByAddress(uint64_t Address, uint32_t Length) const { std::unique_ptr<IPDBEnumSourceFiles> RawSession::findSourceFiles(const PDBSymbolCompiland *Compiland, - llvm::StringRef Pattern, + StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<IPDBSourceFile> RawSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, - llvm::StringRef Pattern, + StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> -RawSession::findCompilandsForSourceFile(llvm::StringRef Pattern, +RawSession::findCompilandsForSourceFile(StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } std::unique_ptr<PDBSymbolCompiland> -RawSession::findOneCompilandForSourceFile(llvm::StringRef Pattern, +RawSession::findOneCompilandForSourceFile(StringRef Pattern, PDB_NameSearchFlags Flags) const { return nullptr; } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp index 41b2a64..2f3ac34 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp @@ -10,10 +10,9 @@ #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.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" @@ -21,6 +20,7 @@ #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; @@ -30,7 +30,7 @@ SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) SymbolStream::~SymbolStream() {} Error SymbolStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) return EC; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiHashing.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiHashing.cpp new file mode 100644 index 0000000..6c3ddb3 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiHashing.cpp @@ -0,0 +1,110 @@ +//===- TpiHashing.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Raw/TpiHashing.h" + +#include "llvm/DebugInfo/PDB/Raw/Hash.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Corresponds to `fUDTAnon`. +template <typename T> static bool isAnonymous(T &Rec) { + StringRef Name = Rec.getName(); + return Name == "<unnamed-tag>" || Name == "__unnamed" || + Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); +} + +// Computes a hash for a given TPI record. +template <typename T> +static uint32_t getTpiHash(T &Rec, ArrayRef<uint8_t> FullRecord) { + auto Opts = static_cast<uint16_t>(Rec.getOptions()); + + bool ForwardRef = + Opts & static_cast<uint16_t>(ClassOptions::ForwardReference); + bool Scoped = Opts & static_cast<uint16_t>(ClassOptions::Scoped); + bool UniqueName = Opts & static_cast<uint16_t>(ClassOptions::HasUniqueName); + bool IsAnon = UniqueName && isAnonymous(Rec); + + if (!ForwardRef && !Scoped && !IsAnon) + return hashStringV1(Rec.getName()); + if (!ForwardRef && UniqueName && !IsAnon) + return hashStringV1(Rec.getUniqueName()); + return hashBufferV8(FullRecord); +} + +template <typename T> static uint32_t getSourceLineHash(T &Rec) { + char Buf[4]; + support::endian::write32le(Buf, Rec.getUDT().getIndex()); + return hashStringV1(StringRef(Buf, 4)); +} + +void TpiHashUpdater::visitKnownRecordImpl(CVType &CVR, + UdtSourceLineRecord &Rec) { + CVR.Hash = getSourceLineHash(Rec); +} + +void TpiHashUpdater::visitKnownRecordImpl(CVType &CVR, + UdtModSourceLineRecord &Rec) { + CVR.Hash = getSourceLineHash(Rec); +} + +void TpiHashUpdater::visitKnownRecordImpl(CVType &CVR, ClassRecord &Rec) { + CVR.Hash = getTpiHash(Rec, CVR.data()); +} + +void TpiHashUpdater::visitKnownRecordImpl(CVType &CVR, EnumRecord &Rec) { + CVR.Hash = getTpiHash(Rec, CVR.data()); +} + +void TpiHashUpdater::visitKnownRecordImpl(CVType &CVR, UnionRecord &Rec) { + CVR.Hash = getTpiHash(Rec, CVR.data()); +} + +Error TpiHashVerifier::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &Rec) { + return verifySourceLine(Rec.getUDT()); +} + +Error TpiHashVerifier::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Rec) { + return verifySourceLine(Rec.getUDT()); +} + +Error TpiHashVerifier::visitKnownRecord(CVType &CVR, ClassRecord &Rec) { + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); +} +Error TpiHashVerifier::visitKnownRecord(CVType &CVR, EnumRecord &Rec) { + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); +} +Error TpiHashVerifier::visitKnownRecord(CVType &CVR, UnionRecord &Rec) { + if (getTpiHash(Rec, CVR.data()) % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); +} + +Error TpiHashVerifier::verifySourceLine(codeview::TypeIndex TI) { + char Buf[4]; + support::endian::write32le(Buf, TI.getIndex()); + uint32_t Hash = hashStringV1(StringRef(Buf, 4)); + if (Hash % NumHashBuckets != HashValues[Index]) + return errorInvalidHash(); + return Error::success(); +} + +Error TpiHashVerifier::visitTypeBegin(CVType &Rec) { + ++Index; + RawRecord = Rec; + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp index 5617e57..a1167cd 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -7,155 +7,55 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" - +#include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Raw/Hash.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.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/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> +#include <vector> using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; +using namespace llvm::msf; using namespace llvm::pdb; -namespace { -const uint32_t MinHashBuckets = 0x1000; -const uint32_t MaxHashBuckets = 0x40000; -} - -// This corresponds to `HDR` in PDB/dbi/tpi.h. -struct TpiStream::HeaderInfo { - struct EmbeddedBuf { - little32_t Off; - ulittle32_t Length; - }; - - ulittle32_t Version; - ulittle32_t HeaderSize; - ulittle32_t TypeIndexBegin; - ulittle32_t TypeIndexEnd; - ulittle32_t TypeRecordBytes; - - // The following members correspond to `TpiHash` in PDB/dbi/tpi.h. - ulittle16_t HashStreamIndex; - ulittle16_t HashAuxStreamIndex; - ulittle32_t HashKeySize; - ulittle32_t NumHashBuckets; - - EmbeddedBuf HashValueBuffer; - EmbeddedBuf IndexOffsetBuffer; - EmbeddedBuf HashAdjBuffer; -}; - TpiStream::TpiStream(const PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) : Pdb(File), Stream(std::move(Stream)) {} -TpiStream::~TpiStream() {} - -// Corresponds to `fUDTAnon`. -template <typename T> static bool isAnonymous(T &Rec) { - StringRef Name = Rec.getName(); - return Name == "<unnamed-tag>" || Name == "__unnamed" || - Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); -} - -// Computes a hash for a given TPI record. -template <typename T> -static uint32_t getTpiHash(T &Rec, const CVRecord<TypeLeafKind> &RawRec) { - auto Opts = static_cast<uint16_t>(Rec.getOptions()); - - bool ForwardRef = - Opts & static_cast<uint16_t>(ClassOptions::ForwardReference); - bool Scoped = Opts & static_cast<uint16_t>(ClassOptions::Scoped); - bool UniqueName = Opts & static_cast<uint16_t>(ClassOptions::HasUniqueName); - bool IsAnon = UniqueName && isAnonymous(Rec); - - if (!ForwardRef && !Scoped && !IsAnon) - return hashStringV1(Rec.getName()); - if (!ForwardRef && UniqueName && !IsAnon) - return hashStringV1(Rec.getUniqueName()); - return hashBufferV8(RawRec.RawData); -} - -namespace { -class TpiHashVerifier : public TypeVisitorCallbacks { -public: - TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues, - uint32_t NumHashBuckets) - : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} - - Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override { - return verifySourceLine(Rec); - } - - Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override { - return verifySourceLine(Rec); - } - - Error visitClass(ClassRecord &Rec) override { return verify(Rec); } - Error visitEnum(EnumRecord &Rec) override { return verify(Rec); } - Error visitUnion(UnionRecord &Rec) override { return verify(Rec); } - - Error visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) override { - ++Index; - RawRecord = &Rec; - return Error::success(); - } - -private: - template <typename T> Error verify(T &Rec) { - uint32_t Hash = getTpiHash(Rec, *RawRecord); - if (Hash % NumHashBuckets != HashValues[Index]) - return errorInvalidHash(); - return Error::success(); - } - - template <typename T> Error verifySourceLine(T &Rec) { - char Buf[4]; - support::endian::write32le(Buf, Rec.getUDT().getIndex()); - uint32_t Hash = hashStringV1(StringRef(Buf, 4)); - if (Hash % NumHashBuckets != HashValues[Index]) - return errorInvalidHash(); - return Error::success(); - } - - Error errorInvalidHash() { - return make_error<RawError>( - raw_error_code::invalid_tpi_hash, - "Type index is 0x" + utohexstr(TypeIndex::FirstNonSimpleIndex + Index)); - } - - FixedStreamArray<support::ulittle32_t> HashValues; - const CVRecord<TypeLeafKind> *RawRecord; - uint32_t NumHashBuckets; - uint32_t Index = -1; -}; -} +TpiStream::~TpiStream() = default; // Verifies that a given type record matches with a given hash value. // Currently we only verify SRC_LINE records. Error TpiStream::verifyHashValues() { TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets); - CVTypeVisitor Visitor(Verifier); + TypeDeserializer Deserializer; + + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Verifier); + + CVTypeVisitor Visitor(Pipeline); return Visitor.visitTypeStream(TypeRecords); } Error TpiStream::reload() { StreamReader Reader(*Stream); - if (Reader.bytesRemaining() < sizeof(HeaderInfo)) + if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream does not contain a header."); @@ -167,7 +67,7 @@ Error TpiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "Unsupported TPI Version."); - if (Header->HeaderSize != sizeof(HeaderInfo)) + if (Header->HeaderSize != sizeof(TpiStreamHeader)) return make_error<RawError>(raw_error_code::corrupt_file, "Corrupt TPI Header size."); @@ -175,8 +75,8 @@ Error TpiStream::reload() { return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream expected 4 byte hash key size."); - if (Header->NumHashBuckets < MinHashBuckets || - Header->NumHashBuckets > MaxHashBuckets) + if (Header->NumHashBuckets < MinTpiHashBuckets || + Header->NumHashBuckets > MaxTpiHashBuckets) return make_error<RawError>(raw_error_code::corrupt_file, "TPI Stream Invalid number of hash buckets."); @@ -185,43 +85,47 @@ Error TpiStream::reload() { return EC; // Hash indices, hash values, etc come from the hash stream. - if (Header->HashStreamIndex >= Pdb.getNumStreams()) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid TPI hash stream index."); - - auto HS = - MappedBlockStream::createIndexedStream(Header->HashStreamIndex, Pdb); - if (!HS) - return HS.takeError(); - StreamReader HSR(**HS); - - uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); - if (NumHashValues != NumTypeRecords()) - return make_error<RawError>( - raw_error_code::corrupt_file, - "TPI hash count does not match with the number of type records."); - HSR.setOffset(Header->HashValueBuffer.Off); - if (auto EC = HSR.readArray(HashValues, NumHashValues)) - return EC; - - HSR.setOffset(Header->IndexOffsetBuffer.Off); - uint32_t NumTypeIndexOffsets = - Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); - 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; - - 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 (Header->HashStreamIndex != kInvalidStreamIndex) { + if (Header->HashStreamIndex >= Pdb.getNumStreams()) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid TPI hash stream index."); + + auto HS = MappedBlockStream::createIndexedStream( + Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); + StreamReader HSR(*HS); + + uint32_t NumHashValues = + Header->HashValueBuffer.Length / sizeof(ulittle32_t); + if (NumHashValues != NumTypeRecords()) + return make_error<RawError>( + raw_error_code::corrupt_file, + "TPI hash count does not match with the number of type records."); + HSR.setOffset(Header->HashValueBuffer.Off); + if (auto EC = HSR.readArray(HashValues, NumHashValues)) + return EC; + std::vector<ulittle32_t> HashValueList; + for (auto I : HashValues) + HashValueList.push_back(I); + + HSR.setOffset(Header->IndexOffsetBuffer.Off); + uint32_t NumTypeIndexOffsets = + Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset); + 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; + + 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; + } return Error::success(); } @@ -267,7 +171,7 @@ TpiStream::getHashAdjustments() const { iterator_range<CVTypeArray::Iterator> TpiStream::types(bool *HadError) const { - return llvm::make_range(TypeRecords.begin(HadError), TypeRecords.end()); + return make_range(TypeRecords.begin(HadError), TypeRecords.end()); } Error TpiStream::commit() { return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp new file mode 100644 index 0000000..c769321 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/PDB/Raw/TpiStreamBuilder.cpp @@ -0,0 +1,145 @@ +//===- TpiStreamBuilder.cpp - -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::support; + +TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx) + : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) { +} + +TpiStreamBuilder::~TpiStreamBuilder() = default; + +void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) { + VerHeader = Version; +} + +void TpiStreamBuilder::addTypeRecord(const codeview::CVType &Record) { + TypeRecords.push_back(Record); + TypeRecordStream.setItems(TypeRecords); +} + +Error TpiStreamBuilder::finalize() { + if (Header) + return Error::success(); + + 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->HashStreamIndex = HashStreamIndex; + H->HashAuxStreamIndex = kInvalidStreamIndex; + H->HashKeySize = sizeof(ulittle32_t); + H->NumHashBuckets = MinTpiHashBuckets; + + // Recall that hash values go into a completely different stream identified by + // 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->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; + + Header = H; + return Error::success(); +} + +uint32_t TpiStreamBuilder::calculateSerializedLength() const { + return sizeof(TpiStreamHeader) + TypeRecordStream.getLength(); +} + +uint32_t TpiStreamBuilder::calculateHashBufferSize() const { + if (TypeRecords.empty() || !TypeRecords[0].Hash.hasValue()) + return 0; + return TypeRecords.size() * sizeof(ulittle32_t); +} + +Error TpiStreamBuilder::finalizeMsfLayout() { + uint32_t Length = calculateSerializedLength(); + if (auto EC = Msf.setStreamSize(Idx, Length)) + return EC; + + uint32_t HashBufferSize = calculateHashBufferSize(); + + if (HashBufferSize == 0) + return Error::success(); + + auto ExpectedIndex = Msf.addStream(HashBufferSize); + 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; + } + 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) { + if (auto EC = finalize()) + return EC; + + auto InfoS = + WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); + + StreamWriter Writer(*InfoS); + if (auto EC = Writer.writeObject(*Header)) + return EC; + + auto RecordArray = VarStreamArray<codeview::CVType>(TypeRecordStream); + if (auto EC = Writer.writeArray(RecordArray)) + return EC; + + if (HashStreamIndex != kInvalidStreamIndex) { + auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, + HashStreamIndex); + StreamWriter HW(*HVS); + if (auto EC = HW.writeStreamRef(*HashValueStream)) + return EC; + } + + return Error::success(); +} diff --git a/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp index adbe0cb..7e56859 100644 --- a/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/contrib/llvm/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -391,10 +391,11 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { // If this is a COFF object containing PDB info, use a PDBContext to // symbolize. Otherwise, use DWARF. if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) { - const debug_pdb_info *PDBInfo; + const codeview::DebugInfo *DebugInfo; StringRef PDBFileName; - auto EC = CoffObject->getDebugPDBInfo(PDBInfo, PDBFileName); - if (!EC && PDBInfo != nullptr) { + auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName); + if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) { +#if 0 using namespace pdb; std::unique_ptr<IPDBSession> Session; if (auto Err = loadDataForEXE(PDB_ReaderType::DIA, @@ -404,6 +405,11 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { return std::move(Err); } Context.reset(new PDBContext(*CoffObject, std::move(Session))); +#else + return make_error<StringError>( + "PDB support not compiled in", + std::make_error_code(std::errc::not_supported)); +#endif } } if (!Context) |