diff options
author | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2017-04-02 17:24:58 +0000 |
commit | 60b571e49a90d38697b3aca23020d9da42fc7d7f (patch) | |
tree | 99351324c24d6cb146b6285b6caffa4d26fce188 /contrib/llvm/lib/DebugInfo | |
parent | bea1b22c7a9bce1dfdd73e6e5b65bc4752215180 (diff) | |
download | FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.zip FreeBSD-src-60b571e49a90d38697b3aca23020d9da42fc7d7f.tar.gz |
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release:
MFC r309142 (by emaste):
Add WITH_LLD_AS_LD build knob
If set it installs LLD as /usr/bin/ld. LLD (as of version 3.9) is not
capable of linking the world and kernel, but can self-host and link many
substantial applications. GNU ld continues to be used for the world and
kernel build, regardless of how this knob is set.
It is on by default for arm64, and off for all other CPU architectures.
Sponsored by: The FreeBSD Foundation
MFC r310840:
Reapply 310775, now it also builds correctly if lldb is disabled:
Move llvm-objdump from CLANG_EXTRAS to installed by default
We currently install three tools from binutils 2.17.50: as, ld, and
objdump. Work is underway to migrate to a permissively-licensed
tool-chain, with one goal being the retirement of binutils 2.17.50.
LLVM's llvm-objdump is intended to be compatible with GNU objdump
although it is currently missing some options and may have formatting
differences. Enable it by default for testing and further investigation.
It may later be changed to install as /usr/bin/objdump, it becomes a
fully viable replacement.
Reviewed by: emaste
Differential Revision: https://reviews.freebsd.org/D8879
MFC r312855 (by emaste):
Rename LLD_AS_LD to LLD_IS_LD, for consistency with CLANG_IS_CC
Reported by: Dan McGregor <dan.mcgregor usask.ca>
MFC r313559 | glebius | 2017-02-10 18:34:48 +0100 (Fri, 10 Feb 2017) | 5 lines
Don't check struct rtentry on FreeBSD, it is an internal kernel structure.
On other systems it may be API structure for SIOCADDRT/SIOCDELRT.
Reviewed by: emaste, dim
MFC r314152 (by jkim):
Remove an assembler flag, which is redundant since r309124. The upstream
took care of it by introducing a macro NO_EXEC_STACK_DIRECTIVE.
http://llvm.org/viewvc/llvm-project?rev=273500&view=rev
Reviewed by: dim
MFC r314564:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
4.0.0 (branches/release_40 296509). The release will follow soon.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Also note that as of 4.0.0, lld should be able to link the base system
on amd64 and aarch64. See the WITH_LLD_IS_LLD setting in src.conf(5).
Though please be aware that this is work in progress.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/4.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/4.0.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Jan Beich, Antoine Brodin and Eric Fiselier for
their help.
Relnotes: yes
Exp-run: antoine
PR: 215969, 216008
MFC r314708:
For now, revert r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
This commit is the cause of excessive compile times on skein_block.c
(and possibly other files) during kernel builds on amd64.
We never saw the problematic behavior described in this upstream commit,
so for now it is better to revert it. An upstream bug has been filed
here: https://bugs.llvm.org/show_bug.cgi?id=32142
Reported by: mjg
MFC r314795:
Reapply r287232 from upstream llvm trunk (by Daniil Fukalov):
[SCEV] limit recursion depth of CompareSCEVComplexity
Summary:
CompareSCEVComplexity goes too deep (50+ on a quite a big unrolled
loop) and runs almost infinite time.
Added cache of "equal" SCEV pairs to earlier cutoff of further
estimation. Recursion depth limit was also introduced as a parameter.
Reviewers: sanjoy
Subscribers: mzolotukhin, tstellarAMD, llvm-commits
Differential Revision: https://reviews.llvm.org/D26389
Pull in r296992 from upstream llvm trunk (by Sanjoy Das):
[SCEV] Decrease the recursion threshold for CompareValueComplexity
Fixes PR32142.
r287232 accidentally increased the recursion threshold for
CompareValueComplexity from 2 to 32. This change reverses that
change by introducing a separate flag for CompareValueComplexity's
threshold.
The latter revision fixes the excessive compile times for skein_block.c.
MFC r314907 | mmel | 2017-03-08 12:40:27 +0100 (Wed, 08 Mar 2017) | 7 lines
Unbreak ARMv6 world.
The new compiler_rt library imported with clang 4.0.0 have several fatal
issues (non-functional __udivsi3 for example) with ARM specific instrict
functions. As temporary workaround, until upstream solve these problems,
disable all thumb[1][2] related feature.
MFC r315016:
Update clang, llvm, lld, lldb, compiler-rt and libc++ to 4.0.0 release.
We were already very close to the last release candidate, so this is a
pretty minor update.
Relnotes: yes
MFC r316005:
Revert r314907, and pull in r298713 from upstream compiler-rt trunk (by
Weiming Zhao):
builtins: Select correct code fragments when compiling for Thumb1/Thum2/ARM ISA.
Summary:
Value of __ARM_ARCH_ISA_THUMB isn't based on the actual compilation
mode (-mthumb, -marm), it reflect's capability of given CPU.
Due to this:
- use __tbumb__ and __thumb2__ insteand of __ARM_ARCH_ISA_THUMB
- use '.thumb' directive consistently in all affected files
- decorate all thumb functions using
DEFINE_COMPILERRT_THUMB_FUNCTION()
---------
Note: This patch doesn't fix broken Thumb1 variant of __udivsi3 !
Reviewers: weimingz, rengolin, compnerd
Subscribers: aemerson, dim
Differential Revision: https://reviews.llvm.org/D30938
Discussed with: mmel
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) |