diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/lib/DebugInfo | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/DebugInfo')
169 files changed, 32982 insertions, 32982 deletions
diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp index 4d8b15530b..6aaa8f581d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp @@ -1,112 +1,112 @@ -//===- AppendingTypeTableBuilder.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -TypeIndex AppendingTypeTableBuilder::nextTypeIndex() const { - return TypeIndex::fromArrayIndex(SeenRecords.size()); -} - -AppendingTypeTableBuilder::AppendingTypeTableBuilder(BumpPtrAllocator &Storage) - : RecordStorage(Storage) {} - -AppendingTypeTableBuilder::~AppendingTypeTableBuilder() = default; - -Optional<TypeIndex> AppendingTypeTableBuilder::getFirst() { - if (empty()) - return None; - - return TypeIndex(TypeIndex::FirstNonSimpleIndex); -} - -Optional<TypeIndex> AppendingTypeTableBuilder::getNext(TypeIndex Prev) { - if (++Prev == nextTypeIndex()) - return None; - return Prev; -} - -CVType AppendingTypeTableBuilder::getType(TypeIndex Index){ - return CVType(SeenRecords[Index.toArrayIndex()]); -} - -StringRef AppendingTypeTableBuilder::getTypeName(TypeIndex Index) { - llvm_unreachable("Method not implemented"); -} - -bool AppendingTypeTableBuilder::contains(TypeIndex Index) { - if (Index.isSimple() || Index.isNoneType()) - return false; - - return Index.toArrayIndex() < SeenRecords.size(); -} - -uint32_t AppendingTypeTableBuilder::size() { return SeenRecords.size(); } - -uint32_t AppendingTypeTableBuilder::capacity() { return SeenRecords.size(); } - -ArrayRef<ArrayRef<uint8_t>> AppendingTypeTableBuilder::records() const { - return SeenRecords; -} - -void AppendingTypeTableBuilder::reset() { SeenRecords.clear(); } - -static ArrayRef<uint8_t> stabilize(BumpPtrAllocator &RecordStorage, - ArrayRef<uint8_t> Record) { - uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size()); - memcpy(Stable, Record.data(), Record.size()); - return ArrayRef<uint8_t>(Stable, Record.size()); -} - -TypeIndex -AppendingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { - TypeIndex NewTI = nextTypeIndex(); - Record = stabilize(RecordStorage, Record); - SeenRecords.push_back(Record); - return NewTI; -} - -TypeIndex -AppendingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { - TypeIndex TI; - auto Fragments = Builder.end(nextTypeIndex()); - assert(!Fragments.empty()); - for (auto C : Fragments) - TI = insertRecordBytes(C.RecordData); - return TI; -} - -bool AppendingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, - bool Stabilize) { - assert(Index.toArrayIndex() < SeenRecords.size() && - "This function cannot be used to insert records!"); - - ArrayRef<uint8_t> Record = Data.data(); - if (Stabilize) - Record = stabilize(RecordStorage, Record); - SeenRecords[Index.toArrayIndex()] = Record; - return true; -} +//===- AppendingTypeTableBuilder.cpp --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex AppendingTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +AppendingTypeTableBuilder::AppendingTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) {} + +AppendingTypeTableBuilder::~AppendingTypeTableBuilder() = default; + +Optional<TypeIndex> AppendingTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> AppendingTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType AppendingTypeTableBuilder::getType(TypeIndex Index){ + return CVType(SeenRecords[Index.toArrayIndex()]); +} + +StringRef AppendingTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool AppendingTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t AppendingTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t AppendingTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> AppendingTypeTableBuilder::records() const { + return SeenRecords; +} + +void AppendingTypeTableBuilder::reset() { SeenRecords.clear(); } + +static ArrayRef<uint8_t> stabilize(BumpPtrAllocator &RecordStorage, + ArrayRef<uint8_t> Record) { + uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size()); + memcpy(Stable, Record.data(), Record.size()); + return ArrayRef<uint8_t>(Stable, Record.size()); +} + +TypeIndex +AppendingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { + TypeIndex NewTI = nextTypeIndex(); + Record = stabilize(RecordStorage, Record); + SeenRecords.push_back(Record); + return NewTI; +} + +TypeIndex +AppendingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} + +bool AppendingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, + bool Stabilize) { + assert(Index.toArrayIndex() < SeenRecords.size() && + "This function cannot be used to insert records!"); + + ArrayRef<uint8_t> Record = Data.data(); + if (Stabilize) + Record = stabilize(RecordStorage, Record); + SeenRecords[Index.toArrayIndex()] = Record; + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp index 48b9b0496f..153eda0790 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp @@ -1,82 +1,82 @@ -//===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" - -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" - -using namespace llvm; -using namespace llvm::codeview; - -CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks) - : Callbacks(Callbacks) {} - -template <typename T> -static Error visitKnownRecord(CVSymbol &Record, - SymbolVisitorCallbacks &Callbacks) { - SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind()); - T KnownRecord(RK); - if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) - return EC; - return Error::success(); -} - -static Error finishVisitation(CVSymbol &Record, - SymbolVisitorCallbacks &Callbacks) { - switch (Record.kind()) { - 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/CodeViewSymbols.def" - } - - if (auto EC = Callbacks.visitSymbolEnd(Record)) - return EC; - - return Error::success(); -} - -Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) { - if (auto EC = Callbacks.visitSymbolBegin(Record)) - return EC; - return finishVisitation(Record, Callbacks); -} - -Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) { - if (auto EC = Callbacks.visitSymbolBegin(Record, Offset)) - return EC; - return finishVisitation(Record, Callbacks); -} - -Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) { - for (auto I : Symbols) { - if (auto EC = visitSymbolRecord(I)) - return EC; - } - return Error::success(); -} - -Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols, - uint32_t InitialOffset) { - for (auto I : Symbols) { - if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew())) - return EC; - InitialOffset += I.length(); - } - return Error::success(); -} +//===- CVSymbolVisitor.cpp --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" + +using namespace llvm; +using namespace llvm::codeview; + +CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + +template <typename T> +static Error visitKnownRecord(CVSymbol &Record, + SymbolVisitorCallbacks &Callbacks) { + SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind()); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; + return Error::success(); +} + +static Error finishVisitation(CVSymbol &Record, + SymbolVisitorCallbacks &Callbacks) { + switch (Record.kind()) { + 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/CodeViewSymbols.def" + } + + if (auto EC = Callbacks.visitSymbolEnd(Record)) + return EC; + + return Error::success(); +} + +Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) { + if (auto EC = Callbacks.visitSymbolBegin(Record)) + return EC; + return finishVisitation(Record, Callbacks); +} + +Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) { + if (auto EC = Callbacks.visitSymbolBegin(Record, Offset)) + return EC; + return finishVisitation(Record, Callbacks); +} + +Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) { + for (auto I : Symbols) { + if (auto EC = visitSymbolRecord(I)) + return EC; + } + return Error::success(); +} + +Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols, + uint32_t InitialOffset) { + for (auto I : Symbols) { + if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew())) + return EC; + InitialOffset += I.length(); + } + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index dd6f75f97a..4f36c4a719 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -1,274 +1,274 @@ -//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" - -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamReader.h" - -using namespace llvm; -using namespace llvm::codeview; - - -template <typename T> -static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) { - TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind()); - T KnownRecord(RK); - if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) - return EC; - return Error::success(); -} - -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(); -} - -static Error visitMemberRecord(CVMemberRecord &Record, - TypeVisitorCallbacks &Callbacks) { - if (auto EC = Callbacks.visitMemberBegin(Record)) - return EC; - - switch (Record.Kind) { - default: - if (auto EC = Callbacks.visitUnknownMember(Record)) - return EC; - break; -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - 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/CodeViewTypes.def" - } - - if (auto EC = Callbacks.visitMemberEnd(Record)) - return EC; - - return Error::success(); -} - -namespace { - -class CVTypeVisitor { -public: - explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); - - Error visitTypeRecord(CVType &Record, TypeIndex Index); - Error visitTypeRecord(CVType &Record); - - /// Visits the type records in Data. Sets the error flag on parse failures. - Error visitTypeStream(const CVTypeArray &Types); - Error visitTypeStream(CVTypeRange Types); - Error visitTypeStream(TypeCollection &Types); - - Error visitMemberRecord(CVMemberRecord Record); - Error visitFieldListMemberStream(BinaryStreamReader &Stream); - -private: - Error finishVisitation(CVType &Record); - - /// The interface to the class that gets notified of each visitation. - TypeVisitorCallbacks &Callbacks; -}; - -CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) - : Callbacks(Callbacks) {} - -Error CVTypeVisitor::finishVisitation(CVType &Record) { - switch (Record.kind()) { - default: - if (auto EC = Callbacks.visitUnknownType(Record)) - return EC; - break; -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - 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/CodeViewTypes.def" - } - - if (auto EC = Callbacks.visitTypeEnd(Record)) - return EC; - - return Error::success(); -} - -Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) { - if (auto EC = Callbacks.visitTypeBegin(Record, Index)) - return EC; - - return finishVisitation(Record); -} - -Error CVTypeVisitor::visitTypeRecord(CVType &Record) { - if (auto EC = Callbacks.visitTypeBegin(Record)) - return EC; - - return finishVisitation(Record); -} - -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::visitTypeStream(CVTypeRange Types) { - for (auto I : Types) { - if (auto EC = visitTypeRecord(I)) - return EC; - } - return Error::success(); -} - -Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) { - Optional<TypeIndex> I = Types.getFirst(); - while (I) { - CVType Type = Types.getType(*I); - if (auto EC = visitTypeRecord(Type, *I)) - return EC; - I = Types.getNext(*I); - } - return Error::success(); -} - -Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) { - TypeLeafKind Leaf; - while (!Reader.empty()) { - if (auto EC = Reader.readEnum(Leaf)) - return EC; - - CVMemberRecord Record; - Record.Kind = Leaf; - if (auto EC = ::visitMemberRecord(Record, Callbacks)) - return EC; - } - - return Error::success(); -} - -struct FieldListVisitHelper { - FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data, - VisitorDataSource Source) - : Stream(Data, llvm::support::little), Reader(Stream), - Deserializer(Reader), - Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) { - if (Source == VDS_BytesPresent) { - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Callbacks); - } - } - - BinaryByteStream Stream; - BinaryStreamReader Reader; - FieldListDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - CVTypeVisitor Visitor; -}; - -struct VisitHelper { - VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source) - : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) { - if (Source == VDS_BytesPresent) { - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Callbacks); - } - } - - TypeDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - CVTypeVisitor Visitor; -}; -} - -Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index, - TypeVisitorCallbacks &Callbacks, - VisitorDataSource Source) { - VisitHelper V(Callbacks, Source); - return V.Visitor.visitTypeRecord(Record, Index); -} - -Error llvm::codeview::visitTypeRecord(CVType &Record, - TypeVisitorCallbacks &Callbacks, - VisitorDataSource Source) { - VisitHelper V(Callbacks, Source); - return V.Visitor.visitTypeRecord(Record); -} - -Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, - TypeVisitorCallbacks &Callbacks, - VisitorDataSource Source) { - VisitHelper V(Callbacks, Source); - return V.Visitor.visitTypeStream(Types); -} - -Error llvm::codeview::visitTypeStream(CVTypeRange Types, - TypeVisitorCallbacks &Callbacks) { - VisitHelper V(Callbacks, VDS_BytesPresent); - return V.Visitor.visitTypeStream(Types); -} - -Error llvm::codeview::visitTypeStream(TypeCollection &Types, - TypeVisitorCallbacks &Callbacks) { - // When the internal visitor calls Types.getType(Index) the interface is - // required to return a CVType with the bytes filled out. So we can assume - // that the bytes will be present when individual records are visited. - VisitHelper V(Callbacks, VDS_BytesPresent); - return V.Visitor.visitTypeStream(Types); -} - -Error llvm::codeview::visitMemberRecord(CVMemberRecord Record, - TypeVisitorCallbacks &Callbacks, - VisitorDataSource Source) { - FieldListVisitHelper V(Callbacks, Record.Data, Source); - return V.Visitor.visitMemberRecord(Record); -} - -Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind, - ArrayRef<uint8_t> Record, - TypeVisitorCallbacks &Callbacks) { - CVMemberRecord R; - R.Data = Record; - R.Kind = Kind; - return visitMemberRecord(R, Callbacks, VDS_BytesPresent); -} - -Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList, - TypeVisitorCallbacks &Callbacks) { - FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent); - return V.Visitor.visitFieldListMemberStream(V.Reader); -} +//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + + +template <typename T> +static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) { + TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind()); + T KnownRecord(RK); + if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord)) + return EC; + return Error::success(); +} + +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(); +} + +static Error visitMemberRecord(CVMemberRecord &Record, + TypeVisitorCallbacks &Callbacks) { + if (auto EC = Callbacks.visitMemberBegin(Record)) + return EC; + + switch (Record.Kind) { + default: + if (auto EC = Callbacks.visitUnknownMember(Record)) + return EC; + break; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + 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/CodeViewTypes.def" + } + + if (auto EC = Callbacks.visitMemberEnd(Record)) + return EC; + + return Error::success(); +} + +namespace { + +class CVTypeVisitor { +public: + explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); + + Error visitTypeRecord(CVType &Record, TypeIndex Index); + Error visitTypeRecord(CVType &Record); + + /// Visits the type records in Data. Sets the error flag on parse failures. + Error visitTypeStream(const CVTypeArray &Types); + Error visitTypeStream(CVTypeRange Types); + Error visitTypeStream(TypeCollection &Types); + + Error visitMemberRecord(CVMemberRecord Record); + Error visitFieldListMemberStream(BinaryStreamReader &Stream); + +private: + Error finishVisitation(CVType &Record); + + /// The interface to the class that gets notified of each visitation. + TypeVisitorCallbacks &Callbacks; +}; + +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + +Error CVTypeVisitor::finishVisitation(CVType &Record) { + switch (Record.kind()) { + default: + if (auto EC = Callbacks.visitUnknownType(Record)) + return EC; + break; +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + 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/CodeViewTypes.def" + } + + if (auto EC = Callbacks.visitTypeEnd(Record)) + return EC; + + return Error::success(); +} + +Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) { + if (auto EC = Callbacks.visitTypeBegin(Record, Index)) + return EC; + + return finishVisitation(Record); +} + +Error CVTypeVisitor::visitTypeRecord(CVType &Record) { + if (auto EC = Callbacks.visitTypeBegin(Record)) + return EC; + + return finishVisitation(Record); +} + +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::visitTypeStream(CVTypeRange Types) { + for (auto I : Types) { + if (auto EC = visitTypeRecord(I)) + return EC; + } + return Error::success(); +} + +Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) { + Optional<TypeIndex> I = Types.getFirst(); + while (I) { + CVType Type = Types.getType(*I); + if (auto EC = visitTypeRecord(Type, *I)) + return EC; + I = Types.getNext(*I); + } + return Error::success(); +} + +Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) { + TypeLeafKind Leaf; + while (!Reader.empty()) { + if (auto EC = Reader.readEnum(Leaf)) + return EC; + + CVMemberRecord Record; + Record.Kind = Leaf; + if (auto EC = ::visitMemberRecord(Record, Callbacks)) + return EC; + } + + return Error::success(); +} + +struct FieldListVisitHelper { + FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data, + VisitorDataSource Source) + : Stream(Data, llvm::support::little), Reader(Stream), + Deserializer(Reader), + Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) { + if (Source == VDS_BytesPresent) { + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Callbacks); + } + } + + BinaryByteStream Stream; + BinaryStreamReader Reader; + FieldListDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + CVTypeVisitor Visitor; +}; + +struct VisitHelper { + VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source) + : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) { + if (Source == VDS_BytesPresent) { + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Callbacks); + } + } + + TypeDeserializer Deserializer; + TypeVisitorCallbackPipeline Pipeline; + CVTypeVisitor Visitor; +}; +} + +Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index, + TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source) { + VisitHelper V(Callbacks, Source); + return V.Visitor.visitTypeRecord(Record, Index); +} + +Error llvm::codeview::visitTypeRecord(CVType &Record, + TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source) { + VisitHelper V(Callbacks, Source); + return V.Visitor.visitTypeRecord(Record); +} + +Error llvm::codeview::visitTypeStream(const CVTypeArray &Types, + TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source) { + VisitHelper V(Callbacks, Source); + return V.Visitor.visitTypeStream(Types); +} + +Error llvm::codeview::visitTypeStream(CVTypeRange Types, + TypeVisitorCallbacks &Callbacks) { + VisitHelper V(Callbacks, VDS_BytesPresent); + return V.Visitor.visitTypeStream(Types); +} + +Error llvm::codeview::visitTypeStream(TypeCollection &Types, + TypeVisitorCallbacks &Callbacks) { + // When the internal visitor calls Types.getType(Index) the interface is + // required to return a CVType with the bytes filled out. So we can assume + // that the bytes will be present when individual records are visited. + VisitHelper V(Callbacks, VDS_BytesPresent); + return V.Visitor.visitTypeStream(Types); +} + +Error llvm::codeview::visitMemberRecord(CVMemberRecord Record, + TypeVisitorCallbacks &Callbacks, + VisitorDataSource Source) { + FieldListVisitHelper V(Callbacks, Record.Data, Source); + return V.Visitor.visitMemberRecord(Record); +} + +Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind, + ArrayRef<uint8_t> Record, + TypeVisitorCallbacks &Callbacks) { + CVMemberRecord R; + R.Data = Record; + R.Kind = Kind; + return visitMemberRecord(R, Callbacks, VDS_BytesPresent); +} + +Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList, + TypeVisitorCallbacks &Callbacks) { + FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent); + return V.Visitor.visitFieldListMemberStream(V.Reader); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewError.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewError.cpp index 69390c708f..40c45b1f07 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewError.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewError.cpp @@ -1,49 +1,49 @@ -//===- CodeViewError.cpp - Error extensions for CodeView --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" - -using namespace llvm; -using namespace llvm::codeview; - -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 CodeViewErrorCategory : public std::error_category { -public: - const char *name() const noexcept override { return "llvm.codeview"; } - std::string message(int Condition) const override { - switch (static_cast<cv_error_code>(Condition)) { - case cv_error_code::unspecified: - return "An unknown CodeView error has occurred."; - case cv_error_code::insufficient_buffer: - return "The buffer is not large enough to read the requested number of " - "bytes."; - case cv_error_code::corrupt_record: - return "The CodeView record is corrupted."; - case cv_error_code::no_records: - return "There are no records."; - case cv_error_code::operation_unsupported: - return "The requested operation is not supported."; - case cv_error_code::unknown_member_record: - return "The member record is of an unknown type."; - } - llvm_unreachable("Unrecognized cv_error_code"); - } -}; -} // namespace - -static llvm::ManagedStatic<CodeViewErrorCategory> CodeViewErrCategory; -const std::error_category &llvm::codeview::CVErrorCategory() { - return *CodeViewErrCategory; -} - -char CodeViewError::ID; +//===- CodeViewError.cpp - Error extensions for CodeView --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::codeview; + +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 CodeViewErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.codeview"; } + std::string message(int Condition) const override { + switch (static_cast<cv_error_code>(Condition)) { + case cv_error_code::unspecified: + return "An unknown CodeView error has occurred."; + case cv_error_code::insufficient_buffer: + return "The buffer is not large enough to read the requested number of " + "bytes."; + case cv_error_code::corrupt_record: + return "The CodeView record is corrupted."; + case cv_error_code::no_records: + return "There are no records."; + case cv_error_code::operation_unsupported: + return "The requested operation is not supported."; + case cv_error_code::unknown_member_record: + return "The member record is of an unknown type."; + } + llvm_unreachable("Unrecognized cv_error_code"); + } +}; +} // namespace + +static llvm::ManagedStatic<CodeViewErrorCategory> CodeViewErrCategory; +const std::error_category &llvm::codeview::CVErrorCategory() { + return *CodeViewErrCategory; +} + +char CodeViewError::ID; diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp index c272985cf2..df7a78fcd2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -1,370 +1,370 @@ -//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.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(); - // We would like to assert that we actually read / wrote all the bytes that we - // expected to for this record, but unfortunately we can't do this. Some - // producers such as MASM over-allocate for certain types of records and - // commit the extraneous data, so when reading we can't be sure every byte - // will have been read. And when writing we over-allocate temporarily since - // we don't know how big the record is until we're finished writing it, so - // even though we don't commit the extraneous data, we still can't guarantee - // we're at the end of the allocated data. - - if (isStreaming()) { - // For streaming mode, add padding to align with 4 byte boundaries for each - // record - uint32_t Align = getStreamedLen() % 4; - if (Align == 0) - return Error::success(); - - int PaddingBytes = 4 - Align; - while (PaddingBytes > 0) { - char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); - StringRef BytesSR = StringRef(&Pad, sizeof(Pad)); - Streamer->emitBytes(BytesSR); - --PaddingBytes; - } - resetStreamedLen(); - } - return Error::success(); -} - -uint32_t CodeViewRecordIO::maxFieldLength() const { - if (isStreaming()) - return 0; - - 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::padToAlignment(uint32_t Align) { - if (isReading()) - return Reader->padToAlignment(Align); - return Writer->padToAlignment(Align); -} - -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, - const Twine &Comment) { - if (isStreaming()) { - emitComment(Comment); - Streamer->emitBinaryData(toStringRef(Bytes)); - incrStreamedLen(Bytes.size()); - } else 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, - const Twine &Comment) { - ArrayRef<uint8_t> BytesRef(Bytes); - if (auto EC = mapByteVectorTail(BytesRef, Comment)) - return EC; - if (!isWriting()) - Bytes.assign(BytesRef.begin(), BytesRef.end()); - - return Error::success(); -} - -Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) { - if (isStreaming()) { - std::string TypeNameStr = Streamer->getTypeName(TypeInd); - if (!TypeNameStr.empty()) - emitComment(Comment + ": " + TypeNameStr); - else - emitComment(Comment); - Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex())); - incrStreamedLen(sizeof(TypeInd.getIndex())); - } else if (isWriting()) { - if (auto EC = Writer->writeInteger(TypeInd.getIndex())) - return EC; - } else { - uint32_t I; - if (auto EC = Reader->readInteger(I)) - return EC; - TypeInd.setIndex(I); - } - return Error::success(); -} - -Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value, - const Twine &Comment) { - if (isStreaming()) { - if (Value >= 0) - emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment); - else - emitEncodedSignedInteger(Value, Comment); - } else 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, - const Twine &Comment) { - if (isStreaming()) - emitEncodedUnsignedInteger(Value, Comment); - else 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, const Twine &Comment) { - if (isStreaming()) { - if (Value.isSigned()) - emitEncodedSignedInteger(Value.getSExtValue(), Comment); - else - emitEncodedUnsignedInteger(Value.getZExtValue(), Comment); - } else if (isWriting()) { - if (Value.isSigned()) - return writeEncodedSignedInteger(Value.getSExtValue()); - return writeEncodedUnsignedInteger(Value.getZExtValue()); - } else - return consume(*Reader, Value); - return Error::success(); -} - -Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) { - if (isStreaming()) { - auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1); - emitComment(Comment); - Streamer->emitBytes(NullTerminatedString); - incrStreamedLen(NullTerminatedString.size()); - } else if (isWriting()) { - // Truncate if we attempt to write too much. - StringRef S = Value.take_front(maxFieldLength() - 1); - if (auto EC = Writer->writeCString(S)) - return EC; - } else { - if (auto EC = Reader->readCString(Value)) - return EC; - } - return Error::success(); -} - -Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) { - constexpr uint32_t GuidSize = 16; - - if (isStreaming()) { - StringRef GuidSR = - StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize); - emitComment(Comment); - Streamer->emitBytes(GuidSR); - incrStreamedLen(GuidSize); - return Error::success(); - } - - if (maxFieldLength() < GuidSize) - return make_error<CodeViewError>(cv_error_code::insufficient_buffer); - - if (isWriting()) { - if (auto EC = Writer->writeBytes(Guid.Guid)) - return EC; - } else { - ArrayRef<uint8_t> GuidBytes; - if (auto EC = Reader->readBytes(GuidBytes, GuidSize)) - return EC; - memcpy(Guid.Guid, GuidBytes.data(), GuidSize); - } - return Error::success(); -} - -Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value, - const Twine &Comment) { - - if (!isReading()) { - emitComment(Comment); - for (auto V : Value) { - if (auto EC = mapStringZ(V)) - return EC; - } - uint8_t FinalZero = 0; - if (auto EC = mapInteger(FinalZero)) - 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(); -} - -void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value, - const Twine &Comment) { - if (Value >= std::numeric_limits<int8_t>::min()) { - Streamer->emitIntValue(LF_CHAR, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 1); - incrStreamedLen(3); - } else if (Value >= std::numeric_limits<int16_t>::min()) { - Streamer->emitIntValue(LF_SHORT, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 2); - incrStreamedLen(4); - } else if (Value >= std::numeric_limits<int32_t>::min()) { - Streamer->emitIntValue(LF_LONG, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 4); - incrStreamedLen(6); - } else { - Streamer->emitIntValue(LF_QUADWORD, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 4); - incrStreamedLen(6); - } -} - -void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value, - const Twine &Comment) { - if (Value < LF_NUMERIC) { - emitComment(Comment); - Streamer->emitIntValue(Value, 2); - incrStreamedLen(2); - } else if (Value <= std::numeric_limits<uint16_t>::max()) { - Streamer->emitIntValue(LF_USHORT, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 2); - incrStreamedLen(4); - } else if (Value <= std::numeric_limits<uint32_t>::max()) { - Streamer->emitIntValue(LF_ULONG, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 4); - incrStreamedLen(6); - } else { - Streamer->emitIntValue(LF_UQUADWORD, 2); - emitComment(Comment); - Streamer->emitIntValue(Value, 8); - incrStreamedLen(6); - } -} - -Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { - if (Value >= std::numeric_limits<int8_t>::min()) { - if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR)) - return EC; - if (auto EC = Writer->writeInteger<int8_t>(Value)) - return EC; - } else if (Value >= std::numeric_limits<int16_t>::min()) { - if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT)) - return EC; - if (auto EC = Writer->writeInteger<int16_t>(Value)) - return EC; - } else if (Value >= std::numeric_limits<int32_t>::min()) { - if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG)) - return EC; - if (auto EC = Writer->writeInteger<int32_t>(Value)) - return EC; - } else { - if (auto EC = Writer->writeInteger<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<uint16_t>(Value)) - return EC; - } else if (Value <= std::numeric_limits<uint16_t>::max()) { - if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT)) - return EC; - if (auto EC = Writer->writeInteger<uint16_t>(Value)) - return EC; - } else if (Value <= std::numeric_limits<uint32_t>::max()) { - if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG)) - return EC; - if (auto EC = Writer->writeInteger<uint32_t>(Value)) - return EC; - } else { - if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD)) - return EC; - if (auto EC = Writer->writeInteger(Value)) - return EC; - } - - return Error::success(); -} +//===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.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(); + // We would like to assert that we actually read / wrote all the bytes that we + // expected to for this record, but unfortunately we can't do this. Some + // producers such as MASM over-allocate for certain types of records and + // commit the extraneous data, so when reading we can't be sure every byte + // will have been read. And when writing we over-allocate temporarily since + // we don't know how big the record is until we're finished writing it, so + // even though we don't commit the extraneous data, we still can't guarantee + // we're at the end of the allocated data. + + if (isStreaming()) { + // For streaming mode, add padding to align with 4 byte boundaries for each + // record + uint32_t Align = getStreamedLen() % 4; + if (Align == 0) + return Error::success(); + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + StringRef BytesSR = StringRef(&Pad, sizeof(Pad)); + Streamer->emitBytes(BytesSR); + --PaddingBytes; + } + resetStreamedLen(); + } + return Error::success(); +} + +uint32_t CodeViewRecordIO::maxFieldLength() const { + if (isStreaming()) + return 0; + + 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::padToAlignment(uint32_t Align) { + if (isReading()) + return Reader->padToAlignment(Align); + return Writer->padToAlignment(Align); +} + +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, + const Twine &Comment) { + if (isStreaming()) { + emitComment(Comment); + Streamer->emitBinaryData(toStringRef(Bytes)); + incrStreamedLen(Bytes.size()); + } else 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, + const Twine &Comment) { + ArrayRef<uint8_t> BytesRef(Bytes); + if (auto EC = mapByteVectorTail(BytesRef, Comment)) + return EC; + if (!isWriting()) + Bytes.assign(BytesRef.begin(), BytesRef.end()); + + return Error::success(); +} + +Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) { + if (isStreaming()) { + std::string TypeNameStr = Streamer->getTypeName(TypeInd); + if (!TypeNameStr.empty()) + emitComment(Comment + ": " + TypeNameStr); + else + emitComment(Comment); + Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex())); + incrStreamedLen(sizeof(TypeInd.getIndex())); + } else if (isWriting()) { + if (auto EC = Writer->writeInteger(TypeInd.getIndex())) + return EC; + } else { + uint32_t I; + if (auto EC = Reader->readInteger(I)) + return EC; + TypeInd.setIndex(I); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value, + const Twine &Comment) { + if (isStreaming()) { + if (Value >= 0) + emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment); + else + emitEncodedSignedInteger(Value, Comment); + } else 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, + const Twine &Comment) { + if (isStreaming()) + emitEncodedUnsignedInteger(Value, Comment); + else 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, const Twine &Comment) { + if (isStreaming()) { + if (Value.isSigned()) + emitEncodedSignedInteger(Value.getSExtValue(), Comment); + else + emitEncodedUnsignedInteger(Value.getZExtValue(), Comment); + } else if (isWriting()) { + if (Value.isSigned()) + return writeEncodedSignedInteger(Value.getSExtValue()); + return writeEncodedUnsignedInteger(Value.getZExtValue()); + } else + return consume(*Reader, Value); + return Error::success(); +} + +Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) { + if (isStreaming()) { + auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1); + emitComment(Comment); + Streamer->emitBytes(NullTerminatedString); + incrStreamedLen(NullTerminatedString.size()); + } else if (isWriting()) { + // Truncate if we attempt to write too much. + StringRef S = Value.take_front(maxFieldLength() - 1); + if (auto EC = Writer->writeCString(S)) + return EC; + } else { + if (auto EC = Reader->readCString(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) { + constexpr uint32_t GuidSize = 16; + + if (isStreaming()) { + StringRef GuidSR = + StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize); + emitComment(Comment); + Streamer->emitBytes(GuidSR); + incrStreamedLen(GuidSize); + return Error::success(); + } + + if (maxFieldLength() < GuidSize) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + + if (isWriting()) { + if (auto EC = Writer->writeBytes(Guid.Guid)) + return EC; + } else { + ArrayRef<uint8_t> GuidBytes; + if (auto EC = Reader->readBytes(GuidBytes, GuidSize)) + return EC; + memcpy(Guid.Guid, GuidBytes.data(), GuidSize); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value, + const Twine &Comment) { + + if (!isReading()) { + emitComment(Comment); + for (auto V : Value) { + if (auto EC = mapStringZ(V)) + return EC; + } + uint8_t FinalZero = 0; + if (auto EC = mapInteger(FinalZero)) + 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(); +} + +void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value, + const Twine &Comment) { + if (Value >= std::numeric_limits<int8_t>::min()) { + Streamer->emitIntValue(LF_CHAR, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 1); + incrStreamedLen(3); + } else if (Value >= std::numeric_limits<int16_t>::min()) { + Streamer->emitIntValue(LF_SHORT, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 2); + incrStreamedLen(4); + } else if (Value >= std::numeric_limits<int32_t>::min()) { + Streamer->emitIntValue(LF_LONG, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 4); + incrStreamedLen(6); + } else { + Streamer->emitIntValue(LF_QUADWORD, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 4); + incrStreamedLen(6); + } +} + +void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value, + const Twine &Comment) { + if (Value < LF_NUMERIC) { + emitComment(Comment); + Streamer->emitIntValue(Value, 2); + incrStreamedLen(2); + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + Streamer->emitIntValue(LF_USHORT, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 2); + incrStreamedLen(4); + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + Streamer->emitIntValue(LF_ULONG, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 4); + incrStreamedLen(6); + } else { + Streamer->emitIntValue(LF_UQUADWORD, 2); + emitComment(Comment); + Streamer->emitIntValue(Value, 8); + incrStreamedLen(6); + } +} + +Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { + if (Value >= std::numeric_limits<int8_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR)) + return EC; + if (auto EC = Writer->writeInteger<int8_t>(Value)) + return EC; + } else if (Value >= std::numeric_limits<int16_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT)) + return EC; + if (auto EC = Writer->writeInteger<int16_t>(Value)) + return EC; + } else if (Value >= std::numeric_limits<int32_t>::min()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG)) + return EC; + if (auto EC = Writer->writeInteger<int32_t>(Value)) + return EC; + } else { + if (auto EC = Writer->writeInteger<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<uint16_t>(Value)) + return EC; + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT)) + return EC; + if (auto EC = Writer->writeInteger<uint16_t>(Value)) + return EC; + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG)) + return EC; + if (auto EC = Writer->writeInteger<uint32_t>(Value)) + return EC; + } else { + if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD)) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp index 799cffb711..52389956dc 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp @@ -1,251 +1,251 @@ -#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" - -using namespace llvm; -using namespace llvm::codeview; - -namespace { -struct ContinuationRecord { - ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)}; - ulittle16_t Size{0}; - ulittle32_t IndexRef{0xB0C0B0C0}; -}; - -struct SegmentInjection { - SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; } - - ContinuationRecord Cont; - RecordPrefix Prefix; -}; -} // namespace - -static void addPadding(BinaryStreamWriter &Writer) { - uint32_t Align = Writer.getOffset() % 4; - if (Align == 0) - return; - - int PaddingBytes = 4 - Align; - while (PaddingBytes > 0) { - uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); - cantFail(Writer.writeInteger(Pad)); - --PaddingBytes; - } -} - -static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST); -static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST); - -static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord); -static constexpr uint32_t MaxSegmentLength = - MaxRecordLength - ContinuationLength; - -static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) { - return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST - : LF_METHODLIST; -} - -ContinuationRecordBuilder::ContinuationRecordBuilder() - : SegmentWriter(Buffer), Mapping(SegmentWriter) {} - -ContinuationRecordBuilder::~ContinuationRecordBuilder() {} - -void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) { - assert(!Kind.hasValue()); - Kind = RecordKind; - Buffer.clear(); - SegmentWriter.setOffset(0); - SegmentOffsets.clear(); - SegmentOffsets.push_back(0); - assert(SegmentWriter.getOffset() == 0); - assert(SegmentWriter.getLength() == 0); - - const SegmentInjection *FLI = - (RecordKind == ContinuationRecordKind::FieldList) - ? &InjectFieldList - : &InjectMethodOverloadList; - const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI); - InjectedSegmentBytes = - ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection)); - - // Seed the first record with an appropriate record prefix. - RecordPrefix Prefix(getTypeLeafKind(RecordKind)); - CVType Type(&Prefix, sizeof(Prefix)); - cantFail(Mapping.visitTypeBegin(Type)); - - cantFail(SegmentWriter.writeObject(Prefix)); -} - -template <typename RecordType> -void ContinuationRecordBuilder::writeMemberType(RecordType &Record) { - assert(Kind.hasValue()); - - uint32_t OriginalOffset = SegmentWriter.getOffset(); - CVMemberRecord CVMR; - CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind()); - - // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind - // at the beginning. - cantFail(SegmentWriter.writeEnum(CVMR.Kind)); - - // Let the Mapping handle the rest. - cantFail(Mapping.visitMemberBegin(CVMR)); - cantFail(Mapping.visitKnownMember(CVMR, Record)); - cantFail(Mapping.visitMemberEnd(CVMR)); - - // Make sure it's padded to 4 bytes. - addPadding(SegmentWriter); - assert(getCurrentSegmentLength() % 4 == 0); - - // The maximum length of a single segment is 64KB minus the size to insert a - // continuation. So if we are over that, inject a continuation between the - // previous member and the member that was just written, then end the previous - // segment after the continuation and begin a new one with the just-written - // member. - if (getCurrentSegmentLength() > MaxSegmentLength) { - // We need to inject some bytes before the member we just wrote but after - // the previous member. Save off the length of the member we just wrote so - // that we can do some sanity checking on it. - uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset; - (void) MemberLength; - insertSegmentEnd(OriginalOffset); - // Since this member now becomes a new top-level record, it should have - // gotten a RecordPrefix injected, and that RecordPrefix + the member we - // just wrote should now constitute the entirety of the current "new" - // segment. - assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix)); - } - - assert(getCurrentSegmentLength() % 4 == 0); - assert(getCurrentSegmentLength() <= MaxSegmentLength); -} - -uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const { - return SegmentWriter.getOffset() - SegmentOffsets.back(); -} - -void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) { - uint32_t SegmentBegin = SegmentOffsets.back(); - (void)SegmentBegin; - assert(Offset > SegmentBegin); - assert(Offset - SegmentBegin <= MaxSegmentLength); - - // We need to make space for the continuation record. For now we can't fill - // out the length or the TypeIndex of the back-reference, but we need the - // space to at least be there. - Buffer.insert(Offset, InjectedSegmentBytes); - - uint32_t NewSegmentBegin = Offset + ContinuationLength; - uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back(); - (void) SegmentLength; - - assert(SegmentLength % 4 == 0); - assert(SegmentLength <= MaxRecordLength); - SegmentOffsets.push_back(NewSegmentBegin); - - // Seek to the end so that we can keep writing against the new segment. - SegmentWriter.setOffset(SegmentWriter.getLength()); - assert(SegmentWriter.bytesRemaining() == 0); -} - -CVType ContinuationRecordBuilder::createSegmentRecord( - uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) { - assert(OffEnd - OffBegin <= USHRT_MAX); - - MutableArrayRef<uint8_t> Data = Buffer.data(); - Data = Data.slice(OffBegin, OffEnd - OffBegin); - - // Write the length to the RecordPrefix, making sure it does not include - // sizeof(RecordPrefix.Length) - RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data()); - Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen); - - if (RefersTo.hasValue()) { - auto Continuation = Data.take_back(ContinuationLength); - ContinuationRecord *CR = - reinterpret_cast<ContinuationRecord *>(Continuation.data()); - assert(CR->Kind == TypeLeafKind::LF_INDEX); - assert(CR->IndexRef == 0xB0C0B0C0); - CR->IndexRef = RefersTo->getIndex(); - } - - return CVType(Data); -} - -std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) { - RecordPrefix Prefix(getTypeLeafKind(*Kind)); - CVType Type(&Prefix, sizeof(Prefix)); - cantFail(Mapping.visitTypeEnd(Type)); - - // We're now done, and we have a series of segments each beginning at an - // offset specified in the SegmentOffsets array. We now need to iterate - // over each segment and post-process them in the following two ways: - // 1) Each top-level record has a RecordPrefix whose type is either - // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0. - // Those should all be set to the correct length now. - // 2) Each continuation record has an IndexRef field which we set to the - // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex - // they want this sequence to start from, we can go through and update - // each one. - // - // Logically, the sequence of records we've built up looks like this: - // - // SegmentOffsets[0]: <Length> (Initially: uninitialized) - // SegmentOffsets[0]+2: LF_FIELDLIST - // SegmentOffsets[0]+4: Member[0] - // SegmentOffsets[0]+?: ... - // SegmentOffsets[0]+?: Member[4] - // SegmentOffsets[1]-8: LF_INDEX - // SegmentOffsets[1]-6: 0 - // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) - // - // SegmentOffsets[1]: <Length> (Initially: uninitialized) - // SegmentOffsets[1]+2: LF_FIELDLIST - // SegmentOffsets[1]+4: Member[0] - // SegmentOffsets[1]+?: ... - // SegmentOffsets[1]+?: Member[s] - // SegmentOffsets[2]-8: LF_INDEX - // SegmentOffsets[2]-6: 0 - // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) - // - // ... - // - // SegmentOffsets[N]: <Length> (Initially: uninitialized) - // SegmentOffsets[N]+2: LF_FIELDLIST - // SegmentOffsets[N]+4: Member[0] - // SegmentOffsets[N]+?: ... - // SegmentOffsets[N]+?: Member[t] - // - // And this is the way we have laid them out in the serialization buffer. But - // we cannot actually commit them to the underlying stream this way, due to - // the topological sorting requirement of a type stream (specifically, - // TypeIndex references can only point backwards, not forwards). So the - // sequence that we return to the caller contains the records in reverse - // order, which is the proper order for committing the serialized records. - - std::vector<CVType> Types; - Types.reserve(SegmentOffsets.size()); - - auto SO = makeArrayRef(SegmentOffsets); - - uint32_t End = SegmentWriter.getOffset(); - - Optional<TypeIndex> RefersTo; - for (uint32_t Offset : reverse(SO)) { - Types.push_back(createSegmentRecord(Offset, End, RefersTo)); - - End = Offset; - RefersTo = Index++; - } - - Kind.reset(); - return Types; -} - -// Explicitly instantiate the member function for each known type so that we can -// implement this in the cpp file. -#define TYPE_RECORD(EnumName, EnumVal, Name) -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \ - Name##Record &Record); -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +struct ContinuationRecord { + ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)}; + ulittle16_t Size{0}; + ulittle32_t IndexRef{0xB0C0B0C0}; +}; + +struct SegmentInjection { + SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; } + + ContinuationRecord Cont; + RecordPrefix Prefix; +}; +} // namespace + +static void addPadding(BinaryStreamWriter &Writer) { + uint32_t Align = Writer.getOffset() % 4; + if (Align == 0) + return; + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + cantFail(Writer.writeInteger(Pad)); + --PaddingBytes; + } +} + +static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST); +static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST); + +static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord); +static constexpr uint32_t MaxSegmentLength = + MaxRecordLength - ContinuationLength; + +static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) { + return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST + : LF_METHODLIST; +} + +ContinuationRecordBuilder::ContinuationRecordBuilder() + : SegmentWriter(Buffer), Mapping(SegmentWriter) {} + +ContinuationRecordBuilder::~ContinuationRecordBuilder() {} + +void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) { + assert(!Kind.hasValue()); + Kind = RecordKind; + Buffer.clear(); + SegmentWriter.setOffset(0); + SegmentOffsets.clear(); + SegmentOffsets.push_back(0); + assert(SegmentWriter.getOffset() == 0); + assert(SegmentWriter.getLength() == 0); + + const SegmentInjection *FLI = + (RecordKind == ContinuationRecordKind::FieldList) + ? &InjectFieldList + : &InjectMethodOverloadList; + const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI); + InjectedSegmentBytes = + ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection)); + + // Seed the first record with an appropriate record prefix. + RecordPrefix Prefix(getTypeLeafKind(RecordKind)); + CVType Type(&Prefix, sizeof(Prefix)); + cantFail(Mapping.visitTypeBegin(Type)); + + cantFail(SegmentWriter.writeObject(Prefix)); +} + +template <typename RecordType> +void ContinuationRecordBuilder::writeMemberType(RecordType &Record) { + assert(Kind.hasValue()); + + uint32_t OriginalOffset = SegmentWriter.getOffset(); + CVMemberRecord CVMR; + CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind()); + + // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind + // at the beginning. + cantFail(SegmentWriter.writeEnum(CVMR.Kind)); + + // Let the Mapping handle the rest. + cantFail(Mapping.visitMemberBegin(CVMR)); + cantFail(Mapping.visitKnownMember(CVMR, Record)); + cantFail(Mapping.visitMemberEnd(CVMR)); + + // Make sure it's padded to 4 bytes. + addPadding(SegmentWriter); + assert(getCurrentSegmentLength() % 4 == 0); + + // The maximum length of a single segment is 64KB minus the size to insert a + // continuation. So if we are over that, inject a continuation between the + // previous member and the member that was just written, then end the previous + // segment after the continuation and begin a new one with the just-written + // member. + if (getCurrentSegmentLength() > MaxSegmentLength) { + // We need to inject some bytes before the member we just wrote but after + // the previous member. Save off the length of the member we just wrote so + // that we can do some sanity checking on it. + uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset; + (void) MemberLength; + insertSegmentEnd(OriginalOffset); + // Since this member now becomes a new top-level record, it should have + // gotten a RecordPrefix injected, and that RecordPrefix + the member we + // just wrote should now constitute the entirety of the current "new" + // segment. + assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix)); + } + + assert(getCurrentSegmentLength() % 4 == 0); + assert(getCurrentSegmentLength() <= MaxSegmentLength); +} + +uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const { + return SegmentWriter.getOffset() - SegmentOffsets.back(); +} + +void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) { + uint32_t SegmentBegin = SegmentOffsets.back(); + (void)SegmentBegin; + assert(Offset > SegmentBegin); + assert(Offset - SegmentBegin <= MaxSegmentLength); + + // We need to make space for the continuation record. For now we can't fill + // out the length or the TypeIndex of the back-reference, but we need the + // space to at least be there. + Buffer.insert(Offset, InjectedSegmentBytes); + + uint32_t NewSegmentBegin = Offset + ContinuationLength; + uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back(); + (void) SegmentLength; + + assert(SegmentLength % 4 == 0); + assert(SegmentLength <= MaxRecordLength); + SegmentOffsets.push_back(NewSegmentBegin); + + // Seek to the end so that we can keep writing against the new segment. + SegmentWriter.setOffset(SegmentWriter.getLength()); + assert(SegmentWriter.bytesRemaining() == 0); +} + +CVType ContinuationRecordBuilder::createSegmentRecord( + uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) { + assert(OffEnd - OffBegin <= USHRT_MAX); + + MutableArrayRef<uint8_t> Data = Buffer.data(); + Data = Data.slice(OffBegin, OffEnd - OffBegin); + + // Write the length to the RecordPrefix, making sure it does not include + // sizeof(RecordPrefix.Length) + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data()); + Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen); + + if (RefersTo.hasValue()) { + auto Continuation = Data.take_back(ContinuationLength); + ContinuationRecord *CR = + reinterpret_cast<ContinuationRecord *>(Continuation.data()); + assert(CR->Kind == TypeLeafKind::LF_INDEX); + assert(CR->IndexRef == 0xB0C0B0C0); + CR->IndexRef = RefersTo->getIndex(); + } + + return CVType(Data); +} + +std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) { + RecordPrefix Prefix(getTypeLeafKind(*Kind)); + CVType Type(&Prefix, sizeof(Prefix)); + cantFail(Mapping.visitTypeEnd(Type)); + + // We're now done, and we have a series of segments each beginning at an + // offset specified in the SegmentOffsets array. We now need to iterate + // over each segment and post-process them in the following two ways: + // 1) Each top-level record has a RecordPrefix whose type is either + // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0. + // Those should all be set to the correct length now. + // 2) Each continuation record has an IndexRef field which we set to the + // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex + // they want this sequence to start from, we can go through and update + // each one. + // + // Logically, the sequence of records we've built up looks like this: + // + // SegmentOffsets[0]: <Length> (Initially: uninitialized) + // SegmentOffsets[0]+2: LF_FIELDLIST + // SegmentOffsets[0]+4: Member[0] + // SegmentOffsets[0]+?: ... + // SegmentOffsets[0]+?: Member[4] + // SegmentOffsets[1]-8: LF_INDEX + // SegmentOffsets[1]-6: 0 + // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) + // + // SegmentOffsets[1]: <Length> (Initially: uninitialized) + // SegmentOffsets[1]+2: LF_FIELDLIST + // SegmentOffsets[1]+4: Member[0] + // SegmentOffsets[1]+?: ... + // SegmentOffsets[1]+?: Member[s] + // SegmentOffsets[2]-8: LF_INDEX + // SegmentOffsets[2]-6: 0 + // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0) + // + // ... + // + // SegmentOffsets[N]: <Length> (Initially: uninitialized) + // SegmentOffsets[N]+2: LF_FIELDLIST + // SegmentOffsets[N]+4: Member[0] + // SegmentOffsets[N]+?: ... + // SegmentOffsets[N]+?: Member[t] + // + // And this is the way we have laid them out in the serialization buffer. But + // we cannot actually commit them to the underlying stream this way, due to + // the topological sorting requirement of a type stream (specifically, + // TypeIndex references can only point backwards, not forwards). So the + // sequence that we return to the caller contains the records in reverse + // order, which is the proper order for committing the serialized records. + + std::vector<CVType> Types; + Types.reserve(SegmentOffsets.size()); + + auto SO = makeArrayRef(SegmentOffsets); + + uint32_t End = SegmentWriter.getOffset(); + + Optional<TypeIndex> RefersTo; + for (uint32_t Offset : reverse(SO)) { + Types.push_back(createSegmentRecord(Offset, End, RefersTo)); + + End = Offset; + RefersTo = Index++; + } + + Kind.reset(); + return Types; +} + +// Explicitly instantiate the member function for each known type so that we can +// implement this in the cpp file. +#define TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \ + Name##Record &Record); +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp index 3d28bac00c..856bc26dfa 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp @@ -1,115 +1,115 @@ -//===- DebugChecksumsSubsection.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <cassert> -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -struct FileChecksumEntryHeader { - using ulittle32_t = support::ulittle32_t; - - ulittle32_t FileNameOffset; // Byte offset of filename in global string table. - uint8_t ChecksumSize; // Number of bytes of checksum. - uint8_t ChecksumKind; // FileChecksumKind - // Checksum bytes follow. -}; - -Error VarStreamArrayExtractor<FileChecksumEntry>:: -operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { - BinaryStreamReader Reader(Stream); - - const FileChecksumEntryHeader *Header; - if (auto EC = Reader.readObject(Header)) - return EC; - - Item.FileNameOffset = Header->FileNameOffset; - Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind); - if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize)) - return EC; - - Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4); - return Error::success(); -} - -Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) { - if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) - return EC; - - return Error::success(); -} - -Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) { - BinaryStreamReader Reader(Section); - return initialize(Reader); -} - -DebugChecksumsSubsection::DebugChecksumsSubsection( - DebugStringTableSubsection &Strings) - : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {} - -void DebugChecksumsSubsection::addChecksum(StringRef FileName, - FileChecksumKind Kind, - ArrayRef<uint8_t> Bytes) { - FileChecksumEntry Entry; - if (!Bytes.empty()) { - uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size()); - ::memcpy(Copy, Bytes.data(), Bytes.size()); - Entry.Checksum = makeArrayRef(Copy, Bytes.size()); - } - - Entry.FileNameOffset = Strings.insert(FileName); - Entry.Kind = Kind; - Checksums.push_back(Entry); - - // This maps the offset of this string in the string table to the offset - // of this checksum entry in the checksum buffer. - OffsetMap[Entry.FileNameOffset] = SerializedSize; - assert(SerializedSize % 4 == 0); - - uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4); - SerializedSize += Len; -} - -uint32_t DebugChecksumsSubsection::calculateSerializedSize() const { - return SerializedSize; -} - -Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const { - for (const auto &FC : Checksums) { - FileChecksumEntryHeader Header; - Header.ChecksumKind = uint8_t(FC.Kind); - Header.ChecksumSize = FC.Checksum.size(); - Header.FileNameOffset = FC.FileNameOffset; - if (auto EC = Writer.writeObject(Header)) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum))) - return EC; - if (auto EC = Writer.padToAlignment(4)) - return EC; - } - return Error::success(); -} - -uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const { - uint32_t Offset = Strings.getIdForString(FileName); - auto Iter = OffsetMap.find(Offset); - assert(Iter != OffsetMap.end()); - return Iter->second; -} +//===- DebugChecksumsSubsection.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +struct FileChecksumEntryHeader { + using ulittle32_t = support::ulittle32_t; + + ulittle32_t FileNameOffset; // Byte offset of filename in global string table. + uint8_t ChecksumSize; // Number of bytes of checksum. + uint8_t ChecksumKind; // FileChecksumKind + // Checksum bytes follow. +}; + +Error VarStreamArrayExtractor<FileChecksumEntry>:: +operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { + BinaryStreamReader Reader(Stream); + + const FileChecksumEntryHeader *Header; + if (auto EC = Reader.readObject(Header)) + return EC; + + Item.FileNameOffset = Header->FileNameOffset; + Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind); + if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize)) + return EC; + + Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4); + return Error::success(); +} + +Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) + return EC; + + return Error::success(); +} + +Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) { + BinaryStreamReader Reader(Section); + return initialize(Reader); +} + +DebugChecksumsSubsection::DebugChecksumsSubsection( + DebugStringTableSubsection &Strings) + : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {} + +void DebugChecksumsSubsection::addChecksum(StringRef FileName, + FileChecksumKind Kind, + ArrayRef<uint8_t> Bytes) { + FileChecksumEntry Entry; + if (!Bytes.empty()) { + uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size()); + ::memcpy(Copy, Bytes.data(), Bytes.size()); + Entry.Checksum = makeArrayRef(Copy, Bytes.size()); + } + + Entry.FileNameOffset = Strings.insert(FileName); + Entry.Kind = Kind; + Checksums.push_back(Entry); + + // This maps the offset of this string in the string table to the offset + // of this checksum entry in the checksum buffer. + OffsetMap[Entry.FileNameOffset] = SerializedSize; + assert(SerializedSize % 4 == 0); + + uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4); + SerializedSize += Len; +} + +uint32_t DebugChecksumsSubsection::calculateSerializedSize() const { + return SerializedSize; +} + +Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const { + for (const auto &FC : Checksums) { + FileChecksumEntryHeader Header; + Header.ChecksumKind = uint8_t(FC.Kind); + Header.ChecksumSize = FC.Checksum.size(); + Header.FileNameOffset = FC.FileNameOffset; + if (auto EC = Writer.writeObject(Header)) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum))) + return EC; + if (auto EC = Writer.padToAlignment(4)) + return EC; + } + return Error::success(); +} + +uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const { + uint32_t Offset = Strings.getIdForString(FileName); + auto Iter = OffsetMap.find(Offset); + assert(Iter != OffsetMap.end()); + return Iter->second; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp index b23410409f..2334e9f5f6 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp @@ -1,52 +1,52 @@ -//===- DebugCrossExSubsection.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -Error DebugCrossModuleExportsSubsectionRef::initialize( - BinaryStreamReader Reader) { - if (Reader.bytesRemaining() % sizeof(CrossModuleExport) != 0) - return make_error<CodeViewError>( - cv_error_code::corrupt_record, - "Cross Scope Exports section is an invalid size!"); - - uint32_t Size = Reader.bytesRemaining() / sizeof(CrossModuleExport); - return Reader.readArray(References, Size); -} - -Error DebugCrossModuleExportsSubsectionRef::initialize(BinaryStreamRef Stream) { - BinaryStreamReader Reader(Stream); - return initialize(Reader); -} - -void DebugCrossModuleExportsSubsection::addMapping(uint32_t Local, - uint32_t Global) { - Mappings[Local] = Global; -} - -uint32_t DebugCrossModuleExportsSubsection::calculateSerializedSize() const { - return Mappings.size() * sizeof(CrossModuleExport); -} - -Error DebugCrossModuleExportsSubsection::commit( - BinaryStreamWriter &Writer) const { - for (const auto &M : Mappings) { - if (auto EC = Writer.writeInteger(M.first)) - return EC; - if (auto EC = Writer.writeInteger(M.second)) - return EC; - } - return Error::success(); -} +//===- DebugCrossExSubsection.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +Error DebugCrossModuleExportsSubsectionRef::initialize( + BinaryStreamReader Reader) { + if (Reader.bytesRemaining() % sizeof(CrossModuleExport) != 0) + return make_error<CodeViewError>( + cv_error_code::corrupt_record, + "Cross Scope Exports section is an invalid size!"); + + uint32_t Size = Reader.bytesRemaining() / sizeof(CrossModuleExport); + return Reader.readArray(References, Size); +} + +Error DebugCrossModuleExportsSubsectionRef::initialize(BinaryStreamRef Stream) { + BinaryStreamReader Reader(Stream); + return initialize(Reader); +} + +void DebugCrossModuleExportsSubsection::addMapping(uint32_t Local, + uint32_t Global) { + Mappings[Local] = Global; +} + +uint32_t DebugCrossModuleExportsSubsection::calculateSerializedSize() const { + return Mappings.size() * sizeof(CrossModuleExport); +} + +Error DebugCrossModuleExportsSubsection::commit( + BinaryStreamWriter &Writer) const { + for (const auto &M : Mappings) { + if (auto EC = Writer.writeInteger(M.first)) + return EC; + if (auto EC = Writer.writeInteger(M.second)) + return EC; + } + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp index dbadafd3aa..58b479ae16 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp @@ -1,96 +1,96 @@ -//===- DebugCrossImpSubsection.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> -#include <utility> -#include <vector> - -using namespace llvm; -using namespace llvm::codeview; - -Error VarStreamArrayExtractor<CrossModuleImportItem>:: -operator()(BinaryStreamRef Stream, uint32_t &Len, - codeview::CrossModuleImportItem &Item) { - BinaryStreamReader Reader(Stream); - if (Reader.bytesRemaining() < sizeof(CrossModuleImport)) - return make_error<CodeViewError>( - cv_error_code::insufficient_buffer, - "Not enough bytes for a Cross Module Import Header!"); - if (auto EC = Reader.readObject(Item.Header)) - return EC; - if (Reader.bytesRemaining() < Item.Header->Count * sizeof(uint32_t)) - return make_error<CodeViewError>( - cv_error_code::insufficient_buffer, - "Not enough to read specified number of Cross Module References!"); - if (auto EC = Reader.readArray(Item.Imports, Item.Header->Count)) - return EC; - return Error::success(); -} - -Error DebugCrossModuleImportsSubsectionRef::initialize( - BinaryStreamReader Reader) { - return Reader.readArray(References, Reader.bytesRemaining()); -} - -Error DebugCrossModuleImportsSubsectionRef::initialize(BinaryStreamRef Stream) { - BinaryStreamReader Reader(Stream); - return initialize(Reader); -} - -void DebugCrossModuleImportsSubsection::addImport(StringRef Module, - uint32_t ImportId) { - Strings.insert(Module); - std::vector<support::ulittle32_t> Targets = {support::ulittle32_t(ImportId)}; - auto Result = Mappings.insert(std::make_pair(Module, Targets)); - if (!Result.second) - Result.first->getValue().push_back(Targets[0]); -} - -uint32_t DebugCrossModuleImportsSubsection::calculateSerializedSize() const { - uint32_t Size = 0; - for (const auto &Item : Mappings) { - Size += sizeof(CrossModuleImport); - Size += sizeof(support::ulittle32_t) * Item.second.size(); - } - return Size; -} - -Error DebugCrossModuleImportsSubsection::commit( - BinaryStreamWriter &Writer) const { - using T = decltype(&*Mappings.begin()); - std::vector<T> Ids; - Ids.reserve(Mappings.size()); - - for (const auto &M : Mappings) - Ids.push_back(&M); - - llvm::sort(Ids, [this](const T &L1, const T &L2) { - return Strings.getIdForString(L1->getKey()) < - Strings.getIdForString(L2->getKey()); - }); - - for (const auto &Item : Ids) { - CrossModuleImport Imp; - Imp.ModuleNameOffset = Strings.getIdForString(Item->getKey()); - Imp.Count = Item->getValue().size(); - if (auto EC = Writer.writeObject(Imp)) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(Item->getValue()))) - return EC; - } - return Error::success(); -} +//===- DebugCrossImpSubsection.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace llvm::codeview; + +Error VarStreamArrayExtractor<CrossModuleImportItem>:: +operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::CrossModuleImportItem &Item) { + BinaryStreamReader Reader(Stream); + if (Reader.bytesRemaining() < sizeof(CrossModuleImport)) + return make_error<CodeViewError>( + cv_error_code::insufficient_buffer, + "Not enough bytes for a Cross Module Import Header!"); + if (auto EC = Reader.readObject(Item.Header)) + return EC; + if (Reader.bytesRemaining() < Item.Header->Count * sizeof(uint32_t)) + return make_error<CodeViewError>( + cv_error_code::insufficient_buffer, + "Not enough to read specified number of Cross Module References!"); + if (auto EC = Reader.readArray(Item.Imports, Item.Header->Count)) + return EC; + return Error::success(); +} + +Error DebugCrossModuleImportsSubsectionRef::initialize( + BinaryStreamReader Reader) { + return Reader.readArray(References, Reader.bytesRemaining()); +} + +Error DebugCrossModuleImportsSubsectionRef::initialize(BinaryStreamRef Stream) { + BinaryStreamReader Reader(Stream); + return initialize(Reader); +} + +void DebugCrossModuleImportsSubsection::addImport(StringRef Module, + uint32_t ImportId) { + Strings.insert(Module); + std::vector<support::ulittle32_t> Targets = {support::ulittle32_t(ImportId)}; + auto Result = Mappings.insert(std::make_pair(Module, Targets)); + if (!Result.second) + Result.first->getValue().push_back(Targets[0]); +} + +uint32_t DebugCrossModuleImportsSubsection::calculateSerializedSize() const { + uint32_t Size = 0; + for (const auto &Item : Mappings) { + Size += sizeof(CrossModuleImport); + Size += sizeof(support::ulittle32_t) * Item.second.size(); + } + return Size; +} + +Error DebugCrossModuleImportsSubsection::commit( + BinaryStreamWriter &Writer) const { + using T = decltype(&*Mappings.begin()); + std::vector<T> Ids; + Ids.reserve(Mappings.size()); + + for (const auto &M : Mappings) + Ids.push_back(&M); + + llvm::sort(Ids, [this](const T &L1, const T &L2) { + return Strings.getIdForString(L1->getKey()) < + Strings.getIdForString(L2->getKey()); + }); + + for (const auto &Item : Ids) { + CrossModuleImport Imp; + Imp.ModuleNameOffset = Strings.getIdForString(Item->getKey()); + Imp.Count = Item->getValue().size(); + if (auto EC = Writer.writeObject(Imp)) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(Item->getValue()))) + return EC; + } + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp index 9bc69abea1..1da20b8144 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp @@ -1,60 +1,60 @@ -//===- DebugFrameDataSubsection.cpp -----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" - -using namespace llvm; -using namespace llvm::codeview; - -Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) { - if (Reader.bytesRemaining() % sizeof(FrameData) != 0) { - if (auto EC = Reader.readObject(RelocPtr)) - return EC; - } - - if (Reader.bytesRemaining() % sizeof(FrameData) != 0) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid frame data record format!"); - - uint32_t Count = Reader.bytesRemaining() / sizeof(FrameData); - if (auto EC = Reader.readArray(Frames, Count)) - return EC; - return Error::success(); -} - -Error DebugFrameDataSubsectionRef::initialize(BinaryStreamRef Section) { - BinaryStreamReader Reader(Section); - return initialize(Reader); -} - -uint32_t DebugFrameDataSubsection::calculateSerializedSize() const { - uint32_t Size = sizeof(FrameData) * Frames.size(); - if (IncludeRelocPtr) - Size += sizeof(uint32_t); - return Size; -} - -Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const { - if (IncludeRelocPtr) { - if (auto EC = Writer.writeInteger<uint32_t>(0)) - return EC; - } - - std::vector<FrameData> SortedFrames(Frames.begin(), Frames.end()); +//===- DebugFrameDataSubsection.cpp -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) { + if (Reader.bytesRemaining() % sizeof(FrameData) != 0) { + if (auto EC = Reader.readObject(RelocPtr)) + return EC; + } + + if (Reader.bytesRemaining() % sizeof(FrameData) != 0) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid frame data record format!"); + + uint32_t Count = Reader.bytesRemaining() / sizeof(FrameData); + if (auto EC = Reader.readArray(Frames, Count)) + return EC; + return Error::success(); +} + +Error DebugFrameDataSubsectionRef::initialize(BinaryStreamRef Section) { + BinaryStreamReader Reader(Section); + return initialize(Reader); +} + +uint32_t DebugFrameDataSubsection::calculateSerializedSize() const { + uint32_t Size = sizeof(FrameData) * Frames.size(); + if (IncludeRelocPtr) + Size += sizeof(uint32_t); + return Size; +} + +Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const { + if (IncludeRelocPtr) { + if (auto EC = Writer.writeInteger<uint32_t>(0)) + return EC; + } + + std::vector<FrameData> SortedFrames(Frames.begin(), Frames.end()); llvm::sort(SortedFrames, [](const FrameData &LHS, const FrameData &RHS) { return LHS.RvaStart < RHS.RvaStart; }); - if (auto EC = Writer.writeArray(makeArrayRef(SortedFrames))) - return EC; - return Error::success(); -} - -void DebugFrameDataSubsection::addFrameData(const FrameData &Frame) { - Frames.push_back(Frame); -} + if (auto EC = Writer.writeArray(makeArrayRef(SortedFrames))) + return EC; + return Error::success(); +} + +void DebugFrameDataSubsection::addFrameData(const FrameData &Frame) { + Frames.push_back(Frame); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp index 48ec7e4ecd..4893b3fab7 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp @@ -1,125 +1,125 @@ -//===- DebugInlineeLinesSubsection.cpp ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <cassert> -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -Error VarStreamArrayExtractor<InlineeSourceLine>:: -operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) { - BinaryStreamReader Reader(Stream); - - if (auto EC = Reader.readObject(Item.Header)) - return EC; - - if (HasExtraFiles) { - uint32_t ExtraFileCount; - if (auto EC = Reader.readInteger(ExtraFileCount)) - return EC; - if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount)) - return EC; - } - - Len = Reader.getOffset(); - return Error::success(); -} - -DebugInlineeLinesSubsectionRef::DebugInlineeLinesSubsectionRef() - : DebugSubsectionRef(DebugSubsectionKind::InlineeLines) {} - -Error DebugInlineeLinesSubsectionRef::initialize(BinaryStreamReader Reader) { - if (auto EC = Reader.readEnum(Signature)) - return EC; - - Lines.getExtractor().HasExtraFiles = hasExtraFiles(); - if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining())) - return EC; - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} - -bool DebugInlineeLinesSubsectionRef::hasExtraFiles() const { - return Signature == InlineeLinesSignature::ExtraFiles; -} - -DebugInlineeLinesSubsection::DebugInlineeLinesSubsection( - DebugChecksumsSubsection &Checksums, bool HasExtraFiles) - : DebugSubsection(DebugSubsectionKind::InlineeLines), Checksums(Checksums), - HasExtraFiles(HasExtraFiles) {} - -uint32_t DebugInlineeLinesSubsection::calculateSerializedSize() const { - // 4 bytes for the signature - uint32_t Size = sizeof(InlineeLinesSignature); - - // one header for each entry. - Size += Entries.size() * sizeof(InlineeSourceLineHeader); - if (HasExtraFiles) { - // If extra files are enabled, one count for each entry. - Size += Entries.size() * sizeof(uint32_t); - - // And one file id for each file. - Size += ExtraFileCount * sizeof(uint32_t); - } - assert(Size % 4 == 0); - return Size; -} - -Error DebugInlineeLinesSubsection::commit(BinaryStreamWriter &Writer) const { - InlineeLinesSignature Sig = InlineeLinesSignature::Normal; - if (HasExtraFiles) - Sig = InlineeLinesSignature::ExtraFiles; - - if (auto EC = Writer.writeEnum(Sig)) - return EC; - - for (const auto &E : Entries) { - if (auto EC = Writer.writeObject(E.Header)) - return EC; - - if (!HasExtraFiles) - continue; - - if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size())) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles))) - return EC; - } - - return Error::success(); -} - -void DebugInlineeLinesSubsection::addExtraFile(StringRef FileName) { - uint32_t Offset = Checksums.mapChecksumOffset(FileName); - - auto &Entry = Entries.back(); - Entry.ExtraFiles.push_back(ulittle32_t(Offset)); - ++ExtraFileCount; -} - -void DebugInlineeLinesSubsection::addInlineSite(TypeIndex FuncId, - StringRef FileName, - uint32_t SourceLine) { - uint32_t Offset = Checksums.mapChecksumOffset(FileName); - - Entries.emplace_back(); - auto &Entry = Entries.back(); - Entry.Header.FileID = Offset; - Entry.Header.SourceLineNum = SourceLine; - Entry.Header.Inlinee = FuncId; -} +//===- DebugInlineeLinesSubsection.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +Error VarStreamArrayExtractor<InlineeSourceLine>:: +operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) { + BinaryStreamReader Reader(Stream); + + if (auto EC = Reader.readObject(Item.Header)) + return EC; + + if (HasExtraFiles) { + uint32_t ExtraFileCount; + if (auto EC = Reader.readInteger(ExtraFileCount)) + return EC; + if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount)) + return EC; + } + + Len = Reader.getOffset(); + return Error::success(); +} + +DebugInlineeLinesSubsectionRef::DebugInlineeLinesSubsectionRef() + : DebugSubsectionRef(DebugSubsectionKind::InlineeLines) {} + +Error DebugInlineeLinesSubsectionRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readEnum(Signature)) + return EC; + + Lines.getExtractor().HasExtraFiles = hasExtraFiles(); + if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining())) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +bool DebugInlineeLinesSubsectionRef::hasExtraFiles() const { + return Signature == InlineeLinesSignature::ExtraFiles; +} + +DebugInlineeLinesSubsection::DebugInlineeLinesSubsection( + DebugChecksumsSubsection &Checksums, bool HasExtraFiles) + : DebugSubsection(DebugSubsectionKind::InlineeLines), Checksums(Checksums), + HasExtraFiles(HasExtraFiles) {} + +uint32_t DebugInlineeLinesSubsection::calculateSerializedSize() const { + // 4 bytes for the signature + uint32_t Size = sizeof(InlineeLinesSignature); + + // one header for each entry. + Size += Entries.size() * sizeof(InlineeSourceLineHeader); + if (HasExtraFiles) { + // If extra files are enabled, one count for each entry. + Size += Entries.size() * sizeof(uint32_t); + + // And one file id for each file. + Size += ExtraFileCount * sizeof(uint32_t); + } + assert(Size % 4 == 0); + return Size; +} + +Error DebugInlineeLinesSubsection::commit(BinaryStreamWriter &Writer) const { + InlineeLinesSignature Sig = InlineeLinesSignature::Normal; + if (HasExtraFiles) + Sig = InlineeLinesSignature::ExtraFiles; + + if (auto EC = Writer.writeEnum(Sig)) + return EC; + + for (const auto &E : Entries) { + if (auto EC = Writer.writeObject(E.Header)) + return EC; + + if (!HasExtraFiles) + continue; + + if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size())) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles))) + return EC; + } + + return Error::success(); +} + +void DebugInlineeLinesSubsection::addExtraFile(StringRef FileName) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + auto &Entry = Entries.back(); + Entry.ExtraFiles.push_back(ulittle32_t(Offset)); + ++ExtraFileCount; +} + +void DebugInlineeLinesSubsection::addInlineSite(TypeIndex FuncId, + StringRef FileName, + uint32_t SourceLine) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + Entries.emplace_back(); + auto &Entry = Entries.back(); + Entry.Header.FileID = Offset; + Entry.Header.SourceLineNum = SourceLine; + Entry.Header.Inlinee = FuncId; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp index ea16c0a6c6..e653d77092 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp @@ -1,160 +1,160 @@ -//===- DebugLinesSubsection.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include <cassert> -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len, - LineColumnEntry &Item) { - const LineBlockFragmentHeader *BlockHeader; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readObject(BlockHeader)) - return EC; - bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns); - uint32_t LineInfoSize = - BlockHeader->NumLines * - (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); - if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader)) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid line block record size"); - uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader); - if (LineInfoSize > Size) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid line block record size"); - // The value recorded in BlockHeader->BlockSize includes the size of - // LineBlockFragmentHeader. - Len = BlockHeader->BlockSize; - Item.NameIndex = BlockHeader->NameIndex; - if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) - return EC; - if (HasColumn) { - if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) - return EC; - } - return Error::success(); -} - -DebugLinesSubsectionRef::DebugLinesSubsectionRef() - : DebugSubsectionRef(DebugSubsectionKind::Lines) {} - -Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) { - if (auto EC = Reader.readObject(Header)) - return EC; - - LinesAndColumns.getExtractor().Header = Header; - if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining())) - return EC; - - return Error::success(); -} - -bool DebugLinesSubsectionRef::hasColumnInfo() const { - return !!(Header->Flags & LF_HaveColumns); -} - -DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums, - DebugStringTableSubsection &Strings) - : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {} - -void DebugLinesSubsection::createBlock(StringRef FileName) { - uint32_t Offset = Checksums.mapChecksumOffset(FileName); - - Blocks.emplace_back(Offset); -} - -void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) { - Block &B = Blocks.back(); - LineNumberEntry LNE; - LNE.Flags = Line.getRawData(); - LNE.Offset = Offset; - B.Lines.push_back(LNE); -} - -void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset, - const LineInfo &Line, - uint32_t ColStart, - uint32_t ColEnd) { - Block &B = Blocks.back(); - assert(B.Lines.size() == B.Columns.size()); - - addLineInfo(Offset, Line); - ColumnNumberEntry CNE; - CNE.StartColumn = ColStart; - CNE.EndColumn = ColEnd; - B.Columns.push_back(CNE); -} - -Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const { - LineFragmentHeader Header; - Header.CodeSize = CodeSize; - Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0; - Header.RelocOffset = RelocOffset; - Header.RelocSegment = RelocSegment; - - if (auto EC = Writer.writeObject(Header)) - return EC; - - for (const auto &B : Blocks) { - LineBlockFragmentHeader BlockHeader; - assert(B.Lines.size() == B.Columns.size() || B.Columns.empty()); - - BlockHeader.NumLines = B.Lines.size(); - BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader); - BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry); - if (hasColumnInfo()) - BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry); - BlockHeader.NameIndex = B.ChecksumBufferOffset; - if (auto EC = Writer.writeObject(BlockHeader)) - return EC; - - if (auto EC = Writer.writeArray(makeArrayRef(B.Lines))) - return EC; - - if (hasColumnInfo()) { - if (auto EC = Writer.writeArray(makeArrayRef(B.Columns))) - return EC; - } - } - return Error::success(); -} - -uint32_t DebugLinesSubsection::calculateSerializedSize() const { - uint32_t Size = sizeof(LineFragmentHeader); - for (const auto &B : Blocks) { - Size += sizeof(LineBlockFragmentHeader); - Size += B.Lines.size() * sizeof(LineNumberEntry); - if (hasColumnInfo()) - Size += B.Columns.size() * sizeof(ColumnNumberEntry); - } - return Size; -} - -void DebugLinesSubsection::setRelocationAddress(uint16_t Segment, - uint32_t Offset) { - RelocOffset = Offset; - RelocSegment = Segment; -} - -void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; } - -void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; } - -bool DebugLinesSubsection::hasColumnInfo() const { - return Flags & LF_HaveColumns; -} +//===- DebugLinesSubsection.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) { + const LineBlockFragmentHeader *BlockHeader; + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readObject(BlockHeader)) + return EC; + bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns); + uint32_t LineInfoSize = + BlockHeader->NumLines * + (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); + if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader)) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader); + if (LineInfoSize > Size) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Invalid line block record size"); + // The value recorded in BlockHeader->BlockSize includes the size of + // LineBlockFragmentHeader. + Len = BlockHeader->BlockSize; + Item.NameIndex = BlockHeader->NameIndex; + if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) + return EC; + if (HasColumn) { + if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) + return EC; + } + return Error::success(); +} + +DebugLinesSubsectionRef::DebugLinesSubsectionRef() + : DebugSubsectionRef(DebugSubsectionKind::Lines) {} + +Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) { + if (auto EC = Reader.readObject(Header)) + return EC; + + LinesAndColumns.getExtractor().Header = Header; + if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining())) + return EC; + + return Error::success(); +} + +bool DebugLinesSubsectionRef::hasColumnInfo() const { + return !!(Header->Flags & LF_HaveColumns); +} + +DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums, + DebugStringTableSubsection &Strings) + : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {} + +void DebugLinesSubsection::createBlock(StringRef FileName) { + uint32_t Offset = Checksums.mapChecksumOffset(FileName); + + Blocks.emplace_back(Offset); +} + +void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) { + Block &B = Blocks.back(); + LineNumberEntry LNE; + LNE.Flags = Line.getRawData(); + LNE.Offset = Offset; + B.Lines.push_back(LNE); +} + +void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset, + const LineInfo &Line, + uint32_t ColStart, + uint32_t ColEnd) { + Block &B = Blocks.back(); + assert(B.Lines.size() == B.Columns.size()); + + addLineInfo(Offset, Line); + ColumnNumberEntry CNE; + CNE.StartColumn = ColStart; + CNE.EndColumn = ColEnd; + B.Columns.push_back(CNE); +} + +Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const { + LineFragmentHeader Header; + Header.CodeSize = CodeSize; + Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0; + Header.RelocOffset = RelocOffset; + Header.RelocSegment = RelocSegment; + + if (auto EC = Writer.writeObject(Header)) + return EC; + + for (const auto &B : Blocks) { + LineBlockFragmentHeader BlockHeader; + assert(B.Lines.size() == B.Columns.size() || B.Columns.empty()); + + BlockHeader.NumLines = B.Lines.size(); + BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader); + BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry); + if (hasColumnInfo()) + BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry); + BlockHeader.NameIndex = B.ChecksumBufferOffset; + if (auto EC = Writer.writeObject(BlockHeader)) + return EC; + + if (auto EC = Writer.writeArray(makeArrayRef(B.Lines))) + return EC; + + if (hasColumnInfo()) { + if (auto EC = Writer.writeArray(makeArrayRef(B.Columns))) + return EC; + } + } + return Error::success(); +} + +uint32_t DebugLinesSubsection::calculateSerializedSize() const { + uint32_t Size = sizeof(LineFragmentHeader); + for (const auto &B : Blocks) { + Size += sizeof(LineBlockFragmentHeader); + Size += B.Lines.size() * sizeof(LineNumberEntry); + if (hasColumnInfo()) + Size += B.Columns.size() * sizeof(ColumnNumberEntry); + } + return Size; +} + +void DebugLinesSubsection::setRelocationAddress(uint16_t Segment, + uint32_t Offset) { + RelocOffset = Offset; + RelocSegment = Segment; +} + +void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; } + +void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; } + +bool DebugLinesSubsection::hasColumnInfo() const { + return Flags & LF_HaveColumns; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp index 6334274991..205678c500 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp @@ -1,107 +1,107 @@ -//===- DebugStringTableSubsection.cpp - CodeView String Table -------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -DebugStringTableSubsectionRef::DebugStringTableSubsectionRef() - : DebugSubsectionRef(DebugSubsectionKind::StringTable) {} - -Error DebugStringTableSubsectionRef::initialize(BinaryStreamRef Contents) { - Stream = Contents; - return Error::success(); -} - -Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) { - return Reader.readStreamRef(Stream); -} - -Expected<StringRef> -DebugStringTableSubsectionRef::getString(uint32_t Offset) const { - BinaryStreamReader Reader(Stream); - Reader.setOffset(Offset); - StringRef Result; - if (auto EC = Reader.readCString(Result)) - return std::move(EC); - return Result; -} - -DebugStringTableSubsection::DebugStringTableSubsection() - : DebugSubsection(DebugSubsectionKind::StringTable) {} - -uint32_t DebugStringTableSubsection::insert(StringRef S) { - auto P = StringToId.insert({S, StringSize}); - - // If a given string didn't exist in the string table, we want to increment - // the string table size and insert it into the reverse lookup. - if (P.second) { - IdToString.insert({P.first->getValue(), P.first->getKey()}); - StringSize += S.size() + 1; // +1 for '\0' - } - - return P.first->second; -} - -uint32_t DebugStringTableSubsection::calculateSerializedSize() const { - return StringSize; -} - -Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const { - uint32_t Begin = Writer.getOffset(); - uint32_t End = Begin + StringSize; - - // Write a null string at the beginning. - if (auto EC = Writer.writeCString(StringRef())) - return EC; - - for (auto &Pair : StringToId) { - StringRef S = Pair.getKey(); - uint32_t Offset = Begin + Pair.getValue(); - Writer.setOffset(Offset); - if (auto EC = Writer.writeCString(S)) - return EC; - assert(Writer.getOffset() <= End); - } - - Writer.setOffset(End); - assert((End - Begin) == StringSize); - return Error::success(); -} - -uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); } - -std::vector<uint32_t> DebugStringTableSubsection::sortedIds() const { - std::vector<uint32_t> Result; - Result.reserve(IdToString.size()); - for (const auto &Entry : IdToString) - Result.push_back(Entry.first); - llvm::sort(Result); - return Result; -} - -uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const { - auto Iter = StringToId.find(S); - assert(Iter != StringToId.end()); - return Iter->second; -} - -StringRef DebugStringTableSubsection::getStringForId(uint32_t Id) const { - auto Iter = IdToString.find(Id); - assert(Iter != IdToString.end()); - return Iter->second; -} +//===- DebugStringTableSubsection.cpp - CodeView String Table -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +DebugStringTableSubsectionRef::DebugStringTableSubsectionRef() + : DebugSubsectionRef(DebugSubsectionKind::StringTable) {} + +Error DebugStringTableSubsectionRef::initialize(BinaryStreamRef Contents) { + Stream = Contents; + return Error::success(); +} + +Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) { + return Reader.readStreamRef(Stream); +} + +Expected<StringRef> +DebugStringTableSubsectionRef::getString(uint32_t Offset) const { + BinaryStreamReader Reader(Stream); + Reader.setOffset(Offset); + StringRef Result; + if (auto EC = Reader.readCString(Result)) + return std::move(EC); + return Result; +} + +DebugStringTableSubsection::DebugStringTableSubsection() + : DebugSubsection(DebugSubsectionKind::StringTable) {} + +uint32_t DebugStringTableSubsection::insert(StringRef S) { + auto P = StringToId.insert({S, StringSize}); + + // If a given string didn't exist in the string table, we want to increment + // the string table size and insert it into the reverse lookup. + if (P.second) { + IdToString.insert({P.first->getValue(), P.first->getKey()}); + StringSize += S.size() + 1; // +1 for '\0' + } + + return P.first->second; +} + +uint32_t DebugStringTableSubsection::calculateSerializedSize() const { + return StringSize; +} + +Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const { + uint32_t Begin = Writer.getOffset(); + uint32_t End = Begin + StringSize; + + // Write a null string at the beginning. + if (auto EC = Writer.writeCString(StringRef())) + return EC; + + for (auto &Pair : StringToId) { + StringRef S = Pair.getKey(); + uint32_t Offset = Begin + Pair.getValue(); + Writer.setOffset(Offset); + if (auto EC = Writer.writeCString(S)) + return EC; + assert(Writer.getOffset() <= End); + } + + Writer.setOffset(End); + assert((End - Begin) == StringSize); + return Error::success(); +} + +uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); } + +std::vector<uint32_t> DebugStringTableSubsection::sortedIds() const { + std::vector<uint32_t> Result; + Result.reserve(IdToString.size()); + for (const auto &Entry : IdToString) + Result.push_back(Entry.first); + llvm::sort(Result); + return Result; +} + +uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const { + auto Iter = StringToId.find(S); + assert(Iter != StringToId.end()); + return Iter->second; +} + +StringRef DebugStringTableSubsection::getStringForId(uint32_t Id) const { + auto Iter = IdToString.find(Id); + assert(Iter != IdToString.end()); + return Iter->second; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsection.cpp index 3f93463fe6..484afa6653 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsection.cpp @@ -1,15 +1,15 @@ -//===- DebugSubsection.cpp -----------------------------------*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugSubsection.h" - -using namespace llvm::codeview; - -DebugSubsectionRef::~DebugSubsectionRef() {} - -DebugSubsection::~DebugSubsection() {} +//===- DebugSubsection.cpp -----------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugSubsection.h" + +using namespace llvm::codeview; + +DebugSubsectionRef::~DebugSubsectionRef() {} + +DebugSubsection::~DebugSubsection() {} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp index 3c8a301014..9070125d82 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp @@ -1,94 +1,94 @@ -//===- DebugSubsectionRecord.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/DebugSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <algorithm> -#include <cassert> -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -DebugSubsectionRecord::DebugSubsectionRecord() = default; - -DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind, - BinaryStreamRef Data) - : Kind(Kind), Data(Data) {} - -Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream, - DebugSubsectionRecord &Info) { - const DebugSubsectionHeader *Header; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readObject(Header)) - return EC; - - DebugSubsectionKind Kind = - static_cast<DebugSubsectionKind>(uint32_t(Header->Kind)); - if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) - return EC; - Info.Kind = Kind; - return Error::success(); -} - -uint32_t DebugSubsectionRecord::getRecordLength() const { - return sizeof(DebugSubsectionHeader) + Data.getLength(); -} - -DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; } - -BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; } - -DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( - std::shared_ptr<DebugSubsection> Subsection) - : Subsection(std::move(Subsection)) {} - -DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( - const DebugSubsectionRecord &Contents) - : Contents(Contents) {} - -uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() const { - uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() - : Contents.getRecordData().getLength(); - // The length of the entire subsection is always padded to 4 bytes, - // regardless of the container kind. - return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4); -} - -Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer, - CodeViewContainer Container) const { - assert(Writer.getOffset() % alignOf(Container) == 0 && - "Debug Subsection not properly aligned"); - - DebugSubsectionHeader Header; - Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind()); - // The value written into the Header's Length field is only padded to the - // container's alignment - uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() - : Contents.getRecordData().getLength(); - Header.Length = alignTo(DataSize, alignOf(Container)); - - if (auto EC = Writer.writeObject(Header)) - return EC; - if (Subsection) { - if (auto EC = Subsection->commit(Writer)) - return EC; - } else { - if (auto EC = Writer.writeStreamRef(Contents.getRecordData())) - return EC; - } - if (auto EC = Writer.padToAlignment(4)) - return EC; - - return Error::success(); -} +//===- DebugSubsectionRecord.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +DebugSubsectionRecord::DebugSubsectionRecord() = default; + +DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind, + BinaryStreamRef Data) + : Kind(Kind), Data(Data) {} + +Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream, + DebugSubsectionRecord &Info) { + const DebugSubsectionHeader *Header; + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readObject(Header)) + return EC; + + DebugSubsectionKind Kind = + static_cast<DebugSubsectionKind>(uint32_t(Header->Kind)); + if (auto EC = Reader.readStreamRef(Info.Data, Header->Length)) + return EC; + Info.Kind = Kind; + return Error::success(); +} + +uint32_t DebugSubsectionRecord::getRecordLength() const { + return sizeof(DebugSubsectionHeader) + Data.getLength(); +} + +DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; } + +BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; } + +DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( + std::shared_ptr<DebugSubsection> Subsection) + : Subsection(std::move(Subsection)) {} + +DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( + const DebugSubsectionRecord &Contents) + : Contents(Contents) {} + +uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() const { + uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() + : Contents.getRecordData().getLength(); + // The length of the entire subsection is always padded to 4 bytes, + // regardless of the container kind. + return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4); +} + +Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer, + CodeViewContainer Container) const { + assert(Writer.getOffset() % alignOf(Container) == 0 && + "Debug Subsection not properly aligned"); + + DebugSubsectionHeader Header; + Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind()); + // The value written into the Header's Length field is only padded to the + // container's alignment + uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() + : Contents.getRecordData().getLength(); + Header.Length = alignTo(DataSize, alignOf(Container)); + + if (auto EC = Writer.writeObject(Header)) + return EC; + if (Subsection) { + if (auto EC = Subsection->commit(Writer)) + return EC; + } else { + if (auto EC = Writer.writeStreamRef(Contents.getRecordData())) + return EC; + } + if (auto EC = Writer.padToAlignment(4)) + return EC; + + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp index 7968b6a2d7..b6c46fe4cc 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp @@ -1,94 +1,94 @@ -//===- DebugSubsectionVisitor.cpp -------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" - -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamRef.h" - -using namespace llvm; -using namespace llvm::codeview; - -Error llvm::codeview::visitDebugSubsection( - const DebugSubsectionRecord &R, DebugSubsectionVisitor &V, - const StringsAndChecksumsRef &State) { - BinaryStreamReader Reader(R.getRecordData()); - switch (R.kind()) { - case DebugSubsectionKind::Lines: { - DebugLinesSubsectionRef Fragment; - if (auto EC = Fragment.initialize(Reader)) - return EC; - - return V.visitLines(Fragment, State); - } - case DebugSubsectionKind::FileChecksums: { - DebugChecksumsSubsectionRef Fragment; - if (auto EC = Fragment.initialize(Reader)) - return EC; - - return V.visitFileChecksums(Fragment, State); - } - case DebugSubsectionKind::InlineeLines: { - DebugInlineeLinesSubsectionRef Fragment; - if (auto EC = Fragment.initialize(Reader)) - return EC; - return V.visitInlineeLines(Fragment, State); - } - case DebugSubsectionKind::CrossScopeExports: { - DebugCrossModuleExportsSubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitCrossModuleExports(Section, State); - } - case DebugSubsectionKind::CrossScopeImports: { - DebugCrossModuleImportsSubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitCrossModuleImports(Section, State); - } - case DebugSubsectionKind::Symbols: { - DebugSymbolsSubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitSymbols(Section, State); - } - case DebugSubsectionKind::StringTable: { - DebugStringTableSubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitStringTable(Section, State); - } - case DebugSubsectionKind::FrameData: { - DebugFrameDataSubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitFrameData(Section, State); - } - case DebugSubsectionKind::CoffSymbolRVA: { - DebugSymbolRVASubsectionRef Section; - if (auto EC = Section.initialize(Reader)) - return EC; - return V.visitCOFFSymbolRVAs(Section, State); - } - default: { - DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData()); - return V.visitUnknown(Fragment); - } - } -} +//===- DebugSubsectionVisitor.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" + +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error llvm::codeview::visitDebugSubsection( + const DebugSubsectionRecord &R, DebugSubsectionVisitor &V, + const StringsAndChecksumsRef &State) { + BinaryStreamReader Reader(R.getRecordData()); + switch (R.kind()) { + case DebugSubsectionKind::Lines: { + DebugLinesSubsectionRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + + return V.visitLines(Fragment, State); + } + case DebugSubsectionKind::FileChecksums: { + DebugChecksumsSubsectionRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + + return V.visitFileChecksums(Fragment, State); + } + case DebugSubsectionKind::InlineeLines: { + DebugInlineeLinesSubsectionRef Fragment; + if (auto EC = Fragment.initialize(Reader)) + return EC; + return V.visitInlineeLines(Fragment, State); + } + case DebugSubsectionKind::CrossScopeExports: { + DebugCrossModuleExportsSubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitCrossModuleExports(Section, State); + } + case DebugSubsectionKind::CrossScopeImports: { + DebugCrossModuleImportsSubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitCrossModuleImports(Section, State); + } + case DebugSubsectionKind::Symbols: { + DebugSymbolsSubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitSymbols(Section, State); + } + case DebugSubsectionKind::StringTable: { + DebugStringTableSubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitStringTable(Section, State); + } + case DebugSubsectionKind::FrameData: { + DebugFrameDataSubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitFrameData(Section, State); + } + case DebugSubsectionKind::CoffSymbolRVA: { + DebugSymbolRVASubsectionRef Section; + if (auto EC = Section.initialize(Reader)) + return EC; + return V.visitCOFFSymbolRVAs(Section, State); + } + default: { + DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData()); + return V.visitUnknown(Fragment); + } + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp index 5232896735..eb5c4129fe 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp @@ -1,35 +1,35 @@ -//===- DebugSymbolRVASubsection.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include <cstdint> - -using namespace llvm; -using namespace llvm::codeview; - -DebugSymbolRVASubsectionRef::DebugSymbolRVASubsectionRef() - : DebugSubsectionRef(DebugSubsectionKind::CoffSymbolRVA) {} - -Error DebugSymbolRVASubsectionRef::initialize(BinaryStreamReader &Reader) { - return Reader.readArray(RVAs, Reader.bytesRemaining() / sizeof(uint32_t)); -} - -DebugSymbolRVASubsection::DebugSymbolRVASubsection() - : DebugSubsection(DebugSubsectionKind::CoffSymbolRVA) {} - -Error DebugSymbolRVASubsection::commit(BinaryStreamWriter &Writer) const { - return Writer.writeArray(makeArrayRef(RVAs)); -} - -uint32_t DebugSymbolRVASubsection::calculateSerializedSize() const { - return RVAs.size() * sizeof(uint32_t); -} +//===- DebugSymbolRVASubsection.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include <cstdint> + +using namespace llvm; +using namespace llvm::codeview; + +DebugSymbolRVASubsectionRef::DebugSymbolRVASubsectionRef() + : DebugSubsectionRef(DebugSubsectionKind::CoffSymbolRVA) {} + +Error DebugSymbolRVASubsectionRef::initialize(BinaryStreamReader &Reader) { + return Reader.readArray(RVAs, Reader.bytesRemaining() / sizeof(uint32_t)); +} + +DebugSymbolRVASubsection::DebugSymbolRVASubsection() + : DebugSubsection(DebugSubsectionKind::CoffSymbolRVA) {} + +Error DebugSymbolRVASubsection::commit(BinaryStreamWriter &Writer) const { + return Writer.writeArray(makeArrayRef(RVAs)); +} + +uint32_t DebugSymbolRVASubsection::calculateSerializedSize() const { + return RVAs.size() * sizeof(uint32_t); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp index c833103663..0719ebff7e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp @@ -1,33 +1,33 @@ -//===- DebugSymbolsSubsection.cpp -------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" - -using namespace llvm; -using namespace llvm::codeview; - -Error DebugSymbolsSubsectionRef::initialize(BinaryStreamReader Reader) { - return Reader.readArray(Records, Reader.getLength()); -} - -uint32_t DebugSymbolsSubsection::calculateSerializedSize() const { - return Length; -} - -Error DebugSymbolsSubsection::commit(BinaryStreamWriter &Writer) const { - for (const auto &Record : Records) { - if (auto EC = Writer.writeBytes(Record.RecordData)) - return EC; - } - return Error::success(); -} - -void DebugSymbolsSubsection::addSymbol(CVSymbol Symbol) { - Records.push_back(Symbol); - Length += Symbol.length(); -} +//===- DebugSymbolsSubsection.cpp -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" + +using namespace llvm; +using namespace llvm::codeview; + +Error DebugSymbolsSubsectionRef::initialize(BinaryStreamReader Reader) { + return Reader.readArray(Records, Reader.getLength()); +} + +uint32_t DebugSymbolsSubsection::calculateSerializedSize() const { + return Length; +} + +Error DebugSymbolsSubsection::commit(BinaryStreamWriter &Writer) const { + for (const auto &Record : Records) { + if (auto EC = Writer.writeBytes(Record.RecordData)) + return EC; + } + return Error::success(); +} + +void DebugSymbolsSubsection::addSymbol(CVSymbol Symbol) { + Records.push_back(Symbol); + Length += Symbol.length(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/EnumTables.cpp index 949707bf54..62e84f9769 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/EnumTables.cpp @@ -1,44 +1,44 @@ -//===- EnumTables.cpp - Enum to string conversion tables ------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/EnumTables.h" -#include "llvm/Support/ScopedPrinter.h" -#include <type_traits> - -using namespace llvm; -using namespace codeview; - -#define CV_ENUM_CLASS_ENT(enum_class, enum) \ - { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } - -#define CV_ENUM_ENT(ns, enum) \ - { #enum, ns::enum } - -static const EnumEntry<SymbolKind> SymbolTypeNames[] = { -#define CV_SYMBOL(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" -#undef CV_SYMBOL -}; - -static const EnumEntry<TypeLeafKind> TypeLeafNames[] = { -#define CV_TYPE(name, val) {#name, name}, -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -#undef CV_TYPE -}; - -static const EnumEntry<uint16_t> RegisterNames_X86[] = { -#define CV_REGISTERS_X86 -#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), -#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" -#undef CV_REGISTER -#undef CV_REGISTERS_X86 -}; - +//===- EnumTables.cpp - Enum to string conversion tables ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/Support/ScopedPrinter.h" +#include <type_traits> + +using namespace llvm; +using namespace codeview; + +#define CV_ENUM_CLASS_ENT(enum_class, enum) \ + { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } + +#define CV_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } + +static const EnumEntry<SymbolKind> SymbolTypeNames[] = { +#define CV_SYMBOL(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" +#undef CV_SYMBOL +}; + +static const EnumEntry<TypeLeafKind> TypeLeafNames[] = { +#define CV_TYPE(name, val) {#name, name}, +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +#undef CV_TYPE +}; + +static const EnumEntry<uint16_t> RegisterNames_X86[] = { +#define CV_REGISTERS_X86 +#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_X86 +}; + static const EnumEntry<uint16_t> RegisterNames_ARM[] = { #define CV_REGISTERS_ARM #define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), @@ -47,513 +47,513 @@ static const EnumEntry<uint16_t> RegisterNames_ARM[] = { #undef CV_REGISTERS_ARM }; -static const EnumEntry<uint16_t> RegisterNames_ARM64[] = { -#define CV_REGISTERS_ARM64 -#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), -#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" -#undef CV_REGISTER -#undef CV_REGISTERS_ARM64 -}; - -static const EnumEntry<uint32_t> PublicSymFlagNames[] = { - CV_ENUM_CLASS_ENT(PublicSymFlags, Code), - CV_ENUM_CLASS_ENT(PublicSymFlags, Function), - CV_ENUM_CLASS_ENT(PublicSymFlags, Managed), - CV_ENUM_CLASS_ENT(PublicSymFlags, MSIL), -}; - -static const EnumEntry<uint8_t> ProcSymFlagNames[] = { - CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP), - CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET), - CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET), - CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn), - CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable), - CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv), - CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline), - CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo), -}; - -static const EnumEntry<uint16_t> LocalFlags[] = { - CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal), - CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic), -}; - -static const EnumEntry<uint8_t> FrameCookieKinds[] = { - CV_ENUM_CLASS_ENT(FrameCookieKind, Copy), - CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer), - CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer), - CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13), -}; - -static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = { - CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp), - CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm), - CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic), - CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link), - CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd), - CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB), - CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java), - CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL), - CV_ENUM_ENT(SourceLanguage, HLSL), CV_ENUM_ENT(SourceLanguage, D), - CV_ENUM_ENT(SourceLanguage, Swift), -}; - -static const EnumEntry<uint32_t> CompileSym2FlagNames[] = { - CV_ENUM_CLASS_ENT(CompileSym2Flags, EC), - CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo), - CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG), - CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign), - CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent), - CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks), - CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch), - CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL), - CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule), -}; - -static const EnumEntry<uint32_t> CompileSym3FlagNames[] = { - CV_ENUM_CLASS_ENT(CompileSym3Flags, EC), - CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo), - CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG), - CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign), - CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent), - CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks), - CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch), - CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL), - CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule), - CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl), - CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO), - CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp), -}; - -static const EnumEntry<uint32_t> FileChecksumNames[] = { - CV_ENUM_CLASS_ENT(FileChecksumKind, None), - CV_ENUM_CLASS_ENT(FileChecksumKind, MD5), - CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1), - CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256), -}; - -static const EnumEntry<unsigned> CPUTypeNames[] = { - CV_ENUM_CLASS_ENT(CPUType, Intel8080), - CV_ENUM_CLASS_ENT(CPUType, Intel8086), - CV_ENUM_CLASS_ENT(CPUType, Intel80286), - CV_ENUM_CLASS_ENT(CPUType, Intel80386), - CV_ENUM_CLASS_ENT(CPUType, Intel80486), - CV_ENUM_CLASS_ENT(CPUType, Pentium), - CV_ENUM_CLASS_ENT(CPUType, PentiumPro), - CV_ENUM_CLASS_ENT(CPUType, Pentium3), - CV_ENUM_CLASS_ENT(CPUType, MIPS), - CV_ENUM_CLASS_ENT(CPUType, MIPS16), - CV_ENUM_CLASS_ENT(CPUType, MIPS32), - CV_ENUM_CLASS_ENT(CPUType, MIPS64), - CV_ENUM_CLASS_ENT(CPUType, MIPSI), - CV_ENUM_CLASS_ENT(CPUType, MIPSII), - CV_ENUM_CLASS_ENT(CPUType, MIPSIII), - CV_ENUM_CLASS_ENT(CPUType, MIPSIV), - CV_ENUM_CLASS_ENT(CPUType, MIPSV), - CV_ENUM_CLASS_ENT(CPUType, M68000), - CV_ENUM_CLASS_ENT(CPUType, M68010), - CV_ENUM_CLASS_ENT(CPUType, M68020), - CV_ENUM_CLASS_ENT(CPUType, M68030), - CV_ENUM_CLASS_ENT(CPUType, M68040), - CV_ENUM_CLASS_ENT(CPUType, Alpha), - CV_ENUM_CLASS_ENT(CPUType, Alpha21164), - CV_ENUM_CLASS_ENT(CPUType, Alpha21164A), - CV_ENUM_CLASS_ENT(CPUType, Alpha21264), - CV_ENUM_CLASS_ENT(CPUType, Alpha21364), - CV_ENUM_CLASS_ENT(CPUType, PPC601), - CV_ENUM_CLASS_ENT(CPUType, PPC603), - CV_ENUM_CLASS_ENT(CPUType, PPC604), - CV_ENUM_CLASS_ENT(CPUType, PPC620), - CV_ENUM_CLASS_ENT(CPUType, PPCFP), - CV_ENUM_CLASS_ENT(CPUType, PPCBE), - CV_ENUM_CLASS_ENT(CPUType, SH3), - CV_ENUM_CLASS_ENT(CPUType, SH3E), - CV_ENUM_CLASS_ENT(CPUType, SH3DSP), - CV_ENUM_CLASS_ENT(CPUType, SH4), - CV_ENUM_CLASS_ENT(CPUType, SHMedia), - CV_ENUM_CLASS_ENT(CPUType, ARM3), - CV_ENUM_CLASS_ENT(CPUType, ARM4), - CV_ENUM_CLASS_ENT(CPUType, ARM4T), - CV_ENUM_CLASS_ENT(CPUType, ARM5), - CV_ENUM_CLASS_ENT(CPUType, ARM5T), - CV_ENUM_CLASS_ENT(CPUType, ARM6), - CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC), - CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX), - CV_ENUM_CLASS_ENT(CPUType, ARM7), - CV_ENUM_CLASS_ENT(CPUType, ARM64), - CV_ENUM_CLASS_ENT(CPUType, Omni), - CV_ENUM_CLASS_ENT(CPUType, Ia64), - CV_ENUM_CLASS_ENT(CPUType, Ia64_2), - CV_ENUM_CLASS_ENT(CPUType, CEE), - CV_ENUM_CLASS_ENT(CPUType, AM33), - CV_ENUM_CLASS_ENT(CPUType, M32R), - CV_ENUM_CLASS_ENT(CPUType, TriCore), - CV_ENUM_CLASS_ENT(CPUType, X64), - CV_ENUM_CLASS_ENT(CPUType, EBC), - CV_ENUM_CLASS_ENT(CPUType, Thumb), - CV_ENUM_CLASS_ENT(CPUType, ARMNT), - CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader), -}; - -static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = { - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedLocalBasePointerMask), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedParamBasePointerMask), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg), - CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw), -}; - -static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = { - CV_ENUM_CLASS_ENT(DebugSubsectionKind, None), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, Lines), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput), - CV_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA), -}; - -static const EnumEntry<uint16_t> ExportSymFlagNames[] = { - CV_ENUM_CLASS_ENT(ExportFlags, IsConstant), - CV_ENUM_CLASS_ENT(ExportFlags, IsData), - CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate), - CV_ENUM_CLASS_ENT(ExportFlags, HasNoName), - CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal), - CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder), -}; - -static const EnumEntry<uint8_t> ThunkOrdinalNames[] = { - CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard), - CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor), - CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall), - CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode), - CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad), - CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental), - CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland), -}; - -static const EnumEntry<uint16_t> TrampolineNames[] = { - CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental), - CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland), -}; - -static const EnumEntry<COFF::SectionCharacteristics> - ImageSectionCharacteristicNames[] = { - CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD), - CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD), - CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE), - CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA), - CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), - CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER), - CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO), - CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE), - CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT), - CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES), - CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ), - CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)}; - -static const EnumEntry<uint16_t> ClassOptionNames[] = { - CV_ENUM_CLASS_ENT(ClassOptions, Packed), - CV_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor), - CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator), - CV_ENUM_CLASS_ENT(ClassOptions, Nested), - CV_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass), - CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator), - CV_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator), - CV_ENUM_CLASS_ENT(ClassOptions, ForwardReference), - CV_ENUM_CLASS_ENT(ClassOptions, Scoped), - CV_ENUM_CLASS_ENT(ClassOptions, HasUniqueName), - CV_ENUM_CLASS_ENT(ClassOptions, Sealed), - CV_ENUM_CLASS_ENT(ClassOptions, Intrinsic), -}; - -static const EnumEntry<uint8_t> MemberAccessNames[] = { - CV_ENUM_CLASS_ENT(MemberAccess, None), - CV_ENUM_CLASS_ENT(MemberAccess, Private), - CV_ENUM_CLASS_ENT(MemberAccess, Protected), - CV_ENUM_CLASS_ENT(MemberAccess, Public), -}; - -static const EnumEntry<uint16_t> MethodOptionNames[] = { - CV_ENUM_CLASS_ENT(MethodOptions, Pseudo), - CV_ENUM_CLASS_ENT(MethodOptions, NoInherit), - CV_ENUM_CLASS_ENT(MethodOptions, NoConstruct), - CV_ENUM_CLASS_ENT(MethodOptions, CompilerGenerated), - CV_ENUM_CLASS_ENT(MethodOptions, Sealed), -}; - -static const EnumEntry<uint16_t> MemberKindNames[] = { - CV_ENUM_CLASS_ENT(MethodKind, Vanilla), - CV_ENUM_CLASS_ENT(MethodKind, Virtual), - CV_ENUM_CLASS_ENT(MethodKind, Static), - CV_ENUM_CLASS_ENT(MethodKind, Friend), - CV_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual), - CV_ENUM_CLASS_ENT(MethodKind, PureVirtual), - CV_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual), -}; - -static const EnumEntry<uint8_t> PtrKindNames[] = { - CV_ENUM_CLASS_ENT(PointerKind, Near16), - CV_ENUM_CLASS_ENT(PointerKind, Far16), - CV_ENUM_CLASS_ENT(PointerKind, Huge16), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegment), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnValue), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentValue), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnAddress), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentAddress), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnType), - CV_ENUM_CLASS_ENT(PointerKind, BasedOnSelf), - CV_ENUM_CLASS_ENT(PointerKind, Near32), - CV_ENUM_CLASS_ENT(PointerKind, Far32), - CV_ENUM_CLASS_ENT(PointerKind, Near64), -}; - -static const EnumEntry<uint8_t> PtrModeNames[] = { - CV_ENUM_CLASS_ENT(PointerMode, Pointer), - CV_ENUM_CLASS_ENT(PointerMode, LValueReference), - CV_ENUM_CLASS_ENT(PointerMode, PointerToDataMember), - CV_ENUM_CLASS_ENT(PointerMode, PointerToMemberFunction), - CV_ENUM_CLASS_ENT(PointerMode, RValueReference), -}; - -static const EnumEntry<uint16_t> PtrMemberRepNames[] = { - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, Unknown), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceData), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, MultipleInheritanceData), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, VirtualInheritanceData), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralData), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceFunction), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, - MultipleInheritanceFunction), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, - VirtualInheritanceFunction), - CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralFunction), -}; - -static const EnumEntry<uint16_t> TypeModifierNames[] = { - CV_ENUM_CLASS_ENT(ModifierOptions, Const), - CV_ENUM_CLASS_ENT(ModifierOptions, Volatile), - CV_ENUM_CLASS_ENT(ModifierOptions, Unaligned), -}; - -static const EnumEntry<uint8_t> CallingConventions[] = { - CV_ENUM_CLASS_ENT(CallingConvention, NearC), - CV_ENUM_CLASS_ENT(CallingConvention, FarC), - CV_ENUM_CLASS_ENT(CallingConvention, NearPascal), - CV_ENUM_CLASS_ENT(CallingConvention, FarPascal), - CV_ENUM_CLASS_ENT(CallingConvention, NearFast), - CV_ENUM_CLASS_ENT(CallingConvention, FarFast), - CV_ENUM_CLASS_ENT(CallingConvention, NearStdCall), - CV_ENUM_CLASS_ENT(CallingConvention, FarStdCall), - CV_ENUM_CLASS_ENT(CallingConvention, NearSysCall), - CV_ENUM_CLASS_ENT(CallingConvention, FarSysCall), - CV_ENUM_CLASS_ENT(CallingConvention, ThisCall), - CV_ENUM_CLASS_ENT(CallingConvention, MipsCall), - CV_ENUM_CLASS_ENT(CallingConvention, Generic), - CV_ENUM_CLASS_ENT(CallingConvention, AlphaCall), - CV_ENUM_CLASS_ENT(CallingConvention, PpcCall), - CV_ENUM_CLASS_ENT(CallingConvention, SHCall), - CV_ENUM_CLASS_ENT(CallingConvention, ArmCall), - CV_ENUM_CLASS_ENT(CallingConvention, AM33Call), - CV_ENUM_CLASS_ENT(CallingConvention, TriCall), - CV_ENUM_CLASS_ENT(CallingConvention, SH5Call), - CV_ENUM_CLASS_ENT(CallingConvention, M32RCall), - CV_ENUM_CLASS_ENT(CallingConvention, ClrCall), - CV_ENUM_CLASS_ENT(CallingConvention, Inline), - CV_ENUM_CLASS_ENT(CallingConvention, NearVector), -}; - -static const EnumEntry<uint8_t> FunctionOptionEnum[] = { - CV_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt), - CV_ENUM_CLASS_ENT(FunctionOptions, Constructor), - CV_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases), -}; - -static const EnumEntry<uint16_t> LabelTypeEnum[] = { - CV_ENUM_CLASS_ENT(LabelType, Near), - CV_ENUM_CLASS_ENT(LabelType, Far), -}; - -namespace llvm { -namespace codeview { - -ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() { - return makeArrayRef(SymbolTypeNames); -} - -ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames() { - return makeArrayRef(TypeLeafNames); -} - -ArrayRef<EnumEntry<uint16_t>> getRegisterNames(CPUType Cpu) { +static const EnumEntry<uint16_t> RegisterNames_ARM64[] = { +#define CV_REGISTERS_ARM64 +#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name), +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_ARM64 +}; + +static const EnumEntry<uint32_t> PublicSymFlagNames[] = { + CV_ENUM_CLASS_ENT(PublicSymFlags, Code), + CV_ENUM_CLASS_ENT(PublicSymFlags, Function), + CV_ENUM_CLASS_ENT(PublicSymFlags, Managed), + CV_ENUM_CLASS_ENT(PublicSymFlags, MSIL), +}; + +static const EnumEntry<uint8_t> ProcSymFlagNames[] = { + CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP), + CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET), + CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET), + CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn), + CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable), + CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv), + CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline), + CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo), +}; + +static const EnumEntry<uint16_t> LocalFlags[] = { + CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal), + CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic), +}; + +static const EnumEntry<uint8_t> FrameCookieKinds[] = { + CV_ENUM_CLASS_ENT(FrameCookieKind, Copy), + CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer), + CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer), + CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13), +}; + +static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = { + CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp), + CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm), + CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic), + CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link), + CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd), + CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB), + CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java), + CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL), + CV_ENUM_ENT(SourceLanguage, HLSL), CV_ENUM_ENT(SourceLanguage, D), + CV_ENUM_ENT(SourceLanguage, Swift), +}; + +static const EnumEntry<uint32_t> CompileSym2FlagNames[] = { + CV_ENUM_CLASS_ENT(CompileSym2Flags, EC), + CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo), + CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG), + CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign), + CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent), + CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks), + CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch), + CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL), + CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule), +}; + +static const EnumEntry<uint32_t> CompileSym3FlagNames[] = { + CV_ENUM_CLASS_ENT(CompileSym3Flags, EC), + CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo), + CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG), + CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign), + CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent), + CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks), + CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch), + CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL), + CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule), + CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl), + CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO), + CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp), +}; + +static const EnumEntry<uint32_t> FileChecksumNames[] = { + CV_ENUM_CLASS_ENT(FileChecksumKind, None), + CV_ENUM_CLASS_ENT(FileChecksumKind, MD5), + CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1), + CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256), +}; + +static const EnumEntry<unsigned> CPUTypeNames[] = { + CV_ENUM_CLASS_ENT(CPUType, Intel8080), + CV_ENUM_CLASS_ENT(CPUType, Intel8086), + CV_ENUM_CLASS_ENT(CPUType, Intel80286), + CV_ENUM_CLASS_ENT(CPUType, Intel80386), + CV_ENUM_CLASS_ENT(CPUType, Intel80486), + CV_ENUM_CLASS_ENT(CPUType, Pentium), + CV_ENUM_CLASS_ENT(CPUType, PentiumPro), + CV_ENUM_CLASS_ENT(CPUType, Pentium3), + CV_ENUM_CLASS_ENT(CPUType, MIPS), + CV_ENUM_CLASS_ENT(CPUType, MIPS16), + CV_ENUM_CLASS_ENT(CPUType, MIPS32), + CV_ENUM_CLASS_ENT(CPUType, MIPS64), + CV_ENUM_CLASS_ENT(CPUType, MIPSI), + CV_ENUM_CLASS_ENT(CPUType, MIPSII), + CV_ENUM_CLASS_ENT(CPUType, MIPSIII), + CV_ENUM_CLASS_ENT(CPUType, MIPSIV), + CV_ENUM_CLASS_ENT(CPUType, MIPSV), + CV_ENUM_CLASS_ENT(CPUType, M68000), + CV_ENUM_CLASS_ENT(CPUType, M68010), + CV_ENUM_CLASS_ENT(CPUType, M68020), + CV_ENUM_CLASS_ENT(CPUType, M68030), + CV_ENUM_CLASS_ENT(CPUType, M68040), + CV_ENUM_CLASS_ENT(CPUType, Alpha), + CV_ENUM_CLASS_ENT(CPUType, Alpha21164), + CV_ENUM_CLASS_ENT(CPUType, Alpha21164A), + CV_ENUM_CLASS_ENT(CPUType, Alpha21264), + CV_ENUM_CLASS_ENT(CPUType, Alpha21364), + CV_ENUM_CLASS_ENT(CPUType, PPC601), + CV_ENUM_CLASS_ENT(CPUType, PPC603), + CV_ENUM_CLASS_ENT(CPUType, PPC604), + CV_ENUM_CLASS_ENT(CPUType, PPC620), + CV_ENUM_CLASS_ENT(CPUType, PPCFP), + CV_ENUM_CLASS_ENT(CPUType, PPCBE), + CV_ENUM_CLASS_ENT(CPUType, SH3), + CV_ENUM_CLASS_ENT(CPUType, SH3E), + CV_ENUM_CLASS_ENT(CPUType, SH3DSP), + CV_ENUM_CLASS_ENT(CPUType, SH4), + CV_ENUM_CLASS_ENT(CPUType, SHMedia), + CV_ENUM_CLASS_ENT(CPUType, ARM3), + CV_ENUM_CLASS_ENT(CPUType, ARM4), + CV_ENUM_CLASS_ENT(CPUType, ARM4T), + CV_ENUM_CLASS_ENT(CPUType, ARM5), + CV_ENUM_CLASS_ENT(CPUType, ARM5T), + CV_ENUM_CLASS_ENT(CPUType, ARM6), + CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC), + CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX), + CV_ENUM_CLASS_ENT(CPUType, ARM7), + CV_ENUM_CLASS_ENT(CPUType, ARM64), + CV_ENUM_CLASS_ENT(CPUType, Omni), + CV_ENUM_CLASS_ENT(CPUType, Ia64), + CV_ENUM_CLASS_ENT(CPUType, Ia64_2), + CV_ENUM_CLASS_ENT(CPUType, CEE), + CV_ENUM_CLASS_ENT(CPUType, AM33), + CV_ENUM_CLASS_ENT(CPUType, M32R), + CV_ENUM_CLASS_ENT(CPUType, TriCore), + CV_ENUM_CLASS_ENT(CPUType, X64), + CV_ENUM_CLASS_ENT(CPUType, EBC), + CV_ENUM_CLASS_ENT(CPUType, Thumb), + CV_ENUM_CLASS_ENT(CPUType, ARMNT), + CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader), +}; + +static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = { + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedLocalBasePointerMask), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedParamBasePointerMask), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg), + CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw), +}; + +static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = { + CV_ENUM_CLASS_ENT(DebugSubsectionKind, None), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, Lines), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput), + CV_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA), +}; + +static const EnumEntry<uint16_t> ExportSymFlagNames[] = { + CV_ENUM_CLASS_ENT(ExportFlags, IsConstant), + CV_ENUM_CLASS_ENT(ExportFlags, IsData), + CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate), + CV_ENUM_CLASS_ENT(ExportFlags, HasNoName), + CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal), + CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder), +}; + +static const EnumEntry<uint8_t> ThunkOrdinalNames[] = { + CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard), + CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor), + CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall), + CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode), + CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad), + CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental), + CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland), +}; + +static const EnumEntry<uint16_t> TrampolineNames[] = { + CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental), + CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland), +}; + +static const EnumEntry<COFF::SectionCharacteristics> + ImageSectionCharacteristicNames[] = { + CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD), + CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD), + CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE), + CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA), + CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), + CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER), + CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO), + CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE), + CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT), + CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES), + CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ), + CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)}; + +static const EnumEntry<uint16_t> ClassOptionNames[] = { + CV_ENUM_CLASS_ENT(ClassOptions, Packed), + CV_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor), + CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator), + CV_ENUM_CLASS_ENT(ClassOptions, Nested), + CV_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass), + CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator), + CV_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator), + CV_ENUM_CLASS_ENT(ClassOptions, ForwardReference), + CV_ENUM_CLASS_ENT(ClassOptions, Scoped), + CV_ENUM_CLASS_ENT(ClassOptions, HasUniqueName), + CV_ENUM_CLASS_ENT(ClassOptions, Sealed), + CV_ENUM_CLASS_ENT(ClassOptions, Intrinsic), +}; + +static const EnumEntry<uint8_t> MemberAccessNames[] = { + CV_ENUM_CLASS_ENT(MemberAccess, None), + CV_ENUM_CLASS_ENT(MemberAccess, Private), + CV_ENUM_CLASS_ENT(MemberAccess, Protected), + CV_ENUM_CLASS_ENT(MemberAccess, Public), +}; + +static const EnumEntry<uint16_t> MethodOptionNames[] = { + CV_ENUM_CLASS_ENT(MethodOptions, Pseudo), + CV_ENUM_CLASS_ENT(MethodOptions, NoInherit), + CV_ENUM_CLASS_ENT(MethodOptions, NoConstruct), + CV_ENUM_CLASS_ENT(MethodOptions, CompilerGenerated), + CV_ENUM_CLASS_ENT(MethodOptions, Sealed), +}; + +static const EnumEntry<uint16_t> MemberKindNames[] = { + CV_ENUM_CLASS_ENT(MethodKind, Vanilla), + CV_ENUM_CLASS_ENT(MethodKind, Virtual), + CV_ENUM_CLASS_ENT(MethodKind, Static), + CV_ENUM_CLASS_ENT(MethodKind, Friend), + CV_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual), + CV_ENUM_CLASS_ENT(MethodKind, PureVirtual), + CV_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual), +}; + +static const EnumEntry<uint8_t> PtrKindNames[] = { + CV_ENUM_CLASS_ENT(PointerKind, Near16), + CV_ENUM_CLASS_ENT(PointerKind, Far16), + CV_ENUM_CLASS_ENT(PointerKind, Huge16), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegment), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnValue), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentValue), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnAddress), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentAddress), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnType), + CV_ENUM_CLASS_ENT(PointerKind, BasedOnSelf), + CV_ENUM_CLASS_ENT(PointerKind, Near32), + CV_ENUM_CLASS_ENT(PointerKind, Far32), + CV_ENUM_CLASS_ENT(PointerKind, Near64), +}; + +static const EnumEntry<uint8_t> PtrModeNames[] = { + CV_ENUM_CLASS_ENT(PointerMode, Pointer), + CV_ENUM_CLASS_ENT(PointerMode, LValueReference), + CV_ENUM_CLASS_ENT(PointerMode, PointerToDataMember), + CV_ENUM_CLASS_ENT(PointerMode, PointerToMemberFunction), + CV_ENUM_CLASS_ENT(PointerMode, RValueReference), +}; + +static const EnumEntry<uint16_t> PtrMemberRepNames[] = { + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, Unknown), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceData), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, MultipleInheritanceData), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, VirtualInheritanceData), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralData), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceFunction), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, + MultipleInheritanceFunction), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, + VirtualInheritanceFunction), + CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralFunction), +}; + +static const EnumEntry<uint16_t> TypeModifierNames[] = { + CV_ENUM_CLASS_ENT(ModifierOptions, Const), + CV_ENUM_CLASS_ENT(ModifierOptions, Volatile), + CV_ENUM_CLASS_ENT(ModifierOptions, Unaligned), +}; + +static const EnumEntry<uint8_t> CallingConventions[] = { + CV_ENUM_CLASS_ENT(CallingConvention, NearC), + CV_ENUM_CLASS_ENT(CallingConvention, FarC), + CV_ENUM_CLASS_ENT(CallingConvention, NearPascal), + CV_ENUM_CLASS_ENT(CallingConvention, FarPascal), + CV_ENUM_CLASS_ENT(CallingConvention, NearFast), + CV_ENUM_CLASS_ENT(CallingConvention, FarFast), + CV_ENUM_CLASS_ENT(CallingConvention, NearStdCall), + CV_ENUM_CLASS_ENT(CallingConvention, FarStdCall), + CV_ENUM_CLASS_ENT(CallingConvention, NearSysCall), + CV_ENUM_CLASS_ENT(CallingConvention, FarSysCall), + CV_ENUM_CLASS_ENT(CallingConvention, ThisCall), + CV_ENUM_CLASS_ENT(CallingConvention, MipsCall), + CV_ENUM_CLASS_ENT(CallingConvention, Generic), + CV_ENUM_CLASS_ENT(CallingConvention, AlphaCall), + CV_ENUM_CLASS_ENT(CallingConvention, PpcCall), + CV_ENUM_CLASS_ENT(CallingConvention, SHCall), + CV_ENUM_CLASS_ENT(CallingConvention, ArmCall), + CV_ENUM_CLASS_ENT(CallingConvention, AM33Call), + CV_ENUM_CLASS_ENT(CallingConvention, TriCall), + CV_ENUM_CLASS_ENT(CallingConvention, SH5Call), + CV_ENUM_CLASS_ENT(CallingConvention, M32RCall), + CV_ENUM_CLASS_ENT(CallingConvention, ClrCall), + CV_ENUM_CLASS_ENT(CallingConvention, Inline), + CV_ENUM_CLASS_ENT(CallingConvention, NearVector), +}; + +static const EnumEntry<uint8_t> FunctionOptionEnum[] = { + CV_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt), + CV_ENUM_CLASS_ENT(FunctionOptions, Constructor), + CV_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases), +}; + +static const EnumEntry<uint16_t> LabelTypeEnum[] = { + CV_ENUM_CLASS_ENT(LabelType, Near), + CV_ENUM_CLASS_ENT(LabelType, Far), +}; + +namespace llvm { +namespace codeview { + +ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() { + return makeArrayRef(SymbolTypeNames); +} + +ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames() { + return makeArrayRef(TypeLeafNames); +} + +ArrayRef<EnumEntry<uint16_t>> getRegisterNames(CPUType Cpu) { if (Cpu == CPUType::ARMNT) { return makeArrayRef(RegisterNames_ARM); } else if (Cpu == CPUType::ARM64) { - return makeArrayRef(RegisterNames_ARM64); - } - return makeArrayRef(RegisterNames_X86); -} - -ArrayRef<EnumEntry<uint32_t>> getPublicSymFlagNames() { - return makeArrayRef(PublicSymFlagNames); -} - -ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() { - return makeArrayRef(ProcSymFlagNames); -} - -ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() { - return makeArrayRef(LocalFlags); -} - -ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() { - return makeArrayRef(FrameCookieKinds); -} - -ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() { - return makeArrayRef(SourceLanguages); -} - -ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() { - return makeArrayRef(CompileSym2FlagNames); -} - -ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() { - return makeArrayRef(CompileSym3FlagNames); -} - -ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() { - return makeArrayRef(FileChecksumNames); -} - -ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() { - return makeArrayRef(CPUTypeNames); -} - -ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() { - return makeArrayRef(FrameProcSymFlagNames); -} - -ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() { - return makeArrayRef(ExportSymFlagNames); -} - -ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() { - return makeArrayRef(ModuleSubstreamKindNames); -} - -ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() { - return makeArrayRef(ThunkOrdinalNames); -} - -ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() { - return makeArrayRef(TrampolineNames); -} - -ArrayRef<EnumEntry<COFF::SectionCharacteristics>> -getImageSectionCharacteristicNames() { - return makeArrayRef(ImageSectionCharacteristicNames); -} - -ArrayRef<EnumEntry<uint16_t>> getClassOptionNames() { - return makeArrayRef(ClassOptionNames); -} - -ArrayRef<EnumEntry<uint8_t>> getMemberAccessNames() { - return makeArrayRef(MemberAccessNames); -} - -ArrayRef<EnumEntry<uint16_t>> getMethodOptionNames() { - return makeArrayRef(MethodOptionNames); -} - -ArrayRef<EnumEntry<uint16_t>> getMemberKindNames() { - return makeArrayRef(MemberKindNames); -} - -ArrayRef<EnumEntry<uint8_t>> getPtrKindNames() { - return makeArrayRef(PtrKindNames); -} - -ArrayRef<EnumEntry<uint8_t>> getPtrModeNames() { - return makeArrayRef(PtrModeNames); -} - -ArrayRef<EnumEntry<uint16_t>> getPtrMemberRepNames() { - return makeArrayRef(PtrMemberRepNames); -} - -ArrayRef<EnumEntry<uint16_t>> getTypeModifierNames() { - return makeArrayRef(TypeModifierNames); -} - -ArrayRef<EnumEntry<uint8_t>> getCallingConventions() { - return makeArrayRef(CallingConventions); -} - -ArrayRef<EnumEntry<uint8_t>> getFunctionOptionEnum() { - return makeArrayRef(FunctionOptionEnum); -} - -ArrayRef<EnumEntry<uint16_t>> getLabelTypeEnum() { - return makeArrayRef(LabelTypeEnum); -} - -} // end namespace codeview -} // end namespace llvm + return makeArrayRef(RegisterNames_ARM64); + } + return makeArrayRef(RegisterNames_X86); +} + +ArrayRef<EnumEntry<uint32_t>> getPublicSymFlagNames() { + return makeArrayRef(PublicSymFlagNames); +} + +ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() { + return makeArrayRef(ProcSymFlagNames); +} + +ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() { + return makeArrayRef(LocalFlags); +} + +ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() { + return makeArrayRef(FrameCookieKinds); +} + +ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() { + return makeArrayRef(SourceLanguages); +} + +ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() { + return makeArrayRef(CompileSym2FlagNames); +} + +ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() { + return makeArrayRef(CompileSym3FlagNames); +} + +ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() { + return makeArrayRef(FileChecksumNames); +} + +ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() { + return makeArrayRef(CPUTypeNames); +} + +ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() { + return makeArrayRef(FrameProcSymFlagNames); +} + +ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() { + return makeArrayRef(ExportSymFlagNames); +} + +ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() { + return makeArrayRef(ModuleSubstreamKindNames); +} + +ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() { + return makeArrayRef(ThunkOrdinalNames); +} + +ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() { + return makeArrayRef(TrampolineNames); +} + +ArrayRef<EnumEntry<COFF::SectionCharacteristics>> +getImageSectionCharacteristicNames() { + return makeArrayRef(ImageSectionCharacteristicNames); +} + +ArrayRef<EnumEntry<uint16_t>> getClassOptionNames() { + return makeArrayRef(ClassOptionNames); +} + +ArrayRef<EnumEntry<uint8_t>> getMemberAccessNames() { + return makeArrayRef(MemberAccessNames); +} + +ArrayRef<EnumEntry<uint16_t>> getMethodOptionNames() { + return makeArrayRef(MethodOptionNames); +} + +ArrayRef<EnumEntry<uint16_t>> getMemberKindNames() { + return makeArrayRef(MemberKindNames); +} + +ArrayRef<EnumEntry<uint8_t>> getPtrKindNames() { + return makeArrayRef(PtrKindNames); +} + +ArrayRef<EnumEntry<uint8_t>> getPtrModeNames() { + return makeArrayRef(PtrModeNames); +} + +ArrayRef<EnumEntry<uint16_t>> getPtrMemberRepNames() { + return makeArrayRef(PtrMemberRepNames); +} + +ArrayRef<EnumEntry<uint16_t>> getTypeModifierNames() { + return makeArrayRef(TypeModifierNames); +} + +ArrayRef<EnumEntry<uint8_t>> getCallingConventions() { + return makeArrayRef(CallingConventions); +} + +ArrayRef<EnumEntry<uint8_t>> getFunctionOptionEnum() { + return makeArrayRef(FunctionOptionEnum); +} + +ArrayRef<EnumEntry<uint16_t>> getLabelTypeEnum() { + return makeArrayRef(LabelTypeEnum); +} + +} // end namespace codeview +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/Formatters.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/Formatters.cpp index a7a8c7ff82..fc8482ed81 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/Formatters.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/Formatters.cpp @@ -1,47 +1,47 @@ -//===- Formatters.cpp -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/Formatters.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/GUID.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::codeview::detail; - -GuidAdapter::GuidAdapter(StringRef Guid) - : FormatAdapter(makeArrayRef(Guid.bytes_begin(), Guid.bytes_end())) {} - -GuidAdapter::GuidAdapter(ArrayRef<uint8_t> Guid) - : FormatAdapter(std::move(Guid)) {} - -void GuidAdapter::format(raw_ostream &Stream, StringRef Style) { - static const char *Lookup = "0123456789ABCDEF"; - - assert(Item.size() == 16 && "Expected 16-byte GUID"); - Stream << "{"; - for (int i = 0; i < 16;) { - uint8_t Byte = Item[i]; - uint8_t HighNibble = (Byte >> 4) & 0xF; - uint8_t LowNibble = Byte & 0xF; - Stream << Lookup[HighNibble] << Lookup[LowNibble]; - ++i; - if (i >= 4 && i <= 10 && i % 2 == 0) - Stream << "-"; - } - Stream << "}"; -} - -raw_ostream &llvm::codeview::operator<<(raw_ostream &OS, const GUID &Guid) { - codeview::detail::GuidAdapter A(Guid.Guid); - A.format(OS, ""); - return OS; -} +//===- Formatters.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/GUID.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::codeview::detail; + +GuidAdapter::GuidAdapter(StringRef Guid) + : FormatAdapter(makeArrayRef(Guid.bytes_begin(), Guid.bytes_end())) {} + +GuidAdapter::GuidAdapter(ArrayRef<uint8_t> Guid) + : FormatAdapter(std::move(Guid)) {} + +void GuidAdapter::format(raw_ostream &Stream, StringRef Style) { + static const char *Lookup = "0123456789ABCDEF"; + + assert(Item.size() == 16 && "Expected 16-byte GUID"); + Stream << "{"; + for (int i = 0; i < 16;) { + uint8_t Byte = Item[i]; + uint8_t HighNibble = (Byte >> 4) & 0xF; + uint8_t LowNibble = Byte & 0xF; + Stream << Lookup[HighNibble] << Lookup[LowNibble]; + ++i; + if (i >= 4 && i <= 10 && i % 2 == 0) + Stream << "-"; + } + Stream << "}"; +} + +raw_ostream &llvm::codeview::operator<<(raw_ostream &OS, const GUID &Guid) { + codeview::detail::GuidAdapter A(Guid.Guid); + A.format(OS, ""); + return OS; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp index 7cd9ca7498..0923eb1729 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp @@ -1,140 +1,140 @@ -//===- GlobalTypeTableBuilder.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const { - return TypeIndex::fromArrayIndex(SeenRecords.size()); -} - -GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage) - : RecordStorage(Storage) { - SeenRecords.reserve(4096); -} - -GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default; - -Optional<TypeIndex> GlobalTypeTableBuilder::getFirst() { - if (empty()) - return None; - - return TypeIndex(TypeIndex::FirstNonSimpleIndex); -} - -Optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) { - if (++Prev == nextTypeIndex()) - return None; - return Prev; -} - -CVType GlobalTypeTableBuilder::getType(TypeIndex Index) { - CVType Type(SeenRecords[Index.toArrayIndex()]); - return Type; -} - -StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) { - llvm_unreachable("Method not implemented"); -} - -bool GlobalTypeTableBuilder::contains(TypeIndex Index) { - if (Index.isSimple() || Index.isNoneType()) - return false; - - return Index.toArrayIndex() < SeenRecords.size(); -} - -uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); } - -uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); } - -ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const { - return SeenRecords; -} - -ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const { - return SeenHashes; -} - -void GlobalTypeTableBuilder::reset() { - HashedRecords.clear(); - SeenRecords.clear(); -} - -static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, - ArrayRef<uint8_t> Data) { - uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); - memcpy(Stable, Data.data(), Data.size()); - return makeArrayRef(Stable, Data.size()); -} - -TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) { - GloballyHashedType GHT = - GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); - return insertRecordAs(GHT, Record.size(), - [Record](MutableArrayRef<uint8_t> Data) { - assert(Data.size() == Record.size()); - ::memcpy(Data.data(), Record.data(), Record.size()); - return Data; - }); -} - -TypeIndex -GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { - TypeIndex TI; - auto Fragments = Builder.end(nextTypeIndex()); - assert(!Fragments.empty()); - for (auto C : Fragments) - TI = insertRecordBytes(C.RecordData); - return TI; -} - -bool GlobalTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, - bool Stabilize) { - assert(Index.toArrayIndex() < SeenRecords.size() && - "This function cannot be used to insert records!"); - - ArrayRef<uint8_t> Record = Data.data(); - assert(Record.size() < UINT32_MAX && "Record too big"); - assert(Record.size() % 4 == 0 && - "The type record size is not a multiple of 4 bytes which will cause " - "misalignment in the output TPI stream!"); - - GloballyHashedType Hash = - GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); - auto Result = HashedRecords.try_emplace(Hash, Index.toArrayIndex()); - if (!Result.second) { - Index = Result.first->second; - return false; // The record is already there, at a different location - } - - if (Stabilize) - Record = stabilize(RecordStorage, Record); - - SeenRecords[Index.toArrayIndex()] = Record; - SeenHashes[Index.toArrayIndex()] = Hash; - return true; -} +//===- GlobalTypeTableBuilder.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) { + SeenRecords.reserve(4096); +} + +GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default; + +Optional<TypeIndex> GlobalTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType GlobalTypeTableBuilder::getType(TypeIndex Index) { + CVType Type(SeenRecords[Index.toArrayIndex()]); + return Type; +} + +StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool GlobalTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const { + return SeenRecords; +} + +ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const { + return SeenHashes; +} + +void GlobalTypeTableBuilder::reset() { + HashedRecords.clear(); + SeenRecords.clear(); +} + +static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, + ArrayRef<uint8_t> Data) { + uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); + memcpy(Stable, Data.data(), Data.size()); + return makeArrayRef(Stable, Data.size()); +} + +TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) { + GloballyHashedType GHT = + GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); + return insertRecordAs(GHT, Record.size(), + [Record](MutableArrayRef<uint8_t> Data) { + assert(Data.size() == Record.size()); + ::memcpy(Data.data(), Record.data(), Record.size()); + return Data; + }); +} + +TypeIndex +GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} + +bool GlobalTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, + bool Stabilize) { + assert(Index.toArrayIndex() < SeenRecords.size() && + "This function cannot be used to insert records!"); + + ArrayRef<uint8_t> Record = Data.data(); + assert(Record.size() < UINT32_MAX && "Record too big"); + assert(Record.size() % 4 == 0 && + "The type record size is not a multiple of 4 bytes which will cause " + "misalignment in the output TPI stream!"); + + GloballyHashedType Hash = + GloballyHashedType::hashType(Record, SeenHashes, SeenHashes); + auto Result = HashedRecords.try_emplace(Hash, Index.toArrayIndex()); + if (!Result.second) { + Index = Result.first->second; + return false; // The record is already there, at a different location + } + + if (Stabilize) + Record = stabilize(RecordStorage, Record); + + SeenRecords[Index.toArrayIndex()] = Record; + SeenHashes[Index.toArrayIndex()] = Hash; + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp index c0fc3e0ef6..dae7fbe2ac 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -1,284 +1,284 @@ -//===- LazyRandomTypeCollection.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <iterator> - -using namespace llvm; -using namespace llvm::codeview; - -static void error(Error &&EC) { - assert(!static_cast<bool>(EC)); - if (EC) - consumeError(std::move(EC)); -} - -LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint) - : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint, - PartialOffsetArray()) {} - -LazyRandomTypeCollection::LazyRandomTypeCollection( - const CVTypeArray &Types, uint32_t RecordCountHint, - PartialOffsetArray PartialOffsets) - : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) { - Records.resize(RecordCountHint); -} - -LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data, - uint32_t RecordCountHint) - : LazyRandomTypeCollection(RecordCountHint) { -} - -LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data, - uint32_t RecordCountHint) - : LazyRandomTypeCollection( - makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) { -} - -LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types, - uint32_t NumRecords) - : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {} - -void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader, - uint32_t RecordCountHint) { - Count = 0; - PartialOffsets = PartialOffsetArray(); - - error(Reader.readArray(Types, Reader.bytesRemaining())); - - // Clear and then resize, to make sure existing data gets destroyed. - Records.clear(); - Records.resize(RecordCountHint); -} - -void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) { - BinaryStreamReader Reader(Data, support::little); - reset(Reader, RecordCountHint); -} - -void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data, - uint32_t RecordCountHint) { - BinaryStreamReader Reader(Data, support::little); - reset(Reader, RecordCountHint); -} - -uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { - error(ensureTypeExists(Index)); - assert(contains(Index)); - - return Records[Index.toArrayIndex()].Offset; -} - -CVType LazyRandomTypeCollection::getType(TypeIndex Index) { - assert(!Index.isSimple()); - - auto EC = ensureTypeExists(Index); - error(std::move(EC)); - assert(contains(Index)); - - return Records[Index.toArrayIndex()].Type; -} - -Optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) { - if (Index.isSimple()) - return None; - - if (auto EC = ensureTypeExists(Index)) { - consumeError(std::move(EC)); - return None; - } - - assert(contains(Index)); - return Records[Index.toArrayIndex()].Type; -} - -StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { - if (Index.isNoneType() || Index.isSimple()) - return TypeIndex::simpleTypeName(Index); - - // Try to make sure the type exists. Even if it doesn't though, it may be - // because we're dumping a symbol stream with no corresponding type stream - // present, in which case we still want to be able to print <unknown UDT> - // for the type names. - if (auto EC = ensureTypeExists(Index)) { - consumeError(std::move(EC)); - return "<unknown UDT>"; - } - - uint32_t I = Index.toArrayIndex(); - ensureCapacityFor(Index); - if (Records[I].Name.data() == nullptr) { - StringRef Result = NameStorage.save(computeTypeName(*this, Index)); - Records[I].Name = Result; - } - return Records[I].Name; -} - -bool LazyRandomTypeCollection::contains(TypeIndex Index) { - if (Index.isSimple() || Index.isNoneType()) - return false; - - if (Records.size() <= Index.toArrayIndex()) - return false; - if (!Records[Index.toArrayIndex()].Type.valid()) - return false; - return true; -} - -uint32_t LazyRandomTypeCollection::size() { return Count; } - -uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); } - -Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) { - if (contains(TI)) - return Error::success(); - - return visitRangeForType(TI); -} - -void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) { - assert(!Index.isSimple()); - uint32_t MinSize = Index.toArrayIndex() + 1; - - if (MinSize <= capacity()) - return; - - uint32_t NewCapacity = MinSize * 3 / 2; - - assert(NewCapacity > capacity()); - Records.resize(NewCapacity); -} - -Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { - assert(!TI.isSimple()); - if (PartialOffsets.empty()) - return fullScanForType(TI); - +//===- LazyRandomTypeCollection.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <iterator> + +using namespace llvm; +using namespace llvm::codeview; + +static void error(Error &&EC) { + assert(!static_cast<bool>(EC)); + if (EC) + consumeError(std::move(EC)); +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint) + : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint, + PartialOffsetArray()) {} + +LazyRandomTypeCollection::LazyRandomTypeCollection( + const CVTypeArray &Types, uint32_t RecordCountHint, + PartialOffsetArray PartialOffsets) + : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) { + Records.resize(RecordCountHint); +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data, + uint32_t RecordCountHint) + : LazyRandomTypeCollection(RecordCountHint) { +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data, + uint32_t RecordCountHint) + : LazyRandomTypeCollection( + makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) { +} + +LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types, + uint32_t NumRecords) + : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {} + +void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader, + uint32_t RecordCountHint) { + Count = 0; + PartialOffsets = PartialOffsetArray(); + + error(Reader.readArray(Types, Reader.bytesRemaining())); + + // Clear and then resize, to make sure existing data gets destroyed. + Records.clear(); + Records.resize(RecordCountHint); +} + +void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) { + BinaryStreamReader Reader(Data, support::little); + reset(Reader, RecordCountHint); +} + +void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data, + uint32_t RecordCountHint) { + BinaryStreamReader Reader(Data, support::little); + reset(Reader, RecordCountHint); +} + +uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { + error(ensureTypeExists(Index)); + assert(contains(Index)); + + return Records[Index.toArrayIndex()].Offset; +} + +CVType LazyRandomTypeCollection::getType(TypeIndex Index) { + assert(!Index.isSimple()); + + auto EC = ensureTypeExists(Index); + error(std::move(EC)); + assert(contains(Index)); + + return Records[Index.toArrayIndex()].Type; +} + +Optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) { + if (Index.isSimple()) + return None; + + if (auto EC = ensureTypeExists(Index)) { + consumeError(std::move(EC)); + return None; + } + + assert(contains(Index)); + return Records[Index.toArrayIndex()].Type; +} + +StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); + + // Try to make sure the type exists. Even if it doesn't though, it may be + // because we're dumping a symbol stream with no corresponding type stream + // present, in which case we still want to be able to print <unknown UDT> + // for the type names. + if (auto EC = ensureTypeExists(Index)) { + consumeError(std::move(EC)); + return "<unknown UDT>"; + } + + uint32_t I = Index.toArrayIndex(); + ensureCapacityFor(Index); + if (Records[I].Name.data() == nullptr) { + StringRef Result = NameStorage.save(computeTypeName(*this, Index)); + Records[I].Name = Result; + } + return Records[I].Name; +} + +bool LazyRandomTypeCollection::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + if (Records.size() <= Index.toArrayIndex()) + return false; + if (!Records[Index.toArrayIndex()].Type.valid()) + return false; + return true; +} + +uint32_t LazyRandomTypeCollection::size() { return Count; } + +uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); } + +Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) { + if (contains(TI)) + return Error::success(); + + return visitRangeForType(TI); +} + +void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) { + assert(!Index.isSimple()); + uint32_t MinSize = Index.toArrayIndex() + 1; + + if (MinSize <= capacity()) + return; + + uint32_t NewCapacity = MinSize * 3 / 2; + + assert(NewCapacity > capacity()); + Records.resize(NewCapacity); +} + +Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { + assert(!TI.isSimple()); + if (PartialOffsets.empty()) + return fullScanForType(TI); + auto Next = llvm::upper_bound(PartialOffsets, TI, [](TypeIndex Value, const TypeIndexOffset &IO) { return Value < IO.Type; }); - - assert(Next != PartialOffsets.begin()); - auto Prev = std::prev(Next); - - TypeIndex TIB = Prev->Type; - if (contains(TIB)) { - // They've asked us to fetch a type index, but the entry we found in the - // partial offsets array has already been visited. Since we visit an entire - // block every time, that means this record should have been previously + + assert(Next != PartialOffsets.begin()); + auto Prev = std::prev(Next); + + TypeIndex TIB = Prev->Type; + if (contains(TIB)) { + // They've asked us to fetch a type index, but the entry we found in the + // partial offsets array has already been visited. Since we visit an entire + // block every time, that means this record should have been previously // discovered. Ultimately, this means this is a request for a non-existent - // type index. - return make_error<CodeViewError>("Invalid type index"); - } - - TypeIndex TIE; - if (Next == PartialOffsets.end()) { - TIE = TypeIndex::fromArrayIndex(capacity()); - } else { - TIE = Next->Type; - } - - visitRange(TIB, Prev->Offset, TIE); - return Error::success(); -} - -Optional<TypeIndex> LazyRandomTypeCollection::getFirst() { - TypeIndex TI = TypeIndex::fromArrayIndex(0); - if (auto EC = ensureTypeExists(TI)) { - consumeError(std::move(EC)); - return None; - } - return TI; -} - -Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) { - // We can't be sure how long this type stream is, given that the initial count - // given to the constructor is just a hint. So just try to make sure the next - // record exists, and if anything goes wrong, we must be at the end. - if (auto EC = ensureTypeExists(Prev + 1)) { - consumeError(std::move(EC)); - return None; - } - - return Prev + 1; -} - -Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) { - assert(!TI.isSimple()); - assert(PartialOffsets.empty()); - - TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0); - auto Begin = Types.begin(); - - if (Count > 0) { - // In the case of type streams which we don't know the number of records of, - // it's possible to search for a type index triggering a full scan, but then - // later additional records are added since we didn't know how many there - // would be until we did a full visitation, then you try to access the new - // type triggering another full scan. To avoid this, we assume that if the - // database has some records, this must be what's going on. We can also - // assume that this index must be larger than the largest type index we've - // visited, so we start from there and scan forward. - uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset; - CurrentTI = LargestTypeIndex + 1; - Begin = Types.at(Offset); - ++Begin; - } - - auto End = Types.end(); - while (Begin != End) { - ensureCapacityFor(CurrentTI); - LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI); - auto Idx = CurrentTI.toArrayIndex(); - Records[Idx].Type = *Begin; - Records[Idx].Offset = Begin.offset(); - ++Count; - ++Begin; - ++CurrentTI; - } - if (CurrentTI <= TI) { - return make_error<CodeViewError>("Type Index does not exist!"); - } - return Error::success(); -} - -void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset, - TypeIndex End) { - auto RI = Types.at(BeginOffset); - assert(RI != Types.end()); - - ensureCapacityFor(End); - while (Begin != End) { - LargestTypeIndex = std::max(LargestTypeIndex, Begin); - auto Idx = Begin.toArrayIndex(); - Records[Idx].Type = *RI; - Records[Idx].Offset = RI.offset(); - ++Count; - ++Begin; - ++RI; - } -} - -bool LazyRandomTypeCollection::replaceType(TypeIndex &Index, CVType Data, - bool Stabilize) { - llvm_unreachable("Method cannot be called"); -} + // type index. + return make_error<CodeViewError>("Invalid type index"); + } + + TypeIndex TIE; + if (Next == PartialOffsets.end()) { + TIE = TypeIndex::fromArrayIndex(capacity()); + } else { + TIE = Next->Type; + } + + visitRange(TIB, Prev->Offset, TIE); + return Error::success(); +} + +Optional<TypeIndex> LazyRandomTypeCollection::getFirst() { + TypeIndex TI = TypeIndex::fromArrayIndex(0); + if (auto EC = ensureTypeExists(TI)) { + consumeError(std::move(EC)); + return None; + } + return TI; +} + +Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) { + // We can't be sure how long this type stream is, given that the initial count + // given to the constructor is just a hint. So just try to make sure the next + // record exists, and if anything goes wrong, we must be at the end. + if (auto EC = ensureTypeExists(Prev + 1)) { + consumeError(std::move(EC)); + return None; + } + + return Prev + 1; +} + +Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) { + assert(!TI.isSimple()); + assert(PartialOffsets.empty()); + + TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0); + auto Begin = Types.begin(); + + if (Count > 0) { + // In the case of type streams which we don't know the number of records of, + // it's possible to search for a type index triggering a full scan, but then + // later additional records are added since we didn't know how many there + // would be until we did a full visitation, then you try to access the new + // type triggering another full scan. To avoid this, we assume that if the + // database has some records, this must be what's going on. We can also + // assume that this index must be larger than the largest type index we've + // visited, so we start from there and scan forward. + uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset; + CurrentTI = LargestTypeIndex + 1; + Begin = Types.at(Offset); + ++Begin; + } + + auto End = Types.end(); + while (Begin != End) { + ensureCapacityFor(CurrentTI); + LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI); + auto Idx = CurrentTI.toArrayIndex(); + Records[Idx].Type = *Begin; + Records[Idx].Offset = Begin.offset(); + ++Count; + ++Begin; + ++CurrentTI; + } + if (CurrentTI <= TI) { + return make_error<CodeViewError>("Type Index does not exist!"); + } + return Error::success(); +} + +void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset, + TypeIndex End) { + auto RI = Types.at(BeginOffset); + assert(RI != Types.end()); + + ensureCapacityFor(End); + while (Begin != End) { + LargestTypeIndex = std::max(LargestTypeIndex, Begin); + auto Idx = Begin.toArrayIndex(); + Records[Idx].Type = *RI; + Records[Idx].Offset = RI.offset(); + ++Count; + ++Begin; + ++RI; + } +} + +bool LazyRandomTypeCollection::replaceType(TypeIndex &Index, CVType Data, + bool Stabilize) { + llvm_unreachable("Method cannot be called"); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/Line.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/Line.cpp index 53adc8cac5..247cd8d9bf 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/Line.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/Line.cpp @@ -1,21 +1,21 @@ -//===-- Line.cpp ----------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/Line.h" - -using namespace llvm; -using namespace codeview; - -LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) { - LineData = StartLine & StartLineMask; - uint32_t LineDelta = EndLine - StartLine; - LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask; - if (IsStatement) { - LineData |= StatementFlag; - } -} +//===-- Line.cpp ----------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/Line.h" + +using namespace llvm; +using namespace codeview; + +LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) { + LineData = StartLine & StartLineMask; + uint32_t LineDelta = EndLine - StartLine; + LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask; + if (IsStatement) { + LineData |= StatementFlag; + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp index 13ce3ae82c..67200a86aa 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp @@ -1,152 +1,152 @@ -//===- MergingTypeTableBuilder.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -TypeIndex MergingTypeTableBuilder::nextTypeIndex() const { - return TypeIndex::fromArrayIndex(SeenRecords.size()); -} - -MergingTypeTableBuilder::MergingTypeTableBuilder(BumpPtrAllocator &Storage) - : RecordStorage(Storage) { - SeenRecords.reserve(4096); -} - -MergingTypeTableBuilder::~MergingTypeTableBuilder() = default; - -Optional<TypeIndex> MergingTypeTableBuilder::getFirst() { - if (empty()) - return None; - - return TypeIndex(TypeIndex::FirstNonSimpleIndex); -} - -Optional<TypeIndex> MergingTypeTableBuilder::getNext(TypeIndex Prev) { - if (++Prev == nextTypeIndex()) - return None; - return Prev; -} - -CVType MergingTypeTableBuilder::getType(TypeIndex Index) { - CVType Type(SeenRecords[Index.toArrayIndex()]); - return Type; -} - -StringRef MergingTypeTableBuilder::getTypeName(TypeIndex Index) { - llvm_unreachable("Method not implemented"); -} - -bool MergingTypeTableBuilder::contains(TypeIndex Index) { - if (Index.isSimple() || Index.isNoneType()) - return false; - - return Index.toArrayIndex() < SeenRecords.size(); -} - -uint32_t MergingTypeTableBuilder::size() { return SeenRecords.size(); } - -uint32_t MergingTypeTableBuilder::capacity() { return SeenRecords.size(); } - -ArrayRef<ArrayRef<uint8_t>> MergingTypeTableBuilder::records() const { - return SeenRecords; -} - -void MergingTypeTableBuilder::reset() { - HashedRecords.clear(); - SeenRecords.clear(); -} - -static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, - ArrayRef<uint8_t> Data) { - uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); - memcpy(Stable, Data.data(), Data.size()); - return makeArrayRef(Stable, Data.size()); -} - -TypeIndex MergingTypeTableBuilder::insertRecordAs(hash_code Hash, - ArrayRef<uint8_t> &Record) { - assert(Record.size() < UINT32_MAX && "Record too big"); - assert(Record.size() % 4 == 0 && - "The type record size is not a multiple of 4 bytes which will cause " - "misalignment in the output TPI stream!"); - - LocallyHashedType WeakHash{Hash, Record}; - auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex()); - - if (Result.second) { - ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Record); - Result.first->first.RecordData = RecordData; - SeenRecords.push_back(RecordData); - } - - // Update the caller's copy of Record to point a stable copy. - TypeIndex ActualTI = Result.first->second; - Record = SeenRecords[ActualTI.toArrayIndex()]; - return ActualTI; -} - -TypeIndex -MergingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { - return insertRecordAs(hash_value(Record), Record); -} - -TypeIndex -MergingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { - TypeIndex TI; - auto Fragments = Builder.end(nextTypeIndex()); - assert(!Fragments.empty()); - for (auto C : Fragments) - TI = insertRecordBytes(C.RecordData); - return TI; -} - -bool MergingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, - bool Stabilize) { - assert(Index.toArrayIndex() < SeenRecords.size() && - "This function cannot be used to insert records!"); - - ArrayRef<uint8_t> Record = Data.data(); - assert(Record.size() < UINT32_MAX && "Record too big"); - assert(Record.size() % 4 == 0 && - "The type record size is not a multiple of 4 bytes which will cause " - "misalignment in the output TPI stream!"); - - LocallyHashedType WeakHash{hash_value(Record), Record}; - auto Result = HashedRecords.try_emplace(WeakHash, Index.toArrayIndex()); - if (!Result.second) { - Index = Result.first->second; - return false; // The record is already there, at a different location - } - - if (Stabilize) { - Record = stabilize(RecordStorage, Record); - Result.first->first.RecordData = Record; - } - - SeenRecords[Index.toArrayIndex()] = Record; - return true; -} +//===- MergingTypeTableBuilder.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +TypeIndex MergingTypeTableBuilder::nextTypeIndex() const { + return TypeIndex::fromArrayIndex(SeenRecords.size()); +} + +MergingTypeTableBuilder::MergingTypeTableBuilder(BumpPtrAllocator &Storage) + : RecordStorage(Storage) { + SeenRecords.reserve(4096); +} + +MergingTypeTableBuilder::~MergingTypeTableBuilder() = default; + +Optional<TypeIndex> MergingTypeTableBuilder::getFirst() { + if (empty()) + return None; + + return TypeIndex(TypeIndex::FirstNonSimpleIndex); +} + +Optional<TypeIndex> MergingTypeTableBuilder::getNext(TypeIndex Prev) { + if (++Prev == nextTypeIndex()) + return None; + return Prev; +} + +CVType MergingTypeTableBuilder::getType(TypeIndex Index) { + CVType Type(SeenRecords[Index.toArrayIndex()]); + return Type; +} + +StringRef MergingTypeTableBuilder::getTypeName(TypeIndex Index) { + llvm_unreachable("Method not implemented"); +} + +bool MergingTypeTableBuilder::contains(TypeIndex Index) { + if (Index.isSimple() || Index.isNoneType()) + return false; + + return Index.toArrayIndex() < SeenRecords.size(); +} + +uint32_t MergingTypeTableBuilder::size() { return SeenRecords.size(); } + +uint32_t MergingTypeTableBuilder::capacity() { return SeenRecords.size(); } + +ArrayRef<ArrayRef<uint8_t>> MergingTypeTableBuilder::records() const { + return SeenRecords; +} + +void MergingTypeTableBuilder::reset() { + HashedRecords.clear(); + SeenRecords.clear(); +} + +static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc, + ArrayRef<uint8_t> Data) { + uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size()); + memcpy(Stable, Data.data(), Data.size()); + return makeArrayRef(Stable, Data.size()); +} + +TypeIndex MergingTypeTableBuilder::insertRecordAs(hash_code Hash, + ArrayRef<uint8_t> &Record) { + assert(Record.size() < UINT32_MAX && "Record too big"); + assert(Record.size() % 4 == 0 && + "The type record size is not a multiple of 4 bytes which will cause " + "misalignment in the output TPI stream!"); + + LocallyHashedType WeakHash{Hash, Record}; + auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex()); + + if (Result.second) { + ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Record); + Result.first->first.RecordData = RecordData; + SeenRecords.push_back(RecordData); + } + + // Update the caller's copy of Record to point a stable copy. + TypeIndex ActualTI = Result.first->second; + Record = SeenRecords[ActualTI.toArrayIndex()]; + return ActualTI; +} + +TypeIndex +MergingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) { + return insertRecordAs(hash_value(Record), Record); +} + +TypeIndex +MergingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) { + TypeIndex TI; + auto Fragments = Builder.end(nextTypeIndex()); + assert(!Fragments.empty()); + for (auto C : Fragments) + TI = insertRecordBytes(C.RecordData); + return TI; +} + +bool MergingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data, + bool Stabilize) { + assert(Index.toArrayIndex() < SeenRecords.size() && + "This function cannot be used to insert records!"); + + ArrayRef<uint8_t> Record = Data.data(); + assert(Record.size() < UINT32_MAX && "Record too big"); + assert(Record.size() % 4 == 0 && + "The type record size is not a multiple of 4 bytes which will cause " + "misalignment in the output TPI stream!"); + + LocallyHashedType WeakHash{hash_value(Record), Record}; + auto Result = HashedRecords.try_emplace(WeakHash, Index.toArrayIndex()); + if (!Result.second) { + Index = Result.first->second; + return false; // The record is already there, at a different location + } + + if (Stabilize) { + Record = stabilize(RecordStorage, Record); + Result.first->first.RecordData = Record; + } + + SeenRecords[Index.toArrayIndex()] = Record; + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordName.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordName.cpp index 1ca899789b..9bec737a4b 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordName.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordName.cpp @@ -1,339 +1,339 @@ -//===- RecordName.cpp ----------------------------------------- *- C++ --*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/RecordName.h" - -#include "llvm/ADT/SmallString.h" +//===- RecordName.cpp ----------------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/RecordName.h" + +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::codeview; - -namespace { -class TypeNameComputer : public TypeVisitorCallbacks { - /// The type collection. Used to calculate names of nested types. - TypeCollection &Types; - TypeIndex CurrentTypeIndex = TypeIndex::None(); - - /// Name of the current type. Only valid before visitTypeEnd. - SmallString<256> Name; - -public: - explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} - - StringRef name() const { return Name; } - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - Error visitTypeBegin(CVType &Record) override; - Error visitTypeBegin(CVType &Record, TypeIndex Index) override; - Error visitTypeEnd(CVType &Record) override; - -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -}; -} // namespace - -Error TypeNameComputer::visitTypeBegin(CVType &Record) { - llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); - return Error::success(); -} - -Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - CurrentTypeIndex = Index; - return Error::success(); -} - -Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - FieldListRecord &FieldList) { - Name = "<field list>"; - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, - StringIdRecord &String) { - Name = String.getString(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { - auto Indices = Args.getIndices(); - uint32_t Size = Indices.size(); - Name = "("; - for (uint32_t I = 0; I < Size; ++I) { +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +class TypeNameComputer : public TypeVisitorCallbacks { + /// The type collection. Used to calculate names of nested types. + TypeCollection &Types; + TypeIndex CurrentTypeIndex = TypeIndex::None(); + + /// Name of the current type. Only valid before visitTypeEnd. + SmallString<256> Name; + +public: + explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} + + StringRef name() const { return Name; } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(CVType &Record) override; + Error visitTypeBegin(CVType &Record, TypeIndex Index) override; + Error visitTypeEnd(CVType &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; +} // namespace + +Error TypeNameComputer::visitTypeBegin(CVType &Record) { + llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); + return Error::success(); +} + +Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + CurrentTypeIndex = Index; + return Error::success(); +} + +Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = "<field list>"; + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, + StringIdRecord &String) { + Name = String.getString(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + Name = "("; + for (uint32_t I = 0; I < Size; ++I) { if (Indices[I] < CurrentTypeIndex) Name.append(Types.getTypeName(Indices[I])); else Name.append("<unknown 0x" + utohexstr(Indices[I].getIndex()) + ">"); - if (I + 1 != Size) - Name.append(", "); - } - Name.push_back(')'); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - StringListRecord &Strings) { - auto Indices = Strings.getIndices(); - uint32_t Size = Indices.size(); - Name = "\""; - for (uint32_t I = 0; I < Size; ++I) { - Name.append(Types.getTypeName(Indices[I])); - if (I + 1 != Size) - Name.append("\" \""); - } - Name.push_back('\"'); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { - Name = Class.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { - Name = Union.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { - Name = Enum.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { - Name = AT.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { - Name = VFT.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { - Name = Id.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { - StringRef Ret = Types.getTypeName(Proc.getReturnType()); - StringRef Params = Types.getTypeName(Proc.getArgumentList()); - Name = formatv("{0} {1}", Ret, Params).sstr<256>(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - MemberFunctionRecord &MF) { - StringRef Ret = Types.getTypeName(MF.getReturnType()); - StringRef Class = Types.getTypeName(MF.getClassType()); - StringRef Params = Types.getTypeName(MF.getArgumentList()); - Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { - Name = Func.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { - Name = TS.getName(); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { - - if (Ptr.isPointerToMember()) { - const MemberPointerInfo &MI = Ptr.getMemberInfo(); - - StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); - StringRef Class = Types.getTypeName(MI.getContainingType()); - Name = formatv("{0} {1}::*", Pointee, Class); - } else { - Name.append(Types.getTypeName(Ptr.getReferentType())); - - if (Ptr.getMode() == PointerMode::LValueReference) - Name.append("&"); - else if (Ptr.getMode() == PointerMode::RValueReference) - Name.append("&&"); - else if (Ptr.getMode() == PointerMode::Pointer) - Name.append("*"); - - // Qualifiers in pointer records apply to the pointer, not the pointee, so - // they go on the right. - if (Ptr.isConst()) - Name.append(" const"); - if (Ptr.isVolatile()) - Name.append(" volatile"); - if (Ptr.isUnaligned()) - Name.append(" __unaligned"); - if (Ptr.isRestrict()) - Name.append(" __restrict"); - } - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { - uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); - - if (Mods & uint16_t(ModifierOptions::Const)) - Name.append("const "); - if (Mods & uint16_t(ModifierOptions::Volatile)) - Name.append("volatile "); - if (Mods & uint16_t(ModifierOptions::Unaligned)) - Name.append("__unaligned "); - Name.append(Types.getTypeName(Mod.getModifiedType())); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - VFTableShapeRecord &Shape) { - Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord( - CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - UdtSourceLineRecord &SourceLine) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - MethodOverloadListRecord &Overloads) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - PrecompRecord &Precomp) { - return Error::success(); -} - -Error TypeNameComputer::visitKnownRecord(CVType &CVR, - EndPrecompRecord &EndPrecomp) { - return Error::success(); -} - -std::string llvm::codeview::computeTypeName(TypeCollection &Types, - TypeIndex Index) { - TypeNameComputer Computer(Types); - CVType Record = Types.getType(Index); - if (auto EC = visitTypeRecord(Record, Index, Computer)) { - consumeError(std::move(EC)); - return "<unknown UDT>"; - } - return std::string(Computer.name()); -} - -static int getSymbolNameOffset(CVSymbol Sym) { - switch (Sym.kind()) { - // See ProcSym - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - case SymbolKind::S_GPROC32_ID: - case SymbolKind::S_LPROC32_ID: - case SymbolKind::S_LPROC32_DPC: - case SymbolKind::S_LPROC32_DPC_ID: - return 35; - // See Thunk32Sym - case SymbolKind::S_THUNK32: - return 21; - // See SectionSym - case SymbolKind::S_SECTION: - return 16; - // See CoffGroupSym - case SymbolKind::S_COFFGROUP: - return 14; - // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym - case SymbolKind::S_PUB32: - case SymbolKind::S_FILESTATIC: - case SymbolKind::S_REGREL32: - case SymbolKind::S_GDATA32: - case SymbolKind::S_LDATA32: - case SymbolKind::S_LMANDATA: - case SymbolKind::S_GMANDATA: - case SymbolKind::S_LTHREAD32: - case SymbolKind::S_GTHREAD32: - case SymbolKind::S_PROCREF: - case SymbolKind::S_LPROCREF: - return 10; - // See RegisterSym and LocalSym - case SymbolKind::S_REGISTER: - case SymbolKind::S_LOCAL: - return 6; - // See BlockSym - case SymbolKind::S_BLOCK32: - return 18; - // See LabelSym - case SymbolKind::S_LABEL32: - return 7; - // See ObjNameSym, ExportSym, and UDTSym - case SymbolKind::S_OBJNAME: - case SymbolKind::S_EXPORT: - case SymbolKind::S_UDT: - return 4; - // See BPRelativeSym - case SymbolKind::S_BPREL32: - return 8; - // See UsingNamespaceSym - case SymbolKind::S_UNAMESPACE: - return 0; - default: - return -1; - } -} - -StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { - if (Sym.kind() == SymbolKind::S_CONSTANT) { - // S_CONSTANT is preceded by an APSInt, which has a variable length. So we - // have to do a full deserialization. - BinaryStreamReader Reader(Sym.content(), llvm::support::little); - // The container doesn't matter for single records. - SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); - ConstantSym Const(SymbolKind::S_CONSTANT); - cantFail(Mapping.visitSymbolBegin(Sym)); - cantFail(Mapping.visitKnownRecord(Sym, Const)); - cantFail(Mapping.visitSymbolEnd(Sym)); - return Const.Name; - } - - int Offset = getSymbolNameOffset(Sym); - if (Offset == -1) - return StringRef(); - - StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); - return StringData.split('\0').first; -} + if (I + 1 != Size) + Name.append(", "); + } + Name.push_back(')'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + StringListRecord &Strings) { + auto Indices = Strings.getIndices(); + uint32_t Size = Indices.size(); + Name = "\""; + for (uint32_t I = 0; I < Size; ++I) { + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append("\" \""); + } + Name.push_back('\"'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + Name = Class.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + StringRef Ret = Types.getTypeName(Proc.getReturnType()); + StringRef Params = Types.getTypeName(Proc.getArgumentList()); + Name = formatv("{0} {1}", Ret, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef Ret = Types.getTypeName(MF.getReturnType()); + StringRef Class = Types.getTypeName(MF.getClassType()); + StringRef Params = Types.getTypeName(MF.getArgumentList()); + Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); + StringRef Class = Types.getTypeName(MI.getContainingType()); + Name = formatv("{0} {1}::*", Pointee, Class); + } else { + Name.append(Types.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + Name.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + Name.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + Name.append("*"); + + // Qualifiers in pointer records apply to the pointer, not the pointee, so + // they go on the right. + if (Ptr.isConst()) + Name.append(" const"); + if (Ptr.isVolatile()) + Name.append(" volatile"); + if (Ptr.isUnaligned()) + Name.append(" __unaligned"); + if (Ptr.isRestrict()) + Name.append(" __restrict"); + } + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); + + if (Mods & uint16_t(ModifierOptions::Const)) + Name.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + Name.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + Name.append("__unaligned "); + Name.append(Types.getTypeName(Mod.getModifiedType())); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = formatv("<vftable {0} methods>", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + PrecompRecord &Precomp) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + EndPrecompRecord &EndPrecomp) { + return Error::success(); +} + +std::string llvm::codeview::computeTypeName(TypeCollection &Types, + TypeIndex Index) { + TypeNameComputer Computer(Types); + CVType Record = Types.getType(Index); + if (auto EC = visitTypeRecord(Record, Index, Computer)) { + consumeError(std::move(EC)); + return "<unknown UDT>"; + } + return std::string(Computer.name()); +} + +static int getSymbolNameOffset(CVSymbol Sym) { + switch (Sym.kind()) { + // See ProcSym + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: + return 35; + // See Thunk32Sym + case SymbolKind::S_THUNK32: + return 21; + // See SectionSym + case SymbolKind::S_SECTION: + return 16; + // See CoffGroupSym + case SymbolKind::S_COFFGROUP: + return 14; + // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym + case SymbolKind::S_PUB32: + case SymbolKind::S_FILESTATIC: + case SymbolKind::S_REGREL32: + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + case SymbolKind::S_LMANDATA: + case SymbolKind::S_GMANDATA: + case SymbolKind::S_LTHREAD32: + case SymbolKind::S_GTHREAD32: + case SymbolKind::S_PROCREF: + case SymbolKind::S_LPROCREF: + return 10; + // See RegisterSym and LocalSym + case SymbolKind::S_REGISTER: + case SymbolKind::S_LOCAL: + return 6; + // See BlockSym + case SymbolKind::S_BLOCK32: + return 18; + // See LabelSym + case SymbolKind::S_LABEL32: + return 7; + // See ObjNameSym, ExportSym, and UDTSym + case SymbolKind::S_OBJNAME: + case SymbolKind::S_EXPORT: + case SymbolKind::S_UDT: + return 4; + // See BPRelativeSym + case SymbolKind::S_BPREL32: + return 8; + // See UsingNamespaceSym + case SymbolKind::S_UNAMESPACE: + return 0; + default: + return -1; + } +} + +StringRef llvm::codeview::getSymbolName(CVSymbol Sym) { + if (Sym.kind() == SymbolKind::S_CONSTANT) { + // S_CONSTANT is preceded by an APSInt, which has a variable length. So we + // have to do a full deserialization. + BinaryStreamReader Reader(Sym.content(), llvm::support::little); + // The container doesn't matter for single records. + SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile); + ConstantSym Const(SymbolKind::S_CONSTANT); + cantFail(Mapping.visitSymbolBegin(Sym)); + cantFail(Mapping.visitKnownRecord(Sym, Const)); + cantFail(Mapping.visitSymbolEnd(Sym)); + return Const.Name; + } + + int Offset = getSymbolNameOffset(Sym); + if (Offset == -1) + return StringRef(); + + StringRef StringData = toStringRef(Sym.content()).drop_front(Offset); + return StringData.split('\0').first; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordSerialization.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordSerialization.cpp index 63ce302a4e..ff364069ee 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordSerialization.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/RecordSerialization.cpp @@ -1,154 +1,154 @@ -//===-- RecordSerialization.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Utilities for serializing and deserializing CodeView records. -// -//===----------------------------------------------------------------------===// - -#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/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/BinaryByteStream.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::support; - -/// Reinterpret a byte array as an array of characters. Does not interpret as -/// a C string, as StringRef has several helpers (split) that make that easy. -StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { - return StringRef(reinterpret_cast<const char *>(LeafData.data()), - LeafData.size()); -} - -StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { - return getBytesAsCharacters(LeafData).split('\0').first; -} - -Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { +//===-- RecordSerialization.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utilities for serializing and deserializing CodeView records. +// +//===----------------------------------------------------------------------===// + +#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/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::support; + +/// Reinterpret a byte array as an array of characters. Does not interpret as +/// a C string, as StringRef has several helpers (split) that make that easy. +StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { + return StringRef(reinterpret_cast<const char *>(LeafData.data()), + LeafData.size()); +} + +StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { + return getBytesAsCharacters(LeafData).split('\0').first; +} + +Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { // Used to avoid overload ambiguity on APInt constructor. - bool FalseVal = false; - 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 Error::success(); - } - - switch (Short) { - 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(); - } - 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"); -} - -Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { - ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); - BinaryByteStream S(Bytes, llvm::support::little); - BinaryStreamReader SR(S); - auto EC = consume(SR, Num); - Data = Data.take_back(SR.bytesRemaining()); - return EC; -} - -/// Decode a numeric leaf value that is known to be a uint64_t. -Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, - uint64_t &Num) { - APSInt N; - if (auto EC = consume(Reader, N)) - return EC; - if (N.isSigned() || !N.isIntN(64)) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Data is not a numeric value!"); - Num = N.getLimitedValue(); - return Error::success(); -} - -Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { - return Reader.readInteger(Item); -} - -Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { - ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); - BinaryByteStream S(Bytes, llvm::support::little); - BinaryStreamReader SR(S); - auto EC = consume(SR, Item); - Data = Data.take_back(SR.bytesRemaining()); - return EC; -} - -Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { - return Reader.readInteger(Item); -} - -Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { - if (Reader.empty()) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Null terminated string buffer is empty!"); - - return Reader.readCString(Item); -} - -Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, - uint32_t Offset) { - return readCVRecordFromStream<SymbolKind>(Stream, Offset); -} + bool FalseVal = false; + 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 Error::success(); + } + + switch (Short) { + 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(); + } + 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"); +} + +Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { + ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); + BinaryByteStream S(Bytes, llvm::support::little); + BinaryStreamReader SR(S); + auto EC = consume(SR, Num); + Data = Data.take_back(SR.bytesRemaining()); + return EC; +} + +/// Decode a numeric leaf value that is known to be a uint64_t. +Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, + uint64_t &Num) { + APSInt N; + if (auto EC = consume(Reader, N)) + return EC; + if (N.isSigned() || !N.isIntN(64)) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Data is not a numeric value!"); + Num = N.getLimitedValue(); + return Error::success(); +} + +Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { + return Reader.readInteger(Item); +} + +Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { + ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); + BinaryByteStream S(Bytes, llvm::support::little); + BinaryStreamReader SR(S); + auto EC = consume(SR, Item); + Data = Data.take_back(SR.bytesRemaining()); + return EC; +} + +Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { + return Reader.readInteger(Item); +} + +Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { + if (Reader.empty()) + return make_error<CodeViewError>(cv_error_code::corrupt_record, + "Null terminated string buffer is empty!"); + + return Reader.readCString(Item); +} + +Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, + uint32_t Offset) { + return readCVRecordFromStream<SymbolKind>(Stream, Offset); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp index ac3b301759..dd542a142d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp @@ -1,67 +1,67 @@ -//===- SimpleTypeSerializer.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" -#include "llvm/Support/BinaryStreamWriter.h" - -using namespace llvm; -using namespace llvm::codeview; - -static void addPadding(BinaryStreamWriter &Writer) { - uint32_t Align = Writer.getOffset() % 4; - if (Align == 0) - return; - - int PaddingBytes = 4 - Align; - while (PaddingBytes > 0) { - uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); - cantFail(Writer.writeInteger(Pad)); - --PaddingBytes; - } -} - -SimpleTypeSerializer::SimpleTypeSerializer() : ScratchBuffer(MaxRecordLength) {} - -SimpleTypeSerializer::~SimpleTypeSerializer() {} - -template <typename T> -ArrayRef<uint8_t> SimpleTypeSerializer::serialize(T &Record) { - BinaryStreamWriter Writer(ScratchBuffer, support::little); - TypeRecordMapping Mapping(Writer); - - // Write the record prefix first with a dummy length but real kind. - RecordPrefix DummyPrefix(uint16_t(Record.getKind())); - cantFail(Writer.writeObject(DummyPrefix)); - - RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(ScratchBuffer.data()); - CVType CVT(Prefix, sizeof(RecordPrefix)); - - cantFail(Mapping.visitTypeBegin(CVT)); - cantFail(Mapping.visitKnownRecord(CVT, Record)); - cantFail(Mapping.visitTypeEnd(CVT)); - - addPadding(Writer); - - // Update the size and kind after serialization. - Prefix->RecordKind = CVT.kind(); - Prefix->RecordLen = Writer.getOffset() - sizeof(uint16_t); - - return {ScratchBuffer.data(), Writer.getOffset()}; -} - -// Explicitly instantiate the member function for each known type so that we can -// implement this in the cpp file. -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - template ArrayRef<uint8_t> llvm::codeview::SimpleTypeSerializer::serialize( \ - Name##Record &Record); -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +//===- SimpleTypeSerializer.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/SimpleTypeSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; + +static void addPadding(BinaryStreamWriter &Writer) { + uint32_t Align = Writer.getOffset() % 4; + if (Align == 0) + return; + + int PaddingBytes = 4 - Align; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + cantFail(Writer.writeInteger(Pad)); + --PaddingBytes; + } +} + +SimpleTypeSerializer::SimpleTypeSerializer() : ScratchBuffer(MaxRecordLength) {} + +SimpleTypeSerializer::~SimpleTypeSerializer() {} + +template <typename T> +ArrayRef<uint8_t> SimpleTypeSerializer::serialize(T &Record) { + BinaryStreamWriter Writer(ScratchBuffer, support::little); + TypeRecordMapping Mapping(Writer); + + // Write the record prefix first with a dummy length but real kind. + RecordPrefix DummyPrefix(uint16_t(Record.getKind())); + cantFail(Writer.writeObject(DummyPrefix)); + + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(ScratchBuffer.data()); + CVType CVT(Prefix, sizeof(RecordPrefix)); + + cantFail(Mapping.visitTypeBegin(CVT)); + cantFail(Mapping.visitKnownRecord(CVT, Record)); + cantFail(Mapping.visitTypeEnd(CVT)); + + addPadding(Writer); + + // Update the size and kind after serialization. + Prefix->RecordKind = CVT.kind(); + Prefix->RecordLen = Writer.getOffset() - sizeof(uint16_t); + + return {ScratchBuffer.data(), Writer.getOffset()}; +} + +// Explicitly instantiate the member function for each known type so that we can +// implement this in the cpp file. +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + template ArrayRef<uint8_t> llvm::codeview::SimpleTypeSerializer::serialize( \ + Name##Record &Record); +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/StringsAndChecksums.cpp index 9e204eec86..3f11d2775b 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/StringsAndChecksums.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/StringsAndChecksums.cpp @@ -1,80 +1,80 @@ -//===- StringsAndChecksums.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/Support/Error.h" -#include <cassert> - -using namespace llvm; -using namespace llvm::codeview; - -StringsAndChecksumsRef::StringsAndChecksumsRef() = default; - -StringsAndChecksumsRef::StringsAndChecksumsRef( - const DebugStringTableSubsectionRef &Strings) - : Strings(&Strings) {} - -StringsAndChecksumsRef::StringsAndChecksumsRef( - const DebugStringTableSubsectionRef &Strings, - const DebugChecksumsSubsectionRef &Checksums) - : Strings(&Strings), Checksums(&Checksums) {} - -void StringsAndChecksumsRef::initializeStrings( - const DebugSubsectionRecord &SR) { - assert(SR.kind() == DebugSubsectionKind::StringTable); - assert(!Strings && "Found a string table even though we already have one!"); - - OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); - consumeError(OwnedStrings->initialize(SR.getRecordData())); - Strings = OwnedStrings.get(); -} - -void StringsAndChecksumsRef::reset() { - resetStrings(); - resetChecksums(); -} - -void StringsAndChecksumsRef::resetStrings() { - OwnedStrings.reset(); - Strings = nullptr; -} - -void StringsAndChecksumsRef::resetChecksums() { - OwnedChecksums.reset(); - Checksums = nullptr; -} - -void StringsAndChecksumsRef::setStrings( - const DebugStringTableSubsectionRef &StringsRef) { - OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); - *OwnedStrings = StringsRef; - Strings = OwnedStrings.get(); -} - -void StringsAndChecksumsRef::setChecksums( - const DebugChecksumsSubsectionRef &CS) { - OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); - *OwnedChecksums = CS; - Checksums = OwnedChecksums.get(); -} - -void StringsAndChecksumsRef::initializeChecksums( - const DebugSubsectionRecord &FCR) { - assert(FCR.kind() == DebugSubsectionKind::FileChecksums); - if (Checksums) - return; - - OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); - consumeError(OwnedChecksums->initialize(FCR.getRecordData())); - Checksums = OwnedChecksums.get(); -} +//===- StringsAndChecksums.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/Support/Error.h" +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; + +StringsAndChecksumsRef::StringsAndChecksumsRef() = default; + +StringsAndChecksumsRef::StringsAndChecksumsRef( + const DebugStringTableSubsectionRef &Strings) + : Strings(&Strings) {} + +StringsAndChecksumsRef::StringsAndChecksumsRef( + const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums) + : Strings(&Strings), Checksums(&Checksums) {} + +void StringsAndChecksumsRef::initializeStrings( + const DebugSubsectionRecord &SR) { + assert(SR.kind() == DebugSubsectionKind::StringTable); + assert(!Strings && "Found a string table even though we already have one!"); + + OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); + consumeError(OwnedStrings->initialize(SR.getRecordData())); + Strings = OwnedStrings.get(); +} + +void StringsAndChecksumsRef::reset() { + resetStrings(); + resetChecksums(); +} + +void StringsAndChecksumsRef::resetStrings() { + OwnedStrings.reset(); + Strings = nullptr; +} + +void StringsAndChecksumsRef::resetChecksums() { + OwnedChecksums.reset(); + Checksums = nullptr; +} + +void StringsAndChecksumsRef::setStrings( + const DebugStringTableSubsectionRef &StringsRef) { + OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>(); + *OwnedStrings = StringsRef; + Strings = OwnedStrings.get(); +} + +void StringsAndChecksumsRef::setChecksums( + const DebugChecksumsSubsectionRef &CS) { + OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); + *OwnedChecksums = CS; + Checksums = OwnedChecksums.get(); +} + +void StringsAndChecksumsRef::initializeChecksums( + const DebugSubsectionRecord &FCR) { + assert(FCR.kind() == DebugSubsectionKind::FileChecksums); + if (Checksums) + return; + + OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>(); + consumeError(OwnedChecksums->initialize(FCR.getRecordData())); + Checksums = OwnedChecksums.get(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolDumper.cpp index 45b63983be..e130f8b3d2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -1,679 +1,679 @@ -//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.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/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> - -using namespace llvm; -using namespace llvm::codeview; - -namespace { -/// Use this private dumper implementation to keep implementation details about -/// the visitor out of SymbolDumper.h. -class CVSymbolDumperImpl : public SymbolVisitorCallbacks { -public: - CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate, - ScopedPrinter &W, CPUType CPU, bool PrintRecordBytes) - : Types(Types), ObjDelegate(ObjDelegate), W(W), CompilationCPUType(CPU), - PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} - -/// CVSymbolVisitor overrides. -#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVSymbol &CVR, Name &Record) override; -#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" - - Error visitSymbolBegin(CVSymbol &Record) override; - Error visitSymbolEnd(CVSymbol &Record) override; - Error visitUnknownSymbol(CVSymbol &Record) override; - - CPUType getCompilationCPUType() const { return CompilationCPUType; } - -private: - void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, - uint32_t RelocationOffset); - void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); - void printTypeIndex(StringRef FieldName, TypeIndex TI); - - TypeCollection &Types; - SymbolDumpDelegate *ObjDelegate; - ScopedPrinter &W; - - /// Save the machine or CPU type when dumping a compile symbols. - CPUType CompilationCPUType = CPUType::X64; - - bool PrintRecordBytes; - bool InFunctionScope; -}; -} - -static StringRef getSymbolKindName(SymbolKind Kind) { - switch (Kind) { -#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ - case EnumName: \ - return #Name; -#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" - default: - break; - } - return "UnknownSym"; -} - -void CVSymbolDumperImpl::printLocalVariableAddrRange( - const LocalVariableAddrRange &Range, uint32_t RelocationOffset) { - DictScope S(W, "LocalVariableAddrRange"); - if (ObjDelegate) - ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset, - Range.OffsetStart); - W.printHex("ISectStart", Range.ISectStart); - W.printHex("Range", Range.Range); -} - -void CVSymbolDumperImpl::printLocalVariableAddrGap( - ArrayRef<LocalVariableAddrGap> Gaps) { - for (auto &Gap : Gaps) { - ListScope S(W, "LocalVariableAddrGap"); - W.printHex("GapStartOffset", Gap.GapStartOffset); - W.printHex("Range", Gap.Range); - } -} - -void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { - codeview::printTypeIndex(W, FieldName, TI, Types); -} - -Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { - W.startLine() << getSymbolKindName(CVR.kind()); - W.getOStream() << " {\n"; - W.indent(); - W.printEnum("Kind", unsigned(CVR.kind()), getSymbolTypeNames()); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) { - if (PrintRecordBytes && ObjDelegate) - ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content()); - - W.unindent(); - W.startLine() << "}\n"; - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { - StringRef LinkageName; - W.printHex("PtrParent", Block.Parent); - W.printHex("PtrEnd", Block.End); - W.printHex("CodeSize", Block.CodeSize); - if (ObjDelegate) { - ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(), - Block.CodeOffset, &LinkageName); - } - W.printHex("Segment", Block.Segment); - W.printString("BlockName", Block.Name); - W.printString("LinkageName", LinkageName); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { - W.printString("Name", Thunk.Name); - 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) { - 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(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) { - 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(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - CoffGroupSym &CoffGroup) { - W.printNumber("Size", CoffGroup.Size); - W.printFlags("Characteristics", CoffGroup.Characteristics, - getImageSectionCharacteristicNames(), - COFF::SectionCharacteristics(0x00F00000)); - W.printNumber("Offset", CoffGroup.Offset); - W.printNumber("Segment", CoffGroup.Segment); - W.printString("Name", CoffGroup.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - BPRelativeSym &BPRel) { - W.printNumber("Offset", BPRel.Offset); - printTypeIndex("Type", BPRel.Type); - W.printString("VarName", BPRel.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - BuildInfoSym &BuildInfo) { - printTypeIndex("BuildId", BuildInfo.BuildId); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - CallSiteInfoSym &CallSiteInfo) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("CodeOffset", - CallSiteInfo.getRelocationOffset(), - CallSiteInfo.CodeOffset, &LinkageName); - } - W.printHex("Segment", CallSiteInfo.Segment); - printTypeIndex("Type", CallSiteInfo.Type); - if (!LinkageName.empty()) - W.printString("LinkageName", LinkageName); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - EnvBlockSym &EnvBlock) { - ListScope L(W, "Entries"); - for (auto Entry : EnvBlock.Fields) { - W.printString(Entry); - } - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - FileStaticSym &FileStatic) { - printTypeIndex("Index", FileStatic.Index); - W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset); - W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames()); - W.printString("Name", FileStatic.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { - W.printNumber("Ordinal", Export.Ordinal); - W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames()); - W.printString("Name", Export.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - Compile2Sym &Compile2) { - W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames()); - W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames()); - W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); - CompilationCPUType = Compile2.Machine; - std::string FrontendVersion; - { - raw_string_ostream Out(FrontendVersion); - Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor - << '.' << Compile2.VersionFrontendBuild; - } - std::string BackendVersion; - { - raw_string_ostream Out(BackendVersion); - Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor - << '.' << Compile2.VersionBackendBuild; - } - W.printString("FrontendVersion", FrontendVersion); - W.printString("BackendVersion", BackendVersion); - W.printString("VersionName", Compile2.Version); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - Compile3Sym &Compile3) { - W.printEnum("Language", uint8_t(Compile3.getLanguage()), getSourceLanguageNames()); - W.printFlags("Flags", uint32_t(Compile3.getFlags()), - getCompileSym3FlagNames()); - W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); - CompilationCPUType = Compile3.Machine; - std::string FrontendVersion; - { - raw_string_ostream Out(FrontendVersion); - Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor - << '.' << Compile3.VersionFrontendBuild << '.' - << Compile3.VersionFrontendQFE; - } - std::string BackendVersion; - { - raw_string_ostream Out(BackendVersion); - 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(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - ConstantSym &Constant) { - printTypeIndex("Type", Constant.Type); - W.printNumber("Value", Constant.Value); - W.printString("Name", Constant.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), - Data.DataOffset, &LinkageName); - } - printTypeIndex("Type", Data.Type); - W.printString("DisplayName", Data.Name); - if (!LinkageName.empty()) - W.printString("LinkageName", LinkageName); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, - DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { - W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { - W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset); - printLocalVariableAddrRange(DefRangeFramePointerRel.Range, - DefRangeFramePointerRel.getRelocationOffset()); - printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { - W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register), - getRegisterNames(CompilationCPUType)); - W.printBoolean("HasSpilledUDTMember", - DefRangeRegisterRel.hasSpilledUDTMember()); - W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); - W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset); - printLocalVariableAddrRange(DefRangeRegisterRel.Range, - DefRangeRegisterRel.getRelocationOffset()); - printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { - W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register), - getRegisterNames(CompilationCPUType)); - W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); - printLocalVariableAddrRange(DefRangeRegister.Range, - DefRangeRegister.getRelocationOffset()); - printLocalVariableAddrGap(DefRangeRegister.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { - W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register), - getRegisterNames(CompilationCPUType)); - W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); - W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, - DefRangeSubfieldRegister.getRelocationOffset()); - printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) { - if (ObjDelegate) { - DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); - auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program); - if (!ExpectedProgram) { - consumeError(ExpectedProgram.takeError()); - return llvm::make_error<CodeViewError>( - "String table offset outside of bounds of String Table!"); - } - W.printString("Program", *ExpectedProgram); - } - W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); - printLocalVariableAddrRange(DefRangeSubfield.Range, - DefRangeSubfield.getRelocationOffset()); - printLocalVariableAddrGap(DefRangeSubfield.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - DefRangeSym &DefRange) { - if (ObjDelegate) { - DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); - auto ExpectedProgram = Strings.getString(DefRange.Program); - if (!ExpectedProgram) { - consumeError(ExpectedProgram.takeError()); - return llvm::make_error<CodeViewError>( - "String table offset outside of bounds of String Table!"); - } - W.printString("Program", *ExpectedProgram); - } - printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); - printLocalVariableAddrGap(DefRange.Gaps); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - FrameCookieSym &FrameCookie) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("CodeOffset", - FrameCookie.getRelocationOffset(), - FrameCookie.CodeOffset, &LinkageName); - } - W.printEnum("Register", uint16_t(FrameCookie.Register), - getRegisterNames(CompilationCPUType)); - W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind), - getFrameCookieKindNames()); - W.printHex("Flags", FrameCookie.Flags); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - FrameProcSym &FrameProc) { - W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes); - W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes); - W.printHex("OffsetToPadding", FrameProc.OffsetToPadding); - W.printHex("BytesOfCalleeSavedRegisters", - FrameProc.BytesOfCalleeSavedRegisters); - W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler); - W.printHex("SectionIdOfExceptionHandler", - FrameProc.SectionIdOfExceptionHandler); - W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags), - getFrameProcSymFlagNames()); - W.printEnum("LocalFramePtrReg", - uint16_t(FrameProc.getLocalFramePtrReg(CompilationCPUType)), - getRegisterNames(CompilationCPUType)); - W.printEnum("ParamFramePtrReg", - uint16_t(FrameProc.getParamFramePtrReg(CompilationCPUType)), - getRegisterNames(CompilationCPUType)); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord( - CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("CodeOffset", - HeapAllocSite.getRelocationOffset(), - HeapAllocSite.CodeOffset, &LinkageName); - } - W.printHex("Segment", HeapAllocSite.Segment); - W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); - printTypeIndex("Type", HeapAllocSite.Type); - if (!LinkageName.empty()) - W.printString("LinkageName", LinkageName); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - InlineSiteSym &InlineSite) { - 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: - W.printString("(Annotation Padding)"); - break; - case BinaryAnnotationsOpCode::CodeOffset: - case BinaryAnnotationsOpCode::ChangeCodeOffset: - case BinaryAnnotationsOpCode::ChangeCodeLength: - W.printHex(Annotation.Name, Annotation.U1); - break; - case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: - case BinaryAnnotationsOpCode::ChangeLineEndDelta: - case BinaryAnnotationsOpCode::ChangeRangeKind: - case BinaryAnnotationsOpCode::ChangeColumnStart: - case BinaryAnnotationsOpCode::ChangeColumnEnd: - W.printNumber(Annotation.Name, Annotation.U1); - break; - case BinaryAnnotationsOpCode::ChangeLineOffset: - case BinaryAnnotationsOpCode::ChangeColumnEndDelta: - W.printNumber(Annotation.Name, Annotation.S1); - break; - case BinaryAnnotationsOpCode::ChangeFile: - if (ObjDelegate) { - W.printHex("ChangeFile", - ObjDelegate->getFileNameForFileOffset(Annotation.U1), - Annotation.U1); - } else { - W.printHex("ChangeFile", Annotation.U1); - } - - break; - case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { - W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: " - << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1 - << "}\n"; - break; - } - case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { - W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: " - << W.hex(Annotation.U2) - << ", Length: " << W.hex(Annotation.U1) << "}\n"; - break; - } - } - } - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - RegisterSym &Register) { - printTypeIndex("Type", Register.Index); - W.printEnum("Seg", uint16_t(Register.Register), - getRegisterNames(CompilationCPUType)); - W.printString("Name", Register.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { - W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames()); - W.printNumber("Seg", Public.Segment); - W.printNumber("Off", Public.Offset); - W.printString("Name", Public.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) { - W.printNumber("SumName", ProcRef.SumName); - W.printNumber("SymOffset", ProcRef.SymOffset); - W.printNumber("Mod", ProcRef.Module); - W.printString("Name", ProcRef.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(), - Label.CodeOffset, &LinkageName); - } - 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(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { - printTypeIndex("Type", Local.Type); - W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); - W.printString("VarName", Local.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) { - W.printHex("Signature", ObjName.Signature); - W.printString("ObjectName", ObjName.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { - if (InFunctionScope) - return llvm::make_error<CodeViewError>( - "Visiting a ProcSym while inside function scope!"); - - InFunctionScope = true; - - StringRef LinkageName; - 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.CodeOffset, &LinkageName); - } - 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(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - ScopeEndSym &ScopeEnd) { - InFunctionScope = false; - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { - ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); - for (auto FuncID : Caller.Indices) - printTypeIndex("FuncID", FuncID); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - RegRelativeSym &RegRel) { - W.printHex("Offset", RegRel.Offset); - printTypeIndex("Type", RegRel.Type); - W.printEnum("Register", uint16_t(RegRel.Register), - getRegisterNames(CompilationCPUType)); - W.printString("VarName", RegRel.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - ThreadLocalDataSym &Data) { - StringRef LinkageName; - if (ObjDelegate) { - ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), - Data.DataOffset, &LinkageName); - } - printTypeIndex("Type", Data.Type); - W.printString("DisplayName", Data.Name); - if (!LinkageName.empty()) - W.printString("LinkageName", LinkageName); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { - printTypeIndex("Type", UDT.Type); - W.printString("UDTName", UDT.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - UsingNamespaceSym &UN) { - W.printString("Namespace", UN.Name); - return Error::success(); -} - -Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, - AnnotationSym &Annot) { - W.printHex("Offset", Annot.CodeOffset); - W.printHex("Segment", Annot.Segment); - - ListScope S(W, "Strings"); - for (StringRef Str : Annot.Strings) - W.printString(Str); - - return Error::success(); -} - -Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { - W.printNumber("Length", CVR.length()); - return Error::success(); -} - -Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) { - SymbolVisitorCallbackPipeline Pipeline; - SymbolDeserializer Deserializer(ObjDelegate.get(), Container); - CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, - PrintRecordBytes); - - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Dumper); - CVSymbolVisitor Visitor(Pipeline); - auto Err = Visitor.visitSymbolRecord(Record); - CompilationCPUType = Dumper.getCompilationCPUType(); - return Err; -} - -Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { - SymbolVisitorCallbackPipeline Pipeline; - SymbolDeserializer Deserializer(ObjDelegate.get(), Container); - CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, - PrintRecordBytes); - - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(Dumper); - CVSymbolVisitor Visitor(Pipeline); - auto Err = Visitor.visitSymbolStream(Symbols); - CompilationCPUType = Dumper.getCompilationCPUType(); - return Err; -} +//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.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/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> + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +/// Use this private dumper implementation to keep implementation details about +/// the visitor out of SymbolDumper.h. +class CVSymbolDumperImpl : public SymbolVisitorCallbacks { +public: + CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate, + ScopedPrinter &W, CPUType CPU, bool PrintRecordBytes) + : Types(Types), ObjDelegate(ObjDelegate), W(W), CompilationCPUType(CPU), + PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} + +/// CVSymbolVisitor overrides. +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVSymbol &CVR, Name &Record) override; +#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" + + Error visitSymbolBegin(CVSymbol &Record) override; + Error visitSymbolEnd(CVSymbol &Record) override; + Error visitUnknownSymbol(CVSymbol &Record) override; + + CPUType getCompilationCPUType() const { return CompilationCPUType; } + +private: + void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, + uint32_t RelocationOffset); + void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); + void printTypeIndex(StringRef FieldName, TypeIndex TI); + + TypeCollection &Types; + SymbolDumpDelegate *ObjDelegate; + ScopedPrinter &W; + + /// Save the machine or CPU type when dumping a compile symbols. + CPUType CompilationCPUType = CPUType::X64; + + bool PrintRecordBytes; + bool InFunctionScope; +}; +} + +static StringRef getSymbolKindName(SymbolKind Kind) { + switch (Kind) { +#define SYMBOL_RECORD(EnumName, EnumVal, Name) \ + case EnumName: \ + return #Name; +#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" + default: + break; + } + return "UnknownSym"; +} + +void CVSymbolDumperImpl::printLocalVariableAddrRange( + const LocalVariableAddrRange &Range, uint32_t RelocationOffset) { + DictScope S(W, "LocalVariableAddrRange"); + if (ObjDelegate) + ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset, + Range.OffsetStart); + W.printHex("ISectStart", Range.ISectStart); + W.printHex("Range", Range.Range); +} + +void CVSymbolDumperImpl::printLocalVariableAddrGap( + ArrayRef<LocalVariableAddrGap> Gaps) { + for (auto &Gap : Gaps) { + ListScope S(W, "LocalVariableAddrGap"); + W.printHex("GapStartOffset", Gap.GapStartOffset); + W.printHex("Range", Gap.Range); + } +} + +void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { + codeview::printTypeIndex(W, FieldName, TI, Types); +} + +Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { + W.startLine() << getSymbolKindName(CVR.kind()); + W.getOStream() << " {\n"; + W.indent(); + W.printEnum("Kind", unsigned(CVR.kind()), getSymbolTypeNames()); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) { + if (PrintRecordBytes && ObjDelegate) + ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content()); + + W.unindent(); + W.startLine() << "}\n"; + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { + StringRef LinkageName; + W.printHex("PtrParent", Block.Parent); + W.printHex("PtrEnd", Block.End); + W.printHex("CodeSize", Block.CodeSize); + if (ObjDelegate) { + ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(), + Block.CodeOffset, &LinkageName); + } + W.printHex("Segment", Block.Segment); + W.printString("BlockName", Block.Name); + W.printString("LinkageName", LinkageName); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { + W.printString("Name", Thunk.Name); + 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) { + 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(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) { + 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(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + CoffGroupSym &CoffGroup) { + W.printNumber("Size", CoffGroup.Size); + W.printFlags("Characteristics", CoffGroup.Characteristics, + getImageSectionCharacteristicNames(), + COFF::SectionCharacteristics(0x00F00000)); + W.printNumber("Offset", CoffGroup.Offset); + W.printNumber("Segment", CoffGroup.Segment); + W.printString("Name", CoffGroup.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + BPRelativeSym &BPRel) { + W.printNumber("Offset", BPRel.Offset); + printTypeIndex("Type", BPRel.Type); + W.printString("VarName", BPRel.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + BuildInfoSym &BuildInfo) { + printTypeIndex("BuildId", BuildInfo.BuildId); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + CallSiteInfoSym &CallSiteInfo) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("CodeOffset", + CallSiteInfo.getRelocationOffset(), + CallSiteInfo.CodeOffset, &LinkageName); + } + W.printHex("Segment", CallSiteInfo.Segment); + printTypeIndex("Type", CallSiteInfo.Type); + if (!LinkageName.empty()) + W.printString("LinkageName", LinkageName); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + EnvBlockSym &EnvBlock) { + ListScope L(W, "Entries"); + for (auto Entry : EnvBlock.Fields) { + W.printString(Entry); + } + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + FileStaticSym &FileStatic) { + printTypeIndex("Index", FileStatic.Index); + W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset); + W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames()); + W.printString("Name", FileStatic.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { + W.printNumber("Ordinal", Export.Ordinal); + W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames()); + W.printString("Name", Export.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + Compile2Sym &Compile2) { + W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames()); + W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames()); + W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); + CompilationCPUType = Compile2.Machine; + std::string FrontendVersion; + { + raw_string_ostream Out(FrontendVersion); + Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor + << '.' << Compile2.VersionFrontendBuild; + } + std::string BackendVersion; + { + raw_string_ostream Out(BackendVersion); + Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor + << '.' << Compile2.VersionBackendBuild; + } + W.printString("FrontendVersion", FrontendVersion); + W.printString("BackendVersion", BackendVersion); + W.printString("VersionName", Compile2.Version); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + Compile3Sym &Compile3) { + W.printEnum("Language", uint8_t(Compile3.getLanguage()), getSourceLanguageNames()); + W.printFlags("Flags", uint32_t(Compile3.getFlags()), + getCompileSym3FlagNames()); + W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); + CompilationCPUType = Compile3.Machine; + std::string FrontendVersion; + { + raw_string_ostream Out(FrontendVersion); + Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor + << '.' << Compile3.VersionFrontendBuild << '.' + << Compile3.VersionFrontendQFE; + } + std::string BackendVersion; + { + raw_string_ostream Out(BackendVersion); + 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(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ConstantSym &Constant) { + printTypeIndex("Type", Constant.Type); + W.printNumber("Value", Constant.Value); + W.printString("Name", Constant.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), + Data.DataOffset, &LinkageName); + } + printTypeIndex("Type", Data.Type); + W.printString("DisplayName", Data.Name); + if (!LinkageName.empty()) + W.printString("LinkageName", LinkageName); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, + DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { + W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { + W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset); + printLocalVariableAddrRange(DefRangeFramePointerRel.Range, + DefRangeFramePointerRel.getRelocationOffset()); + printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { + W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register), + getRegisterNames(CompilationCPUType)); + W.printBoolean("HasSpilledUDTMember", + DefRangeRegisterRel.hasSpilledUDTMember()); + W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); + W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset); + printLocalVariableAddrRange(DefRangeRegisterRel.Range, + DefRangeRegisterRel.getRelocationOffset()); + printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { + W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register), + getRegisterNames(CompilationCPUType)); + W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); + printLocalVariableAddrRange(DefRangeRegister.Range, + DefRangeRegister.getRelocationOffset()); + printLocalVariableAddrGap(DefRangeRegister.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { + W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register), + getRegisterNames(CompilationCPUType)); + W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); + W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent); + printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, + DefRangeSubfieldRegister.getRelocationOffset()); + printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) { + if (ObjDelegate) { + DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); + auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program); + if (!ExpectedProgram) { + consumeError(ExpectedProgram.takeError()); + return llvm::make_error<CodeViewError>( + "String table offset outside of bounds of String Table!"); + } + W.printString("Program", *ExpectedProgram); + } + W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); + printLocalVariableAddrRange(DefRangeSubfield.Range, + DefRangeSubfield.getRelocationOffset()); + printLocalVariableAddrGap(DefRangeSubfield.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + DefRangeSym &DefRange) { + if (ObjDelegate) { + DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); + auto ExpectedProgram = Strings.getString(DefRange.Program); + if (!ExpectedProgram) { + consumeError(ExpectedProgram.takeError()); + return llvm::make_error<CodeViewError>( + "String table offset outside of bounds of String Table!"); + } + W.printString("Program", *ExpectedProgram); + } + printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); + printLocalVariableAddrGap(DefRange.Gaps); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + FrameCookieSym &FrameCookie) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("CodeOffset", + FrameCookie.getRelocationOffset(), + FrameCookie.CodeOffset, &LinkageName); + } + W.printEnum("Register", uint16_t(FrameCookie.Register), + getRegisterNames(CompilationCPUType)); + W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind), + getFrameCookieKindNames()); + W.printHex("Flags", FrameCookie.Flags); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + FrameProcSym &FrameProc) { + W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes); + W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes); + W.printHex("OffsetToPadding", FrameProc.OffsetToPadding); + W.printHex("BytesOfCalleeSavedRegisters", + FrameProc.BytesOfCalleeSavedRegisters); + W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler); + W.printHex("SectionIdOfExceptionHandler", + FrameProc.SectionIdOfExceptionHandler); + W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags), + getFrameProcSymFlagNames()); + W.printEnum("LocalFramePtrReg", + uint16_t(FrameProc.getLocalFramePtrReg(CompilationCPUType)), + getRegisterNames(CompilationCPUType)); + W.printEnum("ParamFramePtrReg", + uint16_t(FrameProc.getParamFramePtrReg(CompilationCPUType)), + getRegisterNames(CompilationCPUType)); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord( + CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("CodeOffset", + HeapAllocSite.getRelocationOffset(), + HeapAllocSite.CodeOffset, &LinkageName); + } + W.printHex("Segment", HeapAllocSite.Segment); + W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); + printTypeIndex("Type", HeapAllocSite.Type); + if (!LinkageName.empty()) + W.printString("LinkageName", LinkageName); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + InlineSiteSym &InlineSite) { + 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: + W.printString("(Annotation Padding)"); + break; + case BinaryAnnotationsOpCode::CodeOffset: + case BinaryAnnotationsOpCode::ChangeCodeOffset: + case BinaryAnnotationsOpCode::ChangeCodeLength: + W.printHex(Annotation.Name, Annotation.U1); + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: + case BinaryAnnotationsOpCode::ChangeLineEndDelta: + case BinaryAnnotationsOpCode::ChangeRangeKind: + case BinaryAnnotationsOpCode::ChangeColumnStart: + case BinaryAnnotationsOpCode::ChangeColumnEnd: + W.printNumber(Annotation.Name, Annotation.U1); + break; + case BinaryAnnotationsOpCode::ChangeLineOffset: + case BinaryAnnotationsOpCode::ChangeColumnEndDelta: + W.printNumber(Annotation.Name, Annotation.S1); + break; + case BinaryAnnotationsOpCode::ChangeFile: + if (ObjDelegate) { + W.printHex("ChangeFile", + ObjDelegate->getFileNameForFileOffset(Annotation.U1), + Annotation.U1); + } else { + W.printHex("ChangeFile", Annotation.U1); + } + + break; + case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { + W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: " + << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1 + << "}\n"; + break; + } + case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { + W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: " + << W.hex(Annotation.U2) + << ", Length: " << W.hex(Annotation.U1) << "}\n"; + break; + } + } + } + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + RegisterSym &Register) { + printTypeIndex("Type", Register.Index); + W.printEnum("Seg", uint16_t(Register.Register), + getRegisterNames(CompilationCPUType)); + W.printString("Name", Register.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { + W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames()); + W.printNumber("Seg", Public.Segment); + W.printNumber("Off", Public.Offset); + W.printString("Name", Public.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) { + W.printNumber("SumName", ProcRef.SumName); + W.printNumber("SymOffset", ProcRef.SymOffset); + W.printNumber("Mod", ProcRef.Module); + W.printString("Name", ProcRef.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(), + Label.CodeOffset, &LinkageName); + } + 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(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { + printTypeIndex("Type", Local.Type); + W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); + W.printString("VarName", Local.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) { + W.printHex("Signature", ObjName.Signature); + W.printString("ObjectName", ObjName.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { + if (InFunctionScope) + return llvm::make_error<CodeViewError>( + "Visiting a ProcSym while inside function scope!"); + + InFunctionScope = true; + + StringRef LinkageName; + 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.CodeOffset, &LinkageName); + } + 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(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ScopeEndSym &ScopeEnd) { + InFunctionScope = false; + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { + ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); + for (auto FuncID : Caller.Indices) + printTypeIndex("FuncID", FuncID); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + RegRelativeSym &RegRel) { + W.printHex("Offset", RegRel.Offset); + printTypeIndex("Type", RegRel.Type); + W.printEnum("Register", uint16_t(RegRel.Register), + getRegisterNames(CompilationCPUType)); + W.printString("VarName", RegRel.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + ThreadLocalDataSym &Data) { + StringRef LinkageName; + if (ObjDelegate) { + ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), + Data.DataOffset, &LinkageName); + } + printTypeIndex("Type", Data.Type); + W.printString("DisplayName", Data.Name); + if (!LinkageName.empty()) + W.printString("LinkageName", LinkageName); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { + printTypeIndex("Type", UDT.Type); + W.printString("UDTName", UDT.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + UsingNamespaceSym &UN) { + W.printString("Namespace", UN.Name); + return Error::success(); +} + +Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, + AnnotationSym &Annot) { + W.printHex("Offset", Annot.CodeOffset); + W.printHex("Segment", Annot.Segment); + + ListScope S(W, "Strings"); + for (StringRef Str : Annot.Strings) + W.printString(Str); + + return Error::success(); +} + +Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { + W.printNumber("Length", CVR.length()); + return Error::success(); +} + +Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) { + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(ObjDelegate.get(), Container); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, + PrintRecordBytes); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + auto Err = Visitor.visitSymbolRecord(Record); + CompilationCPUType = Dumper.getCompilationCPUType(); + return Err; +} + +Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { + SymbolVisitorCallbackPipeline Pipeline; + SymbolDeserializer Deserializer(ObjDelegate.get(), Container); + CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, + PrintRecordBytes); + + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Dumper); + CVSymbolVisitor Visitor(Pipeline); + auto Err = Visitor.visitSymbolStream(Symbols); + CompilationCPUType = Dumper.getCompilationCPUType(); + return Err; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp index 2562c633bb..a4d3a4068e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp @@ -1,93 +1,93 @@ -//===- SymbolRecordHelpers.cpp ----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" - -using namespace llvm; -using namespace llvm::codeview; - -template <typename RecordT> static RecordT createRecord(const CVSymbol &sym) { - RecordT record(static_cast<SymbolRecordKind>(sym.kind())); - cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record)); - return record; -} - -uint32_t llvm::codeview::getScopeEndOffset(const CVSymbol &Sym) { - assert(symbolOpensScope(Sym.kind())); - switch (Sym.kind()) { - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - case SymbolKind::S_GPROC32_ID: - case SymbolKind::S_LPROC32_ID: - case SymbolKind::S_LPROC32_DPC: - case SymbolKind::S_LPROC32_DPC_ID: { - ProcSym Proc = createRecord<ProcSym>(Sym); - return Proc.End; - } - case SymbolKind::S_BLOCK32: { - BlockSym Block = createRecord<BlockSym>(Sym); - return Block.End; - } - case SymbolKind::S_THUNK32: { - Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym); - return Thunk.End; - } - case SymbolKind::S_INLINESITE: { - InlineSiteSym Site = createRecord<InlineSiteSym>(Sym); - return Site.End; - } - default: - assert(false && "Unknown record type"); - return 0; - } -} - -uint32_t -llvm::codeview::getScopeParentOffset(const llvm::codeview::CVSymbol &Sym) { - assert(symbolOpensScope(Sym.kind())); - switch (Sym.kind()) { - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - case SymbolKind::S_GPROC32_ID: - case SymbolKind::S_LPROC32_ID: - case SymbolKind::S_LPROC32_DPC: - case SymbolKind::S_LPROC32_DPC_ID: { - ProcSym Proc = createRecord<ProcSym>(Sym); - return Proc.Parent; - } - case SymbolKind::S_BLOCK32: { - BlockSym Block = createRecord<BlockSym>(Sym); - return Block.Parent; - } - case SymbolKind::S_THUNK32: { - Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym); - return Thunk.Parent; - } - case SymbolKind::S_INLINESITE: { - InlineSiteSym Site = createRecord<InlineSiteSym>(Sym); - return Site.Parent; - } - default: - assert(false && "Unknown record type"); - return 0; - } -} - -CVSymbolArray -llvm::codeview::limitSymbolArrayToScope(const CVSymbolArray &Symbols, - uint32_t ScopeBegin) { - CVSymbol Opener = *Symbols.at(ScopeBegin); - assert(symbolOpensScope(Opener.kind())); - uint32_t EndOffset = getScopeEndOffset(Opener); - CVSymbol Closer = *Symbols.at(EndOffset); - EndOffset += Closer.RecordData.size(); - return Symbols.substream(ScopeBegin, EndOffset); -} +//===- SymbolRecordHelpers.cpp ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" + +using namespace llvm; +using namespace llvm::codeview; + +template <typename RecordT> static RecordT createRecord(const CVSymbol &sym) { + RecordT record(static_cast<SymbolRecordKind>(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record)); + return record; +} + +uint32_t llvm::codeview::getScopeEndOffset(const CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + switch (Sym.kind()) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: { + ProcSym Proc = createRecord<ProcSym>(Sym); + return Proc.End; + } + case SymbolKind::S_BLOCK32: { + BlockSym Block = createRecord<BlockSym>(Sym); + return Block.End; + } + case SymbolKind::S_THUNK32: { + Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym); + return Thunk.End; + } + case SymbolKind::S_INLINESITE: { + InlineSiteSym Site = createRecord<InlineSiteSym>(Sym); + return Site.End; + } + default: + assert(false && "Unknown record type"); + return 0; + } +} + +uint32_t +llvm::codeview::getScopeParentOffset(const llvm::codeview::CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + switch (Sym.kind()) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: { + ProcSym Proc = createRecord<ProcSym>(Sym); + return Proc.Parent; + } + case SymbolKind::S_BLOCK32: { + BlockSym Block = createRecord<BlockSym>(Sym); + return Block.Parent; + } + case SymbolKind::S_THUNK32: { + Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym); + return Thunk.Parent; + } + case SymbolKind::S_INLINESITE: { + InlineSiteSym Site = createRecord<InlineSiteSym>(Sym); + return Site.Parent; + } + default: + assert(false && "Unknown record type"); + return 0; + } +} + +CVSymbolArray +llvm::codeview::limitSymbolArrayToScope(const CVSymbolArray &Symbols, + uint32_t ScopeBegin) { + CVSymbol Opener = *Symbols.at(ScopeBegin); + assert(symbolOpensScope(Opener.kind())); + uint32_t EndOffset = getScopeEndOffset(Opener); + CVSymbol Closer = *Symbols.at(EndOffset); + EndOffset += Closer.RecordData.size(); + return Symbols.substream(ScopeBegin, EndOffset); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp index 3b627930e2..a2d37c26d4 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp @@ -1,558 +1,558 @@ -//===- SymbolRecordMapping.cpp -----------------------------------*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#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.padToAlignment(alignOf(Container))); - 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.mapObject(DefRangeFramePointerRel.Hdr.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.mapEnum(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.mapEnum(Public.Flags)); - 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.mapEnum(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(); -} - -Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, - UsingNamespaceSym &UN) { - - error(IO.mapStringZ(UN.Name)); - - return Error::success(); -} - -Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, - AnnotationSym &Annot) { - - error(IO.mapInteger(Annot.CodeOffset)); - error(IO.mapInteger(Annot.Segment)); - error(IO.mapVectorN<uint16_t>( - Annot.Strings, - [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); })); - - return Error::success(); -} - -RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg, - CPUType CPU) { - assert(unsigned(EncodedReg) < 4); - switch (CPU) { - // FIXME: Add ARM and AArch64 variants here. - default: - break; - case CPUType::Intel8080: - case CPUType::Intel8086: - case CPUType::Intel80286: - case CPUType::Intel80386: - case CPUType::Intel80486: - case CPUType::Pentium: - case CPUType::PentiumPro: - case CPUType::Pentium3: - switch (EncodedReg) { - case EncodedFramePtrReg::None: return RegisterId::NONE; - case EncodedFramePtrReg::StackPtr: return RegisterId::VFRAME; - case EncodedFramePtrReg::FramePtr: return RegisterId::EBP; - case EncodedFramePtrReg::BasePtr: return RegisterId::EBX; - } - llvm_unreachable("bad encoding"); - case CPUType::X64: - switch (EncodedReg) { - case EncodedFramePtrReg::None: return RegisterId::NONE; - case EncodedFramePtrReg::StackPtr: return RegisterId::RSP; - case EncodedFramePtrReg::FramePtr: return RegisterId::RBP; - case EncodedFramePtrReg::BasePtr: return RegisterId::R13; - } - llvm_unreachable("bad encoding"); - } - return RegisterId::NONE; -} - -EncodedFramePtrReg codeview::encodeFramePtrReg(RegisterId Reg, CPUType CPU) { - switch (CPU) { - // FIXME: Add ARM and AArch64 variants here. - default: - break; - case CPUType::Intel8080: - case CPUType::Intel8086: - case CPUType::Intel80286: - case CPUType::Intel80386: - case CPUType::Intel80486: - case CPUType::Pentium: - case CPUType::PentiumPro: - case CPUType::Pentium3: - switch (Reg) { - case RegisterId::VFRAME: - return EncodedFramePtrReg::StackPtr; - case RegisterId::EBP: - return EncodedFramePtrReg::FramePtr; - case RegisterId::EBX: - return EncodedFramePtrReg::BasePtr; - default: - break; - } - break; - case CPUType::X64: - switch (Reg) { - case RegisterId::RSP: - return EncodedFramePtrReg::StackPtr; - case RegisterId::RBP: - return EncodedFramePtrReg::FramePtr; - case RegisterId::R13: - return EncodedFramePtrReg::BasePtr; - default: - break; - } - break; - } - return EncodedFramePtrReg::None; -} +//===- SymbolRecordMapping.cpp -----------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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.padToAlignment(alignOf(Container))); + 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.mapObject(DefRangeFramePointerRel.Hdr.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.mapEnum(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.mapEnum(Public.Flags)); + 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.mapEnum(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(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + UsingNamespaceSym &UN) { + + error(IO.mapStringZ(UN.Name)); + + return Error::success(); +} + +Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, + AnnotationSym &Annot) { + + error(IO.mapInteger(Annot.CodeOffset)); + error(IO.mapInteger(Annot.Segment)); + error(IO.mapVectorN<uint16_t>( + Annot.Strings, + [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); })); + + return Error::success(); +} + +RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg, + CPUType CPU) { + assert(unsigned(EncodedReg) < 4); + switch (CPU) { + // FIXME: Add ARM and AArch64 variants here. + default: + break; + case CPUType::Intel8080: + case CPUType::Intel8086: + case CPUType::Intel80286: + case CPUType::Intel80386: + case CPUType::Intel80486: + case CPUType::Pentium: + case CPUType::PentiumPro: + case CPUType::Pentium3: + switch (EncodedReg) { + case EncodedFramePtrReg::None: return RegisterId::NONE; + case EncodedFramePtrReg::StackPtr: return RegisterId::VFRAME; + case EncodedFramePtrReg::FramePtr: return RegisterId::EBP; + case EncodedFramePtrReg::BasePtr: return RegisterId::EBX; + } + llvm_unreachable("bad encoding"); + case CPUType::X64: + switch (EncodedReg) { + case EncodedFramePtrReg::None: return RegisterId::NONE; + case EncodedFramePtrReg::StackPtr: return RegisterId::RSP; + case EncodedFramePtrReg::FramePtr: return RegisterId::RBP; + case EncodedFramePtrReg::BasePtr: return RegisterId::R13; + } + llvm_unreachable("bad encoding"); + } + return RegisterId::NONE; +} + +EncodedFramePtrReg codeview::encodeFramePtrReg(RegisterId Reg, CPUType CPU) { + switch (CPU) { + // FIXME: Add ARM and AArch64 variants here. + default: + break; + case CPUType::Intel8080: + case CPUType::Intel8086: + case CPUType::Intel80286: + case CPUType::Intel80386: + case CPUType::Intel80486: + case CPUType::Pentium: + case CPUType::PentiumPro: + case CPUType::Pentium3: + switch (Reg) { + case RegisterId::VFRAME: + return EncodedFramePtrReg::StackPtr; + case RegisterId::EBP: + return EncodedFramePtrReg::FramePtr; + case RegisterId::EBX: + return EncodedFramePtrReg::BasePtr; + default: + break; + } + break; + case CPUType::X64: + switch (Reg) { + case RegisterId::RSP: + return EncodedFramePtrReg::StackPtr; + case RegisterId::RBP: + return EncodedFramePtrReg::FramePtr; + case RegisterId::R13: + return EncodedFramePtrReg::BasePtr; + default: + break; + } + break; + } + return EncodedFramePtrReg::None; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolSerializer.cpp index de9bb42b17..170897257c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolSerializer.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/SymbolSerializer.cpp @@ -1,59 +1,59 @@ -//===- SymbolSerializer.cpp -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <cassert> -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::codeview; - -SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator, - CodeViewContainer Container) - : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream), - Mapping(Writer, Container) {} - -Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) { - assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!"); - - Writer.setOffset(0); - - if (auto EC = writeRecordPrefix(Record.kind())) - return EC; - - CurrentSymbol = Record.kind(); - if (auto EC = Mapping.visitSymbolBegin(Record)) - return EC; - - return Error::success(); -} - -Error SymbolSerializer::visitSymbolEnd(CVSymbol &Record) { - assert(CurrentSymbol.hasValue() && "Not in a symbol mapping!"); - - if (auto EC = Mapping.visitSymbolEnd(Record)) - return EC; - - uint32_t RecordEnd = Writer.getOffset(); - uint16_t Length = RecordEnd - 2; - Writer.setOffset(0); - if (auto EC = Writer.writeInteger(Length)) - return EC; - - uint8_t *StableStorage = Storage.Allocate<uint8_t>(RecordEnd); - ::memcpy(StableStorage, &RecordBuffer[0], RecordEnd); - Record.RecordData = ArrayRef<uint8_t>(StableStorage, RecordEnd); - CurrentSymbol.reset(); - - return Error::success(); -} +//===- SymbolSerializer.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::codeview; + +SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator, + CodeViewContainer Container) + : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream), + Mapping(Writer, Container) {} + +Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) { + assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!"); + + Writer.setOffset(0); + + if (auto EC = writeRecordPrefix(Record.kind())) + return EC; + + CurrentSymbol = Record.kind(); + if (auto EC = Mapping.visitSymbolBegin(Record)) + return EC; + + return Error::success(); +} + +Error SymbolSerializer::visitSymbolEnd(CVSymbol &Record) { + assert(CurrentSymbol.hasValue() && "Not in a symbol mapping!"); + + if (auto EC = Mapping.visitSymbolEnd(Record)) + return EC; + + uint32_t RecordEnd = Writer.getOffset(); + uint16_t Length = RecordEnd - 2; + Writer.setOffset(0); + if (auto EC = Writer.writeInteger(Length)) + return EC; + + uint8_t *StableStorage = Storage.Allocate<uint8_t>(RecordEnd); + ::memcpy(StableStorage, &RecordBuffer[0], RecordEnd); + Record.RecordData = ArrayRef<uint8_t>(StableStorage, RecordEnd); + CurrentSymbol.reset(); + + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index d5fea5ee5e..5886d33a4a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -1,570 +1,570 @@ -//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" - -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/Formatters.h" -#include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace llvm; -using namespace llvm::codeview; - -static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { -#define CV_TYPE(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -}; - -#define ENUM_ENTRY(enum_class, enum) \ - { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } - -static const EnumEntry<uint16_t> ClassOptionNames[] = { - ENUM_ENTRY(ClassOptions, Packed), - ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor), - ENUM_ENTRY(ClassOptions, HasOverloadedOperator), - ENUM_ENTRY(ClassOptions, Nested), - ENUM_ENTRY(ClassOptions, ContainsNestedClass), - ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator), - ENUM_ENTRY(ClassOptions, HasConversionOperator), - ENUM_ENTRY(ClassOptions, ForwardReference), - ENUM_ENTRY(ClassOptions, Scoped), - ENUM_ENTRY(ClassOptions, HasUniqueName), - ENUM_ENTRY(ClassOptions, Sealed), - ENUM_ENTRY(ClassOptions, Intrinsic), -}; - -static const EnumEntry<uint8_t> MemberAccessNames[] = { - ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private), - ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public), -}; - -static const EnumEntry<uint16_t> MethodOptionNames[] = { - ENUM_ENTRY(MethodOptions, Pseudo), - ENUM_ENTRY(MethodOptions, NoInherit), - ENUM_ENTRY(MethodOptions, NoConstruct), - ENUM_ENTRY(MethodOptions, CompilerGenerated), - ENUM_ENTRY(MethodOptions, Sealed), -}; - -static const EnumEntry<uint16_t> MemberKindNames[] = { - ENUM_ENTRY(MethodKind, Vanilla), - ENUM_ENTRY(MethodKind, Virtual), - ENUM_ENTRY(MethodKind, Static), - ENUM_ENTRY(MethodKind, Friend), - ENUM_ENTRY(MethodKind, IntroducingVirtual), - ENUM_ENTRY(MethodKind, PureVirtual), - ENUM_ENTRY(MethodKind, PureIntroducingVirtual), -}; - -static const EnumEntry<uint8_t> PtrKindNames[] = { - ENUM_ENTRY(PointerKind, Near16), - ENUM_ENTRY(PointerKind, Far16), - ENUM_ENTRY(PointerKind, Huge16), - ENUM_ENTRY(PointerKind, BasedOnSegment), - ENUM_ENTRY(PointerKind, BasedOnValue), - ENUM_ENTRY(PointerKind, BasedOnSegmentValue), - ENUM_ENTRY(PointerKind, BasedOnAddress), - ENUM_ENTRY(PointerKind, BasedOnSegmentAddress), - ENUM_ENTRY(PointerKind, BasedOnType), - ENUM_ENTRY(PointerKind, BasedOnSelf), - ENUM_ENTRY(PointerKind, Near32), - ENUM_ENTRY(PointerKind, Far32), - ENUM_ENTRY(PointerKind, Near64), -}; - -static const EnumEntry<uint8_t> PtrModeNames[] = { - ENUM_ENTRY(PointerMode, Pointer), - ENUM_ENTRY(PointerMode, LValueReference), - ENUM_ENTRY(PointerMode, PointerToDataMember), - ENUM_ENTRY(PointerMode, PointerToMemberFunction), - ENUM_ENTRY(PointerMode, RValueReference), -}; - -static const EnumEntry<uint16_t> PtrMemberRepNames[] = { - ENUM_ENTRY(PointerToMemberRepresentation, Unknown), - ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData), - ENUM_ENTRY(PointerToMemberRepresentation, GeneralData), - ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction), - ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction), -}; - -static const EnumEntry<uint16_t> TypeModifierNames[] = { - ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile), - ENUM_ENTRY(ModifierOptions, Unaligned), -}; - -static const EnumEntry<uint8_t> CallingConventions[] = { - ENUM_ENTRY(CallingConvention, NearC), - ENUM_ENTRY(CallingConvention, FarC), - ENUM_ENTRY(CallingConvention, NearPascal), - ENUM_ENTRY(CallingConvention, FarPascal), - ENUM_ENTRY(CallingConvention, NearFast), - ENUM_ENTRY(CallingConvention, FarFast), - ENUM_ENTRY(CallingConvention, NearStdCall), - ENUM_ENTRY(CallingConvention, FarStdCall), - ENUM_ENTRY(CallingConvention, NearSysCall), - ENUM_ENTRY(CallingConvention, FarSysCall), - ENUM_ENTRY(CallingConvention, ThisCall), - ENUM_ENTRY(CallingConvention, MipsCall), - ENUM_ENTRY(CallingConvention, Generic), - ENUM_ENTRY(CallingConvention, AlphaCall), - ENUM_ENTRY(CallingConvention, PpcCall), - ENUM_ENTRY(CallingConvention, SHCall), - ENUM_ENTRY(CallingConvention, ArmCall), - ENUM_ENTRY(CallingConvention, AM33Call), - ENUM_ENTRY(CallingConvention, TriCall), - ENUM_ENTRY(CallingConvention, SH5Call), - ENUM_ENTRY(CallingConvention, M32RCall), - ENUM_ENTRY(CallingConvention, ClrCall), - ENUM_ENTRY(CallingConvention, Inline), - ENUM_ENTRY(CallingConvention, NearVector), -}; - -static const EnumEntry<uint8_t> FunctionOptionEnum[] = { - ENUM_ENTRY(FunctionOptions, CxxReturnUdt), - ENUM_ENTRY(FunctionOptions, Constructor), - ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases), -}; - -static const EnumEntry<uint16_t> LabelTypeEnum[] = { - ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far), -}; - -#undef ENUM_ENTRY - -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define TYPE_RECORD(ename, value, name) \ - case ename: \ - return #name; -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - default: - break; - } - return "UnknownLeaf"; -} - -void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { - codeview::printTypeIndex(*W, FieldName, TI, TpiTypes); -} - -void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const { - codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes()); -} - -Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { - return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size())); -} - -Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { - W->startLine() << getLeafTypeName(Record.kind()); - W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")"; - W->getOStream() << " {\n"; - W->indent(); - W->printEnum("TypeLeafKind", unsigned(Record.kind()), - makeArrayRef(LeafTypeNames)); - return Error::success(); -} - -Error TypeDumpVisitor::visitTypeEnd(CVType &Record) { - if (PrintRecordBytes) - W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); - - 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)); - - W->unindent(); - W->startLine() << "}\n"; - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - FieldListRecord &FieldList) { - if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this)) - return EC; - - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { - printItemIndex("Id", String.getId()); - W->printString("StringData", String.getString()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { - auto Indices = Args.getIndices(); - uint32_t Size = Indices.size(); - W->printNumber("NumArgs", Size); - ListScope Arguments(*W, "Arguments"); - for (uint32_t I = 0; I < Size; ++I) { - printTypeIndex("ArgType", Indices[I]); - } - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) { - auto Indices = Strs.getIndices(); - uint32_t Size = Indices.size(); - W->printNumber("NumStrings", Size); - ListScope Arguments(*W, "Strings"); - for (uint32_t I = 0; I < Size; ++I) { - printItemIndex("String", Indices[I]); - } - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { - uint16_t Props = static_cast<uint16_t>(Class.getOptions()); - W->printNumber("MemberCount", Class.getMemberCount()); - W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); - printTypeIndex("FieldList", Class.getFieldList()); - printTypeIndex("DerivedFrom", Class.getDerivationList()); - printTypeIndex("VShape", Class.getVTableShape()); - W->printNumber("SizeOf", Class.getSize()); - W->printString("Name", Class.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Class.getUniqueName()); - return Error::success(); -} - -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)); - printTypeIndex("FieldList", Union.getFieldList()); - W->printNumber("SizeOf", Union.getSize()); - W->printString("Name", Union.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Union.getUniqueName()); - return Error::success(); -} - -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()), - makeArrayRef(ClassOptionNames)); - printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); - printTypeIndex("FieldListType", Enum.getFieldList()); - W->printString("Name", Enum.getName()); - if (Props & uint16_t(ClassOptions::HasUniqueName)) - W->printString("LinkageName", Enum.getUniqueName()); - return Error::success(); -} - -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()); - return Error::success(); -} - -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); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { - printTypeIndex("ClassType", Id.getClassType()); - printTypeIndex("FunctionType", Id.getFunctionType()); - W->printString("Name", Id.getName()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { - printTypeIndex("ReturnType", Proc.getReturnType()); - W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), - makeArrayRef(CallingConventions)); - W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()), - makeArrayRef(FunctionOptionEnum)); - W->printNumber("NumParameters", Proc.getParameterCount()); - printTypeIndex("ArgListType", Proc.getArgumentList()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { - printTypeIndex("ReturnType", MF.getReturnType()); - printTypeIndex("ClassType", MF.getClassType()); - printTypeIndex("ThisType", MF.getThisType()); - W->printEnum("CallingConvention", uint8_t(MF.getCallConv()), - makeArrayRef(CallingConventions)); - W->printFlags("FunctionOptions", uint8_t(MF.getOptions()), - makeArrayRef(FunctionOptionEnum)); - W->printNumber("NumParameters", MF.getParameterCount()); - printTypeIndex("ArgListType", MF.getArgumentList()); - W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - MethodOverloadListRecord &MethodList) { - for (auto &M : MethodList.getMethods()) { - ListScope S(*W, "Method"); - printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); - printTypeIndex("Type", M.getType()); - if (M.isIntroducingVirtual()) - W->printHex("VFTableOffset", M.getVFTableOffset()); - } - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { - printItemIndex("ParentScope", Func.getParentScope()); - printTypeIndex("FunctionType", Func.getFunctionType()); - W->printString("Name", Func.getName()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { - W->printString("Guid", formatv("{0}", TS.getGuid()).str()); - W->printNumber("Age", TS.getAge()); - W->printString("Name", TS.getName()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { - printTypeIndex("PointeeType", Ptr.getReferentType()); - W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), - makeArrayRef(PtrKindNames)); - W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); - - W->printNumber("IsFlat", Ptr.isFlat()); - W->printNumber("IsConst", Ptr.isConst()); - W->printNumber("IsVolatile", Ptr.isVolatile()); - W->printNumber("IsUnaligned", Ptr.isUnaligned()); - W->printNumber("IsRestrict", Ptr.isRestrict()); - W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr()); - W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr()); - W->printNumber("SizeOf", Ptr.getSize()); - - if (Ptr.isPointerToMember()) { - const MemberPointerInfo &MI = Ptr.getMemberInfo(); - - printTypeIndex("ClassType", MI.getContainingType()); - W->printEnum("Representation", uint16_t(MI.getRepresentation()), - makeArrayRef(PtrMemberRepNames)); - } - - return Error::success(); -} - -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)); - - return Error::success(); -} - -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 TypeDumpVisitor::visitKnownRecord(CVType &CVR, - VFTableShapeRecord &Shape) { - W->printNumber("VFEntryCount", Shape.getEntryCount()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - UdtSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printItemIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - UdtModSourceLineRecord &Line) { - printTypeIndex("UDT", Line.getUDT()); - printItemIndex("SourceFile", Line.getSourceFile()); - W->printNumber("LineNumber", Line.getLineNumber()); - W->printNumber("Module", Line.getModule()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { - W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size())); - - ListScope Arguments(*W, "Arguments"); - for (auto Arg : Args.getArgs()) { - printItemIndex("ArgType", Arg); - } - return Error::success(); -} - -void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) { - return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), - Attrs.getFlags()); -} - -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. - if (Kind != MethodKind::Vanilla) - W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); - if (Options != MethodOptions::None) { - W->printFlags("MethodOptions", unsigned(Options), - makeArrayRef(MethodOptionNames)); - } -} - -Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) { - W->printHex("UnknownMember", unsigned(Record.Kind)); - return Error::success(); -} - -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 TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Nested) { - printTypeIndex("Type", Nested.getNestedType()); - W->printString("Name", Nested.getName()); - return Error::success(); -} - -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()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - OverloadedMethodRecord &Method) { - W->printHex("MethodCount", Method.getNumOverloads()); - printTypeIndex("MethodListIndex", Method.getMethodList()); - W->printString("Name", Method.getName()); - return Error::success(); -} - -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()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - StaticDataMemberRecord &Field) { - printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("Type", Field.getType()); - W->printString("Name", Field.getName()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - VFPtrRecord &VFTable) { - printTypeIndex("Type", VFTable.getType()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - EnumeratorRecord &Enum) { - printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - W->printNumber("EnumValue", Enum.getValue()); - W->printString("Name", Enum.getName()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - BaseClassRecord &Base) { - printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("BaseType", Base.getBaseType()); - W->printHex("BaseOffset", Base.getBaseOffset()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - VirtualBaseClassRecord &Base) { - printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, - MethodOptions::None); - printTypeIndex("BaseType", Base.getBaseType()); - printTypeIndex("VBPtrType", Base.getVBPtrType()); - W->printHex("VBPtrOffset", Base.getVBPtrOffset()); - W->printHex("VBTableIndex", Base.getVTableIndex()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, - ListContinuationRecord &Cont) { - printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) { - W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum)); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - PrecompRecord &Precomp) { - W->printHex("StartIndex", Precomp.getStartTypeIndex()); - W->printHex("Count", Precomp.getTypesCount()); - W->printHex("Signature", Precomp.getSignature()); - W->printString("PrecompFile", Precomp.getPrecompFilePath()); - return Error::success(); -} - -Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, - EndPrecompRecord &EndPrecomp) { - W->printHex("Signature", EndPrecomp.getSignature()); - return Error::success(); -} +//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; + +static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { +#define CV_TYPE(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; + +#define ENUM_ENTRY(enum_class, enum) \ + { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } + +static const EnumEntry<uint16_t> ClassOptionNames[] = { + ENUM_ENTRY(ClassOptions, Packed), + ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor), + ENUM_ENTRY(ClassOptions, HasOverloadedOperator), + ENUM_ENTRY(ClassOptions, Nested), + ENUM_ENTRY(ClassOptions, ContainsNestedClass), + ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator), + ENUM_ENTRY(ClassOptions, HasConversionOperator), + ENUM_ENTRY(ClassOptions, ForwardReference), + ENUM_ENTRY(ClassOptions, Scoped), + ENUM_ENTRY(ClassOptions, HasUniqueName), + ENUM_ENTRY(ClassOptions, Sealed), + ENUM_ENTRY(ClassOptions, Intrinsic), +}; + +static const EnumEntry<uint8_t> MemberAccessNames[] = { + ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private), + ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public), +}; + +static const EnumEntry<uint16_t> MethodOptionNames[] = { + ENUM_ENTRY(MethodOptions, Pseudo), + ENUM_ENTRY(MethodOptions, NoInherit), + ENUM_ENTRY(MethodOptions, NoConstruct), + ENUM_ENTRY(MethodOptions, CompilerGenerated), + ENUM_ENTRY(MethodOptions, Sealed), +}; + +static const EnumEntry<uint16_t> MemberKindNames[] = { + ENUM_ENTRY(MethodKind, Vanilla), + ENUM_ENTRY(MethodKind, Virtual), + ENUM_ENTRY(MethodKind, Static), + ENUM_ENTRY(MethodKind, Friend), + ENUM_ENTRY(MethodKind, IntroducingVirtual), + ENUM_ENTRY(MethodKind, PureVirtual), + ENUM_ENTRY(MethodKind, PureIntroducingVirtual), +}; + +static const EnumEntry<uint8_t> PtrKindNames[] = { + ENUM_ENTRY(PointerKind, Near16), + ENUM_ENTRY(PointerKind, Far16), + ENUM_ENTRY(PointerKind, Huge16), + ENUM_ENTRY(PointerKind, BasedOnSegment), + ENUM_ENTRY(PointerKind, BasedOnValue), + ENUM_ENTRY(PointerKind, BasedOnSegmentValue), + ENUM_ENTRY(PointerKind, BasedOnAddress), + ENUM_ENTRY(PointerKind, BasedOnSegmentAddress), + ENUM_ENTRY(PointerKind, BasedOnType), + ENUM_ENTRY(PointerKind, BasedOnSelf), + ENUM_ENTRY(PointerKind, Near32), + ENUM_ENTRY(PointerKind, Far32), + ENUM_ENTRY(PointerKind, Near64), +}; + +static const EnumEntry<uint8_t> PtrModeNames[] = { + ENUM_ENTRY(PointerMode, Pointer), + ENUM_ENTRY(PointerMode, LValueReference), + ENUM_ENTRY(PointerMode, PointerToDataMember), + ENUM_ENTRY(PointerMode, PointerToMemberFunction), + ENUM_ENTRY(PointerMode, RValueReference), +}; + +static const EnumEntry<uint16_t> PtrMemberRepNames[] = { + ENUM_ENTRY(PointerToMemberRepresentation, Unknown), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralData), + ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction), + ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction), +}; + +static const EnumEntry<uint16_t> TypeModifierNames[] = { + ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile), + ENUM_ENTRY(ModifierOptions, Unaligned), +}; + +static const EnumEntry<uint8_t> CallingConventions[] = { + ENUM_ENTRY(CallingConvention, NearC), + ENUM_ENTRY(CallingConvention, FarC), + ENUM_ENTRY(CallingConvention, NearPascal), + ENUM_ENTRY(CallingConvention, FarPascal), + ENUM_ENTRY(CallingConvention, NearFast), + ENUM_ENTRY(CallingConvention, FarFast), + ENUM_ENTRY(CallingConvention, NearStdCall), + ENUM_ENTRY(CallingConvention, FarStdCall), + ENUM_ENTRY(CallingConvention, NearSysCall), + ENUM_ENTRY(CallingConvention, FarSysCall), + ENUM_ENTRY(CallingConvention, ThisCall), + ENUM_ENTRY(CallingConvention, MipsCall), + ENUM_ENTRY(CallingConvention, Generic), + ENUM_ENTRY(CallingConvention, AlphaCall), + ENUM_ENTRY(CallingConvention, PpcCall), + ENUM_ENTRY(CallingConvention, SHCall), + ENUM_ENTRY(CallingConvention, ArmCall), + ENUM_ENTRY(CallingConvention, AM33Call), + ENUM_ENTRY(CallingConvention, TriCall), + ENUM_ENTRY(CallingConvention, SH5Call), + ENUM_ENTRY(CallingConvention, M32RCall), + ENUM_ENTRY(CallingConvention, ClrCall), + ENUM_ENTRY(CallingConvention, Inline), + ENUM_ENTRY(CallingConvention, NearVector), +}; + +static const EnumEntry<uint8_t> FunctionOptionEnum[] = { + ENUM_ENTRY(FunctionOptions, CxxReturnUdt), + ENUM_ENTRY(FunctionOptions, Constructor), + ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases), +}; + +static const EnumEntry<uint16_t> LabelTypeEnum[] = { + ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far), +}; + +#undef ENUM_ENTRY + +static StringRef getLeafTypeName(TypeLeafKind LT) { + switch (LT) { +#define TYPE_RECORD(ename, value, name) \ + case ename: \ + return #name; +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + default: + break; + } + return "UnknownLeaf"; +} + +void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { + codeview::printTypeIndex(*W, FieldName, TI, TpiTypes); +} + +void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const { + codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes()); +} + +Error TypeDumpVisitor::visitTypeBegin(CVType &Record) { + return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size())); +} + +Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { + W->startLine() << getLeafTypeName(Record.kind()); + W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")"; + W->getOStream() << " {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.kind()), + makeArrayRef(LeafTypeNames)); + return Error::success(); +} + +Error TypeDumpVisitor::visitTypeEnd(CVType &Record) { + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content())); + + 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)); + + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this)) + return EC; + + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) { + printItemIndex("Id", String.getId()); + W->printString("StringData", String.getString()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + W->printNumber("NumArgs", Size); + ListScope Arguments(*W, "Arguments"); + for (uint32_t I = 0; I < Size; ++I) { + printTypeIndex("ArgType", Indices[I]); + } + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) { + auto Indices = Strs.getIndices(); + uint32_t Size = Indices.size(); + W->printNumber("NumStrings", Size); + ListScope Arguments(*W, "Strings"); + for (uint32_t I = 0; I < Size; ++I) { + printItemIndex("String", Indices[I]); + } + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + uint16_t Props = static_cast<uint16_t>(Class.getOptions()); + W->printNumber("MemberCount", Class.getMemberCount()); + W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + printTypeIndex("FieldList", Class.getFieldList()); + printTypeIndex("DerivedFrom", Class.getDerivationList()); + printTypeIndex("VShape", Class.getVTableShape()); + W->printNumber("SizeOf", Class.getSize()); + W->printString("Name", Class.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Class.getUniqueName()); + return Error::success(); +} + +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)); + printTypeIndex("FieldList", Union.getFieldList()); + W->printNumber("SizeOf", Union.getSize()); + W->printString("Name", Union.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Union.getUniqueName()); + return Error::success(); +} + +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()), + makeArrayRef(ClassOptionNames)); + printTypeIndex("UnderlyingType", Enum.getUnderlyingType()); + printTypeIndex("FieldListType", Enum.getFieldList()); + W->printString("Name", Enum.getName()); + if (Props & uint16_t(ClassOptions::HasUniqueName)) + W->printString("LinkageName", Enum.getUniqueName()); + return Error::success(); +} + +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()); + return Error::success(); +} + +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); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + printTypeIndex("ClassType", Id.getClassType()); + printTypeIndex("FunctionType", Id.getFunctionType()); + W->printString("Name", Id.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + printTypeIndex("ReturnType", Proc.getReturnType()); + W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()), + makeArrayRef(CallingConventions)); + W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()), + makeArrayRef(FunctionOptionEnum)); + W->printNumber("NumParameters", Proc.getParameterCount()); + printTypeIndex("ArgListType", Proc.getArgumentList()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { + printTypeIndex("ReturnType", MF.getReturnType()); + printTypeIndex("ClassType", MF.getClassType()); + printTypeIndex("ThisType", MF.getThisType()); + W->printEnum("CallingConvention", uint8_t(MF.getCallConv()), + makeArrayRef(CallingConventions)); + W->printFlags("FunctionOptions", uint8_t(MF.getOptions()), + makeArrayRef(FunctionOptionEnum)); + W->printNumber("NumParameters", MF.getParameterCount()); + printTypeIndex("ArgListType", MF.getArgumentList()); + W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &MethodList) { + for (auto &M : MethodList.getMethods()) { + ListScope S(*W, "Method"); + printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); + printTypeIndex("Type", M.getType()); + if (M.isIntroducingVirtual()) + W->printHex("VFTableOffset", M.getVFTableOffset()); + } + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + printItemIndex("ParentScope", Func.getParentScope()); + printTypeIndex("FunctionType", Func.getFunctionType()); + W->printString("Name", Func.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + W->printString("Guid", formatv("{0}", TS.getGuid()).str()); + W->printNumber("Age", TS.getAge()); + W->printString("Name", TS.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + printTypeIndex("PointeeType", Ptr.getReferentType()); + W->printEnum("PtrType", unsigned(Ptr.getPointerKind()), + makeArrayRef(PtrKindNames)); + W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); + + W->printNumber("IsFlat", Ptr.isFlat()); + W->printNumber("IsConst", Ptr.isConst()); + W->printNumber("IsVolatile", Ptr.isVolatile()); + W->printNumber("IsUnaligned", Ptr.isUnaligned()); + W->printNumber("IsRestrict", Ptr.isRestrict()); + W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr()); + W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr()); + W->printNumber("SizeOf", Ptr.getSize()); + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + printTypeIndex("ClassType", MI.getContainingType()); + W->printEnum("Representation", uint16_t(MI.getRepresentation()), + makeArrayRef(PtrMemberRepNames)); + } + + return Error::success(); +} + +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)); + + return Error::success(); +} + +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 TypeDumpVisitor::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + W->printNumber("VFEntryCount", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printItemIndex("SourceFile", Line.getSourceFile()); + W->printNumber("LineNumber", Line.getLineNumber()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Line) { + printTypeIndex("UDT", Line.getUDT()); + printItemIndex("SourceFile", Line.getSourceFile()); + W->printNumber("LineNumber", Line.getLineNumber()); + W->printNumber("Module", Line.getModule()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) { + W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size())); + + ListScope Arguments(*W, "Arguments"); + for (auto Arg : Args.getArgs()) { + printItemIndex("ArgType", Arg); + } + return Error::success(); +} + +void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) { + return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), + Attrs.getFlags()); +} + +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. + if (Kind != MethodKind::Vanilla) + W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); + if (Options != MethodOptions::None) { + W->printFlags("MethodOptions", unsigned(Options), + makeArrayRef(MethodOptionNames)); + } +} + +Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) { + W->printHex("UnknownMember", unsigned(Record.Kind)); + return Error::success(); +} + +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 TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Nested) { + printTypeIndex("Type", Nested.getNestedType()); + W->printString("Name", Nested.getName()); + return Error::success(); +} + +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()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Method) { + W->printHex("MethodCount", Method.getNumOverloads()); + printTypeIndex("MethodListIndex", Method.getMethodList()); + W->printString("Name", Method.getName()); + return Error::success(); +} + +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()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Field) { + printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("Type", Field.getType()); + W->printString("Name", Field.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &VFTable) { + printTypeIndex("Type", VFTable.getType()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Enum) { + printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + W->printNumber("EnumValue", Enum.getValue()); + W->printString("Name", Enum.getName()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Base) { + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + W->printHex("BaseOffset", Base.getBaseOffset()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Base) { + printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, + MethodOptions::None); + printTypeIndex("BaseType", Base.getBaseType()); + printTypeIndex("VBPtrType", Base.getVBPtrType()); + W->printHex("VBPtrOffset", Base.getVBPtrOffset()); + W->printHex("VBTableIndex", Base.getVTableIndex()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Cont) { + printTypeIndex("ContinuationIndex", Cont.getContinuationIndex()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) { + W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum)); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + PrecompRecord &Precomp) { + W->printHex("StartIndex", Precomp.getStartTypeIndex()); + W->printHex("Count", Precomp.getTypesCount()); + W->printHex("Signature", Precomp.getSignature()); + W->printString("PrecompFile", Precomp.getPrecompFilePath()); + return Error::success(); +} + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, + EndPrecompRecord &EndPrecomp) { + W->printHex("Signature", EndPrecomp.getSignature()); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeHashing.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeHashing.cpp index 2dbc11a84f..797d80a450 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeHashing.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeHashing.cpp @@ -1,80 +1,80 @@ -//===- TypeHashing.cpp -------------------------------------------*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeHashing.h" - -#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" -#include "llvm/Support/SHA1.h" - -using namespace llvm; -using namespace llvm::codeview; - -LocallyHashedType DenseMapInfo<LocallyHashedType>::Empty{0, {}}; -LocallyHashedType DenseMapInfo<LocallyHashedType>::Tombstone{hash_code(-1), {}}; - -static std::array<uint8_t, 8> EmptyHash = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -static std::array<uint8_t, 8> TombstoneHash = { - {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - -GloballyHashedType DenseMapInfo<GloballyHashedType>::Empty{EmptyHash}; -GloballyHashedType DenseMapInfo<GloballyHashedType>::Tombstone{TombstoneHash}; - -LocallyHashedType LocallyHashedType::hashType(ArrayRef<uint8_t> RecordData) { - return {llvm::hash_value(RecordData), RecordData}; -} - -GloballyHashedType -GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData, - ArrayRef<GloballyHashedType> PreviousTypes, - ArrayRef<GloballyHashedType> PreviousIds) { - SmallVector<TiReference, 4> Refs; - discoverTypeIndices(RecordData, Refs); - SHA1 S; - S.init(); - uint32_t Off = 0; - S.update(RecordData.take_front(sizeof(RecordPrefix))); - RecordData = RecordData.drop_front(sizeof(RecordPrefix)); - for (const auto &Ref : Refs) { - // Hash any data that comes before this TiRef. - uint32_t PreLen = Ref.Offset - Off; - ArrayRef<uint8_t> PreData = RecordData.slice(Off, PreLen); - S.update(PreData); - auto Prev = (Ref.Kind == TiRefKind::IndexRef) ? PreviousIds : PreviousTypes; - - auto RefData = RecordData.slice(Ref.Offset, Ref.Count * sizeof(TypeIndex)); - // For each type index referenced, add in the previously computed hash - // value of that type. - ArrayRef<TypeIndex> Indices( - reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count); - for (TypeIndex TI : Indices) { - ArrayRef<uint8_t> BytesToHash; - if (TI.isSimple() || TI.isNoneType()) { - const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI); - BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex)); - } else { - if (TI.toArrayIndex() >= Prev.size() || - Prev[TI.toArrayIndex()].empty()) { - // There are references to yet-unhashed records. Suspend hashing for - // this record until all the other records are processed. - return {}; - } - BytesToHash = Prev[TI.toArrayIndex()].Hash; - } - S.update(BytesToHash); - } - - Off = Ref.Offset + Ref.Count * sizeof(TypeIndex); - } - - // Don't forget to add in any trailing bytes. - auto TrailingBytes = RecordData.drop_front(Off); - S.update(TrailingBytes); - - return {S.final().take_back(8)}; -} +//===- TypeHashing.cpp -------------------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeHashing.h" + +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/Support/SHA1.h" + +using namespace llvm; +using namespace llvm::codeview; + +LocallyHashedType DenseMapInfo<LocallyHashedType>::Empty{0, {}}; +LocallyHashedType DenseMapInfo<LocallyHashedType>::Tombstone{hash_code(-1), {}}; + +static std::array<uint8_t, 8> EmptyHash = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static std::array<uint8_t, 8> TombstoneHash = { + {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +GloballyHashedType DenseMapInfo<GloballyHashedType>::Empty{EmptyHash}; +GloballyHashedType DenseMapInfo<GloballyHashedType>::Tombstone{TombstoneHash}; + +LocallyHashedType LocallyHashedType::hashType(ArrayRef<uint8_t> RecordData) { + return {llvm::hash_value(RecordData), RecordData}; +} + +GloballyHashedType +GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData, + ArrayRef<GloballyHashedType> PreviousTypes, + ArrayRef<GloballyHashedType> PreviousIds) { + SmallVector<TiReference, 4> Refs; + discoverTypeIndices(RecordData, Refs); + SHA1 S; + S.init(); + uint32_t Off = 0; + S.update(RecordData.take_front(sizeof(RecordPrefix))); + RecordData = RecordData.drop_front(sizeof(RecordPrefix)); + for (const auto &Ref : Refs) { + // Hash any data that comes before this TiRef. + uint32_t PreLen = Ref.Offset - Off; + ArrayRef<uint8_t> PreData = RecordData.slice(Off, PreLen); + S.update(PreData); + auto Prev = (Ref.Kind == TiRefKind::IndexRef) ? PreviousIds : PreviousTypes; + + auto RefData = RecordData.slice(Ref.Offset, Ref.Count * sizeof(TypeIndex)); + // For each type index referenced, add in the previously computed hash + // value of that type. + ArrayRef<TypeIndex> Indices( + reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count); + for (TypeIndex TI : Indices) { + ArrayRef<uint8_t> BytesToHash; + if (TI.isSimple() || TI.isNoneType()) { + const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI); + BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex)); + } else { + if (TI.toArrayIndex() >= Prev.size() || + Prev[TI.toArrayIndex()].empty()) { + // There are references to yet-unhashed records. Suspend hashing for + // this record until all the other records are processed. + return {}; + } + BytesToHash = Prev[TI.toArrayIndex()].Hash; + } + S.update(BytesToHash); + } + + Off = Ref.Offset + Ref.Count * sizeof(TypeIndex); + } + + // Don't forget to add in any trailing bytes. + auto TrailingBytes = RecordData.drop_front(Off); + S.update(TrailingBytes); + + return {S.final().take_back(8)}; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndex.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndex.cpp index 604d342448..201197a728 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndex.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndex.cpp @@ -1,106 +1,106 @@ -//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeIndex.h" - -#include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/Support/ScopedPrinter.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}, -}; -} // namespace - -StringRef TypeIndex::simpleTypeName(TypeIndex TI) { - assert(TI.isNoneType() || TI.isSimple()); - - if (TI.isNoneType()) - return "<no type>"; - - if (TI == TypeIndex::NullptrT()) - return "std::nullptr_t"; - - // This is a simple type. - for (const auto &SimpleTypeName : SimpleTypeNames) { - if (SimpleTypeName.Kind == 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>"; -} - -void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, - TypeIndex TI, TypeCollection &Types) { - StringRef TypeName; - if (!TI.isNoneType()) { - if (TI.isSimple()) - TypeName = TypeIndex::simpleTypeName(TI); - else - TypeName = Types.getTypeName(TI); - } - - if (!TypeName.empty()) - Printer.printHex(FieldName, TypeName, TI.getIndex()); - else - Printer.printHex(FieldName, TI.getIndex()); -} +//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/Support/ScopedPrinter.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}, +}; +} // namespace + +StringRef TypeIndex::simpleTypeName(TypeIndex TI) { + assert(TI.isNoneType() || TI.isSimple()); + + if (TI.isNoneType()) + return "<no type>"; + + if (TI == TypeIndex::NullptrT()) + return "std::nullptr_t"; + + // This is a simple type. + for (const auto &SimpleTypeName : SimpleTypeNames) { + if (SimpleTypeName.Kind == 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>"; +} + +void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, + TypeIndex TI, TypeCollection &Types) { + StringRef TypeName; + if (!TI.isNoneType()) { + if (TI.isSimple()) + TypeName = TypeIndex::simpleTypeName(TI); + else + TypeName = Types.getTypeName(TI); + } + + if (!TypeName.empty()) + Printer.printHex(FieldName, TypeName, TI.getIndex()); + else + Printer.printHex(FieldName, TI.getIndex()); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 682747a2b8..bc7759b12e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -1,523 +1,523 @@ -//===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +//===- TypeIndexDiscovery.cpp -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::codeview; - -static inline MethodKind getMethodKind(uint16_t Attrs) { - Attrs &= uint16_t(MethodOptions::MethodKindMask); - Attrs >>= 2; - return MethodKind(Attrs); -} - -static inline bool isIntroVirtual(uint16_t Attrs) { - MethodKind MK = getMethodKind(Attrs); - return MK == MethodKind::IntroducingVirtual || - MK == MethodKind::PureIntroducingVirtual; -} - -static inline PointerMode getPointerMode(uint32_t Attrs) { - return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) & - PointerRecord::PointerModeMask); -} - -static inline bool isMemberPointer(uint32_t Attrs) { - PointerMode Mode = getPointerMode(Attrs); - return Mode == PointerMode::PointerToDataMember || - Mode == PointerMode::PointerToMemberFunction; -} - -static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) { - uint16_t N = support::endian::read16le(Data.data()); - if (N < LF_NUMERIC) - return 2; - - assert(N <= LF_UQUADWORD); - - constexpr uint32_t Sizes[] = { - 1, // LF_CHAR - 2, // LF_SHORT - 2, // LF_USHORT - 4, // LF_LONG - 4, // LF_ULONG - 4, // LF_REAL32 - 8, // LF_REAL64 - 10, // LF_REAL80 - 16, // LF_REAL128 - 8, // LF_QUADWORD - 8, // LF_UQUADWORD - }; - - return 2 + Sizes[N - LF_NUMERIC]; -} - -static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) { - const char *S = reinterpret_cast<const char *>(Data.data()); - return strlen(S) + 1; -} - -static void handleMethodOverloadList(ArrayRef<uint8_t> Content, - SmallVectorImpl<TiReference> &Refs) { - uint32_t Offset = 0; - - while (!Content.empty()) { - // Array of: - // 0: Attrs - // 2: Padding - // 4: TypeIndex - // if (isIntroVirtual()) - // 8: VFTableOffset - - // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an - // intro virtual. - uint32_t Len = 8; - - uint16_t Attrs = support::endian::read16le(Content.data()); - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - - if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) - Len += 4; - Offset += Len; - Content = Content.drop_front(Len); - } -} - -static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - // 8: Encoded Integer - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8 + getEncodedIntegerLength(Data.drop_front(8)); -} - -static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: Encoded Integer - // <next>: Name - uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4)); - return Size + getCStringLength(Data.drop_front(Size)); -} - -static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - // 8: Encoded Integer - // <next>: Name - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8)); - return Size + getCStringLength(Data.drop_front(Size)); -} - -static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - // 8: Name - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8 + getCStringLength(Data.drop_front(8)); -} - -static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Attributes - // 4: Type - // if (isIntroVirtual) - // 8: VFTableOffset - // <next>: Name - uint32_t Size = 8; - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - - uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data()); - if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) - Size += 4; - - return Size + getCStringLength(Data.drop_front(Size)); -} - -static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - // 8: Name - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8 + getCStringLength(Data.drop_front(8)); -} - -static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - // 8: Name - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8 + getCStringLength(Data.drop_front(8)); -} - -static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, - bool IsIndirect, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Attrs - // 4: TypeIndex - // 8: TypeIndex - // 12: Encoded Integer - // <next>: Encoded Integer - uint32_t Size = 12; - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2}); - Size += getEncodedIntegerLength(Data.drop_front(Size)); - Size += getEncodedIntegerLength(Data.drop_front(Size)); - return Size; -} - -static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8; -} - -static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset, - SmallVectorImpl<TiReference> &Refs) { - // 0: Kind - // 2: Padding - // 4: TypeIndex - Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); - return 8; -} - -static void handleFieldList(ArrayRef<uint8_t> Content, - SmallVectorImpl<TiReference> &Refs) { - uint32_t Offset = 0; - uint32_t ThisLen = 0; - while (!Content.empty()) { - TypeLeafKind Kind = - static_cast<TypeLeafKind>(support::endian::read16le(Content.data())); - switch (Kind) { - case LF_BCLASS: - ThisLen = handleBaseClass(Content, Offset, Refs); - break; - case LF_ENUMERATE: - ThisLen = handleEnumerator(Content, Offset, Refs); - break; - case LF_MEMBER: - ThisLen = handleDataMember(Content, Offset, Refs); - break; - case LF_METHOD: - ThisLen = handleOverloadedMethod(Content, Offset, Refs); - break; - case LF_ONEMETHOD: - ThisLen = handleOneMethod(Content, Offset, Refs); - break; - case LF_NESTTYPE: - ThisLen = handleNestedType(Content, Offset, Refs); - break; - case LF_STMEMBER: - ThisLen = handleStaticDataMember(Content, Offset, Refs); - break; - case LF_VBCLASS: - case LF_IVBCLASS: - ThisLen = - handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs); - break; - case LF_VFUNCTAB: - ThisLen = handleVFPtr(Content, Offset, Refs); - break; - case LF_INDEX: - ThisLen = handleListContinuation(Content, Offset, Refs); - break; - default: - return; - } - Content = Content.drop_front(ThisLen); - Offset += ThisLen; - if (!Content.empty()) { - uint8_t Pad = Content.front(); - if (Pad >= LF_PAD0) { - uint32_t Skip = Pad & 0x0F; - Content = Content.drop_front(Skip); - Offset += Skip; - } - } - } -} - -static void handlePointer(ArrayRef<uint8_t> Content, - SmallVectorImpl<TiReference> &Refs) { - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - - uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data()); - if (isMemberPointer(Attrs)) - Refs.push_back({TiRefKind::TypeRef, 8, 1}); -} - -static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind, - SmallVectorImpl<TiReference> &Refs) { - uint32_t Count; - // FIXME: In the future it would be nice if we could avoid hardcoding these - // values. One idea is to define some structures representing these types - // that would allow the use of offsetof(). - switch (Kind) { - case TypeLeafKind::LF_FUNC_ID: - Refs.push_back({TiRefKind::IndexRef, 0, 1}); - Refs.push_back({TiRefKind::TypeRef, 4, 1}); - break; - case TypeLeafKind::LF_MFUNC_ID: - Refs.push_back({TiRefKind::TypeRef, 0, 2}); - break; - case TypeLeafKind::LF_STRING_ID: - Refs.push_back({TiRefKind::IndexRef, 0, 1}); - break; - case TypeLeafKind::LF_SUBSTR_LIST: - Count = support::endian::read32le(Content.data()); - if (Count > 0) - Refs.push_back({TiRefKind::IndexRef, 4, Count}); - break; - case TypeLeafKind::LF_BUILDINFO: - Count = support::endian::read16le(Content.data()); - if (Count > 0) - Refs.push_back({TiRefKind::IndexRef, 2, Count}); - break; - case TypeLeafKind::LF_UDT_SRC_LINE: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - Refs.push_back({TiRefKind::IndexRef, 4, 1}); - break; - case TypeLeafKind::LF_UDT_MOD_SRC_LINE: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - break; - case TypeLeafKind::LF_MODIFIER: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - break; - case TypeLeafKind::LF_PROCEDURE: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - Refs.push_back({TiRefKind::TypeRef, 8, 1}); - break; - case TypeLeafKind::LF_MFUNCTION: - Refs.push_back({TiRefKind::TypeRef, 0, 3}); - Refs.push_back({TiRefKind::TypeRef, 16, 1}); - break; - case TypeLeafKind::LF_ARGLIST: - Count = support::endian::read32le(Content.data()); - if (Count > 0) - Refs.push_back({TiRefKind::TypeRef, 4, Count}); - break; - case TypeLeafKind::LF_ARRAY: - Refs.push_back({TiRefKind::TypeRef, 0, 2}); - break; - case TypeLeafKind::LF_CLASS: - case TypeLeafKind::LF_STRUCTURE: - case TypeLeafKind::LF_INTERFACE: - Refs.push_back({TiRefKind::TypeRef, 4, 3}); - break; - case TypeLeafKind::LF_UNION: - Refs.push_back({TiRefKind::TypeRef, 4, 1}); - break; - case TypeLeafKind::LF_ENUM: - Refs.push_back({TiRefKind::TypeRef, 4, 2}); - break; - case TypeLeafKind::LF_BITFIELD: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); - break; - case TypeLeafKind::LF_VFTABLE: - Refs.push_back({TiRefKind::TypeRef, 0, 2}); - break; - case TypeLeafKind::LF_VTSHAPE: - break; - case TypeLeafKind::LF_METHODLIST: - handleMethodOverloadList(Content, Refs); - break; - case TypeLeafKind::LF_FIELDLIST: - handleFieldList(Content, Refs); - break; - case TypeLeafKind::LF_POINTER: - handlePointer(Content, Refs); - break; - default: - break; - } -} - -static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, - SmallVectorImpl<TiReference> &Refs) { - uint32_t Count; - // FIXME: In the future it would be nice if we could avoid hardcoding these - // values. One idea is to define some structures representing these types - // that would allow the use of offsetof(). - switch (Kind) { - case SymbolKind::S_GPROC32_ID: - case SymbolKind::S_LPROC32_ID: - case SymbolKind::S_LPROC32_DPC: - case SymbolKind::S_LPROC32_DPC_ID: - Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID - break; - case SymbolKind::S_GPROC32: - case SymbolKind::S_LPROC32: - Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type - break; - case SymbolKind::S_UDT: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT - break; - case SymbolKind::S_GDATA32: - case SymbolKind::S_LDATA32: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_BUILDINFO: - Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags - break; - case SymbolKind::S_LTHREAD32: - case SymbolKind::S_GTHREAD32: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_FILESTATIC: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_LOCAL: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_REGISTER: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_CONSTANT: - Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type - break; - case SymbolKind::S_BPREL32: - case SymbolKind::S_REGREL32: - Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type - break; - case SymbolKind::S_CALLSITEINFO: - Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature - break; - case SymbolKind::S_CALLERS: - case SymbolKind::S_CALLEES: - case SymbolKind::S_INLINEES: - // The record is a count followed by an array of type indices. - Count = *reinterpret_cast<const ulittle32_t *>(Content.data()); - Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees - break; - case SymbolKind::S_INLINESITE: - Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee - break; - case SymbolKind::S_HEAPALLOCSITE: - Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated - break; - - // Defranges don't have types, just registers and code offsets. - case SymbolKind::S_DEFRANGE_REGISTER: - case SymbolKind::S_DEFRANGE_REGISTER_REL: - case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL: - case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER: - case SymbolKind::S_DEFRANGE_SUBFIELD: - break; - - // No type references. - case SymbolKind::S_LABEL32: - case SymbolKind::S_OBJNAME: - case SymbolKind::S_COMPILE: - case SymbolKind::S_COMPILE2: - case SymbolKind::S_COMPILE3: - case SymbolKind::S_ENVBLOCK: - case SymbolKind::S_BLOCK32: - case SymbolKind::S_FRAMEPROC: - case SymbolKind::S_THUNK32: - case SymbolKind::S_FRAMECOOKIE: - case SymbolKind::S_UNAMESPACE: - break; - // Scope ending symbols. - case SymbolKind::S_END: - case SymbolKind::S_INLINESITE_END: - case SymbolKind::S_PROC_ID_END: - break; - default: - return false; // Unknown symbol. - } - return true; -} - -void llvm::codeview::discoverTypeIndices(const CVType &Type, - SmallVectorImpl<TiReference> &Refs) { - ::discoverTypeIndices(Type.content(), Type.kind(), Refs); -} - -static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData, - ArrayRef<TiReference> Refs, - SmallVectorImpl<TypeIndex> &Indices) { - Indices.clear(); - - if (Refs.empty()) - return; - - RecordData = RecordData.drop_front(sizeof(RecordPrefix)); - - BinaryStreamReader Reader(RecordData, support::little); - for (const auto &Ref : Refs) { - Reader.setOffset(Ref.Offset); - FixedStreamArray<TypeIndex> Run; - cantFail(Reader.readArray(Run, Ref.Count)); - Indices.append(Run.begin(), Run.end()); - } -} - -void llvm::codeview::discoverTypeIndices(const CVType &Type, - SmallVectorImpl<TypeIndex> &Indices) { - return discoverTypeIndices(Type.RecordData, Indices); -} - -void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, - SmallVectorImpl<TypeIndex> &Indices) { - SmallVector<TiReference, 4> Refs; - discoverTypeIndices(RecordData, Refs); - resolveTypeIndexReferences(RecordData, Refs, Indices); -} - -void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, - SmallVectorImpl<TiReference> &Refs) { - const RecordPrefix *P = - reinterpret_cast<const RecordPrefix *>(RecordData.data()); - TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); - ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); -} - -bool llvm::codeview::discoverTypeIndicesInSymbol( - const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) { - SymbolKind K = Sym.kind(); - return ::discoverTypeIndices(Sym.content(), K, Refs); -} - -bool llvm::codeview::discoverTypeIndicesInSymbol( - ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) { - const RecordPrefix *P = - reinterpret_cast<const RecordPrefix *>(RecordData.data()); - SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind)); - return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, - Refs); -} - -bool llvm::codeview::discoverTypeIndicesInSymbol( - ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) { - SmallVector<TiReference, 2> Refs; - if (!discoverTypeIndicesInSymbol(RecordData, Refs)) - return false; - resolveTypeIndexReferences(RecordData, Refs, Indices); - return true; -} +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::codeview; + +static inline MethodKind getMethodKind(uint16_t Attrs) { + Attrs &= uint16_t(MethodOptions::MethodKindMask); + Attrs >>= 2; + return MethodKind(Attrs); +} + +static inline bool isIntroVirtual(uint16_t Attrs) { + MethodKind MK = getMethodKind(Attrs); + return MK == MethodKind::IntroducingVirtual || + MK == MethodKind::PureIntroducingVirtual; +} + +static inline PointerMode getPointerMode(uint32_t Attrs) { + return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) & + PointerRecord::PointerModeMask); +} + +static inline bool isMemberPointer(uint32_t Attrs) { + PointerMode Mode = getPointerMode(Attrs); + return Mode == PointerMode::PointerToDataMember || + Mode == PointerMode::PointerToMemberFunction; +} + +static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) { + uint16_t N = support::endian::read16le(Data.data()); + if (N < LF_NUMERIC) + return 2; + + assert(N <= LF_UQUADWORD); + + constexpr uint32_t Sizes[] = { + 1, // LF_CHAR + 2, // LF_SHORT + 2, // LF_USHORT + 4, // LF_LONG + 4, // LF_ULONG + 4, // LF_REAL32 + 8, // LF_REAL64 + 10, // LF_REAL80 + 16, // LF_REAL128 + 8, // LF_QUADWORD + 8, // LF_UQUADWORD + }; + + return 2 + Sizes[N - LF_NUMERIC]; +} + +static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) { + const char *S = reinterpret_cast<const char *>(Data.data()); + return strlen(S) + 1; +} + +static void handleMethodOverloadList(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Offset = 0; + + while (!Content.empty()) { + // Array of: + // 0: Attrs + // 2: Padding + // 4: TypeIndex + // if (isIntroVirtual()) + // 8: VFTableOffset + + // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an + // intro virtual. + uint32_t Len = 8; + + uint16_t Attrs = support::endian::read16le(Content.data()); + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + + if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) + Len += 4; + Offset += Len; + Content = Content.drop_front(Len); + } +} + +static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Encoded Integer + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getEncodedIntegerLength(Data.drop_front(8)); +} + +static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: Encoded Integer + // <next>: Name + uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4)); + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Encoded Integer + // <next>: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8)); + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Attributes + // 4: Type + // if (isIntroVirtual) + // 8: VFTableOffset + // <next>: Name + uint32_t Size = 8; + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + + uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data()); + if (LLVM_UNLIKELY(isIntroVirtual(Attrs))) + Size += 4; + + return Size + getCStringLength(Data.drop_front(Size)); +} + +static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + // 8: Name + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8 + getCStringLength(Data.drop_front(8)); +} + +static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset, + bool IsIndirect, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Attrs + // 4: TypeIndex + // 8: TypeIndex + // 12: Encoded Integer + // <next>: Encoded Integer + uint32_t Size = 12; + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2}); + Size += getEncodedIntegerLength(Data.drop_front(Size)); + Size += getEncodedIntegerLength(Data.drop_front(Size)); + return Size; +} + +static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8; +} + +static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset, + SmallVectorImpl<TiReference> &Refs) { + // 0: Kind + // 2: Padding + // 4: TypeIndex + Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1}); + return 8; +} + +static void handleFieldList(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Offset = 0; + uint32_t ThisLen = 0; + while (!Content.empty()) { + TypeLeafKind Kind = + static_cast<TypeLeafKind>(support::endian::read16le(Content.data())); + switch (Kind) { + case LF_BCLASS: + ThisLen = handleBaseClass(Content, Offset, Refs); + break; + case LF_ENUMERATE: + ThisLen = handleEnumerator(Content, Offset, Refs); + break; + case LF_MEMBER: + ThisLen = handleDataMember(Content, Offset, Refs); + break; + case LF_METHOD: + ThisLen = handleOverloadedMethod(Content, Offset, Refs); + break; + case LF_ONEMETHOD: + ThisLen = handleOneMethod(Content, Offset, Refs); + break; + case LF_NESTTYPE: + ThisLen = handleNestedType(Content, Offset, Refs); + break; + case LF_STMEMBER: + ThisLen = handleStaticDataMember(Content, Offset, Refs); + break; + case LF_VBCLASS: + case LF_IVBCLASS: + ThisLen = + handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs); + break; + case LF_VFUNCTAB: + ThisLen = handleVFPtr(Content, Offset, Refs); + break; + case LF_INDEX: + ThisLen = handleListContinuation(Content, Offset, Refs); + break; + default: + return; + } + Content = Content.drop_front(ThisLen); + Offset += ThisLen; + if (!Content.empty()) { + uint8_t Pad = Content.front(); + if (Pad >= LF_PAD0) { + uint32_t Skip = Pad & 0x0F; + Content = Content.drop_front(Skip); + Offset += Skip; + } + } + } +} + +static void handlePointer(ArrayRef<uint8_t> Content, + SmallVectorImpl<TiReference> &Refs) { + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + + uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data()); + if (isMemberPointer(Attrs)) + Refs.push_back({TiRefKind::TypeRef, 8, 1}); +} + +static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Count; + // FIXME: In the future it would be nice if we could avoid hardcoding these + // values. One idea is to define some structures representing these types + // that would allow the use of offsetof(). + switch (Kind) { + case TypeLeafKind::LF_FUNC_ID: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); + Refs.push_back({TiRefKind::TypeRef, 4, 1}); + break; + case TypeLeafKind::LF_MFUNC_ID: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_STRING_ID: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); + break; + case TypeLeafKind::LF_SUBSTR_LIST: + Count = support::endian::read32le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::IndexRef, 4, Count}); + break; + case TypeLeafKind::LF_BUILDINFO: + Count = support::endian::read16le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::IndexRef, 2, Count}); + break; + case TypeLeafKind::LF_UDT_SRC_LINE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + Refs.push_back({TiRefKind::IndexRef, 4, 1}); + break; + case TypeLeafKind::LF_UDT_MOD_SRC_LINE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_MODIFIER: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_PROCEDURE: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + Refs.push_back({TiRefKind::TypeRef, 8, 1}); + break; + case TypeLeafKind::LF_MFUNCTION: + Refs.push_back({TiRefKind::TypeRef, 0, 3}); + Refs.push_back({TiRefKind::TypeRef, 16, 1}); + break; + case TypeLeafKind::LF_ARGLIST: + Count = support::endian::read32le(Content.data()); + if (Count > 0) + Refs.push_back({TiRefKind::TypeRef, 4, Count}); + break; + case TypeLeafKind::LF_ARRAY: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_CLASS: + case TypeLeafKind::LF_STRUCTURE: + case TypeLeafKind::LF_INTERFACE: + Refs.push_back({TiRefKind::TypeRef, 4, 3}); + break; + case TypeLeafKind::LF_UNION: + Refs.push_back({TiRefKind::TypeRef, 4, 1}); + break; + case TypeLeafKind::LF_ENUM: + Refs.push_back({TiRefKind::TypeRef, 4, 2}); + break; + case TypeLeafKind::LF_BITFIELD: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); + break; + case TypeLeafKind::LF_VFTABLE: + Refs.push_back({TiRefKind::TypeRef, 0, 2}); + break; + case TypeLeafKind::LF_VTSHAPE: + break; + case TypeLeafKind::LF_METHODLIST: + handleMethodOverloadList(Content, Refs); + break; + case TypeLeafKind::LF_FIELDLIST: + handleFieldList(Content, Refs); + break; + case TypeLeafKind::LF_POINTER: + handlePointer(Content, Refs); + break; + default: + break; + } +} + +static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind, + SmallVectorImpl<TiReference> &Refs) { + uint32_t Count; + // FIXME: In the future it would be nice if we could avoid hardcoding these + // values. One idea is to define some structures representing these types + // that would allow the use of offsetof(). + switch (Kind) { + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: + Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID + break; + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type + break; + case SymbolKind::S_UDT: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT + break; + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_BUILDINFO: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags + break; + case SymbolKind::S_LTHREAD32: + case SymbolKind::S_GTHREAD32: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_FILESTATIC: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_LOCAL: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_REGISTER: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_CONSTANT: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_BPREL32: + case SymbolKind::S_REGREL32: + Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type + break; + case SymbolKind::S_CALLSITEINFO: + Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature + break; + case SymbolKind::S_CALLERS: + case SymbolKind::S_CALLEES: + case SymbolKind::S_INLINEES: + // The record is a count followed by an array of type indices. + Count = *reinterpret_cast<const ulittle32_t *>(Content.data()); + Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees + break; + case SymbolKind::S_INLINESITE: + Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee + break; + case SymbolKind::S_HEAPALLOCSITE: + Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated + break; + + // Defranges don't have types, just registers and code offsets. + case SymbolKind::S_DEFRANGE_REGISTER: + case SymbolKind::S_DEFRANGE_REGISTER_REL: + case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL: + case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER: + case SymbolKind::S_DEFRANGE_SUBFIELD: + break; + + // No type references. + case SymbolKind::S_LABEL32: + case SymbolKind::S_OBJNAME: + case SymbolKind::S_COMPILE: + case SymbolKind::S_COMPILE2: + case SymbolKind::S_COMPILE3: + case SymbolKind::S_ENVBLOCK: + case SymbolKind::S_BLOCK32: + case SymbolKind::S_FRAMEPROC: + case SymbolKind::S_THUNK32: + case SymbolKind::S_FRAMECOOKIE: + case SymbolKind::S_UNAMESPACE: + break; + // Scope ending symbols. + case SymbolKind::S_END: + case SymbolKind::S_INLINESITE_END: + case SymbolKind::S_PROC_ID_END: + break; + default: + return false; // Unknown symbol. + } + return true; +} + +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl<TiReference> &Refs) { + ::discoverTypeIndices(Type.content(), Type.kind(), Refs); +} + +static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData, + ArrayRef<TiReference> Refs, + SmallVectorImpl<TypeIndex> &Indices) { + Indices.clear(); + + if (Refs.empty()) + return; + + RecordData = RecordData.drop_front(sizeof(RecordPrefix)); + + BinaryStreamReader Reader(RecordData, support::little); + for (const auto &Ref : Refs) { + Reader.setOffset(Ref.Offset); + FixedStreamArray<TypeIndex> Run; + cantFail(Reader.readArray(Run, Ref.Count)); + Indices.append(Run.begin(), Run.end()); + } +} + +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl<TypeIndex> &Indices) { + return discoverTypeIndices(Type.RecordData, Indices); +} + +void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, + SmallVectorImpl<TypeIndex> &Indices) { + SmallVector<TiReference, 4> Refs; + discoverTypeIndices(RecordData, Refs); + resolveTypeIndexReferences(RecordData, Refs, Indices); +} + +void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData, + SmallVectorImpl<TiReference> &Refs) { + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(RecordData.data()); + TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind)); + ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); +} + +bool llvm::codeview::discoverTypeIndicesInSymbol( + const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) { + SymbolKind K = Sym.kind(); + return ::discoverTypeIndices(Sym.content(), K, Refs); +} + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) { + const RecordPrefix *P = + reinterpret_cast<const RecordPrefix *>(RecordData.data()); + SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind)); + return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, + Refs); +} + +bool llvm::codeview::discoverTypeIndicesInSymbol( + ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) { + SmallVector<TiReference, 2> Refs; + if (!discoverTypeIndicesInSymbol(RecordData, Refs)) + return false; + resolveTypeIndexReferences(RecordData, Refs, Indices); + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp index 8e632f3be4..2b6fc8a0fe 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp @@ -1,52 +1,52 @@ -//===- TypeRecordHelpers.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" - -using namespace llvm; -using namespace llvm::codeview; - -template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) { - RecordT Record; - if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) { - consumeError(std::move(EC)); - return ClassOptions::None; - } - return Record.getOptions(); -} - -bool llvm::codeview::isUdtForwardRef(CVType CVT) { - ClassOptions UdtOptions = ClassOptions::None; - switch (CVT.kind()) { - case LF_STRUCTURE: - case LF_CLASS: - case LF_INTERFACE: - UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT)); - break; - case LF_ENUM: - UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT)); - break; - case LF_UNION: - UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT)); - break; - default: - return false; - } - return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None; -} - -TypeIndex llvm::codeview::getModifiedType(const CVType &CVT) { - assert(CVT.kind() == LF_MODIFIER); - SmallVector<TypeIndex, 1> Refs; - discoverTypeIndices(CVT, Refs); - return Refs.front(); -} +//===- TypeRecordHelpers.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +using namespace llvm; +using namespace llvm::codeview; + +template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) { + RecordT Record; + if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) { + consumeError(std::move(EC)); + return ClassOptions::None; + } + return Record.getOptions(); +} + +bool llvm::codeview::isUdtForwardRef(CVType CVT) { + ClassOptions UdtOptions = ClassOptions::None; + switch (CVT.kind()) { + case LF_STRUCTURE: + case LF_CLASS: + case LF_INTERFACE: + UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT)); + break; + case LF_ENUM: + UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT)); + break; + case LF_UNION: + UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT)); + break; + default: + return false; + } + return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None; +} + +TypeIndex llvm::codeview::getModifiedType(const CVType &CVT) { + assert(CVT.kind() == LF_MODIFIER); + SmallVector<TypeIndex, 1> Refs; + discoverTypeIndices(CVT, Refs); + return Refs.front(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordMapping.cpp index 7ac3761561..32a3f9719c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordMapping.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -1,710 +1,710 @@ -//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/EnumTables.h" - -using namespace llvm; -using namespace llvm::codeview; - -namespace { - -#define error(X) \ - if (auto EC = X) \ - return EC; - -static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { -#define CV_TYPE(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -}; - -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define TYPE_RECORD(ename, value, name) \ - case ename: \ - return #name; -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - default: - break; - } - return "UnknownLeaf"; -} - -template <typename T> -static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) { - return lhs.Name < rhs.Name; -} - -template <typename T, typename TFlag> -static std::string getFlagNames(CodeViewRecordIO &IO, T Value, - ArrayRef<EnumEntry<TFlag>> Flags) { - if (!IO.isStreaming()) - return std::string(""); - typedef EnumEntry<TFlag> FlagEntry; - typedef SmallVector<FlagEntry, 10> FlagVector; - FlagVector SetFlags; - for (const auto &Flag : Flags) { - if (Flag.Value == 0) - continue; - if ((Value & Flag.Value) == Flag.Value) { - SetFlags.push_back(Flag); - } - } - - llvm::sort(SetFlags, &compEnumNames<TFlag>); - - std::string FlagLabel; - bool FirstOcc = true; - for (const auto &Flag : SetFlags) { - if (FirstOcc) - FirstOcc = false; - else - FlagLabel += (" | "); - - FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")"); - } - - if (!FlagLabel.empty()) { - std::string LabelWithBraces(" ( "); - LabelWithBraces += FlagLabel + " )"; - return LabelWithBraces; - } else - return FlagLabel; -} - -template <typename T, typename TEnum> -static StringRef getEnumName(CodeViewRecordIO &IO, T Value, - ArrayRef<EnumEntry<TEnum>> EnumValues) { - if (!IO.isStreaming()) - return ""; - StringRef Name; - for (const auto &EnumItem : EnumValues) { - if (EnumItem.Value == Value) { - Name = EnumItem.Name; - break; - } - } - - return Name; -} - -static std::string getMemberAttributes(CodeViewRecordIO &IO, - MemberAccess Access, MethodKind Kind, - MethodOptions Options) { - if (!IO.isStreaming()) - return ""; - std::string AccessSpecifier = std::string( - getEnumName(IO, uint8_t(Access), makeArrayRef(getMemberAccessNames()))); - std::string MemberAttrs(AccessSpecifier); - if (Kind != MethodKind::Vanilla) { - std::string MethodKind = std::string( - getEnumName(IO, unsigned(Kind), makeArrayRef(getMemberKindNames()))); - MemberAttrs += ", " + MethodKind; - } - if (Options != MethodOptions::None) { - std::string MethodOptions = getFlagNames( - IO, unsigned(Options), makeArrayRef(getMethodOptionNames())); - MemberAttrs += ", " + MethodOptions; - } - return MemberAttrs; -} - -struct MapOneMethodRecord { - explicit MapOneMethodRecord(bool IsFromOverloadList) - : IsFromOverloadList(IsFromOverloadList) {} - - Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const { - std::string Attrs = getMemberAttributes( - IO, Method.getAccess(), Method.getMethodKind(), Method.getOptions()); - error(IO.mapInteger(Method.Attrs.Attrs, "Attrs: " + Attrs)); - if (IsFromOverloadList) { - uint16_t Padding = 0; - error(IO.mapInteger(Padding)); - } - error(IO.mapInteger(Method.Type, "Type")); - if (Method.isIntroducingVirtual()) { - error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset")); - } else if (IO.isReading()) - Method.VFTableOffset = -1; - - if (!IsFromOverloadList) - error(IO.mapStringZ(Method.Name, "Name")); - - return Error::success(); - } - -private: - bool IsFromOverloadList; -}; -} // namespace - -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 { - // Cap the length of the string at however many bytes we have available, - // plus one for the required null terminator. - auto N = StringRef(Name).take_front(BytesLeft - 1); - error(IO.mapStringZ(N)); - } - } else { - // Reading & Streaming mode come after writing mode is executed for each - // record. Truncating large names are done during writing, so its not - // necessary to do it while reading or streaming. - error(IO.mapStringZ(Name, "Name")); - if (HasUniqueName) - error(IO.mapStringZ(UniqueName, "LinkageName")); - } - - 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.kind() != TypeLeafKind::LF_FIELDLIST && - CVR.kind() != TypeLeafKind::LF_METHODLIST) - MaxLen = MaxRecordLength - sizeof(RecordPrefix); - error(IO.beginRecord(MaxLen)); - TypeKind = CVR.kind(); - - if (IO.isStreaming()) { - auto RecordKind = CVR.kind(); - uint16_t RecordLen = CVR.length() - 2; - std::string RecordKindName = std::string( - getEnumName(IO, unsigned(RecordKind), makeArrayRef(LeafTypeNames))); - error(IO.mapInteger(RecordLen, "Record length")); - error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName)); - } - return Error::success(); -} - -Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) { - if (IO.isStreaming()) - IO.emitRawComment(" " + getLeafTypeName(CVR.kind()) + " (0x" + - utohexstr(Index.getIndex()) + ")"); - return visitTypeBegin(CVR); -} - -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 +//===- TypeRecordMapping.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { + +#define error(X) \ + if (auto EC = X) \ + return EC; + +static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { +#define CV_TYPE(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; + +static StringRef getLeafTypeName(TypeLeafKind LT) { + switch (LT) { +#define TYPE_RECORD(ename, value, name) \ + case ename: \ + return #name; +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + default: + break; + } + return "UnknownLeaf"; +} + +template <typename T> +static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) { + return lhs.Name < rhs.Name; +} + +template <typename T, typename TFlag> +static std::string getFlagNames(CodeViewRecordIO &IO, T Value, + ArrayRef<EnumEntry<TFlag>> Flags) { + if (!IO.isStreaming()) + return std::string(""); + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + for (const auto &Flag : Flags) { + if (Flag.Value == 0) + continue; + if ((Value & Flag.Value) == Flag.Value) { + SetFlags.push_back(Flag); + } + } + + llvm::sort(SetFlags, &compEnumNames<TFlag>); + + std::string FlagLabel; + bool FirstOcc = true; + for (const auto &Flag : SetFlags) { + if (FirstOcc) + FirstOcc = false; + else + FlagLabel += (" | "); + + FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")"); + } + + if (!FlagLabel.empty()) { + std::string LabelWithBraces(" ( "); + LabelWithBraces += FlagLabel + " )"; + return LabelWithBraces; + } else + return FlagLabel; +} + +template <typename T, typename TEnum> +static StringRef getEnumName(CodeViewRecordIO &IO, T Value, + ArrayRef<EnumEntry<TEnum>> EnumValues) { + if (!IO.isStreaming()) + return ""; + StringRef Name; + for (const auto &EnumItem : EnumValues) { + if (EnumItem.Value == Value) { + Name = EnumItem.Name; + break; + } + } + + return Name; +} + +static std::string getMemberAttributes(CodeViewRecordIO &IO, + MemberAccess Access, MethodKind Kind, + MethodOptions Options) { + if (!IO.isStreaming()) + return ""; + std::string AccessSpecifier = std::string( + getEnumName(IO, uint8_t(Access), makeArrayRef(getMemberAccessNames()))); + std::string MemberAttrs(AccessSpecifier); + if (Kind != MethodKind::Vanilla) { + std::string MethodKind = std::string( + getEnumName(IO, unsigned(Kind), makeArrayRef(getMemberKindNames()))); + MemberAttrs += ", " + MethodKind; + } + if (Options != MethodOptions::None) { + std::string MethodOptions = getFlagNames( + IO, unsigned(Options), makeArrayRef(getMethodOptionNames())); + MemberAttrs += ", " + MethodOptions; + } + return MemberAttrs; +} + +struct MapOneMethodRecord { + explicit MapOneMethodRecord(bool IsFromOverloadList) + : IsFromOverloadList(IsFromOverloadList) {} + + Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const { + std::string Attrs = getMemberAttributes( + IO, Method.getAccess(), Method.getMethodKind(), Method.getOptions()); + error(IO.mapInteger(Method.Attrs.Attrs, "Attrs: " + Attrs)); + if (IsFromOverloadList) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + } + error(IO.mapInteger(Method.Type, "Type")); + if (Method.isIntroducingVirtual()) { + error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset")); + } else if (IO.isReading()) + Method.VFTableOffset = -1; + + if (!IsFromOverloadList) + error(IO.mapStringZ(Method.Name, "Name")); + + return Error::success(); + } + +private: + bool IsFromOverloadList; +}; +} // namespace + +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 { + // Cap the length of the string at however many bytes we have available, + // plus one for the required null terminator. + auto N = StringRef(Name).take_front(BytesLeft - 1); + error(IO.mapStringZ(N)); + } + } else { + // Reading & Streaming mode come after writing mode is executed for each + // record. Truncating large names are done during writing, so its not + // necessary to do it while reading or streaming. + error(IO.mapStringZ(Name, "Name")); + if (HasUniqueName) + error(IO.mapStringZ(UniqueName, "LinkageName")); + } + + 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.kind() != TypeLeafKind::LF_FIELDLIST && + CVR.kind() != TypeLeafKind::LF_METHODLIST) + MaxLen = MaxRecordLength - sizeof(RecordPrefix); + error(IO.beginRecord(MaxLen)); + TypeKind = CVR.kind(); + + if (IO.isStreaming()) { + auto RecordKind = CVR.kind(); + uint16_t RecordLen = CVR.length() - 2; + std::string RecordKindName = std::string( + getEnumName(IO, unsigned(RecordKind), makeArrayRef(LeafTypeNames))); + error(IO.mapInteger(RecordLen, "Record length")); + error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName)); + } + return Error::success(); +} + +Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) { + if (IO.isStreaming()) + IO.emitRawComment(" " + getLeafTypeName(CVR.kind()) + " (0x" + + utohexstr(Index.getIndex()) + ")"); + return visitTypeBegin(CVR); +} + +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 spawns `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; - if (IO.isStreaming()) { - std::string MemberKindName = std::string(getLeafTypeName(Record.Kind)); - MemberKindName += - " ( " + - (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames))) - .str() + - " )"; - error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName)); - } - 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.isReading()) { - if (auto EC = IO.skipPadding()) - return EC; - } - - MemberKind.reset(); - error(IO.endRecord()); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) { - std::string ModifierNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers), - makeArrayRef(getTypeModifierNames())); - error(IO.mapInteger(Record.ModifiedType, "ModifiedType")); - error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames)); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - ProcedureRecord &Record) { - std::string CallingConvName = std::string(getEnumName( - IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()))); - std::string FuncOptionNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Options), - makeArrayRef(getFunctionOptionEnum())); - error(IO.mapInteger(Record.ReturnType, "ReturnType")); - error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName)); - error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames)); - error(IO.mapInteger(Record.ParameterCount, "NumParameters")); - error(IO.mapInteger(Record.ArgumentList, "ArgListType")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - MemberFunctionRecord &Record) { - std::string CallingConvName = std::string(getEnumName( - IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()))); - std::string FuncOptionNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Options), - makeArrayRef(getFunctionOptionEnum())); - error(IO.mapInteger(Record.ReturnType, "ReturnType")); - error(IO.mapInteger(Record.ClassType, "ClassType")); - error(IO.mapInteger(Record.ThisType, "ThisType")); - error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName)); - error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames)); - error(IO.mapInteger(Record.ParameterCount, "NumParameters")); - error(IO.mapInteger(Record.ArgumentList, "ArgListType")); - error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { - error(IO.mapVectorN<uint32_t>( - Record.ArgIndices, - [](CodeViewRecordIO &IO, TypeIndex &N) { - return IO.mapInteger(N, "Argument"); - }, - "NumArgs")); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - StringListRecord &Record) { - error(IO.mapVectorN<uint32_t>( - Record.StringIndices, - [](CodeViewRecordIO &IO, TypeIndex &N) { - return IO.mapInteger(N, "Strings"); - }, - "NumStrings")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) { - - SmallString<128> Attr("Attrs: "); - - if (IO.isStreaming()) { - std::string PtrType = - std::string(getEnumName(IO, unsigned(Record.getPointerKind()), - makeArrayRef(getPtrKindNames()))); - Attr += "[ Type: " + PtrType; - - std::string PtrMode = std::string(getEnumName( - IO, unsigned(Record.getMode()), makeArrayRef(getPtrModeNames()))); - Attr += ", Mode: " + PtrMode; - - auto PtrSizeOf = Record.getSize(); - Attr += ", SizeOf: " + itostr(PtrSizeOf); - - if (Record.isFlat()) - Attr += ", isFlat"; - if (Record.isConst()) - Attr += ", isConst"; - if (Record.isVolatile()) - Attr += ", isVolatile"; - if (Record.isUnaligned()) - Attr += ", isUnaligned"; - if (Record.isRestrict()) - Attr += ", isRestricted"; - if (Record.isLValueReferenceThisPtr()) - Attr += ", isThisPtr&"; - if (Record.isRValueReferenceThisPtr()) - Attr += ", isThisPtr&&"; - Attr += " ]"; - } - - error(IO.mapInteger(Record.ReferentType, "PointeeType")); - error(IO.mapInteger(Record.Attrs, Attr)); - - if (Record.isPointerToMember()) { - if (IO.isReading()) - Record.MemberInfo.emplace(); - - MemberPointerInfo &M = *Record.MemberInfo; - error(IO.mapInteger(M.ContainingType, "ClassType")); - std::string PtrMemberGetRepresentation = std::string(getEnumName( - IO, uint16_t(M.Representation), makeArrayRef(getPtrMemberRepNames()))); - error(IO.mapEnum(M.Representation, - "Representation: " + PtrMemberGetRepresentation)); - } - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) { - error(IO.mapInteger(Record.ElementType, "ElementType")); - error(IO.mapInteger(Record.IndexType, "IndexType")); - error(IO.mapEncodedInteger(Record.Size, "SizeOf")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { - assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) || - (CVR.kind() == TypeLeafKind::LF_CLASS) || - (CVR.kind() == TypeLeafKind::LF_INTERFACE)); - - std::string PropertiesNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Options), - makeArrayRef(getClassOptionNames())); - error(IO.mapInteger(Record.MemberCount, "MemberCount")); - error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); - error(IO.mapInteger(Record.FieldList, "FieldList")); - error(IO.mapInteger(Record.DerivationList, "DerivedFrom")); - error(IO.mapInteger(Record.VTableShape, "VShape")); - error(IO.mapEncodedInteger(Record.Size, "SizeOf")); - error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, - Record.hasUniqueName())); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { - std::string PropertiesNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Options), - makeArrayRef(getClassOptionNames())); - error(IO.mapInteger(Record.MemberCount, "MemberCount")); - error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); - error(IO.mapInteger(Record.FieldList, "FieldList")); - error(IO.mapEncodedInteger(Record.Size, "SizeOf")); - error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, - Record.hasUniqueName())); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) { - std::string PropertiesNames = - getFlagNames(IO, static_cast<uint16_t>(Record.Options), - makeArrayRef(getClassOptionNames())); - error(IO.mapInteger(Record.MemberCount, "NumEnumerators")); - error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); - error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType")); - error(IO.mapInteger(Record.FieldList, "FieldListType")); - error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, - Record.hasUniqueName())); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) { - error(IO.mapInteger(Record.Type, "Type")); - error(IO.mapInteger(Record.BitSize, "BitSize")); - error(IO.mapInteger(Record.BitOffset, "BitOffset")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - VFTableShapeRecord &Record) { - uint16_t Size; - if (!IO.isReading()) { - ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); - Size = Slots.size(); - error(IO.mapInteger(Size, "VFEntryCount")); - - 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, "CompleteClass")); - error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable")); - error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset")); - uint32_t NamesLen = 0; - if (!IO.isReading()) { - 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, "MethodName"); - }, - "VFTableName")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) { - error(IO.mapInteger(Record.Id, "Id")); - error(IO.mapStringZ(Record.String, "StringData")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - UdtSourceLineRecord &Record) { - error(IO.mapInteger(Record.UDT, "UDT")); - error(IO.mapInteger(Record.SourceFile, "SourceFile")); - error(IO.mapInteger(Record.LineNumber, "LineNumber")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - UdtModSourceLineRecord &Record) { - error(IO.mapInteger(Record.UDT, "UDT")); - error(IO.mapInteger(Record.SourceFile, "SourceFile")); - error(IO.mapInteger(Record.LineNumber, "LineNumber")); - error(IO.mapInteger(Record.Module, "Module")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) { - error(IO.mapInteger(Record.ParentScope, "ParentScope")); - error(IO.mapInteger(Record.FunctionType, "FunctionType")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - MemberFuncIdRecord &Record) { - error(IO.mapInteger(Record.ClassType, "ClassType")); - error(IO.mapInteger(Record.FunctionType, "FunctionType")); - error(IO.mapStringZ(Record.Name, "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, "Argument"); - }, - "NumArgs")); - - 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), "Method")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - FieldListRecord &Record) { - if (IO.isStreaming()) { - if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this)) - return EC; - } else - error(IO.mapByteVectorTail(Record.Data)); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - TypeServer2Record &Record) { - error(IO.mapGuid(Record.Guid, "Guid")); - error(IO.mapInteger(Record.Age, "Age")); - error(IO.mapStringZ(Record.Name, "Name")); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) { - std::string ModeName = std::string( - getEnumName(IO, uint16_t(Record.Mode), makeArrayRef(getLabelTypeEnum()))); - error(IO.mapEnum(Record.Mode, "Mode: " + ModeName)); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - BaseClassRecord &Record) { - std::string Attrs = getMemberAttributes( - IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); - error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); - error(IO.mapInteger(Record.Type, "BaseType")); - error(IO.mapEncodedInteger(Record.Offset, "BaseOffset")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - EnumeratorRecord &Record) { - std::string Attrs = getMemberAttributes( - IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); - error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); - - // FIXME: Handle full APInt such as __int128. - error(IO.mapEncodedInteger(Record.Value, "EnumValue")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - DataMemberRecord &Record) { - std::string Attrs = getMemberAttributes( - IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); - error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); - error(IO.mapInteger(Record.Type, "Type")); - error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - OverloadedMethodRecord &Record) { - error(IO.mapInteger(Record.NumOverloads, "MethodCount")); - error(IO.mapInteger(Record.MethodList, "MethodListIndex")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - OneMethodRecord &Record) { - const bool IsFromOverloadList = (TypeKind == LF_METHODLIST); - MapOneMethodRecord Mapper(IsFromOverloadList); - return Mapper(IO, Record); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Record) { - uint16_t Padding = 0; - error(IO.mapInteger(Padding, "Padding")); - error(IO.mapInteger(Record.Type, "Type")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - StaticDataMemberRecord &Record) { - - std::string Attrs = getMemberAttributes( - IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); - error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); - error(IO.mapInteger(Record.Type, "Type")); - error(IO.mapStringZ(Record.Name, "Name")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - VirtualBaseClassRecord &Record) { - - std::string Attrs = getMemberAttributes( - IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); - error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); - error(IO.mapInteger(Record.BaseType, "BaseType")); - error(IO.mapInteger(Record.VBPtrType, "VBPtrType")); - error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset")); - error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - VFPtrRecord &Record) { - uint16_t Padding = 0; - error(IO.mapInteger(Padding, "Padding")); - error(IO.mapInteger(Record.Type, "Type")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, - ListContinuationRecord &Record) { - uint16_t Padding = 0; - error(IO.mapInteger(Padding, "Padding")); - error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex")); - - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - PrecompRecord &Precomp) { - error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex")); - error(IO.mapInteger(Precomp.TypesCount, "Count")); - error(IO.mapInteger(Precomp.Signature, "Signature")); - error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile")); - return Error::success(); -} - -Error TypeRecordMapping::visitKnownRecord(CVType &CVR, - EndPrecompRecord &EndPrecomp) { - error(IO.mapInteger(EndPrecomp.Signature, "Signature")); - return Error::success(); -} + // calculated as follows. + + constexpr uint32_t ContinuationLength = 8; + error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) - + ContinuationLength)); + + MemberKind = Record.Kind; + if (IO.isStreaming()) { + std::string MemberKindName = std::string(getLeafTypeName(Record.Kind)); + MemberKindName += + " ( " + + (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames))) + .str() + + " )"; + error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName)); + } + 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.isReading()) { + if (auto EC = IO.skipPadding()) + return EC; + } + + MemberKind.reset(); + error(IO.endRecord()); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) { + std::string ModifierNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers), + makeArrayRef(getTypeModifierNames())); + error(IO.mapInteger(Record.ModifiedType, "ModifiedType")); + error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames)); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + ProcedureRecord &Record) { + std::string CallingConvName = std::string(getEnumName( + IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()))); + std::string FuncOptionNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Options), + makeArrayRef(getFunctionOptionEnum())); + error(IO.mapInteger(Record.ReturnType, "ReturnType")); + error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName)); + error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames)); + error(IO.mapInteger(Record.ParameterCount, "NumParameters")); + error(IO.mapInteger(Record.ArgumentList, "ArgListType")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &Record) { + std::string CallingConvName = std::string(getEnumName( + IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions()))); + std::string FuncOptionNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Options), + makeArrayRef(getFunctionOptionEnum())); + error(IO.mapInteger(Record.ReturnType, "ReturnType")); + error(IO.mapInteger(Record.ClassType, "ClassType")); + error(IO.mapInteger(Record.ThisType, "ThisType")); + error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName)); + error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames)); + error(IO.mapInteger(Record.ParameterCount, "NumParameters")); + error(IO.mapInteger(Record.ArgumentList, "ArgListType")); + error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { + error(IO.mapVectorN<uint32_t>( + Record.ArgIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { + return IO.mapInteger(N, "Argument"); + }, + "NumArgs")); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + StringListRecord &Record) { + error(IO.mapVectorN<uint32_t>( + Record.StringIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { + return IO.mapInteger(N, "Strings"); + }, + "NumStrings")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) { + + SmallString<128> Attr("Attrs: "); + + if (IO.isStreaming()) { + std::string PtrType = + std::string(getEnumName(IO, unsigned(Record.getPointerKind()), + makeArrayRef(getPtrKindNames()))); + Attr += "[ Type: " + PtrType; + + std::string PtrMode = std::string(getEnumName( + IO, unsigned(Record.getMode()), makeArrayRef(getPtrModeNames()))); + Attr += ", Mode: " + PtrMode; + + auto PtrSizeOf = Record.getSize(); + Attr += ", SizeOf: " + itostr(PtrSizeOf); + + if (Record.isFlat()) + Attr += ", isFlat"; + if (Record.isConst()) + Attr += ", isConst"; + if (Record.isVolatile()) + Attr += ", isVolatile"; + if (Record.isUnaligned()) + Attr += ", isUnaligned"; + if (Record.isRestrict()) + Attr += ", isRestricted"; + if (Record.isLValueReferenceThisPtr()) + Attr += ", isThisPtr&"; + if (Record.isRValueReferenceThisPtr()) + Attr += ", isThisPtr&&"; + Attr += " ]"; + } + + error(IO.mapInteger(Record.ReferentType, "PointeeType")); + error(IO.mapInteger(Record.Attrs, Attr)); + + if (Record.isPointerToMember()) { + if (IO.isReading()) + Record.MemberInfo.emplace(); + + MemberPointerInfo &M = *Record.MemberInfo; + error(IO.mapInteger(M.ContainingType, "ClassType")); + std::string PtrMemberGetRepresentation = std::string(getEnumName( + IO, uint16_t(M.Representation), makeArrayRef(getPtrMemberRepNames()))); + error(IO.mapEnum(M.Representation, + "Representation: " + PtrMemberGetRepresentation)); + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) { + error(IO.mapInteger(Record.ElementType, "ElementType")); + error(IO.mapInteger(Record.IndexType, "IndexType")); + error(IO.mapEncodedInteger(Record.Size, "SizeOf")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { + assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) || + (CVR.kind() == TypeLeafKind::LF_CLASS) || + (CVR.kind() == TypeLeafKind::LF_INTERFACE)); + + std::string PropertiesNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Options), + makeArrayRef(getClassOptionNames())); + error(IO.mapInteger(Record.MemberCount, "MemberCount")); + error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); + error(IO.mapInteger(Record.FieldList, "FieldList")); + error(IO.mapInteger(Record.DerivationList, "DerivedFrom")); + error(IO.mapInteger(Record.VTableShape, "VShape")); + error(IO.mapEncodedInteger(Record.Size, "SizeOf")); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { + std::string PropertiesNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Options), + makeArrayRef(getClassOptionNames())); + error(IO.mapInteger(Record.MemberCount, "MemberCount")); + error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); + error(IO.mapInteger(Record.FieldList, "FieldList")); + error(IO.mapEncodedInteger(Record.Size, "SizeOf")); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) { + std::string PropertiesNames = + getFlagNames(IO, static_cast<uint16_t>(Record.Options), + makeArrayRef(getClassOptionNames())); + error(IO.mapInteger(Record.MemberCount, "NumEnumerators")); + error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames)); + error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType")); + error(IO.mapInteger(Record.FieldList, "FieldListType")); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) { + error(IO.mapInteger(Record.Type, "Type")); + error(IO.mapInteger(Record.BitSize, "BitSize")); + error(IO.mapInteger(Record.BitOffset, "BitOffset")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Record) { + uint16_t Size; + if (!IO.isReading()) { + ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); + Size = Slots.size(); + error(IO.mapInteger(Size, "VFEntryCount")); + + 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, "CompleteClass")); + error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable")); + error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset")); + uint32_t NamesLen = 0; + if (!IO.isReading()) { + 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, "MethodName"); + }, + "VFTableName")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) { + error(IO.mapInteger(Record.Id, "Id")); + error(IO.mapStringZ(Record.String, "StringData")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT, "UDT")); + error(IO.mapInteger(Record.SourceFile, "SourceFile")); + error(IO.mapInteger(Record.LineNumber, "LineNumber")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT, "UDT")); + error(IO.mapInteger(Record.SourceFile, "SourceFile")); + error(IO.mapInteger(Record.LineNumber, "LineNumber")); + error(IO.mapInteger(Record.Module, "Module")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) { + error(IO.mapInteger(Record.ParentScope, "ParentScope")); + error(IO.mapInteger(Record.FunctionType, "FunctionType")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Record) { + error(IO.mapInteger(Record.ClassType, "ClassType")); + error(IO.mapInteger(Record.FunctionType, "FunctionType")); + error(IO.mapStringZ(Record.Name, "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, "Argument"); + }, + "NumArgs")); + + 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), "Method")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + FieldListRecord &Record) { + if (IO.isStreaming()) { + if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this)) + return EC; + } else + error(IO.mapByteVectorTail(Record.Data)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + TypeServer2Record &Record) { + error(IO.mapGuid(Record.Guid, "Guid")); + error(IO.mapInteger(Record.Age, "Age")); + error(IO.mapStringZ(Record.Name, "Name")); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) { + std::string ModeName = std::string( + getEnumName(IO, uint16_t(Record.Mode), makeArrayRef(getLabelTypeEnum()))); + error(IO.mapEnum(Record.Mode, "Mode: " + ModeName)); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Record) { + std::string Attrs = getMemberAttributes( + IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); + error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); + error(IO.mapInteger(Record.Type, "BaseType")); + error(IO.mapEncodedInteger(Record.Offset, "BaseOffset")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Record) { + std::string Attrs = getMemberAttributes( + IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); + error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); + + // FIXME: Handle full APInt such as __int128. + error(IO.mapEncodedInteger(Record.Value, "EnumValue")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Record) { + std::string Attrs = getMemberAttributes( + IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); + error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); + error(IO.mapInteger(Record.Type, "Type")); + error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Record) { + error(IO.mapInteger(Record.NumOverloads, "MethodCount")); + error(IO.mapInteger(Record.MethodList, "MethodListIndex")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Record) { + const bool IsFromOverloadList = (TypeKind == LF_METHODLIST); + MapOneMethodRecord Mapper(IsFromOverloadList); + return Mapper(IO, Record); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding, "Padding")); + error(IO.mapInteger(Record.Type, "Type")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Record) { + + std::string Attrs = getMemberAttributes( + IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); + error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); + error(IO.mapInteger(Record.Type, "Type")); + error(IO.mapStringZ(Record.Name, "Name")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Record) { + + std::string Attrs = getMemberAttributes( + IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None); + error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs)); + error(IO.mapInteger(Record.BaseType, "BaseType")); + error(IO.mapInteger(Record.VBPtrType, "VBPtrType")); + error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset")); + error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding, "Padding")); + error(IO.mapInteger(Record.Type, "Type")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding, "Padding")); + error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex")); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + PrecompRecord &Precomp) { + error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex")); + error(IO.mapInteger(Precomp.TypesCount, "Count")); + error(IO.mapInteger(Precomp.Signature, "Signature")); + error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile")); + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + EndPrecompRecord &EndPrecomp) { + error(IO.mapInteger(EndPrecomp.Signature, "Signature")); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index 587a68142a..f08fbb1df2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -1,496 +1,496 @@ -//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" -#include "llvm/Support/Error.h" - -using namespace llvm; -using namespace llvm::codeview; - -static inline size_t slotForIndex(TypeIndex Idx) { - assert(!Idx.isSimple() && "simple type indices have no slots"); - return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; -} - -namespace { - -/// Implementation of CodeView type stream merging. -/// -/// A CodeView type stream is a series of records that reference each other -/// through type indices. A type index is either "simple", meaning it is less -/// than 0x1000 and refers to a builtin type, or it is complex, meaning it -/// refers to a prior type record in the current stream. The type index of a -/// record is equal to the number of records before it in the stream plus -/// 0x1000. -/// -/// Type records are only allowed to use type indices smaller than their own, so +//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace llvm::codeview; + +static inline size_t slotForIndex(TypeIndex Idx) { + assert(!Idx.isSimple() && "simple type indices have no slots"); + return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; +} + +namespace { + +/// Implementation of CodeView type stream merging. +/// +/// A CodeView type stream is a series of records that reference each other +/// through type indices. A type index is either "simple", meaning it is less +/// than 0x1000 and refers to a builtin type, or it is complex, meaning it +/// refers to a prior type record in the current stream. The type index of a +/// record is equal to the number of records before it in the stream plus +/// 0x1000. +/// +/// Type records are only allowed to use type indices smaller than their own, so /// a type stream is effectively a topologically sorted DAG. Cycles occurring in -/// the type graph of the source program are resolved with forward declarations -/// of composite types. This class implements the following type stream merging -/// algorithm, which relies on this DAG structure: -/// -/// - Begin with a new empty stream, and a new empty hash table that maps from -/// type record contents to new type index. -/// - For each new type stream, maintain a map from source type index to -/// destination type index. -/// - For each record, copy it and rewrite its type indices to be valid in the -/// destination type stream. -/// - If the new type record is not already present in the destination stream -/// hash table, append it to the destination type stream, assign it the next -/// type index, and update the two hash tables. -/// - If the type record already exists in the destination stream, discard it -/// and update the type index map to forward the source type index to the -/// existing destination type index. -/// -/// As an additional complication, type stream merging actually produces two -/// streams: an item (or IPI) stream and a type stream, as this is what is -/// actually stored in the final PDB. We choose which records go where by -/// looking at the record kind. -class TypeStreamMerger { -public: - explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest) - : IndexMap(SourceToDest) { - // When dealing with precompiled headers objects, all data in SourceToDest - // belongs to the precompiled headers object, and is assumed to be already - // remapped to the target PDB. Any forthcoming type that will be merged in - // might potentially back-reference this data. We also don't want to resolve - // twice the types in the precompiled object. - CurIndex += SourceToDest.size(); - } - - static const TypeIndex Untranslated; - - // Local hashing entry points - Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds, - MergingTypeTableBuilder &DestTypes, - const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S); - Error mergeIdRecords(MergingTypeTableBuilder &Dest, - ArrayRef<TypeIndex> TypeSourceToDest, - const CVTypeArray &Ids); - Error mergeTypeRecords(MergingTypeTableBuilder &Dest, - const CVTypeArray &Types); - - // Global hashing entry points - Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, - GlobalTypeTableBuilder &DestTypes, - const CVTypeArray &IdsAndTypes, - ArrayRef<GloballyHashedType> Hashes, - Optional<uint32_t> &S); - Error mergeIdRecords(GlobalTypeTableBuilder &Dest, - ArrayRef<TypeIndex> TypeSourceToDest, - const CVTypeArray &Ids, - ArrayRef<GloballyHashedType> Hashes); - Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types, - ArrayRef<GloballyHashedType> Hashes, - Optional<uint32_t> &S); - -private: - Error doit(const CVTypeArray &Types); - - Error remapAllTypes(const CVTypeArray &Types); - - Error remapType(const CVType &Type); - - void addMapping(TypeIndex Idx); - - inline bool remapTypeIndex(TypeIndex &Idx) { - // If we're mapping a pure index stream, then IndexMap only contains - // mappings from OldIdStream -> NewIdStream, in which case we will need to - // use the special mapping from OldTypeStream -> NewTypeStream which was - // computed externally. Regardless, we use this special map if and only if - // we are doing an id-only mapping. - if (!hasTypeStream()) - return remapIndex(Idx, TypeLookup); - - assert(TypeLookup.empty()); - return remapIndex(Idx, IndexMap); - } - inline bool remapItemIndex(TypeIndex &Idx) { - assert(hasIdStream()); - return remapIndex(Idx, IndexMap); - } - - bool hasTypeStream() const { - return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream); - } - - bool hasIdStream() const { - return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream); - } - - ArrayRef<uint8_t> remapIndices(const CVType &OriginalType, - MutableArrayRef<uint8_t> Storage); - - inline bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) { - if (LLVM_LIKELY(remapIndexSimple(Idx, Map))) - return true; - - return remapIndexFallback(Idx, Map); - } - - inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef<TypeIndex> Map) const { - // Simple types are unchanged. - if (Idx.isSimple()) - return true; - - // Check if this type index refers to a record we've already translated - // successfully. If it refers to a type later in the stream or a record we - // had to defer, defer it until later pass. - unsigned MapPos = slotForIndex(Idx); - if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated)) - return false; - - Idx = Map[MapPos]; - return true; - } - - bool remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map); - - Error errorCorruptRecord() const { - return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); - } - - Expected<bool> shouldRemapType(const CVType &Type); - - Optional<Error> LastError; - - bool UseGlobalHashes = false; - - bool IsSecondPass = false; - - unsigned NumBadIndices = 0; - - TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; - - MergingTypeTableBuilder *DestIdStream = nullptr; - MergingTypeTableBuilder *DestTypeStream = nullptr; - - GlobalTypeTableBuilder *DestGlobalIdStream = nullptr; - GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr; - - ArrayRef<GloballyHashedType> GlobalHashes; - - // If we're only mapping id records, this array contains the mapping for - // type records. - ArrayRef<TypeIndex> TypeLookup; - - /// Map from source type index to destination type index. Indexed by source - /// type index minus 0x1000. - SmallVectorImpl<TypeIndex> &IndexMap; - - /// Temporary storage that we use to copy a record's data while re-writing - /// its type indices. - SmallVector<uint8_t, 256> RemapStorage; - - Optional<uint32_t> PCHSignature; -}; - -} // end anonymous namespace - -const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); - -void TypeStreamMerger::addMapping(TypeIndex Idx) { - if (!IsSecondPass) { - assert(IndexMap.size() == slotForIndex(CurIndex) && - "visitKnownRecord should add one index map entry"); - IndexMap.push_back(Idx); - } else { - assert(slotForIndex(CurIndex) < IndexMap.size()); - IndexMap[slotForIndex(CurIndex)] = Idx; - } -} - -bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx, - ArrayRef<TypeIndex> Map) { - size_t MapPos = slotForIndex(Idx); - - // If this is the second pass and this index isn't in the map, then it points - // outside the current type stream, and this is a corrupt record. - if (IsSecondPass && MapPos >= Map.size()) { - // FIXME: Print a more useful error. We can give the current record and the - // index that we think its pointing to. - if (LastError) - LastError = joinErrors(std::move(*LastError), errorCorruptRecord()); - else - LastError = errorCorruptRecord(); - } - - ++NumBadIndices; - - // This type index is invalid. Remap this to "not translated by cvpack", - // and return failure. - Idx = Untranslated; - return false; -} - -// Local hashing entry points -Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest, - const CVTypeArray &Types) { - DestTypeStream = &Dest; - UseGlobalHashes = false; - - return doit(Types); -} - -Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest, - ArrayRef<TypeIndex> TypeSourceToDest, - const CVTypeArray &Ids) { - DestIdStream = &Dest; - TypeLookup = TypeSourceToDest; - UseGlobalHashes = false; - - return doit(Ids); -} - -Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds, - MergingTypeTableBuilder &DestTypes, - const CVTypeArray &IdsAndTypes, - Optional<uint32_t> &S) { - DestIdStream = &DestIds; - DestTypeStream = &DestTypes; - UseGlobalHashes = false; - auto Err = doit(IdsAndTypes); - S = PCHSignature; - return Err; -} - -// Global hashing entry points -Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest, - const CVTypeArray &Types, - ArrayRef<GloballyHashedType> Hashes, - Optional<uint32_t> &S) { - DestGlobalTypeStream = &Dest; - UseGlobalHashes = true; - GlobalHashes = Hashes; - auto Err = doit(Types); - S = PCHSignature; - return Err; -} - -Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest, - ArrayRef<TypeIndex> TypeSourceToDest, - const CVTypeArray &Ids, - ArrayRef<GloballyHashedType> Hashes) { - DestGlobalIdStream = &Dest; - TypeLookup = TypeSourceToDest; - UseGlobalHashes = true; - GlobalHashes = Hashes; - - return doit(Ids); -} - -Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, - GlobalTypeTableBuilder &DestTypes, - const CVTypeArray &IdsAndTypes, - ArrayRef<GloballyHashedType> Hashes, - Optional<uint32_t> &S) { - DestGlobalIdStream = &DestIds; - DestGlobalTypeStream = &DestTypes; - UseGlobalHashes = true; - GlobalHashes = Hashes; - auto Err = doit(IdsAndTypes); - S = PCHSignature; - return Err; -} - -Error TypeStreamMerger::doit(const CVTypeArray &Types) { - if (auto EC = remapAllTypes(Types)) - return EC; - - // If we found bad indices but no other errors, try doing another pass and see - // if we can resolve the indices that weren't in the map on the first pass. - // This may require multiple passes, but we should always make progress. MASM - // is the only known CodeView producer that makes type streams that aren't - // topologically sorted. The standard library contains MASM-produced objects, - // so this is important to handle correctly, but we don't have to be too - // efficient. MASM type streams are usually very small. - while (!LastError && NumBadIndices > 0) { - unsigned BadIndicesRemaining = NumBadIndices; - IsSecondPass = true; - NumBadIndices = 0; - CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); - - if (auto EC = remapAllTypes(Types)) - return EC; - - assert(NumBadIndices <= BadIndicesRemaining && - "second pass found more bad indices"); - if (!LastError && NumBadIndices == BadIndicesRemaining) { - return llvm::make_error<CodeViewError>( - cv_error_code::corrupt_record, "Input type graph contains cycles"); - } - } - - if (LastError) - return std::move(*LastError); - return Error::success(); -} - -Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) { - BinaryStreamRef Stream = Types.getUnderlyingStream(); - ArrayRef<uint8_t> Buffer; - cantFail(Stream.readBytes(0, Stream.getLength(), Buffer)); - - return forEachCodeViewRecord<CVType>( - Buffer, [this](const CVType &T) { return remapType(T); }); -} - -Error TypeStreamMerger::remapType(const CVType &Type) { - auto R = shouldRemapType(Type); - if (!R) - return R.takeError(); - - TypeIndex DestIdx = Untranslated; - if (*R) { - auto DoSerialize = - [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> { - return remapIndices(Type, Storage); - }; - unsigned AlignedSize = alignTo(Type.RecordData.size(), 4); - - if (LLVM_LIKELY(UseGlobalHashes)) { - GlobalTypeTableBuilder &Dest = - isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream; - GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()]; - DestIdx = Dest.insertRecordAs(H, AlignedSize, DoSerialize); - } else { - MergingTypeTableBuilder &Dest = - isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; - - RemapStorage.resize(AlignedSize); - ArrayRef<uint8_t> Result = DoSerialize(RemapStorage); - if (!Result.empty()) - DestIdx = Dest.insertRecordBytes(Result); - } - } - addMapping(DestIdx); - - ++CurIndex; - assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) && - "visitKnownRecord should add one index map entry"); - return Error::success(); -} - -ArrayRef<uint8_t> -TypeStreamMerger::remapIndices(const CVType &OriginalType, - MutableArrayRef<uint8_t> Storage) { - unsigned Align = OriginalType.RecordData.size() & 3; - assert(Storage.size() == alignTo(OriginalType.RecordData.size(), 4) && - "The storage buffer size is not a multiple of 4 bytes which will " - "cause misalignment in the output TPI stream!"); - - SmallVector<TiReference, 4> Refs; - discoverTypeIndices(OriginalType.RecordData, Refs); - if (Refs.empty() && Align == 0) - return OriginalType.RecordData; - - ::memcpy(Storage.data(), OriginalType.RecordData.data(), - OriginalType.RecordData.size()); - - uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix); - - for (auto &Ref : Refs) { - TypeIndex *DestTIs = - reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset); - - for (size_t I = 0; I < Ref.Count; ++I) { - TypeIndex &TI = DestTIs[I]; - bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI) - : remapTypeIndex(TI); - if (LLVM_UNLIKELY(!Success)) - return {}; - } - } - - if (Align > 0) { - RecordPrefix *StorageHeader = - reinterpret_cast<RecordPrefix *>(Storage.data()); - StorageHeader->RecordLen += 4 - Align; - - DestContent = Storage.data() + OriginalType.RecordData.size(); - for (; Align < 4; ++Align) - *DestContent++ = LF_PAD4 - Align; - } - return Storage; -} - -Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest, - SmallVectorImpl<TypeIndex> &SourceToDest, - const CVTypeArray &Types) { - TypeStreamMerger M(SourceToDest); - return M.mergeTypeRecords(Dest, Types); -} - -Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest, - ArrayRef<TypeIndex> TypeSourceToDest, - SmallVectorImpl<TypeIndex> &SourceToDest, - const CVTypeArray &Ids) { - TypeStreamMerger M(SourceToDest); - return M.mergeIdRecords(Dest, TypeSourceToDest, Ids); -} - -Error llvm::codeview::mergeTypeAndIdRecords( - MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, - SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, - Optional<uint32_t> &PCHSignature) { - TypeStreamMerger M(SourceToDest); - return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHSignature); -} - -Error llvm::codeview::mergeTypeAndIdRecords( - GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, - SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, - ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) { - TypeStreamMerger M(SourceToDest); - return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes, - PCHSignature); -} - -Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest, - SmallVectorImpl<TypeIndex> &SourceToDest, - const CVTypeArray &Types, - ArrayRef<GloballyHashedType> Hashes, - Optional<uint32_t> &PCHSignature) { - TypeStreamMerger M(SourceToDest); - return M.mergeTypeRecords(Dest, Types, Hashes, PCHSignature); -} - -Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest, - ArrayRef<TypeIndex> Types, - SmallVectorImpl<TypeIndex> &SourceToDest, - const CVTypeArray &Ids, - ArrayRef<GloballyHashedType> Hashes) { - TypeStreamMerger M(SourceToDest); - return M.mergeIdRecords(Dest, Types, Ids, Hashes); -} - -Expected<bool> TypeStreamMerger::shouldRemapType(const CVType &Type) { - // For object files containing precompiled types, we need to extract the - // signature, through EndPrecompRecord. This is done here for performance - // reasons, to avoid re-parsing the Types stream. - if (Type.kind() == LF_ENDPRECOMP) { - EndPrecompRecord EP; - if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), - EP)) - return joinErrors(std::move(EC), errorCorruptRecord()); - if (PCHSignature.hasValue()) - return errorCorruptRecord(); - PCHSignature.emplace(EP.getSignature()); - return false; - } - return true; -} +/// the type graph of the source program are resolved with forward declarations +/// of composite types. This class implements the following type stream merging +/// algorithm, which relies on this DAG structure: +/// +/// - Begin with a new empty stream, and a new empty hash table that maps from +/// type record contents to new type index. +/// - For each new type stream, maintain a map from source type index to +/// destination type index. +/// - For each record, copy it and rewrite its type indices to be valid in the +/// destination type stream. +/// - If the new type record is not already present in the destination stream +/// hash table, append it to the destination type stream, assign it the next +/// type index, and update the two hash tables. +/// - If the type record already exists in the destination stream, discard it +/// and update the type index map to forward the source type index to the +/// existing destination type index. +/// +/// As an additional complication, type stream merging actually produces two +/// streams: an item (or IPI) stream and a type stream, as this is what is +/// actually stored in the final PDB. We choose which records go where by +/// looking at the record kind. +class TypeStreamMerger { +public: + explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest) + : IndexMap(SourceToDest) { + // When dealing with precompiled headers objects, all data in SourceToDest + // belongs to the precompiled headers object, and is assumed to be already + // remapped to the target PDB. Any forthcoming type that will be merged in + // might potentially back-reference this data. We also don't want to resolve + // twice the types in the precompiled object. + CurIndex += SourceToDest.size(); + } + + static const TypeIndex Untranslated; + + // Local hashing entry points + Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds, + MergingTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S); + Error mergeIdRecords(MergingTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids); + Error mergeTypeRecords(MergingTypeTableBuilder &Dest, + const CVTypeArray &Types); + + // Global hashing entry points + Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, + GlobalTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes, + Optional<uint32_t> &S); + Error mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes); + Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes, + Optional<uint32_t> &S); + +private: + Error doit(const CVTypeArray &Types); + + Error remapAllTypes(const CVTypeArray &Types); + + Error remapType(const CVType &Type); + + void addMapping(TypeIndex Idx); + + inline bool remapTypeIndex(TypeIndex &Idx) { + // If we're mapping a pure index stream, then IndexMap only contains + // mappings from OldIdStream -> NewIdStream, in which case we will need to + // use the special mapping from OldTypeStream -> NewTypeStream which was + // computed externally. Regardless, we use this special map if and only if + // we are doing an id-only mapping. + if (!hasTypeStream()) + return remapIndex(Idx, TypeLookup); + + assert(TypeLookup.empty()); + return remapIndex(Idx, IndexMap); + } + inline bool remapItemIndex(TypeIndex &Idx) { + assert(hasIdStream()); + return remapIndex(Idx, IndexMap); + } + + bool hasTypeStream() const { + return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream); + } + + bool hasIdStream() const { + return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream); + } + + ArrayRef<uint8_t> remapIndices(const CVType &OriginalType, + MutableArrayRef<uint8_t> Storage); + + inline bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) { + if (LLVM_LIKELY(remapIndexSimple(Idx, Map))) + return true; + + return remapIndexFallback(Idx, Map); + } + + inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef<TypeIndex> Map) const { + // Simple types are unchanged. + if (Idx.isSimple()) + return true; + + // Check if this type index refers to a record we've already translated + // successfully. If it refers to a type later in the stream or a record we + // had to defer, defer it until later pass. + unsigned MapPos = slotForIndex(Idx); + if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated)) + return false; + + Idx = Map[MapPos]; + return true; + } + + bool remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map); + + Error errorCorruptRecord() const { + return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); + } + + Expected<bool> shouldRemapType(const CVType &Type); + + Optional<Error> LastError; + + bool UseGlobalHashes = false; + + bool IsSecondPass = false; + + unsigned NumBadIndices = 0; + + TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; + + MergingTypeTableBuilder *DestIdStream = nullptr; + MergingTypeTableBuilder *DestTypeStream = nullptr; + + GlobalTypeTableBuilder *DestGlobalIdStream = nullptr; + GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr; + + ArrayRef<GloballyHashedType> GlobalHashes; + + // If we're only mapping id records, this array contains the mapping for + // type records. + ArrayRef<TypeIndex> TypeLookup; + + /// Map from source type index to destination type index. Indexed by source + /// type index minus 0x1000. + SmallVectorImpl<TypeIndex> &IndexMap; + + /// Temporary storage that we use to copy a record's data while re-writing + /// its type indices. + SmallVector<uint8_t, 256> RemapStorage; + + Optional<uint32_t> PCHSignature; +}; + +} // end anonymous namespace + +const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); + +void TypeStreamMerger::addMapping(TypeIndex Idx) { + if (!IsSecondPass) { + assert(IndexMap.size() == slotForIndex(CurIndex) && + "visitKnownRecord should add one index map entry"); + IndexMap.push_back(Idx); + } else { + assert(slotForIndex(CurIndex) < IndexMap.size()); + IndexMap[slotForIndex(CurIndex)] = Idx; + } +} + +bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx, + ArrayRef<TypeIndex> Map) { + size_t MapPos = slotForIndex(Idx); + + // If this is the second pass and this index isn't in the map, then it points + // outside the current type stream, and this is a corrupt record. + if (IsSecondPass && MapPos >= Map.size()) { + // FIXME: Print a more useful error. We can give the current record and the + // index that we think its pointing to. + if (LastError) + LastError = joinErrors(std::move(*LastError), errorCorruptRecord()); + else + LastError = errorCorruptRecord(); + } + + ++NumBadIndices; + + // This type index is invalid. Remap this to "not translated by cvpack", + // and return failure. + Idx = Untranslated; + return false; +} + +// Local hashing entry points +Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest, + const CVTypeArray &Types) { + DestTypeStream = &Dest; + UseGlobalHashes = false; + + return doit(Types); +} + +Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids) { + DestIdStream = &Dest; + TypeLookup = TypeSourceToDest; + UseGlobalHashes = false; + + return doit(Ids); +} + +Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds, + MergingTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, + Optional<uint32_t> &S) { + DestIdStream = &DestIds; + DestTypeStream = &DestTypes; + UseGlobalHashes = false; + auto Err = doit(IdsAndTypes); + S = PCHSignature; + return Err; +} + +// Global hashing entry points +Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest, + const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes, + Optional<uint32_t> &S) { + DestGlobalTypeStream = &Dest; + UseGlobalHashes = true; + GlobalHashes = Hashes; + auto Err = doit(Types); + S = PCHSignature; + return Err; +} + +Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes) { + DestGlobalIdStream = &Dest; + TypeLookup = TypeSourceToDest; + UseGlobalHashes = true; + GlobalHashes = Hashes; + + return doit(Ids); +} + +Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, + GlobalTypeTableBuilder &DestTypes, + const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes, + Optional<uint32_t> &S) { + DestGlobalIdStream = &DestIds; + DestGlobalTypeStream = &DestTypes; + UseGlobalHashes = true; + GlobalHashes = Hashes; + auto Err = doit(IdsAndTypes); + S = PCHSignature; + return Err; +} + +Error TypeStreamMerger::doit(const CVTypeArray &Types) { + if (auto EC = remapAllTypes(Types)) + return EC; + + // If we found bad indices but no other errors, try doing another pass and see + // if we can resolve the indices that weren't in the map on the first pass. + // This may require multiple passes, but we should always make progress. MASM + // is the only known CodeView producer that makes type streams that aren't + // topologically sorted. The standard library contains MASM-produced objects, + // so this is important to handle correctly, but we don't have to be too + // efficient. MASM type streams are usually very small. + while (!LastError && NumBadIndices > 0) { + unsigned BadIndicesRemaining = NumBadIndices; + IsSecondPass = true; + NumBadIndices = 0; + CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); + + if (auto EC = remapAllTypes(Types)) + return EC; + + assert(NumBadIndices <= BadIndicesRemaining && + "second pass found more bad indices"); + if (!LastError && NumBadIndices == BadIndicesRemaining) { + return llvm::make_error<CodeViewError>( + cv_error_code::corrupt_record, "Input type graph contains cycles"); + } + } + + if (LastError) + return std::move(*LastError); + return Error::success(); +} + +Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) { + BinaryStreamRef Stream = Types.getUnderlyingStream(); + ArrayRef<uint8_t> Buffer; + cantFail(Stream.readBytes(0, Stream.getLength(), Buffer)); + + return forEachCodeViewRecord<CVType>( + Buffer, [this](const CVType &T) { return remapType(T); }); +} + +Error TypeStreamMerger::remapType(const CVType &Type) { + auto R = shouldRemapType(Type); + if (!R) + return R.takeError(); + + TypeIndex DestIdx = Untranslated; + if (*R) { + auto DoSerialize = + [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> { + return remapIndices(Type, Storage); + }; + unsigned AlignedSize = alignTo(Type.RecordData.size(), 4); + + if (LLVM_LIKELY(UseGlobalHashes)) { + GlobalTypeTableBuilder &Dest = + isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream; + GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()]; + DestIdx = Dest.insertRecordAs(H, AlignedSize, DoSerialize); + } else { + MergingTypeTableBuilder &Dest = + isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; + + RemapStorage.resize(AlignedSize); + ArrayRef<uint8_t> Result = DoSerialize(RemapStorage); + if (!Result.empty()) + DestIdx = Dest.insertRecordBytes(Result); + } + } + addMapping(DestIdx); + + ++CurIndex; + assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) && + "visitKnownRecord should add one index map entry"); + return Error::success(); +} + +ArrayRef<uint8_t> +TypeStreamMerger::remapIndices(const CVType &OriginalType, + MutableArrayRef<uint8_t> Storage) { + unsigned Align = OriginalType.RecordData.size() & 3; + assert(Storage.size() == alignTo(OriginalType.RecordData.size(), 4) && + "The storage buffer size is not a multiple of 4 bytes which will " + "cause misalignment in the output TPI stream!"); + + SmallVector<TiReference, 4> Refs; + discoverTypeIndices(OriginalType.RecordData, Refs); + if (Refs.empty() && Align == 0) + return OriginalType.RecordData; + + ::memcpy(Storage.data(), OriginalType.RecordData.data(), + OriginalType.RecordData.size()); + + uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix); + + for (auto &Ref : Refs) { + TypeIndex *DestTIs = + reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset); + + for (size_t I = 0; I < Ref.Count; ++I) { + TypeIndex &TI = DestTIs[I]; + bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI) + : remapTypeIndex(TI); + if (LLVM_UNLIKELY(!Success)) + return {}; + } + } + + if (Align > 0) { + RecordPrefix *StorageHeader = + reinterpret_cast<RecordPrefix *>(Storage.data()); + StorageHeader->RecordLen += 4 - Align; + + DestContent = Storage.data() + OriginalType.RecordData.size(); + for (; Align < 4; ++Align) + *DestContent++ = LF_PAD4 - Align; + } + return Storage; +} + +Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Types) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypeRecords(Dest, Types); +} + +Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest, + ArrayRef<TypeIndex> TypeSourceToDest, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Ids) { + TypeStreamMerger M(SourceToDest); + return M.mergeIdRecords(Dest, TypeSourceToDest, Ids); +} + +Error llvm::codeview::mergeTypeAndIdRecords( + MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, + SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, + Optional<uint32_t> &PCHSignature) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHSignature); +} + +Error llvm::codeview::mergeTypeAndIdRecords( + GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, + SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, + ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes, + PCHSignature); +} + +Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Types, + ArrayRef<GloballyHashedType> Hashes, + Optional<uint32_t> &PCHSignature) { + TypeStreamMerger M(SourceToDest); + return M.mergeTypeRecords(Dest, Types, Hashes, PCHSignature); +} + +Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest, + ArrayRef<TypeIndex> Types, + SmallVectorImpl<TypeIndex> &SourceToDest, + const CVTypeArray &Ids, + ArrayRef<GloballyHashedType> Hashes) { + TypeStreamMerger M(SourceToDest); + return M.mergeIdRecords(Dest, Types, Ids, Hashes); +} + +Expected<bool> TypeStreamMerger::shouldRemapType(const CVType &Type) { + // For object files containing precompiled types, we need to extract the + // signature, through EndPrecompRecord. This is done here for performance + // reasons, to avoid re-parsing the Types stream. + if (Type.kind() == LF_ENDPRECOMP) { + EndPrecompRecord EP; + if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), + EP)) + return joinErrors(std::move(EC), errorCorruptRecord()); + if (PCHSignature.hasValue()) + return errorCorruptRecord(); + PCHSignature.emplace(EP.getSignature()); + return false; + } + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeTableCollection.cpp index e517e8846d..fb2ceda9c1 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeTableCollection.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/TypeTableCollection.cpp @@ -1,65 +1,65 @@ -//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeTableCollection.h" - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/Support/BinaryStreamReader.h" - -using namespace llvm; -using namespace llvm::codeview; - -TypeTableCollection::TypeTableCollection(ArrayRef<ArrayRef<uint8_t>> Records) - : NameStorage(Allocator), Records(Records) { - Names.resize(Records.size()); -} - -Optional<TypeIndex> TypeTableCollection::getFirst() { - if (empty()) - return None; - return TypeIndex::fromArrayIndex(0); -} - -Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) { - assert(contains(Prev)); - ++Prev; - if (Prev.toArrayIndex() == size()) - return None; - return Prev; -} - -CVType TypeTableCollection::getType(TypeIndex Index) { - assert(Index.toArrayIndex() < Records.size()); - return CVType(Records[Index.toArrayIndex()]); -} - -StringRef TypeTableCollection::getTypeName(TypeIndex Index) { - if (Index.isNoneType() || Index.isSimple()) - return TypeIndex::simpleTypeName(Index); - - uint32_t I = Index.toArrayIndex(); - if (Names[I].data() == nullptr) { - StringRef Result = NameStorage.save(computeTypeName(*this, Index)); - Names[I] = Result; - } - return Names[I]; -} - -bool TypeTableCollection::contains(TypeIndex Index) { - return Index.toArrayIndex() <= size(); -} - -uint32_t TypeTableCollection::size() { return Records.size(); } - -uint32_t TypeTableCollection::capacity() { return Records.size(); } - -bool TypeTableCollection::replaceType(TypeIndex &Index, CVType Data, - bool Stabilize) { - llvm_unreachable("Method cannot be called"); -} +//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeTableCollection.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; + +TypeTableCollection::TypeTableCollection(ArrayRef<ArrayRef<uint8_t>> Records) + : NameStorage(Allocator), Records(Records) { + Names.resize(Records.size()); +} + +Optional<TypeIndex> TypeTableCollection::getFirst() { + if (empty()) + return None; + return TypeIndex::fromArrayIndex(0); +} + +Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) { + assert(contains(Prev)); + ++Prev; + if (Prev.toArrayIndex() == size()) + return None; + return Prev; +} + +CVType TypeTableCollection::getType(TypeIndex Index) { + assert(Index.toArrayIndex() < Records.size()); + return CVType(Records[Index.toArrayIndex()]); +} + +StringRef TypeTableCollection::getTypeName(TypeIndex Index) { + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); + + uint32_t I = Index.toArrayIndex(); + if (Names[I].data() == nullptr) { + StringRef Result = NameStorage.save(computeTypeName(*this, Index)); + Names[I] = Result; + } + return Names[I]; +} + +bool TypeTableCollection::contains(TypeIndex Index) { + return Index.toArrayIndex() <= size(); +} + +uint32_t TypeTableCollection::size() { return Records.size(); } + +uint32_t TypeTableCollection::capacity() { return Records.size(); } + +bool TypeTableCollection::replaceType(TypeIndex &Index, CVType Data, + bool Stabilize) { + llvm_unreachable("Method cannot be called"); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/CodeView/ya.make b/contrib/libs/llvm12/lib/DebugInfo/CodeView/ya.make index 8829a8f09f..b099dd11da 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/CodeView/ya.make +++ b/contrib/libs/llvm12/lib/DebugInfo/CodeView/ya.make @@ -1,71 +1,71 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/DebugInfo/MSF contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/DebugInfo/CodeView ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - AppendingTypeTableBuilder.cpp - CVSymbolVisitor.cpp - CVTypeVisitor.cpp - CodeViewError.cpp - CodeViewRecordIO.cpp - ContinuationRecordBuilder.cpp - DebugChecksumsSubsection.cpp - DebugCrossExSubsection.cpp - DebugCrossImpSubsection.cpp - DebugFrameDataSubsection.cpp - DebugInlineeLinesSubsection.cpp - DebugLinesSubsection.cpp - DebugStringTableSubsection.cpp - DebugSubsection.cpp - DebugSubsectionRecord.cpp - DebugSubsectionVisitor.cpp - DebugSymbolRVASubsection.cpp - DebugSymbolsSubsection.cpp - EnumTables.cpp - Formatters.cpp - GlobalTypeTableBuilder.cpp - LazyRandomTypeCollection.cpp - Line.cpp - MergingTypeTableBuilder.cpp - RecordName.cpp - RecordSerialization.cpp - SimpleTypeSerializer.cpp - StringsAndChecksums.cpp - SymbolDumper.cpp - SymbolRecordHelpers.cpp - SymbolRecordMapping.cpp - SymbolSerializer.cpp - TypeDumpVisitor.cpp - TypeHashing.cpp - TypeIndex.cpp - TypeIndexDiscovery.cpp - TypeRecordHelpers.cpp - TypeRecordMapping.cpp - TypeStreamMerger.cpp - TypeTableCollection.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + AppendingTypeTableBuilder.cpp + CVSymbolVisitor.cpp + CVTypeVisitor.cpp + CodeViewError.cpp + CodeViewRecordIO.cpp + ContinuationRecordBuilder.cpp + DebugChecksumsSubsection.cpp + DebugCrossExSubsection.cpp + DebugCrossImpSubsection.cpp + DebugFrameDataSubsection.cpp + DebugInlineeLinesSubsection.cpp + DebugLinesSubsection.cpp + DebugStringTableSubsection.cpp + DebugSubsection.cpp + DebugSubsectionRecord.cpp + DebugSubsectionVisitor.cpp + DebugSymbolRVASubsection.cpp + DebugSymbolsSubsection.cpp + EnumTables.cpp + Formatters.cpp + GlobalTypeTableBuilder.cpp + LazyRandomTypeCollection.cpp + Line.cpp + MergingTypeTableBuilder.cpp + RecordName.cpp + RecordSerialization.cpp + SimpleTypeSerializer.cpp + StringsAndChecksums.cpp + SymbolDumper.cpp + SymbolRecordHelpers.cpp + SymbolRecordMapping.cpp + SymbolSerializer.cpp + TypeDumpVisitor.cpp + TypeHashing.cpp + TypeIndex.cpp + TypeIndexDiscovery.cpp + TypeRecordHelpers.cpp + TypeRecordMapping.cpp + TypeStreamMerger.cpp + TypeTableCollection.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index ee1ff5460b..ef0711fb9a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -1,215 +1,215 @@ -//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" - -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include <cstddef> -#include <cstdint> - -using namespace llvm; -using namespace dwarf; - -void DWARFAbbreviationDeclaration::clear() { - Code = 0; - Tag = DW_TAG_null; - CodeByteSize = 0; - HasChildren = false; - AttributeSpecs.clear(); - FixedAttributeSize.reset(); -} - -DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { - clear(); -} - -bool -DWARFAbbreviationDeclaration::extract(DataExtractor Data, - uint64_t* OffsetPtr) { - clear(); - const uint64_t Offset = *OffsetPtr; - Code = Data.getULEB128(OffsetPtr); - if (Code == 0) { - return false; - } - 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) { - auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); - auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); - if (A && F) { - bool IsImplicitConst = (F == DW_FORM_implicit_const); - if (IsImplicitConst) { - int64_t V = Data.getSLEB128(OffsetPtr); - AttributeSpecs.push_back(AttributeSpec(A, F, V)); - continue; - } - Optional<uint8_t> ByteSize; - // If this abbrevation still has a fixed byte size, then update the - // FixedAttributeSize as needed. - switch (F) { - case DW_FORM_addr: - if (FixedAttributeSize) - ++FixedAttributeSize->NumAddrs; - break; - - case DW_FORM_ref_addr: - if (FixedAttributeSize) - ++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: - if (FixedAttributeSize) - ++FixedAttributeSize->NumDwarfOffsets; - break; - - default: - // The form has a byte size that doesn't depend on Params. - // If it's a fixed size, keep track of it. - if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) { - if (FixedAttributeSize) - FixedAttributeSize->NumBytes += *ByteSize; - break; - } - // 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; - } - // Record this attribute and its fixed size if it has one. - AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); - } 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; - } - } - return true; -} - -void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { - OS << '[' << getCode() << "] "; - OS << formatv("{0}", getTag()); - OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; - for (const AttributeSpec &Spec : AttributeSpecs) { - OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); - if (Spec.isImplicitConst()) - OS << '\t' << Spec.getImplicitConstValue(); - OS << '\n'; - } - OS << '\n'; -} - -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) - return i; - } - return None; -} - -Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( - const uint64_t DIEOffset, const dwarf::Attribute Attr, - const DWARFUnit &U) const { - // Check if this abbreviation has this attribute without needing to skip - // any data so we can return quickly if it doesn't. - 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. - uint64_t Offset = DIEOffset + CodeByteSize; - for (uint32_t CurAttrIdx = 0; CurAttrIdx != *MatchAttrIndex; ++CurAttrIdx) - // Match Offset along until we get to the attribute we want. - if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U)) - Offset += *FixedSize; - else - DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, - &Offset, U.getFormParams()); - - // We have arrived at the attribute to extract, extract if from Offset. - const AttributeSpec &Spec = AttributeSpecs[*MatchAttrIndex]; - if (Spec.isImplicitConst()) - return DWARFFormValue::createFromSValue(Spec.Form, - Spec.getImplicitConstValue()); - - DWARFFormValue FormValue(Spec.Form); - if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) - return FormValue; - - 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 (ByteSize.HasByteSize) - return ByteSize.ByteSize; - Optional<int64_t> S; - auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); - if (FixedByteSize) - S = *FixedByteSize; - return S; -} - -Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize( - const DWARFUnit &U) const { - if (FixedAttributeSize) - return FixedAttributeSize->getByteSize(U); - return None; -} +//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" + +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> + +using namespace llvm; +using namespace dwarf; + +void DWARFAbbreviationDeclaration::clear() { + Code = 0; + Tag = DW_TAG_null; + CodeByteSize = 0; + HasChildren = false; + AttributeSpecs.clear(); + FixedAttributeSize.reset(); +} + +DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() { + clear(); +} + +bool +DWARFAbbreviationDeclaration::extract(DataExtractor Data, + uint64_t* OffsetPtr) { + clear(); + const uint64_t Offset = *OffsetPtr; + Code = Data.getULEB128(OffsetPtr); + if (Code == 0) { + return false; + } + 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) { + auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr)); + auto F = static_cast<Form>(Data.getULEB128(OffsetPtr)); + if (A && F) { + bool IsImplicitConst = (F == DW_FORM_implicit_const); + if (IsImplicitConst) { + int64_t V = Data.getSLEB128(OffsetPtr); + AttributeSpecs.push_back(AttributeSpec(A, F, V)); + continue; + } + Optional<uint8_t> ByteSize; + // If this abbrevation still has a fixed byte size, then update the + // FixedAttributeSize as needed. + switch (F) { + case DW_FORM_addr: + if (FixedAttributeSize) + ++FixedAttributeSize->NumAddrs; + break; + + case DW_FORM_ref_addr: + if (FixedAttributeSize) + ++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: + if (FixedAttributeSize) + ++FixedAttributeSize->NumDwarfOffsets; + break; + + default: + // The form has a byte size that doesn't depend on Params. + // If it's a fixed size, keep track of it. + if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) { + if (FixedAttributeSize) + FixedAttributeSize->NumBytes += *ByteSize; + break; + } + // 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; + } + // Record this attribute and its fixed size if it has one. + AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize)); + } 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; + } + } + return true; +} + +void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const { + OS << '[' << getCode() << "] "; + OS << formatv("{0}", getTag()); + OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n'; + for (const AttributeSpec &Spec : AttributeSpecs) { + OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form); + if (Spec.isImplicitConst()) + OS << '\t' << Spec.getImplicitConstValue(); + OS << '\n'; + } + OS << '\n'; +} + +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) + return i; + } + return None; +} + +Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue( + const uint64_t DIEOffset, const dwarf::Attribute Attr, + const DWARFUnit &U) const { + // Check if this abbreviation has this attribute without needing to skip + // any data so we can return quickly if it doesn't. + 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. + uint64_t Offset = DIEOffset + CodeByteSize; + for (uint32_t CurAttrIdx = 0; CurAttrIdx != *MatchAttrIndex; ++CurAttrIdx) + // Match Offset along until we get to the attribute we want. + if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U)) + Offset += *FixedSize; + else + DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData, + &Offset, U.getFormParams()); + + // We have arrived at the attribute to extract, extract if from Offset. + const AttributeSpec &Spec = AttributeSpecs[*MatchAttrIndex]; + if (Spec.isImplicitConst()) + return DWARFFormValue::createFromSValue(Spec.Form, + Spec.getImplicitConstValue()); + + DWARFFormValue FormValue(Spec.Form); + if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U)) + return FormValue; + + 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 (ByteSize.HasByteSize) + return ByteSize.ByteSize; + Optional<int64_t> S; + auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams()); + 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/libs/llvm12/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 28d35b609c..88566eecd5 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -1,905 +1,905 @@ -//===- DWARFAcceleratorTable.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DJB.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/raw_ostream.h" -#include <cstddef> -#include <cstdint> -#include <utility> - -using namespace llvm; - -namespace { -struct Atom { - unsigned Value; -}; - -static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { - StringRef Str = dwarf::AtomTypeString(A.Value); - if (!Str.empty()) - return OS << Str; - return OS << "DW_ATOM_unknown_" << format("%x", A.Value); -} -} // namespace - -static Atom formatAtom(unsigned Atom) { return {Atom}; } - -DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; - -Error AppleAcceleratorTable::extract() { - uint64_t Offset = 0; - - // Check that we can at least read the header. - if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4)) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read header."); - - Hdr.Magic = AccelSection.getU32(&Offset); - Hdr.Version = AccelSection.getU16(&Offset); - Hdr.HashFunction = AccelSection.getU16(&Offset); - Hdr.BucketCount = AccelSection.getU32(&Offset); - Hdr.HashCount = AccelSection.getU32(&Offset); - Hdr.HeaderDataLength = AccelSection.getU32(&Offset); - - // Check that we can read all the hashes and offsets from the - // section (see SourceLevelDebugging.rst for the structure of the index). - // We need to substract one because we're checking for an *offset* which is - // equal to the size for an empty table and hence pointer after the section. - if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + - Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1)) - return createStringError( - errc::illegal_byte_sequence, - "Section too small: cannot read buckets and hashes."); - - HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); - uint32_t NumAtoms = AccelSection.getU32(&Offset); - - for (unsigned i = 0; i < NumAtoms; ++i) { - uint16_t AtomType = AccelSection.getU16(&Offset); - auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); - HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); - } - - IsValid = true; - return Error::success(); -} - -uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; } -uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; } -uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } -uint32_t AppleAcceleratorTable::getHeaderDataLength() { - return Hdr.HeaderDataLength; -} - -ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType, - AppleAcceleratorTable::HeaderData::Form>> -AppleAcceleratorTable::getAtomsDesc() { - return HdrData.Atoms; -} - -bool AppleAcceleratorTable::validateForms() { - for (auto Atom : getAtomsDesc()) { - DWARFFormValue FormValue(Atom.second); - switch (Atom.first) { - case dwarf::DW_ATOM_die_offset: - case dwarf::DW_ATOM_die_tag: - case dwarf::DW_ATOM_type_flags: - if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && - !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || - FormValue.getForm() == dwarf::DW_FORM_sdata) - return false; - break; - default: - break; - } - } - return true; -} - -std::pair<uint64_t, dwarf::Tag> -AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) { - uint64_t DieOffset = dwarf::DW_INVALID_OFFSET; - dwarf::Tag DieTag = dwarf::DW_TAG_null; - dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; - - for (auto Atom : getAtomsDesc()) { - DWARFFormValue FormValue(Atom.second); - FormValue.extractValue(AccelSection, HashDataOffset, FormParams); - switch (Atom.first) { - case dwarf::DW_ATOM_die_offset: - DieOffset = *FormValue.getAsUnsignedConstant(); - break; - case dwarf::DW_ATOM_die_tag: - DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); - break; - default: - break; - } - } - return {DieOffset, DieTag}; -} - -void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const { - DictScope HeaderScope(W, "Header"); - W.printHex("Magic", Magic); - W.printHex("Version", Version); - W.printHex("Hash function", HashFunction); - W.printNumber("Bucket count", BucketCount); - W.printNumber("Hashes count", HashCount); - W.printNumber("HeaderData length", HeaderDataLength); -} - -Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset( - Optional<DWARFFormValue> Value) const { - if (!Value) - return None; - - switch (Value->getForm()) { - case dwarf::DW_FORM_ref1: - case dwarf::DW_FORM_ref2: - case dwarf::DW_FORM_ref4: - case dwarf::DW_FORM_ref8: - case dwarf::DW_FORM_ref_udata: - return Value->getRawUValue() + DIEOffsetBase; - default: - return Value->getAsSectionOffset(); - } -} - -bool AppleAcceleratorTable::dumpName(ScopedPrinter &W, - SmallVectorImpl<DWARFFormValue> &AtomForms, - uint64_t *DataOffset) const { - dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; - uint64_t NameOffset = *DataOffset; - if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) { - W.printString("Incorrectly terminated list."); - return false; - } - uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset); - if (!StringOffset) - return false; // End of list - - DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str()); - W.startLine() << format("String: 0x%08" PRIx64, StringOffset); - W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n"; - - unsigned NumData = AccelSection.getU32(DataOffset); - for (unsigned Data = 0; Data < NumData; ++Data) { - ListScope DataScope(W, ("Data " + Twine(Data)).str()); - unsigned i = 0; - for (auto &Atom : AtomForms) { - W.startLine() << format("Atom[%d]: ", i); - if (Atom.extractValue(AccelSection, DataOffset, FormParams)) { - Atom.dump(W.getOStream()); - if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) { - StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val); - if (!Str.empty()) - W.getOStream() << " (" << Str << ")"; - } - } else - W.getOStream() << "Error extracting the value"; - W.getOStream() << "\n"; - i++; - } - } - return true; // more entries follow -} - -LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { - if (!IsValid) - return; - - ScopedPrinter W(OS); - - Hdr.dump(W); - - W.printNumber("DIE offset base", HdrData.DIEOffsetBase); - W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size())); - SmallVector<DWARFFormValue, 3> AtomForms; - { - ListScope AtomsScope(W, "Atoms"); - unsigned i = 0; - for (const auto &Atom : HdrData.Atoms) { - DictScope AtomScope(W, ("Atom " + Twine(i++)).str()); - W.startLine() << "Type: " << formatAtom(Atom.first) << '\n'; - W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n'; - AtomForms.push_back(DWARFFormValue(Atom.second)); - } - } - - // Now go through the actual tables and dump them. - uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; - uint64_t HashesBase = Offset + Hdr.BucketCount * 4; - uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; - - for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) { - unsigned Index = AccelSection.getU32(&Offset); - - ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); - if (Index == UINT32_MAX) { - W.printString("EMPTY"); - continue; - } - - for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { - uint64_t HashOffset = HashesBase + HashIdx*4; - uint64_t OffsetsOffset = OffsetsBase + HashIdx*4; - uint32_t Hash = AccelSection.getU32(&HashOffset); - - if (Hash % Hdr.BucketCount != Bucket) - break; - - uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); - ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str()); - if (!AccelSection.isValidOffset(DataOffset)) { - W.printString("Invalid section offset"); - continue; - } - while (dumpName(W, AtomForms, &DataOffset)) - /*empty*/; - } - } -} - -AppleAcceleratorTable::Entry::Entry( - const AppleAcceleratorTable::HeaderData &HdrData) - : HdrData(&HdrData) { - Values.reserve(HdrData.Atoms.size()); - for (const auto &Atom : HdrData.Atoms) - Values.push_back(DWARFFormValue(Atom.second)); -} - -void AppleAcceleratorTable::Entry::extract( - const AppleAcceleratorTable &AccelTable, uint64_t *Offset) { - - dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0, - dwarf::DwarfFormat::DWARF32}; - for (auto &Atom : Values) - Atom.extractValue(AccelTable.AccelSection, Offset, FormParams); -} - -Optional<DWARFFormValue> -AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const { - assert(HdrData && "Dereferencing end iterator?"); - assert(HdrData->Atoms.size() == Values.size()); - for (auto Tuple : zip_first(HdrData->Atoms, Values)) { - if (std::get<0>(Tuple).first == Atom) - return std::get<1>(Tuple); - } - return None; -} - -Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const { - return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset)); -} - -Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const { - return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset)); -} - -Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const { - Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag); - if (!Tag) - return None; - if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant()) - return dwarf::Tag(*Value); - return None; -} - -AppleAcceleratorTable::ValueIterator::ValueIterator( - const AppleAcceleratorTable &AccelTable, uint64_t Offset) - : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) { - if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) - return; - - // Read the first entry. - NumData = AccelTable.AccelSection.getU32(&DataOffset); - Next(); -} - -void AppleAcceleratorTable::ValueIterator::Next() { - assert(NumData > 0 && "attempted to increment iterator past the end"); - auto &AccelSection = AccelTable->AccelSection; - if (Data >= NumData || - !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { - NumData = 0; - DataOffset = 0; - return; - } - Current.extract(*AccelTable, &DataOffset); - ++Data; -} - -iterator_range<AppleAcceleratorTable::ValueIterator> -AppleAcceleratorTable::equal_range(StringRef Key) const { - if (!IsValid) - return make_range(ValueIterator(), ValueIterator()); - - // Find the bucket. - unsigned HashValue = djbHash(Key); - unsigned Bucket = HashValue % Hdr.BucketCount; - uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength; - uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4; - uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; - - uint64_t BucketOffset = BucketBase + Bucket * 4; - unsigned Index = AccelSection.getU32(&BucketOffset); - - // Search through all hashes in the bucket. - for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { - uint64_t HashOffset = HashesBase + HashIdx * 4; - uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4; - uint32_t Hash = AccelSection.getU32(&HashOffset); - - if (Hash % Hdr.BucketCount != Bucket) - // We are already in the next bucket. - break; - - uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); - uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); - if (!StringOffset) - break; - - // Finally, compare the key. - if (Key == StringSection.getCStr(&StringOffset)) - return make_range({*this, DataOffset}, ValueIterator()); - } - return make_range(ValueIterator(), ValueIterator()); -} - -void DWARFDebugNames::Header::dump(ScopedPrinter &W) const { - DictScope HeaderScope(W, "Header"); - W.printHex("Length", UnitLength); - W.printString("Format", dwarf::FormatString(Format)); - W.printNumber("Version", Version); - W.printNumber("CU count", CompUnitCount); - W.printNumber("Local TU count", LocalTypeUnitCount); - W.printNumber("Foreign TU count", ForeignTypeUnitCount); - W.printNumber("Bucket count", BucketCount); - W.printNumber("Name count", NameCount); - W.printHex("Abbreviations table size", AbbrevTableSize); - W.startLine() << "Augmentation: '" << AugmentationString << "'\n"; -} - -Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, - uint64_t *Offset) { - auto HeaderError = [Offset = *Offset](Error E) { - return createStringError(errc::illegal_byte_sequence, - "parsing .debug_names header at 0x%" PRIx64 ": %s", - Offset, toString(std::move(E)).c_str()); - }; - - DataExtractor::Cursor C(*Offset); - std::tie(UnitLength, Format) = AS.getInitialLength(C); - - Version = AS.getU16(C); - AS.skip(C, 2); // padding - CompUnitCount = AS.getU32(C); - LocalTypeUnitCount = AS.getU32(C); - ForeignTypeUnitCount = AS.getU32(C); - BucketCount = AS.getU32(C); - NameCount = AS.getU32(C); - AbbrevTableSize = AS.getU32(C); - AugmentationStringSize = alignTo(AS.getU32(C), 4); - - if (!C) - return HeaderError(C.takeError()); - - if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize)) - return HeaderError(createStringError(errc::illegal_byte_sequence, - "cannot read header augmentation")); - AugmentationString.resize(AugmentationStringSize); - AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()), - AugmentationStringSize); - *Offset = C.tell(); - return C.takeError(); -} - -void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { - DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str()); - W.startLine() << formatv("Tag: {0}\n", Tag); - - for (const auto &Attr : Attributes) - W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form); -} - -static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() { - return {dwarf::Index(0), dwarf::Form(0)}; -} - -static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) { - return AE == sentinelAttrEnc(); -} - -static DWARFDebugNames::Abbrev sentinelAbbrev() { - return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {}); -} - -static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) { - return Abbr.Code == 0; -} - -DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() { - return sentinelAbbrev(); -} - -DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() { - return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {}); -} - -Expected<DWARFDebugNames::AttributeEncoding> -DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) { - if (*Offset >= EntriesBase) { - return createStringError(errc::illegal_byte_sequence, - "Incorrectly terminated abbreviation table."); - } - - uint32_t Index = Section.AccelSection.getULEB128(Offset); - uint32_t Form = Section.AccelSection.getULEB128(Offset); - return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form)); -} - -Expected<std::vector<DWARFDebugNames::AttributeEncoding>> -DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) { - std::vector<AttributeEncoding> Result; - for (;;) { - auto AttrEncOr = extractAttributeEncoding(Offset); - if (!AttrEncOr) - return AttrEncOr.takeError(); - if (isSentinel(*AttrEncOr)) - return std::move(Result); - - Result.emplace_back(*AttrEncOr); - } -} - -Expected<DWARFDebugNames::Abbrev> -DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) { - if (*Offset >= EntriesBase) { - return createStringError(errc::illegal_byte_sequence, - "Incorrectly terminated abbreviation table."); - } - - uint32_t Code = Section.AccelSection.getULEB128(Offset); - if (Code == 0) - return sentinelAbbrev(); - - uint32_t Tag = Section.AccelSection.getULEB128(Offset); - auto AttrEncOr = extractAttributeEncodings(Offset); - if (!AttrEncOr) - return AttrEncOr.takeError(); - return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr)); -} - -Error DWARFDebugNames::NameIndex::extract() { - const DWARFDataExtractor &AS = Section.AccelSection; - uint64_t Offset = Base; - if (Error E = Hdr.extract(AS, &Offset)) - return E; - - const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); - CUsBase = Offset; - Offset += Hdr.CompUnitCount * SectionOffsetSize; - Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize; - Offset += Hdr.ForeignTypeUnitCount * 8; - BucketsBase = Offset; - Offset += Hdr.BucketCount * 4; - HashesBase = Offset; - if (Hdr.BucketCount > 0) - Offset += Hdr.NameCount * 4; - StringOffsetsBase = Offset; - Offset += Hdr.NameCount * SectionOffsetSize; - EntryOffsetsBase = Offset; - Offset += Hdr.NameCount * SectionOffsetSize; - - if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) - return createStringError(errc::illegal_byte_sequence, - "Section too small: cannot read abbreviations."); - - EntriesBase = Offset + Hdr.AbbrevTableSize; - - for (;;) { - auto AbbrevOr = extractAbbrev(&Offset); - if (!AbbrevOr) - return AbbrevOr.takeError(); - if (isSentinel(*AbbrevOr)) - return Error::success(); - - if (!Abbrevs.insert(std::move(*AbbrevOr)).second) - return createStringError(errc::invalid_argument, - "Duplicate abbreviation code."); - } -} - -DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) - : NameIdx(&NameIdx), Abbr(&Abbr) { - // This merely creates form values. It is up to the caller - // (NameIndex::getEntry) to populate them. - Values.reserve(Abbr.Attributes.size()); - for (const auto &Attr : Abbr.Attributes) - Values.emplace_back(Attr.Form); -} - -Optional<DWARFFormValue> -DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { - assert(Abbr->Attributes.size() == Values.size()); - for (auto Tuple : zip_first(Abbr->Attributes, Values)) { - if (std::get<0>(Tuple).Index == Index) - return std::get<1>(Tuple); - } - return None; -} - -Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const { - if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset)) - return Off->getAsReferenceUVal(); - return None; -} - -Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const { - if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit)) - return Off->getAsUnsignedConstant(); - // In a per-CU index, the entries without a DW_IDX_compile_unit attribute - // implicitly refer to the single CU. - if (NameIdx->getCUCount() == 1) - return 0; - return None; -} - -Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const { - Optional<uint64_t> Index = getCUIndex(); - if (!Index || *Index >= NameIdx->getCUCount()) - return None; - return NameIdx->getCUOffset(*Index); -} - -void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { - W.printHex("Abbrev", Abbr->Code); - W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); - assert(Abbr->Attributes.size() == Values.size()); - for (auto Tuple : zip_first(Abbr->Attributes, Values)) { - W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index); - std::get<1>(Tuple).dump(W.getOStream()); - W.getOStream() << '\n'; - } -} - -char DWARFDebugNames::SentinelError::ID; -std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const { - return inconvertibleErrorCode(); -} - -uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const { - assert(CU < Hdr.CompUnitCount); - const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); - uint64_t Offset = CUsBase + SectionOffsetSize * CU; - return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); -} - -uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { - assert(TU < Hdr.LocalTypeUnitCount); - const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); - uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU); - return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); -} - -uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { - assert(TU < Hdr.ForeignTypeUnitCount); - const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); - uint64_t Offset = - CUsBase + - SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; - return Section.AccelSection.getU64(&Offset); -} - -Expected<DWARFDebugNames::Entry> -DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const { - const DWARFDataExtractor &AS = Section.AccelSection; - if (!AS.isValidOffset(*Offset)) - return createStringError(errc::illegal_byte_sequence, - "Incorrectly terminated entry list."); - - uint32_t AbbrevCode = AS.getULEB128(Offset); - if (AbbrevCode == 0) - return make_error<SentinelError>(); - - const auto AbbrevIt = Abbrevs.find_as(AbbrevCode); - if (AbbrevIt == Abbrevs.end()) - return createStringError(errc::invalid_argument, "Invalid abbreviation."); - - Entry E(*this, *AbbrevIt); - - dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format}; - for (auto &Value : E.Values) { - if (!Value.extractValue(AS, Offset, FormParams)) - return createStringError(errc::io_error, - "Error extracting index attribute values."); - } - return std::move(E); -} - -DWARFDebugNames::NameTableEntry -DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const { - assert(0 < Index && Index <= Hdr.NameCount); - const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); - uint64_t StringOffsetOffset = - StringOffsetsBase + SectionOffsetSize * (Index - 1); - uint64_t EntryOffsetOffset = - EntryOffsetsBase + SectionOffsetSize * (Index - 1); - const DWARFDataExtractor &AS = Section.AccelSection; - - uint64_t StringOffset = - AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset); - uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize); - EntryOffset += EntriesBase; - return {Section.StringSection, Index, StringOffset, EntryOffset}; -} - -uint32_t -DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const { - assert(Bucket < Hdr.BucketCount); - uint64_t BucketOffset = BucketsBase + 4 * Bucket; - return Section.AccelSection.getU32(&BucketOffset); -} - -uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const { - assert(0 < Index && Index <= Hdr.NameCount); - uint64_t HashOffset = HashesBase + 4 * (Index - 1); - return Section.AccelSection.getU32(&HashOffset); -} - -// Returns true if we should continue scanning for entries, false if this is the -// last (sentinel) entry). In case of a parsing error we also return false, as -// it's not possible to recover this entry list (but the other lists may still -// parse OK). -bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W, - uint64_t *Offset) const { - uint64_t EntryId = *Offset; - auto EntryOr = getEntry(Offset); - if (!EntryOr) { - handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {}, - [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); }); - return false; - } - - DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str()); - EntryOr->dump(W); - return true; -} - -void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, - const NameTableEntry &NTE, - Optional<uint32_t> Hash) const { - DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str()); - if (Hash) - W.printHex("Hash", *Hash); - - W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset()); - W.getOStream() << " \"" << NTE.getString() << "\"\n"; - - uint64_t EntryOffset = NTE.getEntryOffset(); - while (dumpEntry(W, &EntryOffset)) - /*empty*/; -} - -void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const { - ListScope CUScope(W, "Compilation Unit offsets"); - for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU) - W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU)); -} - -void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const { - if (Hdr.LocalTypeUnitCount == 0) - return; - - ListScope TUScope(W, "Local Type Unit offsets"); - for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU) - W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU, - getLocalTUOffset(TU)); -} - -void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const { - if (Hdr.ForeignTypeUnitCount == 0) - return; - - ListScope TUScope(W, "Foreign Type Unit signatures"); - for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) { - W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU, - getForeignTUSignature(TU)); - } -} - -void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const { - ListScope AbbrevsScope(W, "Abbreviations"); - for (const auto &Abbr : Abbrevs) - Abbr.dump(W); -} - -void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W, - uint32_t Bucket) const { - ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); - uint32_t Index = getBucketArrayEntry(Bucket); - if (Index == 0) { - W.printString("EMPTY"); - return; - } - if (Index > Hdr.NameCount) { - W.printString("Name index is invalid"); - return; - } - - for (; Index <= Hdr.NameCount; ++Index) { - uint32_t Hash = getHashArrayEntry(Index); - if (Hash % Hdr.BucketCount != Bucket) - break; - - dumpName(W, getNameTableEntry(Index), Hash); - } -} - -LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const { - DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str()); - Hdr.dump(W); - dumpCUs(W); - dumpLocalTUs(W); - dumpForeignTUs(W); - dumpAbbreviations(W); - - if (Hdr.BucketCount > 0) { - for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) - dumpBucket(W, Bucket); - return; - } - - W.startLine() << "Hash table not present\n"; - for (NameTableEntry NTE : *this) - dumpName(W, NTE, None); -} - -Error DWARFDebugNames::extract() { - uint64_t Offset = 0; - while (AccelSection.isValidOffset(Offset)) { - NameIndex Next(*this, Offset); - if (Error E = Next.extract()) - return E; - Offset = Next.getNextUnitOffset(); - NameIndices.push_back(std::move(Next)); - } - return Error::success(); -} - -iterator_range<DWARFDebugNames::ValueIterator> -DWARFDebugNames::NameIndex::equal_range(StringRef Key) const { - return make_range(ValueIterator(*this, Key), ValueIterator()); -} - -LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const { - ScopedPrinter W(OS); - for (const NameIndex &NI : NameIndices) - NI.dump(W); -} - -Optional<uint64_t> -DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { - const Header &Hdr = CurrentIndex->Hdr; - if (Hdr.BucketCount == 0) { - // No Hash Table, We need to search through all names in the Name Index. - for (NameTableEntry NTE : *CurrentIndex) { - if (NTE.getString() == Key) - return NTE.getEntryOffset(); - } - return None; - } - - // The Name Index has a Hash Table, so use that to speed up the search. - // Compute the Key Hash, if it has not been done already. - if (!Hash) - Hash = caseFoldingDjbHash(Key); - uint32_t Bucket = *Hash % Hdr.BucketCount; - uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket); - if (Index == 0) - return None; // Empty bucket - - for (; Index <= Hdr.NameCount; ++Index) { - uint32_t Hash = CurrentIndex->getHashArrayEntry(Index); - if (Hash % Hdr.BucketCount != Bucket) - return None; // End of bucket - - NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); - if (NTE.getString() == Key) - return NTE.getEntryOffset(); - } - return None; -} - -bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() { - auto EntryOr = CurrentIndex->getEntry(&DataOffset); - if (!EntryOr) { - consumeError(EntryOr.takeError()); - return false; - } - CurrentEntry = std::move(*EntryOr); - return true; -} - -bool DWARFDebugNames::ValueIterator::findInCurrentIndex() { - Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex(); - if (!Offset) - return false; - DataOffset = *Offset; - return getEntryAtCurrentOffset(); -} - -void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() { - for (const NameIndex *End = CurrentIndex->Section.NameIndices.end(); - CurrentIndex != End; ++CurrentIndex) { - if (findInCurrentIndex()) - return; - } - setEnd(); -} - -void DWARFDebugNames::ValueIterator::next() { - assert(CurrentIndex && "Incrementing an end() iterator?"); - - // First try the next entry in the current Index. - if (getEntryAtCurrentOffset()) - return; - - // If we're a local iterator or we have reached the last Index, we're done. - if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) { - setEnd(); - return; - } - - // Otherwise, try the next index. - ++CurrentIndex; - searchFromStartOfCurrentIndex(); -} - -DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable, - StringRef Key) - : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), - Key(std::string(Key)) { - searchFromStartOfCurrentIndex(); -} - -DWARFDebugNames::ValueIterator::ValueIterator( - const DWARFDebugNames::NameIndex &NI, StringRef Key) - : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) { - if (!findInCurrentIndex()) - setEnd(); -} - -iterator_range<DWARFDebugNames::ValueIterator> -DWARFDebugNames::equal_range(StringRef Key) const { - if (NameIndices.empty()) - return make_range(ValueIterator(), ValueIterator()); - return make_range(ValueIterator(*this, Key), ValueIterator()); -} - -const DWARFDebugNames::NameIndex * -DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) { - if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) { - for (const auto &NI : *this) { - for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU) - CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI); - } - } - return CUToNameIndex.lookup(CUOffset); -} +//===- DWARFAcceleratorTable.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <cstdint> +#include <utility> + +using namespace llvm; + +namespace { +struct Atom { + unsigned Value; +}; + +static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) { + StringRef Str = dwarf::AtomTypeString(A.Value); + if (!Str.empty()) + return OS << Str; + return OS << "DW_ATOM_unknown_" << format("%x", A.Value); +} +} // namespace + +static Atom formatAtom(unsigned Atom) { return {Atom}; } + +DWARFAcceleratorTable::~DWARFAcceleratorTable() = default; + +Error AppleAcceleratorTable::extract() { + uint64_t Offset = 0; + + // Check that we can at least read the header. + if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4)) + return createStringError(errc::illegal_byte_sequence, + "Section too small: cannot read header."); + + Hdr.Magic = AccelSection.getU32(&Offset); + Hdr.Version = AccelSection.getU16(&Offset); + Hdr.HashFunction = AccelSection.getU16(&Offset); + Hdr.BucketCount = AccelSection.getU32(&Offset); + Hdr.HashCount = AccelSection.getU32(&Offset); + Hdr.HeaderDataLength = AccelSection.getU32(&Offset); + + // Check that we can read all the hashes and offsets from the + // section (see SourceLevelDebugging.rst for the structure of the index). + // We need to substract one because we're checking for an *offset* which is + // equal to the size for an empty table and hence pointer after the section. + if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength + + Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1)) + return createStringError( + errc::illegal_byte_sequence, + "Section too small: cannot read buckets and hashes."); + + HdrData.DIEOffsetBase = AccelSection.getU32(&Offset); + uint32_t NumAtoms = AccelSection.getU32(&Offset); + + for (unsigned i = 0; i < NumAtoms; ++i) { + uint16_t AtomType = AccelSection.getU16(&Offset); + auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset)); + HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm)); + } + + IsValid = true; + return Error::success(); +} + +uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; } +uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; } +uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); } +uint32_t AppleAcceleratorTable::getHeaderDataLength() { + return Hdr.HeaderDataLength; +} + +ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType, + AppleAcceleratorTable::HeaderData::Form>> +AppleAcceleratorTable::getAtomsDesc() { + return HdrData.Atoms; +} + +bool AppleAcceleratorTable::validateForms() { + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + case dwarf::DW_ATOM_die_tag: + case dwarf::DW_ATOM_type_flags: + if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) && + !FormValue.isFormClass(DWARFFormValue::FC_Flag)) || + FormValue.getForm() == dwarf::DW_FORM_sdata) + return false; + break; + default: + break; + } + } + return true; +} + +std::pair<uint64_t, dwarf::Tag> +AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) { + uint64_t DieOffset = dwarf::DW_INVALID_OFFSET; + dwarf::Tag DieTag = dwarf::DW_TAG_null; + dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; + + for (auto Atom : getAtomsDesc()) { + DWARFFormValue FormValue(Atom.second); + FormValue.extractValue(AccelSection, HashDataOffset, FormParams); + switch (Atom.first) { + case dwarf::DW_ATOM_die_offset: + DieOffset = *FormValue.getAsUnsignedConstant(); + break; + case dwarf::DW_ATOM_die_tag: + DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant(); + break; + default: + break; + } + } + return {DieOffset, DieTag}; +} + +void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const { + DictScope HeaderScope(W, "Header"); + W.printHex("Magic", Magic); + W.printHex("Version", Version); + W.printHex("Hash function", HashFunction); + W.printNumber("Bucket count", BucketCount); + W.printNumber("Hashes count", HashCount); + W.printNumber("HeaderData length", HeaderDataLength); +} + +Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset( + Optional<DWARFFormValue> Value) const { + if (!Value) + return None; + + switch (Value->getForm()) { + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + case dwarf::DW_FORM_ref_udata: + return Value->getRawUValue() + DIEOffsetBase; + default: + return Value->getAsSectionOffset(); + } +} + +bool AppleAcceleratorTable::dumpName(ScopedPrinter &W, + SmallVectorImpl<DWARFFormValue> &AtomForms, + uint64_t *DataOffset) const { + dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32}; + uint64_t NameOffset = *DataOffset; + if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) { + W.printString("Incorrectly terminated list."); + return false; + } + uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset); + if (!StringOffset) + return false; // End of list + + DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str()); + W.startLine() << format("String: 0x%08" PRIx64, StringOffset); + W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n"; + + unsigned NumData = AccelSection.getU32(DataOffset); + for (unsigned Data = 0; Data < NumData; ++Data) { + ListScope DataScope(W, ("Data " + Twine(Data)).str()); + unsigned i = 0; + for (auto &Atom : AtomForms) { + W.startLine() << format("Atom[%d]: ", i); + if (Atom.extractValue(AccelSection, DataOffset, FormParams)) { + Atom.dump(W.getOStream()); + if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) { + StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val); + if (!Str.empty()) + W.getOStream() << " (" << Str << ")"; + } + } else + W.getOStream() << "Error extracting the value"; + W.getOStream() << "\n"; + i++; + } + } + return true; // more entries follow +} + +LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const { + if (!IsValid) + return; + + ScopedPrinter W(OS); + + Hdr.dump(W); + + W.printNumber("DIE offset base", HdrData.DIEOffsetBase); + W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size())); + SmallVector<DWARFFormValue, 3> AtomForms; + { + ListScope AtomsScope(W, "Atoms"); + unsigned i = 0; + for (const auto &Atom : HdrData.Atoms) { + DictScope AtomScope(W, ("Atom " + Twine(i++)).str()); + W.startLine() << "Type: " << formatAtom(Atom.first) << '\n'; + W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n'; + AtomForms.push_back(DWARFFormValue(Atom.second)); + } + } + + // Now go through the actual tables and dump them. + uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength; + uint64_t HashesBase = Offset + Hdr.BucketCount * 4; + uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; + + for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) { + unsigned Index = AccelSection.getU32(&Offset); + + ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); + if (Index == UINT32_MAX) { + W.printString("EMPTY"); + continue; + } + + for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { + uint64_t HashOffset = HashesBase + HashIdx*4; + uint64_t OffsetsOffset = OffsetsBase + HashIdx*4; + uint32_t Hash = AccelSection.getU32(&HashOffset); + + if (Hash % Hdr.BucketCount != Bucket) + break; + + uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); + ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str()); + if (!AccelSection.isValidOffset(DataOffset)) { + W.printString("Invalid section offset"); + continue; + } + while (dumpName(W, AtomForms, &DataOffset)) + /*empty*/; + } + } +} + +AppleAcceleratorTable::Entry::Entry( + const AppleAcceleratorTable::HeaderData &HdrData) + : HdrData(&HdrData) { + Values.reserve(HdrData.Atoms.size()); + for (const auto &Atom : HdrData.Atoms) + Values.push_back(DWARFFormValue(Atom.second)); +} + +void AppleAcceleratorTable::Entry::extract( + const AppleAcceleratorTable &AccelTable, uint64_t *Offset) { + + dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0, + dwarf::DwarfFormat::DWARF32}; + for (auto &Atom : Values) + Atom.extractValue(AccelTable.AccelSection, Offset, FormParams); +} + +Optional<DWARFFormValue> +AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const { + assert(HdrData && "Dereferencing end iterator?"); + assert(HdrData->Atoms.size() == Values.size()); + for (auto Tuple : zip_first(HdrData->Atoms, Values)) { + if (std::get<0>(Tuple).first == Atom) + return std::get<1>(Tuple); + } + return None; +} + +Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const { + return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset)); +} + +Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const { + return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset)); +} + +Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const { + Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag); + if (!Tag) + return None; + if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant()) + return dwarf::Tag(*Value); + return None; +} + +AppleAcceleratorTable::ValueIterator::ValueIterator( + const AppleAcceleratorTable &AccelTable, uint64_t Offset) + : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) { + if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) + return; + + // Read the first entry. + NumData = AccelTable.AccelSection.getU32(&DataOffset); + Next(); +} + +void AppleAcceleratorTable::ValueIterator::Next() { + assert(NumData > 0 && "attempted to increment iterator past the end"); + auto &AccelSection = AccelTable->AccelSection; + if (Data >= NumData || + !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) { + NumData = 0; + DataOffset = 0; + return; + } + Current.extract(*AccelTable, &DataOffset); + ++Data; +} + +iterator_range<AppleAcceleratorTable::ValueIterator> +AppleAcceleratorTable::equal_range(StringRef Key) const { + if (!IsValid) + return make_range(ValueIterator(), ValueIterator()); + + // Find the bucket. + unsigned HashValue = djbHash(Key); + unsigned Bucket = HashValue % Hdr.BucketCount; + uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength; + uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4; + uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4; + + uint64_t BucketOffset = BucketBase + Bucket * 4; + unsigned Index = AccelSection.getU32(&BucketOffset); + + // Search through all hashes in the bucket. + for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) { + uint64_t HashOffset = HashesBase + HashIdx * 4; + uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4; + uint32_t Hash = AccelSection.getU32(&HashOffset); + + if (Hash % Hdr.BucketCount != Bucket) + // We are already in the next bucket. + break; + + uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset); + uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset); + if (!StringOffset) + break; + + // Finally, compare the key. + if (Key == StringSection.getCStr(&StringOffset)) + return make_range({*this, DataOffset}, ValueIterator()); + } + return make_range(ValueIterator(), ValueIterator()); +} + +void DWARFDebugNames::Header::dump(ScopedPrinter &W) const { + DictScope HeaderScope(W, "Header"); + W.printHex("Length", UnitLength); + W.printString("Format", dwarf::FormatString(Format)); + W.printNumber("Version", Version); + W.printNumber("CU count", CompUnitCount); + W.printNumber("Local TU count", LocalTypeUnitCount); + W.printNumber("Foreign TU count", ForeignTypeUnitCount); + W.printNumber("Bucket count", BucketCount); + W.printNumber("Name count", NameCount); + W.printHex("Abbreviations table size", AbbrevTableSize); + W.startLine() << "Augmentation: '" << AugmentationString << "'\n"; +} + +Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS, + uint64_t *Offset) { + auto HeaderError = [Offset = *Offset](Error E) { + return createStringError(errc::illegal_byte_sequence, + "parsing .debug_names header at 0x%" PRIx64 ": %s", + Offset, toString(std::move(E)).c_str()); + }; + + DataExtractor::Cursor C(*Offset); + std::tie(UnitLength, Format) = AS.getInitialLength(C); + + Version = AS.getU16(C); + AS.skip(C, 2); // padding + CompUnitCount = AS.getU32(C); + LocalTypeUnitCount = AS.getU32(C); + ForeignTypeUnitCount = AS.getU32(C); + BucketCount = AS.getU32(C); + NameCount = AS.getU32(C); + AbbrevTableSize = AS.getU32(C); + AugmentationStringSize = alignTo(AS.getU32(C), 4); + + if (!C) + return HeaderError(C.takeError()); + + if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize)) + return HeaderError(createStringError(errc::illegal_byte_sequence, + "cannot read header augmentation")); + AugmentationString.resize(AugmentationStringSize); + AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()), + AugmentationStringSize); + *Offset = C.tell(); + return C.takeError(); +} + +void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const { + DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str()); + W.startLine() << formatv("Tag: {0}\n", Tag); + + for (const auto &Attr : Attributes) + W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form); +} + +static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() { + return {dwarf::Index(0), dwarf::Form(0)}; +} + +static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) { + return AE == sentinelAttrEnc(); +} + +static DWARFDebugNames::Abbrev sentinelAbbrev() { + return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {}); +} + +static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) { + return Abbr.Code == 0; +} + +DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() { + return sentinelAbbrev(); +} + +DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() { + return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {}); +} + +Expected<DWARFDebugNames::AttributeEncoding> +DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) { + if (*Offset >= EntriesBase) { + return createStringError(errc::illegal_byte_sequence, + "Incorrectly terminated abbreviation table."); + } + + uint32_t Index = Section.AccelSection.getULEB128(Offset); + uint32_t Form = Section.AccelSection.getULEB128(Offset); + return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form)); +} + +Expected<std::vector<DWARFDebugNames::AttributeEncoding>> +DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) { + std::vector<AttributeEncoding> Result; + for (;;) { + auto AttrEncOr = extractAttributeEncoding(Offset); + if (!AttrEncOr) + return AttrEncOr.takeError(); + if (isSentinel(*AttrEncOr)) + return std::move(Result); + + Result.emplace_back(*AttrEncOr); + } +} + +Expected<DWARFDebugNames::Abbrev> +DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) { + if (*Offset >= EntriesBase) { + return createStringError(errc::illegal_byte_sequence, + "Incorrectly terminated abbreviation table."); + } + + uint32_t Code = Section.AccelSection.getULEB128(Offset); + if (Code == 0) + return sentinelAbbrev(); + + uint32_t Tag = Section.AccelSection.getULEB128(Offset); + auto AttrEncOr = extractAttributeEncodings(Offset); + if (!AttrEncOr) + return AttrEncOr.takeError(); + return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr)); +} + +Error DWARFDebugNames::NameIndex::extract() { + const DWARFDataExtractor &AS = Section.AccelSection; + uint64_t Offset = Base; + if (Error E = Hdr.extract(AS, &Offset)) + return E; + + const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); + CUsBase = Offset; + Offset += Hdr.CompUnitCount * SectionOffsetSize; + Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize; + Offset += Hdr.ForeignTypeUnitCount * 8; + BucketsBase = Offset; + Offset += Hdr.BucketCount * 4; + HashesBase = Offset; + if (Hdr.BucketCount > 0) + Offset += Hdr.NameCount * 4; + StringOffsetsBase = Offset; + Offset += Hdr.NameCount * SectionOffsetSize; + EntryOffsetsBase = Offset; + Offset += Hdr.NameCount * SectionOffsetSize; + + if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize)) + return createStringError(errc::illegal_byte_sequence, + "Section too small: cannot read abbreviations."); + + EntriesBase = Offset + Hdr.AbbrevTableSize; + + for (;;) { + auto AbbrevOr = extractAbbrev(&Offset); + if (!AbbrevOr) + return AbbrevOr.takeError(); + if (isSentinel(*AbbrevOr)) + return Error::success(); + + if (!Abbrevs.insert(std::move(*AbbrevOr)).second) + return createStringError(errc::invalid_argument, + "Duplicate abbreviation code."); + } +} + +DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr) + : NameIdx(&NameIdx), Abbr(&Abbr) { + // This merely creates form values. It is up to the caller + // (NameIndex::getEntry) to populate them. + Values.reserve(Abbr.Attributes.size()); + for (const auto &Attr : Abbr.Attributes) + Values.emplace_back(Attr.Form); +} + +Optional<DWARFFormValue> +DWARFDebugNames::Entry::lookup(dwarf::Index Index) const { + assert(Abbr->Attributes.size() == Values.size()); + for (auto Tuple : zip_first(Abbr->Attributes, Values)) { + if (std::get<0>(Tuple).Index == Index) + return std::get<1>(Tuple); + } + return None; +} + +Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const { + if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset)) + return Off->getAsReferenceUVal(); + return None; +} + +Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const { + if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit)) + return Off->getAsUnsignedConstant(); + // In a per-CU index, the entries without a DW_IDX_compile_unit attribute + // implicitly refer to the single CU. + if (NameIdx->getCUCount() == 1) + return 0; + return None; +} + +Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const { + Optional<uint64_t> Index = getCUIndex(); + if (!Index || *Index >= NameIdx->getCUCount()) + return None; + return NameIdx->getCUOffset(*Index); +} + +void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const { + W.printHex("Abbrev", Abbr->Code); + W.startLine() << formatv("Tag: {0}\n", Abbr->Tag); + assert(Abbr->Attributes.size() == Values.size()); + for (auto Tuple : zip_first(Abbr->Attributes, Values)) { + W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index); + std::get<1>(Tuple).dump(W.getOStream()); + W.getOStream() << '\n'; + } +} + +char DWARFDebugNames::SentinelError::ID; +std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const { + return inconvertibleErrorCode(); +} + +uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const { + assert(CU < Hdr.CompUnitCount); + const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t Offset = CUsBase + SectionOffsetSize * CU; + return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); +} + +uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const { + assert(TU < Hdr.LocalTypeUnitCount); + const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU); + return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset); +} + +uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const { + assert(TU < Hdr.ForeignTypeUnitCount); + const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t Offset = + CUsBase + + SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU; + return Section.AccelSection.getU64(&Offset); +} + +Expected<DWARFDebugNames::Entry> +DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const { + const DWARFDataExtractor &AS = Section.AccelSection; + if (!AS.isValidOffset(*Offset)) + return createStringError(errc::illegal_byte_sequence, + "Incorrectly terminated entry list."); + + uint32_t AbbrevCode = AS.getULEB128(Offset); + if (AbbrevCode == 0) + return make_error<SentinelError>(); + + const auto AbbrevIt = Abbrevs.find_as(AbbrevCode); + if (AbbrevIt == Abbrevs.end()) + return createStringError(errc::invalid_argument, "Invalid abbreviation."); + + Entry E(*this, *AbbrevIt); + + dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format}; + for (auto &Value : E.Values) { + if (!Value.extractValue(AS, Offset, FormParams)) + return createStringError(errc::io_error, + "Error extracting index attribute values."); + } + return std::move(E); +} + +DWARFDebugNames::NameTableEntry +DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const { + assert(0 < Index && Index <= Hdr.NameCount); + const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format); + uint64_t StringOffsetOffset = + StringOffsetsBase + SectionOffsetSize * (Index - 1); + uint64_t EntryOffsetOffset = + EntryOffsetsBase + SectionOffsetSize * (Index - 1); + const DWARFDataExtractor &AS = Section.AccelSection; + + uint64_t StringOffset = + AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset); + uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize); + EntryOffset += EntriesBase; + return {Section.StringSection, Index, StringOffset, EntryOffset}; +} + +uint32_t +DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const { + assert(Bucket < Hdr.BucketCount); + uint64_t BucketOffset = BucketsBase + 4 * Bucket; + return Section.AccelSection.getU32(&BucketOffset); +} + +uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const { + assert(0 < Index && Index <= Hdr.NameCount); + uint64_t HashOffset = HashesBase + 4 * (Index - 1); + return Section.AccelSection.getU32(&HashOffset); +} + +// Returns true if we should continue scanning for entries, false if this is the +// last (sentinel) entry). In case of a parsing error we also return false, as +// it's not possible to recover this entry list (but the other lists may still +// parse OK). +bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W, + uint64_t *Offset) const { + uint64_t EntryId = *Offset; + auto EntryOr = getEntry(Offset); + if (!EntryOr) { + handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {}, + [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); }); + return false; + } + + DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str()); + EntryOr->dump(W); + return true; +} + +void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W, + const NameTableEntry &NTE, + Optional<uint32_t> Hash) const { + DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str()); + if (Hash) + W.printHex("Hash", *Hash); + + W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset()); + W.getOStream() << " \"" << NTE.getString() << "\"\n"; + + uint64_t EntryOffset = NTE.getEntryOffset(); + while (dumpEntry(W, &EntryOffset)) + /*empty*/; +} + +void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const { + ListScope CUScope(W, "Compilation Unit offsets"); + for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU) + W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU)); +} + +void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const { + if (Hdr.LocalTypeUnitCount == 0) + return; + + ListScope TUScope(W, "Local Type Unit offsets"); + for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU) + W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU, + getLocalTUOffset(TU)); +} + +void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const { + if (Hdr.ForeignTypeUnitCount == 0) + return; + + ListScope TUScope(W, "Foreign Type Unit signatures"); + for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) { + W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU, + getForeignTUSignature(TU)); + } +} + +void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const { + ListScope AbbrevsScope(W, "Abbreviations"); + for (const auto &Abbr : Abbrevs) + Abbr.dump(W); +} + +void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W, + uint32_t Bucket) const { + ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str()); + uint32_t Index = getBucketArrayEntry(Bucket); + if (Index == 0) { + W.printString("EMPTY"); + return; + } + if (Index > Hdr.NameCount) { + W.printString("Name index is invalid"); + return; + } + + for (; Index <= Hdr.NameCount; ++Index) { + uint32_t Hash = getHashArrayEntry(Index); + if (Hash % Hdr.BucketCount != Bucket) + break; + + dumpName(W, getNameTableEntry(Index), Hash); + } +} + +LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const { + DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str()); + Hdr.dump(W); + dumpCUs(W); + dumpLocalTUs(W); + dumpForeignTUs(W); + dumpAbbreviations(W); + + if (Hdr.BucketCount > 0) { + for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) + dumpBucket(W, Bucket); + return; + } + + W.startLine() << "Hash table not present\n"; + for (NameTableEntry NTE : *this) + dumpName(W, NTE, None); +} + +Error DWARFDebugNames::extract() { + uint64_t Offset = 0; + while (AccelSection.isValidOffset(Offset)) { + NameIndex Next(*this, Offset); + if (Error E = Next.extract()) + return E; + Offset = Next.getNextUnitOffset(); + NameIndices.push_back(std::move(Next)); + } + return Error::success(); +} + +iterator_range<DWARFDebugNames::ValueIterator> +DWARFDebugNames::NameIndex::equal_range(StringRef Key) const { + return make_range(ValueIterator(*this, Key), ValueIterator()); +} + +LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const { + ScopedPrinter W(OS); + for (const NameIndex &NI : NameIndices) + NI.dump(W); +} + +Optional<uint64_t> +DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { + const Header &Hdr = CurrentIndex->Hdr; + if (Hdr.BucketCount == 0) { + // No Hash Table, We need to search through all names in the Name Index. + for (NameTableEntry NTE : *CurrentIndex) { + if (NTE.getString() == Key) + return NTE.getEntryOffset(); + } + return None; + } + + // The Name Index has a Hash Table, so use that to speed up the search. + // Compute the Key Hash, if it has not been done already. + if (!Hash) + Hash = caseFoldingDjbHash(Key); + uint32_t Bucket = *Hash % Hdr.BucketCount; + uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket); + if (Index == 0) + return None; // Empty bucket + + for (; Index <= Hdr.NameCount; ++Index) { + uint32_t Hash = CurrentIndex->getHashArrayEntry(Index); + if (Hash % Hdr.BucketCount != Bucket) + return None; // End of bucket + + NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); + if (NTE.getString() == Key) + return NTE.getEntryOffset(); + } + return None; +} + +bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() { + auto EntryOr = CurrentIndex->getEntry(&DataOffset); + if (!EntryOr) { + consumeError(EntryOr.takeError()); + return false; + } + CurrentEntry = std::move(*EntryOr); + return true; +} + +bool DWARFDebugNames::ValueIterator::findInCurrentIndex() { + Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex(); + if (!Offset) + return false; + DataOffset = *Offset; + return getEntryAtCurrentOffset(); +} + +void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() { + for (const NameIndex *End = CurrentIndex->Section.NameIndices.end(); + CurrentIndex != End; ++CurrentIndex) { + if (findInCurrentIndex()) + return; + } + setEnd(); +} + +void DWARFDebugNames::ValueIterator::next() { + assert(CurrentIndex && "Incrementing an end() iterator?"); + + // First try the next entry in the current Index. + if (getEntryAtCurrentOffset()) + return; + + // If we're a local iterator or we have reached the last Index, we're done. + if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) { + setEnd(); + return; + } + + // Otherwise, try the next index. + ++CurrentIndex; + searchFromStartOfCurrentIndex(); +} + +DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable, + StringRef Key) + : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), + Key(std::string(Key)) { + searchFromStartOfCurrentIndex(); +} + +DWARFDebugNames::ValueIterator::ValueIterator( + const DWARFDebugNames::NameIndex &NI, StringRef Key) + : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) { + if (!findInCurrentIndex()) + setEnd(); +} + +iterator_range<DWARFDebugNames::ValueIterator> +DWARFDebugNames::equal_range(StringRef Key) const { + if (NameIndices.empty()) + return make_range(ValueIterator(), ValueIterator()); + return make_range(ValueIterator(*this, Key), ValueIterator()); +} + +const DWARFDebugNames::NameIndex * +DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) { + if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) { + for (const auto &NI : *this) { + for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU) + CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI); + } + } + return CUToNameIndex.lookup(CUOffset); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAddressRange.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAddressRange.cpp index 25d2e852a7..b5921d04ef 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAddressRange.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFAddressRange.cpp @@ -1,33 +1,33 @@ -//===- DWARFDebugAranges.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize, - DIDumpOptions DumpOpts, - const DWARFObject *Obj) const { - - OS << (DumpOpts.DisplayRawContents ? " " : "["); +//===- DWARFDebugAranges.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize, + DIDumpOptions DumpOpts, + const DWARFObject *Obj) const { + + OS << (DumpOpts.DisplayRawContents ? " " : "["); DWARFFormValue::dumpAddress(OS, AddressSize, LowPC); OS << ", "; DWARFFormValue::dumpAddress(OS, AddressSize, HighPC); - OS << (DumpOpts.DisplayRawContents ? "" : ")"); - - if (Obj) - DWARFFormValue::dumpAddressSection(*Obj, OS, DumpOpts, SectionIndex); -} - -raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { - R.dump(OS, /* AddressSize */ 8); - return OS; -} + OS << (DumpOpts.DisplayRawContents ? "" : ")"); + + if (Obj) + DWARFFormValue::dumpAddressSection(*Obj, OS, DumpOpts, SectionIndex); +} + +raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) { + R.dump(OS, /* AddressSize */ 8); + return OS; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp index 2b08120ef4..cfd72886d8 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp @@ -1,41 +1,41 @@ -//===-- DWARFCompileUnit.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#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" - -using namespace llvm; - -void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat()); - OS << format("0x%08" PRIx64, getOffset()) << ": Compile Unit:" - << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) - << ", format = " << dwarf::FormatString(getFormat()) - << ", version = " << format("0x%04x", getVersion()); - if (getVersion() >= 5) - OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType()); +//===-- DWARFCompileUnit.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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" + +using namespace llvm; + +void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat()); + OS << format("0x%08" PRIx64, getOffset()) << ": Compile Unit:" + << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) + << ", format = " << dwarf::FormatString(getFormat()) + << ", version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType()); OS << ", abbr_offset = " << format("0x%04" PRIx64, getAbbrOffset()); if (!getAbbreviations()) OS << " (invalid)"; OS << ", addr_size = " << format("0x%02x", getAddressByteSize()); - if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile) - OS << ", DWO_id = " << format("0x%016" PRIx64, *getDWOId()); - OS << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset()) - << ")\n"; - - if (DWARFDie CUDie = getUnitDIE(false)) - CUDie.dump(OS, 0, DumpOpts); - else - OS << "<compile unit can't be parsed!>\n\n"; -} - -// VTable anchor. -DWARFCompileUnit::~DWARFCompileUnit() = default; + if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile) + OS << ", DWO_id = " << format("0x%016" PRIx64, *getDWOId()); + OS << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset()) + << ")\n"; + + if (DWARFDie CUDie = getUnitDIE(false)) + CUDie.dump(OS, 0, DumpOpts); + else + OS << "<compile unit can't be parsed!>\n\n"; +} + +// VTable anchor. +DWARFCompileUnit::~DWARFCompileUnit() = default; diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFContext.cpp index 749d738af9..47ac74b02d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1,531 +1,531 @@ -//===- DWARFContext.cpp ---------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" -#include "llvm/DebugInfo/DWARF/DWARFSection.h" -#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" -#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Object/Decompressor.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/RelocationResolver.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/LEB128.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cstdint> -#include <deque> -#include <map> -#include <string> -#include <utility> -#include <vector> - -using namespace llvm; -using namespace dwarf; -using namespace object; - -#define DEBUG_TYPE "dwarf" - -using DWARFLineTable = DWARFDebugLine::LineTable; -using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; -using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; - -DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj, - std::string DWPName, - std::function<void(Error)> RecoverableErrorHandler, - std::function<void(Error)> WarningHandler) - : DIContext(CK_DWARF), DWPName(std::move(DWPName)), - RecoverableErrorHandler(RecoverableErrorHandler), - WarningHandler(WarningHandler), DObj(std::move(DObj)) {} - -DWARFContext::~DWARFContext() = default; - -/// Dump the UUID load command. -static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) { - auto *MachO = dyn_cast<MachOObjectFile>(&Obj); - if (!MachO) - return; - for (auto LC : MachO->load_commands()) { - raw_ostream::uuid_t UUID; - if (LC.C.cmd == MachO::LC_UUID) { - if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) { - OS << "error: UUID load command is too short.\n"; - return; - } - OS << "UUID: "; - memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID)); - OS.write_uuid(UUID); - Triple T = MachO->getArchTriple(); - OS << " (" << T.getArchName() << ')'; - OS << ' ' << MachO->getFileName() << '\n'; - } - } -} - -using ContributionCollection = - std::vector<Optional<StrOffsetsContributionDescriptor>>; - -// Collect all the contributions to the string offsets table from all units, -// sort them by their starting offsets and remove duplicates. -static ContributionCollection -collectContributionData(DWARFContext::unit_iterator_range Units) { - ContributionCollection Contributions; - for (const auto &U : Units) - if (const auto &C = U->getStringOffsetsTableContribution()) - Contributions.push_back(C); - // Sort the contributions so that any invalid ones are placed at - // the start of the contributions vector. This way they are reported - // first. - llvm::sort(Contributions, - [](const Optional<StrOffsetsContributionDescriptor> &L, - const Optional<StrOffsetsContributionDescriptor> &R) { - if (L && R) - return L->Base < R->Base; - return R.hasValue(); - }); - - // Uniquify contributions, as it is possible that units (specifically - // type units in dwo or dwp files) share contributions. We don't want - // to report them more than once. - Contributions.erase( - std::unique(Contributions.begin(), Contributions.end(), - [](const Optional<StrOffsetsContributionDescriptor> &L, - const Optional<StrOffsetsContributionDescriptor> &R) { - if (L && R) - return L->Base == R->Base && L->Size == R->Size; - return false; - }), - Contributions.end()); - return Contributions; -} - -// Dump a DWARF string offsets section. This may be a DWARF v5 formatted -// string offsets section, where each compile or type unit contributes a -// number of entries (string offsets), with each contribution preceded by -// a header containing size and version number. Alternatively, it may be a -// monolithic series of string offsets, as generated by the pre-DWARF v5 -// implementation of split DWARF; however, in that case we still need to -// collect contributions of units because the size of the offsets (4 or 8 -// bytes) depends on the format of the referencing unit (DWARF32 or DWARF64). -static void dumpStringOffsetsSection(raw_ostream &OS, DIDumpOptions DumpOpts, - StringRef SectionName, - const DWARFObject &Obj, - const DWARFSection &StringOffsetsSection, - StringRef StringSection, - DWARFContext::unit_iterator_range Units, - bool LittleEndian) { - auto Contributions = collectContributionData(Units); - DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0); - DataExtractor StrData(StringSection, LittleEndian, 0); - uint64_t SectionSize = StringOffsetsSection.Data.size(); - uint64_t Offset = 0; - for (auto &Contribution : Contributions) { - // Report an ill-formed contribution. - if (!Contribution) { - OS << "error: invalid contribution to string offsets table in section ." - << SectionName << ".\n"; - return; - } - - dwarf::DwarfFormat Format = Contribution->getFormat(); - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); - uint16_t Version = Contribution->getVersion(); - uint64_t ContributionHeader = Contribution->Base; - // In DWARF v5 there is a contribution header that immediately precedes - // the string offsets base (the location we have previously retrieved from - // the CU DIE's DW_AT_str_offsets attribute). The header is located either - // 8 or 16 bytes before the base, depending on the contribution's format. - if (Version >= 5) - ContributionHeader -= Format == DWARF32 ? 8 : 16; - - // Detect overlapping contributions. - if (Offset > ContributionHeader) { - DumpOpts.RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "overlapping contributions to string offsets table in section .%s.", - SectionName.data())); - } - // Report a gap in the table. - if (Offset < ContributionHeader) { - OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset); - OS << (ContributionHeader - Offset) << "\n"; - } - OS << format("0x%8.8" PRIx64 ": ", ContributionHeader); - // In DWARF v5 the contribution size in the descriptor does not equal - // the originally encoded length (it does not contain the length of the - // version field and the padding, a total of 4 bytes). Add them back in - // for reporting. - OS << "Contribution size = " << (Contribution->Size + (Version < 5 ? 0 : 4)) - << ", Format = " << dwarf::FormatString(Format) - << ", Version = " << Version << "\n"; - - Offset = Contribution->Base; - unsigned EntrySize = Contribution->getDwarfOffsetByteSize(); - while (Offset - Contribution->Base < Contribution->Size) { - OS << format("0x%8.8" PRIx64 ": ", Offset); - uint64_t StringOffset = - StrOffsetExt.getRelocatedValue(EntrySize, &Offset); - OS << format("%0*" PRIx64 " ", OffsetDumpWidth, StringOffset); - const char *S = StrData.getCStr(&StringOffset); - if (S) - OS << format("\"%s\"", S); - OS << "\n"; - } - } - // Report a gap at the end of the table. - if (Offset < SectionSize) { - OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset); - OS << (SectionSize - Offset) << "\n"; - } -} - -// Dump the .debug_addr section. -static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData, - DIDumpOptions DumpOpts, uint16_t Version, - uint8_t AddrSize) { - uint64_t Offset = 0; - while (AddrData.isValidOffset(Offset)) { - DWARFDebugAddrTable AddrTable; - uint64_t TableOffset = Offset; - if (Error Err = AddrTable.extract(AddrData, &Offset, Version, AddrSize, - DumpOpts.WarningHandler)) { - DumpOpts.RecoverableErrorHandler(std::move(Err)); - // Keep going after an error, if we can, assuming that the length field - // could be read. If it couldn't, stop reading the section. - if (auto TableLength = AddrTable.getFullLength()) { - Offset = TableOffset + *TableLength; - continue; - } - break; - } - AddrTable.dump(OS, DumpOpts); - } -} - -// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5). -static void dumpRnglistsSection( - raw_ostream &OS, DWARFDataExtractor &rnglistData, - llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> - LookupPooledAddress, - DIDumpOptions DumpOpts) { - uint64_t Offset = 0; - while (rnglistData.isValidOffset(Offset)) { - llvm::DWARFDebugRnglistTable Rnglists; - uint64_t TableOffset = Offset; - if (Error Err = Rnglists.extract(rnglistData, &Offset)) { - DumpOpts.RecoverableErrorHandler(std::move(Err)); - uint64_t Length = Rnglists.length(); - // Keep going after an error, if we can, assuming that the length field - // could be read. If it couldn't, stop reading the section. - if (Length == 0) - break; - Offset = TableOffset + Length; - } else { +//===- DWARFContext.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Object/Decompressor.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/RelocationResolver.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdint> +#include <deque> +#include <map> +#include <string> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +#define DEBUG_TYPE "dwarf" + +using DWARFLineTable = DWARFDebugLine::LineTable; +using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; +using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; + +DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj, + std::string DWPName, + std::function<void(Error)> RecoverableErrorHandler, + std::function<void(Error)> WarningHandler) + : DIContext(CK_DWARF), DWPName(std::move(DWPName)), + RecoverableErrorHandler(RecoverableErrorHandler), + WarningHandler(WarningHandler), DObj(std::move(DObj)) {} + +DWARFContext::~DWARFContext() = default; + +/// Dump the UUID load command. +static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) { + auto *MachO = dyn_cast<MachOObjectFile>(&Obj); + if (!MachO) + return; + for (auto LC : MachO->load_commands()) { + raw_ostream::uuid_t UUID; + if (LC.C.cmd == MachO::LC_UUID) { + if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) { + OS << "error: UUID load command is too short.\n"; + return; + } + OS << "UUID: "; + memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID)); + OS.write_uuid(UUID); + Triple T = MachO->getArchTriple(); + OS << " (" << T.getArchName() << ')'; + OS << ' ' << MachO->getFileName() << '\n'; + } + } +} + +using ContributionCollection = + std::vector<Optional<StrOffsetsContributionDescriptor>>; + +// Collect all the contributions to the string offsets table from all units, +// sort them by their starting offsets and remove duplicates. +static ContributionCollection +collectContributionData(DWARFContext::unit_iterator_range Units) { + ContributionCollection Contributions; + for (const auto &U : Units) + if (const auto &C = U->getStringOffsetsTableContribution()) + Contributions.push_back(C); + // Sort the contributions so that any invalid ones are placed at + // the start of the contributions vector. This way they are reported + // first. + llvm::sort(Contributions, + [](const Optional<StrOffsetsContributionDescriptor> &L, + const Optional<StrOffsetsContributionDescriptor> &R) { + if (L && R) + return L->Base < R->Base; + return R.hasValue(); + }); + + // Uniquify contributions, as it is possible that units (specifically + // type units in dwo or dwp files) share contributions. We don't want + // to report them more than once. + Contributions.erase( + std::unique(Contributions.begin(), Contributions.end(), + [](const Optional<StrOffsetsContributionDescriptor> &L, + const Optional<StrOffsetsContributionDescriptor> &R) { + if (L && R) + return L->Base == R->Base && L->Size == R->Size; + return false; + }), + Contributions.end()); + return Contributions; +} + +// Dump a DWARF string offsets section. This may be a DWARF v5 formatted +// string offsets section, where each compile or type unit contributes a +// number of entries (string offsets), with each contribution preceded by +// a header containing size and version number. Alternatively, it may be a +// monolithic series of string offsets, as generated by the pre-DWARF v5 +// implementation of split DWARF; however, in that case we still need to +// collect contributions of units because the size of the offsets (4 or 8 +// bytes) depends on the format of the referencing unit (DWARF32 or DWARF64). +static void dumpStringOffsetsSection(raw_ostream &OS, DIDumpOptions DumpOpts, + StringRef SectionName, + const DWARFObject &Obj, + const DWARFSection &StringOffsetsSection, + StringRef StringSection, + DWARFContext::unit_iterator_range Units, + bool LittleEndian) { + auto Contributions = collectContributionData(Units); + DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0); + DataExtractor StrData(StringSection, LittleEndian, 0); + uint64_t SectionSize = StringOffsetsSection.Data.size(); + uint64_t Offset = 0; + for (auto &Contribution : Contributions) { + // Report an ill-formed contribution. + if (!Contribution) { + OS << "error: invalid contribution to string offsets table in section ." + << SectionName << ".\n"; + return; + } + + dwarf::DwarfFormat Format = Contribution->getFormat(); + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); + uint16_t Version = Contribution->getVersion(); + uint64_t ContributionHeader = Contribution->Base; + // In DWARF v5 there is a contribution header that immediately precedes + // the string offsets base (the location we have previously retrieved from + // the CU DIE's DW_AT_str_offsets attribute). The header is located either + // 8 or 16 bytes before the base, depending on the contribution's format. + if (Version >= 5) + ContributionHeader -= Format == DWARF32 ? 8 : 16; + + // Detect overlapping contributions. + if (Offset > ContributionHeader) { + DumpOpts.RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "overlapping contributions to string offsets table in section .%s.", + SectionName.data())); + } + // Report a gap in the table. + if (Offset < ContributionHeader) { + OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset); + OS << (ContributionHeader - Offset) << "\n"; + } + OS << format("0x%8.8" PRIx64 ": ", ContributionHeader); + // In DWARF v5 the contribution size in the descriptor does not equal + // the originally encoded length (it does not contain the length of the + // version field and the padding, a total of 4 bytes). Add them back in + // for reporting. + OS << "Contribution size = " << (Contribution->Size + (Version < 5 ? 0 : 4)) + << ", Format = " << dwarf::FormatString(Format) + << ", Version = " << Version << "\n"; + + Offset = Contribution->Base; + unsigned EntrySize = Contribution->getDwarfOffsetByteSize(); + while (Offset - Contribution->Base < Contribution->Size) { + OS << format("0x%8.8" PRIx64 ": ", Offset); + uint64_t StringOffset = + StrOffsetExt.getRelocatedValue(EntrySize, &Offset); + OS << format("%0*" PRIx64 " ", OffsetDumpWidth, StringOffset); + const char *S = StrData.getCStr(&StringOffset); + if (S) + OS << format("\"%s\"", S); + OS << "\n"; + } + } + // Report a gap at the end of the table. + if (Offset < SectionSize) { + OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset); + OS << (SectionSize - Offset) << "\n"; + } +} + +// Dump the .debug_addr section. +static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData, + DIDumpOptions DumpOpts, uint16_t Version, + uint8_t AddrSize) { + uint64_t Offset = 0; + while (AddrData.isValidOffset(Offset)) { + DWARFDebugAddrTable AddrTable; + uint64_t TableOffset = Offset; + if (Error Err = AddrTable.extract(AddrData, &Offset, Version, AddrSize, + DumpOpts.WarningHandler)) { + DumpOpts.RecoverableErrorHandler(std::move(Err)); + // Keep going after an error, if we can, assuming that the length field + // could be read. If it couldn't, stop reading the section. + if (auto TableLength = AddrTable.getFullLength()) { + Offset = TableOffset + *TableLength; + continue; + } + break; + } + AddrTable.dump(OS, DumpOpts); + } +} + +// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5). +static void dumpRnglistsSection( + raw_ostream &OS, DWARFDataExtractor &rnglistData, + llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress, + DIDumpOptions DumpOpts) { + uint64_t Offset = 0; + while (rnglistData.isValidOffset(Offset)) { + llvm::DWARFDebugRnglistTable Rnglists; + uint64_t TableOffset = Offset; + if (Error Err = Rnglists.extract(rnglistData, &Offset)) { + DumpOpts.RecoverableErrorHandler(std::move(Err)); + uint64_t Length = Rnglists.length(); + // Keep going after an error, if we can, assuming that the length field + // could be read. If it couldn't, stop reading the section. + if (Length == 0) + break; + Offset = TableOffset + Length; + } else { Rnglists.dump(rnglistData, OS, LookupPooledAddress, DumpOpts); - } - } -} - -std::unique_ptr<DWARFDebugMacro> -DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) { - auto Macro = std::make_unique<DWARFDebugMacro>(); - auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) { - if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection - ? compile_units() - : dwo_compile_units(), - SectionType == MacroSection - ? getStringExtractor() - : getStringDWOExtractor(), - Data) - : Macro->parseMacinfo(Data)) { - RecoverableErrorHandler(std::move(Err)); - Macro = nullptr; - } - }; - switch (SectionType) { - case MacinfoSection: { - DWARFDataExtractor Data(DObj->getMacinfoSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/false); - break; - } - case MacinfoDwoSection: { - DWARFDataExtractor Data(DObj->getMacinfoDWOSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/false); - break; - } - case MacroSection: { - DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(), - 0); - ParseAndDump(Data, /*IsMacro=*/true); - break; - } - case MacroDwoSection: { - DWARFDataExtractor Data(DObj->getMacroDWOSection(), isLittleEndian(), 0); - ParseAndDump(Data, /*IsMacro=*/true); - break; - } - } - return Macro; -} - -static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts, - DWARFDataExtractor Data, - const MCRegisterInfo *MRI, - const DWARFObject &Obj, - Optional<uint64_t> DumpOffset) { - uint64_t Offset = 0; - - while (Data.isValidOffset(Offset)) { - DWARFListTableHeader Header(".debug_loclists", "locations"); - if (Error E = Header.extract(Data, &Offset)) { - DumpOpts.RecoverableErrorHandler(std::move(E)); - return; - } - + } + } +} + +std::unique_ptr<DWARFDebugMacro> +DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) { + auto Macro = std::make_unique<DWARFDebugMacro>(); + auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) { + if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection + ? compile_units() + : dwo_compile_units(), + SectionType == MacroSection + ? getStringExtractor() + : getStringDWOExtractor(), + Data) + : Macro->parseMacinfo(Data)) { + RecoverableErrorHandler(std::move(Err)); + Macro = nullptr; + } + }; + switch (SectionType) { + case MacinfoSection: { + DWARFDataExtractor Data(DObj->getMacinfoSection(), isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/false); + break; + } + case MacinfoDwoSection: { + DWARFDataExtractor Data(DObj->getMacinfoDWOSection(), isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/false); + break; + } + case MacroSection: { + DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(), + 0); + ParseAndDump(Data, /*IsMacro=*/true); + break; + } + case MacroDwoSection: { + DWARFDataExtractor Data(DObj->getMacroDWOSection(), isLittleEndian(), 0); + ParseAndDump(Data, /*IsMacro=*/true); + break; + } + } + return Macro; +} + +static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts, + DWARFDataExtractor Data, + const MCRegisterInfo *MRI, + const DWARFObject &Obj, + Optional<uint64_t> DumpOffset) { + uint64_t Offset = 0; + + while (Data.isValidOffset(Offset)) { + DWARFListTableHeader Header(".debug_loclists", "locations"); + if (Error E = Header.extract(Data, &Offset)) { + DumpOpts.RecoverableErrorHandler(std::move(E)); + return; + } + Header.dump(Data, OS, DumpOpts); - - uint64_t EndOffset = Header.length() + Header.getHeaderOffset(); - Data.setAddressSize(Header.getAddrSize()); - DWARFDebugLoclists Loc(Data, Header.getVersion()); - if (DumpOffset) { - if (DumpOffset >= Offset && DumpOffset < EndOffset) { - Offset = *DumpOffset; - Loc.dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, nullptr, - DumpOpts, /*Indent=*/0); - OS << "\n"; - return; - } - } else { - Loc.dumpRange(Offset, EndOffset - Offset, OS, MRI, Obj, DumpOpts); - } - Offset = EndOffset; - } -} - -static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts, - DWARFDataExtractor Data, bool GnuStyle) { - DWARFDebugPubTable Table; - Table.extract(Data, GnuStyle, DumpOpts.RecoverableErrorHandler); - Table.dump(OS); -} - -void DWARFContext::dump( - raw_ostream &OS, DIDumpOptions DumpOpts, - std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) { - uint64_t DumpType = DumpOpts.DumpType; - - StringRef Extension = sys::path::extension(DObj->getFileName()); - bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp"); - - // Print UUID header. - const auto *ObjFile = DObj->getFile(); - if (DumpType & DIDT_UUID) - dumpUUID(OS, *ObjFile); - - // Print a header for each explicitly-requested section. - // Otherwise just print one for non-empty sections. - // Only print empty .dwo section headers when dumping a .dwo file. - bool Explicit = DumpType != DIDT_All && !IsDWO; - bool ExplicitDWO = Explicit && IsDWO; - auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID, - StringRef Section) -> Optional<uint64_t> * { - unsigned Mask = 1U << ID; - bool Should = (DumpType & Mask) && (Explicit || !Section.empty()); - if (!Should) - return nullptr; - OS << "\n" << Name << " contents:\n"; - return &DumpOffsets[ID]; - }; - - // Dump individual sections. - if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev, - DObj->getAbbrevSection())) - getDebugAbbrev()->dump(OS); - if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev, - DObj->getAbbrevDWOSection())) - getDebugAbbrevDWO()->dump(OS); - - auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) { - OS << '\n' << Name << " contents:\n"; - if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo]) - for (const auto &U : Units) - U->getDIEForOffset(DumpOffset.getValue()) - .dump(OS, 0, DumpOpts.noImplicitRecursion()); - else - for (const auto &U : Units) - U->dump(OS, DumpOpts); - }; - if ((DumpType & DIDT_DebugInfo)) { - if (Explicit || getNumCompileUnits()) - dumpDebugInfo(".debug_info", info_section_units()); - if (ExplicitDWO || getNumDWOCompileUnits()) - dumpDebugInfo(".debug_info.dwo", dwo_info_section_units()); - } - - auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) { - OS << '\n' << Name << " contents:\n"; - for (const auto &U : Units) - if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugTypes]) - U->getDIEForOffset(*DumpOffset) - .dump(OS, 0, DumpOpts.noImplicitRecursion()); - else - U->dump(OS, DumpOpts); - }; - if ((DumpType & DIDT_DebugTypes)) { - if (Explicit || getNumTypeUnits()) - dumpDebugType(".debug_types", types_section_units()); - if (ExplicitDWO || getNumDWOTypeUnits()) - dumpDebugType(".debug_types.dwo", dwo_types_section_units()); - } - - DIDumpOptions LLDumpOpts = DumpOpts; - if (LLDumpOpts.Verbose) - LLDumpOpts.DisplayRawContents = true; - - if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc, - DObj->getLocSection().Data)) { - getDebugLoc()->dump(OS, getRegisterInfo(), *DObj, LLDumpOpts, *Off); - } - if (const auto *Off = - shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists, - DObj->getLoclistsSection().Data)) { - DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(), - 0); - dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off); - } - if (const auto *Off = - shouldDump(ExplicitDWO, ".debug_loclists.dwo", DIDT_ID_DebugLoclists, - DObj->getLoclistsDWOSection().Data)) { - DWARFDataExtractor Data(*DObj, DObj->getLoclistsDWOSection(), - isLittleEndian(), 0); - dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off); - } - - if (const auto *Off = - shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc, - DObj->getLocDWOSection().Data)) { - DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(), - 4); - DWARFDebugLoclists Loc(Data, /*Version=*/4); - if (*Off) { - uint64_t Offset = **Off; - Loc.dumpLocationList(&Offset, OS, - /*BaseAddr=*/None, getRegisterInfo(), *DObj, nullptr, - LLDumpOpts, /*Indent=*/0); - OS << "\n"; - } else { - Loc.dumpRange(0, Data.getData().size(), OS, getRegisterInfo(), *DObj, - LLDumpOpts); - } - } - - if (const Optional<uint64_t> *Off = - shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame, - DObj->getFrameSection().Data)) { - if (Expected<const DWARFDebugFrame *> DF = getDebugFrame()) + + uint64_t EndOffset = Header.length() + Header.getHeaderOffset(); + Data.setAddressSize(Header.getAddrSize()); + DWARFDebugLoclists Loc(Data, Header.getVersion()); + if (DumpOffset) { + if (DumpOffset >= Offset && DumpOffset < EndOffset) { + Offset = *DumpOffset; + Loc.dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, nullptr, + DumpOpts, /*Indent=*/0); + OS << "\n"; + return; + } + } else { + Loc.dumpRange(Offset, EndOffset - Offset, OS, MRI, Obj, DumpOpts); + } + Offset = EndOffset; + } +} + +static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts, + DWARFDataExtractor Data, bool GnuStyle) { + DWARFDebugPubTable Table; + Table.extract(Data, GnuStyle, DumpOpts.RecoverableErrorHandler); + Table.dump(OS); +} + +void DWARFContext::dump( + raw_ostream &OS, DIDumpOptions DumpOpts, + std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) { + uint64_t DumpType = DumpOpts.DumpType; + + StringRef Extension = sys::path::extension(DObj->getFileName()); + bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp"); + + // Print UUID header. + const auto *ObjFile = DObj->getFile(); + if (DumpType & DIDT_UUID) + dumpUUID(OS, *ObjFile); + + // Print a header for each explicitly-requested section. + // Otherwise just print one for non-empty sections. + // Only print empty .dwo section headers when dumping a .dwo file. + bool Explicit = DumpType != DIDT_All && !IsDWO; + bool ExplicitDWO = Explicit && IsDWO; + auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID, + StringRef Section) -> Optional<uint64_t> * { + unsigned Mask = 1U << ID; + bool Should = (DumpType & Mask) && (Explicit || !Section.empty()); + if (!Should) + return nullptr; + OS << "\n" << Name << " contents:\n"; + return &DumpOffsets[ID]; + }; + + // Dump individual sections. + if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev, + DObj->getAbbrevSection())) + getDebugAbbrev()->dump(OS); + if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev, + DObj->getAbbrevDWOSection())) + getDebugAbbrevDWO()->dump(OS); + + auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) { + OS << '\n' << Name << " contents:\n"; + if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo]) + for (const auto &U : Units) + U->getDIEForOffset(DumpOffset.getValue()) + .dump(OS, 0, DumpOpts.noImplicitRecursion()); + else + for (const auto &U : Units) + U->dump(OS, DumpOpts); + }; + if ((DumpType & DIDT_DebugInfo)) { + if (Explicit || getNumCompileUnits()) + dumpDebugInfo(".debug_info", info_section_units()); + if (ExplicitDWO || getNumDWOCompileUnits()) + dumpDebugInfo(".debug_info.dwo", dwo_info_section_units()); + } + + auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) { + OS << '\n' << Name << " contents:\n"; + for (const auto &U : Units) + if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugTypes]) + U->getDIEForOffset(*DumpOffset) + .dump(OS, 0, DumpOpts.noImplicitRecursion()); + else + U->dump(OS, DumpOpts); + }; + if ((DumpType & DIDT_DebugTypes)) { + if (Explicit || getNumTypeUnits()) + dumpDebugType(".debug_types", types_section_units()); + if (ExplicitDWO || getNumDWOTypeUnits()) + dumpDebugType(".debug_types.dwo", dwo_types_section_units()); + } + + DIDumpOptions LLDumpOpts = DumpOpts; + if (LLDumpOpts.Verbose) + LLDumpOpts.DisplayRawContents = true; + + if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc, + DObj->getLocSection().Data)) { + getDebugLoc()->dump(OS, getRegisterInfo(), *DObj, LLDumpOpts, *Off); + } + if (const auto *Off = + shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists, + DObj->getLoclistsSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(), + 0); + dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off); + } + if (const auto *Off = + shouldDump(ExplicitDWO, ".debug_loclists.dwo", DIDT_ID_DebugLoclists, + DObj->getLoclistsDWOSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getLoclistsDWOSection(), + isLittleEndian(), 0); + dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off); + } + + if (const auto *Off = + shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc, + DObj->getLocDWOSection().Data)) { + DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(), + 4); + DWARFDebugLoclists Loc(Data, /*Version=*/4); + if (*Off) { + uint64_t Offset = **Off; + Loc.dumpLocationList(&Offset, OS, + /*BaseAddr=*/None, getRegisterInfo(), *DObj, nullptr, + LLDumpOpts, /*Indent=*/0); + OS << "\n"; + } else { + Loc.dumpRange(0, Data.getData().size(), OS, getRegisterInfo(), *DObj, + LLDumpOpts); + } + } + + if (const Optional<uint64_t> *Off = + shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame, + DObj->getFrameSection().Data)) { + if (Expected<const DWARFDebugFrame *> DF = getDebugFrame()) (*DF)->dump(OS, DumpOpts, getRegisterInfo(), *Off); - else - RecoverableErrorHandler(DF.takeError()); - } - - if (const Optional<uint64_t> *Off = - shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame, - DObj->getEHFrameSection().Data)) { - if (Expected<const DWARFDebugFrame *> DF = getEHFrame()) + else + RecoverableErrorHandler(DF.takeError()); + } + + if (const Optional<uint64_t> *Off = + shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame, + DObj->getEHFrameSection().Data)) { + if (Expected<const DWARFDebugFrame *> DF = getEHFrame()) (*DF)->dump(OS, DumpOpts, getRegisterInfo(), *Off); - else - RecoverableErrorHandler(DF.takeError()); - } - - if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro, - DObj->getMacroSection().Data)) { - if (auto Macro = getDebugMacro()) - Macro->dump(OS); - } - - if (shouldDump(Explicit, ".debug_macro.dwo", DIDT_ID_DebugMacro, - DObj->getMacroDWOSection())) { - if (auto MacroDWO = getDebugMacroDWO()) - MacroDWO->dump(OS); - } - - if (shouldDump(Explicit, ".debug_macinfo", DIDT_ID_DebugMacro, - DObj->getMacinfoSection())) { - if (auto Macinfo = getDebugMacinfo()) - Macinfo->dump(OS); - } - - if (shouldDump(Explicit, ".debug_macinfo.dwo", DIDT_ID_DebugMacro, - DObj->getMacinfoDWOSection())) { - if (auto MacinfoDWO = getDebugMacinfoDWO()) - MacinfoDWO->dump(OS); - } - - if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges, - DObj->getArangesSection())) { - uint64_t offset = 0; - DWARFDataExtractor arangesData(DObj->getArangesSection(), isLittleEndian(), - 0); - DWARFDebugArangeSet set; - while (arangesData.isValidOffset(offset)) { + else + RecoverableErrorHandler(DF.takeError()); + } + + if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro, + DObj->getMacroSection().Data)) { + if (auto Macro = getDebugMacro()) + Macro->dump(OS); + } + + if (shouldDump(Explicit, ".debug_macro.dwo", DIDT_ID_DebugMacro, + DObj->getMacroDWOSection())) { + if (auto MacroDWO = getDebugMacroDWO()) + MacroDWO->dump(OS); + } + + if (shouldDump(Explicit, ".debug_macinfo", DIDT_ID_DebugMacro, + DObj->getMacinfoSection())) { + if (auto Macinfo = getDebugMacinfo()) + Macinfo->dump(OS); + } + + if (shouldDump(Explicit, ".debug_macinfo.dwo", DIDT_ID_DebugMacro, + DObj->getMacinfoDWOSection())) { + if (auto MacinfoDWO = getDebugMacinfoDWO()) + MacinfoDWO->dump(OS); + } + + if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges, + DObj->getArangesSection())) { + uint64_t offset = 0; + DWARFDataExtractor arangesData(DObj->getArangesSection(), isLittleEndian(), + 0); + DWARFDebugArangeSet set; + while (arangesData.isValidOffset(offset)) { if (Error E = set.extract(arangesData, &offset, DumpOpts.WarningHandler)) { - RecoverableErrorHandler(std::move(E)); - break; - } - set.dump(OS); - } - } - - auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser, - DIDumpOptions DumpOpts, - Optional<uint64_t> DumpOffset) { - while (!Parser.done()) { - if (DumpOffset && Parser.getOffset() != *DumpOffset) { - Parser.skip(DumpOpts.WarningHandler, DumpOpts.WarningHandler); - continue; - } - OS << "debug_line[" << format("0x%8.8" PRIx64, Parser.getOffset()) - << "]\n"; - Parser.parseNext(DumpOpts.WarningHandler, DumpOpts.WarningHandler, &OS, - DumpOpts.Verbose); - } - }; - + RecoverableErrorHandler(std::move(E)); + break; + } + set.dump(OS); + } + } + + auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser, + DIDumpOptions DumpOpts, + Optional<uint64_t> DumpOffset) { + while (!Parser.done()) { + if (DumpOffset && Parser.getOffset() != *DumpOffset) { + Parser.skip(DumpOpts.WarningHandler, DumpOpts.WarningHandler); + continue; + } + OS << "debug_line[" << format("0x%8.8" PRIx64, Parser.getOffset()) + << "]\n"; + Parser.parseNext(DumpOpts.WarningHandler, DumpOpts.WarningHandler, &OS, + DumpOpts.Verbose); + } + }; + auto DumpStrSection = [&](StringRef Section) { DataExtractor StrData(Section, isLittleEndian(), 0); uint64_t Offset = 0; @@ -544,1171 +544,1171 @@ void DWARFContext::dump( } }; - if (const auto *Off = shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine, - DObj->getLineSection().Data)) { - DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(), - 0); + if (const auto *Off = shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine, + DObj->getLineSection().Data)) { + DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(), + 0); DWARFDebugLine::SectionParser Parser(LineData, *this, normal_units()); - DumpLineSection(Parser, DumpOpts, *Off); - } - - if (const auto *Off = - shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine, - DObj->getLineDWOSection().Data)) { - DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(), - isLittleEndian(), 0); + DumpLineSection(Parser, DumpOpts, *Off); + } + + if (const auto *Off = + shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine, + DObj->getLineDWOSection().Data)) { + DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(), + isLittleEndian(), 0); DWARFDebugLine::SectionParser Parser(LineData, *this, dwo_units()); - DumpLineSection(Parser, DumpOpts, *Off); - } - - if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex, - DObj->getCUIndexSection())) { - getCUIndex().dump(OS); - } - - if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex, - DObj->getTUIndexSection())) { - getTUIndex().dump(OS); - } - - if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr, + DumpLineSection(Parser, DumpOpts, *Off); + } + + if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex, + DObj->getCUIndexSection())) { + getCUIndex().dump(OS); + } + + if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex, + DObj->getTUIndexSection())) { + getTUIndex().dump(OS); + } + + if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr, DObj->getStrSection())) DumpStrSection(DObj->getStrSection()); - if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr, + if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr, DObj->getStrDWOSection())) DumpStrSection(DObj->getStrDWOSection()); - if (shouldDump(Explicit, ".debug_line_str", DIDT_ID_DebugLineStr, + if (shouldDump(Explicit, ".debug_line_str", DIDT_ID_DebugLineStr, DObj->getLineStrSection())) DumpStrSection(DObj->getLineStrSection()); - - if (shouldDump(Explicit, ".debug_addr", DIDT_ID_DebugAddr, - DObj->getAddrSection().Data)) { - DWARFDataExtractor AddrData(*DObj, DObj->getAddrSection(), - isLittleEndian(), 0); - dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize()); - } - - if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges, - DObj->getRangesSection().Data)) { - uint8_t savedAddressByteSize = getCUAddrSize(); - DWARFDataExtractor rangesData(*DObj, DObj->getRangesSection(), - isLittleEndian(), savedAddressByteSize); - uint64_t offset = 0; - DWARFDebugRangeList rangeList; - while (rangesData.isValidOffset(offset)) { - if (Error E = rangeList.extract(rangesData, &offset)) { - DumpOpts.RecoverableErrorHandler(std::move(E)); - break; - } - rangeList.dump(OS); - } - } - - auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> { - const auto &CUs = compile_units(); - auto I = CUs.begin(); - if (I == CUs.end()) - return None; - return (*I)->getAddrOffsetSectionItem(Index); - }; - - if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists, - DObj->getRnglistsSection().Data)) { - DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(), - isLittleEndian(), 0); - dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts); - } - - if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists, - DObj->getRnglistsDWOSection().Data)) { - DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(), - isLittleEndian(), 0); - dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts); - } - - if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, - DObj->getPubnamesSection().Data)) { - DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(), - isLittleEndian(), 0); - dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); - } - - if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes, - DObj->getPubtypesSection().Data)) { - DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(), - isLittleEndian(), 0); - dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); - } - - if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames, - DObj->getGnuPubnamesSection().Data)) { - DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(), - isLittleEndian(), 0); - dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); - } - - if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes, - DObj->getGnuPubtypesSection().Data)) { - DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(), - isLittleEndian(), 0); - dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); - } - - if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets, - DObj->getStrOffsetsSection().Data)) - dumpStringOffsetsSection( - OS, DumpOpts, "debug_str_offsets", *DObj, DObj->getStrOffsetsSection(), - DObj->getStrSection(), normal_units(), isLittleEndian()); - if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets, - DObj->getStrOffsetsDWOSection().Data)) - dumpStringOffsetsSection(OS, DumpOpts, "debug_str_offsets.dwo", *DObj, - DObj->getStrOffsetsDWOSection(), - DObj->getStrDWOSection(), dwo_units(), - isLittleEndian()); - - if (shouldDump(Explicit, ".gdb_index", DIDT_ID_GdbIndex, - DObj->getGdbIndexSection())) { - getGdbIndex().dump(OS); - } - - if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames, - DObj->getAppleNamesSection().Data)) - getAppleNames().dump(OS); - - if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes, - DObj->getAppleTypesSection().Data)) - getAppleTypes().dump(OS); - - if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces, - DObj->getAppleNamespacesSection().Data)) - getAppleNamespaces().dump(OS); - - if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC, - DObj->getAppleObjCSection().Data)) - getAppleObjC().dump(OS); - if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames, - DObj->getNamesSection().Data)) - getDebugNames().dump(OS); -} - -DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) { - parseDWOUnits(LazyParse); - - if (const auto &CUI = getCUIndex()) { - if (const auto *R = CUI.getFromHash(Hash)) - return dyn_cast_or_null<DWARFCompileUnit>( - DWOUnits.getUnitForIndexEntry(*R)); - return nullptr; - } - - // If there's no index, just search through the CUs in the DWO - there's - // probably only one unless this is something like LTO - though an in-process - // built/cached lookup table could be used in that case to improve repeated - // lookups of different CUs in the DWO. - for (const auto &DWOCU : dwo_compile_units()) { - // Might not have parsed DWO ID yet. - if (!DWOCU->getDWOId()) { - if (Optional<uint64_t> DWOId = - toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id))) - DWOCU->setDWOId(*DWOId); - else - // No DWO ID? - continue; - } - if (DWOCU->getDWOId() == Hash) - return dyn_cast<DWARFCompileUnit>(DWOCU.get()); - } - return nullptr; -} - -DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) { - parseNormalUnits(); - if (auto *CU = NormalUnits.getUnitForOffset(Offset)) - return CU->getDIEForOffset(Offset); - return DWARFDie(); -} - -bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) { - bool Success = true; - DWARFVerifier verifier(OS, *this, DumpOpts); - - Success &= verifier.handleDebugAbbrev(); - if (DumpOpts.DumpType & DIDT_DebugInfo) - Success &= verifier.handleDebugInfo(); - if (DumpOpts.DumpType & DIDT_DebugLine) - Success &= verifier.handleDebugLine(); - Success &= verifier.handleAccelTables(); - return Success; -} - -const DWARFUnitIndex &DWARFContext::getCUIndex() { - if (CUIndex) - return *CUIndex; - - DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0); - - CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO); - CUIndex->parse(CUIndexData); - return *CUIndex; -} - -const DWARFUnitIndex &DWARFContext::getTUIndex() { - if (TUIndex) - return *TUIndex; - - DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0); - - TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_EXT_TYPES); - TUIndex->parse(TUIndexData); - return *TUIndex; -} - -DWARFGdbIndex &DWARFContext::getGdbIndex() { - if (GdbIndex) - return *GdbIndex; - - DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0); - GdbIndex = std::make_unique<DWARFGdbIndex>(); - GdbIndex->parse(GdbIndexData); - return *GdbIndex; -} - -const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { - if (Abbrev) - return Abbrev.get(); - - DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0); - - Abbrev.reset(new DWARFDebugAbbrev()); - Abbrev->extract(abbrData); - return Abbrev.get(); -} - -const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { - if (AbbrevDWO) - return AbbrevDWO.get(); - - DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0); - AbbrevDWO.reset(new DWARFDebugAbbrev()); - AbbrevDWO->extract(abbrData); - return AbbrevDWO.get(); -} - -const DWARFDebugLoc *DWARFContext::getDebugLoc() { - if (Loc) - return Loc.get(); - - // Assume all units have the same address byte size. - auto LocData = - getNumCompileUnits() - ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(), - getUnitAtIndex(0)->getAddressByteSize()) - : DWARFDataExtractor("", isLittleEndian(), 0); - Loc.reset(new DWARFDebugLoc(std::move(LocData))); - return Loc.get(); -} - -const DWARFDebugAranges *DWARFContext::getDebugAranges() { - if (Aranges) - return Aranges.get(); - - Aranges.reset(new DWARFDebugAranges()); - Aranges->generate(this); - return Aranges.get(); -} - -Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() { - if (DebugFrame) - return DebugFrame.get(); - - // There's a "bug" in the DWARFv3 standard with respect to the target address - // size within debug frame sections. While DWARF is supposed to be independent - // of its container, FDEs have fields with size being "target address size", - // which isn't specified in DWARF in general. It's only specified for CUs, but - // .eh_frame can appear without a .debug_info section. Follow the example of - // other tools (libdwarf) and extract this from the container (ObjectFile - // provides this information). This problem is fixed in DWARFv4 - // See this dwarf-discuss discussion for more details: - // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html - DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(), - isLittleEndian(), DObj->getAddressSize()); - auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false); - if (Error E = DF->parse(debugFrameData)) - return std::move(E); - - DebugFrame.swap(DF); - return DebugFrame.get(); -} - -Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() { - if (EHFrame) - return EHFrame.get(); - - DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(), - isLittleEndian(), DObj->getAddressSize()); - - auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true); - if (Error E = DF->parse(debugFrameData)) - return std::move(E); - DebugFrame.swap(DF); - return DebugFrame.get(); -} - -const DWARFDebugMacro *DWARFContext::getDebugMacro() { - if (!Macro) - Macro = parseMacroOrMacinfo(MacroSection); - return Macro.get(); -} - -const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() { - if (!MacroDWO) - MacroDWO = parseMacroOrMacinfo(MacroDwoSection); - return MacroDWO.get(); -} - -const DWARFDebugMacro *DWARFContext::getDebugMacinfo() { - if (!Macinfo) - Macinfo = parseMacroOrMacinfo(MacinfoSection); - return Macinfo.get(); -} - -const DWARFDebugMacro *DWARFContext::getDebugMacinfoDWO() { - if (!MacinfoDWO) - MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection); - return MacinfoDWO.get(); -} - -template <typename T> -static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj, - const DWARFSection &Section, StringRef StringSection, - bool IsLittleEndian) { - if (Cache) - return *Cache; - DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0); - DataExtractor StrData(StringSection, IsLittleEndian, 0); - Cache.reset(new T(AccelSection, StrData)); - if (Error E = Cache->extract()) - llvm::consumeError(std::move(E)); - return *Cache; -} - -const DWARFDebugNames &DWARFContext::getDebugNames() { - return getAccelTable(Names, *DObj, DObj->getNamesSection(), - DObj->getStrSection(), isLittleEndian()); -} - -const AppleAcceleratorTable &DWARFContext::getAppleNames() { - return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(), - DObj->getStrSection(), isLittleEndian()); -} - -const AppleAcceleratorTable &DWARFContext::getAppleTypes() { - return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(), - DObj->getStrSection(), isLittleEndian()); -} - -const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() { - return getAccelTable(AppleNamespaces, *DObj, - DObj->getAppleNamespacesSection(), - DObj->getStrSection(), isLittleEndian()); -} - -const AppleAcceleratorTable &DWARFContext::getAppleObjC() { - return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(), - DObj->getStrSection(), isLittleEndian()); -} - -const DWARFDebugLine::LineTable * -DWARFContext::getLineTableForUnit(DWARFUnit *U) { - Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable = - getLineTableForUnit(U, WarningHandler); - if (!ExpectedLineTable) { - WarningHandler(ExpectedLineTable.takeError()); - return nullptr; - } - return *ExpectedLineTable; -} - -Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit( - DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) { - if (!Line) - Line.reset(new DWARFDebugLine); - - auto UnitDIE = U->getUnitDIE(); - if (!UnitDIE) - return nullptr; - - auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); - if (!Offset) - return nullptr; // No line table for this compile unit. - - uint64_t stmtOffset = *Offset + U->getLineTableOffset(); - // See if the line table is cached. - if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) - return lt; - - // Make sure the offset is good before we try to parse. - if (stmtOffset >= U->getLineSection().Data.size()) - return nullptr; - - // We have to parse it first. - DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(), - U->getAddressByteSize()); - return Line->getOrParseLineTable(lineData, stmtOffset, *this, U, - RecoverableErrorHandler); -} - -void DWARFContext::parseNormalUnits() { - if (!NormalUnits.empty()) - return; - DObj->forEachInfoSections([&](const DWARFSection &S) { - NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO); - }); - NormalUnits.finishedInfoUnits(); - DObj->forEachTypesSections([&](const DWARFSection &S) { - NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES); - }); -} - -void DWARFContext::parseDWOUnits(bool Lazy) { - if (!DWOUnits.empty()) - return; - DObj->forEachInfoDWOSections([&](const DWARFSection &S) { - DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy); - }); - DWOUnits.finishedInfoUnits(); - DObj->forEachTypesDWOSections([&](const DWARFSection &S) { - DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy); - }); -} - -DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) { - parseNormalUnits(); - return dyn_cast_or_null<DWARFCompileUnit>( - NormalUnits.getUnitForOffset(Offset)); -} - -DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { - // First, get the offset of the compile unit. - uint64_t CUOffset = getDebugAranges()->findAddress(Address); - // Retrieve the compile unit. - return getCompileUnitForOffset(CUOffset); -} - -DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { - DIEsForAddress Result; - - DWARFCompileUnit *CU = getCompileUnitForAddress(Address); - if (!CU) - return Result; - - Result.CompileUnit = CU; - Result.FunctionDIE = CU->getSubroutineForAddress(Address); - - std::vector<DWARFDie> Worklist; - Worklist.push_back(Result.FunctionDIE); - while (!Worklist.empty()) { - DWARFDie DIE = Worklist.back(); - Worklist.pop_back(); - - if (!DIE.isValid()) - continue; - - if (DIE.getTag() == DW_TAG_lexical_block && - DIE.addressRangeContainsAddress(Address)) { - Result.BlockDIE = DIE; - break; - } - - for (auto Child : DIE) - Worklist.push_back(Child); - } - - return Result; -} - -/// TODO: change input parameter from "uint64_t Address" -/// into "SectionedAddress Address" -static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU, - uint64_t Address, - FunctionNameKind Kind, + + if (shouldDump(Explicit, ".debug_addr", DIDT_ID_DebugAddr, + DObj->getAddrSection().Data)) { + DWARFDataExtractor AddrData(*DObj, DObj->getAddrSection(), + isLittleEndian(), 0); + dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize()); + } + + if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges, + DObj->getRangesSection().Data)) { + uint8_t savedAddressByteSize = getCUAddrSize(); + DWARFDataExtractor rangesData(*DObj, DObj->getRangesSection(), + isLittleEndian(), savedAddressByteSize); + uint64_t offset = 0; + DWARFDebugRangeList rangeList; + while (rangesData.isValidOffset(offset)) { + if (Error E = rangeList.extract(rangesData, &offset)) { + DumpOpts.RecoverableErrorHandler(std::move(E)); + break; + } + rangeList.dump(OS); + } + } + + auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> { + const auto &CUs = compile_units(); + auto I = CUs.begin(); + if (I == CUs.end()) + return None; + return (*I)->getAddrOffsetSectionItem(Index); + }; + + if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists, + DObj->getRnglistsSection().Data)) { + DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(), + isLittleEndian(), 0); + dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts); + } + + if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists, + DObj->getRnglistsDWOSection().Data)) { + DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(), + isLittleEndian(), 0); + dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts); + } + + if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames, + DObj->getPubnamesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); + } + + if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes, + DObj->getPubtypesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false); + } + + if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames, + DObj->getGnuPubnamesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); + } + + if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes, + DObj->getGnuPubtypesSection().Data)) { + DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(), + isLittleEndian(), 0); + dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true); + } + + if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets, + DObj->getStrOffsetsSection().Data)) + dumpStringOffsetsSection( + OS, DumpOpts, "debug_str_offsets", *DObj, DObj->getStrOffsetsSection(), + DObj->getStrSection(), normal_units(), isLittleEndian()); + if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets, + DObj->getStrOffsetsDWOSection().Data)) + dumpStringOffsetsSection(OS, DumpOpts, "debug_str_offsets.dwo", *DObj, + DObj->getStrOffsetsDWOSection(), + DObj->getStrDWOSection(), dwo_units(), + isLittleEndian()); + + if (shouldDump(Explicit, ".gdb_index", DIDT_ID_GdbIndex, + DObj->getGdbIndexSection())) { + getGdbIndex().dump(OS); + } + + if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames, + DObj->getAppleNamesSection().Data)) + getAppleNames().dump(OS); + + if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes, + DObj->getAppleTypesSection().Data)) + getAppleTypes().dump(OS); + + if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces, + DObj->getAppleNamespacesSection().Data)) + getAppleNamespaces().dump(OS); + + if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC, + DObj->getAppleObjCSection().Data)) + getAppleObjC().dump(OS); + if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames, + DObj->getNamesSection().Data)) + getDebugNames().dump(OS); +} + +DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) { + parseDWOUnits(LazyParse); + + if (const auto &CUI = getCUIndex()) { + if (const auto *R = CUI.getFromHash(Hash)) + return dyn_cast_or_null<DWARFCompileUnit>( + DWOUnits.getUnitForIndexEntry(*R)); + return nullptr; + } + + // If there's no index, just search through the CUs in the DWO - there's + // probably only one unless this is something like LTO - though an in-process + // built/cached lookup table could be used in that case to improve repeated + // lookups of different CUs in the DWO. + for (const auto &DWOCU : dwo_compile_units()) { + // Might not have parsed DWO ID yet. + if (!DWOCU->getDWOId()) { + if (Optional<uint64_t> DWOId = + toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id))) + DWOCU->setDWOId(*DWOId); + else + // No DWO ID? + continue; + } + if (DWOCU->getDWOId() == Hash) + return dyn_cast<DWARFCompileUnit>(DWOCU.get()); + } + return nullptr; +} + +DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) { + parseNormalUnits(); + if (auto *CU = NormalUnits.getUnitForOffset(Offset)) + return CU->getDIEForOffset(Offset); + return DWARFDie(); +} + +bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) { + bool Success = true; + DWARFVerifier verifier(OS, *this, DumpOpts); + + Success &= verifier.handleDebugAbbrev(); + if (DumpOpts.DumpType & DIDT_DebugInfo) + Success &= verifier.handleDebugInfo(); + if (DumpOpts.DumpType & DIDT_DebugLine) + Success &= verifier.handleDebugLine(); + Success &= verifier.handleAccelTables(); + return Success; +} + +const DWARFUnitIndex &DWARFContext::getCUIndex() { + if (CUIndex) + return *CUIndex; + + DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0); + + CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO); + CUIndex->parse(CUIndexData); + return *CUIndex; +} + +const DWARFUnitIndex &DWARFContext::getTUIndex() { + if (TUIndex) + return *TUIndex; + + DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0); + + TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_EXT_TYPES); + TUIndex->parse(TUIndexData); + return *TUIndex; +} + +DWARFGdbIndex &DWARFContext::getGdbIndex() { + if (GdbIndex) + return *GdbIndex; + + DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0); + GdbIndex = std::make_unique<DWARFGdbIndex>(); + GdbIndex->parse(GdbIndexData); + return *GdbIndex; +} + +const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() { + if (Abbrev) + return Abbrev.get(); + + DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0); + + Abbrev.reset(new DWARFDebugAbbrev()); + Abbrev->extract(abbrData); + return Abbrev.get(); +} + +const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() { + if (AbbrevDWO) + return AbbrevDWO.get(); + + DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0); + AbbrevDWO.reset(new DWARFDebugAbbrev()); + AbbrevDWO->extract(abbrData); + return AbbrevDWO.get(); +} + +const DWARFDebugLoc *DWARFContext::getDebugLoc() { + if (Loc) + return Loc.get(); + + // Assume all units have the same address byte size. + auto LocData = + getNumCompileUnits() + ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(), + getUnitAtIndex(0)->getAddressByteSize()) + : DWARFDataExtractor("", isLittleEndian(), 0); + Loc.reset(new DWARFDebugLoc(std::move(LocData))); + return Loc.get(); +} + +const DWARFDebugAranges *DWARFContext::getDebugAranges() { + if (Aranges) + return Aranges.get(); + + Aranges.reset(new DWARFDebugAranges()); + Aranges->generate(this); + return Aranges.get(); +} + +Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() { + if (DebugFrame) + return DebugFrame.get(); + + // There's a "bug" in the DWARFv3 standard with respect to the target address + // size within debug frame sections. While DWARF is supposed to be independent + // of its container, FDEs have fields with size being "target address size", + // which isn't specified in DWARF in general. It's only specified for CUs, but + // .eh_frame can appear without a .debug_info section. Follow the example of + // other tools (libdwarf) and extract this from the container (ObjectFile + // provides this information). This problem is fixed in DWARFv4 + // See this dwarf-discuss discussion for more details: + // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html + DWARFDataExtractor debugFrameData(*DObj, DObj->getFrameSection(), + isLittleEndian(), DObj->getAddressSize()); + auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false); + if (Error E = DF->parse(debugFrameData)) + return std::move(E); + + DebugFrame.swap(DF); + return DebugFrame.get(); +} + +Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() { + if (EHFrame) + return EHFrame.get(); + + DWARFDataExtractor debugFrameData(*DObj, DObj->getEHFrameSection(), + isLittleEndian(), DObj->getAddressSize()); + + auto DF = std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true); + if (Error E = DF->parse(debugFrameData)) + return std::move(E); + DebugFrame.swap(DF); + return DebugFrame.get(); +} + +const DWARFDebugMacro *DWARFContext::getDebugMacro() { + if (!Macro) + Macro = parseMacroOrMacinfo(MacroSection); + return Macro.get(); +} + +const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() { + if (!MacroDWO) + MacroDWO = parseMacroOrMacinfo(MacroDwoSection); + return MacroDWO.get(); +} + +const DWARFDebugMacro *DWARFContext::getDebugMacinfo() { + if (!Macinfo) + Macinfo = parseMacroOrMacinfo(MacinfoSection); + return Macinfo.get(); +} + +const DWARFDebugMacro *DWARFContext::getDebugMacinfoDWO() { + if (!MacinfoDWO) + MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection); + return MacinfoDWO.get(); +} + +template <typename T> +static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj, + const DWARFSection &Section, StringRef StringSection, + bool IsLittleEndian) { + if (Cache) + return *Cache; + DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0); + DataExtractor StrData(StringSection, IsLittleEndian, 0); + Cache.reset(new T(AccelSection, StrData)); + if (Error E = Cache->extract()) + llvm::consumeError(std::move(E)); + return *Cache; +} + +const DWARFDebugNames &DWARFContext::getDebugNames() { + return getAccelTable(Names, *DObj, DObj->getNamesSection(), + DObj->getStrSection(), isLittleEndian()); +} + +const AppleAcceleratorTable &DWARFContext::getAppleNames() { + return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(), + DObj->getStrSection(), isLittleEndian()); +} + +const AppleAcceleratorTable &DWARFContext::getAppleTypes() { + return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(), + DObj->getStrSection(), isLittleEndian()); +} + +const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() { + return getAccelTable(AppleNamespaces, *DObj, + DObj->getAppleNamespacesSection(), + DObj->getStrSection(), isLittleEndian()); +} + +const AppleAcceleratorTable &DWARFContext::getAppleObjC() { + return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(), + DObj->getStrSection(), isLittleEndian()); +} + +const DWARFDebugLine::LineTable * +DWARFContext::getLineTableForUnit(DWARFUnit *U) { + Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable = + getLineTableForUnit(U, WarningHandler); + if (!ExpectedLineTable) { + WarningHandler(ExpectedLineTable.takeError()); + return nullptr; + } + return *ExpectedLineTable; +} + +Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit( + DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) { + if (!Line) + Line.reset(new DWARFDebugLine); + + auto UnitDIE = U->getUnitDIE(); + if (!UnitDIE) + return nullptr; + + auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list)); + if (!Offset) + return nullptr; // No line table for this compile unit. + + uint64_t stmtOffset = *Offset + U->getLineTableOffset(); + // See if the line table is cached. + if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset)) + return lt; + + // Make sure the offset is good before we try to parse. + if (stmtOffset >= U->getLineSection().Data.size()) + return nullptr; + + // We have to parse it first. + DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(), + U->getAddressByteSize()); + return Line->getOrParseLineTable(lineData, stmtOffset, *this, U, + RecoverableErrorHandler); +} + +void DWARFContext::parseNormalUnits() { + if (!NormalUnits.empty()) + return; + DObj->forEachInfoSections([&](const DWARFSection &S) { + NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO); + }); + NormalUnits.finishedInfoUnits(); + DObj->forEachTypesSections([&](const DWARFSection &S) { + NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES); + }); +} + +void DWARFContext::parseDWOUnits(bool Lazy) { + if (!DWOUnits.empty()) + return; + DObj->forEachInfoDWOSections([&](const DWARFSection &S) { + DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy); + }); + DWOUnits.finishedInfoUnits(); + DObj->forEachTypesDWOSections([&](const DWARFSection &S) { + DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy); + }); +} + +DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) { + parseNormalUnits(); + return dyn_cast_or_null<DWARFCompileUnit>( + NormalUnits.getUnitForOffset(Offset)); +} + +DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) { + // First, get the offset of the compile unit. + uint64_t CUOffset = getDebugAranges()->findAddress(Address); + // Retrieve the compile unit. + return getCompileUnitForOffset(CUOffset); +} + +DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) { + DIEsForAddress Result; + + DWARFCompileUnit *CU = getCompileUnitForAddress(Address); + if (!CU) + return Result; + + Result.CompileUnit = CU; + Result.FunctionDIE = CU->getSubroutineForAddress(Address); + + std::vector<DWARFDie> Worklist; + Worklist.push_back(Result.FunctionDIE); + while (!Worklist.empty()) { + DWARFDie DIE = Worklist.back(); + Worklist.pop_back(); + + if (!DIE.isValid()) + continue; + + if (DIE.getTag() == DW_TAG_lexical_block && + DIE.addressRangeContainsAddress(Address)) { + Result.BlockDIE = DIE; + break; + } + + for (auto Child : DIE) + Worklist.push_back(Child); + } + + return Result; +} + +/// TODO: change input parameter from "uint64_t Address" +/// into "SectionedAddress Address" +static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU, + uint64_t Address, + FunctionNameKind Kind, DILineInfoSpecifier::FileLineInfoKind FileNameKind, - std::string &FunctionName, + std::string &FunctionName, std::string &StartFile, - uint32_t &StartLine) { - // The address may correspond to instruction in some inlined function, - // so we have to build the chain of inlined functions and take the - // name of the topmost function in it. - SmallVector<DWARFDie, 4> InlinedChain; - CU->getInlinedChainForAddress(Address, InlinedChain); - if (InlinedChain.empty()) - return false; - - const DWARFDie &DIE = InlinedChain[0]; - bool FoundResult = false; - const char *Name = nullptr; - if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) { - FunctionName = Name; - FoundResult = true; - } + uint32_t &StartLine) { + // The address may correspond to instruction in some inlined function, + // so we have to build the chain of inlined functions and take the + // name of the topmost function in it. + SmallVector<DWARFDie, 4> InlinedChain; + CU->getInlinedChainForAddress(Address, InlinedChain); + if (InlinedChain.empty()) + return false; + + const DWARFDie &DIE = InlinedChain[0]; + bool FoundResult = false; + const char *Name = nullptr; + if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) { + FunctionName = Name; + FoundResult = true; + } std::string DeclFile = DIE.getDeclFile(FileNameKind); if (!DeclFile.empty()) { StartFile = DeclFile; FoundResult = true; } - if (auto DeclLineResult = DIE.getDeclLine()) { - StartLine = DeclLineResult; - FoundResult = true; - } - - return FoundResult; -} - -static Optional<uint64_t> getTypeSize(DWARFDie Type, uint64_t PointerSize) { - if (auto SizeAttr = Type.find(DW_AT_byte_size)) - if (Optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant()) - return Size; - - switch (Type.getTag()) { - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - return PointerSize; - case DW_TAG_ptr_to_member_type: { - if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) - if (BaseType.getTag() == DW_TAG_subroutine_type) - return 2 * PointerSize; - return PointerSize; - } - case DW_TAG_const_type: - case DW_TAG_volatile_type: - case DW_TAG_restrict_type: - case DW_TAG_typedef: { - if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) - return getTypeSize(BaseType, PointerSize); - break; - } - case DW_TAG_array_type: { - DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type); - if (!BaseType) - return Optional<uint64_t>(); - Optional<uint64_t> BaseSize = getTypeSize(BaseType, PointerSize); - if (!BaseSize) - return Optional<uint64_t>(); - uint64_t Size = *BaseSize; - for (DWARFDie Child : Type) { - if (Child.getTag() != DW_TAG_subrange_type) - continue; - - if (auto ElemCountAttr = Child.find(DW_AT_count)) - if (Optional<uint64_t> ElemCount = - ElemCountAttr->getAsUnsignedConstant()) - Size *= *ElemCount; - if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound)) - if (Optional<int64_t> UpperBound = - UpperBoundAttr->getAsSignedConstant()) { - int64_t LowerBound = 0; - if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound)) - LowerBound = LowerBoundAttr->getAsSignedConstant().getValueOr(0); - Size *= *UpperBound - LowerBound + 1; - } - } - return Size; - } - default: - break; - } - return Optional<uint64_t>(); -} - -static Optional<int64_t> -getExpressionFrameOffset(ArrayRef<uint8_t> Expr, - Optional<unsigned> FrameBaseReg) { - if (!Expr.empty() && - (Expr[0] == DW_OP_fbreg || - (FrameBaseReg && Expr[0] == DW_OP_breg0 + *FrameBaseReg))) { - unsigned Count; - int64_t Offset = decodeSLEB128(Expr.data() + 1, &Count, Expr.end()); - // A single DW_OP_fbreg or DW_OP_breg. - if (Expr.size() == Count + 1) - return Offset; - // Same + DW_OP_deref (Fortran arrays look like this). - if (Expr.size() == Count + 2 && Expr[Count + 1] == DW_OP_deref) - return Offset; - // Fallthrough. Do not accept ex. (DW_OP_breg W29, DW_OP_stack_value) - } - return None; -} - -void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, - DWARFDie Die, std::vector<DILocal> &Result) { - if (Die.getTag() == DW_TAG_variable || - Die.getTag() == DW_TAG_formal_parameter) { - DILocal Local; - if (const char *Name = Subprogram.getSubroutineName(DINameKind::ShortName)) - Local.FunctionName = Name; - - Optional<unsigned> FrameBaseReg; - if (auto FrameBase = Subprogram.find(DW_AT_frame_base)) - if (Optional<ArrayRef<uint8_t>> Expr = FrameBase->getAsBlock()) - if (!Expr->empty() && (*Expr)[0] >= DW_OP_reg0 && - (*Expr)[0] <= DW_OP_reg31) { - FrameBaseReg = (*Expr)[0] - DW_OP_reg0; - } - - if (Expected<std::vector<DWARFLocationExpression>> Loc = - Die.getLocations(DW_AT_location)) { - for (const auto &Entry : *Loc) { - if (Optional<int64_t> FrameOffset = - getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) { - Local.FrameOffset = *FrameOffset; - break; - } - } - } else { - // FIXME: missing DW_AT_location is OK here, but other errors should be - // reported to the user. - consumeError(Loc.takeError()); - } - - if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset)) - Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant(); - - if (auto Origin = - Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) - Die = Origin; - if (auto NameAttr = Die.find(DW_AT_name)) - if (Optional<const char *> Name = NameAttr->getAsCString()) - Local.Name = *Name; - if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type)) - Local.Size = getTypeSize(Type, getCUAddrSize()); - if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) { - if (const auto *LT = CU->getContext().getLineTableForUnit(CU)) - LT->getFileNameByIndex( - DeclFileAttr->getAsUnsignedConstant().getValue(), - CU->getCompilationDir(), - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - Local.DeclFile); - } - if (auto DeclLineAttr = Die.find(DW_AT_decl_line)) - Local.DeclLine = DeclLineAttr->getAsUnsignedConstant().getValue(); - - Result.push_back(Local); - return; - } - - if (Die.getTag() == DW_TAG_inlined_subroutine) - if (auto Origin = - Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) - Subprogram = Origin; - - for (auto Child : Die) - addLocalsForDie(CU, Subprogram, Child, Result); -} - -std::vector<DILocal> -DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { - std::vector<DILocal> Result; - DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); - if (!CU) - return Result; - - DWARFDie Subprogram = CU->getSubroutineForAddress(Address.Address); - if (Subprogram.isValid()) - addLocalsForDie(CU, Subprogram, Subprogram, Result); - return Result; -} - -DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, - DILineInfoSpecifier Spec) { - DILineInfo Result; - - DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); - if (!CU) - return Result; - + if (auto DeclLineResult = DIE.getDeclLine()) { + StartLine = DeclLineResult; + FoundResult = true; + } + + return FoundResult; +} + +static Optional<uint64_t> getTypeSize(DWARFDie Type, uint64_t PointerSize) { + if (auto SizeAttr = Type.find(DW_AT_byte_size)) + if (Optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant()) + return Size; + + switch (Type.getTag()) { + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + return PointerSize; + case DW_TAG_ptr_to_member_type: { + if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) + if (BaseType.getTag() == DW_TAG_subroutine_type) + return 2 * PointerSize; + return PointerSize; + } + case DW_TAG_const_type: + case DW_TAG_volatile_type: + case DW_TAG_restrict_type: + case DW_TAG_typedef: { + if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type)) + return getTypeSize(BaseType, PointerSize); + break; + } + case DW_TAG_array_type: { + DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type); + if (!BaseType) + return Optional<uint64_t>(); + Optional<uint64_t> BaseSize = getTypeSize(BaseType, PointerSize); + if (!BaseSize) + return Optional<uint64_t>(); + uint64_t Size = *BaseSize; + for (DWARFDie Child : Type) { + if (Child.getTag() != DW_TAG_subrange_type) + continue; + + if (auto ElemCountAttr = Child.find(DW_AT_count)) + if (Optional<uint64_t> ElemCount = + ElemCountAttr->getAsUnsignedConstant()) + Size *= *ElemCount; + if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound)) + if (Optional<int64_t> UpperBound = + UpperBoundAttr->getAsSignedConstant()) { + int64_t LowerBound = 0; + if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound)) + LowerBound = LowerBoundAttr->getAsSignedConstant().getValueOr(0); + Size *= *UpperBound - LowerBound + 1; + } + } + return Size; + } + default: + break; + } + return Optional<uint64_t>(); +} + +static Optional<int64_t> +getExpressionFrameOffset(ArrayRef<uint8_t> Expr, + Optional<unsigned> FrameBaseReg) { + if (!Expr.empty() && + (Expr[0] == DW_OP_fbreg || + (FrameBaseReg && Expr[0] == DW_OP_breg0 + *FrameBaseReg))) { + unsigned Count; + int64_t Offset = decodeSLEB128(Expr.data() + 1, &Count, Expr.end()); + // A single DW_OP_fbreg or DW_OP_breg. + if (Expr.size() == Count + 1) + return Offset; + // Same + DW_OP_deref (Fortran arrays look like this). + if (Expr.size() == Count + 2 && Expr[Count + 1] == DW_OP_deref) + return Offset; + // Fallthrough. Do not accept ex. (DW_OP_breg W29, DW_OP_stack_value) + } + return None; +} + +void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram, + DWARFDie Die, std::vector<DILocal> &Result) { + if (Die.getTag() == DW_TAG_variable || + Die.getTag() == DW_TAG_formal_parameter) { + DILocal Local; + if (const char *Name = Subprogram.getSubroutineName(DINameKind::ShortName)) + Local.FunctionName = Name; + + Optional<unsigned> FrameBaseReg; + if (auto FrameBase = Subprogram.find(DW_AT_frame_base)) + if (Optional<ArrayRef<uint8_t>> Expr = FrameBase->getAsBlock()) + if (!Expr->empty() && (*Expr)[0] >= DW_OP_reg0 && + (*Expr)[0] <= DW_OP_reg31) { + FrameBaseReg = (*Expr)[0] - DW_OP_reg0; + } + + if (Expected<std::vector<DWARFLocationExpression>> Loc = + Die.getLocations(DW_AT_location)) { + for (const auto &Entry : *Loc) { + if (Optional<int64_t> FrameOffset = + getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) { + Local.FrameOffset = *FrameOffset; + break; + } + } + } else { + // FIXME: missing DW_AT_location is OK here, but other errors should be + // reported to the user. + consumeError(Loc.takeError()); + } + + if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset)) + Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant(); + + if (auto Origin = + Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) + Die = Origin; + if (auto NameAttr = Die.find(DW_AT_name)) + if (Optional<const char *> Name = NameAttr->getAsCString()) + Local.Name = *Name; + if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type)) + Local.Size = getTypeSize(Type, getCUAddrSize()); + if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) { + if (const auto *LT = CU->getContext().getLineTableForUnit(CU)) + LT->getFileNameByIndex( + DeclFileAttr->getAsUnsignedConstant().getValue(), + CU->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, + Local.DeclFile); + } + if (auto DeclLineAttr = Die.find(DW_AT_decl_line)) + Local.DeclLine = DeclLineAttr->getAsUnsignedConstant().getValue(); + + Result.push_back(Local); + return; + } + + if (Die.getTag() == DW_TAG_inlined_subroutine) + if (auto Origin = + Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) + Subprogram = Origin; + + for (auto Child : Die) + addLocalsForDie(CU, Subprogram, Child, Result); +} + +std::vector<DILocal> +DWARFContext::getLocalsForAddress(object::SectionedAddress Address) { + std::vector<DILocal> Result; + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + + DWARFDie Subprogram = CU->getSubroutineForAddress(Address.Address); + if (Subprogram.isValid()) + addLocalsForDie(CU, Subprogram, Subprogram, Result); + return Result; +} + +DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DILineInfo Result; + + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Result; + getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName, Result.StartFileName, Result.StartLine); - if (Spec.FLIKind != FileLineInfoKind::None) { - if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) { - LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), - Spec.FLIKind, Result); - } - } - return Result; -} - -DILineInfoTable DWARFContext::getLineInfoForAddressRange( - object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) { - DILineInfoTable Lines; - DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); - if (!CU) - return Lines; - - uint32_t StartLine = 0; + if (Spec.FLIKind != FileLineInfoKind::None) { + if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) { + LineTable->getFileLineInfoForAddress( + {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), + Spec.FLIKind, Result); + } + } + return Result; +} + +DILineInfoTable DWARFContext::getLineInfoForAddressRange( + object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) { + DILineInfoTable Lines; + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return Lines; + + uint32_t StartLine = 0; std::string StartFileName; - std::string FunctionName(DILineInfo::BadString); + std::string FunctionName(DILineInfo::BadString); getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind, Spec.FLIKind, FunctionName, StartFileName, StartLine); - - // If the Specifier says we don't need FileLineInfo, just - // return the top-most function at the starting address. - if (Spec.FLIKind == FileLineInfoKind::None) { - DILineInfo Result; - Result.FunctionName = FunctionName; + + // If the Specifier says we don't need FileLineInfo, just + // return the top-most function at the starting address. + if (Spec.FLIKind == FileLineInfoKind::None) { + DILineInfo Result; + Result.FunctionName = FunctionName; Result.StartFileName = StartFileName; - Result.StartLine = StartLine; - Lines.push_back(std::make_pair(Address.Address, Result)); - return Lines; - } - - const DWARFLineTable *LineTable = getLineTableForUnit(CU); - - // Get the index of row we're looking for in the line table. - std::vector<uint32_t> RowVector; - if (!LineTable->lookupAddressRange({Address.Address, Address.SectionIndex}, - Size, RowVector)) { - return Lines; - } - - for (uint32_t RowIndex : RowVector) { - // Take file number and line/column from the row. - const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; - DILineInfo Result; - LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(), - Spec.FLIKind, Result.FileName); - Result.FunctionName = FunctionName; - Result.Line = Row.Line; - Result.Column = Row.Column; + Result.StartLine = StartLine; + Lines.push_back(std::make_pair(Address.Address, Result)); + return Lines; + } + + const DWARFLineTable *LineTable = getLineTableForUnit(CU); + + // Get the index of row we're looking for in the line table. + std::vector<uint32_t> RowVector; + if (!LineTable->lookupAddressRange({Address.Address, Address.SectionIndex}, + Size, RowVector)) { + return Lines; + } + + for (uint32_t RowIndex : RowVector) { + // Take file number and line/column from the row. + const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; + DILineInfo Result; + LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(), + Spec.FLIKind, Result.FileName); + Result.FunctionName = FunctionName; + Result.Line = Row.Line; + Result.Column = Row.Column; Result.StartFileName = StartFileName; - Result.StartLine = StartLine; - Lines.push_back(std::make_pair(Row.Address.Address, Result)); - } - - return Lines; -} - -DIInliningInfo -DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, - DILineInfoSpecifier Spec) { - DIInliningInfo InliningInfo; - - DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); - if (!CU) - return InliningInfo; - - const DWARFLineTable *LineTable = nullptr; - SmallVector<DWARFDie, 4> InlinedChain; - CU->getInlinedChainForAddress(Address.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) { - DILineInfo Frame; - LineTable = getLineTableForUnit(CU); - if (LineTable && LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, - CU->getCompilationDir(), Spec.FLIKind, Frame)) - InliningInfo.addFrame(Frame); - } - return InliningInfo; - } - - uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0; - 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(Spec.FNKind)) - Frame.FunctionName = Name; - if (auto DeclLineResult = FunctionDIE.getDeclLine()) - Frame.StartLine = DeclLineResult; + Result.StartLine = StartLine; + Lines.push_back(std::make_pair(Row.Address.Address, Result)); + } + + return Lines; +} + +DIInliningInfo +DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Spec) { + DIInliningInfo InliningInfo; + + DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address); + if (!CU) + return InliningInfo; + + const DWARFLineTable *LineTable = nullptr; + SmallVector<DWARFDie, 4> InlinedChain; + CU->getInlinedChainForAddress(Address.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) { + DILineInfo Frame; + LineTable = getLineTableForUnit(CU); + if (LineTable && LineTable->getFileLineInfoForAddress( + {Address.Address, Address.SectionIndex}, + CU->getCompilationDir(), Spec.FLIKind, Frame)) + InliningInfo.addFrame(Frame); + } + return InliningInfo; + } + + uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0; + 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(Spec.FNKind)) + Frame.FunctionName = Name; + if (auto DeclLineResult = FunctionDIE.getDeclLine()) + Frame.StartLine = DeclLineResult; Frame.StartFileName = FunctionDIE.getDeclFile(Spec.FLIKind); - if (Spec.FLIKind != FileLineInfoKind::None) { - if (i == 0) { - // For the topmost frame, initialize the line table of this - // compile unit and fetch file/line info from it. - LineTable = getLineTableForUnit(CU); - // For the topmost routine, get file/line info from line table. - if (LineTable) - LineTable->getFileLineInfoForAddress( - {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), - Spec.FLIKind, Frame); - } else { - // Otherwise, use call file, call line and call column from - // previous DIE in inlined chain. - if (LineTable) - LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(), - Spec.FLIKind, Frame.FileName); - Frame.Line = CallLine; - Frame.Column = CallColumn; - Frame.Discriminator = CallDiscriminator; - } - // Get call file/line/column of a current DIE. - if (i + 1 < n) { - FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn, - CallDiscriminator); - } - } - InliningInfo.addFrame(Frame); - } - return InliningInfo; -} - -std::shared_ptr<DWARFContext> -DWARFContext::getDWOContext(StringRef AbsolutePath) { - if (auto S = DWP.lock()) { - DWARFContext *Ctxt = S->Context.get(); - return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); - } - - std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath]; - - if (auto S = Entry->lock()) { - DWARFContext *Ctxt = S->Context.get(); - return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); - } - - Expected<OwningBinary<ObjectFile>> Obj = [&] { - if (!CheckedForDWP) { - SmallString<128> DWPName; - auto Obj = object::ObjectFile::createObjectFile( - this->DWPName.empty() - ? (DObj->getFileName() + ".dwp").toStringRef(DWPName) - : StringRef(this->DWPName)); - if (Obj) { - Entry = &DWP; - return Obj; - } else { - CheckedForDWP = true; - // TODO: Should this error be handled (maybe in a high verbosity mode) - // before falling back to .dwo files? - consumeError(Obj.takeError()); - } - } - - return object::ObjectFile::createObjectFile(AbsolutePath); - }(); - - if (!Obj) { - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return nullptr; - } - - auto S = std::make_shared<DWOFile>(); - S->File = std::move(Obj.get()); - S->Context = DWARFContext::create(*S->File.getBinary()); - *Entry = S; - auto *Ctxt = S->Context.get(); - return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); -} - -static Error createError(const Twine &Reason, llvm::Error E) { - return make_error<StringError>(Reason + toString(std::move(E)), - inconvertibleErrorCode()); -} - -/// SymInfo contains information about symbol: it's address -/// and section index which is -1LL for absolute symbols. -struct SymInfo { - uint64_t Address; - uint64_t SectionIndex; -}; - -/// Returns the address of symbol relocation used against and a section index. -/// Used for futher relocations computation. Symbol's section load address is -static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj, - const RelocationRef &Reloc, - const LoadedObjectInfo *L, - std::map<SymbolRef, SymInfo> &Cache) { - SymInfo Ret = {0, (uint64_t)-1LL}; - object::section_iterator RSec = Obj.section_end(); - object::symbol_iterator Sym = Reloc.getSymbol(); - - std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end(); - // First calculate the address of the symbol or section as it appears - // in the object file - if (Sym != Obj.symbol_end()) { - bool New; - std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}}); - if (!New) - return CacheIt->second; - - Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); - if (!SymAddrOrErr) - return createError("failed to compute symbol address: ", - SymAddrOrErr.takeError()); - - // Also remember what section this symbol is in for later - auto SectOrErr = Sym->getSection(); - if (!SectOrErr) - return createError("failed to get symbol section: ", - SectOrErr.takeError()); - - RSec = *SectOrErr; - Ret.Address = *SymAddrOrErr; - } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { - RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); - Ret.Address = RSec->getAddress(); - } - - if (RSec != Obj.section_end()) - Ret.SectionIndex = RSec->getIndex(); - - // If we are given load addresses for the sections, we need to adjust: - // SymAddr = (Address of Symbol Or Section in File) - - // (Address of Section in File) + - // (Load Address of Section) - // RSec is now either the section being targeted or the section - // containing the symbol being targeted. In either case, - // we need to perform the same computation. - if (L && RSec != Obj.section_end()) - if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec)) - Ret.Address += SectionLoadAddress - RSec->getAddress(); - - if (CacheIt != Cache.end()) - CacheIt->second = Ret; - - return Ret; -} - -static bool isRelocScattered(const object::ObjectFile &Obj, - const RelocationRef &Reloc) { - const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj); - if (!MachObj) - return false; - // MachO also has relocations that point to sections and - // scattered relocations. - auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl()); - return MachObj->isRelocationScattered(RelocInfo); -} - -namespace { -struct DWARFSectionMap final : public DWARFSection { - RelocAddrMap Relocs; -}; - -class DWARFObjInMemory final : public DWARFObject { - bool IsLittleEndian; - uint8_t AddressSize; - StringRef FileName; - const object::ObjectFile *Obj = nullptr; - std::vector<SectionName> SectionNames; - - using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap, - std::map<object::SectionRef, unsigned>>; - - InfoSectionMap InfoSections; - InfoSectionMap TypesSections; - InfoSectionMap InfoDWOSections; - InfoSectionMap TypesDWOSections; - - DWARFSectionMap LocSection; - DWARFSectionMap LoclistsSection; - DWARFSectionMap LoclistsDWOSection; - DWARFSectionMap LineSection; - DWARFSectionMap RangesSection; - DWARFSectionMap RnglistsSection; - DWARFSectionMap StrOffsetsSection; - DWARFSectionMap LineDWOSection; - DWARFSectionMap FrameSection; - DWARFSectionMap EHFrameSection; - DWARFSectionMap LocDWOSection; - DWARFSectionMap StrOffsetsDWOSection; - DWARFSectionMap RangesDWOSection; - DWARFSectionMap RnglistsDWOSection; - DWARFSectionMap AddrSection; - DWARFSectionMap AppleNamesSection; - DWARFSectionMap AppleTypesSection; - DWARFSectionMap AppleNamespacesSection; - DWARFSectionMap AppleObjCSection; - DWARFSectionMap NamesSection; - DWARFSectionMap PubnamesSection; - DWARFSectionMap PubtypesSection; - DWARFSectionMap GnuPubnamesSection; - DWARFSectionMap GnuPubtypesSection; - DWARFSectionMap MacroSection; - - DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { - return StringSwitch<DWARFSectionMap *>(Name) - .Case("debug_loc", &LocSection) - .Case("debug_loclists", &LoclistsSection) - .Case("debug_loclists.dwo", &LoclistsDWOSection) - .Case("debug_line", &LineSection) - .Case("debug_frame", &FrameSection) - .Case("eh_frame", &EHFrameSection) - .Case("debug_str_offsets", &StrOffsetsSection) - .Case("debug_ranges", &RangesSection) - .Case("debug_rnglists", &RnglistsSection) - .Case("debug_loc.dwo", &LocDWOSection) - .Case("debug_line.dwo", &LineDWOSection) - .Case("debug_names", &NamesSection) - .Case("debug_rnglists.dwo", &RnglistsDWOSection) - .Case("debug_str_offsets.dwo", &StrOffsetsDWOSection) - .Case("debug_addr", &AddrSection) - .Case("apple_names", &AppleNamesSection) - .Case("debug_pubnames", &PubnamesSection) - .Case("debug_pubtypes", &PubtypesSection) - .Case("debug_gnu_pubnames", &GnuPubnamesSection) - .Case("debug_gnu_pubtypes", &GnuPubtypesSection) - .Case("apple_types", &AppleTypesSection) - .Case("apple_namespaces", &AppleNamespacesSection) - .Case("apple_namespac", &AppleNamespacesSection) - .Case("apple_objc", &AppleObjCSection) - .Case("debug_macro", &MacroSection) - .Default(nullptr); - } - - StringRef AbbrevSection; - StringRef ArangesSection; - StringRef StrSection; - StringRef MacinfoSection; - StringRef MacinfoDWOSection; - StringRef MacroDWOSection; - StringRef AbbrevDWOSection; - StringRef StrDWOSection; - StringRef CUIndexSection; - StringRef GdbIndexSection; - StringRef TUIndexSection; - StringRef LineStrSection; - - // A deque holding section data whose iterators are not invalidated when - // new decompressed sections are inserted at the end. - std::deque<SmallString<0>> UncompressedSections; - - StringRef *mapSectionToMember(StringRef Name) { - if (DWARFSection *Sec = mapNameToDWARFSection(Name)) - return &Sec->Data; - return StringSwitch<StringRef *>(Name) - .Case("debug_abbrev", &AbbrevSection) - .Case("debug_aranges", &ArangesSection) - .Case("debug_str", &StrSection) - .Case("debug_macinfo", &MacinfoSection) - .Case("debug_macinfo.dwo", &MacinfoDWOSection) - .Case("debug_macro.dwo", &MacroDWOSection) - .Case("debug_abbrev.dwo", &AbbrevDWOSection) - .Case("debug_str.dwo", &StrDWOSection) - .Case("debug_cu_index", &CUIndexSection) - .Case("debug_tu_index", &TUIndexSection) - .Case("gdb_index", &GdbIndexSection) - .Case("debug_line_str", &LineStrSection) - // Any more debug info sections go here. - .Default(nullptr); - } - - /// If Sec is compressed section, decompresses and updates its contents - /// provided by Data. Otherwise leaves it unchanged. - Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, - StringRef &Data) { - if (!Decompressor::isCompressed(Sec)) - return Error::success(); - - Expected<Decompressor> Decompressor = - Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8); - if (!Decompressor) - return Decompressor.takeError(); - - SmallString<0> Out; - if (auto Err = Decompressor->resizeAndDecompress(Out)) - return Err; - - UncompressedSections.push_back(std::move(Out)); - Data = UncompressedSections.back(); - - return Error::success(); - } - -public: - DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, - uint8_t AddrSize, bool IsLittleEndian) - : IsLittleEndian(IsLittleEndian) { - for (const auto &SecIt : Sections) { - if (StringRef *SectionData = mapSectionToMember(SecIt.first())) - *SectionData = SecIt.second->getBuffer(); - else if (SecIt.first() == "debug_info") - // Find debug_info and debug_types data by section rather than name as - // there are multiple, comdat grouped, of these sections. - InfoSections[SectionRef()].Data = SecIt.second->getBuffer(); - else if (SecIt.first() == "debug_info.dwo") - InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); - else if (SecIt.first() == "debug_types") - TypesSections[SectionRef()].Data = SecIt.second->getBuffer(); - else if (SecIt.first() == "debug_types.dwo") - TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); - } - } - DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L, - function_ref<void(Error)> HandleError, function_ref<void(Error)> HandleWarning ) - : IsLittleEndian(Obj.isLittleEndian()), - AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()), - Obj(&Obj) { - - StringMap<unsigned> SectionAmountMap; - for (const SectionRef &Section : Obj.sections()) { - StringRef Name; - if (auto NameOrErr = Section.getName()) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - ++SectionAmountMap[Name]; - SectionNames.push_back({ Name, true }); - - // Skip BSS and Virtual sections, they aren't interesting. - if (Section.isBSS() || Section.isVirtual()) - continue; - - // Skip sections stripped by dsymutil. - if (Section.isStripped()) - continue; - - StringRef Data; - Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); - if (!SecOrErr) { - HandleError(createError("failed to get relocated section: ", - SecOrErr.takeError())); - continue; - } - - // Try to obtain an already relocated version of this section. - // Else use the unrelocated section from the object file. We'll have to - // apply relocations ourselves later. - section_iterator RelocatedSection = *SecOrErr; - if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) { - Expected<StringRef> E = Section.getContents(); - if (E) - Data = *E; - else - // maybeDecompress below will error. - consumeError(E.takeError()); - } - - if (auto Err = maybeDecompress(Section, Name, Data)) { - HandleError(createError("failed to decompress '" + Name + "', ", - std::move(Err))); - continue; - } - - // 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. - - // Map platform specific debug section names to DWARF standard section - // names. - Name = Obj.mapDebugSectionName(Name); - - if (StringRef *SectionData = mapSectionToMember(Name)) { - *SectionData = Data; - if (Name == "debug_ranges") { - // FIXME: Use the other dwo range section when we emit it. - RangesDWOSection.Data = Data; - } + if (Spec.FLIKind != FileLineInfoKind::None) { + if (i == 0) { + // For the topmost frame, initialize the line table of this + // compile unit and fetch file/line info from it. + LineTable = getLineTableForUnit(CU); + // For the topmost routine, get file/line info from line table. + if (LineTable) + LineTable->getFileLineInfoForAddress( + {Address.Address, Address.SectionIndex}, CU->getCompilationDir(), + Spec.FLIKind, Frame); + } else { + // Otherwise, use call file, call line and call column from + // previous DIE in inlined chain. + if (LineTable) + LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(), + Spec.FLIKind, Frame.FileName); + Frame.Line = CallLine; + Frame.Column = CallColumn; + Frame.Discriminator = CallDiscriminator; + } + // Get call file/line/column of a current DIE. + if (i + 1 < n) { + FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn, + CallDiscriminator); + } + } + InliningInfo.addFrame(Frame); + } + return InliningInfo; +} + +std::shared_ptr<DWARFContext> +DWARFContext::getDWOContext(StringRef AbsolutePath) { + if (auto S = DWP.lock()) { + DWARFContext *Ctxt = S->Context.get(); + return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); + } + + std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath]; + + if (auto S = Entry->lock()) { + DWARFContext *Ctxt = S->Context.get(); + return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); + } + + Expected<OwningBinary<ObjectFile>> Obj = [&] { + if (!CheckedForDWP) { + SmallString<128> DWPName; + auto Obj = object::ObjectFile::createObjectFile( + this->DWPName.empty() + ? (DObj->getFileName() + ".dwp").toStringRef(DWPName) + : StringRef(this->DWPName)); + if (Obj) { + Entry = &DWP; + return Obj; + } else { + CheckedForDWP = true; + // TODO: Should this error be handled (maybe in a high verbosity mode) + // before falling back to .dwo files? + consumeError(Obj.takeError()); + } + } + + return object::ObjectFile::createObjectFile(AbsolutePath); + }(); + + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); + return nullptr; + } + + auto S = std::make_shared<DWOFile>(); + S->File = std::move(Obj.get()); + S->Context = DWARFContext::create(*S->File.getBinary()); + *Entry = S; + auto *Ctxt = S->Context.get(); + return std::shared_ptr<DWARFContext>(std::move(S), Ctxt); +} + +static Error createError(const Twine &Reason, llvm::Error E) { + return make_error<StringError>(Reason + toString(std::move(E)), + inconvertibleErrorCode()); +} + +/// SymInfo contains information about symbol: it's address +/// and section index which is -1LL for absolute symbols. +struct SymInfo { + uint64_t Address; + uint64_t SectionIndex; +}; + +/// Returns the address of symbol relocation used against and a section index. +/// Used for futher relocations computation. Symbol's section load address is +static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj, + const RelocationRef &Reloc, + const LoadedObjectInfo *L, + std::map<SymbolRef, SymInfo> &Cache) { + SymInfo Ret = {0, (uint64_t)-1LL}; + object::section_iterator RSec = Obj.section_end(); + object::symbol_iterator Sym = Reloc.getSymbol(); + + std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end(); + // First calculate the address of the symbol or section as it appears + // in the object file + if (Sym != Obj.symbol_end()) { + bool New; + std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}}); + if (!New) + return CacheIt->second; + + Expected<uint64_t> SymAddrOrErr = Sym->getAddress(); + if (!SymAddrOrErr) + return createError("failed to compute symbol address: ", + SymAddrOrErr.takeError()); + + // Also remember what section this symbol is in for later + auto SectOrErr = Sym->getSection(); + if (!SectOrErr) + return createError("failed to get symbol section: ", + SectOrErr.takeError()); + + RSec = *SectOrErr; + Ret.Address = *SymAddrOrErr; + } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { + RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); + Ret.Address = RSec->getAddress(); + } + + if (RSec != Obj.section_end()) + Ret.SectionIndex = RSec->getIndex(); + + // If we are given load addresses for the sections, we need to adjust: + // SymAddr = (Address of Symbol Or Section in File) - + // (Address of Section in File) + + // (Load Address of Section) + // RSec is now either the section being targeted or the section + // containing the symbol being targeted. In either case, + // we need to perform the same computation. + if (L && RSec != Obj.section_end()) + if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec)) + Ret.Address += SectionLoadAddress - RSec->getAddress(); + + if (CacheIt != Cache.end()) + CacheIt->second = Ret; + + return Ret; +} + +static bool isRelocScattered(const object::ObjectFile &Obj, + const RelocationRef &Reloc) { + const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj); + if (!MachObj) + return false; + // MachO also has relocations that point to sections and + // scattered relocations. + auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl()); + return MachObj->isRelocationScattered(RelocInfo); +} + +namespace { +struct DWARFSectionMap final : public DWARFSection { + RelocAddrMap Relocs; +}; + +class DWARFObjInMemory final : public DWARFObject { + bool IsLittleEndian; + uint8_t AddressSize; + StringRef FileName; + const object::ObjectFile *Obj = nullptr; + std::vector<SectionName> SectionNames; + + using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap, + std::map<object::SectionRef, unsigned>>; + + InfoSectionMap InfoSections; + InfoSectionMap TypesSections; + InfoSectionMap InfoDWOSections; + InfoSectionMap TypesDWOSections; + + DWARFSectionMap LocSection; + DWARFSectionMap LoclistsSection; + DWARFSectionMap LoclistsDWOSection; + DWARFSectionMap LineSection; + DWARFSectionMap RangesSection; + DWARFSectionMap RnglistsSection; + DWARFSectionMap StrOffsetsSection; + DWARFSectionMap LineDWOSection; + DWARFSectionMap FrameSection; + DWARFSectionMap EHFrameSection; + DWARFSectionMap LocDWOSection; + DWARFSectionMap StrOffsetsDWOSection; + DWARFSectionMap RangesDWOSection; + DWARFSectionMap RnglistsDWOSection; + DWARFSectionMap AddrSection; + DWARFSectionMap AppleNamesSection; + DWARFSectionMap AppleTypesSection; + DWARFSectionMap AppleNamespacesSection; + DWARFSectionMap AppleObjCSection; + DWARFSectionMap NamesSection; + DWARFSectionMap PubnamesSection; + DWARFSectionMap PubtypesSection; + DWARFSectionMap GnuPubnamesSection; + DWARFSectionMap GnuPubtypesSection; + DWARFSectionMap MacroSection; + + DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { + return StringSwitch<DWARFSectionMap *>(Name) + .Case("debug_loc", &LocSection) + .Case("debug_loclists", &LoclistsSection) + .Case("debug_loclists.dwo", &LoclistsDWOSection) + .Case("debug_line", &LineSection) + .Case("debug_frame", &FrameSection) + .Case("eh_frame", &EHFrameSection) + .Case("debug_str_offsets", &StrOffsetsSection) + .Case("debug_ranges", &RangesSection) + .Case("debug_rnglists", &RnglistsSection) + .Case("debug_loc.dwo", &LocDWOSection) + .Case("debug_line.dwo", &LineDWOSection) + .Case("debug_names", &NamesSection) + .Case("debug_rnglists.dwo", &RnglistsDWOSection) + .Case("debug_str_offsets.dwo", &StrOffsetsDWOSection) + .Case("debug_addr", &AddrSection) + .Case("apple_names", &AppleNamesSection) + .Case("debug_pubnames", &PubnamesSection) + .Case("debug_pubtypes", &PubtypesSection) + .Case("debug_gnu_pubnames", &GnuPubnamesSection) + .Case("debug_gnu_pubtypes", &GnuPubtypesSection) + .Case("apple_types", &AppleTypesSection) + .Case("apple_namespaces", &AppleNamespacesSection) + .Case("apple_namespac", &AppleNamespacesSection) + .Case("apple_objc", &AppleObjCSection) + .Case("debug_macro", &MacroSection) + .Default(nullptr); + } + + StringRef AbbrevSection; + StringRef ArangesSection; + StringRef StrSection; + StringRef MacinfoSection; + StringRef MacinfoDWOSection; + StringRef MacroDWOSection; + StringRef AbbrevDWOSection; + StringRef StrDWOSection; + StringRef CUIndexSection; + StringRef GdbIndexSection; + StringRef TUIndexSection; + StringRef LineStrSection; + + // A deque holding section data whose iterators are not invalidated when + // new decompressed sections are inserted at the end. + std::deque<SmallString<0>> UncompressedSections; + + StringRef *mapSectionToMember(StringRef Name) { + if (DWARFSection *Sec = mapNameToDWARFSection(Name)) + return &Sec->Data; + return StringSwitch<StringRef *>(Name) + .Case("debug_abbrev", &AbbrevSection) + .Case("debug_aranges", &ArangesSection) + .Case("debug_str", &StrSection) + .Case("debug_macinfo", &MacinfoSection) + .Case("debug_macinfo.dwo", &MacinfoDWOSection) + .Case("debug_macro.dwo", &MacroDWOSection) + .Case("debug_abbrev.dwo", &AbbrevDWOSection) + .Case("debug_str.dwo", &StrDWOSection) + .Case("debug_cu_index", &CUIndexSection) + .Case("debug_tu_index", &TUIndexSection) + .Case("gdb_index", &GdbIndexSection) + .Case("debug_line_str", &LineStrSection) + // Any more debug info sections go here. + .Default(nullptr); + } + + /// If Sec is compressed section, decompresses and updates its contents + /// provided by Data. Otherwise leaves it unchanged. + Error maybeDecompress(const object::SectionRef &Sec, StringRef Name, + StringRef &Data) { + if (!Decompressor::isCompressed(Sec)) + return Error::success(); + + Expected<Decompressor> Decompressor = + Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8); + if (!Decompressor) + return Decompressor.takeError(); + + SmallString<0> Out; + if (auto Err = Decompressor->resizeAndDecompress(Out)) + return Err; + + UncompressedSections.push_back(std::move(Out)); + Data = UncompressedSections.back(); + + return Error::success(); + } + +public: + DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool IsLittleEndian) + : IsLittleEndian(IsLittleEndian) { + for (const auto &SecIt : Sections) { + if (StringRef *SectionData = mapSectionToMember(SecIt.first())) + *SectionData = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_info") + // Find debug_info and debug_types data by section rather than name as + // there are multiple, comdat grouped, of these sections. + InfoSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_info.dwo") + InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_types") + TypesSections[SectionRef()].Data = SecIt.second->getBuffer(); + else if (SecIt.first() == "debug_types.dwo") + TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer(); + } + } + DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L, + function_ref<void(Error)> HandleError, function_ref<void(Error)> HandleWarning ) + : IsLittleEndian(Obj.isLittleEndian()), + AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()), + Obj(&Obj) { + + StringMap<unsigned> SectionAmountMap; + for (const SectionRef &Section : Obj.sections()) { + StringRef Name; + if (auto NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + ++SectionAmountMap[Name]; + SectionNames.push_back({ Name, true }); + + // Skip BSS and Virtual sections, they aren't interesting. + if (Section.isBSS() || Section.isVirtual()) + continue; + + // Skip sections stripped by dsymutil. + if (Section.isStripped()) + continue; + + StringRef Data; + Expected<section_iterator> SecOrErr = Section.getRelocatedSection(); + if (!SecOrErr) { + HandleError(createError("failed to get relocated section: ", + SecOrErr.takeError())); + continue; + } + + // Try to obtain an already relocated version of this section. + // Else use the unrelocated section from the object file. We'll have to + // apply relocations ourselves later. + section_iterator RelocatedSection = *SecOrErr; + if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) { + Expected<StringRef> E = Section.getContents(); + if (E) + Data = *E; + else + // maybeDecompress below will error. + consumeError(E.takeError()); + } + + if (auto Err = maybeDecompress(Section, Name, Data)) { + HandleError(createError("failed to decompress '" + Name + "', ", + std::move(Err))); + continue; + } + + // 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. + + // Map platform specific debug section names to DWARF standard section + // names. + Name = Obj.mapDebugSectionName(Name); + + if (StringRef *SectionData = mapSectionToMember(Name)) { + *SectionData = Data; + if (Name == "debug_ranges") { + // FIXME: Use the other dwo range section when we emit it. + RangesDWOSection.Data = Data; + } } else if (InfoSectionMap *Sections = StringSwitch<InfoSectionMap *>(Name) .Case("debug_info", &InfoSections) @@ -1716,288 +1716,288 @@ public: .Case("debug_types", &TypesSections) .Case("debug_types.dwo", &TypesDWOSections) .Default(nullptr)) { - // Find debug_info and debug_types data by section rather than name as - // there are multiple, comdat grouped, of these sections. + // Find debug_info and debug_types data by section rather than name as + // there are multiple, comdat grouped, of these sections. DWARFSectionMap &S = (*Sections)[Section]; S.Data = Data; - } - - if (RelocatedSection == Obj.section_end()) - continue; - - StringRef RelSecName; - if (auto NameOrErr = RelocatedSection->getName()) - RelSecName = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - // If the section we're relocating was relocated already by the JIT, - // then we used the relocated version above, so we do not need to process - // relocations for it now. - StringRef RelSecData; - if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData)) - continue; - - // In Mach-o files, the relocations do not need to be applied if - // there is no load offset to apply. The value read at the - // relocation point already factors in the section address - // (actually applying the relocations will produce wrong results - // as the section address will be added twice). - if (!L && isa<MachOObjectFile>(&Obj)) - continue; - - RelSecName = RelSecName.substr( - RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes. - - // TODO: Add support for relocations in other sections as needed. - // Record relocations for the debug_info and debug_line sections. - DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName); - RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr; - if (!Map) { - // Find debug_info and debug_types relocs by section rather than name - // as there are multiple, comdat grouped, of these sections. - if (RelSecName == "debug_info") - Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection]) - .Relocs; - else if (RelSecName == "debug_info.dwo") - Map = &static_cast<DWARFSectionMap &>( - InfoDWOSections[*RelocatedSection]) - .Relocs; - else if (RelSecName == "debug_types") - Map = - &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection]) - .Relocs; - else if (RelSecName == "debug_types.dwo") - Map = &static_cast<DWARFSectionMap &>( - TypesDWOSections[*RelocatedSection]) - .Relocs; - else - continue; - } - - if (Section.relocation_begin() == Section.relocation_end()) - continue; - - // Symbol to [address, section index] cache mapping. - std::map<SymbolRef, SymInfo> AddrCache; + } + + if (RelocatedSection == Obj.section_end()) + continue; + + StringRef RelSecName; + if (auto NameOrErr = RelocatedSection->getName()) + RelSecName = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + // If the section we're relocating was relocated already by the JIT, + // then we used the relocated version above, so we do not need to process + // relocations for it now. + StringRef RelSecData; + if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData)) + continue; + + // In Mach-o files, the relocations do not need to be applied if + // there is no load offset to apply. The value read at the + // relocation point already factors in the section address + // (actually applying the relocations will produce wrong results + // as the section address will be added twice). + if (!L && isa<MachOObjectFile>(&Obj)) + continue; + + RelSecName = RelSecName.substr( + RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes. + + // TODO: Add support for relocations in other sections as needed. + // Record relocations for the debug_info and debug_line sections. + DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName); + RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr; + if (!Map) { + // Find debug_info and debug_types relocs by section rather than name + // as there are multiple, comdat grouped, of these sections. + if (RelSecName == "debug_info") + Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_info.dwo") + Map = &static_cast<DWARFSectionMap &>( + InfoDWOSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_types") + Map = + &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection]) + .Relocs; + else if (RelSecName == "debug_types.dwo") + Map = &static_cast<DWARFSectionMap &>( + TypesDWOSections[*RelocatedSection]) + .Relocs; + else + continue; + } + + if (Section.relocation_begin() == Section.relocation_end()) + continue; + + // Symbol to [address, section index] cache mapping. + std::map<SymbolRef, SymInfo> AddrCache; SupportsRelocation Supports; - RelocationResolver Resolver; - std::tie(Supports, Resolver) = getRelocationResolver(Obj); - for (const RelocationRef &Reloc : Section.relocations()) { - // FIXME: it's not clear how to correctly handle scattered - // relocations. - if (isRelocScattered(Obj, Reloc)) - continue; - - Expected<SymInfo> SymInfoOrErr = - getSymbolInfo(Obj, Reloc, L, AddrCache); - if (!SymInfoOrErr) { - HandleError(SymInfoOrErr.takeError()); - continue; - } - - // Check if Resolver can handle this relocation type early so as not to - // handle invalid cases in DWARFDataExtractor. - // - // TODO Don't store Resolver in every RelocAddrEntry. - if (Supports && Supports(Reloc.getType())) { - auto I = Map->try_emplace( - Reloc.getOffset(), - RelocAddrEntry{SymInfoOrErr->SectionIndex, Reloc, - SymInfoOrErr->Address, - Optional<object::RelocationRef>(), 0, Resolver}); - // If we didn't successfully insert that's because we already had a - // relocation for that offset. Store it as a second relocation in the - // same RelocAddrEntry instead. - if (!I.second) { - RelocAddrEntry &entry = I.first->getSecond(); - if (entry.Reloc2) { - HandleError(createError( - "At most two relocations per offset are supported")); - } - entry.Reloc2 = Reloc; - entry.SymbolValue2 = SymInfoOrErr->Address; - } - } else { - SmallString<32> Type; - Reloc.getTypeName(Type); - // FIXME: Support more relocations & change this to an error - HandleWarning( - createError("failed to compute relocation: " + Type + ", ", - errorCodeToError(object_error::parse_failed))); - } - } - } - - for (SectionName &S : SectionNames) - if (SectionAmountMap[S.Name] > 1) - S.IsNameUnique = false; - } - - Optional<RelocAddrEntry> find(const DWARFSection &S, - uint64_t Pos) const override { - auto &Sec = static_cast<const DWARFSectionMap &>(S); - RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos); - if (AI == Sec.Relocs.end()) - return None; - return AI->second; - } - - const object::ObjectFile *getFile() const override { return Obj; } - - ArrayRef<SectionName> getSectionNames() const override { - return SectionNames; - } - - bool isLittleEndian() const override { return IsLittleEndian; } - StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; } - const DWARFSection &getLineDWOSection() const override { - return LineDWOSection; - } - const DWARFSection &getLocDWOSection() const override { - return LocDWOSection; - } - StringRef getStrDWOSection() const override { return StrDWOSection; } - const DWARFSection &getStrOffsetsDWOSection() const override { - return StrOffsetsDWOSection; - } - const DWARFSection &getRangesDWOSection() const override { - return RangesDWOSection; - } - const DWARFSection &getRnglistsDWOSection() const override { - return RnglistsDWOSection; - } - const DWARFSection &getLoclistsDWOSection() const override { - return LoclistsDWOSection; - } - const DWARFSection &getAddrSection() const override { return AddrSection; } - StringRef getCUIndexSection() const override { return CUIndexSection; } - StringRef getGdbIndexSection() const override { return GdbIndexSection; } - StringRef getTUIndexSection() const override { return TUIndexSection; } - - // DWARF v5 - const DWARFSection &getStrOffsetsSection() const override { - return StrOffsetsSection; - } - StringRef getLineStrSection() const override { return LineStrSection; } - - // Sections for DWARF5 split dwarf proposal. - void forEachInfoDWOSections( - function_ref<void(const DWARFSection &)> F) const override { - for (auto &P : InfoDWOSections) - F(P.second); - } - void forEachTypesDWOSections( - function_ref<void(const DWARFSection &)> F) const override { - for (auto &P : TypesDWOSections) - F(P.second); - } - - StringRef getAbbrevSection() const override { return AbbrevSection; } - const DWARFSection &getLocSection() const override { return LocSection; } - const DWARFSection &getLoclistsSection() const override { return LoclistsSection; } - StringRef getArangesSection() const override { return ArangesSection; } - const DWARFSection &getFrameSection() const override { - return FrameSection; - } - const DWARFSection &getEHFrameSection() const override { - return EHFrameSection; - } - const DWARFSection &getLineSection() const override { return LineSection; } - StringRef getStrSection() const override { return StrSection; } - const DWARFSection &getRangesSection() const override { return RangesSection; } - const DWARFSection &getRnglistsSection() const override { - return RnglistsSection; - } - const DWARFSection &getMacroSection() const override { return MacroSection; } - StringRef getMacroDWOSection() const override { return MacroDWOSection; } - StringRef getMacinfoSection() const override { return MacinfoSection; } - StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; } - const DWARFSection &getPubnamesSection() const override { return PubnamesSection; } - const DWARFSection &getPubtypesSection() const override { return PubtypesSection; } - const DWARFSection &getGnuPubnamesSection() const override { - return GnuPubnamesSection; - } - const DWARFSection &getGnuPubtypesSection() const override { - return GnuPubtypesSection; - } - const DWARFSection &getAppleNamesSection() const override { - return AppleNamesSection; - } - const DWARFSection &getAppleTypesSection() const override { - return AppleTypesSection; - } - const DWARFSection &getAppleNamespacesSection() const override { - return AppleNamespacesSection; - } - const DWARFSection &getAppleObjCSection() const override { - return AppleObjCSection; - } - const DWARFSection &getNamesSection() const override { - return NamesSection; - } - - StringRef getFileName() const override { return FileName; } - uint8_t getAddressSize() const override { return AddressSize; } - void forEachInfoSections( - function_ref<void(const DWARFSection &)> F) const override { - for (auto &P : InfoSections) - F(P.second); - } - void forEachTypesSections( - function_ref<void(const DWARFSection &)> F) const override { - for (auto &P : TypesSections) - F(P.second); - } -}; -} // namespace - -std::unique_ptr<DWARFContext> -DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L, - std::string DWPName, - std::function<void(Error)> RecoverableErrorHandler, - std::function<void(Error)> WarningHandler) { - auto DObj = - std::make_unique<DWARFObjInMemory>(Obj, L, RecoverableErrorHandler, WarningHandler); - return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName), - RecoverableErrorHandler, - WarningHandler); -} - -std::unique_ptr<DWARFContext> -DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, - uint8_t AddrSize, bool isLittleEndian, - std::function<void(Error)> RecoverableErrorHandler, - std::function<void(Error)> WarningHandler) { - auto DObj = - std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian); - return std::make_unique<DWARFContext>( - std::move(DObj), "", RecoverableErrorHandler, WarningHandler); -} - -Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) { - // Detect the architecture from the object file. We usually don't need OS - // info to lookup a target and create register info. - Triple TT; - TT.setArch(Triple::ArchType(Obj.getArch())); - TT.setVendor(Triple::UnknownVendor); - TT.setOS(Triple::UnknownOS); - std::string TargetLookupError; - const Target *TheTarget = - TargetRegistry::lookupTarget(TT.str(), TargetLookupError); - if (!TargetLookupError.empty()) - return createStringError(errc::invalid_argument, - TargetLookupError.c_str()); - RegInfo.reset(TheTarget->createMCRegInfo(TT.str())); - return Error::success(); -} - -uint8_t DWARFContext::getCUAddrSize() { - // In theory, different compile units may have different address byte - // sizes, but for simplicity we just use the address byte size of the - // first compile unit. In practice the address size field is repeated across - // various DWARF headers (at least in version 5) to make it easier to dump - // them independently, not to enable varying the address size. + RelocationResolver Resolver; + std::tie(Supports, Resolver) = getRelocationResolver(Obj); + for (const RelocationRef &Reloc : Section.relocations()) { + // FIXME: it's not clear how to correctly handle scattered + // relocations. + if (isRelocScattered(Obj, Reloc)) + continue; + + Expected<SymInfo> SymInfoOrErr = + getSymbolInfo(Obj, Reloc, L, AddrCache); + if (!SymInfoOrErr) { + HandleError(SymInfoOrErr.takeError()); + continue; + } + + // Check if Resolver can handle this relocation type early so as not to + // handle invalid cases in DWARFDataExtractor. + // + // TODO Don't store Resolver in every RelocAddrEntry. + if (Supports && Supports(Reloc.getType())) { + auto I = Map->try_emplace( + Reloc.getOffset(), + RelocAddrEntry{SymInfoOrErr->SectionIndex, Reloc, + SymInfoOrErr->Address, + Optional<object::RelocationRef>(), 0, Resolver}); + // If we didn't successfully insert that's because we already had a + // relocation for that offset. Store it as a second relocation in the + // same RelocAddrEntry instead. + if (!I.second) { + RelocAddrEntry &entry = I.first->getSecond(); + if (entry.Reloc2) { + HandleError(createError( + "At most two relocations per offset are supported")); + } + entry.Reloc2 = Reloc; + entry.SymbolValue2 = SymInfoOrErr->Address; + } + } else { + SmallString<32> Type; + Reloc.getTypeName(Type); + // FIXME: Support more relocations & change this to an error + HandleWarning( + createError("failed to compute relocation: " + Type + ", ", + errorCodeToError(object_error::parse_failed))); + } + } + } + + for (SectionName &S : SectionNames) + if (SectionAmountMap[S.Name] > 1) + S.IsNameUnique = false; + } + + Optional<RelocAddrEntry> find(const DWARFSection &S, + uint64_t Pos) const override { + auto &Sec = static_cast<const DWARFSectionMap &>(S); + RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos); + if (AI == Sec.Relocs.end()) + return None; + return AI->second; + } + + const object::ObjectFile *getFile() const override { return Obj; } + + ArrayRef<SectionName> getSectionNames() const override { + return SectionNames; + } + + bool isLittleEndian() const override { return IsLittleEndian; } + StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; } + const DWARFSection &getLineDWOSection() const override { + return LineDWOSection; + } + const DWARFSection &getLocDWOSection() const override { + return LocDWOSection; + } + StringRef getStrDWOSection() const override { return StrDWOSection; } + const DWARFSection &getStrOffsetsDWOSection() const override { + return StrOffsetsDWOSection; + } + const DWARFSection &getRangesDWOSection() const override { + return RangesDWOSection; + } + const DWARFSection &getRnglistsDWOSection() const override { + return RnglistsDWOSection; + } + const DWARFSection &getLoclistsDWOSection() const override { + return LoclistsDWOSection; + } + const DWARFSection &getAddrSection() const override { return AddrSection; } + StringRef getCUIndexSection() const override { return CUIndexSection; } + StringRef getGdbIndexSection() const override { return GdbIndexSection; } + StringRef getTUIndexSection() const override { return TUIndexSection; } + + // DWARF v5 + const DWARFSection &getStrOffsetsSection() const override { + return StrOffsetsSection; + } + StringRef getLineStrSection() const override { return LineStrSection; } + + // Sections for DWARF5 split dwarf proposal. + void forEachInfoDWOSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : InfoDWOSections) + F(P.second); + } + void forEachTypesDWOSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : TypesDWOSections) + F(P.second); + } + + StringRef getAbbrevSection() const override { return AbbrevSection; } + const DWARFSection &getLocSection() const override { return LocSection; } + const DWARFSection &getLoclistsSection() const override { return LoclistsSection; } + StringRef getArangesSection() const override { return ArangesSection; } + const DWARFSection &getFrameSection() const override { + return FrameSection; + } + const DWARFSection &getEHFrameSection() const override { + return EHFrameSection; + } + const DWARFSection &getLineSection() const override { return LineSection; } + StringRef getStrSection() const override { return StrSection; } + const DWARFSection &getRangesSection() const override { return RangesSection; } + const DWARFSection &getRnglistsSection() const override { + return RnglistsSection; + } + const DWARFSection &getMacroSection() const override { return MacroSection; } + StringRef getMacroDWOSection() const override { return MacroDWOSection; } + StringRef getMacinfoSection() const override { return MacinfoSection; } + StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; } + const DWARFSection &getPubnamesSection() const override { return PubnamesSection; } + const DWARFSection &getPubtypesSection() const override { return PubtypesSection; } + const DWARFSection &getGnuPubnamesSection() const override { + return GnuPubnamesSection; + } + const DWARFSection &getGnuPubtypesSection() const override { + return GnuPubtypesSection; + } + const DWARFSection &getAppleNamesSection() const override { + return AppleNamesSection; + } + const DWARFSection &getAppleTypesSection() const override { + return AppleTypesSection; + } + const DWARFSection &getAppleNamespacesSection() const override { + return AppleNamespacesSection; + } + const DWARFSection &getAppleObjCSection() const override { + return AppleObjCSection; + } + const DWARFSection &getNamesSection() const override { + return NamesSection; + } + + StringRef getFileName() const override { return FileName; } + uint8_t getAddressSize() const override { return AddressSize; } + void forEachInfoSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : InfoSections) + F(P.second); + } + void forEachTypesSections( + function_ref<void(const DWARFSection &)> F) const override { + for (auto &P : TypesSections) + F(P.second); + } +}; +} // namespace + +std::unique_ptr<DWARFContext> +DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L, + std::string DWPName, + std::function<void(Error)> RecoverableErrorHandler, + std::function<void(Error)> WarningHandler) { + auto DObj = + std::make_unique<DWARFObjInMemory>(Obj, L, RecoverableErrorHandler, WarningHandler); + return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName), + RecoverableErrorHandler, + WarningHandler); +} + +std::unique_ptr<DWARFContext> +DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, + uint8_t AddrSize, bool isLittleEndian, + std::function<void(Error)> RecoverableErrorHandler, + std::function<void(Error)> WarningHandler) { + auto DObj = + std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian); + return std::make_unique<DWARFContext>( + std::move(DObj), "", RecoverableErrorHandler, WarningHandler); +} + +Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) { + // Detect the architecture from the object file. We usually don't need OS + // info to lookup a target and create register info. + Triple TT; + TT.setArch(Triple::ArchType(Obj.getArch())); + TT.setVendor(Triple::UnknownVendor); + TT.setOS(Triple::UnknownOS); + std::string TargetLookupError; + const Target *TheTarget = + TargetRegistry::lookupTarget(TT.str(), TargetLookupError); + if (!TargetLookupError.empty()) + return createStringError(errc::invalid_argument, + TargetLookupError.c_str()); + RegInfo.reset(TheTarget->createMCRegInfo(TT.str())); + return Error::success(); +} + +uint8_t DWARFContext::getCUAddrSize() { + // In theory, different compile units may have different address byte + // sizes, but for simplicity we just use the address byte size of the + // first compile unit. In practice the address size field is repeated across + // various DWARF headers (at least in version 5) to make it easier to dump + // them independently, not to enable varying the address size. auto CUs = compile_units(); - return CUs.empty() ? 0 : (*CUs.begin())->getAddressByteSize(); -} + return CUs.empty() ? 0 : (*CUs.begin())->getAddressByteSize(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp index da6f6ad903..e640b47d58 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -1,135 +1,135 @@ -//===- DWARFDataExtractor.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" - -using namespace llvm; - -std::pair<uint64_t, dwarf::DwarfFormat> -DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const { - ErrorAsOutParameter ErrAsOut(Err); - if (Err && *Err) - return {0, dwarf::DWARF32}; - - Cursor C(*Off); - uint64_t Length = getRelocatedValue(C, 4); - dwarf::DwarfFormat Format = dwarf::DWARF32; - if (Length == dwarf::DW_LENGTH_DWARF64) { - Length = getRelocatedValue(C, 8); - Format = dwarf::DWARF64; - } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { - cantFail(C.takeError()); - if (Err) - *Err = createStringError( - errc::invalid_argument, - "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); - return {0, dwarf::DWARF32}; - } - - if (C) { - *Off = C.tell(); - return {Length, Format}; - } - if (Err) - *Err = C.takeError(); - else - consumeError(C.takeError()); - return {0, dwarf::DWARF32}; -} - -uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, - uint64_t *SecNdx, - Error *Err) const { - if (SecNdx) - *SecNdx = object::SectionedAddress::UndefSection; - if (!Section) - return getUnsigned(Off, Size, Err); - - ErrorAsOutParameter ErrAsOut(Err); - Optional<RelocAddrEntry> E = Obj->find(*Section, *Off); +//===- DWARFDataExtractor.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" + +using namespace llvm; + +std::pair<uint64_t, dwarf::DwarfFormat> +DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const { + ErrorAsOutParameter ErrAsOut(Err); + if (Err && *Err) + return {0, dwarf::DWARF32}; + + Cursor C(*Off); + uint64_t Length = getRelocatedValue(C, 4); + dwarf::DwarfFormat Format = dwarf::DWARF32; + if (Length == dwarf::DW_LENGTH_DWARF64) { + Length = getRelocatedValue(C, 8); + Format = dwarf::DWARF64; + } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { + cantFail(C.takeError()); + if (Err) + *Err = createStringError( + errc::invalid_argument, + "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); + return {0, dwarf::DWARF32}; + } + + if (C) { + *Off = C.tell(); + return {Length, Format}; + } + if (Err) + *Err = C.takeError(); + else + consumeError(C.takeError()); + return {0, dwarf::DWARF32}; +} + +uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, + uint64_t *SecNdx, + Error *Err) const { + if (SecNdx) + *SecNdx = object::SectionedAddress::UndefSection; + if (!Section) + return getUnsigned(Off, Size, Err); + + ErrorAsOutParameter ErrAsOut(Err); + Optional<RelocAddrEntry> E = Obj->find(*Section, *Off); uint64_t LocData = getUnsigned(Off, Size, Err); - if (!E || (Err && *Err)) + if (!E || (Err && *Err)) return LocData; - if (SecNdx) - *SecNdx = E->SectionIndex; + if (SecNdx) + *SecNdx = E->SectionIndex; uint64_t R = object::resolveRelocation(E->Resolver, E->Reloc, E->SymbolValue, LocData); - if (E->Reloc2) + if (E->Reloc2) R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2, R); - return R; -} - -Optional<uint64_t> -DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, - uint64_t PCRelOffset) const { - if (Encoding == dwarf::DW_EH_PE_omit) - return None; - - uint64_t Result = 0; - uint64_t OldOffset = *Offset; - // First get value - switch (Encoding & 0x0F) { - case dwarf::DW_EH_PE_absptr: - switch (getAddressSize()) { - case 2: - case 4: - case 8: - Result = getUnsigned(Offset, getAddressSize()); - break; - default: - return None; - } - break; - case dwarf::DW_EH_PE_uleb128: - Result = getULEB128(Offset); - break; - case dwarf::DW_EH_PE_sleb128: - Result = getSLEB128(Offset); - break; - case dwarf::DW_EH_PE_udata2: - Result = getUnsigned(Offset, 2); - break; - case dwarf::DW_EH_PE_udata4: - Result = getUnsigned(Offset, 4); - break; - case dwarf::DW_EH_PE_udata8: - Result = getUnsigned(Offset, 8); - break; - case dwarf::DW_EH_PE_sdata2: - Result = getSigned(Offset, 2); - break; - case dwarf::DW_EH_PE_sdata4: + return R; +} + +Optional<uint64_t> +DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, + uint64_t PCRelOffset) const { + if (Encoding == dwarf::DW_EH_PE_omit) + return None; + + uint64_t Result = 0; + uint64_t OldOffset = *Offset; + // First get value + switch (Encoding & 0x0F) { + case dwarf::DW_EH_PE_absptr: + switch (getAddressSize()) { + case 2: + case 4: + case 8: + Result = getUnsigned(Offset, getAddressSize()); + break; + default: + return None; + } + break; + case dwarf::DW_EH_PE_uleb128: + Result = getULEB128(Offset); + break; + case dwarf::DW_EH_PE_sleb128: + Result = getSLEB128(Offset); + break; + case dwarf::DW_EH_PE_udata2: + Result = getUnsigned(Offset, 2); + break; + case dwarf::DW_EH_PE_udata4: + Result = getUnsigned(Offset, 4); + break; + case dwarf::DW_EH_PE_udata8: + Result = getUnsigned(Offset, 8); + break; + case dwarf::DW_EH_PE_sdata2: + Result = getSigned(Offset, 2); + break; + case dwarf::DW_EH_PE_sdata4: Result = SignExtend64<32>(getRelocatedValue(4, Offset)); - break; - case dwarf::DW_EH_PE_sdata8: + break; + case dwarf::DW_EH_PE_sdata8: Result = getRelocatedValue(8, Offset); - break; - default: - return None; - } - // Then add relative offset, if required - switch (Encoding & 0x70) { - case dwarf::DW_EH_PE_absptr: - // do nothing - break; - case dwarf::DW_EH_PE_pcrel: - Result += PCRelOffset; - break; - case dwarf::DW_EH_PE_datarel: - case dwarf::DW_EH_PE_textrel: - case dwarf::DW_EH_PE_funcrel: - case dwarf::DW_EH_PE_aligned: - default: - *Offset = OldOffset; - return None; - } - - return Result; -} + break; + default: + return None; + } + // Then add relative offset, if required + switch (Encoding & 0x70) { + case dwarf::DW_EH_PE_absptr: + // do nothing + break; + case dwarf::DW_EH_PE_pcrel: + Result += PCRelOffset; + break; + case dwarf::DW_EH_PE_datarel: + case dwarf::DW_EH_PE_textrel: + case dwarf::DW_EH_PE_funcrel: + case dwarf::DW_EH_PE_aligned: + default: + *Offset = OldOffset; + return None; + } + + return Result; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp index 4afac2f995..3e426d6340 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp @@ -1,138 +1,138 @@ -//===- DWARFDebugAbbrev.cpp -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cinttypes> -#include <cstdint> - -using namespace llvm; - -DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { - clear(); -} - -void DWARFAbbreviationDeclarationSet::clear() { - Offset = 0; - FirstAbbrCode = 0; - Decls.clear(); -} - -bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, - uint64_t *OffsetPtr) { - clear(); - const uint64_t BeginOffset = *OffsetPtr; - Offset = BeginOffset; - DWARFAbbreviationDeclaration AbbrDecl; - uint32_t PrevAbbrCode = 0; - while (AbbrDecl.extract(Data, OffsetPtr)) { - if (FirstAbbrCode == 0) { - FirstAbbrCode = AbbrDecl.getCode(); - } else { - if (PrevAbbrCode + 1 != AbbrDecl.getCode()) { - // Codes are not consecutive, can't do O(1) lookups. - FirstAbbrCode = UINT32_MAX; - } - } - PrevAbbrCode = AbbrDecl.getCode(); - Decls.push_back(std::move(AbbrDecl)); - } - return BeginOffset != *OffsetPtr; -} - -void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { - for (const auto &Decl : Decls) - Decl.dump(OS); -} - -const DWARFAbbreviationDeclaration * -DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( - uint32_t AbbrCode) const { - if (FirstAbbrCode == UINT32_MAX) { - for (const auto &Decl : Decls) { - if (Decl.getCode() == AbbrCode) - return &Decl; - } - return nullptr; - } - if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size()) - return nullptr; - return &Decls[AbbrCode - FirstAbbrCode]; -} - -DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); } - -void DWARFDebugAbbrev::clear() { - AbbrDeclSets.clear(); - PrevAbbrOffsetPos = AbbrDeclSets.end(); -} - -void DWARFDebugAbbrev::extract(DataExtractor Data) { - clear(); - this->Data = Data; -} - -void DWARFDebugAbbrev::parse() const { - if (!Data) - return; - uint64_t Offset = 0; - auto I = AbbrDeclSets.begin(); - while (Data->isValidOffset(Offset)) { - while (I != AbbrDeclSets.end() && I->first < Offset) - ++I; - uint64_t CUAbbrOffset = Offset; - DWARFAbbreviationDeclarationSet AbbrDecls; - if (!AbbrDecls.extract(*Data, &Offset)) - break; - AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); - } - Data = None; -} - -void DWARFDebugAbbrev::dump(raw_ostream &OS) const { - parse(); - - if (AbbrDeclSets.empty()) { - OS << "< EMPTY >\n"; - return; - } - - for (const auto &I : AbbrDeclSets) { - OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first); - I.second.dump(OS); - } -} - -const DWARFAbbreviationDeclarationSet* -DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { - const auto End = AbbrDeclSets.end(); - if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) { - return &(PrevAbbrOffsetPos->second); - } - - const auto Pos = AbbrDeclSets.find(CUAbbrOffset); - if (Pos != End) { - PrevAbbrOffsetPos = Pos; - return &(Pos->second); - } - - if (Data && CUAbbrOffset < Data->getData().size()) { - uint64_t Offset = CUAbbrOffset; - DWARFAbbreviationDeclarationSet AbbrDecls; - if (!AbbrDecls.extract(*Data, &Offset)) - return nullptr; - PrevAbbrOffsetPos = - AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) - .first; - return &PrevAbbrOffsetPos->second; - } - - return nullptr; -} +//===- DWARFDebugAbbrev.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> + +using namespace llvm; + +DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() { + clear(); +} + +void DWARFAbbreviationDeclarationSet::clear() { + Offset = 0; + FirstAbbrCode = 0; + Decls.clear(); +} + +bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data, + uint64_t *OffsetPtr) { + clear(); + const uint64_t BeginOffset = *OffsetPtr; + Offset = BeginOffset; + DWARFAbbreviationDeclaration AbbrDecl; + uint32_t PrevAbbrCode = 0; + while (AbbrDecl.extract(Data, OffsetPtr)) { + if (FirstAbbrCode == 0) { + FirstAbbrCode = AbbrDecl.getCode(); + } else { + if (PrevAbbrCode + 1 != AbbrDecl.getCode()) { + // Codes are not consecutive, can't do O(1) lookups. + FirstAbbrCode = UINT32_MAX; + } + } + PrevAbbrCode = AbbrDecl.getCode(); + Decls.push_back(std::move(AbbrDecl)); + } + return BeginOffset != *OffsetPtr; +} + +void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const { + for (const auto &Decl : Decls) + Decl.dump(OS); +} + +const DWARFAbbreviationDeclaration * +DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration( + uint32_t AbbrCode) const { + if (FirstAbbrCode == UINT32_MAX) { + for (const auto &Decl : Decls) { + if (Decl.getCode() == AbbrCode) + return &Decl; + } + return nullptr; + } + if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size()) + return nullptr; + return &Decls[AbbrCode - FirstAbbrCode]; +} + +DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); } + +void DWARFDebugAbbrev::clear() { + AbbrDeclSets.clear(); + PrevAbbrOffsetPos = AbbrDeclSets.end(); +} + +void DWARFDebugAbbrev::extract(DataExtractor Data) { + clear(); + this->Data = Data; +} + +void DWARFDebugAbbrev::parse() const { + if (!Data) + return; + uint64_t Offset = 0; + auto I = AbbrDeclSets.begin(); + while (Data->isValidOffset(Offset)) { + while (I != AbbrDeclSets.end() && I->first < Offset) + ++I; + uint64_t CUAbbrOffset = Offset; + DWARFAbbreviationDeclarationSet AbbrDecls; + if (!AbbrDecls.extract(*Data, &Offset)) + break; + AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls))); + } + Data = None; +} + +void DWARFDebugAbbrev::dump(raw_ostream &OS) const { + parse(); + + if (AbbrDeclSets.empty()) { + OS << "< EMPTY >\n"; + return; + } + + for (const auto &I : AbbrDeclSets) { + OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first); + I.second.dump(OS); + } +} + +const DWARFAbbreviationDeclarationSet* +DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const { + const auto End = AbbrDeclSets.end(); + if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) { + return &(PrevAbbrOffsetPos->second); + } + + const auto Pos = AbbrDeclSets.find(CUAbbrOffset); + if (Pos != End) { + PrevAbbrOffsetPos = Pos; + return &(Pos->second); + } + + if (Data && CUAbbrOffset < Data->getData().size()) { + uint64_t Offset = CUAbbrOffset; + DWARFAbbreviationDeclarationSet AbbrDecls; + if (!AbbrDecls.extract(*Data, &Offset)) + return nullptr; + PrevAbbrOffsetPos = + AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls))) + .first; + return &PrevAbbrOffsetPos->second; + } + + return nullptr; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp index dcf2aefeb3..9ce43fbae4 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp @@ -1,174 +1,174 @@ -//===- DWARFDebugAddr.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" - -using namespace llvm; - -Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, - uint64_t *OffsetPtr, - uint64_t EndOffset) { - assert(EndOffset >= *OffsetPtr); - uint64_t DataSize = EndOffset - *OffsetPtr; - assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); - if (AddrSize != 4 && AddrSize != 8) - return createStringError(errc::not_supported, - "address table at offset 0x%" PRIx64 - " has unsupported address size %" PRIu8 - " (4 and 8 are supported)", - Offset, AddrSize); - if (DataSize % AddrSize != 0) { - invalidateLength(); - return createStringError(errc::invalid_argument, - "address table at offset 0x%" PRIx64 - " contains data of size 0x%" PRIx64 - " which is not a multiple of addr size %" PRIu8, - Offset, DataSize, AddrSize); - } - Addrs.clear(); - size_t Count = DataSize / AddrSize; - Addrs.reserve(Count); - while (Count--) - Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); - return Error::success(); -} - -Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, - uint64_t *OffsetPtr, uint8_t CUAddrSize, - std::function<void(Error)> WarnCallback) { - Offset = *OffsetPtr; - llvm::Error Err = Error::success(); - std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); - if (Err) { - invalidateLength(); - return createStringError(errc::invalid_argument, - "parsing address table at offset 0x%" PRIx64 - ": %s", - Offset, toString(std::move(Err)).c_str()); - } - - if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { - uint64_t DiagnosticLength = Length; - invalidateLength(); - return createStringError( - errc::invalid_argument, - "section is not large enough to contain an address table " - "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, - Offset, DiagnosticLength); - } - uint64_t EndOffset = *OffsetPtr + Length; - // Ensure that we can read the remaining header fields. - if (Length < 4) { - uint64_t DiagnosticLength = Length; - invalidateLength(); - return createStringError( - errc::invalid_argument, - "address table at offset 0x%" PRIx64 - " has a unit_length value of 0x%" PRIx64 - ", which is too small to contain a complete header", - Offset, DiagnosticLength); - } - - Version = Data.getU16(OffsetPtr); - AddrSize = Data.getU8(OffsetPtr); - SegSize = Data.getU8(OffsetPtr); - - // Perform a basic validation of the header fields. - if (Version != 5) - return createStringError(errc::not_supported, - "address table at offset 0x%" PRIx64 - " has unsupported version %" PRIu16, - Offset, Version); - // TODO: add support for non-zero segment selector size. - if (SegSize != 0) - return createStringError(errc::not_supported, - "address table at offset 0x%" PRIx64 - " has unsupported segment selector size %" PRIu8, - Offset, SegSize); - - if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) - return Err; - if (CUAddrSize && AddrSize != CUAddrSize) { - WarnCallback(createStringError( - errc::invalid_argument, - "address table at offset 0x%" PRIx64 " has address size %" PRIu8 - " which is different from CU address size %" PRIu8, - Offset, AddrSize, CUAddrSize)); - } - return Error::success(); -} - -Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, - uint64_t *OffsetPtr, - uint16_t CUVersion, - uint8_t CUAddrSize) { - assert(CUVersion > 0 && CUVersion < 5); - - Offset = *OffsetPtr; - Length = 0; - Version = CUVersion; - AddrSize = CUAddrSize; - SegSize = 0; - - return extractAddresses(Data, OffsetPtr, Data.size()); -} - -Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, - uint64_t *OffsetPtr, - uint16_t CUVersion, - uint8_t CUAddrSize, - std::function<void(Error)> WarnCallback) { - if (CUVersion > 0 && CUVersion < 5) - return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); - if (CUVersion == 0) - WarnCallback(createStringError(errc::invalid_argument, - "DWARF version is not defined in CU," - " assuming version 5")); - return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); -} - -void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { - if (DumpOpts.Verbose) - OS << format("0x%8.8" PRIx64 ": ", Offset); - if (Length) { - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); - OS << "Address table header: " - << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) - << ", format = " << dwarf::FormatString(Format) - << format(", version = 0x%4.4" PRIx16, Version) - << format(", addr_size = 0x%2.2" PRIx8, AddrSize) - << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; - } - - if (Addrs.size() > 0) { - const char *AddrFmt = - (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; - OS << "Addrs: [\n"; - for (uint64_t Addr : Addrs) - OS << format(AddrFmt, Addr); - OS << "]\n"; - } -} - -Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { - if (Index < Addrs.size()) - return Addrs[Index]; - return createStringError(errc::invalid_argument, - "Index %" PRIu32 " is out of range of the " - "address table at offset 0x%" PRIx64, - Index, Offset); -} - -Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { - if (Length == 0) - return None; - return Length + dwarf::getUnitLengthFieldByteSize(Format); -} - +//===- DWARFDebugAddr.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" + +using namespace llvm; + +Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint64_t EndOffset) { + assert(EndOffset >= *OffsetPtr); + uint64_t DataSize = EndOffset - *OffsetPtr; + assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); + if (AddrSize != 4 && AddrSize != 8) + return createStringError(errc::not_supported, + "address table at offset 0x%" PRIx64 + " has unsupported address size %" PRIu8 + " (4 and 8 are supported)", + Offset, AddrSize); + if (DataSize % AddrSize != 0) { + invalidateLength(); + return createStringError(errc::invalid_argument, + "address table at offset 0x%" PRIx64 + " contains data of size 0x%" PRIx64 + " which is not a multiple of addr size %" PRIu8, + Offset, DataSize, AddrSize); + } + Addrs.clear(); + size_t Count = DataSize / AddrSize; + Addrs.reserve(Count); + while (Count--) + Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr)); + return Error::success(); +} + +Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, uint8_t CUAddrSize, + std::function<void(Error)> WarnCallback) { + Offset = *OffsetPtr; + llvm::Error Err = Error::success(); + std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err); + if (Err) { + invalidateLength(); + return createStringError(errc::invalid_argument, + "parsing address table at offset 0x%" PRIx64 + ": %s", + Offset, toString(std::move(Err)).c_str()); + } + + if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) { + uint64_t DiagnosticLength = Length; + invalidateLength(); + return createStringError( + errc::invalid_argument, + "section is not large enough to contain an address table " + "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64, + Offset, DiagnosticLength); + } + uint64_t EndOffset = *OffsetPtr + Length; + // Ensure that we can read the remaining header fields. + if (Length < 4) { + uint64_t DiagnosticLength = Length; + invalidateLength(); + return createStringError( + errc::invalid_argument, + "address table at offset 0x%" PRIx64 + " has a unit_length value of 0x%" PRIx64 + ", which is too small to contain a complete header", + Offset, DiagnosticLength); + } + + Version = Data.getU16(OffsetPtr); + AddrSize = Data.getU8(OffsetPtr); + SegSize = Data.getU8(OffsetPtr); + + // Perform a basic validation of the header fields. + if (Version != 5) + return createStringError(errc::not_supported, + "address table at offset 0x%" PRIx64 + " has unsupported version %" PRIu16, + Offset, Version); + // TODO: add support for non-zero segment selector size. + if (SegSize != 0) + return createStringError(errc::not_supported, + "address table at offset 0x%" PRIx64 + " has unsupported segment selector size %" PRIu8, + Offset, SegSize); + + if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset)) + return Err; + if (CUAddrSize && AddrSize != CUAddrSize) { + WarnCallback(createStringError( + errc::invalid_argument, + "address table at offset 0x%" PRIx64 " has address size %" PRIu8 + " which is different from CU address size %" PRIu8, + Offset, AddrSize, CUAddrSize)); + } + return Error::success(); +} + +Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint16_t CUVersion, + uint8_t CUAddrSize) { + assert(CUVersion > 0 && CUVersion < 5); + + Offset = *OffsetPtr; + Length = 0; + Version = CUVersion; + AddrSize = CUAddrSize; + SegSize = 0; + + return extractAddresses(Data, OffsetPtr, Data.size()); +} + +Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, + uint16_t CUVersion, + uint8_t CUAddrSize, + std::function<void(Error)> WarnCallback) { + if (CUVersion > 0 && CUVersion < 5) + return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize); + if (CUVersion == 0) + WarnCallback(createStringError(errc::invalid_argument, + "DWARF version is not defined in CU," + " assuming version 5")); + return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback); +} + +void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { + if (DumpOpts.Verbose) + OS << format("0x%8.8" PRIx64 ": ", Offset); + if (Length) { + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); + OS << "Address table header: " + << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length) + << ", format = " << dwarf::FormatString(Format) + << format(", version = 0x%4.4" PRIx16, Version) + << format(", addr_size = 0x%2.2" PRIx8, AddrSize) + << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n"; + } + + if (Addrs.size() > 0) { + const char *AddrFmt = + (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; + OS << "Addrs: [\n"; + for (uint64_t Addr : Addrs) + OS << format(AddrFmt, Addr); + OS << "]\n"; + } +} + +Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const { + if (Index < Addrs.size()) + return Addrs[Index]; + return createStringError(errc::invalid_argument, + "Index %" PRIu32 " is out of range of the " + "address table at offset 0x%" PRIx64, + Index, Offset); +} + +Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const { + if (Length == 0) + return None; + return Length + dwarf::getUnitLengthFieldByteSize(Format); +} + diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp index 598e3ecee3..292383f039 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -1,179 +1,179 @@ -//===- DWARFDebugArangeSet.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" -#include "llvm/BinaryFormat/Dwarf.h" +//===- DWARFDebugArangeSet.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cassert> -#include <cinttypes> -#include <cstdint> -#include <cstring> - -using namespace llvm; - -void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS, - uint32_t AddressSize) const { +#include "llvm/Support/Errc.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstring> + +using namespace llvm; + +void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS, + uint32_t AddressSize) const { OS << '['; DWARFFormValue::dumpAddress(OS, AddressSize, Address); OS << ", "; DWARFFormValue::dumpAddress(OS, AddressSize, getEndAddress()); OS << ')'; -} - -void DWARFDebugArangeSet::clear() { - Offset = -1ULL; - std::memset(&HeaderData, 0, sizeof(Header)); - ArangeDescriptors.clear(); -} - -Error DWARFDebugArangeSet::extract(DWARFDataExtractor data, +} + +void DWARFDebugArangeSet::clear() { + Offset = -1ULL; + std::memset(&HeaderData, 0, sizeof(Header)); + ArangeDescriptors.clear(); +} + +Error DWARFDebugArangeSet::extract(DWARFDataExtractor data, uint64_t *offset_ptr, function_ref<void(Error)> WarningHandler) { - assert(data.isValidOffset(*offset_ptr)); - ArangeDescriptors.clear(); - Offset = *offset_ptr; - - // 7.21 Address Range Table (extract) - // Each set of entries in the table of address ranges contained in - // the .debug_aranges section begins with a header containing: - // 1. unit_length (initial length) - // A 4-byte (32-bit DWARF) or 12-byte (64-bit DWARF) length containing - // the length of the set of entries for this compilation unit, - // not including the length field itself. - // 2. version (uhalf) - // The value in this field is 2. - // 3. debug_info_offset (section offset) - // A 4-byte (32-bit DWARF) or 8-byte (64-bit DWARF) offset into the - // .debug_info section of the compilation unit header. - // 4. address_size (ubyte) - // 5. segment_selector_size (ubyte) - // This header is followed by a series of tuples. Each tuple consists of - // a segment, an address and a length. The segment selector size is given by - // the segment_selector_size field of the header; the address and length - // size are each given by the address_size field of the header. Each set of - // tuples is terminated by a 0 for the segment, a 0 for the address and 0 - // for the length. If the segment_selector_size field in the header is zero, - // the segment selectors are omitted from all tuples, including - // the terminating tuple. - - Error Err = Error::success(); - std::tie(HeaderData.Length, HeaderData.Format) = - data.getInitialLength(offset_ptr, &Err); - HeaderData.Version = data.getU16(offset_ptr, &Err); - HeaderData.CuOffset = data.getUnsigned( - offset_ptr, dwarf::getDwarfOffsetByteSize(HeaderData.Format), &Err); - HeaderData.AddrSize = data.getU8(offset_ptr, &Err); - HeaderData.SegSize = data.getU8(offset_ptr, &Err); - if (Err) { - return createStringError(errc::invalid_argument, - "parsing address ranges table at offset 0x%" PRIx64 - ": %s", - Offset, toString(std::move(Err)).c_str()); - } - - // Perform basic validation of the header fields. - uint64_t full_length = - dwarf::getUnitLengthFieldByteSize(HeaderData.Format) + HeaderData.Length; - if (!data.isValidOffsetForDataOfSize(Offset, full_length)) - return createStringError(errc::invalid_argument, - "the length of address range table at offset " - "0x%" PRIx64 " exceeds section size", - Offset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) - return createStringError(errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " has unsupported address size: %d " - "(4 and 8 supported)", - Offset, HeaderData.AddrSize); - if (HeaderData.SegSize != 0) - return createStringError(errc::not_supported, - "non-zero segment selector size in address range " - "table at offset 0x%" PRIx64 " is not supported", - Offset); - - // The first tuple following the header in each set begins at an offset that - // is a multiple of the size of a single tuple (that is, twice the size of - // an address because we do not support non-zero segment selector sizes). - // Therefore, the full length should also be a multiple of the tuple size. - const uint32_t tuple_size = HeaderData.AddrSize * 2; - if (full_length % tuple_size != 0) - return createStringError( - errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " has length that is not a multiple of the tuple size", - Offset); - - // The header is padded, if necessary, to the appropriate boundary. - const uint32_t header_size = *offset_ptr - Offset; - uint32_t first_tuple_offset = 0; - while (first_tuple_offset < header_size) - first_tuple_offset += tuple_size; - - // There should be space for at least one tuple. - if (full_length <= first_tuple_offset) - return createStringError( - errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " has an insufficient length to contain any entries", - Offset); - - *offset_ptr = Offset + first_tuple_offset; - - Descriptor arangeDescriptor; - - static_assert(sizeof(arangeDescriptor.Address) == - sizeof(arangeDescriptor.Length), - "Different datatypes for addresses and sizes!"); - assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); - - uint64_t end_offset = Offset + full_length; - while (*offset_ptr < end_offset) { - uint64_t EntryOffset = *offset_ptr; - arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); - arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); - - // Each set of tuples is terminated by a 0 for the address and 0 - // for the length. - if (arangeDescriptor.Length == 0 && arangeDescriptor.Address == 0) { - if (*offset_ptr == end_offset) - return ErrorSuccess(); + assert(data.isValidOffset(*offset_ptr)); + ArangeDescriptors.clear(); + Offset = *offset_ptr; + + // 7.21 Address Range Table (extract) + // Each set of entries in the table of address ranges contained in + // the .debug_aranges section begins with a header containing: + // 1. unit_length (initial length) + // A 4-byte (32-bit DWARF) or 12-byte (64-bit DWARF) length containing + // the length of the set of entries for this compilation unit, + // not including the length field itself. + // 2. version (uhalf) + // The value in this field is 2. + // 3. debug_info_offset (section offset) + // A 4-byte (32-bit DWARF) or 8-byte (64-bit DWARF) offset into the + // .debug_info section of the compilation unit header. + // 4. address_size (ubyte) + // 5. segment_selector_size (ubyte) + // This header is followed by a series of tuples. Each tuple consists of + // a segment, an address and a length. The segment selector size is given by + // the segment_selector_size field of the header; the address and length + // size are each given by the address_size field of the header. Each set of + // tuples is terminated by a 0 for the segment, a 0 for the address and 0 + // for the length. If the segment_selector_size field in the header is zero, + // the segment selectors are omitted from all tuples, including + // the terminating tuple. + + Error Err = Error::success(); + std::tie(HeaderData.Length, HeaderData.Format) = + data.getInitialLength(offset_ptr, &Err); + HeaderData.Version = data.getU16(offset_ptr, &Err); + HeaderData.CuOffset = data.getUnsigned( + offset_ptr, dwarf::getDwarfOffsetByteSize(HeaderData.Format), &Err); + HeaderData.AddrSize = data.getU8(offset_ptr, &Err); + HeaderData.SegSize = data.getU8(offset_ptr, &Err); + if (Err) { + return createStringError(errc::invalid_argument, + "parsing address ranges table at offset 0x%" PRIx64 + ": %s", + Offset, toString(std::move(Err)).c_str()); + } + + // Perform basic validation of the header fields. + uint64_t full_length = + dwarf::getUnitLengthFieldByteSize(HeaderData.Format) + HeaderData.Length; + if (!data.isValidOffsetForDataOfSize(Offset, full_length)) + return createStringError(errc::invalid_argument, + "the length of address range table at offset " + "0x%" PRIx64 " exceeds section size", + Offset); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createStringError(errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has unsupported address size: %d " + "(4 and 8 supported)", + Offset, HeaderData.AddrSize); + if (HeaderData.SegSize != 0) + return createStringError(errc::not_supported, + "non-zero segment selector size in address range " + "table at offset 0x%" PRIx64 " is not supported", + Offset); + + // The first tuple following the header in each set begins at an offset that + // is a multiple of the size of a single tuple (that is, twice the size of + // an address because we do not support non-zero segment selector sizes). + // Therefore, the full length should also be a multiple of the tuple size. + const uint32_t tuple_size = HeaderData.AddrSize * 2; + if (full_length % tuple_size != 0) + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has length that is not a multiple of the tuple size", + Offset); + + // The header is padded, if necessary, to the appropriate boundary. + const uint32_t header_size = *offset_ptr - Offset; + uint32_t first_tuple_offset = 0; + while (first_tuple_offset < header_size) + first_tuple_offset += tuple_size; + + // There should be space for at least one tuple. + if (full_length <= first_tuple_offset) + return createStringError( + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has an insufficient length to contain any entries", + Offset); + + *offset_ptr = Offset + first_tuple_offset; + + Descriptor arangeDescriptor; + + static_assert(sizeof(arangeDescriptor.Address) == + sizeof(arangeDescriptor.Length), + "Different datatypes for addresses and sizes!"); + assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize); + + uint64_t end_offset = Offset + full_length; + while (*offset_ptr < end_offset) { + uint64_t EntryOffset = *offset_ptr; + arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize); + arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize); + + // Each set of tuples is terminated by a 0 for the address and 0 + // for the length. + if (arangeDescriptor.Length == 0 && arangeDescriptor.Address == 0) { + if (*offset_ptr == end_offset) + return ErrorSuccess(); WarningHandler(createStringError( - errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " has a premature terminator entry at offset 0x%" PRIx64, + errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " has a premature terminator entry at offset 0x%" PRIx64, Offset, EntryOffset)); - } - - ArangeDescriptors.push_back(arangeDescriptor); - } - - return createStringError(errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " is not terminated by null entry", - Offset); -} - -void DWARFDebugArangeSet::dump(raw_ostream &OS) const { - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(HeaderData.Format); - OS << "Address Range Header: " - << format("length = 0x%0*" PRIx64 ", ", OffsetDumpWidth, HeaderData.Length) - << "format = " << dwarf::FormatString(HeaderData.Format) << ", " - << format("version = 0x%4.4x, ", HeaderData.Version) - << format("cu_offset = 0x%0*" PRIx64 ", ", OffsetDumpWidth, - HeaderData.CuOffset) - << format("addr_size = 0x%2.2x, ", HeaderData.AddrSize) - << format("seg_size = 0x%2.2x\n", HeaderData.SegSize); - - for (const auto &Desc : ArangeDescriptors) { - Desc.dump(OS, HeaderData.AddrSize); - OS << '\n'; - } -} + } + + ArangeDescriptors.push_back(arangeDescriptor); + } + + return createStringError(errc::invalid_argument, + "address range table at offset 0x%" PRIx64 + " is not terminated by null entry", + Offset); +} + +void DWARFDebugArangeSet::dump(raw_ostream &OS) const { + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(HeaderData.Format); + OS << "Address Range Header: " + << format("length = 0x%0*" PRIx64 ", ", OffsetDumpWidth, HeaderData.Length) + << "format = " << dwarf::FormatString(HeaderData.Format) << ", " + << format("version = 0x%4.4x, ", HeaderData.Version) + << format("cu_offset = 0x%0*" PRIx64 ", ", OffsetDumpWidth, + HeaderData.CuOffset) + << format("addr_size = 0x%2.2x, ", HeaderData.AddrSize) + << format("seg_size = 0x%2.2x\n", HeaderData.SegSize); + + for (const auto &Desc : ArangeDescriptors) { + Desc.dump(OS, HeaderData.AddrSize); + OS << '\n'; + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp index e0db469752..57367b3948 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp @@ -1,128 +1,128 @@ -//===- DWARFDebugAranges.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" -#include "llvm/Support/DataExtractor.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <set> -#include <vector> - -using namespace llvm; - -void DWARFDebugAranges::extract( - DWARFDataExtractor DebugArangesData, - function_ref<void(Error)> RecoverableErrorHandler) { - if (!DebugArangesData.isValidOffset(0)) - return; - uint64_t Offset = 0; - DWARFDebugArangeSet Set; - - while (DebugArangesData.isValidOffset(Offset)) { +//===- DWARFDebugAranges.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" +#include "llvm/Support/DataExtractor.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <set> +#include <vector> + +using namespace llvm; + +void DWARFDebugAranges::extract( + DWARFDataExtractor DebugArangesData, + function_ref<void(Error)> RecoverableErrorHandler) { + if (!DebugArangesData.isValidOffset(0)) + return; + uint64_t Offset = 0; + DWARFDebugArangeSet Set; + + while (DebugArangesData.isValidOffset(Offset)) { if (Error E = Set.extract(DebugArangesData, &Offset, RecoverableErrorHandler)) { - RecoverableErrorHandler(std::move(E)); - return; - } - uint64_t CUOffset = Set.getCompileUnitDIEOffset(); - for (const auto &Desc : Set.descriptors()) { - uint64_t LowPC = Desc.Address; - uint64_t HighPC = Desc.getEndAddress(); - appendRange(CUOffset, LowPC, HighPC); - } - ParsedCUOffsets.insert(CUOffset); - } -} - -void DWARFDebugAranges::generate(DWARFContext *CTX) { - clear(); - if (!CTX) - return; - - // Extract aranges from .debug_aranges section. - DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(), - CTX->isLittleEndian(), 0); - extract(ArangesData, CTX->getRecoverableErrorHandler()); - - // Generate aranges from DIEs: even if .debug_aranges section is present, - // it may describe only a small subset of compilation units, so we need to - // manually build aranges for the rest of them. - for (const auto &CU : CTX->compile_units()) { - uint64_t CUOffset = CU->getOffset(); - if (ParsedCUOffsets.insert(CUOffset).second) { - Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges(); - if (!CURanges) - CTX->getRecoverableErrorHandler()(CURanges.takeError()); - else - for (const auto &R : *CURanges) - appendRange(CUOffset, R.LowPC, R.HighPC); - } - } - - construct(); -} - -void DWARFDebugAranges::clear() { - Endpoints.clear(); - Aranges.clear(); - ParsedCUOffsets.clear(); -} - -void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC, - uint64_t HighPC) { - if (LowPC >= HighPC) - return; - Endpoints.emplace_back(LowPC, CUOffset, true); - Endpoints.emplace_back(HighPC, CUOffset, false); -} - -void DWARFDebugAranges::construct() { - std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing - // a current address range. - llvm::sort(Endpoints); - uint64_t PrevAddress = -1ULL; - for (const auto &E : Endpoints) { - if (PrevAddress < E.Address && !ValidCUs.empty()) { - // If the address range between two endpoints is described by some - // CU, first try to extend the last range in Aranges. If we can't - // do it, start a new range. - if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress && - ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) { - Aranges.back().setHighPC(E.Address); - } else { - Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin()); - } - } - // Update the set of valid CUs. - if (E.IsRangeStart) { - ValidCUs.insert(E.CUOffset); - } else { - auto CUPos = ValidCUs.find(E.CUOffset); - assert(CUPos != ValidCUs.end()); - ValidCUs.erase(CUPos); - } - PrevAddress = E.Address; - } - assert(ValidCUs.empty()); - - // Endpoints are not needed now. - Endpoints.clear(); - Endpoints.shrink_to_fit(); -} - -uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const { - RangeCollIterator It = - partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; }); - if (It != Aranges.end() && It->LowPC <= Address) - return It->CUOffset; - return -1ULL; -} + RecoverableErrorHandler(std::move(E)); + return; + } + uint64_t CUOffset = Set.getCompileUnitDIEOffset(); + for (const auto &Desc : Set.descriptors()) { + uint64_t LowPC = Desc.Address; + uint64_t HighPC = Desc.getEndAddress(); + appendRange(CUOffset, LowPC, HighPC); + } + ParsedCUOffsets.insert(CUOffset); + } +} + +void DWARFDebugAranges::generate(DWARFContext *CTX) { + clear(); + if (!CTX) + return; + + // Extract aranges from .debug_aranges section. + DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(), + CTX->isLittleEndian(), 0); + extract(ArangesData, CTX->getRecoverableErrorHandler()); + + // Generate aranges from DIEs: even if .debug_aranges section is present, + // it may describe only a small subset of compilation units, so we need to + // manually build aranges for the rest of them. + for (const auto &CU : CTX->compile_units()) { + uint64_t CUOffset = CU->getOffset(); + if (ParsedCUOffsets.insert(CUOffset).second) { + Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges(); + if (!CURanges) + CTX->getRecoverableErrorHandler()(CURanges.takeError()); + else + for (const auto &R : *CURanges) + appendRange(CUOffset, R.LowPC, R.HighPC); + } + } + + construct(); +} + +void DWARFDebugAranges::clear() { + Endpoints.clear(); + Aranges.clear(); + ParsedCUOffsets.clear(); +} + +void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC, + uint64_t HighPC) { + if (LowPC >= HighPC) + return; + Endpoints.emplace_back(LowPC, CUOffset, true); + Endpoints.emplace_back(HighPC, CUOffset, false); +} + +void DWARFDebugAranges::construct() { + std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing + // a current address range. + llvm::sort(Endpoints); + uint64_t PrevAddress = -1ULL; + for (const auto &E : Endpoints) { + if (PrevAddress < E.Address && !ValidCUs.empty()) { + // If the address range between two endpoints is described by some + // CU, first try to extend the last range in Aranges. If we can't + // do it, start a new range. + if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress && + ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) { + Aranges.back().setHighPC(E.Address); + } else { + Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin()); + } + } + // Update the set of valid CUs. + if (E.IsRangeStart) { + ValidCUs.insert(E.CUOffset); + } else { + auto CUPos = ValidCUs.find(E.CUOffset); + assert(CUPos != ValidCUs.end()); + ValidCUs.erase(CUPos); + } + PrevAddress = E.Address; + } + assert(ValidCUs.empty()); + + // Endpoints are not needed now. + Endpoints.clear(); + Endpoints.shrink_to_fit(); +} + +uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const { + RangeCollIterator It = + partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; }); + if (It != Aranges.end() && It->LowPC <= Address) + return It->CUOffset; + return -1ULL; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index b74ecac681..6a6749c33c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -1,35 +1,35 @@ -//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" +//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Errc.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 <vector> - -using namespace llvm; -using namespace dwarf; - +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.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 <vector> + +using namespace llvm; +using namespace dwarf; + static void printRegister(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, unsigned RegNum) { if (MRI) { @@ -42,575 +42,575 @@ static void printRegister(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH, } OS << "reg" << RegNum; } - -// 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; - -Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, - uint64_t EndOffset) { - DataExtractor::Cursor C(*Offset); - while (C && C.tell() < EndOffset) { - uint8_t Opcode = Data.getRelocatedValue(C, 1); - if (!C) - break; - - // Some instructions have a primary opcode encoded in the top bits. - if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) { - // If it's a primary opcode, the first operand is encoded in the bottom - // bits of the opcode itself. - uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; - switch (Primary) { - case DW_CFA_advance_loc: - case DW_CFA_restore: - addInstruction(Primary, Op1); - break; - case DW_CFA_offset: - addInstruction(Primary, Op1, Data.getULEB128(C)); - break; - default: - llvm_unreachable("invalid primary CFI opcode"); - } - continue; - } - - // Extended opcode - its value is Opcode itself. - switch (Opcode) { - default: - return createStringError(errc::illegal_byte_sequence, - "invalid extended CFI opcode 0x%" PRIx8, Opcode); - case DW_CFA_nop: - case DW_CFA_remember_state: - case DW_CFA_restore_state: - case DW_CFA_GNU_window_save: - // No operands - addInstruction(Opcode); - break; - case DW_CFA_set_loc: - // Operands: Address - addInstruction(Opcode, Data.getRelocatedAddress(C)); - break; - case DW_CFA_advance_loc1: - // Operands: 1-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 1)); - break; - case DW_CFA_advance_loc2: - // Operands: 2-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 2)); - break; - case DW_CFA_advance_loc4: - // Operands: 4-byte delta - addInstruction(Opcode, Data.getRelocatedValue(C, 4)); - break; - case DW_CFA_restore_extended: - case DW_CFA_undefined: - case DW_CFA_same_value: - case DW_CFA_def_cfa_register: - case DW_CFA_def_cfa_offset: - case DW_CFA_GNU_args_size: - // Operands: ULEB128 - addInstruction(Opcode, Data.getULEB128(C)); - break; - case DW_CFA_def_cfa_offset_sf: - // Operands: SLEB128 - addInstruction(Opcode, Data.getSLEB128(C)); - break; - case DW_CFA_offset_extended: - case DW_CFA_register: - case DW_CFA_def_cfa: - case DW_CFA_val_offset: { - // Operands: ULEB128, ULEB128 - // Note: We can not embed getULEB128 directly into function - // argument list. getULEB128 changes Offset and order of evaluation - // for arguments is unspecified. - uint64_t op1 = Data.getULEB128(C); - uint64_t op2 = Data.getULEB128(C); - addInstruction(Opcode, op1, op2); - break; - } - case DW_CFA_offset_extended_sf: - case DW_CFA_def_cfa_sf: - case DW_CFA_val_offset_sf: { - // Operands: ULEB128, SLEB128 - // Note: see comment for the previous case - uint64_t op1 = Data.getULEB128(C); - uint64_t op2 = (uint64_t)Data.getSLEB128(C); - addInstruction(Opcode, op1, op2); - break; - } - case DW_CFA_def_cfa_expression: { - uint64_t ExprLength = Data.getULEB128(C); - addInstruction(Opcode, 0); - StringRef Expression = Data.getBytes(C, ExprLength); - - DataExtractor Extractor(Expression, Data.isLittleEndian(), - Data.getAddressSize()); - // Note. We do not pass the DWARF format to DWARFExpression, because - // DW_OP_call_ref, the only operation which depends on the format, is - // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. - Instructions.back().Expression = - DWARFExpression(Extractor, Data.getAddressSize()); - break; - } - case DW_CFA_expression: - case DW_CFA_val_expression: { - uint64_t RegNum = Data.getULEB128(C); - addInstruction(Opcode, RegNum, 0); - - uint64_t BlockLength = Data.getULEB128(C); - StringRef Expression = Data.getBytes(C, BlockLength); - DataExtractor Extractor(Expression, Data.isLittleEndian(), - Data.getAddressSize()); - // Note. We do not pass the DWARF format to DWARFExpression, because - // DW_OP_call_ref, the only operation which depends on the format, is - // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. - Instructions.back().Expression = - DWARFExpression(Extractor, Data.getAddressSize()); - break; - } - } - } - - *Offset = C.tell(); - return C.takeError(); -} - -namespace { - - -} // end anonymous namespace - -ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() { - static OperandType OpTypes[DW_CFA_restore+1][2]; - static bool Initialized = false; - if (Initialized) { - return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1); - } - Initialized = true; - -#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \ - do { \ - OpTypes[OP][0] = OPTYPE0; \ - OpTypes[OP][1] = OPTYPE1; \ - } while (false) -#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) -#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) - - DECLARE_OP1(DW_CFA_set_loc, OT_Address); - DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset); - DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset); - DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); - DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); - DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); - DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); - DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); - DECLARE_OP1(DW_CFA_undefined, OT_Register); - DECLARE_OP1(DW_CFA_same_value, OT_Register); - DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset); - DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset); - DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register); - DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression); - DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression); - DECLARE_OP1(DW_CFA_restore, OT_Register); - DECLARE_OP1(DW_CFA_restore_extended, OT_Register); - DECLARE_OP0(DW_CFA_remember_state); - DECLARE_OP0(DW_CFA_restore_state); - DECLARE_OP0(DW_CFA_GNU_window_save); - DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset); - DECLARE_OP0(DW_CFA_nop); - -#undef DECLARE_OP0 -#undef DECLARE_OP1 -#undef DECLARE_OP2 - - return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1); -} - -/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. + +// 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; + +Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset, + uint64_t EndOffset) { + DataExtractor::Cursor C(*Offset); + while (C && C.tell() < EndOffset) { + uint8_t Opcode = Data.getRelocatedValue(C, 1); + if (!C) + break; + + // Some instructions have a primary opcode encoded in the top bits. + if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) { + // If it's a primary opcode, the first operand is encoded in the bottom + // bits of the opcode itself. + uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK; + switch (Primary) { + case DW_CFA_advance_loc: + case DW_CFA_restore: + addInstruction(Primary, Op1); + break; + case DW_CFA_offset: + addInstruction(Primary, Op1, Data.getULEB128(C)); + break; + default: + llvm_unreachable("invalid primary CFI opcode"); + } + continue; + } + + // Extended opcode - its value is Opcode itself. + switch (Opcode) { + default: + return createStringError(errc::illegal_byte_sequence, + "invalid extended CFI opcode 0x%" PRIx8, Opcode); + case DW_CFA_nop: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + case DW_CFA_GNU_window_save: + // No operands + addInstruction(Opcode); + break; + case DW_CFA_set_loc: + // Operands: Address + addInstruction(Opcode, Data.getRelocatedAddress(C)); + break; + case DW_CFA_advance_loc1: + // Operands: 1-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 1)); + break; + case DW_CFA_advance_loc2: + // Operands: 2-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 2)); + break; + case DW_CFA_advance_loc4: + // Operands: 4-byte delta + addInstruction(Opcode, Data.getRelocatedValue(C, 4)); + break; + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_same_value: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa_offset: + case DW_CFA_GNU_args_size: + // Operands: ULEB128 + addInstruction(Opcode, Data.getULEB128(C)); + break; + case DW_CFA_def_cfa_offset_sf: + // Operands: SLEB128 + addInstruction(Opcode, Data.getSLEB128(C)); + break; + case DW_CFA_offset_extended: + case DW_CFA_register: + case DW_CFA_def_cfa: + case DW_CFA_val_offset: { + // Operands: ULEB128, ULEB128 + // Note: We can not embed getULEB128 directly into function + // argument list. getULEB128 changes Offset and order of evaluation + // for arguments is unspecified. + uint64_t op1 = Data.getULEB128(C); + uint64_t op2 = Data.getULEB128(C); + addInstruction(Opcode, op1, op2); + break; + } + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_val_offset_sf: { + // Operands: ULEB128, SLEB128 + // Note: see comment for the previous case + uint64_t op1 = Data.getULEB128(C); + uint64_t op2 = (uint64_t)Data.getSLEB128(C); + addInstruction(Opcode, op1, op2); + break; + } + case DW_CFA_def_cfa_expression: { + uint64_t ExprLength = Data.getULEB128(C); + addInstruction(Opcode, 0); + StringRef Expression = Data.getBytes(C, ExprLength); + + DataExtractor Extractor(Expression, Data.isLittleEndian(), + Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. + Instructions.back().Expression = + DWARFExpression(Extractor, Data.getAddressSize()); + break; + } + case DW_CFA_expression: + case DW_CFA_val_expression: { + uint64_t RegNum = Data.getULEB128(C); + addInstruction(Opcode, RegNum, 0); + + uint64_t BlockLength = Data.getULEB128(C); + StringRef Expression = Data.getBytes(C, BlockLength); + DataExtractor Extractor(Expression, Data.isLittleEndian(), + Data.getAddressSize()); + // Note. We do not pass the DWARF format to DWARFExpression, because + // DW_OP_call_ref, the only operation which depends on the format, is + // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5. + Instructions.back().Expression = + DWARFExpression(Extractor, Data.getAddressSize()); + break; + } + } + } + + *Offset = C.tell(); + return C.takeError(); +} + +namespace { + + +} // end anonymous namespace + +ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() { + static OperandType OpTypes[DW_CFA_restore+1][2]; + static bool Initialized = false; + if (Initialized) { + return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1); + } + Initialized = true; + +#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \ + do { \ + OpTypes[OP][0] = OPTYPE0; \ + OpTypes[OP][1] = OPTYPE1; \ + } while (false) +#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None) +#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None) + + DECLARE_OP1(DW_CFA_set_loc, OT_Address); + DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset); + DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset); + DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); + DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); + DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); + DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); + DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); + DECLARE_OP1(DW_CFA_undefined, OT_Register); + DECLARE_OP1(DW_CFA_same_value, OT_Register); + DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset); + DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset); + DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register); + DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression); + DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression); + DECLARE_OP1(DW_CFA_restore, OT_Register); + DECLARE_OP1(DW_CFA_restore_extended, OT_Register); + DECLARE_OP0(DW_CFA_remember_state); + DECLARE_OP0(DW_CFA_restore_state); + DECLARE_OP0(DW_CFA_GNU_window_save); + DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset); + DECLARE_OP0(DW_CFA_nop); + +#undef DECLARE_OP0 +#undef DECLARE_OP1 +#undef DECLARE_OP2 + + return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1); +} + +/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand. void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI, bool IsEH, const Instruction &Instr, unsigned OperandIdx, uint64_t Operand) const { - assert(OperandIdx < 2); - uint8_t Opcode = Instr.Opcode; - OperandType Type = getOperandTypes()[Opcode][OperandIdx]; - - switch (Type) { - case OT_Unset: { - OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to"; - auto OpcodeName = CallFrameString(Opcode, Arch); - if (!OpcodeName.empty()) - OS << " " << OpcodeName; - else - OS << format(" Opcode %x", Opcode); - break; - } - case OT_None: - break; - case OT_Address: - OS << format(" %" PRIx64, Operand); - break; - case OT_Offset: - // The offsets are all encoded in a unsigned form, but in practice - // consumers use them signed. It's most certainly legacy due to - // the lack of signed variants in the first Dwarf standards. - OS << format(" %+" PRId64, int64_t(Operand)); - break; - case OT_FactoredCodeOffset: // Always Unsigned - if (CodeAlignmentFactor) - OS << format(" %" PRId64, Operand * CodeAlignmentFactor); - else - OS << format(" %" PRId64 "*code_alignment_factor" , Operand); - break; - case OT_SignedFactDataOffset: - if (DataAlignmentFactor) - OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor); - else - OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand)); - break; - case OT_UnsignedFactDataOffset: - if (DataAlignmentFactor) - OS << format(" %" PRId64, Operand * DataAlignmentFactor); - else - OS << format(" %" PRId64 "*data_alignment_factor" , Operand); - break; - case OT_Register: + assert(OperandIdx < 2); + uint8_t Opcode = Instr.Opcode; + OperandType Type = getOperandTypes()[Opcode][OperandIdx]; + + switch (Type) { + case OT_Unset: { + OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to"; + auto OpcodeName = CallFrameString(Opcode, Arch); + if (!OpcodeName.empty()) + OS << " " << OpcodeName; + else + OS << format(" Opcode %x", Opcode); + break; + } + case OT_None: + break; + case OT_Address: + OS << format(" %" PRIx64, Operand); + break; + case OT_Offset: + // The offsets are all encoded in a unsigned form, but in practice + // consumers use them signed. It's most certainly legacy due to + // the lack of signed variants in the first Dwarf standards. + OS << format(" %+" PRId64, int64_t(Operand)); + break; + case OT_FactoredCodeOffset: // Always Unsigned + if (CodeAlignmentFactor) + OS << format(" %" PRId64, Operand * CodeAlignmentFactor); + else + OS << format(" %" PRId64 "*code_alignment_factor" , Operand); + break; + case OT_SignedFactDataOffset: + if (DataAlignmentFactor) + OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor); + else + OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand)); + break; + case OT_UnsignedFactDataOffset: + if (DataAlignmentFactor) + OS << format(" %" PRId64, Operand * DataAlignmentFactor); + else + OS << format(" %" PRId64 "*data_alignment_factor" , Operand); + break; + case OT_Register: OS << ' '; printRegister(OS, MRI, IsEH, Operand); - break; - case OT_Expression: - assert(Instr.Expression && "missing DWARFExpression object"); - OS << " "; + break; + case OT_Expression: + assert(Instr.Expression && "missing DWARFExpression object"); + OS << " "; Instr.Expression->print(OS, DumpOpts, MRI, nullptr, IsEH); - break; - } -} - + break; + } +} + void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI, bool IsEH, - unsigned IndentLevel) const { - for (const auto &Instr : Instructions) { - uint8_t Opcode = Instr.Opcode; - if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) - Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; - OS.indent(2 * IndentLevel); - OS << CallFrameString(Opcode, Arch) << ":"; - for (unsigned i = 0; i < Instr.Ops.size(); ++i) + unsigned IndentLevel) const { + for (const auto &Instr : Instructions) { + uint8_t Opcode = Instr.Opcode; + if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) + Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK; + OS.indent(2 * IndentLevel); + OS << CallFrameString(Opcode, Arch) << ":"; + for (unsigned i = 0; i < Instr.Ops.size(); ++i) printOperand(OS, DumpOpts, MRI, IsEH, Instr, i, Instr.Ops[i]); - OS << '\n'; - } -} - -// Returns the CIE identifier to be used by the requested format. -// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5. -// For CIE ID in .eh_frame sections see -// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html -constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) { - if (IsEH) - return 0; - if (IsDWARF64) - return DW64_CIE_ID; - return DW_CIE_ID; -} - + OS << '\n'; + } +} + +// Returns the CIE identifier to be used by the requested format. +// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5. +// For CIE ID in .eh_frame sections see +// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) { + if (IsEH) + return 0; + if (IsDWARF64) + return DW64_CIE_ID; + return DW_CIE_ID; +} + void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI, bool IsEH) const { - // A CIE with a zero length is a terminator entry in the .eh_frame section. - if (IsEH && Length == 0) { - OS << format("%08" PRIx64, Offset) << " ZERO terminator\n"; - return; - } - - OS << format("%08" PRIx64, Offset) - << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length) - << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8, - getCIEId(IsDWARF64, IsEH)) - << " CIE\n" - << " Format: " << FormatString(IsDWARF64) << "\n" - << format(" Version: %d\n", Version) - << " Augmentation: \"" << Augmentation << "\"\n"; - if (Version >= 4) { - OS << format(" Address size: %u\n", (uint32_t)AddressSize); - OS << format(" Segment desc size: %u\n", - (uint32_t)SegmentDescriptorSize); - } - OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor); - OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor); - OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); - if (Personality) - OS << format(" Personality Address: %016" PRIx64 "\n", *Personality); - if (!AugmentationData.empty()) { - OS << " Augmentation data: "; - for (uint8_t Byte : AugmentationData) - OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf); - OS << "\n"; - } - OS << "\n"; + // A CIE with a zero length is a terminator entry in the .eh_frame section. + if (IsEH && Length == 0) { + OS << format("%08" PRIx64, Offset) << " ZERO terminator\n"; + return; + } + + OS << format("%08" PRIx64, Offset) + << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length) + << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8, + getCIEId(IsDWARF64, IsEH)) + << " CIE\n" + << " Format: " << FormatString(IsDWARF64) << "\n" + << format(" Version: %d\n", Version) + << " Augmentation: \"" << Augmentation << "\"\n"; + if (Version >= 4) { + OS << format(" Address size: %u\n", (uint32_t)AddressSize); + OS << format(" Segment desc size: %u\n", + (uint32_t)SegmentDescriptorSize); + } + OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor); + OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor); + OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister); + if (Personality) + OS << format(" Personality Address: %016" PRIx64 "\n", *Personality); + if (!AugmentationData.empty()) { + OS << " Augmentation data: "; + for (uint8_t Byte : AugmentationData) + OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf); + OS << "\n"; + } + OS << "\n"; CFIs.dump(OS, DumpOpts, MRI, IsEH); - OS << "\n"; -} - + OS << "\n"; +} + void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI, bool IsEH) const { - OS << format("%08" PRIx64, Offset) - << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length) - << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8, CIEPointer) - << " FDE cie="; - if (LinkedCIE) - OS << format("%08" PRIx64, LinkedCIE->getOffset()); - else - OS << "<invalid offset>"; - OS << format(" pc=%08" PRIx64 "...%08" PRIx64 "\n", InitialLocation, - InitialLocation + AddressRange); - OS << " Format: " << FormatString(IsDWARF64) << "\n"; - if (LSDAAddress) - OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress); + OS << format("%08" PRIx64, Offset) + << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length) + << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8, CIEPointer) + << " FDE cie="; + if (LinkedCIE) + OS << format("%08" PRIx64, LinkedCIE->getOffset()); + else + OS << "<invalid offset>"; + OS << format(" pc=%08" PRIx64 "...%08" PRIx64 "\n", InitialLocation, + InitialLocation + AddressRange); + OS << " Format: " << FormatString(IsDWARF64) << "\n"; + if (LSDAAddress) + OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress); CFIs.dump(OS, DumpOpts, MRI, IsEH); - OS << "\n"; -} - -DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch, - bool IsEH, uint64_t EHFrameAddress) - : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {} - -DWARFDebugFrame::~DWARFDebugFrame() = default; - -static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, - uint64_t Offset, int Length) { - errs() << "DUMP: "; - for (int i = 0; i < Length; ++i) { - uint8_t c = Data.getU8(&Offset); - errs().write_hex(c); errs() << " "; - } - errs() << "\n"; -} - -Error DWARFDebugFrame::parse(DWARFDataExtractor Data) { - uint64_t Offset = 0; - DenseMap<uint64_t, CIE *> CIEs; - - while (Data.isValidOffset(Offset)) { - uint64_t StartOffset = Offset; - - uint64_t Length; - DwarfFormat Format; - std::tie(Length, Format) = Data.getInitialLength(&Offset); - bool IsDWARF64 = Format == DWARF64; - - // If the Length is 0, then this CIE is a terminator. We add it because some - // dumper tools might need it to print something special for such entries - // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator"). - if (Length == 0) { - auto Cie = std::make_unique<CIE>( - IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0, - SmallString<8>(), 0, 0, None, None, Arch); - CIEs[StartOffset] = Cie.get(); - Entries.push_back(std::move(Cie)); - break; - } - - // At this point, Offset points to the next field after Length. - // Length is the structure size excluding itself. Compute an offset one - // past the end of the structure (needed to know how many instructions to - // read). - uint64_t StartStructureOffset = Offset; - uint64_t EndStructureOffset = Offset + Length; - - // The Id field's size depends on the DWARF format - Error Err = Error::success(); - uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset, - /*SectionIndex=*/nullptr, &Err); - if (Err) - return Err; - - if (Id == getCIEId(IsDWARF64, IsEH)) { - uint8_t Version = Data.getU8(&Offset); - const char *Augmentation = Data.getCStr(&Offset); - StringRef AugmentationString(Augmentation ? Augmentation : ""); - // TODO: we should provide a way to report a warning and continue dumping. - if (IsEH && Version != 1) - return createStringError(errc::not_supported, - "unsupported CIE version: %" PRIu8, Version); - - uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : - Data.getU8(&Offset); - Data.setAddressSize(AddressSize); - uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); - uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); - int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); - uint64_t ReturnAddressRegister = - Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset); - - // Parse the augmentation data for EH CIEs - StringRef AugmentationData(""); - uint32_t FDEPointerEncoding = DW_EH_PE_absptr; - uint32_t LSDAPointerEncoding = DW_EH_PE_omit; - Optional<uint64_t> Personality; - Optional<uint32_t> PersonalityEncoding; - if (IsEH) { - Optional<uint64_t> AugmentationLength; - uint64_t StartAugmentationOffset; - uint64_t EndAugmentationOffset; - - // Walk the augmentation string to get all the augmentation data. - for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { - switch (AugmentationString[i]) { - default: - return createStringError( - errc::invalid_argument, - "unknown augmentation character in entry at 0x%" PRIx64, - StartOffset); - case 'L': - LSDAPointerEncoding = Data.getU8(&Offset); - break; - case 'P': { - if (Personality) - return createStringError( - errc::invalid_argument, - "duplicate personality in entry at 0x%" PRIx64, StartOffset); - PersonalityEncoding = Data.getU8(&Offset); - Personality = Data.getEncodedPointer( - &Offset, *PersonalityEncoding, - EHFrameAddress ? EHFrameAddress + Offset : 0); - break; - } - case 'R': - FDEPointerEncoding = Data.getU8(&Offset); - break; - case 'S': - // Current frame is a signal trampoline. - break; - case 'z': - if (i) - return createStringError( - errc::invalid_argument, - "'z' must be the first character at 0x%" PRIx64, StartOffset); - // Parse the augmentation length first. We only parse it if - // the string contains a 'z'. - AugmentationLength = Data.getULEB128(&Offset); - StartAugmentationOffset = Offset; - EndAugmentationOffset = Offset + *AugmentationLength; - break; - case 'B': - // B-Key is used for signing functions associated with this - // augmentation string - break; - } - } - - if (AugmentationLength.hasValue()) { - if (Offset != EndAugmentationOffset) - return createStringError(errc::invalid_argument, - "parsing augmentation data at 0x%" PRIx64 - " failed", - StartOffset); - AugmentationData = Data.getData().slice(StartAugmentationOffset, - EndAugmentationOffset); - } - } - - auto Cie = std::make_unique<CIE>( - IsDWARF64, StartOffset, Length, Version, AugmentationString, - AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, - DataAlignmentFactor, ReturnAddressRegister, AugmentationData, - FDEPointerEncoding, LSDAPointerEncoding, Personality, - PersonalityEncoding, Arch); - CIEs[StartOffset] = Cie.get(); - Entries.emplace_back(std::move(Cie)); - } else { - // FDE - uint64_t CIEPointer = Id; - uint64_t InitialLocation = 0; - uint64_t AddressRange = 0; - Optional<uint64_t> LSDAAddress; - CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; - - if (IsEH) { - // The address size is encoded in the CIE we reference. - if (!Cie) - return createStringError(errc::invalid_argument, - "parsing FDE data at 0x%" PRIx64 - " failed due to missing CIE", - StartOffset); + OS << "\n"; +} + +DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch, + bool IsEH, uint64_t EHFrameAddress) + : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {} + +DWARFDebugFrame::~DWARFDebugFrame() = default; + +static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data, + uint64_t Offset, int Length) { + errs() << "DUMP: "; + for (int i = 0; i < Length; ++i) { + uint8_t c = Data.getU8(&Offset); + errs().write_hex(c); errs() << " "; + } + errs() << "\n"; +} + +Error DWARFDebugFrame::parse(DWARFDataExtractor Data) { + uint64_t Offset = 0; + DenseMap<uint64_t, CIE *> CIEs; + + while (Data.isValidOffset(Offset)) { + uint64_t StartOffset = Offset; + + uint64_t Length; + DwarfFormat Format; + std::tie(Length, Format) = Data.getInitialLength(&Offset); + bool IsDWARF64 = Format == DWARF64; + + // If the Length is 0, then this CIE is a terminator. We add it because some + // dumper tools might need it to print something special for such entries + // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator"). + if (Length == 0) { + auto Cie = std::make_unique<CIE>( + IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0, + SmallString<8>(), 0, 0, None, None, Arch); + CIEs[StartOffset] = Cie.get(); + Entries.push_back(std::move(Cie)); + break; + } + + // At this point, Offset points to the next field after Length. + // Length is the structure size excluding itself. Compute an offset one + // past the end of the structure (needed to know how many instructions to + // read). + uint64_t StartStructureOffset = Offset; + uint64_t EndStructureOffset = Offset + Length; + + // The Id field's size depends on the DWARF format + Error Err = Error::success(); + uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset, + /*SectionIndex=*/nullptr, &Err); + if (Err) + return Err; + + if (Id == getCIEId(IsDWARF64, IsEH)) { + uint8_t Version = Data.getU8(&Offset); + const char *Augmentation = Data.getCStr(&Offset); + StringRef AugmentationString(Augmentation ? Augmentation : ""); + // TODO: we should provide a way to report a warning and continue dumping. + if (IsEH && Version != 1) + return createStringError(errc::not_supported, + "unsupported CIE version: %" PRIu8, Version); + + uint8_t AddressSize = Version < 4 ? Data.getAddressSize() : + Data.getU8(&Offset); + Data.setAddressSize(AddressSize); + uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset); + uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset); + int64_t DataAlignmentFactor = Data.getSLEB128(&Offset); + uint64_t ReturnAddressRegister = + Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset); + + // Parse the augmentation data for EH CIEs + StringRef AugmentationData(""); + uint32_t FDEPointerEncoding = DW_EH_PE_absptr; + uint32_t LSDAPointerEncoding = DW_EH_PE_omit; + Optional<uint64_t> Personality; + Optional<uint32_t> PersonalityEncoding; + if (IsEH) { + Optional<uint64_t> AugmentationLength; + uint64_t StartAugmentationOffset; + uint64_t EndAugmentationOffset; + + // Walk the augmentation string to get all the augmentation data. + for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { + switch (AugmentationString[i]) { + default: + return createStringError( + errc::invalid_argument, + "unknown augmentation character in entry at 0x%" PRIx64, + StartOffset); + case 'L': + LSDAPointerEncoding = Data.getU8(&Offset); + break; + case 'P': { + if (Personality) + return createStringError( + errc::invalid_argument, + "duplicate personality in entry at 0x%" PRIx64, StartOffset); + PersonalityEncoding = Data.getU8(&Offset); + Personality = Data.getEncodedPointer( + &Offset, *PersonalityEncoding, + EHFrameAddress ? EHFrameAddress + Offset : 0); + break; + } + case 'R': + FDEPointerEncoding = Data.getU8(&Offset); + break; + case 'S': + // Current frame is a signal trampoline. + break; + case 'z': + if (i) + return createStringError( + errc::invalid_argument, + "'z' must be the first character at 0x%" PRIx64, StartOffset); + // Parse the augmentation length first. We only parse it if + // the string contains a 'z'. + AugmentationLength = Data.getULEB128(&Offset); + StartAugmentationOffset = Offset; + EndAugmentationOffset = Offset + *AugmentationLength; + break; + case 'B': + // B-Key is used for signing functions associated with this + // augmentation string + break; + } + } + + if (AugmentationLength.hasValue()) { + if (Offset != EndAugmentationOffset) + return createStringError(errc::invalid_argument, + "parsing augmentation data at 0x%" PRIx64 + " failed", + StartOffset); + AugmentationData = Data.getData().slice(StartAugmentationOffset, + EndAugmentationOffset); + } + } + + auto Cie = std::make_unique<CIE>( + IsDWARF64, StartOffset, Length, Version, AugmentationString, + AddressSize, SegmentDescriptorSize, CodeAlignmentFactor, + DataAlignmentFactor, ReturnAddressRegister, AugmentationData, + FDEPointerEncoding, LSDAPointerEncoding, Personality, + PersonalityEncoding, Arch); + CIEs[StartOffset] = Cie.get(); + Entries.emplace_back(std::move(Cie)); + } else { + // FDE + uint64_t CIEPointer = Id; + uint64_t InitialLocation = 0; + uint64_t AddressRange = 0; + Optional<uint64_t> LSDAAddress; + CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer]; + + if (IsEH) { + // The address size is encoded in the CIE we reference. + if (!Cie) + return createStringError(errc::invalid_argument, + "parsing FDE data at 0x%" PRIx64 + " failed due to missing CIE", + StartOffset); if (auto Val = Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(), EHFrameAddress + Offset)) { - InitialLocation = *Val; - } - if (auto Val = Data.getEncodedPointer( - &Offset, Cie->getFDEPointerEncoding(), 0)) { - AddressRange = *Val; - } - - StringRef AugmentationString = Cie->getAugmentationString(); - if (!AugmentationString.empty()) { - // Parse the augmentation length and data for this FDE. - uint64_t AugmentationLength = Data.getULEB128(&Offset); - - uint64_t EndAugmentationOffset = Offset + AugmentationLength; - - // Decode the LSDA if the CIE augmentation string said we should. - if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) { - LSDAAddress = Data.getEncodedPointer( - &Offset, Cie->getLSDAPointerEncoding(), - EHFrameAddress ? Offset + EHFrameAddress : 0); - } - - if (Offset != EndAugmentationOffset) - return createStringError(errc::invalid_argument, - "parsing augmentation data at 0x%" PRIx64 - " failed", - StartOffset); - } - } else { - InitialLocation = Data.getRelocatedAddress(&Offset); - AddressRange = Data.getRelocatedAddress(&Offset); - } - - Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer, - InitialLocation, AddressRange, Cie, - LSDAAddress, Arch)); - } - - if (Error E = - Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) - return E; - - if (Offset != EndStructureOffset) - return createStringError( - errc::invalid_argument, - "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset); - } - - return Error::success(); -} - -FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const { - auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) { - return E->getOffset() < Offset; - }); - if (It != Entries.end() && (*It)->getOffset() == Offset) - return It->get(); - return nullptr; -} - + InitialLocation = *Val; + } + if (auto Val = Data.getEncodedPointer( + &Offset, Cie->getFDEPointerEncoding(), 0)) { + AddressRange = *Val; + } + + StringRef AugmentationString = Cie->getAugmentationString(); + if (!AugmentationString.empty()) { + // Parse the augmentation length and data for this FDE. + uint64_t AugmentationLength = Data.getULEB128(&Offset); + + uint64_t EndAugmentationOffset = Offset + AugmentationLength; + + // Decode the LSDA if the CIE augmentation string said we should. + if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) { + LSDAAddress = Data.getEncodedPointer( + &Offset, Cie->getLSDAPointerEncoding(), + EHFrameAddress ? Offset + EHFrameAddress : 0); + } + + if (Offset != EndAugmentationOffset) + return createStringError(errc::invalid_argument, + "parsing augmentation data at 0x%" PRIx64 + " failed", + StartOffset); + } + } else { + InitialLocation = Data.getRelocatedAddress(&Offset); + AddressRange = Data.getRelocatedAddress(&Offset); + } + + Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer, + InitialLocation, AddressRange, Cie, + LSDAAddress, Arch)); + } + + if (Error E = + Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) + return E; + + if (Offset != EndStructureOffset) + return createStringError( + errc::invalid_argument, + "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset); + } + + return Error::success(); +} + +FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const { + auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) { + return E->getOffset() < Offset; + }); + if (It != Entries.end() && (*It)->getOffset() == Offset) + return It->get(); + return nullptr; +} + void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *MRI, - Optional<uint64_t> Offset) const { - if (Offset) { - if (auto *Entry = getEntryAtOffset(*Offset)) + Optional<uint64_t> Offset) const { + if (Offset) { + if (auto *Entry = getEntryAtOffset(*Offset)) Entry->dump(OS, DumpOpts, MRI, IsEH); - return; - } - - OS << "\n"; - for (const auto &Entry : Entries) + return; + } + + OS << "\n"; + for (const auto &Entry : Entries) Entry->dump(OS, DumpOpts, MRI, IsEH); -} +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index 2b7d0c3363..b72c5071ea 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -1,70 +1,70 @@ -//===- DWARFDebugInfoEntry.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" -#include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/DataExtractor.h" -#include <cstddef> -#include <cstdint> - -using namespace llvm; -using namespace dwarf; - -bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, - uint64_t *OffsetPtr) { - DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); - const uint64_t UEndOffset = U.getNextUnitOffset(); - return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0); -} - -bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr, - const DWARFDataExtractor &DebugInfoData, - uint64_t UEndOffset, uint32_t D) { - Offset = *OffsetPtr; - Depth = D; - if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset)) - return false; - uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); - if (0 == AbbrCode) { - // NULL debug tag entry. - AbbrevDecl = nullptr; - return true; - } +//===- DWARFDebugInfoEntry.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/DataExtractor.h" +#include <cstddef> +#include <cstdint> + +using namespace llvm; +using namespace dwarf; + +bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, + uint64_t *OffsetPtr) { + DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor(); + const uint64_t UEndOffset = U.getNextUnitOffset(); + return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0); +} + +bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr, + const DWARFDataExtractor &DebugInfoData, + uint64_t UEndOffset, uint32_t D) { + Offset = *OffsetPtr; + Depth = D; + if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset)) + return false; + uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr); + if (0 == AbbrCode) { + // NULL debug tag entry. + AbbrevDecl = nullptr; + return true; + } if (const auto *AbbrevSet = U.getAbbreviations()) AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode); - if (nullptr == AbbrevDecl) { - // Restore the original offset. - *OffsetPtr = Offset; - return false; - } - // 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()) { - // 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.getFormParams())) { - // We failed to skip this attribute's value, restore the original offset - // and return the failure status. - *OffsetPtr = Offset; - return false; - } - } - return true; -} + if (nullptr == AbbrevDecl) { + // Restore the original offset. + *OffsetPtr = Offset; + return false; + } + // 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()) { + // 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.getFormParams())) { + // We failed to skip this attribute's value, restore the original offset + // and return the failure status. + *OffsetPtr = Offset; + return false; + } + } + return true; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index bda41b1f34..34c5256488 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -1,84 +1,84 @@ -//===- DWARFDebugLine.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cinttypes> -#include <cstdint> -#include <cstdio> -#include <utility> - -using namespace llvm; -using namespace dwarf; - -using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; - -namespace { - -struct ContentDescriptor { - dwarf::LineNumberEntryFormat Type; - dwarf::Form Form; -}; - -using ContentDescriptors = SmallVector<ContentDescriptor, 4>; - -} // end anonymous namespace - -static bool versionIsSupported(uint16_t Version) { - return Version >= 2 && Version <= 5; -} - -void DWARFDebugLine::ContentTypeTracker::trackContentType( - dwarf::LineNumberEntryFormat ContentType) { - switch (ContentType) { - case dwarf::DW_LNCT_timestamp: - HasModTime = true; - break; - case dwarf::DW_LNCT_size: - HasLength = true; - break; - case dwarf::DW_LNCT_MD5: - HasMD5 = true; - break; - case dwarf::DW_LNCT_LLVM_source: - HasSource = true; - break; - default: - // We only care about values we consider optional, and new values may be - // added in the vendor extension range, so we do not match exhaustively. - break; - } -} - -DWARFDebugLine::Prologue::Prologue() { clear(); } - -bool DWARFDebugLine::Prologue::hasFileAtIndex(uint64_t FileIndex) const { - uint16_t DwarfVersion = getVersion(); - assert(DwarfVersion != 0 && - "line table prologue has no dwarf version information"); - if (DwarfVersion >= 5) - return FileIndex < FileNames.size(); - return FileIndex != 0 && FileIndex <= FileNames.size(); -} - +//===- DWARFDebugLine.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstdio> +#include <utility> + +using namespace llvm; +using namespace dwarf; + +using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; + +namespace { + +struct ContentDescriptor { + dwarf::LineNumberEntryFormat Type; + dwarf::Form Form; +}; + +using ContentDescriptors = SmallVector<ContentDescriptor, 4>; + +} // end anonymous namespace + +static bool versionIsSupported(uint16_t Version) { + return Version >= 2 && Version <= 5; +} + +void DWARFDebugLine::ContentTypeTracker::trackContentType( + dwarf::LineNumberEntryFormat ContentType) { + switch (ContentType) { + case dwarf::DW_LNCT_timestamp: + HasModTime = true; + break; + case dwarf::DW_LNCT_size: + HasLength = true; + break; + case dwarf::DW_LNCT_MD5: + HasMD5 = true; + break; + case dwarf::DW_LNCT_LLVM_source: + HasSource = true; + break; + default: + // We only care about values we consider optional, and new values may be + // added in the vendor extension range, so we do not match exhaustively. + break; + } +} + +DWARFDebugLine::Prologue::Prologue() { clear(); } + +bool DWARFDebugLine::Prologue::hasFileAtIndex(uint64_t FileIndex) const { + uint16_t DwarfVersion = getVersion(); + assert(DwarfVersion != 0 && + "line table prologue has no dwarf version information"); + if (DwarfVersion >= 5) + return FileIndex < FileNames.size(); + return FileIndex != 0 && FileIndex <= FileNames.size(); +} + Optional<uint64_t> DWARFDebugLine::Prologue::getLastValidFileIndex() const { if (FileNames.empty()) return None; @@ -91,698 +91,698 @@ Optional<uint64_t> DWARFDebugLine::Prologue::getLastValidFileIndex() const { return FileNames.size(); } -const llvm::DWARFDebugLine::FileNameEntry & -DWARFDebugLine::Prologue::getFileNameEntry(uint64_t Index) const { - uint16_t DwarfVersion = getVersion(); - assert(DwarfVersion != 0 && - "line table prologue has no dwarf version information"); - // In DWARF v5 the file names are 0-indexed. - if (DwarfVersion >= 5) - return FileNames[Index]; - return FileNames[Index - 1]; -} - -void DWARFDebugLine::Prologue::clear() { - TotalLength = PrologueLength = 0; - SegSelectorSize = 0; - MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; - OpcodeBase = 0; - FormParams = dwarf::FormParams({0, 0, DWARF32}); - ContentTypes = ContentTypeTracker(); - StandardOpcodeLengths.clear(); - IncludeDirectories.clear(); - FileNames.clear(); -} - -void DWARFDebugLine::Prologue::dump(raw_ostream &OS, - DIDumpOptions DumpOptions) const { - if (!totalLengthIsValid()) - return; - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(FormParams.Format); - OS << "Line table prologue:\n" - << format(" total_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth, - TotalLength) - << " format: " << dwarf::FormatString(FormParams.Format) << "\n" - << format(" version: %u\n", getVersion()); - if (!versionIsSupported(getVersion())) - return; - if (getVersion() >= 5) - OS << format(" address_size: %u\n", getAddressSize()) - << format(" seg_select_size: %u\n", SegSelectorSize); - OS << format(" prologue_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth, - PrologueLength) - << format(" min_inst_length: %u\n", MinInstLength) - << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) - << format(" default_is_stmt: %u\n", DefaultIsStmt) - << format(" line_base: %i\n", LineBase) - << format(" line_range: %u\n", LineRange) - << format(" opcode_base: %u\n", OpcodeBase); - - for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I) - OS << formatv("standard_opcode_lengths[{0}] = {1}\n", - static_cast<dwarf::LineNumberOps>(I + 1), - StandardOpcodeLengths[I]); - - if (!IncludeDirectories.empty()) { - // DWARF v5 starts directory indexes at 0. - uint32_t DirBase = getVersion() >= 5 ? 0 : 1; - for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) { - OS << format("include_directories[%3u] = ", I + DirBase); - IncludeDirectories[I].dump(OS, DumpOptions); - OS << '\n'; - } - } - - if (!FileNames.empty()) { - // DWARF v5 starts file indexes at 0. - uint32_t FileBase = getVersion() >= 5 ? 0 : 1; - for (uint32_t I = 0; I != FileNames.size(); ++I) { - const FileNameEntry &FileEntry = FileNames[I]; - OS << format("file_names[%3u]:\n", I + FileBase); - OS << " name: "; - FileEntry.Name.dump(OS, DumpOptions); - OS << '\n' - << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx); - if (ContentTypes.HasMD5) - OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n'; - if (ContentTypes.HasModTime) - OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime); - if (ContentTypes.HasLength) - OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length); - if (ContentTypes.HasSource) { - OS << " source: "; - FileEntry.Source.dump(OS, DumpOptions); - OS << '\n'; - } - } - } -} - -// Parse v2-v4 directory and file tables. -static Error -parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, - uint64_t *OffsetPtr, - DWARFDebugLine::ContentTypeTracker &ContentTypes, - std::vector<DWARFFormValue> &IncludeDirectories, - std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { - while (true) { - Error Err = Error::success(); - StringRef S = DebugLineData.getCStrRef(OffsetPtr, &Err); - if (Err) { - consumeError(std::move(Err)); - return createStringError(errc::invalid_argument, - "include directories table was not null " - "terminated before the end of the prologue"); - } - if (S.empty()) - break; - DWARFFormValue Dir = - DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, S.data()); - IncludeDirectories.push_back(Dir); - } - - ContentTypes.HasModTime = true; - ContentTypes.HasLength = true; - - while (true) { - Error Err = Error::success(); - StringRef Name = DebugLineData.getCStrRef(OffsetPtr, &Err); - if (!Err && Name.empty()) - break; - - DWARFDebugLine::FileNameEntry FileEntry; - FileEntry.Name = - DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data()); - FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr, &Err); - FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr, &Err); - FileEntry.Length = DebugLineData.getULEB128(OffsetPtr, &Err); - - if (Err) { - consumeError(std::move(Err)); - return createStringError( - errc::invalid_argument, - "file names table was not null terminated before " - "the end of the prologue"); - } - FileNames.push_back(FileEntry); - } - - return Error::success(); -} - -// Parse v5 directory/file entry content descriptions. -// Returns the descriptors, or an error if we did not find a path or ran off -// the end of the prologue. -static llvm::Expected<ContentDescriptors> -parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, - DWARFDebugLine::ContentTypeTracker *ContentTypes) { - Error Err = Error::success(); - ContentDescriptors Descriptors; - int FormatCount = DebugLineData.getU8(OffsetPtr, &Err); - bool HasPath = false; - for (int I = 0; I != FormatCount && !Err; ++I) { - ContentDescriptor Descriptor; - Descriptor.Type = - dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr, &Err)); - Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr, &Err)); - if (Descriptor.Type == dwarf::DW_LNCT_path) - HasPath = true; - if (ContentTypes) - ContentTypes->trackContentType(Descriptor.Type); - Descriptors.push_back(Descriptor); - } - - if (Err) - return createStringError(errc::invalid_argument, - "failed to parse entry content descriptors: %s", - toString(std::move(Err)).c_str()); - - if (!HasPath) - return createStringError(errc::invalid_argument, - "failed to parse entry content descriptions" - " because no path was found"); - return Descriptors; -} - -static Error -parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, - uint64_t *OffsetPtr, const dwarf::FormParams &FormParams, - const DWARFContext &Ctx, const DWARFUnit *U, - DWARFDebugLine::ContentTypeTracker &ContentTypes, - std::vector<DWARFFormValue> &IncludeDirectories, - std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { - // Get the directory entry description. - llvm::Expected<ContentDescriptors> DirDescriptors = - parseV5EntryFormat(DebugLineData, OffsetPtr, nullptr); - if (!DirDescriptors) - return DirDescriptors.takeError(); - - // Get the directory entries, according to the format described above. - uint64_t DirEntryCount = DebugLineData.getULEB128(OffsetPtr); - for (uint64_t I = 0; I != DirEntryCount; ++I) { - for (auto Descriptor : *DirDescriptors) { - DWARFFormValue Value(Descriptor.Form); - switch (Descriptor.Type) { - case DW_LNCT_path: - if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) - return createStringError(errc::invalid_argument, - "failed to parse directory entry because " - "extracting the form value failed"); - IncludeDirectories.push_back(Value); - break; - default: - if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams)) - return createStringError(errc::invalid_argument, - "failed to parse directory entry because " - "skipping the form value failed"); - } - } - } - - // Get the file entry description. - llvm::Expected<ContentDescriptors> FileDescriptors = - parseV5EntryFormat(DebugLineData, OffsetPtr, &ContentTypes); - if (!FileDescriptors) - return FileDescriptors.takeError(); - - // Get the file entries, according to the format described above. - uint64_t FileEntryCount = DebugLineData.getULEB128(OffsetPtr); - for (uint64_t I = 0; I != FileEntryCount; ++I) { - DWARFDebugLine::FileNameEntry FileEntry; - for (auto Descriptor : *FileDescriptors) { - DWARFFormValue Value(Descriptor.Form); - if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) - return createStringError(errc::invalid_argument, - "failed to parse file entry because " - "extracting the form value failed"); - switch (Descriptor.Type) { - case DW_LNCT_path: - FileEntry.Name = Value; - break; - case DW_LNCT_LLVM_source: - FileEntry.Source = Value; - break; - case DW_LNCT_directory_index: - FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue(); - break; - case DW_LNCT_timestamp: - FileEntry.ModTime = Value.getAsUnsignedConstant().getValue(); - break; - case DW_LNCT_size: - FileEntry.Length = Value.getAsUnsignedConstant().getValue(); - break; - case DW_LNCT_MD5: - if (!Value.getAsBlock() || Value.getAsBlock().getValue().size() != 16) - return createStringError( - errc::invalid_argument, - "failed to parse file entry because the MD5 hash is invalid"); - std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16, - FileEntry.Checksum.Bytes.begin()); - break; - default: - break; - } - } - FileNames.push_back(FileEntry); - } - return Error::success(); -} - -uint64_t DWARFDebugLine::Prologue::getLength() const { - uint64_t Length = PrologueLength + sizeofTotalLength() + - sizeof(getVersion()) + sizeofPrologueLength(); - if (getVersion() >= 5) - Length += 2; // Address + Segment selector sizes. - return Length; -} - -Error DWARFDebugLine::Prologue::parse( - DWARFDataExtractor DebugLineData, uint64_t *OffsetPtr, - function_ref<void(Error)> RecoverableErrorHandler, const DWARFContext &Ctx, - const DWARFUnit *U) { - const uint64_t PrologueOffset = *OffsetPtr; - - clear(); - DataExtractor::Cursor Cursor(*OffsetPtr); - std::tie(TotalLength, FormParams.Format) = - DebugLineData.getInitialLength(Cursor); - - DebugLineData = - DWARFDataExtractor(DebugLineData, Cursor.tell() + TotalLength); - FormParams.Version = DebugLineData.getU16(Cursor); - if (Cursor && !versionIsSupported(getVersion())) { - // Treat this error as unrecoverable - we cannot be sure what any of - // the data represents including the length field, so cannot skip it or make - // any reasonable assumptions. - *OffsetPtr = Cursor.tell(); - return createStringError( - errc::not_supported, - "parsing line table prologue at offset 0x%8.8" PRIx64 - ": unsupported version %" PRIu16, - PrologueOffset, getVersion()); - } - - if (getVersion() >= 5) { - FormParams.AddrSize = DebugLineData.getU8(Cursor); - assert((!Cursor || DebugLineData.getAddressSize() == 0 || - DebugLineData.getAddressSize() == getAddressSize()) && - "Line table header and data extractor disagree"); - SegSelectorSize = DebugLineData.getU8(Cursor); - } - - PrologueLength = - DebugLineData.getRelocatedValue(Cursor, sizeofPrologueLength()); - const uint64_t EndPrologueOffset = PrologueLength + Cursor.tell(); - DebugLineData = DWARFDataExtractor(DebugLineData, EndPrologueOffset); - MinInstLength = DebugLineData.getU8(Cursor); - if (getVersion() >= 4) - MaxOpsPerInst = DebugLineData.getU8(Cursor); - DefaultIsStmt = DebugLineData.getU8(Cursor); - LineBase = DebugLineData.getU8(Cursor); - LineRange = DebugLineData.getU8(Cursor); - OpcodeBase = DebugLineData.getU8(Cursor); - - if (Cursor && OpcodeBase == 0) { - // If the opcode base is 0, we cannot read the standard opcode lengths (of - // which there are supposed to be one fewer than the opcode base). Assume - // there are no standard opcodes and continue parsing. - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "parsing line table prologue at offset 0x%8.8" PRIx64 - " found opcode base of 0. Assuming no standard opcodes", - PrologueOffset)); - } else if (Cursor) { - StandardOpcodeLengths.reserve(OpcodeBase - 1); - for (uint32_t I = 1; I < OpcodeBase; ++I) { - uint8_t OpLen = DebugLineData.getU8(Cursor); - StandardOpcodeLengths.push_back(OpLen); - } - } - - *OffsetPtr = Cursor.tell(); - // A corrupt file name or directory table does not prevent interpretation of - // the main line program, so check the cursor state now so that its errors can - // be handled separately. - if (!Cursor) - return createStringError( - errc::invalid_argument, - "parsing line table prologue at offset 0x%8.8" PRIx64 ": %s", - PrologueOffset, toString(Cursor.takeError()).c_str()); - - Error E = - getVersion() >= 5 - ? parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U, - ContentTypes, IncludeDirectories, FileNames) - : parseV2DirFileTables(DebugLineData, OffsetPtr, ContentTypes, - IncludeDirectories, FileNames); - if (E) { - RecoverableErrorHandler(joinErrors( - createStringError( - errc::invalid_argument, - "parsing line table prologue at 0x%8.8" PRIx64 - " found an invalid directory or file table description at" - " 0x%8.8" PRIx64, - PrologueOffset, *OffsetPtr), - std::move(E))); - return Error::success(); - } - - assert(*OffsetPtr <= EndPrologueOffset); - if (*OffsetPtr != EndPrologueOffset) { - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "unknown data in line table prologue at offset 0x%8.8" PRIx64 - ": parsing ended (at offset 0x%8.8" PRIx64 - ") before reaching the prologue end at offset 0x%8.8" PRIx64, - PrologueOffset, *OffsetPtr, EndPrologueOffset)); - } - return Error::success(); -} - -DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); } - -void DWARFDebugLine::Row::postAppend() { - Discriminator = 0; - BasicBlock = false; - PrologueEnd = false; - EpilogueBegin = false; -} - -void DWARFDebugLine::Row::reset(bool DefaultIsStmt) { - Address.Address = 0; - Address.SectionIndex = object::SectionedAddress::UndefSection; - Line = 1; - Column = 0; - File = 1; - Isa = 0; - Discriminator = 0; - IsStmt = DefaultIsStmt; - BasicBlock = false; - EndSequence = false; - PrologueEnd = false; - EpilogueBegin = false; -} - -void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS, unsigned Indent) { - OS.indent(Indent) - << "Address Line Column File ISA Discriminator Flags\n"; - OS.indent(Indent) - << "------------------ ------ ------ ------ --- ------------- " - "-------------\n"; -} - -void DWARFDebugLine::Row::dump(raw_ostream &OS) const { - OS << format("0x%16.16" PRIx64 " %6u %6u", Address.Address, Line, Column) - << format(" %6u %3u %13u ", File, Isa, Discriminator) - << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "") - << (PrologueEnd ? " prologue_end" : "") - << (EpilogueBegin ? " epilogue_begin" : "") - << (EndSequence ? " end_sequence" : "") << '\n'; -} - -DWARFDebugLine::Sequence::Sequence() { reset(); } - -void DWARFDebugLine::Sequence::reset() { - LowPC = 0; - HighPC = 0; - SectionIndex = object::SectionedAddress::UndefSection; - FirstRowIndex = 0; - LastRowIndex = 0; - Empty = true; -} - -DWARFDebugLine::LineTable::LineTable() { clear(); } - -void DWARFDebugLine::LineTable::dump(raw_ostream &OS, - DIDumpOptions DumpOptions) const { - Prologue.dump(OS, DumpOptions); - - if (!Rows.empty()) { - OS << '\n'; - Row::dumpTableHeader(OS, 0); - for (const Row &R : Rows) { - R.dump(OS); - } - } - - // Terminate the table with a final blank line to clearly delineate it from - // later dumps. - OS << '\n'; -} - -void DWARFDebugLine::LineTable::clear() { - Prologue.clear(); - Rows.clear(); - Sequences.clear(); -} - -DWARFDebugLine::ParsingState::ParsingState( - struct LineTable *LT, uint64_t TableOffset, - function_ref<void(Error)> ErrorHandler) - : LineTable(LT), LineTableOffset(TableOffset), ErrorHandler(ErrorHandler) { - resetRowAndSequence(); -} - -void DWARFDebugLine::ParsingState::resetRowAndSequence() { - Row.reset(LineTable->Prologue.DefaultIsStmt); - Sequence.reset(); -} - -void DWARFDebugLine::ParsingState::appendRowToMatrix() { - unsigned RowNumber = LineTable->Rows.size(); - if (Sequence.Empty) { - // Record the beginning of instruction sequence. - Sequence.Empty = false; - Sequence.LowPC = Row.Address.Address; - Sequence.FirstRowIndex = RowNumber; - } - LineTable->appendRow(Row); - if (Row.EndSequence) { - // Record the end of instruction sequence. - Sequence.HighPC = Row.Address.Address; - Sequence.LastRowIndex = RowNumber + 1; - Sequence.SectionIndex = Row.Address.SectionIndex; - if (Sequence.isValid()) - LineTable->appendSequence(Sequence); - Sequence.reset(); - } - Row.postAppend(); -} - -const DWARFDebugLine::LineTable * -DWARFDebugLine::getLineTable(uint64_t Offset) const { - LineTableConstIter Pos = LineTableMap.find(Offset); - if (Pos != LineTableMap.end()) - return &Pos->second; - return nullptr; -} - -Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable( - DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx, - const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) { - if (!DebugLineData.isValidOffset(Offset)) - return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64 - " is not a valid debug line section offset", - Offset); - - std::pair<LineTableIter, bool> Pos = - LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); - LineTable *LT = &Pos.first->second; - if (Pos.second) { - if (Error Err = - LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorHandler)) - return std::move(Err); - return LT; - } - return LT; -} - -static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) { - assert(Opcode != 0); - if (Opcode < OpcodeBase) - return LNStandardString(Opcode); - return "special"; -} - -uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance, - uint8_t Opcode, - uint64_t OpcodeOffset) { - StringRef OpcodeName = getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase); - // For versions less than 4, the MaxOpsPerInst member is set to 0, as the - // maximum_operations_per_instruction field wasn't introduced until DWARFv4. - // Don't warn about bad values in this situation. - if (ReportAdvanceAddrProblem && LineTable->Prologue.getVersion() >= 4 && - LineTable->Prologue.MaxOpsPerInst != 1) - ErrorHandler(createStringError( - errc::not_supported, - "line table program at offset 0x%8.8" PRIx64 - " contains a %s opcode at offset 0x%8.8" PRIx64 - ", but the prologue maximum_operations_per_instruction value is %" PRId8 - ", which is unsupported. Assuming a value of 1 instead", - LineTableOffset, OpcodeName.data(), OpcodeOffset, - LineTable->Prologue.MaxOpsPerInst)); - if (ReportAdvanceAddrProblem && LineTable->Prologue.MinInstLength == 0) - ErrorHandler( - createStringError(errc::invalid_argument, - "line table program at offset 0x%8.8" PRIx64 - " contains a %s opcode at offset 0x%8.8" PRIx64 - ", but the prologue minimum_instruction_length value " - "is 0, which prevents any address advancing", - LineTableOffset, OpcodeName.data(), OpcodeOffset)); - ReportAdvanceAddrProblem = false; - uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength; - Row.Address.Address += AddrOffset; - return AddrOffset; -} - -DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode -DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode, - uint64_t OpcodeOffset) { - assert(Opcode == DW_LNS_const_add_pc || - Opcode >= LineTable->Prologue.OpcodeBase); - if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) { - StringRef OpcodeName = - getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase); - ErrorHandler( - createStringError(errc::not_supported, - "line table program at offset 0x%8.8" PRIx64 - " contains a %s opcode at offset 0x%8.8" PRIx64 - ", but the prologue line_range value is 0. The " - "address and line will not be adjusted", - LineTableOffset, OpcodeName.data(), OpcodeOffset)); - ReportBadLineRange = false; - } - - uint8_t OpcodeValue = Opcode; - if (Opcode == DW_LNS_const_add_pc) - OpcodeValue = 255; - uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase; - uint64_t OperationAdvance = - LineTable->Prologue.LineRange != 0 - ? AdjustedOpcode / LineTable->Prologue.LineRange - : 0; - uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset); - return {AddrOffset, AdjustedOpcode}; -} - -DWARFDebugLine::ParsingState::AddrAndLineDelta -DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode, - uint64_t OpcodeOffset) { - // A special opcode value is chosen based on the amount that needs - // to be added to the line and address registers. The maximum line - // increment for a special opcode is the value of the line_base - // field in the header, plus the value of the line_range field, - // minus 1 (line base + line range - 1). If the desired line - // increment is greater than the maximum line increment, a standard - // opcode must be used instead of a special opcode. The "address - // advance" is calculated by dividing the desired address increment - // by the minimum_instruction_length field from the header. The - // special opcode is then calculated using the following formula: - // - // opcode = (desired line increment - line_base) + - // (line_range * address advance) + opcode_base - // - // If the resulting opcode is greater than 255, a standard opcode - // must be used instead. - // - // To decode a special opcode, subtract the opcode_base from the - // opcode itself to give the adjusted opcode. The amount to - // increment the address register is the result of the adjusted - // opcode divided by the line_range multiplied by the - // minimum_instruction_length field from the header. That is: - // - // address increment = (adjusted opcode / line_range) * - // minimum_instruction_length - // - // The amount to increment the line register is the line_base plus - // the result of the adjusted opcode modulo the line_range. That is: - // - // line increment = line_base + (adjusted opcode % line_range) - - DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult = - advanceAddrForOpcode(Opcode, OpcodeOffset); - int32_t LineOffset = 0; - if (LineTable->Prologue.LineRange != 0) - LineOffset = - LineTable->Prologue.LineBase + - (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange); - Row.Line += LineOffset; - return {AddrAdvanceResult.AddrDelta, LineOffset}; -} - -/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on -/// success, or None if \p Cursor is in a failing state. -template <typename T> -static Optional<T> parseULEB128(DWARFDataExtractor &Data, - DataExtractor::Cursor &Cursor) { - T Value = Data.getULEB128(Cursor); - if (Cursor) - return Value; - return None; -} - -Error DWARFDebugLine::LineTable::parse( - DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, - const DWARFContext &Ctx, const DWARFUnit *U, - function_ref<void(Error)> RecoverableErrorHandler, raw_ostream *OS, - bool Verbose) { - assert((OS || !Verbose) && "cannot have verbose output without stream"); - const uint64_t DebugLineOffset = *OffsetPtr; - - clear(); - - Error PrologueErr = - Prologue.parse(DebugLineData, OffsetPtr, RecoverableErrorHandler, Ctx, U); - - if (OS) { - DIDumpOptions DumpOptions; - DumpOptions.Verbose = Verbose; - Prologue.dump(*OS, DumpOptions); - } - - if (PrologueErr) { - // Ensure there is a blank line after the prologue to clearly delineate it - // from later dumps. - if (OS) - *OS << "\n"; - return PrologueErr; - } - - uint64_t ProgramLength = Prologue.TotalLength + Prologue.sizeofTotalLength(); - if (!DebugLineData.isValidOffsetForDataOfSize(DebugLineOffset, - ProgramLength)) { - assert(DebugLineData.size() > DebugLineOffset && - "prologue parsing should handle invalid offset"); - uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset; - RecoverableErrorHandler( - createStringError(errc::invalid_argument, - "line table program with offset 0x%8.8" PRIx64 - " has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64 - " bytes are available", - DebugLineOffset, ProgramLength, BytesRemaining)); - // Continue by capping the length at the number of remaining bytes. - ProgramLength = BytesRemaining; - } - - // Create a DataExtractor which can only see the data up to the end of the - // table, to prevent reading past the end. - const uint64_t EndOffset = DebugLineOffset + ProgramLength; - DWARFDataExtractor TableData(DebugLineData, EndOffset); - - // See if we should tell the data extractor the address size. - if (TableData.getAddressSize() == 0) - TableData.setAddressSize(Prologue.getAddressSize()); - else - assert(Prologue.getAddressSize() == 0 || - Prologue.getAddressSize() == TableData.getAddressSize()); - - ParsingState State(this, DebugLineOffset, RecoverableErrorHandler); - - *OffsetPtr = DebugLineOffset + Prologue.getLength(); - if (OS && *OffsetPtr < EndOffset) { - *OS << '\n'; - Row::dumpTableHeader(*OS, /*Indent=*/Verbose ? 12 : 0); - } +const llvm::DWARFDebugLine::FileNameEntry & +DWARFDebugLine::Prologue::getFileNameEntry(uint64_t Index) const { + uint16_t DwarfVersion = getVersion(); + assert(DwarfVersion != 0 && + "line table prologue has no dwarf version information"); + // In DWARF v5 the file names are 0-indexed. + if (DwarfVersion >= 5) + return FileNames[Index]; + return FileNames[Index - 1]; +} + +void DWARFDebugLine::Prologue::clear() { + TotalLength = PrologueLength = 0; + SegSelectorSize = 0; + MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; + OpcodeBase = 0; + FormParams = dwarf::FormParams({0, 0, DWARF32}); + ContentTypes = ContentTypeTracker(); + StandardOpcodeLengths.clear(); + IncludeDirectories.clear(); + FileNames.clear(); +} + +void DWARFDebugLine::Prologue::dump(raw_ostream &OS, + DIDumpOptions DumpOptions) const { + if (!totalLengthIsValid()) + return; + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(FormParams.Format); + OS << "Line table prologue:\n" + << format(" total_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth, + TotalLength) + << " format: " << dwarf::FormatString(FormParams.Format) << "\n" + << format(" version: %u\n", getVersion()); + if (!versionIsSupported(getVersion())) + return; + if (getVersion() >= 5) + OS << format(" address_size: %u\n", getAddressSize()) + << format(" seg_select_size: %u\n", SegSelectorSize); + OS << format(" prologue_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth, + PrologueLength) + << format(" min_inst_length: %u\n", MinInstLength) + << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) + << format(" default_is_stmt: %u\n", DefaultIsStmt) + << format(" line_base: %i\n", LineBase) + << format(" line_range: %u\n", LineRange) + << format(" opcode_base: %u\n", OpcodeBase); + + for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I) + OS << formatv("standard_opcode_lengths[{0}] = {1}\n", + static_cast<dwarf::LineNumberOps>(I + 1), + StandardOpcodeLengths[I]); + + if (!IncludeDirectories.empty()) { + // DWARF v5 starts directory indexes at 0. + uint32_t DirBase = getVersion() >= 5 ? 0 : 1; + for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) { + OS << format("include_directories[%3u] = ", I + DirBase); + IncludeDirectories[I].dump(OS, DumpOptions); + OS << '\n'; + } + } + + if (!FileNames.empty()) { + // DWARF v5 starts file indexes at 0. + uint32_t FileBase = getVersion() >= 5 ? 0 : 1; + for (uint32_t I = 0; I != FileNames.size(); ++I) { + const FileNameEntry &FileEntry = FileNames[I]; + OS << format("file_names[%3u]:\n", I + FileBase); + OS << " name: "; + FileEntry.Name.dump(OS, DumpOptions); + OS << '\n' + << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx); + if (ContentTypes.HasMD5) + OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n'; + if (ContentTypes.HasModTime) + OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime); + if (ContentTypes.HasLength) + OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length); + if (ContentTypes.HasSource) { + OS << " source: "; + FileEntry.Source.dump(OS, DumpOptions); + OS << '\n'; + } + } + } +} + +// Parse v2-v4 directory and file tables. +static Error +parseV2DirFileTables(const DWARFDataExtractor &DebugLineData, + uint64_t *OffsetPtr, + DWARFDebugLine::ContentTypeTracker &ContentTypes, + std::vector<DWARFFormValue> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + while (true) { + Error Err = Error::success(); + StringRef S = DebugLineData.getCStrRef(OffsetPtr, &Err); + if (Err) { + consumeError(std::move(Err)); + return createStringError(errc::invalid_argument, + "include directories table was not null " + "terminated before the end of the prologue"); + } + if (S.empty()) + break; + DWARFFormValue Dir = + DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, S.data()); + IncludeDirectories.push_back(Dir); + } + + ContentTypes.HasModTime = true; + ContentTypes.HasLength = true; + + while (true) { + Error Err = Error::success(); + StringRef Name = DebugLineData.getCStrRef(OffsetPtr, &Err); + if (!Err && Name.empty()) + break; + + DWARFDebugLine::FileNameEntry FileEntry; + FileEntry.Name = + DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data()); + FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr, &Err); + FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr, &Err); + FileEntry.Length = DebugLineData.getULEB128(OffsetPtr, &Err); + + if (Err) { + consumeError(std::move(Err)); + return createStringError( + errc::invalid_argument, + "file names table was not null terminated before " + "the end of the prologue"); + } + FileNames.push_back(FileEntry); + } + + return Error::success(); +} + +// Parse v5 directory/file entry content descriptions. +// Returns the descriptors, or an error if we did not find a path or ran off +// the end of the prologue. +static llvm::Expected<ContentDescriptors> +parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, + DWARFDebugLine::ContentTypeTracker *ContentTypes) { + Error Err = Error::success(); + ContentDescriptors Descriptors; + int FormatCount = DebugLineData.getU8(OffsetPtr, &Err); + bool HasPath = false; + for (int I = 0; I != FormatCount && !Err; ++I) { + ContentDescriptor Descriptor; + Descriptor.Type = + dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr, &Err)); + Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr, &Err)); + if (Descriptor.Type == dwarf::DW_LNCT_path) + HasPath = true; + if (ContentTypes) + ContentTypes->trackContentType(Descriptor.Type); + Descriptors.push_back(Descriptor); + } + + if (Err) + return createStringError(errc::invalid_argument, + "failed to parse entry content descriptors: %s", + toString(std::move(Err)).c_str()); + + if (!HasPath) + return createStringError(errc::invalid_argument, + "failed to parse entry content descriptions" + " because no path was found"); + return Descriptors; +} + +static Error +parseV5DirFileTables(const DWARFDataExtractor &DebugLineData, + uint64_t *OffsetPtr, const dwarf::FormParams &FormParams, + const DWARFContext &Ctx, const DWARFUnit *U, + DWARFDebugLine::ContentTypeTracker &ContentTypes, + std::vector<DWARFFormValue> &IncludeDirectories, + std::vector<DWARFDebugLine::FileNameEntry> &FileNames) { + // Get the directory entry description. + llvm::Expected<ContentDescriptors> DirDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, nullptr); + if (!DirDescriptors) + return DirDescriptors.takeError(); + + // Get the directory entries, according to the format described above. + uint64_t DirEntryCount = DebugLineData.getULEB128(OffsetPtr); + for (uint64_t I = 0; I != DirEntryCount; ++I) { + for (auto Descriptor : *DirDescriptors) { + DWARFFormValue Value(Descriptor.Form); + switch (Descriptor.Type) { + case DW_LNCT_path: + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) + return createStringError(errc::invalid_argument, + "failed to parse directory entry because " + "extracting the form value failed"); + IncludeDirectories.push_back(Value); + break; + default: + if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams)) + return createStringError(errc::invalid_argument, + "failed to parse directory entry because " + "skipping the form value failed"); + } + } + } + + // Get the file entry description. + llvm::Expected<ContentDescriptors> FileDescriptors = + parseV5EntryFormat(DebugLineData, OffsetPtr, &ContentTypes); + if (!FileDescriptors) + return FileDescriptors.takeError(); + + // Get the file entries, according to the format described above. + uint64_t FileEntryCount = DebugLineData.getULEB128(OffsetPtr); + for (uint64_t I = 0; I != FileEntryCount; ++I) { + DWARFDebugLine::FileNameEntry FileEntry; + for (auto Descriptor : *FileDescriptors) { + DWARFFormValue Value(Descriptor.Form); + if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U)) + return createStringError(errc::invalid_argument, + "failed to parse file entry because " + "extracting the form value failed"); + switch (Descriptor.Type) { + case DW_LNCT_path: + FileEntry.Name = Value; + break; + case DW_LNCT_LLVM_source: + FileEntry.Source = Value; + break; + case DW_LNCT_directory_index: + FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_timestamp: + FileEntry.ModTime = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_size: + FileEntry.Length = Value.getAsUnsignedConstant().getValue(); + break; + case DW_LNCT_MD5: + if (!Value.getAsBlock() || Value.getAsBlock().getValue().size() != 16) + return createStringError( + errc::invalid_argument, + "failed to parse file entry because the MD5 hash is invalid"); + std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16, + FileEntry.Checksum.Bytes.begin()); + break; + default: + break; + } + } + FileNames.push_back(FileEntry); + } + return Error::success(); +} + +uint64_t DWARFDebugLine::Prologue::getLength() const { + uint64_t Length = PrologueLength + sizeofTotalLength() + + sizeof(getVersion()) + sizeofPrologueLength(); + if (getVersion() >= 5) + Length += 2; // Address + Segment selector sizes. + return Length; +} + +Error DWARFDebugLine::Prologue::parse( + DWARFDataExtractor DebugLineData, uint64_t *OffsetPtr, + function_ref<void(Error)> RecoverableErrorHandler, const DWARFContext &Ctx, + const DWARFUnit *U) { + const uint64_t PrologueOffset = *OffsetPtr; + + clear(); + DataExtractor::Cursor Cursor(*OffsetPtr); + std::tie(TotalLength, FormParams.Format) = + DebugLineData.getInitialLength(Cursor); + + DebugLineData = + DWARFDataExtractor(DebugLineData, Cursor.tell() + TotalLength); + FormParams.Version = DebugLineData.getU16(Cursor); + if (Cursor && !versionIsSupported(getVersion())) { + // Treat this error as unrecoverable - we cannot be sure what any of + // the data represents including the length field, so cannot skip it or make + // any reasonable assumptions. + *OffsetPtr = Cursor.tell(); + return createStringError( + errc::not_supported, + "parsing line table prologue at offset 0x%8.8" PRIx64 + ": unsupported version %" PRIu16, + PrologueOffset, getVersion()); + } + + if (getVersion() >= 5) { + FormParams.AddrSize = DebugLineData.getU8(Cursor); + assert((!Cursor || DebugLineData.getAddressSize() == 0 || + DebugLineData.getAddressSize() == getAddressSize()) && + "Line table header and data extractor disagree"); + SegSelectorSize = DebugLineData.getU8(Cursor); + } + + PrologueLength = + DebugLineData.getRelocatedValue(Cursor, sizeofPrologueLength()); + const uint64_t EndPrologueOffset = PrologueLength + Cursor.tell(); + DebugLineData = DWARFDataExtractor(DebugLineData, EndPrologueOffset); + MinInstLength = DebugLineData.getU8(Cursor); + if (getVersion() >= 4) + MaxOpsPerInst = DebugLineData.getU8(Cursor); + DefaultIsStmt = DebugLineData.getU8(Cursor); + LineBase = DebugLineData.getU8(Cursor); + LineRange = DebugLineData.getU8(Cursor); + OpcodeBase = DebugLineData.getU8(Cursor); + + if (Cursor && OpcodeBase == 0) { + // If the opcode base is 0, we cannot read the standard opcode lengths (of + // which there are supposed to be one fewer than the opcode base). Assume + // there are no standard opcodes and continue parsing. + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "parsing line table prologue at offset 0x%8.8" PRIx64 + " found opcode base of 0. Assuming no standard opcodes", + PrologueOffset)); + } else if (Cursor) { + StandardOpcodeLengths.reserve(OpcodeBase - 1); + for (uint32_t I = 1; I < OpcodeBase; ++I) { + uint8_t OpLen = DebugLineData.getU8(Cursor); + StandardOpcodeLengths.push_back(OpLen); + } + } + + *OffsetPtr = Cursor.tell(); + // A corrupt file name or directory table does not prevent interpretation of + // the main line program, so check the cursor state now so that its errors can + // be handled separately. + if (!Cursor) + return createStringError( + errc::invalid_argument, + "parsing line table prologue at offset 0x%8.8" PRIx64 ": %s", + PrologueOffset, toString(Cursor.takeError()).c_str()); + + Error E = + getVersion() >= 5 + ? parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U, + ContentTypes, IncludeDirectories, FileNames) + : parseV2DirFileTables(DebugLineData, OffsetPtr, ContentTypes, + IncludeDirectories, FileNames); + if (E) { + RecoverableErrorHandler(joinErrors( + createStringError( + errc::invalid_argument, + "parsing line table prologue at 0x%8.8" PRIx64 + " found an invalid directory or file table description at" + " 0x%8.8" PRIx64, + PrologueOffset, *OffsetPtr), + std::move(E))); + return Error::success(); + } + + assert(*OffsetPtr <= EndPrologueOffset); + if (*OffsetPtr != EndPrologueOffset) { + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "unknown data in line table prologue at offset 0x%8.8" PRIx64 + ": parsing ended (at offset 0x%8.8" PRIx64 + ") before reaching the prologue end at offset 0x%8.8" PRIx64, + PrologueOffset, *OffsetPtr, EndPrologueOffset)); + } + return Error::success(); +} + +DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); } + +void DWARFDebugLine::Row::postAppend() { + Discriminator = 0; + BasicBlock = false; + PrologueEnd = false; + EpilogueBegin = false; +} + +void DWARFDebugLine::Row::reset(bool DefaultIsStmt) { + Address.Address = 0; + Address.SectionIndex = object::SectionedAddress::UndefSection; + Line = 1; + Column = 0; + File = 1; + Isa = 0; + Discriminator = 0; + IsStmt = DefaultIsStmt; + BasicBlock = false; + EndSequence = false; + PrologueEnd = false; + EpilogueBegin = false; +} + +void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS, unsigned Indent) { + OS.indent(Indent) + << "Address Line Column File ISA Discriminator Flags\n"; + OS.indent(Indent) + << "------------------ ------ ------ ------ --- ------------- " + "-------------\n"; +} + +void DWARFDebugLine::Row::dump(raw_ostream &OS) const { + OS << format("0x%16.16" PRIx64 " %6u %6u", Address.Address, Line, Column) + << format(" %6u %3u %13u ", File, Isa, Discriminator) + << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "") + << (PrologueEnd ? " prologue_end" : "") + << (EpilogueBegin ? " epilogue_begin" : "") + << (EndSequence ? " end_sequence" : "") << '\n'; +} + +DWARFDebugLine::Sequence::Sequence() { reset(); } + +void DWARFDebugLine::Sequence::reset() { + LowPC = 0; + HighPC = 0; + SectionIndex = object::SectionedAddress::UndefSection; + FirstRowIndex = 0; + LastRowIndex = 0; + Empty = true; +} + +DWARFDebugLine::LineTable::LineTable() { clear(); } + +void DWARFDebugLine::LineTable::dump(raw_ostream &OS, + DIDumpOptions DumpOptions) const { + Prologue.dump(OS, DumpOptions); + + if (!Rows.empty()) { + OS << '\n'; + Row::dumpTableHeader(OS, 0); + for (const Row &R : Rows) { + R.dump(OS); + } + } + + // Terminate the table with a final blank line to clearly delineate it from + // later dumps. + OS << '\n'; +} + +void DWARFDebugLine::LineTable::clear() { + Prologue.clear(); + Rows.clear(); + Sequences.clear(); +} + +DWARFDebugLine::ParsingState::ParsingState( + struct LineTable *LT, uint64_t TableOffset, + function_ref<void(Error)> ErrorHandler) + : LineTable(LT), LineTableOffset(TableOffset), ErrorHandler(ErrorHandler) { + resetRowAndSequence(); +} + +void DWARFDebugLine::ParsingState::resetRowAndSequence() { + Row.reset(LineTable->Prologue.DefaultIsStmt); + Sequence.reset(); +} + +void DWARFDebugLine::ParsingState::appendRowToMatrix() { + unsigned RowNumber = LineTable->Rows.size(); + if (Sequence.Empty) { + // Record the beginning of instruction sequence. + Sequence.Empty = false; + Sequence.LowPC = Row.Address.Address; + Sequence.FirstRowIndex = RowNumber; + } + LineTable->appendRow(Row); + if (Row.EndSequence) { + // Record the end of instruction sequence. + Sequence.HighPC = Row.Address.Address; + Sequence.LastRowIndex = RowNumber + 1; + Sequence.SectionIndex = Row.Address.SectionIndex; + if (Sequence.isValid()) + LineTable->appendSequence(Sequence); + Sequence.reset(); + } + Row.postAppend(); +} + +const DWARFDebugLine::LineTable * +DWARFDebugLine::getLineTable(uint64_t Offset) const { + LineTableConstIter Pos = LineTableMap.find(Offset); + if (Pos != LineTableMap.end()) + return &Pos->second; + return nullptr; +} + +Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable( + DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx, + const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) { + if (!DebugLineData.isValidOffset(Offset)) + return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64 + " is not a valid debug line section offset", + Offset); + + std::pair<LineTableIter, bool> Pos = + LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable())); + LineTable *LT = &Pos.first->second; + if (Pos.second) { + if (Error Err = + LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorHandler)) + return std::move(Err); + return LT; + } + return LT; +} + +static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) { + assert(Opcode != 0); + if (Opcode < OpcodeBase) + return LNStandardString(Opcode); + return "special"; +} + +uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance, + uint8_t Opcode, + uint64_t OpcodeOffset) { + StringRef OpcodeName = getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase); + // For versions less than 4, the MaxOpsPerInst member is set to 0, as the + // maximum_operations_per_instruction field wasn't introduced until DWARFv4. + // Don't warn about bad values in this situation. + if (ReportAdvanceAddrProblem && LineTable->Prologue.getVersion() >= 4 && + LineTable->Prologue.MaxOpsPerInst != 1) + ErrorHandler(createStringError( + errc::not_supported, + "line table program at offset 0x%8.8" PRIx64 + " contains a %s opcode at offset 0x%8.8" PRIx64 + ", but the prologue maximum_operations_per_instruction value is %" PRId8 + ", which is unsupported. Assuming a value of 1 instead", + LineTableOffset, OpcodeName.data(), OpcodeOffset, + LineTable->Prologue.MaxOpsPerInst)); + if (ReportAdvanceAddrProblem && LineTable->Prologue.MinInstLength == 0) + ErrorHandler( + createStringError(errc::invalid_argument, + "line table program at offset 0x%8.8" PRIx64 + " contains a %s opcode at offset 0x%8.8" PRIx64 + ", but the prologue minimum_instruction_length value " + "is 0, which prevents any address advancing", + LineTableOffset, OpcodeName.data(), OpcodeOffset)); + ReportAdvanceAddrProblem = false; + uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength; + Row.Address.Address += AddrOffset; + return AddrOffset; +} + +DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode +DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode, + uint64_t OpcodeOffset) { + assert(Opcode == DW_LNS_const_add_pc || + Opcode >= LineTable->Prologue.OpcodeBase); + if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) { + StringRef OpcodeName = + getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase); + ErrorHandler( + createStringError(errc::not_supported, + "line table program at offset 0x%8.8" PRIx64 + " contains a %s opcode at offset 0x%8.8" PRIx64 + ", but the prologue line_range value is 0. The " + "address and line will not be adjusted", + LineTableOffset, OpcodeName.data(), OpcodeOffset)); + ReportBadLineRange = false; + } + + uint8_t OpcodeValue = Opcode; + if (Opcode == DW_LNS_const_add_pc) + OpcodeValue = 255; + uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase; + uint64_t OperationAdvance = + LineTable->Prologue.LineRange != 0 + ? AdjustedOpcode / LineTable->Prologue.LineRange + : 0; + uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset); + return {AddrOffset, AdjustedOpcode}; +} + +DWARFDebugLine::ParsingState::AddrAndLineDelta +DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode, + uint64_t OpcodeOffset) { + // A special opcode value is chosen based on the amount that needs + // to be added to the line and address registers. The maximum line + // increment for a special opcode is the value of the line_base + // field in the header, plus the value of the line_range field, + // minus 1 (line base + line range - 1). If the desired line + // increment is greater than the maximum line increment, a standard + // opcode must be used instead of a special opcode. The "address + // advance" is calculated by dividing the desired address increment + // by the minimum_instruction_length field from the header. The + // special opcode is then calculated using the following formula: + // + // opcode = (desired line increment - line_base) + + // (line_range * address advance) + opcode_base + // + // If the resulting opcode is greater than 255, a standard opcode + // must be used instead. + // + // To decode a special opcode, subtract the opcode_base from the + // opcode itself to give the adjusted opcode. The amount to + // increment the address register is the result of the adjusted + // opcode divided by the line_range multiplied by the + // minimum_instruction_length field from the header. That is: + // + // address increment = (adjusted opcode / line_range) * + // minimum_instruction_length + // + // The amount to increment the line register is the line_base plus + // the result of the adjusted opcode modulo the line_range. That is: + // + // line increment = line_base + (adjusted opcode % line_range) + + DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult = + advanceAddrForOpcode(Opcode, OpcodeOffset); + int32_t LineOffset = 0; + if (LineTable->Prologue.LineRange != 0) + LineOffset = + LineTable->Prologue.LineBase + + (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange); + Row.Line += LineOffset; + return {AddrAdvanceResult.AddrDelta, LineOffset}; +} + +/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on +/// success, or None if \p Cursor is in a failing state. +template <typename T> +static Optional<T> parseULEB128(DWARFDataExtractor &Data, + DataExtractor::Cursor &Cursor) { + T Value = Data.getULEB128(Cursor); + if (Cursor) + return Value; + return None; +} + +Error DWARFDebugLine::LineTable::parse( + DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr, + const DWARFContext &Ctx, const DWARFUnit *U, + function_ref<void(Error)> RecoverableErrorHandler, raw_ostream *OS, + bool Verbose) { + assert((OS || !Verbose) && "cannot have verbose output without stream"); + const uint64_t DebugLineOffset = *OffsetPtr; + + clear(); + + Error PrologueErr = + Prologue.parse(DebugLineData, OffsetPtr, RecoverableErrorHandler, Ctx, U); + + if (OS) { + DIDumpOptions DumpOptions; + DumpOptions.Verbose = Verbose; + Prologue.dump(*OS, DumpOptions); + } + + if (PrologueErr) { + // Ensure there is a blank line after the prologue to clearly delineate it + // from later dumps. + if (OS) + *OS << "\n"; + return PrologueErr; + } + + uint64_t ProgramLength = Prologue.TotalLength + Prologue.sizeofTotalLength(); + if (!DebugLineData.isValidOffsetForDataOfSize(DebugLineOffset, + ProgramLength)) { + assert(DebugLineData.size() > DebugLineOffset && + "prologue parsing should handle invalid offset"); + uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset; + RecoverableErrorHandler( + createStringError(errc::invalid_argument, + "line table program with offset 0x%8.8" PRIx64 + " has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64 + " bytes are available", + DebugLineOffset, ProgramLength, BytesRemaining)); + // Continue by capping the length at the number of remaining bytes. + ProgramLength = BytesRemaining; + } + + // Create a DataExtractor which can only see the data up to the end of the + // table, to prevent reading past the end. + const uint64_t EndOffset = DebugLineOffset + ProgramLength; + DWARFDataExtractor TableData(DebugLineData, EndOffset); + + // See if we should tell the data extractor the address size. + if (TableData.getAddressSize() == 0) + TableData.setAddressSize(Prologue.getAddressSize()); + else + assert(Prologue.getAddressSize() == 0 || + Prologue.getAddressSize() == TableData.getAddressSize()); + + ParsingState State(this, DebugLineOffset, RecoverableErrorHandler); + + *OffsetPtr = DebugLineOffset + Prologue.getLength(); + if (OS && *OffsetPtr < EndOffset) { + *OS << '\n'; + Row::dumpTableHeader(*OS, /*Indent=*/Verbose ? 12 : 0); + } bool TombstonedAddress = false; auto EmitRow = [&] { if (!TombstonedAddress) { @@ -795,703 +795,703 @@ Error DWARFDebugLine::LineTable::parse( State.appendRowToMatrix(); } }; - while (*OffsetPtr < EndOffset) { - DataExtractor::Cursor Cursor(*OffsetPtr); - - if (Verbose) - *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr); - - uint64_t OpcodeOffset = *OffsetPtr; - uint8_t Opcode = TableData.getU8(Cursor); - size_t RowCount = Rows.size(); - - if (Cursor && Verbose) - *OS << format("%02.02" PRIx8 " ", Opcode); - - if (Opcode == 0) { - // Extended Opcodes always start with a zero opcode followed by - // a uleb128 length so you can skip ones you don't know about - uint64_t Len = TableData.getULEB128(Cursor); - uint64_t ExtOffset = Cursor.tell(); - - // Tolerate zero-length; assume length is correct and soldier on. - if (Len == 0) { - if (Cursor && Verbose) - *OS << "Badly formed extended line op (length 0)\n"; - if (!Cursor) { - if (Verbose) - *OS << "\n"; - RecoverableErrorHandler(Cursor.takeError()); - } - *OffsetPtr = Cursor.tell(); - continue; - } - - uint8_t SubOpcode = TableData.getU8(Cursor); - // OperandOffset will be the same as ExtOffset, if it was not possible to - // read the SubOpcode. - uint64_t OperandOffset = Cursor.tell(); - if (Verbose) - *OS << LNExtendedString(SubOpcode); - switch (SubOpcode) { - case DW_LNE_end_sequence: - // Set the end_sequence register of the state machine to true and - // append a row to the matrix using the current values of the - // state-machine registers. Then reset the registers to the initial - // values specified above. Every statement program sequence must end - // with a DW_LNE_end_sequence instruction which creates a row whose - // address is that of the byte after the last target machine instruction - // of the sequence. - State.Row.EndSequence = true; - // No need to test the Cursor is valid here, since it must be to get - // into this code path - if it were invalid, the default case would be - // followed. + while (*OffsetPtr < EndOffset) { + DataExtractor::Cursor Cursor(*OffsetPtr); + + if (Verbose) + *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr); + + uint64_t OpcodeOffset = *OffsetPtr; + uint8_t Opcode = TableData.getU8(Cursor); + size_t RowCount = Rows.size(); + + if (Cursor && Verbose) + *OS << format("%02.02" PRIx8 " ", Opcode); + + if (Opcode == 0) { + // Extended Opcodes always start with a zero opcode followed by + // a uleb128 length so you can skip ones you don't know about + uint64_t Len = TableData.getULEB128(Cursor); + uint64_t ExtOffset = Cursor.tell(); + + // Tolerate zero-length; assume length is correct and soldier on. + if (Len == 0) { + if (Cursor && Verbose) + *OS << "Badly formed extended line op (length 0)\n"; + if (!Cursor) { + if (Verbose) + *OS << "\n"; + RecoverableErrorHandler(Cursor.takeError()); + } + *OffsetPtr = Cursor.tell(); + continue; + } + + uint8_t SubOpcode = TableData.getU8(Cursor); + // OperandOffset will be the same as ExtOffset, if it was not possible to + // read the SubOpcode. + uint64_t OperandOffset = Cursor.tell(); + if (Verbose) + *OS << LNExtendedString(SubOpcode); + switch (SubOpcode) { + case DW_LNE_end_sequence: + // Set the end_sequence register of the state machine to true and + // append a row to the matrix using the current values of the + // state-machine registers. Then reset the registers to the initial + // values specified above. Every statement program sequence must end + // with a DW_LNE_end_sequence instruction which creates a row whose + // address is that of the byte after the last target machine instruction + // of the sequence. + State.Row.EndSequence = true; + // No need to test the Cursor is valid here, since it must be to get + // into this code path - if it were invalid, the default case would be + // followed. EmitRow(); - State.resetRowAndSequence(); - break; - - case DW_LNE_set_address: - // Takes a single relocatable address as an operand. The size of the - // operand is the size appropriate to hold an address on the target - // machine. Set the address register to the value given by the - // relocatable address. All of the other statement program opcodes - // that affect the address register add a delta to it. This instruction - // stores a relocatable value into it instead. - // - // Make sure the extractor knows the address size. If not, infer it - // from the size of the operand. - { - uint8_t ExtractorAddressSize = TableData.getAddressSize(); - uint64_t OpcodeAddressSize = Len - 1; - if (ExtractorAddressSize != OpcodeAddressSize && - ExtractorAddressSize != 0) - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "mismatching address size at offset 0x%8.8" PRIx64 - " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64, - ExtOffset, ExtractorAddressSize, Len - 1)); - - // Assume that the line table is correct and temporarily override the - // address size. If the size is unsupported, give up trying to read - // the address and continue to the next opcode. - if (OpcodeAddressSize != 1 && OpcodeAddressSize != 2 && - OpcodeAddressSize != 4 && OpcodeAddressSize != 8) { - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "address size 0x%2.2" PRIx64 - " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64 - " is unsupported", - OpcodeAddressSize, ExtOffset)); - TableData.skip(Cursor, OpcodeAddressSize); - } else { - TableData.setAddressSize(OpcodeAddressSize); - State.Row.Address.Address = TableData.getRelocatedAddress( - Cursor, &State.Row.Address.SectionIndex); - + State.resetRowAndSequence(); + break; + + case DW_LNE_set_address: + // Takes a single relocatable address as an operand. The size of the + // operand is the size appropriate to hold an address on the target + // machine. Set the address register to the value given by the + // relocatable address. All of the other statement program opcodes + // that affect the address register add a delta to it. This instruction + // stores a relocatable value into it instead. + // + // Make sure the extractor knows the address size. If not, infer it + // from the size of the operand. + { + uint8_t ExtractorAddressSize = TableData.getAddressSize(); + uint64_t OpcodeAddressSize = Len - 1; + if (ExtractorAddressSize != OpcodeAddressSize && + ExtractorAddressSize != 0) + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "mismatching address size at offset 0x%8.8" PRIx64 + " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64, + ExtOffset, ExtractorAddressSize, Len - 1)); + + // Assume that the line table is correct and temporarily override the + // address size. If the size is unsupported, give up trying to read + // the address and continue to the next opcode. + if (OpcodeAddressSize != 1 && OpcodeAddressSize != 2 && + OpcodeAddressSize != 4 && OpcodeAddressSize != 8) { + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "address size 0x%2.2" PRIx64 + " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64 + " is unsupported", + OpcodeAddressSize, ExtOffset)); + TableData.skip(Cursor, OpcodeAddressSize); + } else { + TableData.setAddressSize(OpcodeAddressSize); + State.Row.Address.Address = TableData.getRelocatedAddress( + Cursor, &State.Row.Address.SectionIndex); + uint64_t Tombstone = dwarf::computeTombstoneAddress(OpcodeAddressSize); TombstonedAddress = State.Row.Address.Address == Tombstone; - // Restore the address size if the extractor already had it. - if (ExtractorAddressSize != 0) - TableData.setAddressSize(ExtractorAddressSize); - } - + // Restore the address size if the extractor already had it. + if (ExtractorAddressSize != 0) + TableData.setAddressSize(ExtractorAddressSize); + } + if (Cursor && Verbose) { *OS << " ("; DWARFFormValue::dumpAddress(*OS, OpcodeAddressSize, State.Row.Address.Address); *OS << ')'; } - } - break; - - case DW_LNE_define_file: - // Takes 4 arguments. The first is a null terminated string containing - // a source file name. The second is an unsigned LEB128 number - // representing the directory index of the directory in which the file - // was found. The third is an unsigned LEB128 number representing the - // time of last modification of the file. The fourth is an unsigned - // LEB128 number representing the length in bytes of the file. The time - // and length fields may contain LEB128(0) if the information is not - // available. - // - // The directory index represents an entry in the include_directories - // section of the statement program prologue. The index is LEB128(0) - // if the file was found in the current directory of the compilation, - // LEB128(1) if it was found in the first directory in the - // include_directories section, and so on. The directory index is - // ignored for file names that represent full path names. - // - // The files are numbered, starting at 1, in the order in which they - // appear; the names in the prologue come before names defined by - // the DW_LNE_define_file instruction. These numbers are used in the - // the file register of the state machine. - { - FileNameEntry FileEntry; - const char *Name = TableData.getCStr(Cursor); - FileEntry.Name = - DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name); - FileEntry.DirIdx = TableData.getULEB128(Cursor); - FileEntry.ModTime = TableData.getULEB128(Cursor); - FileEntry.Length = TableData.getULEB128(Cursor); - Prologue.FileNames.push_back(FileEntry); - if (Cursor && Verbose) - *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time=" - << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime) - << ", length=" << FileEntry.Length << ")"; - } - break; - - case DW_LNE_set_discriminator: - State.Row.Discriminator = TableData.getULEB128(Cursor); - if (Cursor && Verbose) - *OS << " (" << State.Row.Discriminator << ")"; - break; - - default: - if (Cursor && Verbose) - *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode) - << format(" length %" PRIx64, Len); - // Len doesn't include the zero opcode byte or the length itself, but - // it does include the sub_opcode, so we have to adjust for that. - TableData.skip(Cursor, Len - 1); - break; - } - // Make sure the length as recorded in the table and the standard length - // for the opcode match. If they don't, continue from the end as claimed - // by the table. Similarly, continue from the claimed end in the event of - // a parsing error. - uint64_t End = ExtOffset + Len; - if (Cursor && Cursor.tell() != End) - RecoverableErrorHandler(createStringError( - errc::illegal_byte_sequence, - "unexpected line op length at offset 0x%8.8" PRIx64 - " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64, - ExtOffset, Len, Cursor.tell() - ExtOffset)); - if (!Cursor && Verbose) { - DWARFDataExtractor::Cursor ByteCursor(OperandOffset); - uint8_t Byte = TableData.getU8(ByteCursor); - if (ByteCursor) { - *OS << " (<parsing error>"; - do { - *OS << format(" %2.2" PRIx8, Byte); - Byte = TableData.getU8(ByteCursor); - } while (ByteCursor); - *OS << ")"; - } - - // The only parse failure in this case should be if the end was reached. - // In that case, throw away the error, as the main Cursor's error will - // be sufficient. - consumeError(ByteCursor.takeError()); - } - *OffsetPtr = End; - } else if (Opcode < Prologue.OpcodeBase) { - if (Verbose) - *OS << LNStandardString(Opcode); - switch (Opcode) { - // Standard Opcodes - case DW_LNS_copy: - // Takes no arguments. Append a row to the matrix using the - // current values of the state-machine registers. + } + break; + + case DW_LNE_define_file: + // Takes 4 arguments. The first is a null terminated string containing + // a source file name. The second is an unsigned LEB128 number + // representing the directory index of the directory in which the file + // was found. The third is an unsigned LEB128 number representing the + // time of last modification of the file. The fourth is an unsigned + // LEB128 number representing the length in bytes of the file. The time + // and length fields may contain LEB128(0) if the information is not + // available. + // + // The directory index represents an entry in the include_directories + // section of the statement program prologue. The index is LEB128(0) + // if the file was found in the current directory of the compilation, + // LEB128(1) if it was found in the first directory in the + // include_directories section, and so on. The directory index is + // ignored for file names that represent full path names. + // + // The files are numbered, starting at 1, in the order in which they + // appear; the names in the prologue come before names defined by + // the DW_LNE_define_file instruction. These numbers are used in the + // the file register of the state machine. + { + FileNameEntry FileEntry; + const char *Name = TableData.getCStr(Cursor); + FileEntry.Name = + DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name); + FileEntry.DirIdx = TableData.getULEB128(Cursor); + FileEntry.ModTime = TableData.getULEB128(Cursor); + FileEntry.Length = TableData.getULEB128(Cursor); + Prologue.FileNames.push_back(FileEntry); + if (Cursor && Verbose) + *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time=" + << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime) + << ", length=" << FileEntry.Length << ")"; + } + break; + + case DW_LNE_set_discriminator: + State.Row.Discriminator = TableData.getULEB128(Cursor); + if (Cursor && Verbose) + *OS << " (" << State.Row.Discriminator << ")"; + break; + + default: + if (Cursor && Verbose) + *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode) + << format(" length %" PRIx64, Len); + // Len doesn't include the zero opcode byte or the length itself, but + // it does include the sub_opcode, so we have to adjust for that. + TableData.skip(Cursor, Len - 1); + break; + } + // Make sure the length as recorded in the table and the standard length + // for the opcode match. If they don't, continue from the end as claimed + // by the table. Similarly, continue from the claimed end in the event of + // a parsing error. + uint64_t End = ExtOffset + Len; + if (Cursor && Cursor.tell() != End) + RecoverableErrorHandler(createStringError( + errc::illegal_byte_sequence, + "unexpected line op length at offset 0x%8.8" PRIx64 + " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64, + ExtOffset, Len, Cursor.tell() - ExtOffset)); + if (!Cursor && Verbose) { + DWARFDataExtractor::Cursor ByteCursor(OperandOffset); + uint8_t Byte = TableData.getU8(ByteCursor); + if (ByteCursor) { + *OS << " (<parsing error>"; + do { + *OS << format(" %2.2" PRIx8, Byte); + Byte = TableData.getU8(ByteCursor); + } while (ByteCursor); + *OS << ")"; + } + + // The only parse failure in this case should be if the end was reached. + // In that case, throw away the error, as the main Cursor's error will + // be sufficient. + consumeError(ByteCursor.takeError()); + } + *OffsetPtr = End; + } else if (Opcode < Prologue.OpcodeBase) { + if (Verbose) + *OS << LNStandardString(Opcode); + switch (Opcode) { + // Standard Opcodes + case DW_LNS_copy: + // Takes no arguments. Append a row to the matrix using the + // current values of the state-machine registers. EmitRow(); - break; - - case DW_LNS_advance_pc: - // Takes a single unsigned LEB128 operand, multiplies it by the - // min_inst_length field of the prologue, and adds the - // result to the address register of the state machine. - if (Optional<uint64_t> Operand = - parseULEB128<uint64_t>(TableData, Cursor)) { - uint64_t AddrOffset = - State.advanceAddr(*Operand, Opcode, OpcodeOffset); - if (Verbose) - *OS << " (" << AddrOffset << ")"; - } - break; - - case DW_LNS_advance_line: - // Takes a single signed LEB128 operand and adds that value to - // the line register of the state machine. - { - int64_t LineDelta = TableData.getSLEB128(Cursor); - if (Cursor) { - State.Row.Line += LineDelta; - if (Verbose) - *OS << " (" << State.Row.Line << ")"; - } - } - break; - - case DW_LNS_set_file: - // Takes a single unsigned LEB128 operand and stores it in the file - // register of the state machine. - if (Optional<uint16_t> File = - parseULEB128<uint16_t>(TableData, Cursor)) { - State.Row.File = *File; - if (Verbose) - *OS << " (" << State.Row.File << ")"; - } - break; - - case DW_LNS_set_column: - // Takes a single unsigned LEB128 operand and stores it in the - // column register of the state machine. - if (Optional<uint16_t> Column = - parseULEB128<uint16_t>(TableData, Cursor)) { - State.Row.Column = *Column; - if (Verbose) - *OS << " (" << State.Row.Column << ")"; - } - break; - - case DW_LNS_negate_stmt: - // Takes no arguments. Set the is_stmt register of the state - // machine to the logical negation of its current value. - State.Row.IsStmt = !State.Row.IsStmt; - break; - - case DW_LNS_set_basic_block: - // Takes no arguments. Set the basic_block register of the - // state machine to true - State.Row.BasicBlock = true; - break; - - case DW_LNS_const_add_pc: - // Takes no arguments. Add to the address register of the state - // machine the address increment value corresponding to special - // opcode 255. The motivation for DW_LNS_const_add_pc is this: - // when the statement program needs to advance the address by a - // small amount, it can use a single special opcode, which occupies - // a single byte. When it needs to advance the address by up to - // twice the range of the last special opcode, it can use - // DW_LNS_const_add_pc followed by a special opcode, for a total - // of two bytes. Only if it needs to advance the address by more - // than twice that range will it need to use both DW_LNS_advance_pc - // and a special opcode, requiring three or more bytes. - { - uint64_t AddrOffset = - State.advanceAddrForOpcode(Opcode, OpcodeOffset).AddrDelta; - if (Verbose) - *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset); - } - break; - - case DW_LNS_fixed_advance_pc: - // Takes a single uhalf operand. Add to the address register of - // the state machine the value of the (unencoded) operand. This - // is the only extended opcode that takes an argument that is not - // a variable length number. The motivation for DW_LNS_fixed_advance_pc - // is this: existing assemblers cannot emit DW_LNS_advance_pc or - // special opcodes because they cannot encode LEB128 numbers or - // judge when the computation of a special opcode overflows and - // requires the use of DW_LNS_advance_pc. Such assemblers, however, - // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. - { - uint16_t PCOffset = - TableData.getRelocatedValue(Cursor, 2); - if (Cursor) { - State.Row.Address.Address += PCOffset; - if (Verbose) - *OS << format(" (0x%4.4" PRIx16 ")", PCOffset); - } - } - break; - - case DW_LNS_set_prologue_end: - // Takes no arguments. Set the prologue_end register of the - // state machine to true - State.Row.PrologueEnd = true; - break; - - case DW_LNS_set_epilogue_begin: - // Takes no arguments. Set the basic_block register of the - // state machine to true - State.Row.EpilogueBegin = true; - break; - - case DW_LNS_set_isa: - // Takes a single unsigned LEB128 operand and stores it in the - // ISA register of the state machine. - if (Optional<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) { - State.Row.Isa = *Isa; - if (Verbose) - *OS << " (" << (uint64_t)State.Row.Isa << ")"; - } - break; - - default: - // Handle any unknown standard opcodes here. We know the lengths - // of such opcodes because they are specified in the prologue - // as a multiple of LEB128 operands for each opcode. - { - assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); - if (Verbose) - *OS << "Unrecognized standard opcode"; - uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; - std::vector<uint64_t> Operands; - for (uint8_t I = 0; I < OpcodeLength; ++I) { - if (Optional<uint64_t> Value = - parseULEB128<uint64_t>(TableData, Cursor)) - Operands.push_back(*Value); - else - break; - } - if (Verbose && !Operands.empty()) { - *OS << " (operands: "; - bool First = true; - for (uint64_t Value : Operands) { - if (!First) - *OS << ", "; - First = false; - *OS << format("0x%16.16" PRIx64, Value); - } - if (Verbose) - *OS << ')'; - } - } - break; - } - - *OffsetPtr = Cursor.tell(); - } else { - // Special Opcodes. - ParsingState::AddrAndLineDelta Delta = - State.handleSpecialOpcode(Opcode, OpcodeOffset); - + break; + + case DW_LNS_advance_pc: + // Takes a single unsigned LEB128 operand, multiplies it by the + // min_inst_length field of the prologue, and adds the + // result to the address register of the state machine. + if (Optional<uint64_t> Operand = + parseULEB128<uint64_t>(TableData, Cursor)) { + uint64_t AddrOffset = + State.advanceAddr(*Operand, Opcode, OpcodeOffset); + if (Verbose) + *OS << " (" << AddrOffset << ")"; + } + break; + + case DW_LNS_advance_line: + // Takes a single signed LEB128 operand and adds that value to + // the line register of the state machine. + { + int64_t LineDelta = TableData.getSLEB128(Cursor); + if (Cursor) { + State.Row.Line += LineDelta; + if (Verbose) + *OS << " (" << State.Row.Line << ")"; + } + } + break; + + case DW_LNS_set_file: + // Takes a single unsigned LEB128 operand and stores it in the file + // register of the state machine. + if (Optional<uint16_t> File = + parseULEB128<uint16_t>(TableData, Cursor)) { + State.Row.File = *File; + if (Verbose) + *OS << " (" << State.Row.File << ")"; + } + break; + + case DW_LNS_set_column: + // Takes a single unsigned LEB128 operand and stores it in the + // column register of the state machine. + if (Optional<uint16_t> Column = + parseULEB128<uint16_t>(TableData, Cursor)) { + State.Row.Column = *Column; + if (Verbose) + *OS << " (" << State.Row.Column << ")"; + } + break; + + case DW_LNS_negate_stmt: + // Takes no arguments. Set the is_stmt register of the state + // machine to the logical negation of its current value. + State.Row.IsStmt = !State.Row.IsStmt; + break; + + case DW_LNS_set_basic_block: + // Takes no arguments. Set the basic_block register of the + // state machine to true + State.Row.BasicBlock = true; + break; + + case DW_LNS_const_add_pc: + // Takes no arguments. Add to the address register of the state + // machine the address increment value corresponding to special + // opcode 255. The motivation for DW_LNS_const_add_pc is this: + // when the statement program needs to advance the address by a + // small amount, it can use a single special opcode, which occupies + // a single byte. When it needs to advance the address by up to + // twice the range of the last special opcode, it can use + // DW_LNS_const_add_pc followed by a special opcode, for a total + // of two bytes. Only if it needs to advance the address by more + // than twice that range will it need to use both DW_LNS_advance_pc + // and a special opcode, requiring three or more bytes. + { + uint64_t AddrOffset = + State.advanceAddrForOpcode(Opcode, OpcodeOffset).AddrDelta; + if (Verbose) + *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset); + } + break; + + case DW_LNS_fixed_advance_pc: + // Takes a single uhalf operand. Add to the address register of + // the state machine the value of the (unencoded) operand. This + // is the only extended opcode that takes an argument that is not + // a variable length number. The motivation for DW_LNS_fixed_advance_pc + // is this: existing assemblers cannot emit DW_LNS_advance_pc or + // special opcodes because they cannot encode LEB128 numbers or + // judge when the computation of a special opcode overflows and + // requires the use of DW_LNS_advance_pc. Such assemblers, however, + // can use DW_LNS_fixed_advance_pc instead, sacrificing compression. + { + uint16_t PCOffset = + TableData.getRelocatedValue(Cursor, 2); + if (Cursor) { + State.Row.Address.Address += PCOffset; + if (Verbose) + *OS << format(" (0x%4.4" PRIx16 ")", PCOffset); + } + } + break; + + case DW_LNS_set_prologue_end: + // Takes no arguments. Set the prologue_end register of the + // state machine to true + State.Row.PrologueEnd = true; + break; + + case DW_LNS_set_epilogue_begin: + // Takes no arguments. Set the basic_block register of the + // state machine to true + State.Row.EpilogueBegin = true; + break; + + case DW_LNS_set_isa: + // Takes a single unsigned LEB128 operand and stores it in the + // ISA register of the state machine. + if (Optional<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) { + State.Row.Isa = *Isa; + if (Verbose) + *OS << " (" << (uint64_t)State.Row.Isa << ")"; + } + break; + + default: + // Handle any unknown standard opcodes here. We know the lengths + // of such opcodes because they are specified in the prologue + // as a multiple of LEB128 operands for each opcode. + { + assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size()); + if (Verbose) + *OS << "Unrecognized standard opcode"; + uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1]; + std::vector<uint64_t> Operands; + for (uint8_t I = 0; I < OpcodeLength; ++I) { + if (Optional<uint64_t> Value = + parseULEB128<uint64_t>(TableData, Cursor)) + Operands.push_back(*Value); + else + break; + } + if (Verbose && !Operands.empty()) { + *OS << " (operands: "; + bool First = true; + for (uint64_t Value : Operands) { + if (!First) + *OS << ", "; + First = false; + *OS << format("0x%16.16" PRIx64, Value); + } + if (Verbose) + *OS << ')'; + } + } + break; + } + + *OffsetPtr = Cursor.tell(); + } else { + // Special Opcodes. + ParsingState::AddrAndLineDelta Delta = + State.handleSpecialOpcode(Opcode, OpcodeOffset); + if (Verbose) *OS << "address += " << Delta.Address << ", line += " << Delta.Line; EmitRow(); - *OffsetPtr = Cursor.tell(); - } - - // When a row is added to the matrix, it is also dumped, which includes a - // new line already, so don't add an extra one. - if (Verbose && Rows.size() == RowCount) - *OS << "\n"; - - // Most parse failures other than when parsing extended opcodes are due to - // failures to read ULEBs. Bail out of parsing, since we don't know where to - // continue reading from as there is no stated length for such byte - // sequences. Print the final trailing new line if needed before doing so. - if (!Cursor && Opcode != 0) { - if (Verbose) - *OS << "\n"; - return Cursor.takeError(); - } - - if (!Cursor) - RecoverableErrorHandler(Cursor.takeError()); - } - - if (!State.Sequence.Empty) - RecoverableErrorHandler(createStringError( - errc::illegal_byte_sequence, - "last sequence in debug line table at offset 0x%8.8" PRIx64 - " is not terminated", - DebugLineOffset)); - - // Sort all sequences so that address lookup will work faster. - if (!Sequences.empty()) { - llvm::sort(Sequences, Sequence::orderByHighPC); - // Note: actually, instruction address ranges of sequences should not - // overlap (in shared objects and executables). If they do, the address - // lookup would still work, though, but result would be ambiguous. - // We don't report warning in this case. For example, - // sometimes .so compiled from multiple object files contains a few - // rudimentary sequences for address ranges [0x0, 0xsomething). - } - - // Terminate the table with a final blank line to clearly delineate it from - // later dumps. - if (OS) - *OS << "\n"; - - return Error::success(); -} - -uint32_t DWARFDebugLine::LineTable::findRowInSeq( - const DWARFDebugLine::Sequence &Seq, - object::SectionedAddress Address) const { - if (!Seq.containsPC(Address)) - return UnknownRowIndex; - assert(Seq.SectionIndex == Address.SectionIndex); - // In some cases, e.g. first instruction in a function, the compiler generates - // two entries, both with the same address. We want the last one. - // - // In general we want a non-empty range: the last row whose address is less - // than or equal to Address. This can be computed as upper_bound - 1. - DWARFDebugLine::Row Row; - Row.Address = Address; - RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex; - RowIter LastRow = Rows.begin() + Seq.LastRowIndex; - assert(FirstRow->Address.Address <= Row.Address.Address && - Row.Address.Address < LastRow[-1].Address.Address); - RowIter RowPos = std::upper_bound(FirstRow + 1, LastRow - 1, Row, - DWARFDebugLine::Row::orderByAddress) - - 1; - assert(Seq.SectionIndex == RowPos->Address.SectionIndex); - return RowPos - Rows.begin(); -} - -uint32_t DWARFDebugLine::LineTable::lookupAddress( - object::SectionedAddress Address) const { - - // Search for relocatable addresses - uint32_t Result = lookupAddressImpl(Address); - - if (Result != UnknownRowIndex || - Address.SectionIndex == object::SectionedAddress::UndefSection) - return Result; - - // Search for absolute addresses - Address.SectionIndex = object::SectionedAddress::UndefSection; - return lookupAddressImpl(Address); -} - -uint32_t DWARFDebugLine::LineTable::lookupAddressImpl( - object::SectionedAddress Address) const { - // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence Sequence; - Sequence.SectionIndex = Address.SectionIndex; - Sequence.HighPC = Address.Address; - SequenceIter It = llvm::upper_bound(Sequences, Sequence, - DWARFDebugLine::Sequence::orderByHighPC); - if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex) - return UnknownRowIndex; - return findRowInSeq(*It, Address); -} - -bool DWARFDebugLine::LineTable::lookupAddressRange( - object::SectionedAddress Address, uint64_t Size, - std::vector<uint32_t> &Result) const { - - // Search for relocatable addresses - if (lookupAddressRangeImpl(Address, Size, Result)) - return true; - - if (Address.SectionIndex == object::SectionedAddress::UndefSection) - return false; - - // Search for absolute addresses - Address.SectionIndex = object::SectionedAddress::UndefSection; - return lookupAddressRangeImpl(Address, Size, Result); -} - -bool DWARFDebugLine::LineTable::lookupAddressRangeImpl( - object::SectionedAddress Address, uint64_t Size, - std::vector<uint32_t> &Result) const { - if (Sequences.empty()) - return false; - uint64_t EndAddr = Address.Address + Size; - // First, find an instruction sequence containing the given address. - DWARFDebugLine::Sequence Sequence; - Sequence.SectionIndex = Address.SectionIndex; - Sequence.HighPC = Address.Address; - SequenceIter LastSeq = Sequences.end(); - SequenceIter SeqPos = llvm::upper_bound( - Sequences, Sequence, DWARFDebugLine::Sequence::orderByHighPC); - if (SeqPos == LastSeq || !SeqPos->containsPC(Address)) - return false; - - SequenceIter StartPos = SeqPos; - - // Add the rows from the first sequence to the vector, starting with the - // index we just calculated - - while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) { - const DWARFDebugLine::Sequence &CurSeq = *SeqPos; - // For the first sequence, we need to find which row in the sequence is the - // first in our range. - uint32_t FirstRowIndex = CurSeq.FirstRowIndex; - if (SeqPos == StartPos) - FirstRowIndex = findRowInSeq(CurSeq, Address); - - // Figure out the last row in the range. - uint32_t LastRowIndex = - findRowInSeq(CurSeq, {EndAddr - 1, Address.SectionIndex}); - if (LastRowIndex == UnknownRowIndex) - LastRowIndex = CurSeq.LastRowIndex - 1; - - assert(FirstRowIndex != UnknownRowIndex); - assert(LastRowIndex != UnknownRowIndex); - - for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) { - Result.push_back(I); - } - - ++SeqPos; - } - - return true; -} - -Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex, - FileLineInfoKind Kind) const { - if (Kind == FileLineInfoKind::None || !Prologue.hasFileAtIndex(FileIndex)) - return None; - const FileNameEntry &Entry = Prologue.getFileNameEntry(FileIndex); - if (Optional<const char *> source = Entry.Source.getAsCString()) - return StringRef(*source); - return None; -} - -static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) { - // Debug info can contain paths from any OS, not necessarily - // an OS we're currently running on. Moreover different compilation units can - // be compiled on different operating systems and linked together later. - return sys::path::is_absolute(Path, sys::path::Style::posix) || - sys::path::is_absolute(Path, sys::path::Style::windows); -} - -bool DWARFDebugLine::Prologue::getFileNameByIndex( - uint64_t FileIndex, StringRef CompDir, FileLineInfoKind Kind, - std::string &Result, sys::path::Style Style) const { - if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) - return false; - const FileNameEntry &Entry = getFileNameEntry(FileIndex); - Optional<const char *> Name = Entry.Name.getAsCString(); - if (!Name) - return false; - StringRef FileName = *Name; - if (Kind == FileLineInfoKind::RawValue || - isPathAbsoluteOnWindowsOrPosix(FileName)) { - Result = std::string(FileName); - return true; - } - if (Kind == FileLineInfoKind::BaseNameOnly) { - Result = std::string(llvm::sys::path::filename(FileName)); - return true; - } - - SmallString<16> FilePath; - StringRef IncludeDir; - // Be defensive about the contents of Entry. - if (getVersion() >= 5) { - // DirIdx 0 is the compilation directory, so don't include it for - // relative names. - if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) && - Entry.DirIdx < IncludeDirectories.size()) - IncludeDir = IncludeDirectories[Entry.DirIdx].getAsCString().getValue(); - } else { - if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size()) - IncludeDir = - IncludeDirectories[Entry.DirIdx - 1].getAsCString().getValue(); - } - - // For absolute paths only, include the compilation directory of compile unit. - // We know that FileName is not absolute, the only way to have an absolute - // path at this point would be if IncludeDir is absolute. - if (Kind == FileLineInfoKind::AbsoluteFilePath && !CompDir.empty() && - !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) - sys::path::append(FilePath, Style, CompDir); - - assert((Kind == FileLineInfoKind::AbsoluteFilePath || - Kind == FileLineInfoKind::RelativeFilePath) && - "invalid FileLineInfo Kind"); - - // sys::path::append skips empty strings. - sys::path::append(FilePath, Style, IncludeDir, FileName); - Result = std::string(FilePath.str()); - return true; -} - -bool DWARFDebugLine::LineTable::getFileLineInfoForAddress( - object::SectionedAddress Address, const char *CompDir, - FileLineInfoKind Kind, DILineInfo &Result) const { - // Get the index of row we're looking for in the line table. - uint32_t RowIndex = lookupAddress(Address); - if (RowIndex == -1U) - return false; - // Take file number and line/column from the row. - const auto &Row = Rows[RowIndex]; - if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName)) - return false; - Result.Line = Row.Line; - Result.Column = Row.Column; - Result.Discriminator = Row.Discriminator; - Result.Source = getSourceByIndex(Row.File, Kind); - return true; -} - -// We want to supply the Unit associated with a .debug_line[.dwo] table when -// we dump it, if possible, but still dump the table even if there isn't a Unit. -// Therefore, collect up handles on all the Units that point into the -// line-table section. -static DWARFDebugLine::SectionParser::LineToUnitMap + *OffsetPtr = Cursor.tell(); + } + + // When a row is added to the matrix, it is also dumped, which includes a + // new line already, so don't add an extra one. + if (Verbose && Rows.size() == RowCount) + *OS << "\n"; + + // Most parse failures other than when parsing extended opcodes are due to + // failures to read ULEBs. Bail out of parsing, since we don't know where to + // continue reading from as there is no stated length for such byte + // sequences. Print the final trailing new line if needed before doing so. + if (!Cursor && Opcode != 0) { + if (Verbose) + *OS << "\n"; + return Cursor.takeError(); + } + + if (!Cursor) + RecoverableErrorHandler(Cursor.takeError()); + } + + if (!State.Sequence.Empty) + RecoverableErrorHandler(createStringError( + errc::illegal_byte_sequence, + "last sequence in debug line table at offset 0x%8.8" PRIx64 + " is not terminated", + DebugLineOffset)); + + // Sort all sequences so that address lookup will work faster. + if (!Sequences.empty()) { + llvm::sort(Sequences, Sequence::orderByHighPC); + // Note: actually, instruction address ranges of sequences should not + // overlap (in shared objects and executables). If they do, the address + // lookup would still work, though, but result would be ambiguous. + // We don't report warning in this case. For example, + // sometimes .so compiled from multiple object files contains a few + // rudimentary sequences for address ranges [0x0, 0xsomething). + } + + // Terminate the table with a final blank line to clearly delineate it from + // later dumps. + if (OS) + *OS << "\n"; + + return Error::success(); +} + +uint32_t DWARFDebugLine::LineTable::findRowInSeq( + const DWARFDebugLine::Sequence &Seq, + object::SectionedAddress Address) const { + if (!Seq.containsPC(Address)) + return UnknownRowIndex; + assert(Seq.SectionIndex == Address.SectionIndex); + // In some cases, e.g. first instruction in a function, the compiler generates + // two entries, both with the same address. We want the last one. + // + // In general we want a non-empty range: the last row whose address is less + // than or equal to Address. This can be computed as upper_bound - 1. + DWARFDebugLine::Row Row; + Row.Address = Address; + RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex; + RowIter LastRow = Rows.begin() + Seq.LastRowIndex; + assert(FirstRow->Address.Address <= Row.Address.Address && + Row.Address.Address < LastRow[-1].Address.Address); + RowIter RowPos = std::upper_bound(FirstRow + 1, LastRow - 1, Row, + DWARFDebugLine::Row::orderByAddress) - + 1; + assert(Seq.SectionIndex == RowPos->Address.SectionIndex); + return RowPos - Rows.begin(); +} + +uint32_t DWARFDebugLine::LineTable::lookupAddress( + object::SectionedAddress Address) const { + + // Search for relocatable addresses + uint32_t Result = lookupAddressImpl(Address); + + if (Result != UnknownRowIndex || + Address.SectionIndex == object::SectionedAddress::UndefSection) + return Result; + + // Search for absolute addresses + Address.SectionIndex = object::SectionedAddress::UndefSection; + return lookupAddressImpl(Address); +} + +uint32_t DWARFDebugLine::LineTable::lookupAddressImpl( + object::SectionedAddress Address) const { + // First, find an instruction sequence containing the given address. + DWARFDebugLine::Sequence Sequence; + Sequence.SectionIndex = Address.SectionIndex; + Sequence.HighPC = Address.Address; + SequenceIter It = llvm::upper_bound(Sequences, Sequence, + DWARFDebugLine::Sequence::orderByHighPC); + if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex) + return UnknownRowIndex; + return findRowInSeq(*It, Address); +} + +bool DWARFDebugLine::LineTable::lookupAddressRange( + object::SectionedAddress Address, uint64_t Size, + std::vector<uint32_t> &Result) const { + + // Search for relocatable addresses + if (lookupAddressRangeImpl(Address, Size, Result)) + return true; + + if (Address.SectionIndex == object::SectionedAddress::UndefSection) + return false; + + // Search for absolute addresses + Address.SectionIndex = object::SectionedAddress::UndefSection; + return lookupAddressRangeImpl(Address, Size, Result); +} + +bool DWARFDebugLine::LineTable::lookupAddressRangeImpl( + object::SectionedAddress Address, uint64_t Size, + std::vector<uint32_t> &Result) const { + if (Sequences.empty()) + return false; + uint64_t EndAddr = Address.Address + Size; + // First, find an instruction sequence containing the given address. + DWARFDebugLine::Sequence Sequence; + Sequence.SectionIndex = Address.SectionIndex; + Sequence.HighPC = Address.Address; + SequenceIter LastSeq = Sequences.end(); + SequenceIter SeqPos = llvm::upper_bound( + Sequences, Sequence, DWARFDebugLine::Sequence::orderByHighPC); + if (SeqPos == LastSeq || !SeqPos->containsPC(Address)) + return false; + + SequenceIter StartPos = SeqPos; + + // Add the rows from the first sequence to the vector, starting with the + // index we just calculated + + while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) { + const DWARFDebugLine::Sequence &CurSeq = *SeqPos; + // For the first sequence, we need to find which row in the sequence is the + // first in our range. + uint32_t FirstRowIndex = CurSeq.FirstRowIndex; + if (SeqPos == StartPos) + FirstRowIndex = findRowInSeq(CurSeq, Address); + + // Figure out the last row in the range. + uint32_t LastRowIndex = + findRowInSeq(CurSeq, {EndAddr - 1, Address.SectionIndex}); + if (LastRowIndex == UnknownRowIndex) + LastRowIndex = CurSeq.LastRowIndex - 1; + + assert(FirstRowIndex != UnknownRowIndex); + assert(LastRowIndex != UnknownRowIndex); + + for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) { + Result.push_back(I); + } + + ++SeqPos; + } + + return true; +} + +Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex, + FileLineInfoKind Kind) const { + if (Kind == FileLineInfoKind::None || !Prologue.hasFileAtIndex(FileIndex)) + return None; + const FileNameEntry &Entry = Prologue.getFileNameEntry(FileIndex); + if (Optional<const char *> source = Entry.Source.getAsCString()) + return StringRef(*source); + return None; +} + +static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) { + // Debug info can contain paths from any OS, not necessarily + // an OS we're currently running on. Moreover different compilation units can + // be compiled on different operating systems and linked together later. + return sys::path::is_absolute(Path, sys::path::Style::posix) || + sys::path::is_absolute(Path, sys::path::Style::windows); +} + +bool DWARFDebugLine::Prologue::getFileNameByIndex( + uint64_t FileIndex, StringRef CompDir, FileLineInfoKind Kind, + std::string &Result, sys::path::Style Style) const { + if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex)) + return false; + const FileNameEntry &Entry = getFileNameEntry(FileIndex); + Optional<const char *> Name = Entry.Name.getAsCString(); + if (!Name) + return false; + StringRef FileName = *Name; + if (Kind == FileLineInfoKind::RawValue || + isPathAbsoluteOnWindowsOrPosix(FileName)) { + Result = std::string(FileName); + return true; + } + if (Kind == FileLineInfoKind::BaseNameOnly) { + Result = std::string(llvm::sys::path::filename(FileName)); + return true; + } + + SmallString<16> FilePath; + StringRef IncludeDir; + // Be defensive about the contents of Entry. + if (getVersion() >= 5) { + // DirIdx 0 is the compilation directory, so don't include it for + // relative names. + if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) && + Entry.DirIdx < IncludeDirectories.size()) + IncludeDir = IncludeDirectories[Entry.DirIdx].getAsCString().getValue(); + } else { + if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size()) + IncludeDir = + IncludeDirectories[Entry.DirIdx - 1].getAsCString().getValue(); + } + + // For absolute paths only, include the compilation directory of compile unit. + // We know that FileName is not absolute, the only way to have an absolute + // path at this point would be if IncludeDir is absolute. + if (Kind == FileLineInfoKind::AbsoluteFilePath && !CompDir.empty() && + !isPathAbsoluteOnWindowsOrPosix(IncludeDir)) + sys::path::append(FilePath, Style, CompDir); + + assert((Kind == FileLineInfoKind::AbsoluteFilePath || + Kind == FileLineInfoKind::RelativeFilePath) && + "invalid FileLineInfo Kind"); + + // sys::path::append skips empty strings. + sys::path::append(FilePath, Style, IncludeDir, FileName); + Result = std::string(FilePath.str()); + return true; +} + +bool DWARFDebugLine::LineTable::getFileLineInfoForAddress( + object::SectionedAddress Address, const char *CompDir, + FileLineInfoKind Kind, DILineInfo &Result) const { + // Get the index of row we're looking for in the line table. + uint32_t RowIndex = lookupAddress(Address); + if (RowIndex == -1U) + return false; + // Take file number and line/column from the row. + const auto &Row = Rows[RowIndex]; + if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName)) + return false; + Result.Line = Row.Line; + Result.Column = Row.Column; + Result.Discriminator = Row.Discriminator; + Result.Source = getSourceByIndex(Row.File, Kind); + return true; +} + +// We want to supply the Unit associated with a .debug_line[.dwo] table when +// we dump it, if possible, but still dump the table even if there isn't a Unit. +// Therefore, collect up handles on all the Units that point into the +// line-table section. +static DWARFDebugLine::SectionParser::LineToUnitMap buildLineToUnitMap(DWARFUnitVector::iterator_range Units) { - DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit; + DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit; for (const auto &U : Units) if (auto CUDIE = U->getUnitDIE()) - if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) + if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) LineToUnit.insert(std::make_pair(*StmtOffset, &*U)); - return LineToUnit; -} - + return LineToUnit; +} + DWARFDebugLine::SectionParser::SectionParser( DWARFDataExtractor &Data, const DWARFContext &C, DWARFUnitVector::iterator_range Units) - : DebugLineData(Data), Context(C) { + : DebugLineData(Data), Context(C) { LineToUnit = buildLineToUnitMap(Units); - if (!DebugLineData.isValidOffset(Offset)) - Done = true; -} - -bool DWARFDebugLine::Prologue::totalLengthIsValid() const { - return TotalLength != 0u; -} - -DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext( - function_ref<void(Error)> RecoverableErrorHandler, - function_ref<void(Error)> UnrecoverableErrorHandler, raw_ostream *OS, - bool Verbose) { - assert(DebugLineData.isValidOffset(Offset) && - "parsing should have terminated"); - DWARFUnit *U = prepareToParse(Offset); - uint64_t OldOffset = Offset; - LineTable LT; - if (Error Err = LT.parse(DebugLineData, &Offset, Context, U, - RecoverableErrorHandler, OS, Verbose)) - UnrecoverableErrorHandler(std::move(Err)); - moveToNextTable(OldOffset, LT.Prologue); - return LT; -} - -void DWARFDebugLine::SectionParser::skip( - function_ref<void(Error)> RecoverableErrorHandler, - function_ref<void(Error)> UnrecoverableErrorHandler) { - assert(DebugLineData.isValidOffset(Offset) && - "parsing should have terminated"); - DWARFUnit *U = prepareToParse(Offset); - uint64_t OldOffset = Offset; - LineTable LT; - if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, - RecoverableErrorHandler, Context, U)) - UnrecoverableErrorHandler(std::move(Err)); - moveToNextTable(OldOffset, LT.Prologue); -} - -DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint64_t Offset) { - DWARFUnit *U = nullptr; - auto It = LineToUnit.find(Offset); - if (It != LineToUnit.end()) - U = It->second; - DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0); - return U; -} - -void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset, - const Prologue &P) { - // If the length field is not valid, we don't know where the next table is, so - // cannot continue to parse. Mark the parser as done, and leave the Offset - // value as it currently is. This will be the end of the bad length field. - if (!P.totalLengthIsValid()) { - Done = true; - return; - } - - Offset = OldOffset + P.TotalLength + P.sizeofTotalLength(); - if (!DebugLineData.isValidOffset(Offset)) { - Done = true; - } -} + if (!DebugLineData.isValidOffset(Offset)) + Done = true; +} + +bool DWARFDebugLine::Prologue::totalLengthIsValid() const { + return TotalLength != 0u; +} + +DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext( + function_ref<void(Error)> RecoverableErrorHandler, + function_ref<void(Error)> UnrecoverableErrorHandler, raw_ostream *OS, + bool Verbose) { + assert(DebugLineData.isValidOffset(Offset) && + "parsing should have terminated"); + DWARFUnit *U = prepareToParse(Offset); + uint64_t OldOffset = Offset; + LineTable LT; + if (Error Err = LT.parse(DebugLineData, &Offset, Context, U, + RecoverableErrorHandler, OS, Verbose)) + UnrecoverableErrorHandler(std::move(Err)); + moveToNextTable(OldOffset, LT.Prologue); + return LT; +} + +void DWARFDebugLine::SectionParser::skip( + function_ref<void(Error)> RecoverableErrorHandler, + function_ref<void(Error)> UnrecoverableErrorHandler) { + assert(DebugLineData.isValidOffset(Offset) && + "parsing should have terminated"); + DWARFUnit *U = prepareToParse(Offset); + uint64_t OldOffset = Offset; + LineTable LT; + if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, + RecoverableErrorHandler, Context, U)) + UnrecoverableErrorHandler(std::move(Err)); + moveToNextTable(OldOffset, LT.Prologue); +} + +DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint64_t Offset) { + DWARFUnit *U = nullptr; + auto It = LineToUnit.find(Offset); + if (It != LineToUnit.end()) + U = It->second; + DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0); + return U; +} + +void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset, + const Prologue &P) { + // If the length field is not valid, we don't know where the next table is, so + // cannot continue to parse. Mark the parser as done, and leave the Offset + // value as it currently is. This will be the end of the bad length field. + if (!P.totalLengthIsValid()) { + Done = true; + return; + } + + Offset = OldOffset + P.TotalLength + P.sizeofTotalLength(); + if (!DebugLineData.isValidOffset(Offset)) { + Done = true; + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index cdffb36741..f39b3a044a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -1,406 +1,406 @@ -//===- DWARFDebugLoc.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFExpression.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cinttypes> -#include <cstdint> - -using namespace llvm; -using object::SectionedAddress; - -namespace { -class DWARFLocationInterpreter { - Optional<object::SectionedAddress> Base; - std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr; - -public: - DWARFLocationInterpreter( - Optional<object::SectionedAddress> Base, - std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr) - : Base(Base), LookupAddr(std::move(LookupAddr)) {} - - Expected<Optional<DWARFLocationExpression>> - Interpret(const DWARFLocationEntry &E); -}; -} // namespace - -static Error createResolverError(uint32_t Index, unsigned Kind) { - return createStringError(errc::invalid_argument, - "Unable to resolve indirect address %u for: %s", - Index, dwarf::LocListEncodingString(Kind).data()); -} - -Expected<Optional<DWARFLocationExpression>> -DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) { - switch (E.Kind) { - case dwarf::DW_LLE_end_of_list: - return None; - case dwarf::DW_LLE_base_addressx: { - Base = LookupAddr(E.Value0); - if (!Base) - return createResolverError(E.Value0, E.Kind); - return None; - } - case dwarf::DW_LLE_startx_endx: { - Optional<SectionedAddress> LowPC = LookupAddr(E.Value0); - if (!LowPC) - return createResolverError(E.Value0, E.Kind); - Optional<SectionedAddress> HighPC = LookupAddr(E.Value1); - if (!HighPC) - return createResolverError(E.Value1, E.Kind); - return DWARFLocationExpression{ - DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex}, - E.Loc}; - } - case dwarf::DW_LLE_startx_length: { - Optional<SectionedAddress> LowPC = LookupAddr(E.Value0); - if (!LowPC) - return createResolverError(E.Value0, E.Kind); - return DWARFLocationExpression{DWARFAddressRange{LowPC->Address, - LowPC->Address + E.Value1, - LowPC->SectionIndex}, - E.Loc}; - } - case dwarf::DW_LLE_offset_pair: { - if (!Base) { - return createStringError(inconvertibleErrorCode(), - "Unable to resolve location list offset pair: " - "Base address not defined"); - } - DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1, - Base->SectionIndex}; - if (Range.SectionIndex == SectionedAddress::UndefSection) - Range.SectionIndex = E.SectionIndex; - return DWARFLocationExpression{Range, E.Loc}; - } - case dwarf::DW_LLE_default_location: - return DWARFLocationExpression{None, E.Loc}; - case dwarf::DW_LLE_base_address: - Base = SectionedAddress{E.Value0, E.SectionIndex}; - return None; - case dwarf::DW_LLE_start_end: - return DWARFLocationExpression{ - DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc}; - case dwarf::DW_LLE_start_length: - return DWARFLocationExpression{ - DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex}, - E.Loc}; - default: - llvm_unreachable("unreachable locations list kind"); - } -} - +//===- DWARFDebugLoc.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cinttypes> +#include <cstdint> + +using namespace llvm; +using object::SectionedAddress; + +namespace { +class DWARFLocationInterpreter { + Optional<object::SectionedAddress> Base; + std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr; + +public: + DWARFLocationInterpreter( + Optional<object::SectionedAddress> Base, + std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr) + : Base(Base), LookupAddr(std::move(LookupAddr)) {} + + Expected<Optional<DWARFLocationExpression>> + Interpret(const DWARFLocationEntry &E); +}; +} // namespace + +static Error createResolverError(uint32_t Index, unsigned Kind) { + return createStringError(errc::invalid_argument, + "Unable to resolve indirect address %u for: %s", + Index, dwarf::LocListEncodingString(Kind).data()); +} + +Expected<Optional<DWARFLocationExpression>> +DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) { + switch (E.Kind) { + case dwarf::DW_LLE_end_of_list: + return None; + case dwarf::DW_LLE_base_addressx: { + Base = LookupAddr(E.Value0); + if (!Base) + return createResolverError(E.Value0, E.Kind); + return None; + } + case dwarf::DW_LLE_startx_endx: { + Optional<SectionedAddress> LowPC = LookupAddr(E.Value0); + if (!LowPC) + return createResolverError(E.Value0, E.Kind); + Optional<SectionedAddress> HighPC = LookupAddr(E.Value1); + if (!HighPC) + return createResolverError(E.Value1, E.Kind); + return DWARFLocationExpression{ + DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex}, + E.Loc}; + } + case dwarf::DW_LLE_startx_length: { + Optional<SectionedAddress> LowPC = LookupAddr(E.Value0); + if (!LowPC) + return createResolverError(E.Value0, E.Kind); + return DWARFLocationExpression{DWARFAddressRange{LowPC->Address, + LowPC->Address + E.Value1, + LowPC->SectionIndex}, + E.Loc}; + } + case dwarf::DW_LLE_offset_pair: { + if (!Base) { + return createStringError(inconvertibleErrorCode(), + "Unable to resolve location list offset pair: " + "Base address not defined"); + } + DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1, + Base->SectionIndex}; + if (Range.SectionIndex == SectionedAddress::UndefSection) + Range.SectionIndex = E.SectionIndex; + return DWARFLocationExpression{Range, E.Loc}; + } + case dwarf::DW_LLE_default_location: + return DWARFLocationExpression{None, E.Loc}; + case dwarf::DW_LLE_base_address: + Base = SectionedAddress{E.Value0, E.SectionIndex}; + return None; + case dwarf::DW_LLE_start_end: + return DWARFLocationExpression{ + DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc}; + case dwarf::DW_LLE_start_length: + return DWARFLocationExpression{ + DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex}, + E.Loc}; + default: + llvm_unreachable("unreachable locations list kind"); + } +} + static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts, ArrayRef<uint8_t> Data, bool IsLittleEndian, unsigned AddressSize, const MCRegisterInfo *MRI, DWARFUnit *U) { - DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize); - // Note. We do not pass any format to DWARFExpression, even if the - // corresponding unit is known. For now, there is only one operation, - // DW_OP_call_ref, which depends on the format; it is rarely used, and - // is unexpected in location tables. + DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize); + // Note. We do not pass any format to DWARFExpression, even if the + // corresponding unit is known. For now, there is only one operation, + // DW_OP_call_ref, which depends on the format; it is rarely used, and + // is unexpected in location tables. DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, MRI, U); -} - -bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS, - Optional<SectionedAddress> BaseAddr, - const MCRegisterInfo *MRI, - const DWARFObject &Obj, DWARFUnit *U, - DIDumpOptions DumpOpts, - unsigned Indent) const { - DWARFLocationInterpreter Interp( - BaseAddr, [U](uint32_t Index) -> Optional<SectionedAddress> { - if (U) - return U->getAddrOffsetSectionItem(Index); - return None; - }); - OS << format("0x%8.8" PRIx64 ": ", *Offset); - Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) { - Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); - if (!Loc || DumpOpts.DisplayRawContents) - dumpRawEntry(E, OS, Indent, DumpOpts, Obj); - if (Loc && *Loc) { - OS << "\n"; - OS.indent(Indent); - if (DumpOpts.DisplayRawContents) - OS << " => "; - - DIDumpOptions RangeDumpOpts(DumpOpts); - RangeDumpOpts.DisplayRawContents = false; - if (Loc.get()->Range) - Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj); - else - OS << "<default>"; - } - if (!Loc) - consumeError(Loc.takeError()); - - if (E.Kind != dwarf::DW_LLE_base_address && - E.Kind != dwarf::DW_LLE_base_addressx && - E.Kind != dwarf::DW_LLE_end_of_list) { - OS << ": "; +} + +bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS, + Optional<SectionedAddress> BaseAddr, + const MCRegisterInfo *MRI, + const DWARFObject &Obj, DWARFUnit *U, + DIDumpOptions DumpOpts, + unsigned Indent) const { + DWARFLocationInterpreter Interp( + BaseAddr, [U](uint32_t Index) -> Optional<SectionedAddress> { + if (U) + return U->getAddrOffsetSectionItem(Index); + return None; + }); + OS << format("0x%8.8" PRIx64 ": ", *Offset); + Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) { + Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); + if (!Loc || DumpOpts.DisplayRawContents) + dumpRawEntry(E, OS, Indent, DumpOpts, Obj); + if (Loc && *Loc) { + OS << "\n"; + OS.indent(Indent); + if (DumpOpts.DisplayRawContents) + OS << " => "; + + DIDumpOptions RangeDumpOpts(DumpOpts); + RangeDumpOpts.DisplayRawContents = false; + if (Loc.get()->Range) + Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj); + else + OS << "<default>"; + } + if (!Loc) + consumeError(Loc.takeError()); + + if (E.Kind != dwarf::DW_LLE_base_address && + E.Kind != dwarf::DW_LLE_base_addressx && + E.Kind != dwarf::DW_LLE_end_of_list) { + OS << ": "; dumpExpression(OS, DumpOpts, E.Loc, Data.isLittleEndian(), Data.getAddressSize(), MRI, U); - } - return true; - }); - if (E) { - DumpOpts.RecoverableErrorHandler(std::move(E)); - return false; - } - return true; -} - -Error DWARFLocationTable::visitAbsoluteLocationList( - uint64_t Offset, Optional<SectionedAddress> BaseAddr, - std::function<Optional<SectionedAddress>(uint32_t)> LookupAddr, - function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const { - DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr)); - return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) { - Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); - if (!Loc) - return Callback(Loc.takeError()); - if (*Loc) - return Callback(**Loc); - return true; - }); -} - -void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, - const DWARFObject &Obj, DIDumpOptions DumpOpts, - Optional<uint64_t> DumpOffset) const { - auto BaseAddr = None; - unsigned Indent = 12; - if (DumpOffset) { - dumpLocationList(&*DumpOffset, OS, BaseAddr, MRI, Obj, nullptr, DumpOpts, - Indent); - } else { - uint64_t Offset = 0; - StringRef Separator; - bool CanContinue = true; - while (CanContinue && Data.isValidOffset(Offset)) { - OS << Separator; - Separator = "\n"; - - CanContinue = dumpLocationList(&Offset, OS, BaseAddr, MRI, Obj, nullptr, - DumpOpts, Indent); - OS << '\n'; - } - } -} - -Error DWARFDebugLoc::visitLocationList( - uint64_t *Offset, - function_ref<bool(const DWARFLocationEntry &)> Callback) const { - DataExtractor::Cursor C(*Offset); - while (true) { - uint64_t SectionIndex; - uint64_t Value0 = Data.getRelocatedAddress(C); - uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex); - - DWARFLocationEntry E; - - // The end of any given location list is marked by an end of list entry, - // which consists of a 0 for the beginning address offset and a 0 for the - // ending address offset. A beginning offset of 0xff...f marks the base - // address selection entry. - if (Value0 == 0 && Value1 == 0) { - E.Kind = dwarf::DW_LLE_end_of_list; - } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) { - E.Kind = dwarf::DW_LLE_base_address; - E.Value0 = Value1; - E.SectionIndex = SectionIndex; - } else { - E.Kind = dwarf::DW_LLE_offset_pair; - E.Value0 = Value0; - E.Value1 = Value1; - E.SectionIndex = SectionIndex; - unsigned Bytes = Data.getU16(C); - // A single location description describing the location of the object... - Data.getU8(C, E.Loc, Bytes); - } - - if (!C) - return C.takeError(); - if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list) - break; - } - *Offset = C.tell(); - return Error::success(); -} - -void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry, - raw_ostream &OS, unsigned Indent, - DIDumpOptions DumpOpts, - const DWARFObject &Obj) const { - uint64_t Value0, Value1; - switch (Entry.Kind) { - case dwarf::DW_LLE_base_address: - Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL; - Value1 = Entry.Value0; - break; - case dwarf::DW_LLE_offset_pair: - Value0 = Entry.Value0; - Value1 = Entry.Value1; - break; - case dwarf::DW_LLE_end_of_list: - return; - default: - llvm_unreachable("Not possible in DWARF4!"); - } - OS << '\n'; - OS.indent(Indent); - OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", " - << format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')'; - DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex); -} - -Error DWARFDebugLoclists::visitLocationList( - uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { - - DataExtractor::Cursor C(*Offset); - bool Continue = true; - while (Continue) { - DWARFLocationEntry E; - E.Kind = Data.getU8(C); - switch (E.Kind) { - case dwarf::DW_LLE_end_of_list: - break; - case dwarf::DW_LLE_base_addressx: - E.Value0 = Data.getULEB128(C); - break; - case dwarf::DW_LLE_startx_endx: - E.Value0 = Data.getULEB128(C); - E.Value1 = Data.getULEB128(C); - break; - case dwarf::DW_LLE_startx_length: - E.Value0 = Data.getULEB128(C); - // Pre-DWARF 5 has different interpretation of the length field. We have - // to support both pre- and standartized styles for the compatibility. - if (Version < 5) - E.Value1 = Data.getU32(C); - else - E.Value1 = Data.getULEB128(C); - break; - case dwarf::DW_LLE_offset_pair: - E.Value0 = Data.getULEB128(C); - E.Value1 = Data.getULEB128(C); - E.SectionIndex = SectionedAddress::UndefSection; - break; - case dwarf::DW_LLE_default_location: - break; - case dwarf::DW_LLE_base_address: - E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); - break; - case dwarf::DW_LLE_start_end: - E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); - E.Value1 = Data.getRelocatedAddress(C); - break; - case dwarf::DW_LLE_start_length: - E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); - E.Value1 = Data.getULEB128(C); - break; - default: - cantFail(C.takeError()); - return createStringError(errc::illegal_byte_sequence, - "LLE of kind %x not supported", (int)E.Kind); - } - - if (E.Kind != dwarf::DW_LLE_base_address && - E.Kind != dwarf::DW_LLE_base_addressx && - E.Kind != dwarf::DW_LLE_end_of_list) { - unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); - // A single location description describing the location of the object... - Data.getU8(C, E.Loc, Bytes); - } - - if (!C) - return C.takeError(); - Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; - } - *Offset = C.tell(); - return Error::success(); -} - -void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry, - raw_ostream &OS, unsigned Indent, - DIDumpOptions DumpOpts, - const DWARFObject &Obj) const { - size_t MaxEncodingStringLength = 0; -#define HANDLE_DW_LLE(ID, NAME) \ - MaxEncodingStringLength = std::max(MaxEncodingStringLength, \ - dwarf::LocListEncodingString(ID).size()); -#include "llvm/BinaryFormat/Dwarf.def" - - OS << "\n"; - OS.indent(Indent); - StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind); - // Unsupported encodings should have been reported during parsing. - assert(!EncodingString.empty() && "Unknown loclist entry encoding"); - OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data()); - unsigned FieldSize = 2 + 2 * Data.getAddressSize(); - switch (Entry.Kind) { - case dwarf::DW_LLE_end_of_list: - case dwarf::DW_LLE_default_location: - break; - case dwarf::DW_LLE_startx_endx: - case dwarf::DW_LLE_startx_length: - case dwarf::DW_LLE_offset_pair: - case dwarf::DW_LLE_start_end: - case dwarf::DW_LLE_start_length: - OS << format_hex(Entry.Value0, FieldSize) << ", " - << format_hex(Entry.Value1, FieldSize); - break; - case dwarf::DW_LLE_base_addressx: - case dwarf::DW_LLE_base_address: - OS << format_hex(Entry.Value0, FieldSize); - break; - } - OS << ')'; - switch (Entry.Kind) { - case dwarf::DW_LLE_base_address: - case dwarf::DW_LLE_start_end: - case dwarf::DW_LLE_start_length: - DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex); - break; - default: - break; - } -} - -void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, - raw_ostream &OS, const MCRegisterInfo *MRI, - const DWARFObject &Obj, - DIDumpOptions DumpOpts) { - if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) { - OS << "Invalid dump range\n"; - return; - } - uint64_t Offset = StartOffset; - StringRef Separator; - bool CanContinue = true; - while (CanContinue && Offset < StartOffset + Size) { - OS << Separator; - Separator = "\n"; - - CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, - nullptr, DumpOpts, /*Indent=*/12); - OS << '\n'; - } -} + } + return true; + }); + if (E) { + DumpOpts.RecoverableErrorHandler(std::move(E)); + return false; + } + return true; +} + +Error DWARFLocationTable::visitAbsoluteLocationList( + uint64_t Offset, Optional<SectionedAddress> BaseAddr, + std::function<Optional<SectionedAddress>(uint32_t)> LookupAddr, + function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const { + DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr)); + return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) { + Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E); + if (!Loc) + return Callback(Loc.takeError()); + if (*Loc) + return Callback(**Loc); + return true; + }); +} + +void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI, + const DWARFObject &Obj, DIDumpOptions DumpOpts, + Optional<uint64_t> DumpOffset) const { + auto BaseAddr = None; + unsigned Indent = 12; + if (DumpOffset) { + dumpLocationList(&*DumpOffset, OS, BaseAddr, MRI, Obj, nullptr, DumpOpts, + Indent); + } else { + uint64_t Offset = 0; + StringRef Separator; + bool CanContinue = true; + while (CanContinue && Data.isValidOffset(Offset)) { + OS << Separator; + Separator = "\n"; + + CanContinue = dumpLocationList(&Offset, OS, BaseAddr, MRI, Obj, nullptr, + DumpOpts, Indent); + OS << '\n'; + } + } +} + +Error DWARFDebugLoc::visitLocationList( + uint64_t *Offset, + function_ref<bool(const DWARFLocationEntry &)> Callback) const { + DataExtractor::Cursor C(*Offset); + while (true) { + uint64_t SectionIndex; + uint64_t Value0 = Data.getRelocatedAddress(C); + uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex); + + DWARFLocationEntry E; + + // The end of any given location list is marked by an end of list entry, + // which consists of a 0 for the beginning address offset and a 0 for the + // ending address offset. A beginning offset of 0xff...f marks the base + // address selection entry. + if (Value0 == 0 && Value1 == 0) { + E.Kind = dwarf::DW_LLE_end_of_list; + } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) { + E.Kind = dwarf::DW_LLE_base_address; + E.Value0 = Value1; + E.SectionIndex = SectionIndex; + } else { + E.Kind = dwarf::DW_LLE_offset_pair; + E.Value0 = Value0; + E.Value1 = Value1; + E.SectionIndex = SectionIndex; + unsigned Bytes = Data.getU16(C); + // A single location description describing the location of the object... + Data.getU8(C, E.Loc, Bytes); + } + + if (!C) + return C.takeError(); + if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list) + break; + } + *Offset = C.tell(); + return Error::success(); +} + +void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry, + raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts, + const DWARFObject &Obj) const { + uint64_t Value0, Value1; + switch (Entry.Kind) { + case dwarf::DW_LLE_base_address: + Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL; + Value1 = Entry.Value0; + break; + case dwarf::DW_LLE_offset_pair: + Value0 = Entry.Value0; + Value1 = Entry.Value1; + break; + case dwarf::DW_LLE_end_of_list: + return; + default: + llvm_unreachable("Not possible in DWARF4!"); + } + OS << '\n'; + OS.indent(Indent); + OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", " + << format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')'; + DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex); +} + +Error DWARFDebugLoclists::visitLocationList( + uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { + + DataExtractor::Cursor C(*Offset); + bool Continue = true; + while (Continue) { + DWARFLocationEntry E; + E.Kind = Data.getU8(C); + switch (E.Kind) { + case dwarf::DW_LLE_end_of_list: + break; + case dwarf::DW_LLE_base_addressx: + E.Value0 = Data.getULEB128(C); + break; + case dwarf::DW_LLE_startx_endx: + E.Value0 = Data.getULEB128(C); + E.Value1 = Data.getULEB128(C); + break; + case dwarf::DW_LLE_startx_length: + E.Value0 = Data.getULEB128(C); + // Pre-DWARF 5 has different interpretation of the length field. We have + // to support both pre- and standartized styles for the compatibility. + if (Version < 5) + E.Value1 = Data.getU32(C); + else + E.Value1 = Data.getULEB128(C); + break; + case dwarf::DW_LLE_offset_pair: + E.Value0 = Data.getULEB128(C); + E.Value1 = Data.getULEB128(C); + E.SectionIndex = SectionedAddress::UndefSection; + break; + case dwarf::DW_LLE_default_location: + break; + case dwarf::DW_LLE_base_address: + E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); + break; + case dwarf::DW_LLE_start_end: + E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); + E.Value1 = Data.getRelocatedAddress(C); + break; + case dwarf::DW_LLE_start_length: + E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex); + E.Value1 = Data.getULEB128(C); + break; + default: + cantFail(C.takeError()); + return createStringError(errc::illegal_byte_sequence, + "LLE of kind %x not supported", (int)E.Kind); + } + + if (E.Kind != dwarf::DW_LLE_base_address && + E.Kind != dwarf::DW_LLE_base_addressx && + E.Kind != dwarf::DW_LLE_end_of_list) { + unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C); + // A single location description describing the location of the object... + Data.getU8(C, E.Loc, Bytes); + } + + if (!C) + return C.takeError(); + Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; + } + *Offset = C.tell(); + return Error::success(); +} + +void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry, + raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts, + const DWARFObject &Obj) const { + size_t MaxEncodingStringLength = 0; +#define HANDLE_DW_LLE(ID, NAME) \ + MaxEncodingStringLength = std::max(MaxEncodingStringLength, \ + dwarf::LocListEncodingString(ID).size()); +#include "llvm/BinaryFormat/Dwarf.def" + + OS << "\n"; + OS.indent(Indent); + StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind); + // Unsupported encodings should have been reported during parsing. + assert(!EncodingString.empty() && "Unknown loclist entry encoding"); + OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data()); + unsigned FieldSize = 2 + 2 * Data.getAddressSize(); + switch (Entry.Kind) { + case dwarf::DW_LLE_end_of_list: + case dwarf::DW_LLE_default_location: + break; + case dwarf::DW_LLE_startx_endx: + case dwarf::DW_LLE_startx_length: + case dwarf::DW_LLE_offset_pair: + case dwarf::DW_LLE_start_end: + case dwarf::DW_LLE_start_length: + OS << format_hex(Entry.Value0, FieldSize) << ", " + << format_hex(Entry.Value1, FieldSize); + break; + case dwarf::DW_LLE_base_addressx: + case dwarf::DW_LLE_base_address: + OS << format_hex(Entry.Value0, FieldSize); + break; + } + OS << ')'; + switch (Entry.Kind) { + case dwarf::DW_LLE_base_address: + case dwarf::DW_LLE_start_end: + case dwarf::DW_LLE_start_length: + DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex); + break; + default: + break; + } +} + +void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size, + raw_ostream &OS, const MCRegisterInfo *MRI, + const DWARFObject &Obj, + DIDumpOptions DumpOpts) { + if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) { + OS << "Invalid dump range\n"; + return; + } + uint64_t Offset = StartOffset; + StringRef Separator; + bool CanContinue = true; + while (CanContinue && Offset < StartOffset + Size) { + OS << Separator; + Separator = "\n"; + + CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, + nullptr, DumpOpts, /*Indent=*/12); + OS << '\n'; + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp index 80ffd81b34..addc2a3ff2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp @@ -1,245 +1,245 @@ -//===- DWARFDebugMacro.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdint> - -using namespace llvm; -using namespace dwarf; - -DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const { - return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32; -} - -uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const { - return getDwarfOffsetByteSize(getDwarfFormat()); -} - -void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const { - // FIXME: Add support for dumping opcode_operands_table - OS << format("macro header: version = 0x%04" PRIx16, Version) - << format(", flags = 0x%02" PRIx8, Flags) - << ", format = " << FormatString(getDwarfFormat()); - if (Flags & MACRO_DEBUG_LINE_OFFSET) - OS << format(", debug_line_offset = 0x%0*" PRIx64, 2 * getOffsetByteSize(), - DebugLineOffset); - OS << "\n"; -} - -void DWARFDebugMacro::dump(raw_ostream &OS) const { - unsigned IndLevel = 0; - for (const auto &Macros : MacroLists) { - OS << format("0x%08" PRIx64 ":\n", Macros.Offset); +//===- DWARFDebugMacro.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdint> + +using namespace llvm; +using namespace dwarf; + +DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const { + return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32; +} + +uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const { + return getDwarfOffsetByteSize(getDwarfFormat()); +} + +void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const { + // FIXME: Add support for dumping opcode_operands_table + OS << format("macro header: version = 0x%04" PRIx16, Version) + << format(", flags = 0x%02" PRIx8, Flags) + << ", format = " << FormatString(getDwarfFormat()); + if (Flags & MACRO_DEBUG_LINE_OFFSET) + OS << format(", debug_line_offset = 0x%0*" PRIx64, 2 * getOffsetByteSize(), + DebugLineOffset); + OS << "\n"; +} + +void DWARFDebugMacro::dump(raw_ostream &OS) const { + unsigned IndLevel = 0; + for (const auto &Macros : MacroLists) { + OS << format("0x%08" PRIx64 ":\n", Macros.Offset); if (Macros.IsDebugMacro) - Macros.Header.dumpMacroHeader(OS); - for (const Entry &E : Macros.Macros) { - // There should not be DW_MACINFO_end_file when IndLevel is Zero. However, - // this check handles the case of corrupted ".debug_macinfo" section. - if (IndLevel > 0) - IndLevel -= (E.Type == DW_MACINFO_end_file); - // Print indentation. - for (unsigned I = 0; I < IndLevel; I++) - OS << " "; - IndLevel += (E.Type == DW_MACINFO_start_file); - // Based on which version we are handling choose appropriate macro forms. + Macros.Header.dumpMacroHeader(OS); + for (const Entry &E : Macros.Macros) { + // There should not be DW_MACINFO_end_file when IndLevel is Zero. However, + // this check handles the case of corrupted ".debug_macinfo" section. + if (IndLevel > 0) + IndLevel -= (E.Type == DW_MACINFO_end_file); + // Print indentation. + for (unsigned I = 0; I < IndLevel; I++) + OS << " "; + IndLevel += (E.Type == DW_MACINFO_start_file); + // Based on which version we are handling choose appropriate macro forms. if (Macros.IsDebugMacro) WithColor(OS, HighlightColor::Macro).get() << (Macros.Header.Version < 5 ? GnuMacroString(E.Type) : MacroString(E.Type)); - else - WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); - switch (E.Type) { - default: - // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid - // macinfo type). - break; - // debug_macro and debug_macinfo share some common encodings. - // DW_MACRO_define == DW_MACINFO_define - // DW_MACRO_undef == DW_MACINFO_undef - // DW_MACRO_start_file == DW_MACINFO_start_file - // DW_MACRO_end_file == DW_MACINFO_end_file - // For readability/uniformity we are using DW_MACRO_*. + else + WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type); + switch (E.Type) { + default: + // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid + // macinfo type). + break; + // debug_macro and debug_macinfo share some common encodings. + // DW_MACRO_define == DW_MACINFO_define + // DW_MACRO_undef == DW_MACINFO_undef + // DW_MACRO_start_file == DW_MACINFO_start_file + // DW_MACRO_end_file == DW_MACINFO_end_file + // For readability/uniformity we are using DW_MACRO_*. // // The GNU .debug_macro extension's entries have the same encoding // as DWARF 5's DW_MACRO_* entries, so we only use the latter here. - case DW_MACRO_define: - case DW_MACRO_undef: - case DW_MACRO_define_strp: - case DW_MACRO_undef_strp: - case DW_MACRO_define_strx: - case DW_MACRO_undef_strx: - OS << " - lineno: " << E.Line; - OS << " macro: " << E.MacroStr; - break; - case DW_MACRO_start_file: - OS << " - lineno: " << E.Line; - OS << " filenum: " << E.File; - break; - case DW_MACRO_import: - OS << format(" - import offset: 0x%0*" PRIx64, - 2 * Macros.Header.getOffsetByteSize(), E.ImportOffset); - break; - case DW_MACRO_end_file: - break; - case DW_MACINFO_vendor_ext: - OS << " - constant: " << E.ExtConstant; - OS << " string: " << E.ExtStr; - break; - } - OS << "\n"; - } - } -} - -Error DWARFDebugMacro::parseImpl( + case DW_MACRO_define: + case DW_MACRO_undef: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: + case DW_MACRO_define_strx: + case DW_MACRO_undef_strx: + OS << " - lineno: " << E.Line; + OS << " macro: " << E.MacroStr; + break; + case DW_MACRO_start_file: + OS << " - lineno: " << E.Line; + OS << " filenum: " << E.File; + break; + case DW_MACRO_import: + OS << format(" - import offset: 0x%0*" PRIx64, + 2 * Macros.Header.getOffsetByteSize(), E.ImportOffset); + break; + case DW_MACRO_end_file: + break; + case DW_MACINFO_vendor_ext: + OS << " - constant: " << E.ExtConstant; + OS << " string: " << E.ExtStr; + break; + } + OS << "\n"; + } + } +} + +Error DWARFDebugMacro::parseImpl( Optional<DWARFUnitVector::compile_unit_range> Units, - Optional<DataExtractor> StringExtractor, DWARFDataExtractor Data, - bool IsMacro) { - uint64_t Offset = 0; - MacroList *M = nullptr; - using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>; - MacroToUnitsMap MacroToUnits; - if (IsMacro && Data.isValidOffset(Offset)) { - // Keep a mapping from Macro contribution to CUs, this will - // be needed while retrieving macro from DW_MACRO_define_strx form. - for (const auto &U : Units.getValue()) - if (auto CUDIE = U->getUnitDIE()) - // Skip units which does not contibutes to macro section. - if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros))) - MacroToUnits.try_emplace(*MacroOffset, U.get()); - } - while (Data.isValidOffset(Offset)) { - if (!M) { - MacroLists.emplace_back(); - M = &MacroLists.back(); - M->Offset = Offset; + Optional<DataExtractor> StringExtractor, DWARFDataExtractor Data, + bool IsMacro) { + uint64_t Offset = 0; + MacroList *M = nullptr; + using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>; + MacroToUnitsMap MacroToUnits; + if (IsMacro && Data.isValidOffset(Offset)) { + // Keep a mapping from Macro contribution to CUs, this will + // be needed while retrieving macro from DW_MACRO_define_strx form. + for (const auto &U : Units.getValue()) + if (auto CUDIE = U->getUnitDIE()) + // Skip units which does not contibutes to macro section. + if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros))) + MacroToUnits.try_emplace(*MacroOffset, U.get()); + } + while (Data.isValidOffset(Offset)) { + if (!M) { + MacroLists.emplace_back(); + M = &MacroLists.back(); + M->Offset = Offset; M->IsDebugMacro = IsMacro; - if (IsMacro) { - auto Err = M->Header.parseMacroHeader(Data, &Offset); - if (Err) - return Err; - } - } - // A macro list entry consists of: - M->Macros.emplace_back(); - Entry &E = M->Macros.back(); - // 1. Macinfo type - E.Type = Data.getULEB128(&Offset); - - if (E.Type == 0) { - // Reached end of a ".debug_macinfo/debug_macro" section contribution. - M = nullptr; - continue; - } - - switch (E.Type) { - default: - // Got a corrupted ".debug_macinfo" section (invalid macinfo type). - // Push the corrupted entry to the list and halt parsing. - E.Type = DW_MACINFO_invalid; - return Error::success(); - // debug_macro and debug_macinfo share some common encodings. - // DW_MACRO_define == DW_MACINFO_define - // DW_MACRO_undef == DW_MACINFO_undef - // DW_MACRO_start_file == DW_MACINFO_start_file - // DW_MACRO_end_file == DW_MACINFO_end_file - // For readibility/uniformity we are using DW_MACRO_*. - case DW_MACRO_define: - case DW_MACRO_undef: - // 2. Source line - E.Line = Data.getULEB128(&Offset); - // 3. Macro string - E.MacroStr = Data.getCStr(&Offset); - break; - case DW_MACRO_define_strp: - case DW_MACRO_undef_strp: { - if (!IsMacro) { - // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is - // not supported in debug_macinfo[.dwo] sections. Assume it as an - // invalid entry, push it and halt parsing. - E.Type = DW_MACINFO_invalid; - return Error::success(); - } - uint64_t StrOffset = 0; - // 2. Source line - E.Line = Data.getULEB128(&Offset); - // 3. Macro string - StrOffset = - Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset); - assert(StringExtractor && "String Extractor not found"); - E.MacroStr = StringExtractor->getCStr(&StrOffset); - break; - } - case DW_MACRO_define_strx: - case DW_MACRO_undef_strx: { - if (!IsMacro) { - // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is - // not supported in debug_macinfo[.dwo] sections. Assume it as an - // invalid entry, push it and halt parsing. - E.Type = DW_MACINFO_invalid; - return Error::success(); - } - E.Line = Data.getULEB128(&Offset); - auto MacroContributionOffset = MacroToUnits.find(M->Offset); - if (MacroContributionOffset == MacroToUnits.end()) - return createStringError(errc::invalid_argument, - "Macro contribution of the unit not found"); - Optional<uint64_t> StrOffset = - MacroContributionOffset->second->getStringOffsetSectionItem( - Data.getULEB128(&Offset)); - if (!StrOffset) - return createStringError( - errc::invalid_argument, - "String offsets contribution of the unit not found"); - E.MacroStr = - MacroContributionOffset->second->getStringExtractor().getCStr( - &*StrOffset); - break; - } - case DW_MACRO_start_file: - // 2. Source line - E.Line = Data.getULEB128(&Offset); - // 3. Source file id - E.File = Data.getULEB128(&Offset); - break; - case DW_MACRO_end_file: - break; - case DW_MACRO_import: - E.ImportOffset = - Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset); - break; - case DW_MACINFO_vendor_ext: - // 2. Vendor extension constant - E.ExtConstant = Data.getULEB128(&Offset); - // 3. Vendor extension string - E.ExtStr = Data.getCStr(&Offset); - break; - } - } - return Error::success(); -} - -Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data, - uint64_t *Offset) { - Version = Data.getU16(Offset); - uint8_t FlagData = Data.getU8(Offset); - - // FIXME: Add support for parsing opcode_operands_table - if (FlagData & MACRO_OPCODE_OPERANDS_TABLE) - return createStringError(errc::not_supported, - "opcode_operands_table is not supported"); - Flags = FlagData; - if (Flags & MACRO_DEBUG_LINE_OFFSET) - DebugLineOffset = Data.getUnsigned(Offset, getOffsetByteSize()); - return Error::success(); -} + if (IsMacro) { + auto Err = M->Header.parseMacroHeader(Data, &Offset); + if (Err) + return Err; + } + } + // A macro list entry consists of: + M->Macros.emplace_back(); + Entry &E = M->Macros.back(); + // 1. Macinfo type + E.Type = Data.getULEB128(&Offset); + + if (E.Type == 0) { + // Reached end of a ".debug_macinfo/debug_macro" section contribution. + M = nullptr; + continue; + } + + switch (E.Type) { + default: + // Got a corrupted ".debug_macinfo" section (invalid macinfo type). + // Push the corrupted entry to the list and halt parsing. + E.Type = DW_MACINFO_invalid; + return Error::success(); + // debug_macro and debug_macinfo share some common encodings. + // DW_MACRO_define == DW_MACINFO_define + // DW_MACRO_undef == DW_MACINFO_undef + // DW_MACRO_start_file == DW_MACINFO_start_file + // DW_MACRO_end_file == DW_MACINFO_end_file + // For readibility/uniformity we are using DW_MACRO_*. + case DW_MACRO_define: + case DW_MACRO_undef: + // 2. Source line + E.Line = Data.getULEB128(&Offset); + // 3. Macro string + E.MacroStr = Data.getCStr(&Offset); + break; + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: { + if (!IsMacro) { + // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is + // not supported in debug_macinfo[.dwo] sections. Assume it as an + // invalid entry, push it and halt parsing. + E.Type = DW_MACINFO_invalid; + return Error::success(); + } + uint64_t StrOffset = 0; + // 2. Source line + E.Line = Data.getULEB128(&Offset); + // 3. Macro string + StrOffset = + Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset); + assert(StringExtractor && "String Extractor not found"); + E.MacroStr = StringExtractor->getCStr(&StrOffset); + break; + } + case DW_MACRO_define_strx: + case DW_MACRO_undef_strx: { + if (!IsMacro) { + // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is + // not supported in debug_macinfo[.dwo] sections. Assume it as an + // invalid entry, push it and halt parsing. + E.Type = DW_MACINFO_invalid; + return Error::success(); + } + E.Line = Data.getULEB128(&Offset); + auto MacroContributionOffset = MacroToUnits.find(M->Offset); + if (MacroContributionOffset == MacroToUnits.end()) + return createStringError(errc::invalid_argument, + "Macro contribution of the unit not found"); + Optional<uint64_t> StrOffset = + MacroContributionOffset->second->getStringOffsetSectionItem( + Data.getULEB128(&Offset)); + if (!StrOffset) + return createStringError( + errc::invalid_argument, + "String offsets contribution of the unit not found"); + E.MacroStr = + MacroContributionOffset->second->getStringExtractor().getCStr( + &*StrOffset); + break; + } + case DW_MACRO_start_file: + // 2. Source line + E.Line = Data.getULEB128(&Offset); + // 3. Source file id + E.File = Data.getULEB128(&Offset); + break; + case DW_MACRO_end_file: + break; + case DW_MACRO_import: + E.ImportOffset = + Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset); + break; + case DW_MACINFO_vendor_ext: + // 2. Vendor extension constant + E.ExtConstant = Data.getULEB128(&Offset); + // 3. Vendor extension string + E.ExtStr = Data.getCStr(&Offset); + break; + } + } + return Error::success(); +} + +Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data, + uint64_t *Offset) { + Version = Data.getU16(Offset); + uint8_t FlagData = Data.getU8(Offset); + + // FIXME: Add support for parsing opcode_operands_table + if (FlagData & MACRO_OPCODE_OPERANDS_TABLE) + return createStringError(errc::not_supported, + "opcode_operands_table is not supported"); + Flags = FlagData; + if (Flags & MACRO_DEBUG_LINE_OFFSET) + DebugLineOffset = Data.getUnsigned(Offset, getOffsetByteSize()); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp index 5031acdb54..f8e4e9ffcf 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp @@ -1,118 +1,118 @@ -//===- DWARFDebugPubTable.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" -#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdint> - -using namespace llvm; -using namespace dwarf; - -void DWARFDebugPubTable::extract( - DWARFDataExtractor Data, bool GnuStyle, - function_ref<void(Error)> RecoverableErrorHandler) { - this->GnuStyle = GnuStyle; - Sets.clear(); - uint64_t Offset = 0; - while (Data.isValidOffset(Offset)) { - uint64_t SetOffset = Offset; - Sets.push_back({}); - Set &NewSet = Sets.back(); - - DataExtractor::Cursor C(Offset); - std::tie(NewSet.Length, NewSet.Format) = Data.getInitialLength(C); - if (!C) { - // Drop the newly added set because it does not contain anything useful - // to dump. - Sets.pop_back(); - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", - SetOffset, toString(C.takeError()).c_str())); - return; - } - - Offset = C.tell() + NewSet.Length; - DWARFDataExtractor SetData(Data, Offset); - const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(NewSet.Format); - - NewSet.Version = SetData.getU16(C); - NewSet.Offset = SetData.getRelocatedValue(C, OffsetSize); - NewSet.Size = SetData.getUnsigned(C, OffsetSize); - - if (!C) { - // Preserve the newly added set because at least some fields of the header - // are read and can be dumped. - RecoverableErrorHandler( - createStringError(errc::invalid_argument, - "name lookup table at offset 0x%" PRIx64 - " does not have a complete header: %s", - SetOffset, toString(C.takeError()).c_str())); - continue; - } - - while (C) { - uint64_t DieRef = SetData.getUnsigned(C, OffsetSize); - if (DieRef == 0) - break; - uint8_t IndexEntryValue = GnuStyle ? SetData.getU8(C) : 0; - StringRef Name = SetData.getCStrRef(C); - if (C) - NewSet.Entries.push_back( - {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name}); - } - - if (!C) { - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", - SetOffset, toString(C.takeError()).c_str())); - continue; - } - if (C.tell() != Offset) - RecoverableErrorHandler(createStringError( - errc::invalid_argument, - "name lookup table at offset 0x%" PRIx64 - " has a terminator at offset 0x%" PRIx64 - " before the expected end at 0x%" PRIx64, - SetOffset, C.tell() - OffsetSize, Offset - OffsetSize)); - } -} - -void DWARFDebugPubTable::dump(raw_ostream &OS) const { - for (const Set &S : Sets) { - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(S.Format); - OS << "length = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Length); - OS << ", format = " << dwarf::FormatString(S.Format); - OS << ", version = " << format("0x%04x", S.Version); - OS << ", unit_offset = " - << format("0x%0*" PRIx64, OffsetDumpWidth, S.Offset); - OS << ", unit_size = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Size) - << '\n'; - OS << (GnuStyle ? "Offset Linkage Kind Name\n" - : "Offset Name\n"); - - for (const Entry &E : S.Entries) { - OS << format("0x%0*" PRIx64 " ", OffsetDumpWidth, E.SecOffset); - if (GnuStyle) { - StringRef EntryLinkage = - GDBIndexEntryLinkageString(E.Descriptor.Linkage); - StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind); - OS << format("%-8s", EntryLinkage.data()) << ' ' - << format("%-8s", EntryKind.data()) << ' '; - } - OS << '\"' << E.Name << "\"\n"; - } - } -} +//===- DWARFDebugPubTable.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdint> + +using namespace llvm; +using namespace dwarf; + +void DWARFDebugPubTable::extract( + DWARFDataExtractor Data, bool GnuStyle, + function_ref<void(Error)> RecoverableErrorHandler) { + this->GnuStyle = GnuStyle; + Sets.clear(); + uint64_t Offset = 0; + while (Data.isValidOffset(Offset)) { + uint64_t SetOffset = Offset; + Sets.push_back({}); + Set &NewSet = Sets.back(); + + DataExtractor::Cursor C(Offset); + std::tie(NewSet.Length, NewSet.Format) = Data.getInitialLength(C); + if (!C) { + // Drop the newly added set because it does not contain anything useful + // to dump. + Sets.pop_back(); + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", + SetOffset, toString(C.takeError()).c_str())); + return; + } + + Offset = C.tell() + NewSet.Length; + DWARFDataExtractor SetData(Data, Offset); + const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(NewSet.Format); + + NewSet.Version = SetData.getU16(C); + NewSet.Offset = SetData.getRelocatedValue(C, OffsetSize); + NewSet.Size = SetData.getUnsigned(C, OffsetSize); + + if (!C) { + // Preserve the newly added set because at least some fields of the header + // are read and can be dumped. + RecoverableErrorHandler( + createStringError(errc::invalid_argument, + "name lookup table at offset 0x%" PRIx64 + " does not have a complete header: %s", + SetOffset, toString(C.takeError()).c_str())); + continue; + } + + while (C) { + uint64_t DieRef = SetData.getUnsigned(C, OffsetSize); + if (DieRef == 0) + break; + uint8_t IndexEntryValue = GnuStyle ? SetData.getU8(C) : 0; + StringRef Name = SetData.getCStrRef(C); + if (C) + NewSet.Entries.push_back( + {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name}); + } + + if (!C) { + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "name lookup table at offset 0x%" PRIx64 " parsing failed: %s", + SetOffset, toString(C.takeError()).c_str())); + continue; + } + if (C.tell() != Offset) + RecoverableErrorHandler(createStringError( + errc::invalid_argument, + "name lookup table at offset 0x%" PRIx64 + " has a terminator at offset 0x%" PRIx64 + " before the expected end at 0x%" PRIx64, + SetOffset, C.tell() - OffsetSize, Offset - OffsetSize)); + } +} + +void DWARFDebugPubTable::dump(raw_ostream &OS) const { + for (const Set &S : Sets) { + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(S.Format); + OS << "length = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Length); + OS << ", format = " << dwarf::FormatString(S.Format); + OS << ", version = " << format("0x%04x", S.Version); + OS << ", unit_offset = " + << format("0x%0*" PRIx64, OffsetDumpWidth, S.Offset); + OS << ", unit_size = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Size) + << '\n'; + OS << (GnuStyle ? "Offset Linkage Kind Name\n" + : "Offset Name\n"); + + for (const Entry &E : S.Entries) { + OS << format("0x%0*" PRIx64 " ", OffsetDumpWidth, E.SecOffset); + if (GnuStyle) { + StringRef EntryLinkage = + 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/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp index dc7da5d934..f9464af237 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -1,102 +1,102 @@ -//===- DWARFDebugRangesList.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cinttypes> -#include <cstdint> - -using namespace llvm; - -void DWARFDebugRangeList::clear() { - Offset = -1ULL; - AddressSize = 0; - Entries.clear(); -} - -Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data, - uint64_t *offset_ptr) { - clear(); - if (!data.isValidOffset(*offset_ptr)) - return createStringError(errc::invalid_argument, - "invalid range list offset 0x%" PRIx64, *offset_ptr); - - AddressSize = data.getAddressSize(); - if (AddressSize != 4 && AddressSize != 8) - return createStringError(errc::invalid_argument, - "invalid address size: %" PRIu8, AddressSize); - Offset = *offset_ptr; - while (true) { - RangeListEntry Entry; - Entry.SectionIndex = -1ULL; - - uint64_t prev_offset = *offset_ptr; - Entry.StartAddress = data.getRelocatedAddress(offset_ptr); - Entry.EndAddress = - data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex); - - // Check that both values were extracted correctly. - if (*offset_ptr != prev_offset + 2 * AddressSize) { - clear(); - return createStringError(errc::invalid_argument, - "invalid range list entry at offset 0x%" PRIx64, - prev_offset); - } - if (Entry.isEndOfListEntry()) - break; - Entries.push_back(Entry); - } - return Error::success(); -} - -void DWARFDebugRangeList::dump(raw_ostream &OS) const { - for (const RangeListEntry &RLE : Entries) { - const char *format_str = - (AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n" - : "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n"); - OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress); - } - OS << format("%08" PRIx64 " <End of list>\n", Offset); -} - -DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges( - llvm::Optional<object::SectionedAddress> BaseAddr) const { - DWARFAddressRangesVector Res; +//===- DWARFDebugRangesList.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> + +using namespace llvm; + +void DWARFDebugRangeList::clear() { + Offset = -1ULL; + AddressSize = 0; + Entries.clear(); +} + +Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data, + uint64_t *offset_ptr) { + clear(); + if (!data.isValidOffset(*offset_ptr)) + return createStringError(errc::invalid_argument, + "invalid range list offset 0x%" PRIx64, *offset_ptr); + + AddressSize = data.getAddressSize(); + if (AddressSize != 4 && AddressSize != 8) + return createStringError(errc::invalid_argument, + "invalid address size: %" PRIu8, AddressSize); + Offset = *offset_ptr; + while (true) { + RangeListEntry Entry; + Entry.SectionIndex = -1ULL; + + uint64_t prev_offset = *offset_ptr; + Entry.StartAddress = data.getRelocatedAddress(offset_ptr); + Entry.EndAddress = + data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex); + + // Check that both values were extracted correctly. + if (*offset_ptr != prev_offset + 2 * AddressSize) { + clear(); + return createStringError(errc::invalid_argument, + "invalid range list entry at offset 0x%" PRIx64, + prev_offset); + } + if (Entry.isEndOfListEntry()) + break; + Entries.push_back(Entry); + } + return Error::success(); +} + +void DWARFDebugRangeList::dump(raw_ostream &OS) const { + for (const RangeListEntry &RLE : Entries) { + const char *format_str = + (AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n" + : "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n"); + OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress); + } + OS << format("%08" PRIx64 " <End of list>\n", Offset); +} + +DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges( + llvm::Optional<object::SectionedAddress> BaseAddr) const { + DWARFAddressRangesVector Res; // debug_addr can't use the max integer tombstone because that's used for the // base address specifier entry - so use max-1. uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1; - for (const RangeListEntry &RLE : Entries) { - if (RLE.isBaseAddressSelectionEntry(AddressSize)) { - BaseAddr = {RLE.EndAddress, RLE.SectionIndex}; - continue; - } - - DWARFAddressRange E; - E.LowPC = RLE.StartAddress; + for (const RangeListEntry &RLE : Entries) { + if (RLE.isBaseAddressSelectionEntry(AddressSize)) { + BaseAddr = {RLE.EndAddress, RLE.SectionIndex}; + continue; + } + + DWARFAddressRange E; + E.LowPC = RLE.StartAddress; if (E.LowPC == Tombstone) continue; - E.HighPC = RLE.EndAddress; - E.SectionIndex = RLE.SectionIndex; - // Base address of a range list entry is determined by the closest preceding - // base address selection entry in the same range list. It defaults to the - // base address of the compilation unit if there is no such entry. - if (BaseAddr) { + E.HighPC = RLE.EndAddress; + E.SectionIndex = RLE.SectionIndex; + // Base address of a range list entry is determined by the closest preceding + // base address selection entry in the same range list. It defaults to the + // base address of the compilation unit if there is no such entry. + if (BaseAddr) { if (BaseAddr->Address == Tombstone) continue; - E.LowPC += BaseAddr->Address; - E.HighPC += BaseAddr->Address; - if (E.SectionIndex == -1ULL) - E.SectionIndex = BaseAddr->SectionIndex; - } - Res.push_back(E); - } - return Res; -} + E.LowPC += BaseAddr->Address; + E.HighPC += BaseAddr->Address; + if (E.SectionIndex == -1ULL) + E.SectionIndex = BaseAddr->SectionIndex; + } + Res.push_back(E); + } + return Res; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp index d12acca196..fece448bb8 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -1,77 +1,77 @@ -//===- DWARFDebugRnglists.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" -#include "llvm/BinaryFormat/Dwarf.h" +//===- DWARFDebugRnglists.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) { - Offset = *OffsetPtr; - SectionIndex = -1ULL; - // The caller should guarantee that we have at least 1 byte available, so - // we just assert instead of revalidate. + Offset = *OffsetPtr; + SectionIndex = -1ULL; + // The caller should guarantee that we have at least 1 byte available, so + // we just assert instead of revalidate. assert(*OffsetPtr < Data.size() && - "not enough space to extract a rangelist encoding"); - uint8_t Encoding = Data.getU8(OffsetPtr); - + "not enough space to extract a rangelist encoding"); + uint8_t Encoding = Data.getU8(OffsetPtr); + DataExtractor::Cursor C(*OffsetPtr); - switch (Encoding) { - case dwarf::DW_RLE_end_of_list: - Value0 = Value1 = 0; - break; - // TODO: Support other encodings. - case dwarf::DW_RLE_base_addressx: { + switch (Encoding) { + case dwarf::DW_RLE_end_of_list: + Value0 = Value1 = 0; + break; + // TODO: Support other encodings. + case dwarf::DW_RLE_base_addressx: { Value0 = Data.getULEB128(C); - break; - } - case dwarf::DW_RLE_startx_endx: + break; + } + case dwarf::DW_RLE_startx_endx: Value0 = Data.getULEB128(C); Value1 = Data.getULEB128(C); break; - case dwarf::DW_RLE_startx_length: { + case dwarf::DW_RLE_startx_length: { Value0 = Data.getULEB128(C); Value1 = Data.getULEB128(C); - break; - } - case dwarf::DW_RLE_offset_pair: { + break; + } + case dwarf::DW_RLE_offset_pair: { Value0 = Data.getULEB128(C); Value1 = Data.getULEB128(C); - break; - } - case dwarf::DW_RLE_base_address: { + break; + } + case dwarf::DW_RLE_base_address: { Value0 = Data.getRelocatedAddress(C, &SectionIndex); - break; - } - case dwarf::DW_RLE_start_end: { + break; + } + case dwarf::DW_RLE_start_end: { Value0 = Data.getRelocatedAddress(C, &SectionIndex); Value1 = Data.getRelocatedAddress(C); - break; - } - case dwarf::DW_RLE_start_length: { + break; + } + case dwarf::DW_RLE_start_length: { Value0 = Data.getRelocatedAddress(C, &SectionIndex); Value1 = Data.getULEB128(C); - break; - } - default: + break; + } + default: consumeError(C.takeError()); - return createStringError(errc::not_supported, + return createStringError(errc::not_supported, "unknown rnglists encoding 0x%" PRIx32 " at offset 0x%" PRIx64, uint32_t(Encoding), Offset); - } - + } + if (!C) { consumeError(C.takeError()); return createStringError( @@ -81,72 +81,72 @@ Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) { } *OffsetPtr = C.tell(); - EntryKind = Encoding; - return Error::success(); -} - -DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( - llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const { + EntryKind = Encoding; + return Error::success(); +} + +DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( + llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const { return getAbsoluteRanges( BaseAddr, U.getAddressByteSize(), [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); }); -} - -DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( +} + +DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( Optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize, - function_ref<Optional<object::SectionedAddress>(uint32_t)> - LookupPooledAddress) const { - DWARFAddressRangesVector Res; + function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress) const { + DWARFAddressRangesVector Res; uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize); - for (const RangeListEntry &RLE : Entries) { - if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) - break; - if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) { - BaseAddr = LookupPooledAddress(RLE.Value0); - if (!BaseAddr) - BaseAddr = {RLE.Value0, -1ULL}; - continue; - } - if (RLE.EntryKind == dwarf::DW_RLE_base_address) { - BaseAddr = {RLE.Value0, RLE.SectionIndex}; - continue; - } - - DWARFAddressRange E; - E.SectionIndex = RLE.SectionIndex; - if (BaseAddr && E.SectionIndex == -1ULL) - E.SectionIndex = BaseAddr->SectionIndex; - - switch (RLE.EntryKind) { - case dwarf::DW_RLE_offset_pair: - E.LowPC = RLE.Value0; + for (const RangeListEntry &RLE : Entries) { + if (RLE.EntryKind == dwarf::DW_RLE_end_of_list) + break; + if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) { + BaseAddr = LookupPooledAddress(RLE.Value0); + if (!BaseAddr) + BaseAddr = {RLE.Value0, -1ULL}; + continue; + } + if (RLE.EntryKind == dwarf::DW_RLE_base_address) { + BaseAddr = {RLE.Value0, RLE.SectionIndex}; + continue; + } + + DWARFAddressRange E; + E.SectionIndex = RLE.SectionIndex; + if (BaseAddr && E.SectionIndex == -1ULL) + E.SectionIndex = BaseAddr->SectionIndex; + + switch (RLE.EntryKind) { + case dwarf::DW_RLE_offset_pair: + E.LowPC = RLE.Value0; if (E.LowPC == Tombstone) continue; - E.HighPC = RLE.Value1; - if (BaseAddr) { + E.HighPC = RLE.Value1; + if (BaseAddr) { if (BaseAddr->Address == Tombstone) continue; - E.LowPC += BaseAddr->Address; - E.HighPC += BaseAddr->Address; - } - break; - case dwarf::DW_RLE_start_end: - E.LowPC = RLE.Value0; - E.HighPC = RLE.Value1; - break; - case dwarf::DW_RLE_start_length: - E.LowPC = RLE.Value0; - E.HighPC = E.LowPC + RLE.Value1; - break; - case dwarf::DW_RLE_startx_length: { - auto Start = LookupPooledAddress(RLE.Value0); - if (!Start) - Start = {0, -1ULL}; - E.SectionIndex = Start->SectionIndex; - E.LowPC = Start->Address; - E.HighPC = E.LowPC + RLE.Value1; - break; - } + E.LowPC += BaseAddr->Address; + E.HighPC += BaseAddr->Address; + } + break; + case dwarf::DW_RLE_start_end: + E.LowPC = RLE.Value0; + E.HighPC = RLE.Value1; + break; + case dwarf::DW_RLE_start_length: + E.LowPC = RLE.Value0; + E.HighPC = E.LowPC + RLE.Value1; + break; + case dwarf::DW_RLE_startx_length: { + auto Start = LookupPooledAddress(RLE.Value0); + if (!Start) + Start = {0, -1ULL}; + E.SectionIndex = Start->SectionIndex; + E.LowPC = Start->Address; + E.HighPC = E.LowPC + RLE.Value1; + break; + } case dwarf::DW_RLE_startx_endx: { auto Start = LookupPooledAddress(RLE.Value0); if (!Start) @@ -160,91 +160,91 @@ DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges( E.HighPC = End->Address; break; } - default: - // Unsupported encodings should have been reported during extraction, - // so we should not run into any here. - llvm_unreachable("Unsupported range list encoding"); - } + default: + // Unsupported encodings should have been reported during extraction, + // so we should not run into any here. + llvm_unreachable("Unsupported range list encoding"); + } if (E.LowPC == Tombstone) continue; - Res.push_back(E); - } - return Res; -} - -void RangeListEntry::dump( - raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, - uint64_t &CurrentBase, DIDumpOptions DumpOpts, - llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> - LookupPooledAddress) const { - auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, - uint8_t AddrSize, DIDumpOptions DumpOpts) { - if (DumpOpts.Verbose) { - DumpOpts.DisplayRawContents = true; - DWARFAddressRange(Entry.Value0, Entry.Value1) - .dump(OS, AddrSize, DumpOpts); - OS << " => "; - } - }; - - if (DumpOpts.Verbose) { - // Print the section offset in verbose mode. - OS << format("0x%8.8" PRIx64 ":", Offset); - auto EncodingString = dwarf::RangeListEncodingString(EntryKind); - // Unsupported encodings should have been reported during parsing. - assert(!EncodingString.empty() && "Unknown range entry encoding"); - OS << format(" [%s%*c", EncodingString.data(), - MaxEncodingStringLength - EncodingString.size() + 1, ']'); - if (EntryKind != dwarf::DW_RLE_end_of_list) - OS << ": "; - } - + Res.push_back(E); + } + return Res; +} + +void RangeListEntry::dump( + raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength, + uint64_t &CurrentBase, DIDumpOptions DumpOpts, + llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)> + LookupPooledAddress) const { + auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry, + uint8_t AddrSize, DIDumpOptions DumpOpts) { + if (DumpOpts.Verbose) { + DumpOpts.DisplayRawContents = true; + DWARFAddressRange(Entry.Value0, Entry.Value1) + .dump(OS, AddrSize, DumpOpts); + OS << " => "; + } + }; + + if (DumpOpts.Verbose) { + // Print the section offset in verbose mode. + OS << format("0x%8.8" PRIx64 ":", Offset); + auto EncodingString = dwarf::RangeListEncodingString(EntryKind); + // Unsupported encodings should have been reported during parsing. + assert(!EncodingString.empty() && "Unknown range entry encoding"); + OS << format(" [%s%*c", EncodingString.data(), + MaxEncodingStringLength - EncodingString.size() + 1, ']'); + if (EntryKind != dwarf::DW_RLE_end_of_list) + OS << ": "; + } + uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize); - switch (EntryKind) { - case dwarf::DW_RLE_end_of_list: - OS << (DumpOpts.Verbose ? "" : "<End of list>"); - break; - case dwarf::DW_RLE_base_addressx: { - if (auto SA = LookupPooledAddress(Value0)) - CurrentBase = SA->Address; - else - CurrentBase = Value0; - if (!DumpOpts.Verbose) - return; + switch (EntryKind) { + case dwarf::DW_RLE_end_of_list: + OS << (DumpOpts.Verbose ? "" : "<End of list>"); + break; + case dwarf::DW_RLE_base_addressx: { + if (auto SA = LookupPooledAddress(Value0)) + CurrentBase = SA->Address; + else + CurrentBase = Value0; + if (!DumpOpts.Verbose) + return; DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0); - break; - } - case dwarf::DW_RLE_base_address: - // In non-verbose mode we do not print anything for this entry. - CurrentBase = Value0; - if (!DumpOpts.Verbose) - return; + break; + } + case dwarf::DW_RLE_base_address: + // In non-verbose mode we do not print anything for this entry. + CurrentBase = Value0; + if (!DumpOpts.Verbose) + return; DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0); - break; - case dwarf::DW_RLE_start_length: - PrintRawEntry(OS, *this, AddrSize, DumpOpts); - DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); - break; - case dwarf::DW_RLE_offset_pair: - PrintRawEntry(OS, *this, AddrSize, DumpOpts); + break; + case dwarf::DW_RLE_start_length: + PrintRawEntry(OS, *this, AddrSize, DumpOpts); + DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts); + break; + case dwarf::DW_RLE_offset_pair: + PrintRawEntry(OS, *this, AddrSize, DumpOpts); if (CurrentBase != Tombstone) DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase) .dump(OS, AddrSize, DumpOpts); else OS << "dead code"; - break; - case dwarf::DW_RLE_start_end: - DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); - break; - case dwarf::DW_RLE_startx_length: { - PrintRawEntry(OS, *this, AddrSize, DumpOpts); - uint64_t Start = 0; - if (auto SA = LookupPooledAddress(Value0)) - Start = SA->Address; - DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts); - break; - } + break; + case dwarf::DW_RLE_start_end: + DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts); + break; + case dwarf::DW_RLE_startx_length: { + PrintRawEntry(OS, *this, AddrSize, DumpOpts); + uint64_t Start = 0; + if (auto SA = LookupPooledAddress(Value0)) + Start = SA->Address; + DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts); + break; + } case dwarf::DW_RLE_startx_endx: { PrintRawEntry(OS, *this, AddrSize, DumpOpts); uint64_t Start = 0; @@ -256,8 +256,8 @@ void RangeListEntry::dump( DWARFAddressRange(Start, End).dump(OS, AddrSize, DumpOpts); break; } - default: - llvm_unreachable("Unsupported range list encoding"); - } - OS << "\n"; -} + default: + llvm_unreachable("Unsupported range list encoding"); + } + OS << "\n"; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDie.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDie.cpp index 5a55f3a041..f22e8141bd 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -1,274 +1,274 @@ -//===- DWARFDie.cpp -------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" -#include "llvm/DebugInfo/DWARF/DWARFExpression.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatAdapters.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cinttypes> -#include <cstdint> -#include <string> -#include <utility> - -using namespace llvm; -using namespace dwarf; -using namespace object; - -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(const DWARFObject &Obj, raw_ostream &OS, - const DWARFAddressRangesVector &Ranges, - unsigned AddressSize, unsigned Indent, - const DIDumpOptions &DumpOpts) { - if (!DumpOpts.ShowAddresses) - return; - - for (const DWARFAddressRange &R : Ranges) { - OS << '\n'; - OS.indent(Indent); - R.dump(OS, AddressSize, DumpOpts, &Obj); - } -} - +//===- DWARFDie.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <string> +#include <utility> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +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(const DWARFObject &Obj, raw_ostream &OS, + const DWARFAddressRangesVector &Ranges, + unsigned AddressSize, unsigned Indent, + const DIDumpOptions &DumpOpts) { + if (!DumpOpts.ShowAddresses) + return; + + for (const DWARFAddressRange &R : Ranges) { + OS << '\n'; + OS.indent(Indent); + R.dump(OS, AddressSize, DumpOpts, &Obj); + } +} + static void dumpLocation(raw_ostream &OS, const DWARFFormValue &FormValue, - DWARFUnit *U, unsigned Indent, - DIDumpOptions DumpOpts) { - DWARFContext &Ctx = U->getContext(); - const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); - if (FormValue.isFormClass(DWARFFormValue::FC_Block) || - FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { - ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); - DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), - Ctx.isLittleEndian(), 0); - DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format) + DWARFUnit *U, unsigned Indent, + DIDumpOptions DumpOpts) { + DWARFContext &Ctx = U->getContext(); + const MCRegisterInfo *MRI = Ctx.getRegisterInfo(); + if (FormValue.isFormClass(DWARFFormValue::FC_Block) || + FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) { + ArrayRef<uint8_t> Expr = *FormValue.getAsBlock(); + DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()), + Ctx.isLittleEndian(), 0); + DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format) .print(OS, DumpOpts, MRI, U); - return; - } - - if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { - uint64_t Offset = *FormValue.getAsSectionOffset(); - - if (FormValue.getForm() == DW_FORM_loclistx) { - FormValue.dump(OS, DumpOpts); - - if (auto LoclistOffset = U->getLoclistOffset(Offset)) - Offset = *LoclistOffset; - else - return; - } - U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(), - MRI, Ctx.getDWARFObj(), U, DumpOpts, - Indent); - return; - } - - FormValue.dump(OS, DumpOpts); -} - -/// Dump the name encoded in the type tag. -static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) { - StringRef TagStr = TagString(T); - if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type")) - return; - OS << TagStr.substr(7, TagStr.size() - 12) << " "; -} - -static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) { - for (const DWARFDie &C : D.children()) - if (C.getTag() == DW_TAG_subrange_type) { - Optional<uint64_t> LB; - Optional<uint64_t> Count; - Optional<uint64_t> UB; - Optional<unsigned> DefaultLB; - if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound)) - LB = L->getAsUnsignedConstant(); - if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count)) - Count = CountV->getAsUnsignedConstant(); - if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound)) - UB = UpperV->getAsUnsignedConstant(); - if (Optional<DWARFFormValue> LV = - D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) - if (Optional<uint64_t> LC = LV->getAsUnsignedConstant()) - if ((DefaultLB = - LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC)))) - if (LB && *LB == *DefaultLB) - LB = None; - if (!LB && !Count && !UB) - OS << "[]"; - else if (!LB && (Count || UB) && DefaultLB) - OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; - else { - OS << "[["; - if (LB) - OS << *LB; - else - OS << '?'; - OS << ", "; - if (Count) - if (LB) - OS << *LB + *Count; - else - OS << "? + " << *Count; - else if (UB) - OS << *UB + 1; - else - OS << '?'; - OS << ")]"; - } - } -} - -/// Recursively dump the DIE type name when applicable. -static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { - if (!D.isValid()) - return; - - if (const char *Name = D.getName(DINameKind::LinkageName)) { - OS << Name; - return; - } - - // FIXME: We should have pretty printers per language. Currently we print - // everything as if it was C++ and fall back to the TAG type name. - const dwarf::Tag T = D.getTag(); - switch (T) { - case DW_TAG_array_type: - case DW_TAG_pointer_type: - case DW_TAG_ptr_to_member_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_subroutine_type: - break; - default: - dumpTypeTagName(OS, T); - } - - // Follow the DW_AT_type if possible. - DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type); - dumpTypeName(OS, TypeDie); - - switch (T) { - case DW_TAG_subroutine_type: { - if (!TypeDie) - OS << "void"; - OS << '('; - bool First = true; - for (const DWARFDie &C : D.children()) { - if (C.getTag() == DW_TAG_formal_parameter) { - if (!First) - OS << ", "; - First = false; - dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type)); - } - } - OS << ')'; - break; - } - case DW_TAG_array_type: { - dumpArrayType(OS, D); - break; - } - case DW_TAG_pointer_type: - OS << '*'; - break; - case DW_TAG_ptr_to_member_type: - if (DWARFDie Cont = - D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { - dumpTypeName(OS << ' ', Cont); - OS << "::"; - } - OS << '*'; - break; - case DW_TAG_reference_type: - OS << '&'; - break; - case DW_TAG_rvalue_reference_type: - OS << "&&"; - break; - default: - break; - } -} - -static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, + return; + } + + if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) { + uint64_t Offset = *FormValue.getAsSectionOffset(); + + if (FormValue.getForm() == DW_FORM_loclistx) { + FormValue.dump(OS, DumpOpts); + + if (auto LoclistOffset = U->getLoclistOffset(Offset)) + Offset = *LoclistOffset; + else + return; + } + U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(), + MRI, Ctx.getDWARFObj(), U, DumpOpts, + Indent); + return; + } + + FormValue.dump(OS, DumpOpts); +} + +/// Dump the name encoded in the type tag. +static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) { + StringRef TagStr = TagString(T); + if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type")) + return; + OS << TagStr.substr(7, TagStr.size() - 12) << " "; +} + +static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) { + for (const DWARFDie &C : D.children()) + if (C.getTag() == DW_TAG_subrange_type) { + Optional<uint64_t> LB; + Optional<uint64_t> Count; + Optional<uint64_t> UB; + Optional<unsigned> DefaultLB; + if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound)) + LB = L->getAsUnsignedConstant(); + if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count)) + Count = CountV->getAsUnsignedConstant(); + if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound)) + UB = UpperV->getAsUnsignedConstant(); + if (Optional<DWARFFormValue> LV = + D.getDwarfUnit()->getUnitDIE().find(DW_AT_language)) + if (Optional<uint64_t> LC = LV->getAsUnsignedConstant()) + if ((DefaultLB = + LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC)))) + if (LB && *LB == *DefaultLB) + LB = None; + if (!LB && !Count && !UB) + OS << "[]"; + else if (!LB && (Count || UB) && DefaultLB) + OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']'; + else { + OS << "[["; + if (LB) + OS << *LB; + else + OS << '?'; + OS << ", "; + if (Count) + if (LB) + OS << *LB + *Count; + else + OS << "? + " << *Count; + else if (UB) + OS << *UB + 1; + else + OS << '?'; + OS << ")]"; + } + } +} + +/// Recursively dump the DIE type name when applicable. +static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { + if (!D.isValid()) + return; + + if (const char *Name = D.getName(DINameKind::LinkageName)) { + OS << Name; + return; + } + + // FIXME: We should have pretty printers per language. Currently we print + // everything as if it was C++ and fall back to the TAG type name. + const dwarf::Tag T = D.getTag(); + switch (T) { + case DW_TAG_array_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + case DW_TAG_subroutine_type: + break; + default: + dumpTypeTagName(OS, T); + } + + // Follow the DW_AT_type if possible. + DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type); + dumpTypeName(OS, TypeDie); + + switch (T) { + case DW_TAG_subroutine_type: { + if (!TypeDie) + OS << "void"; + OS << '('; + bool First = true; + for (const DWARFDie &C : D.children()) { + if (C.getTag() == DW_TAG_formal_parameter) { + if (!First) + OS << ", "; + First = false; + dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type)); + } + } + OS << ')'; + break; + } + case DW_TAG_array_type: { + dumpArrayType(OS, D); + break; + } + case DW_TAG_pointer_type: + OS << '*'; + break; + case DW_TAG_ptr_to_member_type: + if (DWARFDie Cont = + D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { + dumpTypeName(OS << ' ', Cont); + OS << "::"; + } + OS << '*'; + break; + case DW_TAG_reference_type: + OS << '&'; + break; + case DW_TAG_rvalue_reference_type: + OS << "&&"; + break; + default: + break; + } +} + +static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, const DWARFAttribute &AttrValue, unsigned Indent, - DIDumpOptions DumpOpts) { - if (!Die.isValid()) - return; - const char BaseIndent[] = " "; - OS << BaseIndent; - OS.indent(Indent + 2); + DIDumpOptions DumpOpts) { + if (!Die.isValid()) + return; + const char BaseIndent[] = " "; + OS << BaseIndent; + OS.indent(Indent + 2); dwarf::Attribute Attr = AttrValue.Attr; - WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr); - + WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr); + dwarf::Form Form = AttrValue.Value.getForm(); - if (DumpOpts.Verbose || DumpOpts.ShowForm) - OS << formatv(" [{0}]", Form); - - DWARFUnit *U = Die.getDwarfUnit(); + if (DumpOpts.Verbose || DumpOpts.ShowForm) + OS << formatv(" [{0}]", Form); + + DWARFUnit *U = Die.getDwarfUnit(); const DWARFFormValue &FormValue = AttrValue.Value; - - OS << "\t("; - - StringRef Name; - std::string File; - auto Color = HighlightColor::Enumerator; - if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { - Color = HighlightColor::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(); + + OS << "\t("; + + StringRef Name; + std::string File; + auto Color = HighlightColor::Enumerator; + if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) { + Color = HighlightColor::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 if (Attr == DW_AT_low_pc && (FormValue.getAsAddress() == dwarf::computeTombstoneAddress(U->getAddressByteSize()))) { @@ -281,294 +281,294 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, OS << ')'; } else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose && FormValue.getAsUnsignedConstant()) { - if (DumpOpts.ShowAddresses) { - // Print the actual address rather than the offset. - uint64_t LowPC, HighPC, Index; - if (Die.getLowAndHighPC(LowPC, HighPC, Index)) + if (DumpOpts.ShowAddresses) { + // Print the actual address rather than the offset. + uint64_t LowPC, HighPC, Index; + if (Die.getLowAndHighPC(LowPC, HighPC, Index)) DWARFFormValue::dumpAddress(OS, U->getAddressByteSize(), HighPC); - else - FormValue.dump(OS, DumpOpts); - } - } else if (Form == dwarf::Form::DW_FORM_exprloc || - DWARFAttribute::mayHaveLocationDescription(Attr)) - dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); - else - FormValue.dump(OS, DumpOpts); - - std::string Space = DumpOpts.ShowAddresses ? " " : ""; - - // 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(FormValue).getName( - DINameKind::LinkageName)) - OS << Space << "\"" << Name << '\"'; - } else if (Attr == DW_AT_type) { - OS << Space << "\""; - dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(FormValue)); - OS << '"'; - } else if (Attr == DW_AT_APPLE_property_attribute) { - if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant()) - dumpApplePropertyAttribute(OS, *OptVal); - } else if (Attr == DW_AT_ranges) { - const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); - // For DW_FORM_rnglistx we need to dump the offset separately, since - // we have only dumped the index so far. - if (FormValue.getForm() == DW_FORM_rnglistx) - if (auto RangeListOffset = - U->getRnglistOffset(*FormValue.getAsSectionOffset())) { - DWARFFormValue FV = DWARFFormValue::createFromUValue( - dwarf::DW_FORM_sec_offset, *RangeListOffset); - FV.dump(OS, DumpOpts); - } - if (auto RangesOrError = Die.getAddressRanges()) - dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(), - sizeof(BaseIndent) + Indent + 4, DumpOpts); - else - DumpOpts.RecoverableErrorHandler(createStringError( - errc::invalid_argument, "decoding address ranges: %s", - toString(RangesOrError.takeError()).c_str())); - } - - OS << ")\n"; -} - -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::find(dwarf::Attribute Attr) const { - if (!isValid()) - return None; - auto AbbrevDecl = getAbbreviationDeclarationPtr(); - if (AbbrevDecl) - return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U); - return None; -} - -Optional<DWARFFormValue> -DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { - if (!isValid()) - return None; - auto AbbrevDecl = getAbbreviationDeclarationPtr(); - if (AbbrevDecl) { - for (auto Attr : Attrs) { - if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U)) - return Value; - } - } - return None; -} - -Optional<DWARFFormValue> -DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { - SmallVector<DWARFDie, 3> Worklist; - Worklist.push_back(*this); - - // Keep track if DIEs already seen to prevent infinite recursion. - // Empirically we rarely see a depth of more than 3 when dealing with valid - // DWARF. This corresponds to following the DW_AT_abstract_origin and - // DW_AT_specification just once. - SmallSet<DWARFDie, 3> Seen; - Seen.insert(*this); - - while (!Worklist.empty()) { + else + FormValue.dump(OS, DumpOpts); + } + } else if (Form == dwarf::Form::DW_FORM_exprloc || + DWARFAttribute::mayHaveLocationDescription(Attr)) + dumpLocation(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts); + else + FormValue.dump(OS, DumpOpts); + + std::string Space = DumpOpts.ShowAddresses ? " " : ""; + + // 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(FormValue).getName( + DINameKind::LinkageName)) + OS << Space << "\"" << Name << '\"'; + } else if (Attr == DW_AT_type) { + OS << Space << "\""; + dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(FormValue)); + OS << '"'; + } else if (Attr == DW_AT_APPLE_property_attribute) { + if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant()) + dumpApplePropertyAttribute(OS, *OptVal); + } else if (Attr == DW_AT_ranges) { + const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj(); + // For DW_FORM_rnglistx we need to dump the offset separately, since + // we have only dumped the index so far. + if (FormValue.getForm() == DW_FORM_rnglistx) + if (auto RangeListOffset = + U->getRnglistOffset(*FormValue.getAsSectionOffset())) { + DWARFFormValue FV = DWARFFormValue::createFromUValue( + dwarf::DW_FORM_sec_offset, *RangeListOffset); + FV.dump(OS, DumpOpts); + } + if (auto RangesOrError = Die.getAddressRanges()) + dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(), + sizeof(BaseIndent) + Indent + 4, DumpOpts); + else + DumpOpts.RecoverableErrorHandler(createStringError( + errc::invalid_argument, "decoding address ranges: %s", + toString(RangesOrError.takeError()).c_str())); + } + + OS << ")\n"; +} + +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::find(dwarf::Attribute Attr) const { + if (!isValid()) + return None; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) + return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U); + return None; +} + +Optional<DWARFFormValue> +DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const { + if (!isValid()) + return None; + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + for (auto Attr : Attrs) { + if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U)) + return Value; + } + } + return None; +} + +Optional<DWARFFormValue> +DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const { + SmallVector<DWARFDie, 3> Worklist; + Worklist.push_back(*this); + + // Keep track if DIEs already seen to prevent infinite recursion. + // Empirically we rarely see a depth of more than 3 when dealing with valid + // DWARF. This corresponds to following the DW_AT_abstract_origin and + // DW_AT_specification just once. + SmallSet<DWARFDie, 3> Seen; + Seen.insert(*this); + + while (!Worklist.empty()) { DWARFDie Die = Worklist.pop_back_val(); - - if (!Die.isValid()) - continue; - - if (auto Value = Die.find(Attrs)) - return Value; - - if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) - if (Seen.insert(D).second) - Worklist.push_back(D); - - if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) - if (Seen.insert(D).second) - Worklist.push_back(D); - } - - return None; -} - -DWARFDie -DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { - if (Optional<DWARFFormValue> F = find(Attr)) - return getAttributeValueAsReferencedDie(*F); - return DWARFDie(); -} - -DWARFDie -DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const { - if (auto SpecRef = V.getAsRelativeReference()) { - if (SpecRef->Unit) - return SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() + SpecRef->Offset); - if (auto SpecUnit = U->getUnitVector().getUnitForOffset(SpecRef->Offset)) - return SpecUnit->getDIEForOffset(SpecRef->Offset); - } - return DWARFDie(); -} - -Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { - return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); -} - -Optional<uint64_t> DWARFDie::getLocBaseAttribute() const { - return toSectionOffset(find(DW_AT_loclists_base)); -} - -Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { + + if (!Die.isValid()) + continue; + + if (auto Value = Die.find(Attrs)) + return Value; + + if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) + if (Seen.insert(D).second) + Worklist.push_back(D); + + if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification)) + if (Seen.insert(D).second) + Worklist.push_back(D); + } + + return None; +} + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const { + if (Optional<DWARFFormValue> F = find(Attr)) + return getAttributeValueAsReferencedDie(*F); + return DWARFDie(); +} + +DWARFDie +DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const { + if (auto SpecRef = V.getAsRelativeReference()) { + if (SpecRef->Unit) + return SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() + SpecRef->Offset); + if (auto SpecUnit = U->getUnitVector().getUnitForOffset(SpecRef->Offset)) + return SpecUnit->getDIEForOffset(SpecRef->Offset); + } + return DWARFDie(); +} + +Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const { + return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base})); +} + +Optional<uint64_t> DWARFDie::getLocBaseAttribute() const { + return toSectionOffset(find(DW_AT_loclists_base)); +} + +Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const { uint64_t Tombstone = dwarf::computeTombstoneAddress(U->getAddressByteSize()); if (LowPC == Tombstone) return None; - if (auto FormValue = find(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, - uint64_t &SectionIndex) const { - auto F = find(DW_AT_low_pc); - auto LowPcAddr = toSectionedAddress(F); - if (!LowPcAddr) - return false; - if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) { - LowPC = LowPcAddr->Address; - HighPC = *HighPcAddr; - SectionIndex = LowPcAddr->SectionIndex; - return true; - } - return false; -} - -Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const { - if (isNULL()) - return DWARFAddressRangesVector(); - // Single range specified by low/high PC. - uint64_t LowPC, HighPC, Index; - if (getLowAndHighPC(LowPC, HighPC, Index)) - return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; - - Optional<DWARFFormValue> Value = find(DW_AT_ranges); - if (Value) { - if (Value->getForm() == DW_FORM_rnglistx) - return U->findRnglistFromIndex(*Value->getAsSectionOffset()); - return U->findRnglistFromOffset(*Value->getAsSectionOffset()); - } - return DWARFAddressRangesVector(); -} - -void DWARFDie::collectChildrenAddressRanges( - DWARFAddressRangesVector &Ranges) const { - if (isNULL()) - return; - if (isSubprogramDIE()) { - if (auto DIERangesOrError = getAddressRanges()) + if (auto FormValue = find(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, + uint64_t &SectionIndex) const { + auto F = find(DW_AT_low_pc); + auto LowPcAddr = toSectionedAddress(F); + if (!LowPcAddr) + return false; + if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) { + LowPC = LowPcAddr->Address; + HighPC = *HighPcAddr; + SectionIndex = LowPcAddr->SectionIndex; + return true; + } + return false; +} + +Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const { + if (isNULL()) + return DWARFAddressRangesVector(); + // Single range specified by low/high PC. + uint64_t LowPC, HighPC, Index; + if (getLowAndHighPC(LowPC, HighPC, Index)) + return DWARFAddressRangesVector{{LowPC, HighPC, Index}}; + + Optional<DWARFFormValue> Value = find(DW_AT_ranges); + if (Value) { + if (Value->getForm() == DW_FORM_rnglistx) + return U->findRnglistFromIndex(*Value->getAsSectionOffset()); + return U->findRnglistFromOffset(*Value->getAsSectionOffset()); + } + return DWARFAddressRangesVector(); +} + +void DWARFDie::collectChildrenAddressRanges( + DWARFAddressRangesVector &Ranges) const { + if (isNULL()) + return; + if (isSubprogramDIE()) { + if (auto DIERangesOrError = getAddressRanges()) llvm::append_range(Ranges, DIERangesOrError.get()); - else - llvm::consumeError(DIERangesOrError.takeError()); - } - - for (auto Child : children()) - Child.collectChildrenAddressRanges(Ranges); -} - -bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { - auto RangesOrError = getAddressRanges(); - if (!RangesOrError) { - llvm::consumeError(RangesOrError.takeError()); - return false; - } - - for (const auto &R : RangesOrError.get()) - if (R.LowPC <= Address && Address < R.HighPC) - return true; - return false; -} - -Expected<DWARFLocationExpressionsVector> -DWARFDie::getLocations(dwarf::Attribute Attr) const { - Optional<DWARFFormValue> Location = find(Attr); - if (!Location) - return createStringError(inconvertibleErrorCode(), "No %s", - dwarf::AttributeString(Attr).data()); - - if (Optional<uint64_t> Off = Location->getAsSectionOffset()) { - uint64_t Offset = *Off; - - if (Location->getForm() == DW_FORM_loclistx) { - if (auto LoclistOffset = U->getLoclistOffset(Offset)) - Offset = *LoclistOffset; - else - return createStringError(inconvertibleErrorCode(), - "Loclist table not found"); - } - return U->findLoclistFromOffset(Offset); - } - - if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { - return DWARFLocationExpressionsVector{ - DWARFLocationExpression{None, to_vector<4>(*Expr)}}; - } - - return createStringError( - inconvertibleErrorCode(), "Unsupported %s encoding: %s", - dwarf::AttributeString(Attr).data(), - dwarf::FormEncodingString(Location->getForm()).data()); -} - -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; - // Try to get mangled name only if it was asked for. - if (Kind == DINameKind::LinkageName) { - if (auto Name = getLinkageName()) - return Name; - } - return getShortName(); -} - -const char *DWARFDie::getShortName() const { - if (!isValid()) - return nullptr; - - return dwarf::toString(findRecursively(dwarf::DW_AT_name), nullptr); -} - -const char *DWARFDie::getLinkageName() const { - if (!isValid()) - return nullptr; - - return dwarf::toString(findRecursively({dwarf::DW_AT_MIPS_linkage_name, - dwarf::DW_AT_linkage_name}), - nullptr); -} - -uint64_t DWARFDie::getDeclLine() const { - return toUnsigned(findRecursively(DW_AT_decl_line), 0); -} - + else + llvm::consumeError(DIERangesOrError.takeError()); + } + + for (auto Child : children()) + Child.collectChildrenAddressRanges(Ranges); +} + +bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const { + auto RangesOrError = getAddressRanges(); + if (!RangesOrError) { + llvm::consumeError(RangesOrError.takeError()); + return false; + } + + for (const auto &R : RangesOrError.get()) + if (R.LowPC <= Address && Address < R.HighPC) + return true; + return false; +} + +Expected<DWARFLocationExpressionsVector> +DWARFDie::getLocations(dwarf::Attribute Attr) const { + Optional<DWARFFormValue> Location = find(Attr); + if (!Location) + return createStringError(inconvertibleErrorCode(), "No %s", + dwarf::AttributeString(Attr).data()); + + if (Optional<uint64_t> Off = Location->getAsSectionOffset()) { + uint64_t Offset = *Off; + + if (Location->getForm() == DW_FORM_loclistx) { + if (auto LoclistOffset = U->getLoclistOffset(Offset)) + Offset = *LoclistOffset; + else + return createStringError(inconvertibleErrorCode(), + "Loclist table not found"); + } + return U->findLoclistFromOffset(Offset); + } + + if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) { + return DWARFLocationExpressionsVector{ + DWARFLocationExpression{None, to_vector<4>(*Expr)}}; + } + + return createStringError( + inconvertibleErrorCode(), "Unsupported %s encoding: %s", + dwarf::AttributeString(Attr).data(), + dwarf::FormEncodingString(Location->getForm()).data()); +} + +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; + // Try to get mangled name only if it was asked for. + if (Kind == DINameKind::LinkageName) { + if (auto Name = getLinkageName()) + return Name; + } + return getShortName(); +} + +const char *DWARFDie::getShortName() const { + if (!isValid()) + return nullptr; + + return dwarf::toString(findRecursively(dwarf::DW_AT_name), nullptr); +} + +const char *DWARFDie::getLinkageName() const { + if (!isValid()) + return nullptr; + + return dwarf::toString(findRecursively({dwarf::DW_AT_MIPS_linkage_name, + dwarf::DW_AT_linkage_name}), + nullptr); +} + +uint64_t DWARFDie::getDeclLine() const { + return toUnsigned(findRecursively(DW_AT_decl_line), 0); +} + std::string DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const { std::string FileName; @@ -580,142 +580,142 @@ DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const { return FileName; } -void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, - uint32_t &CallColumn, - uint32_t &CallDiscriminator) const { - CallFile = toUnsigned(find(DW_AT_call_file), 0); - CallLine = toUnsigned(find(DW_AT_call_line), 0); - CallColumn = toUnsigned(find(DW_AT_call_column), 0); - CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); -} - -/// Helper to dump a DIE with all of its parents, but no siblings. -static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, - DIDumpOptions DumpOpts, unsigned Depth = 0) { - if (!Die) - return Indent; - if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth) - return Indent; - Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts, Depth + 1); - Die.dump(OS, Indent, DumpOpts); - return Indent + 2; -} - -void DWARFDie::dump(raw_ostream &OS, unsigned Indent, - DIDumpOptions DumpOpts) const { - if (!isValid()) - return; - DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); - const uint64_t Offset = getOffset(); - uint64_t offset = Offset; - if (DumpOpts.ShowParents) { - DIDumpOptions ParentDumpOpts = DumpOpts; - ParentDumpOpts.ShowParents = false; - ParentDumpOpts.ShowChildren = false; - Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts); - } - - if (debug_info_data.isValidOffset(offset)) { - uint32_t abbrCode = debug_info_data.getULEB128(&offset); - if (DumpOpts.ShowAddresses) - WithColor(OS, HighlightColor::Address).get() - << format("\n0x%8.8" PRIx64 ": ", Offset); - - if (abbrCode) { - auto AbbrevDecl = getAbbreviationDeclarationPtr(); - if (AbbrevDecl) { - WithColor(OS, HighlightColor::Tag).get().indent(Indent) - << formatv("{0}", getTag()); - if (DumpOpts.Verbose) - OS << format(" [%u] %c", abbrCode, - AbbrevDecl->hasChildren() ? '*' : ' '); - OS << '\n'; - - // Dump all data in the DIE for the attributes. +void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, + uint32_t &CallColumn, + uint32_t &CallDiscriminator) const { + CallFile = toUnsigned(find(DW_AT_call_file), 0); + CallLine = toUnsigned(find(DW_AT_call_line), 0); + CallColumn = toUnsigned(find(DW_AT_call_column), 0); + CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0); +} + +/// Helper to dump a DIE with all of its parents, but no siblings. +static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts, unsigned Depth = 0) { + if (!Die) + return Indent; + if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth) + return Indent; + Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts, Depth + 1); + Die.dump(OS, Indent, DumpOpts); + return Indent + 2; +} + +void DWARFDie::dump(raw_ostream &OS, unsigned Indent, + DIDumpOptions DumpOpts) const { + if (!isValid()) + return; + DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor(); + const uint64_t Offset = getOffset(); + uint64_t offset = Offset; + if (DumpOpts.ShowParents) { + DIDumpOptions ParentDumpOpts = DumpOpts; + ParentDumpOpts.ShowParents = false; + ParentDumpOpts.ShowChildren = false; + Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts); + } + + if (debug_info_data.isValidOffset(offset)) { + uint32_t abbrCode = debug_info_data.getULEB128(&offset); + if (DumpOpts.ShowAddresses) + WithColor(OS, HighlightColor::Address).get() + << format("\n0x%8.8" PRIx64 ": ", Offset); + + if (abbrCode) { + auto AbbrevDecl = getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + WithColor(OS, HighlightColor::Tag).get().indent(Indent) + << formatv("{0}", getTag()); + if (DumpOpts.Verbose) + OS << format(" [%u] %c", abbrCode, + AbbrevDecl->hasChildren() ? '*' : ' '); + OS << '\n'; + + // Dump all data in the DIE for the attributes. for (const DWARFAttribute &AttrValue : attributes()) dumpAttribute(OS, *this, AttrValue, Indent, DumpOpts); - - DWARFDie child = getFirstChild(); - if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0 && child) { - DumpOpts.ChildRecurseDepth--; - DIDumpOptions ChildDumpOpts = DumpOpts; - ChildDumpOpts.ShowParents = false; - while (child) { - child.dump(OS, Indent + 2, ChildDumpOpts); - child = child.getSibling(); - } - } - } else { - OS << "Abbreviation code not found in 'debug_abbrev' class for code: " - << abbrCode << '\n'; - } - } else { - OS.indent(Indent) << "NULL\n"; - } - } -} - -LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); } - -DWARFDie DWARFDie::getParent() const { - if (isValid()) - return U->getParent(Die); - return DWARFDie(); -} - -DWARFDie DWARFDie::getSibling() const { - if (isValid()) - return U->getSibling(Die); - return DWARFDie(); -} - -DWARFDie DWARFDie::getPreviousSibling() const { - if (isValid()) - return U->getPreviousSibling(Die); - return DWARFDie(); -} - -DWARFDie DWARFDie::getFirstChild() const { - if (isValid()) - return U->getFirstChild(Die); - return DWARFDie(); -} - -DWARFDie DWARFDie::getLastChild() const { - if (isValid()) - return U->getLastChild(Die); - return DWARFDie(); -} - -iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { - return make_range(attribute_iterator(*this, false), - attribute_iterator(*this, true)); -} - -DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) - : Die(D), Index(0) { - auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); - assert(AbbrDecl && "Must have abbreviation declaration"); - if (End) { - // This is the end iterator so we set the index to the attribute count. - Index = AbbrDecl->getNumAttributes(); - } else { - // This is the begin iterator so we extract the value for this->Index. - AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); - updateForIndex(*AbbrDecl, 0); - } -} - -void DWARFDie::attribute_iterator::updateForIndex( - const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { - Index = I; - // AbbrDecl must be valid before calling this function. - auto NumAttrs = AbbrDecl.getNumAttributes(); - if (Index < NumAttrs) { - AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); - // Add the previous byte size of any previous attribute value. - AttrValue.Offset += AttrValue.ByteSize; - uint64_t ParseOffset = AttrValue.Offset; + + DWARFDie child = getFirstChild(); + if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0 && child) { + DumpOpts.ChildRecurseDepth--; + DIDumpOptions ChildDumpOpts = DumpOpts; + ChildDumpOpts.ShowParents = false; + while (child) { + child.dump(OS, Indent + 2, ChildDumpOpts); + child = child.getSibling(); + } + } + } else { + OS << "Abbreviation code not found in 'debug_abbrev' class for code: " + << abbrCode << '\n'; + } + } else { + OS.indent(Indent) << "NULL\n"; + } + } +} + +LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); } + +DWARFDie DWARFDie::getParent() const { + if (isValid()) + return U->getParent(Die); + return DWARFDie(); +} + +DWARFDie DWARFDie::getSibling() const { + if (isValid()) + return U->getSibling(Die); + return DWARFDie(); +} + +DWARFDie DWARFDie::getPreviousSibling() const { + if (isValid()) + return U->getPreviousSibling(Die); + return DWARFDie(); +} + +DWARFDie DWARFDie::getFirstChild() const { + if (isValid()) + return U->getFirstChild(Die); + return DWARFDie(); +} + +DWARFDie DWARFDie::getLastChild() const { + if (isValid()) + return U->getLastChild(Die); + return DWARFDie(); +} + +iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const { + return make_range(attribute_iterator(*this, false), + attribute_iterator(*this, true)); +} + +DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) + : Die(D), Index(0) { + auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); + assert(AbbrDecl && "Must have abbreviation declaration"); + if (End) { + // This is the end iterator so we set the index to the attribute count. + Index = AbbrDecl->getNumAttributes(); + } else { + // This is the begin iterator so we extract the value for this->Index. + AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); + updateForIndex(*AbbrDecl, 0); + } +} + +void DWARFDie::attribute_iterator::updateForIndex( + const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { + Index = I; + // AbbrDecl must be valid before calling this function. + auto NumAttrs = AbbrDecl.getNumAttributes(); + if (Index < NumAttrs) { + AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); + // Add the previous byte size of any previous attribute value. + AttrValue.Offset += AttrValue.ByteSize; + uint64_t ParseOffset = AttrValue.Offset; if (AbbrDecl.getAttrIsImplicitConstByIndex(Index)) AttrValue.Value = DWARFFormValue::createFromSValue( AbbrDecl.getFormByIndex(Index), @@ -726,52 +726,52 @@ void DWARFDie::attribute_iterator::updateForIndex( AttrValue.Value = DWARFFormValue::createFromUnit( AbbrDecl.getFormByIndex(Index), U, &ParseOffset); } - AttrValue.ByteSize = ParseOffset - AttrValue.Offset; - } else { - assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); - AttrValue = {}; - } -} - -DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { - if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) - updateForIndex(*AbbrDecl, Index + 1); - return *this; -} - -bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) { - switch (Attr) { - // From the DWARF v5 specification. - case DW_AT_location: - case DW_AT_byte_size: - case DW_AT_bit_size: - case DW_AT_string_length: - case DW_AT_lower_bound: - case DW_AT_return_addr: - case DW_AT_bit_stride: - case DW_AT_upper_bound: - case DW_AT_count: - case DW_AT_data_member_location: - case DW_AT_frame_base: - case DW_AT_segment: - case DW_AT_static_link: - case DW_AT_use_location: - case DW_AT_vtable_elem_location: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_byte_stride: - case DW_AT_rank: - case DW_AT_call_value: - case DW_AT_call_origin: - case DW_AT_call_target: - case DW_AT_call_target_clobbered: - case DW_AT_call_data_location: - case DW_AT_call_data_value: - // Extensions. - case DW_AT_GNU_call_site_value: - case DW_AT_GNU_call_site_target: - return true; - default: - return false; - } -} + AttrValue.ByteSize = ParseOffset - AttrValue.Offset; + } else { + assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); + AttrValue = {}; + } +} + +DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { + if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) + updateForIndex(*AbbrDecl, Index + 1); + return *this; +} + +bool DWARFAttribute::mayHaveLocationDescription(dwarf::Attribute Attr) { + switch (Attr) { + // From the DWARF v5 specification. + case DW_AT_location: + case DW_AT_byte_size: + case DW_AT_bit_size: + case DW_AT_string_length: + case DW_AT_lower_bound: + case DW_AT_return_addr: + case DW_AT_bit_stride: + case DW_AT_upper_bound: + case DW_AT_count: + case DW_AT_data_member_location: + case DW_AT_frame_base: + case DW_AT_segment: + case DW_AT_static_link: + case DW_AT_use_location: + case DW_AT_vtable_elem_location: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_byte_stride: + case DW_AT_rank: + case DW_AT_call_value: + case DW_AT_call_origin: + case DW_AT_call_target: + case DW_AT_call_target_clobbered: + case DW_AT_call_data_location: + case DW_AT_call_data_value: + // Extensions. + case DW_AT_GNU_call_site_value: + case DW_AT_GNU_call_site_target: + return true; + default: + return false; + } +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFExpression.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFExpression.cpp index 811716111b..7a109bc290 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -1,504 +1,504 @@ -//===-- DWARFExpression.cpp -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFExpression.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/Format.h" -#include <cassert> -#include <cstdint> -#include <vector> - -using namespace llvm; -using namespace dwarf; - -namespace llvm { - -typedef std::vector<DWARFExpression::Operation::Description> DescVector; - -static DescVector getDescriptions() { - DescVector Descriptions; - typedef DWARFExpression::Operation Op; - typedef Op::Description Desc; - - Descriptions.resize(0xff); - Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr); - Descriptions[DW_OP_deref] = Desc(Op::Dwarf2); - Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1); - Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1); - Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2); - Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2); - Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4); - Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4); - Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8); - Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8); - Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB); - Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB); - Descriptions[DW_OP_dup] = Desc(Op::Dwarf2); - Descriptions[DW_OP_drop] = Desc(Op::Dwarf2); - Descriptions[DW_OP_over] = Desc(Op::Dwarf2); - Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1); - Descriptions[DW_OP_swap] = Desc(Op::Dwarf2); - Descriptions[DW_OP_rot] = Desc(Op::Dwarf2); - Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2); - Descriptions[DW_OP_abs] = Desc(Op::Dwarf2); - Descriptions[DW_OP_and] = Desc(Op::Dwarf2); - Descriptions[DW_OP_div] = Desc(Op::Dwarf2); - Descriptions[DW_OP_minus] = Desc(Op::Dwarf2); - Descriptions[DW_OP_mod] = Desc(Op::Dwarf2); - Descriptions[DW_OP_mul] = Desc(Op::Dwarf2); - Descriptions[DW_OP_neg] = Desc(Op::Dwarf2); - Descriptions[DW_OP_not] = Desc(Op::Dwarf2); - Descriptions[DW_OP_or] = Desc(Op::Dwarf2); - Descriptions[DW_OP_plus] = Desc(Op::Dwarf2); - Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB); - Descriptions[DW_OP_shl] = Desc(Op::Dwarf2); - Descriptions[DW_OP_shr] = Desc(Op::Dwarf2); - Descriptions[DW_OP_shra] = Desc(Op::Dwarf2); - Descriptions[DW_OP_xor] = Desc(Op::Dwarf2); - Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2); - Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2); - Descriptions[DW_OP_eq] = Desc(Op::Dwarf2); - Descriptions[DW_OP_ge] = Desc(Op::Dwarf2); - Descriptions[DW_OP_gt] = Desc(Op::Dwarf2); - Descriptions[DW_OP_le] = Desc(Op::Dwarf2); - Descriptions[DW_OP_lt] = Desc(Op::Dwarf2); - Descriptions[DW_OP_ne] = Desc(Op::Dwarf2); - for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA) - Descriptions[LA] = Desc(Op::Dwarf2); - for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA) - Descriptions[LA] = Desc(Op::Dwarf2); - for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA) - Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB); - Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB); - Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB); - Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB); - Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB); - Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1); - Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1); - Descriptions[DW_OP_nop] = Desc(Op::Dwarf2); - Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3); - Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2); - Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4); - Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr); - Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3); - Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3); - Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB); - Descriptions[DW_OP_implicit_value] = - Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock); - Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3); - Descriptions[DW_OP_WASM_location] = - Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg); - Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); - Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB); - Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); - Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); - Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); - - Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); - Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); - Descriptions[DW_OP_regval_type] = - Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef); - - return Descriptions; -} - -static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) { - // FIXME: Make this constexpr once all compilers are smart enough to do it. - static DescVector Descriptions = getDescriptions(); - // Handle possible corrupted or unsupported operation. - if (OpCode >= Descriptions.size()) - return {}; - return Descriptions[OpCode]; -} - -bool DWARFExpression::Operation::extract(DataExtractor Data, - uint8_t AddressSize, uint64_t Offset, - Optional<DwarfFormat> Format) { - EndOffset = Offset; - Opcode = Data.getU8(&Offset); - - Desc = getOpDesc(Opcode); - if (Desc.Version == Operation::DwarfNA) - return false; - - for (unsigned Operand = 0; Operand < 2; ++Operand) { - unsigned Size = Desc.Op[Operand]; - unsigned Signed = Size & Operation::SignBit; - - if (Size == Operation::SizeNA) - break; - - switch (Size & ~Operation::SignBit) { - case Operation::Size1: - Operands[Operand] = Data.getU8(&Offset); - if (Signed) - Operands[Operand] = (int8_t)Operands[Operand]; - break; - case Operation::Size2: - Operands[Operand] = Data.getU16(&Offset); - if (Signed) - Operands[Operand] = (int16_t)Operands[Operand]; - break; - case Operation::Size4: - Operands[Operand] = Data.getU32(&Offset); - if (Signed) - Operands[Operand] = (int32_t)Operands[Operand]; - break; - case Operation::Size8: - Operands[Operand] = Data.getU64(&Offset); - break; - case Operation::SizeAddr: - Operands[Operand] = Data.getUnsigned(&Offset, AddressSize); - break; - case Operation::SizeRefAddr: - if (!Format) - return false; - Operands[Operand] = - Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format)); - break; - case Operation::SizeLEB: - if (Signed) - Operands[Operand] = Data.getSLEB128(&Offset); - else - Operands[Operand] = Data.getULEB128(&Offset); - break; - case Operation::BaseTypeRef: - Operands[Operand] = Data.getULEB128(&Offset); - break; - case Operation::WasmLocationArg: - assert(Operand == 1); - switch (Operands[0]) { - case 0: case 1: case 2: - Operands[Operand] = Data.getULEB128(&Offset); - break; - case 3: // global as uint32 - Operands[Operand] = Data.getU32(&Offset); - break; - default: - return false; // Unknown Wasm location - } - break; - case Operation::SizeBlock: - // We need a size, so this cannot be the first operand - if (Operand == 0) - return false; - // Store the offset of the block as the value. - Operands[Operand] = Offset; - Offset += Operands[Operand - 1]; - break; - default: - llvm_unreachable("Unknown DWARFExpression Op size"); - } - - OperandEndOffsets[Operand] = Offset; - } - - EndOffset = Offset; - return true; -} - -static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS, +//===-- DWARFExpression.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Format.h" +#include <cassert> +#include <cstdint> +#include <vector> + +using namespace llvm; +using namespace dwarf; + +namespace llvm { + +typedef std::vector<DWARFExpression::Operation::Description> DescVector; + +static DescVector getDescriptions() { + DescVector Descriptions; + typedef DWARFExpression::Operation Op; + typedef Op::Description Desc; + + Descriptions.resize(0xff); + Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr); + Descriptions[DW_OP_deref] = Desc(Op::Dwarf2); + Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1); + Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2); + Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4); + Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4); + Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8); + Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8); + Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_dup] = Desc(Op::Dwarf2); + Descriptions[DW_OP_drop] = Desc(Op::Dwarf2); + Descriptions[DW_OP_over] = Desc(Op::Dwarf2); + Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_swap] = Desc(Op::Dwarf2); + Descriptions[DW_OP_rot] = Desc(Op::Dwarf2); + Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2); + Descriptions[DW_OP_abs] = Desc(Op::Dwarf2); + Descriptions[DW_OP_and] = Desc(Op::Dwarf2); + Descriptions[DW_OP_div] = Desc(Op::Dwarf2); + Descriptions[DW_OP_minus] = Desc(Op::Dwarf2); + Descriptions[DW_OP_mod] = Desc(Op::Dwarf2); + Descriptions[DW_OP_mul] = Desc(Op::Dwarf2); + Descriptions[DW_OP_neg] = Desc(Op::Dwarf2); + Descriptions[DW_OP_not] = Desc(Op::Dwarf2); + Descriptions[DW_OP_or] = Desc(Op::Dwarf2); + Descriptions[DW_OP_plus] = Desc(Op::Dwarf2); + Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_shl] = Desc(Op::Dwarf2); + Descriptions[DW_OP_shr] = Desc(Op::Dwarf2); + Descriptions[DW_OP_shra] = Desc(Op::Dwarf2); + Descriptions[DW_OP_xor] = Desc(Op::Dwarf2); + Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2); + Descriptions[DW_OP_eq] = Desc(Op::Dwarf2); + Descriptions[DW_OP_ge] = Desc(Op::Dwarf2); + Descriptions[DW_OP_gt] = Desc(Op::Dwarf2); + Descriptions[DW_OP_le] = Desc(Op::Dwarf2); + Descriptions[DW_OP_lt] = Desc(Op::Dwarf2); + Descriptions[DW_OP_ne] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2); + for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA) + Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB); + Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB); + Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB); + Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1); + Descriptions[DW_OP_nop] = Desc(Op::Dwarf2); + Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2); + Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4); + Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr); + Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3); + Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB); + Descriptions[DW_OP_implicit_value] = + Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock); + Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3); + Descriptions[DW_OP_WASM_location] = + Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg); + Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3); + Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); + + Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); + Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); + Descriptions[DW_OP_regval_type] = + Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef); + + return Descriptions; +} + +static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) { + // FIXME: Make this constexpr once all compilers are smart enough to do it. + static DescVector Descriptions = getDescriptions(); + // Handle possible corrupted or unsupported operation. + if (OpCode >= Descriptions.size()) + return {}; + return Descriptions[OpCode]; +} + +bool DWARFExpression::Operation::extract(DataExtractor Data, + uint8_t AddressSize, uint64_t Offset, + Optional<DwarfFormat> Format) { + EndOffset = Offset; + Opcode = Data.getU8(&Offset); + + Desc = getOpDesc(Opcode); + if (Desc.Version == Operation::DwarfNA) + return false; + + for (unsigned Operand = 0; Operand < 2; ++Operand) { + unsigned Size = Desc.Op[Operand]; + unsigned Signed = Size & Operation::SignBit; + + if (Size == Operation::SizeNA) + break; + + switch (Size & ~Operation::SignBit) { + case Operation::Size1: + Operands[Operand] = Data.getU8(&Offset); + if (Signed) + Operands[Operand] = (int8_t)Operands[Operand]; + break; + case Operation::Size2: + Operands[Operand] = Data.getU16(&Offset); + if (Signed) + Operands[Operand] = (int16_t)Operands[Operand]; + break; + case Operation::Size4: + Operands[Operand] = Data.getU32(&Offset); + if (Signed) + Operands[Operand] = (int32_t)Operands[Operand]; + break; + case Operation::Size8: + Operands[Operand] = Data.getU64(&Offset); + break; + case Operation::SizeAddr: + Operands[Operand] = Data.getUnsigned(&Offset, AddressSize); + break; + case Operation::SizeRefAddr: + if (!Format) + return false; + Operands[Operand] = + Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format)); + break; + case Operation::SizeLEB: + if (Signed) + Operands[Operand] = Data.getSLEB128(&Offset); + else + Operands[Operand] = Data.getULEB128(&Offset); + break; + case Operation::BaseTypeRef: + Operands[Operand] = Data.getULEB128(&Offset); + break; + case Operation::WasmLocationArg: + assert(Operand == 1); + switch (Operands[0]) { + case 0: case 1: case 2: + Operands[Operand] = Data.getULEB128(&Offset); + break; + case 3: // global as uint32 + Operands[Operand] = Data.getU32(&Offset); + break; + default: + return false; // Unknown Wasm location + } + break; + case Operation::SizeBlock: + // We need a size, so this cannot be the first operand + if (Operand == 0) + return false; + // Store the offset of the block as the value. + Operands[Operand] = Offset; + Offset += Operands[Operand - 1]; + break; + default: + llvm_unreachable("Unknown DWARFExpression Op size"); + } + + OperandEndOffsets[Operand] = Offset; + } + + EndOffset = Offset; + return true; +} + +static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS, DIDumpOptions DumpOpts, uint64_t Operands[2], unsigned Operand) { - assert(Operand < 2 && "operand out of bounds"); - auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]); - if (Die && Die.getTag() == dwarf::DW_TAG_base_type) { + assert(Operand < 2 && "operand out of bounds"); + auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]); + if (Die && Die.getTag() == dwarf::DW_TAG_base_type) { OS << " ("; if (DumpOpts.Verbose) OS << format("0x%08" PRIx64 " -> ", Operands[Operand]); OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]); - if (auto Name = Die.find(dwarf::DW_AT_name)) - OS << " \"" << Name->getAsCString() << "\""; - } else { - OS << format(" <invalid base_type ref: 0x%" PRIx64 ">", - Operands[Operand]); - } -} - + if (auto Name = Die.find(dwarf::DW_AT_name)) + OS << " \"" << Name->getAsCString() << "\""; + } else { + OS << format(" <invalid base_type ref: 0x%" PRIx64 ">", + Operands[Operand]); + } +} + static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS, DIDumpOptions DumpOpts, uint8_t Opcode, - uint64_t Operands[2], - const MCRegisterInfo *MRI, bool isEH) { - if (!MRI) - return false; - - uint64_t DwarfRegNum; - unsigned OpNum = 0; - - if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx || - Opcode == DW_OP_regval_type) - DwarfRegNum = Operands[OpNum++]; - else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx) - DwarfRegNum = Opcode - DW_OP_breg0; - else - DwarfRegNum = Opcode - DW_OP_reg0; - - if (Optional<unsigned> LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH)) { - if (const char *RegName = MRI->getName(*LLVMRegNum)) { - if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || - Opcode == DW_OP_bregx) - OS << format(" %s%+" PRId64, RegName, Operands[OpNum]); - else - OS << ' ' << RegName; - - if (Opcode == DW_OP_regval_type) + uint64_t Operands[2], + const MCRegisterInfo *MRI, bool isEH) { + if (!MRI) + return false; + + uint64_t DwarfRegNum; + unsigned OpNum = 0; + + if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx || + Opcode == DW_OP_regval_type) + DwarfRegNum = Operands[OpNum++]; + else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx) + DwarfRegNum = Opcode - DW_OP_breg0; + else + DwarfRegNum = Opcode - DW_OP_reg0; + + if (Optional<unsigned> LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH)) { + if (const char *RegName = MRI->getName(*LLVMRegNum)) { + if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || + Opcode == DW_OP_bregx) + OS << format(" %s%+" PRId64, RegName, Operands[OpNum]); + else + OS << ' ' << RegName; + + if (Opcode == DW_OP_regval_type) prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1); - return true; - } - } - - return false; -} - + return true; + } + } + + return false; +} + bool DWARFExpression::Operation::print(raw_ostream &OS, DIDumpOptions DumpOpts, - const DWARFExpression *Expr, - const MCRegisterInfo *RegInfo, + const DWARFExpression *Expr, + const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH) { - if (Error) { - OS << "<decoding error>"; - return false; - } - - StringRef Name = OperationEncodingString(Opcode); - assert(!Name.empty() && "DW_OP has no name!"); - OS << Name; - - if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || - (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) || - Opcode == DW_OP_bregx || Opcode == DW_OP_regx || - Opcode == DW_OP_regval_type) + if (Error) { + OS << "<decoding error>"; + return false; + } + + StringRef Name = OperationEncodingString(Opcode); + assert(!Name.empty() && "DW_OP has no name!"); + OS << Name; + + if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || + (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) || + Opcode == DW_OP_bregx || Opcode == DW_OP_regx || + Opcode == DW_OP_regval_type) if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode, Operands, RegInfo, isEH)) - return true; - - for (unsigned Operand = 0; Operand < 2; ++Operand) { - unsigned Size = Desc.Op[Operand]; - unsigned Signed = Size & Operation::SignBit; - - if (Size == Operation::SizeNA) - break; - - if (Size == Operation::BaseTypeRef && U) { - // For DW_OP_convert the operand may be 0 to indicate that conversion to - // the generic type should be done. The same holds for DW_OP_reinterpret, - // which is currently not supported. - if (Opcode == DW_OP_convert && Operands[Operand] == 0) - OS << " 0x0"; - else + return true; + + for (unsigned Operand = 0; Operand < 2; ++Operand) { + unsigned Size = Desc.Op[Operand]; + unsigned Signed = Size & Operation::SignBit; + + if (Size == Operation::SizeNA) + break; + + if (Size == Operation::BaseTypeRef && U) { + // For DW_OP_convert the operand may be 0 to indicate that conversion to + // the generic type should be done. The same holds for DW_OP_reinterpret, + // which is currently not supported. + if (Opcode == DW_OP_convert && Operands[Operand] == 0) + OS << " 0x0"; + else prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand); - } else if (Size == Operation::WasmLocationArg) { - assert(Operand == 1); - switch (Operands[0]) { - case 0: case 1: case 2: - case 3: // global as uint32 - OS << format(" 0x%" PRIx64, Operands[Operand]); - break; - default: assert(false); - } - } else if (Size == Operation::SizeBlock) { - uint64_t Offset = Operands[Operand]; - for (unsigned i = 0; i < Operands[Operand - 1]; ++i) - OS << format(" 0x%02x", Expr->Data.getU8(&Offset)); - } else { - if (Signed) - OS << format(" %+" PRId64, (int64_t)Operands[Operand]); - else if (Opcode != DW_OP_entry_value && - Opcode != DW_OP_GNU_entry_value) - OS << format(" 0x%" PRIx64, Operands[Operand]); - } - } - return true; -} - + } else if (Size == Operation::WasmLocationArg) { + assert(Operand == 1); + switch (Operands[0]) { + case 0: case 1: case 2: + case 3: // global as uint32 + OS << format(" 0x%" PRIx64, Operands[Operand]); + break; + default: assert(false); + } + } else if (Size == Operation::SizeBlock) { + uint64_t Offset = Operands[Operand]; + for (unsigned i = 0; i < Operands[Operand - 1]; ++i) + OS << format(" 0x%02x", Expr->Data.getU8(&Offset)); + } else { + if (Signed) + OS << format(" %+" PRId64, (int64_t)Operands[Operand]); + else if (Opcode != DW_OP_entry_value && + Opcode != DW_OP_GNU_entry_value) + OS << format(" 0x%" PRIx64, Operands[Operand]); + } + } + return true; +} + void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts, const MCRegisterInfo *RegInfo, DWARFUnit *U, bool IsEH) const { - uint32_t EntryValExprSize = 0; - for (auto &Op : *this) { + uint32_t EntryValExprSize = 0; + for (auto &Op : *this) { if (!Op.print(OS, DumpOpts, this, RegInfo, U, IsEH)) { - uint64_t FailOffset = Op.getEndOffset(); - while (FailOffset < Data.getData().size()) - OS << format(" %02x", Data.getU8(&FailOffset)); - return; - } - - if (Op.getCode() == DW_OP_entry_value || - Op.getCode() == DW_OP_GNU_entry_value) { - OS << "("; - EntryValExprSize = Op.getRawOperand(0); - continue; - } - - if (EntryValExprSize) { - EntryValExprSize--; - if (EntryValExprSize == 0) - OS << ")"; - } - - if (Op.getEndOffset() < Data.getData().size()) - OS << ", "; - } -} - -bool DWARFExpression::Operation::verify(DWARFUnit *U) { - - for (unsigned Operand = 0; Operand < 2; ++Operand) { - unsigned Size = Desc.Op[Operand]; - - if (Size == Operation::SizeNA) - break; - - if (Size == Operation::BaseTypeRef) { - // For DW_OP_convert the operand may be 0 to indicate that conversion to - // the generic type should be done, so don't look up a base type in that - // case. The same holds for DW_OP_reinterpret, which is currently not - // supported. - if (Opcode == DW_OP_convert && Operands[Operand] == 0) - continue; - auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]); - if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) { - Error = true; - return false; - } - } - } - - return true; -} - -bool DWARFExpression::verify(DWARFUnit *U) { - for (auto &Op : *this) - if (!Op.verify(U)) - return false; - - return true; -} - -/// A user-facing string representation of a DWARF expression. This might be an -/// Address expression, in which case it will be implicitly dereferenced, or a -/// Value expression. -struct PrintedExpr { - enum ExprKind { - Address, - Value, - }; - ExprKind Kind; - SmallString<16> String; - - PrintedExpr(ExprKind K = Address) : Kind(K) {} -}; - -static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I, - const DWARFExpression::iterator E, - const MCRegisterInfo &MRI) { - SmallVector<PrintedExpr, 4> Stack; - - while (I != E) { - DWARFExpression::Operation &Op = *I; - uint8_t Opcode = Op.getCode(); - switch (Opcode) { - case dwarf::DW_OP_regx: { - // DW_OP_regx: A register, with the register num given as an operand. - // Printed as the plain register name. - uint64_t DwarfRegNum = Op.getRawOperand(0); - Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); - if (!LLVMRegNum) { - OS << "<unknown register " << DwarfRegNum << ">"; - return false; - } - raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); - S << MRI.getName(*LLVMRegNum); - break; - } - case dwarf::DW_OP_bregx: { - int DwarfRegNum = Op.getRawOperand(0); - int64_t Offset = Op.getRawOperand(1); - Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); - if (!LLVMRegNum) { - OS << "<unknown register " << DwarfRegNum << ">"; - return false; - } - raw_svector_ostream S(Stack.emplace_back().String); - S << MRI.getName(*LLVMRegNum); - if (Offset) - S << format("%+" PRId64, Offset); - break; - } - case dwarf::DW_OP_entry_value: - case dwarf::DW_OP_GNU_entry_value: { - // DW_OP_entry_value contains a sub-expression which must be rendered - // separately. - uint64_t SubExprLength = Op.getRawOperand(0); - DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength); - ++I; - raw_svector_ostream S(Stack.emplace_back().String); - S << "entry("; - printCompactDWARFExpr(S, I, SubExprEnd, MRI); - S << ")"; - I = SubExprEnd; - continue; - } - case dwarf::DW_OP_stack_value: { - // The top stack entry should be treated as the actual value of tne - // variable, rather than the address of the variable in memory. - assert(!Stack.empty()); - Stack.back().Kind = PrintedExpr::Value; - break; - } - default: - if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) { - // DW_OP_reg<N>: A register, with the register num implied by the - // opcode. Printed as the plain register name. - uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0; - Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); - if (!LLVMRegNum) { - OS << "<unknown register " << DwarfRegNum << ">"; - return false; - } - raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); - S << MRI.getName(*LLVMRegNum); - } else if (Opcode >= dwarf::DW_OP_breg0 && - Opcode <= dwarf::DW_OP_breg31) { - int DwarfRegNum = Opcode - dwarf::DW_OP_breg0; - int64_t Offset = Op.getRawOperand(0); - Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); - if (!LLVMRegNum) { - OS << "<unknown register " << DwarfRegNum << ">"; - return false; - } - raw_svector_ostream S(Stack.emplace_back().String); - S << MRI.getName(*LLVMRegNum); - if (Offset) - S << format("%+" PRId64, Offset); - } else { - // If we hit an unknown operand, we don't know its effect on the stack, - // so bail out on the whole expression. - OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " (" - << (int)Opcode << ")>"; - return false; - } - break; - } - ++I; - } - - assert(Stack.size() == 1 && "expected one value on stack"); - - if (Stack.front().Kind == PrintedExpr::Address) - OS << "[" << Stack.front().String << "]"; - else - OS << Stack.front().String; - - return true; -} - -bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) { - return printCompactDWARFExpr(OS, begin(), end(), MRI); -} - -} // namespace llvm + uint64_t FailOffset = Op.getEndOffset(); + while (FailOffset < Data.getData().size()) + OS << format(" %02x", Data.getU8(&FailOffset)); + return; + } + + if (Op.getCode() == DW_OP_entry_value || + Op.getCode() == DW_OP_GNU_entry_value) { + OS << "("; + EntryValExprSize = Op.getRawOperand(0); + continue; + } + + if (EntryValExprSize) { + EntryValExprSize--; + if (EntryValExprSize == 0) + OS << ")"; + } + + if (Op.getEndOffset() < Data.getData().size()) + OS << ", "; + } +} + +bool DWARFExpression::Operation::verify(DWARFUnit *U) { + + for (unsigned Operand = 0; Operand < 2; ++Operand) { + unsigned Size = Desc.Op[Operand]; + + if (Size == Operation::SizeNA) + break; + + if (Size == Operation::BaseTypeRef) { + // For DW_OP_convert the operand may be 0 to indicate that conversion to + // the generic type should be done, so don't look up a base type in that + // case. The same holds for DW_OP_reinterpret, which is currently not + // supported. + if (Opcode == DW_OP_convert && Operands[Operand] == 0) + continue; + auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]); + if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) { + Error = true; + return false; + } + } + } + + return true; +} + +bool DWARFExpression::verify(DWARFUnit *U) { + for (auto &Op : *this) + if (!Op.verify(U)) + return false; + + return true; +} + +/// A user-facing string representation of a DWARF expression. This might be an +/// Address expression, in which case it will be implicitly dereferenced, or a +/// Value expression. +struct PrintedExpr { + enum ExprKind { + Address, + Value, + }; + ExprKind Kind; + SmallString<16> String; + + PrintedExpr(ExprKind K = Address) : Kind(K) {} +}; + +static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I, + const DWARFExpression::iterator E, + const MCRegisterInfo &MRI) { + SmallVector<PrintedExpr, 4> Stack; + + while (I != E) { + DWARFExpression::Operation &Op = *I; + uint8_t Opcode = Op.getCode(); + switch (Opcode) { + case dwarf::DW_OP_regx: { + // DW_OP_regx: A register, with the register num given as an operand. + // Printed as the plain register name. + uint64_t DwarfRegNum = Op.getRawOperand(0); + Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); + if (!LLVMRegNum) { + OS << "<unknown register " << DwarfRegNum << ">"; + return false; + } + raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); + S << MRI.getName(*LLVMRegNum); + break; + } + case dwarf::DW_OP_bregx: { + int DwarfRegNum = Op.getRawOperand(0); + int64_t Offset = Op.getRawOperand(1); + Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); + if (!LLVMRegNum) { + OS << "<unknown register " << DwarfRegNum << ">"; + return false; + } + raw_svector_ostream S(Stack.emplace_back().String); + S << MRI.getName(*LLVMRegNum); + if (Offset) + S << format("%+" PRId64, Offset); + break; + } + case dwarf::DW_OP_entry_value: + case dwarf::DW_OP_GNU_entry_value: { + // DW_OP_entry_value contains a sub-expression which must be rendered + // separately. + uint64_t SubExprLength = Op.getRawOperand(0); + DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength); + ++I; + raw_svector_ostream S(Stack.emplace_back().String); + S << "entry("; + printCompactDWARFExpr(S, I, SubExprEnd, MRI); + S << ")"; + I = SubExprEnd; + continue; + } + case dwarf::DW_OP_stack_value: { + // The top stack entry should be treated as the actual value of tne + // variable, rather than the address of the variable in memory. + assert(!Stack.empty()); + Stack.back().Kind = PrintedExpr::Value; + break; + } + default: + if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) { + // DW_OP_reg<N>: A register, with the register num implied by the + // opcode. Printed as the plain register name. + uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0; + Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); + if (!LLVMRegNum) { + OS << "<unknown register " << DwarfRegNum << ">"; + return false; + } + raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String); + S << MRI.getName(*LLVMRegNum); + } else if (Opcode >= dwarf::DW_OP_breg0 && + Opcode <= dwarf::DW_OP_breg31) { + int DwarfRegNum = Opcode - dwarf::DW_OP_breg0; + int64_t Offset = Op.getRawOperand(0); + Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false); + if (!LLVMRegNum) { + OS << "<unknown register " << DwarfRegNum << ">"; + return false; + } + raw_svector_ostream S(Stack.emplace_back().String); + S << MRI.getName(*LLVMRegNum); + if (Offset) + S << format("%+" PRId64, Offset); + } else { + // If we hit an unknown operand, we don't know its effect on the stack, + // so bail out on the whole expression. + OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " (" + << (int)Opcode << ")>"; + return false; + } + break; + } + ++I; + } + + assert(Stack.size() == 1 && "expected one value on stack"); + + if (Stack.front().Kind == PrintedExpr::Address) + OS << "[" << Stack.front().String << "]"; + else + OS << Stack.front().String; + + return true; +} + +bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) { + return printCompactDWARFExpr(OS, begin(), end(), MRI); +} + +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFFormValue.cpp index 2559765876..be27899454 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -1,732 +1,732 @@ -//===- DWARFFormValue.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <cinttypes> -#include <cstdint> -#include <limits> - -using namespace llvm; -using namespace dwarf; - -static const DWARFFormValue::FormClass DWARF5FormClasses[] = { - DWARFFormValue::FC_Unknown, // 0x0 - DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr - DWARFFormValue::FC_Unknown, // 0x02 unused - DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 - DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 - DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 - // --- These can be FC_SectionOffset in DWARF3 and below: - DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 - DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 - // --- - DWARFFormValue::FC_String, // 0x08 DW_FORM_string - DWARFFormValue::FC_Block, // 0x09 DW_FORM_block - DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 - DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 - DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag - DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata - DWARFFormValue::FC_String, // 0x0e DW_FORM_strp - DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata - DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr - DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 - DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 - DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 - DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 - DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata - DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect - DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset - DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc - DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present - DWARFFormValue::FC_String, // 0x1a DW_FORM_strx - DWARFFormValue::FC_Address, // 0x1b DW_FORM_addrx - DWARFFormValue::FC_Reference, // 0x1c DW_FORM_ref_sup4 - DWARFFormValue::FC_String, // 0x1d DW_FORM_strp_sup - DWARFFormValue::FC_Constant, // 0x1e DW_FORM_data16 - DWARFFormValue::FC_String, // 0x1f DW_FORM_line_strp - DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8 - DWARFFormValue::FC_Constant, // 0x21 DW_FORM_implicit_const - DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx - DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx - DWARFFormValue::FC_Reference, // 0x24 DW_FORM_ref_sup8 - DWARFFormValue::FC_String, // 0x25 DW_FORM_strx1 - DWARFFormValue::FC_String, // 0x26 DW_FORM_strx2 - DWARFFormValue::FC_String, // 0x27 DW_FORM_strx3 - DWARFFormValue::FC_String, // 0x28 DW_FORM_strx4 - DWARFFormValue::FC_Address, // 0x29 DW_FORM_addrx1 - DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2 - DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3 - DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4 - -}; - -DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) { - return DWARFFormValue(F, ValueType(V)); -} - -DWARFFormValue DWARFFormValue::createFromUValue(dwarf::Form F, uint64_t V) { - return DWARFFormValue(F, ValueType(V)); -} - -DWARFFormValue DWARFFormValue::createFromPValue(dwarf::Form F, const char *V) { - return DWARFFormValue(F, ValueType(V)); -} - -DWARFFormValue DWARFFormValue::createFromBlockValue(dwarf::Form F, - ArrayRef<uint8_t> D) { - ValueType V; - V.uval = D.size(); - V.data = D.data(); - return DWARFFormValue(F, V); -} - -DWARFFormValue DWARFFormValue::createFromUnit(dwarf::Form F, const DWARFUnit *U, - uint64_t *OffsetPtr) { - DWARFFormValue FormValue(F); - FormValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, - U->getFormParams(), U); - return FormValue; -} - -bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint64_t *OffsetPtr, - const dwarf::FormParams Params) { - 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_data16: - 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_sup4: - case DW_FORM_ref_sup8: - case DW_FORM_strx1: - case DW_FORM_strx2: - case DW_FORM_strx4: - case DW_FORM_addrx1: - case DW_FORM_addrx2: - case DW_FORM_addrx4: - case DW_FORM_sec_offset: - case DW_FORM_strp: - case DW_FORM_strp_sup: - case DW_FORM_line_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: +//===- DWARFFormValue.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> +#include <limits> + +using namespace llvm; +using namespace dwarf; + +static const DWARFFormValue::FormClass DWARF5FormClasses[] = { + DWARFFormValue::FC_Unknown, // 0x0 + DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr + DWARFFormValue::FC_Unknown, // 0x02 unused + DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2 + DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4 + DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2 + // --- These can be FC_SectionOffset in DWARF3 and below: + DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4 + DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8 + // --- + DWARFFormValue::FC_String, // 0x08 DW_FORM_string + DWARFFormValue::FC_Block, // 0x09 DW_FORM_block + DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1 + DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1 + DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag + DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata + DWARFFormValue::FC_String, // 0x0e DW_FORM_strp + DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata + DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr + DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1 + DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2 + DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4 + DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8 + DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata + DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect + DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset + DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc + DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present + DWARFFormValue::FC_String, // 0x1a DW_FORM_strx + DWARFFormValue::FC_Address, // 0x1b DW_FORM_addrx + DWARFFormValue::FC_Reference, // 0x1c DW_FORM_ref_sup4 + DWARFFormValue::FC_String, // 0x1d DW_FORM_strp_sup + DWARFFormValue::FC_Constant, // 0x1e DW_FORM_data16 + DWARFFormValue::FC_String, // 0x1f DW_FORM_line_strp + DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8 + DWARFFormValue::FC_Constant, // 0x21 DW_FORM_implicit_const + DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx + DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx + DWARFFormValue::FC_Reference, // 0x24 DW_FORM_ref_sup8 + DWARFFormValue::FC_String, // 0x25 DW_FORM_strx1 + DWARFFormValue::FC_String, // 0x26 DW_FORM_strx2 + DWARFFormValue::FC_String, // 0x27 DW_FORM_strx3 + DWARFFormValue::FC_String, // 0x28 DW_FORM_strx4 + DWARFFormValue::FC_Address, // 0x29 DW_FORM_addrx1 + DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2 + DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3 + DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4 + +}; + +DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromUValue(dwarf::Form F, uint64_t V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromPValue(dwarf::Form F, const char *V) { + return DWARFFormValue(F, ValueType(V)); +} + +DWARFFormValue DWARFFormValue::createFromBlockValue(dwarf::Form F, + ArrayRef<uint8_t> D) { + ValueType V; + V.uval = D.size(); + V.data = D.data(); + return DWARFFormValue(F, V); +} + +DWARFFormValue DWARFFormValue::createFromUnit(dwarf::Form F, const DWARFUnit *U, + uint64_t *OffsetPtr) { + DWARFFormValue FormValue(F); + FormValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, + U->getFormParams(), U); + return FormValue; +} + +bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, + uint64_t *OffsetPtr, + const dwarf::FormParams Params) { + 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_data16: + 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_sup4: + case DW_FORM_ref_sup8: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx4: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx4: + case DW_FORM_sec_offset: + case DW_FORM_strp: + case DW_FORM_strp_sup: + case DW_FORM_line_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: case DW_FORM_implicit_const: - if (Optional<uint8_t> FixedSize = - dwarf::getFixedFormByteSize(Form, Params)) { - *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; -} - -bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { - // First, check DWARF5 form classes. - if (Form < makeArrayRef(DWARF5FormClasses).size() && - DWARF5FormClasses[Form] == FC) - return true; - // Check more forms from extensions and proposals. - switch (Form) { - case DW_FORM_GNU_ref_alt: - return (FC == FC_Reference); - case DW_FORM_GNU_addr_index: - return (FC == FC_Address); - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_strp_alt: - return (FC == FC_String); - default: - break; - } - - if (FC == FC_SectionOffset) { - if (Form == DW_FORM_strp || Form == DW_FORM_line_strp) - return true; - // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section - // offset. If we don't have a DWARFUnit, default to the old behavior. - if (Form == DW_FORM_data4 || Form == DW_FORM_data8) - return !U || U->getVersion() <= 3; - } - - return false; -} - -bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, - uint64_t *OffsetPtr, dwarf::FormParams FP, - const DWARFContext *Ctx, - const DWARFUnit *CU) { - if (!Ctx && CU) - Ctx = &CU->getContext(); - C = Ctx; - U = CU; - Format = FP.Format; - bool Indirect = false; - bool IsBlock = false; - Value.data = nullptr; - // Read the value for the form into value and follow and DW_FORM_indirect - // instances we run into - Error Err = Error::success(); - do { - Indirect = false; - switch (Form) { - case DW_FORM_addr: - case DW_FORM_ref_addr: { - uint16_t Size = - (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize(); - Value.uval = - Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex, &Err); - break; - } - case DW_FORM_exprloc: - case DW_FORM_block: - Value.uval = Data.getULEB128(OffsetPtr, &Err); - IsBlock = true; - break; - case DW_FORM_block1: - Value.uval = Data.getU8(OffsetPtr, &Err); - IsBlock = true; - break; - case DW_FORM_block2: - Value.uval = Data.getU16(OffsetPtr, &Err); - IsBlock = true; - break; - case DW_FORM_block4: - Value.uval = Data.getU32(OffsetPtr, &Err); - IsBlock = true; - break; - case DW_FORM_data1: - case DW_FORM_ref1: - case DW_FORM_flag: - case DW_FORM_strx1: - case DW_FORM_addrx1: - Value.uval = Data.getU8(OffsetPtr, &Err); - break; - case DW_FORM_data2: - case DW_FORM_ref2: - case DW_FORM_strx2: - case DW_FORM_addrx2: - Value.uval = Data.getU16(OffsetPtr, &Err); - break; - case DW_FORM_strx3: - Value.uval = Data.getU24(OffsetPtr, &Err); - break; - case DW_FORM_data4: - case DW_FORM_ref4: - case DW_FORM_ref_sup4: - case DW_FORM_strx4: - case DW_FORM_addrx4: - Value.uval = Data.getRelocatedValue(4, OffsetPtr, nullptr, &Err); - break; - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sup8: - Value.uval = Data.getRelocatedValue(8, OffsetPtr, nullptr, &Err); - break; - case DW_FORM_data16: - // Treat this like a 16-byte block. - Value.uval = 16; - IsBlock = true; - break; - case DW_FORM_sdata: - Value.sval = Data.getSLEB128(OffsetPtr, &Err); - break; - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_rnglistx: - case DW_FORM_loclistx: - case DW_FORM_GNU_addr_index: - case DW_FORM_GNU_str_index: - case DW_FORM_addrx: - case DW_FORM_strx: - Value.uval = Data.getULEB128(OffsetPtr, &Err); - break; - case DW_FORM_string: - Value.cstr = Data.getCStr(OffsetPtr, &Err); - break; - case DW_FORM_indirect: - Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr, &Err)); - Indirect = true; - break; - case DW_FORM_strp: - case DW_FORM_sec_offset: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - case DW_FORM_line_strp: - case DW_FORM_strp_sup: { - Value.uval = Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), - OffsetPtr, nullptr, &Err); - break; - } - case DW_FORM_flag_present: - Value.uval = 1; - break; - case DW_FORM_ref_sig8: - Value.uval = Data.getU64(OffsetPtr, &Err); - break; + if (Optional<uint8_t> FixedSize = + dwarf::getFixedFormByteSize(Form, Params)) { + *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; +} + +bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { + // First, check DWARF5 form classes. + if (Form < makeArrayRef(DWARF5FormClasses).size() && + DWARF5FormClasses[Form] == FC) + return true; + // Check more forms from extensions and proposals. + switch (Form) { + case DW_FORM_GNU_ref_alt: + return (FC == FC_Reference); + case DW_FORM_GNU_addr_index: + return (FC == FC_Address); + case DW_FORM_GNU_str_index: + case DW_FORM_GNU_strp_alt: + return (FC == FC_String); + default: + break; + } + + if (FC == FC_SectionOffset) { + if (Form == DW_FORM_strp || Form == DW_FORM_line_strp) + return true; + // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section + // offset. If we don't have a DWARFUnit, default to the old behavior. + if (Form == DW_FORM_data4 || Form == DW_FORM_data8) + return !U || U->getVersion() <= 3; + } + + return false; +} + +bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data, + uint64_t *OffsetPtr, dwarf::FormParams FP, + const DWARFContext *Ctx, + const DWARFUnit *CU) { + if (!Ctx && CU) + Ctx = &CU->getContext(); + C = Ctx; + U = CU; + Format = FP.Format; + bool Indirect = false; + bool IsBlock = false; + Value.data = nullptr; + // Read the value for the form into value and follow and DW_FORM_indirect + // instances we run into + Error Err = Error::success(); + do { + Indirect = false; + switch (Form) { + case DW_FORM_addr: + case DW_FORM_ref_addr: { + uint16_t Size = + (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize(); + Value.uval = + Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex, &Err); + break; + } + case DW_FORM_exprloc: + case DW_FORM_block: + Value.uval = Data.getULEB128(OffsetPtr, &Err); + IsBlock = true; + break; + case DW_FORM_block1: + Value.uval = Data.getU8(OffsetPtr, &Err); + IsBlock = true; + break; + case DW_FORM_block2: + Value.uval = Data.getU16(OffsetPtr, &Err); + IsBlock = true; + break; + case DW_FORM_block4: + Value.uval = Data.getU32(OffsetPtr, &Err); + IsBlock = true; + break; + case DW_FORM_data1: + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_strx1: + case DW_FORM_addrx1: + Value.uval = Data.getU8(OffsetPtr, &Err); + break; + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_strx2: + case DW_FORM_addrx2: + Value.uval = Data.getU16(OffsetPtr, &Err); + break; + case DW_FORM_strx3: + Value.uval = Data.getU24(OffsetPtr, &Err); + break; + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_ref_sup4: + case DW_FORM_strx4: + case DW_FORM_addrx4: + Value.uval = Data.getRelocatedValue(4, OffsetPtr, nullptr, &Err); + break; + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sup8: + Value.uval = Data.getRelocatedValue(8, OffsetPtr, nullptr, &Err); + break; + case DW_FORM_data16: + // Treat this like a 16-byte block. + Value.uval = 16; + IsBlock = true; + break; + case DW_FORM_sdata: + Value.sval = Data.getSLEB128(OffsetPtr, &Err); + break; + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_rnglistx: + case DW_FORM_loclistx: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + case DW_FORM_addrx: + case DW_FORM_strx: + Value.uval = Data.getULEB128(OffsetPtr, &Err); + break; + case DW_FORM_string: + Value.cstr = Data.getCStr(OffsetPtr, &Err); + break; + case DW_FORM_indirect: + Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr, &Err)); + Indirect = true; + break; + case DW_FORM_strp: + case DW_FORM_sec_offset: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_strp_sup: { + Value.uval = Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), + OffsetPtr, nullptr, &Err); + break; + } + case DW_FORM_flag_present: + Value.uval = 1; + break; + case DW_FORM_ref_sig8: + Value.uval = Data.getU64(OffsetPtr, &Err); + break; case DW_FORM_implicit_const: // Value has been already set by DWARFFormValue::createFromSValue. break; - default: - // DWARFFormValue::skipValue() will have caught this and caused all - // DWARF DIEs to fail to be parsed, so this code is not be reachable. - llvm_unreachable("unsupported form"); - } - } while (Indirect && !Err); - - if (IsBlock) - Value.data = Data.getBytes(OffsetPtr, Value.uval, &Err).bytes_begin(); - - return !errorToBool(std::move(Err)); -} - + default: + // DWARFFormValue::skipValue() will have caught this and caused all + // DWARF DIEs to fail to be parsed, so this code is not be reachable. + llvm_unreachable("unsupported form"); + } + } while (Indirect && !Err); + + if (IsBlock) + Value.data = Data.getBytes(OffsetPtr, Value.uval, &Err).bytes_begin(); + + return !errorToBool(std::move(Err)); +} + void DWARFFormValue::dumpAddress(raw_ostream &OS, uint8_t AddressSize, uint64_t Address) { uint8_t HexDigits = AddressSize * 2; OS << format("0x%*.*" PRIx64, HexDigits, HexDigits, Address); } -void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS, - DIDumpOptions DumpOpts, - object::SectionedAddress SA) const { +void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS, + DIDumpOptions DumpOpts, + object::SectionedAddress SA) const { dumpAddress(OS, U->getAddressByteSize(), SA.Address); - dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts, - SA.SectionIndex); -} - -void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS, - DIDumpOptions DumpOpts, - uint64_t SectionIndex) { - if (!DumpOpts.Verbose || SectionIndex == -1ULL) - return; - ArrayRef<SectionName> SectionNames = Obj.getSectionNames(); - const auto &SecRef = SectionNames[SectionIndex]; - - OS << " \"" << SecRef.Name << '\"'; - - // Print section index if name is not unique. - if (!SecRef.IsNameUnique) - OS << format(" [%" PRIu64 "]", SectionIndex); -} - -void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { - uint64_t UValue = Value.uval; - bool CURelativeOffset = false; - raw_ostream &AddrOS = DumpOpts.ShowAddresses - ? WithColor(OS, HighlightColor::Address).get() - : nulls(); - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); - switch (Form) { - case DW_FORM_addr: - dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex}); - break; - case DW_FORM_addrx: - case DW_FORM_addrx1: - case DW_FORM_addrx2: - case DW_FORM_addrx3: - case DW_FORM_addrx4: - case DW_FORM_GNU_addr_index: { - if (U == nullptr) { - OS << "<invalid dwarf unit>"; - break; - } - Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(UValue); - if (!A || DumpOpts.Verbose) - AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue); - if (A) - dumpSectionedAddress(AddrOS, DumpOpts, *A); - else - OS << "<unresolved>"; - break; - } - case DW_FORM_flag_present: - OS << "true"; - break; - case DW_FORM_flag: - case DW_FORM_data1: - OS << format("0x%02x", (uint8_t)UValue); - break; - case DW_FORM_data2: - OS << format("0x%04x", (uint16_t)UValue); - break; - case DW_FORM_data4: - OS << format("0x%08x", (uint32_t)UValue); - break; - case DW_FORM_ref_sig8: - AddrOS << format("0x%016" PRIx64, UValue); - break; - case DW_FORM_data8: - OS << format("0x%016" PRIx64, UValue); - break; - case DW_FORM_data16: - OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16); - break; - case DW_FORM_string: - OS << '"'; - OS.write_escaped(Value.cstr); - OS << '"'; - break; - case DW_FORM_exprloc: - case DW_FORM_block: - case DW_FORM_block1: - case DW_FORM_block2: - case DW_FORM_block4: - if (UValue > 0) { - switch (Form) { - case DW_FORM_exprloc: - case DW_FORM_block: - AddrOS << format("<0x%" PRIx64 "> ", UValue); - break; - case DW_FORM_block1: - AddrOS << format("<0x%2.2x> ", (uint8_t)UValue); - break; - case DW_FORM_block2: - AddrOS << format("<0x%4.4x> ", (uint16_t)UValue); - break; - case DW_FORM_block4: - AddrOS << format("<0x%8.8x> ", (uint32_t)UValue); - break; - default: - break; - } - - const uint8_t *DataPtr = Value.data; - if (DataPtr) { - // UValue contains size of block - const uint8_t *EndDataPtr = DataPtr + UValue; - while (DataPtr < EndDataPtr) { - AddrOS << format("%2.2x ", *DataPtr); - ++DataPtr; - } - } else - OS << "NULL"; - } - break; - - case DW_FORM_sdata: + dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts, + SA.SectionIndex); +} + +void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS, + DIDumpOptions DumpOpts, + uint64_t SectionIndex) { + if (!DumpOpts.Verbose || SectionIndex == -1ULL) + return; + ArrayRef<SectionName> SectionNames = Obj.getSectionNames(); + const auto &SecRef = SectionNames[SectionIndex]; + + OS << " \"" << SecRef.Name << '\"'; + + // Print section index if name is not unique. + if (!SecRef.IsNameUnique) + OS << format(" [%" PRIu64 "]", SectionIndex); +} + +void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const { + uint64_t UValue = Value.uval; + bool CURelativeOffset = false; + raw_ostream &AddrOS = DumpOpts.ShowAddresses + ? WithColor(OS, HighlightColor::Address).get() + : nulls(); + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); + switch (Form) { + case DW_FORM_addr: + dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex}); + break; + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + case DW_FORM_GNU_addr_index: { + if (U == nullptr) { + OS << "<invalid dwarf unit>"; + break; + } + Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(UValue); + if (!A || DumpOpts.Verbose) + AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue); + if (A) + dumpSectionedAddress(AddrOS, DumpOpts, *A); + else + OS << "<unresolved>"; + break; + } + case DW_FORM_flag_present: + OS << "true"; + break; + case DW_FORM_flag: + case DW_FORM_data1: + OS << format("0x%02x", (uint8_t)UValue); + break; + case DW_FORM_data2: + OS << format("0x%04x", (uint16_t)UValue); + break; + case DW_FORM_data4: + OS << format("0x%08x", (uint32_t)UValue); + break; + case DW_FORM_ref_sig8: + AddrOS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_data8: + OS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_data16: + OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16); + break; + case DW_FORM_string: + OS << '"'; + OS.write_escaped(Value.cstr); + OS << '"'; + break; + case DW_FORM_exprloc: + case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: + if (UValue > 0) { + switch (Form) { + case DW_FORM_exprloc: + case DW_FORM_block: + AddrOS << format("<0x%" PRIx64 "> ", UValue); + break; + case DW_FORM_block1: + AddrOS << format("<0x%2.2x> ", (uint8_t)UValue); + break; + case DW_FORM_block2: + AddrOS << format("<0x%4.4x> ", (uint16_t)UValue); + break; + case DW_FORM_block4: + AddrOS << format("<0x%8.8x> ", (uint32_t)UValue); + break; + default: + break; + } + + const uint8_t *DataPtr = Value.data; + if (DataPtr) { + // UValue contains size of block + const uint8_t *EndDataPtr = DataPtr + UValue; + while (DataPtr < EndDataPtr) { + AddrOS << format("%2.2x ", *DataPtr); + ++DataPtr; + } + } else + OS << "NULL"; + } + break; + + case DW_FORM_sdata: case DW_FORM_implicit_const: - OS << Value.sval; - break; - case DW_FORM_udata: - OS << Value.uval; - break; - case DW_FORM_strp: - if (DumpOpts.Verbose) - OS << format(" .debug_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, UValue); - dumpString(OS); - break; - case DW_FORM_line_strp: - if (DumpOpts.Verbose) - OS << format(" .debug_line_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, - UValue); - dumpString(OS); - break; - case DW_FORM_strx: - case DW_FORM_strx1: - case DW_FORM_strx2: - case DW_FORM_strx3: - case DW_FORM_strx4: - case DW_FORM_GNU_str_index: - if (DumpOpts.Verbose) - OS << format("indexed (%8.8x) string = ", (uint32_t)UValue); - dumpString(OS); - break; - case DW_FORM_GNU_strp_alt: - if (DumpOpts.Verbose) - OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); - dumpString(OS); - break; - case DW_FORM_ref_addr: - AddrOS << format("0x%016" PRIx64, UValue); - break; - case DW_FORM_ref1: - CURelativeOffset = true; - if (DumpOpts.Verbose) - AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue); - break; - case DW_FORM_ref2: - CURelativeOffset = true; - if (DumpOpts.Verbose) - AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue); - break; - case DW_FORM_ref4: - CURelativeOffset = true; - if (DumpOpts.Verbose) - AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue); - break; - case DW_FORM_ref8: - CURelativeOffset = true; - if (DumpOpts.Verbose) - AddrOS << format("cu + 0x%8.8" PRIx64, UValue); - break; - case DW_FORM_ref_udata: - CURelativeOffset = true; - if (DumpOpts.Verbose) - AddrOS << format("cu + 0x%" PRIx64, UValue); - break; - case DW_FORM_GNU_ref_alt: - AddrOS << format("<alt 0x%" PRIx64 ">", UValue); - break; - - // All DW_FORM_indirect attributes should be resolved prior to calling - // this function - case DW_FORM_indirect: - OS << "DW_FORM_indirect"; - break; - - case DW_FORM_rnglistx: - OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue); - break; - - case DW_FORM_loclistx: - OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue); - break; - - case DW_FORM_sec_offset: - AddrOS << format("0x%0*" PRIx64, OffsetDumpWidth, UValue); - break; - - default: - OS << format("DW_FORM(0x%4.4x)", Form); - break; - } - - if (CURelativeOffset) { - if (DumpOpts.Verbose) - OS << " => {"; - if (DumpOpts.ShowAddresses) - WithColor(OS, HighlightColor::Address).get() - << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0)); - if (DumpOpts.Verbose) - OS << "}"; - } -} - -void DWARFFormValue::dumpString(raw_ostream &OS) const { - Optional<const char *> DbgStr = getAsCString(); - if (DbgStr.hasValue()) { - auto COS = WithColor(OS, HighlightColor::String); - COS.get() << '"'; - COS.get().write_escaped(DbgStr.getValue()); - COS.get() << '"'; - } -} - -Optional<const char *> DWARFFormValue::getAsCString() const { - if (!isFormClass(FC_String)) - return None; - if (Form == DW_FORM_string) - return Value.cstr; - // FIXME: Add support for DW_FORM_GNU_strp_alt - if (Form == DW_FORM_GNU_strp_alt || C == nullptr) - return None; - uint64_t Offset = Value.uval; - if (Form == DW_FORM_line_strp) { - // .debug_line_str is tracked in the Context. - if (const char *Str = C->getLineStringExtractor().getCStr(&Offset)) - return Str; - return None; - } - if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || - Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || - Form == DW_FORM_strx4) { - if (!U) - return None; - Optional<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset); - if (!StrOffset) - return None; - Offset = *StrOffset; - } - // Prefer the Unit's string extractor, because for .dwo it will point to - // .debug_str.dwo, while the Context's extractor always uses .debug_str. - if (U) { - if (const char *Str = U->getStringExtractor().getCStr(&Offset)) - return Str; - return None; - } - if (const char *Str = C->getStringExtractor().getCStr(&Offset)) - return Str; - return None; -} - -Optional<uint64_t> DWARFFormValue::getAsAddress() const { - if (auto SA = getAsSectionedAddress()) - return SA->Address; - return None; -} - -Optional<object::SectionedAddress> -DWARFFormValue::getAsSectionedAddress() const { - if (!isFormClass(FC_Address)) - return None; - if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) { - uint32_t Index = Value.uval; - if (!U) - return None; - Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index); - if (!SA) - return None; - return SA; - } - return {{Value.uval, Value.SectionIndex}}; -} - -Optional<uint64_t> DWARFFormValue::getAsReference() const { - if (auto R = getAsRelativeReference()) - return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset; - return None; -} - -Optional<DWARFFormValue::UnitOffset> DWARFFormValue::getAsRelativeReference() const { - if (!isFormClass(FC_Reference)) - return None; - switch (Form) { - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: - if (!U) - return None; - return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval}; - case DW_FORM_ref_addr: - case DW_FORM_ref_sig8: - case DW_FORM_GNU_ref_alt: - return UnitOffset{nullptr, Value.uval}; - default: - return None; - } -} - -Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const { - if (!isFormClass(FC_SectionOffset)) - return None; - return Value.uval; -} - -Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const { - if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || - Form == DW_FORM_sdata) - return None; - return Value.uval; -} - -Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { - if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || - (Form == DW_FORM_udata && - uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) - return None; - switch (Form) { - case DW_FORM_data4: - return int32_t(Value.uval); - case DW_FORM_data2: - return int16_t(Value.uval); - case DW_FORM_data1: - return int8_t(Value.uval); - case DW_FORM_sdata: - case DW_FORM_data8: - default: - return Value.sval; - } -} - -Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { - if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) && - Form != DW_FORM_data16) - return None; - 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; -} + OS << Value.sval; + break; + case DW_FORM_udata: + OS << Value.uval; + break; + case DW_FORM_strp: + if (DumpOpts.Verbose) + OS << format(" .debug_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, UValue); + dumpString(OS); + break; + case DW_FORM_line_strp: + if (DumpOpts.Verbose) + OS << format(" .debug_line_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, + UValue); + dumpString(OS); + break; + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + case DW_FORM_GNU_str_index: + if (DumpOpts.Verbose) + OS << format("indexed (%8.8x) string = ", (uint32_t)UValue); + dumpString(OS); + break; + case DW_FORM_GNU_strp_alt: + if (DumpOpts.Verbose) + OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue); + dumpString(OS); + break; + case DW_FORM_ref_addr: + AddrOS << format("0x%016" PRIx64, UValue); + break; + case DW_FORM_ref1: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue); + break; + case DW_FORM_ref2: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue); + break; + case DW_FORM_ref4: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue); + break; + case DW_FORM_ref8: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%8.8" PRIx64, UValue); + break; + case DW_FORM_ref_udata: + CURelativeOffset = true; + if (DumpOpts.Verbose) + AddrOS << format("cu + 0x%" PRIx64, UValue); + break; + case DW_FORM_GNU_ref_alt: + AddrOS << format("<alt 0x%" PRIx64 ">", UValue); + break; + + // All DW_FORM_indirect attributes should be resolved prior to calling + // this function + case DW_FORM_indirect: + OS << "DW_FORM_indirect"; + break; + + case DW_FORM_rnglistx: + OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue); + break; + + case DW_FORM_loclistx: + OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue); + break; + + case DW_FORM_sec_offset: + AddrOS << format("0x%0*" PRIx64, OffsetDumpWidth, UValue); + break; + + default: + OS << format("DW_FORM(0x%4.4x)", Form); + break; + } + + if (CURelativeOffset) { + if (DumpOpts.Verbose) + OS << " => {"; + if (DumpOpts.ShowAddresses) + WithColor(OS, HighlightColor::Address).get() + << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0)); + if (DumpOpts.Verbose) + OS << "}"; + } +} + +void DWARFFormValue::dumpString(raw_ostream &OS) const { + Optional<const char *> DbgStr = getAsCString(); + if (DbgStr.hasValue()) { + auto COS = WithColor(OS, HighlightColor::String); + COS.get() << '"'; + COS.get().write_escaped(DbgStr.getValue()); + COS.get() << '"'; + } +} + +Optional<const char *> DWARFFormValue::getAsCString() const { + if (!isFormClass(FC_String)) + return None; + if (Form == DW_FORM_string) + return Value.cstr; + // FIXME: Add support for DW_FORM_GNU_strp_alt + if (Form == DW_FORM_GNU_strp_alt || C == nullptr) + return None; + uint64_t Offset = Value.uval; + if (Form == DW_FORM_line_strp) { + // .debug_line_str is tracked in the Context. + if (const char *Str = C->getLineStringExtractor().getCStr(&Offset)) + return Str; + return None; + } + if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || + Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || + Form == DW_FORM_strx4) { + if (!U) + return None; + Optional<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset); + if (!StrOffset) + return None; + Offset = *StrOffset; + } + // Prefer the Unit's string extractor, because for .dwo it will point to + // .debug_str.dwo, while the Context's extractor always uses .debug_str. + if (U) { + if (const char *Str = U->getStringExtractor().getCStr(&Offset)) + return Str; + return None; + } + if (const char *Str = C->getStringExtractor().getCStr(&Offset)) + return Str; + return None; +} + +Optional<uint64_t> DWARFFormValue::getAsAddress() const { + if (auto SA = getAsSectionedAddress()) + return SA->Address; + return None; +} + +Optional<object::SectionedAddress> +DWARFFormValue::getAsSectionedAddress() const { + if (!isFormClass(FC_Address)) + return None; + if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) { + uint32_t Index = Value.uval; + if (!U) + return None; + Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index); + if (!SA) + return None; + return SA; + } + return {{Value.uval, Value.SectionIndex}}; +} + +Optional<uint64_t> DWARFFormValue::getAsReference() const { + if (auto R = getAsRelativeReference()) + return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset; + return None; +} + +Optional<DWARFFormValue::UnitOffset> DWARFFormValue::getAsRelativeReference() const { + if (!isFormClass(FC_Reference)) + return None; + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + if (!U) + return None; + return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval}; + case DW_FORM_ref_addr: + case DW_FORM_ref_sig8: + case DW_FORM_GNU_ref_alt: + return UnitOffset{nullptr, Value.uval}; + default: + return None; + } +} + +Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const { + if (!isFormClass(FC_SectionOffset)) + return None; + return Value.uval; +} + +Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const { + if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || + Form == DW_FORM_sdata) + return None; + return Value.uval; +} + +Optional<int64_t> DWARFFormValue::getAsSignedConstant() const { + if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) || + (Form == DW_FORM_udata && + uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval)) + return None; + switch (Form) { + case DW_FORM_data4: + return int32_t(Value.uval); + case DW_FORM_data2: + return int16_t(Value.uval); + case DW_FORM_data1: + return int8_t(Value.uval); + case DW_FORM_sdata: + case DW_FORM_data8: + default: + return Value.sval; + } +} + +Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const { + if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) && + Form != DW_FORM_data16) + return None; + 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/libs/llvm12/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp index ace7000f07..b6ed48642e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp @@ -1,199 +1,199 @@ -//===- DWARFGdbIndex.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cassert> -#include <cinttypes> -#include <cstdint> -#include <utility> - -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::dumpTUList(raw_ostream &OS) const { - OS << formatv("\n Types CU list offset = {0:x}, has {1} entries:\n", - TuListOffset, TuList.size()); - uint32_t I = 0; - for (const TypeUnitEntry &TU : TuList) - OS << formatv(" {0}: offset = {1:x8}, type_offset = {2:x8}, " - "type_signature = {3:x16}\n", - I++, TU.Offset, TU.TypeOffset, TU.TypeSignature); -} - -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/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n", - Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress, - 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); - +//===- DWARFGdbIndex.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <utility> + +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::dumpTUList(raw_ostream &OS) const { + OS << formatv("\n Types CU list offset = {0:x}, has {1} entries:\n", + TuListOffset, TuList.size()); + uint32_t I = 0; + for (const TypeUnitEntry &TU : TuList) + OS << formatv(" {0}: offset = {1:x8}, type_offset = {2:x8}, " + "type_signature = {3:x16}\n", + I++, TU.Offset, TU.TypeOffset, TU.TypeSignature); +} + +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/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n", + Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress, + 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 = llvm::find_if( ConstantPoolVectors, - [&](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); - dumpTUList(OS); - dumpAddressArea(OS); - dumpSymbolTable(OS); - dumpConstantPool(OS); - } -} - -bool DWARFGdbIndex::parseImpl(DataExtractor Data) { - uint64_t Offset = 0; - - // Only version 7 is supported at this moment. - Version = Data.getU32(&Offset); - if (Version != 7) - return false; - - CuListOffset = Data.getU32(&Offset); - TuListOffset = Data.getU32(&Offset); - AddressAreaOffset = Data.getU32(&Offset); - SymbolTableOffset = Data.getU32(&Offset); - ConstantPoolOffset = Data.getU32(&Offset); - - if (Offset != CuListOffset) - return false; - - uint32_t CuListSize = (TuListOffset - 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 TuListSize = (AddressAreaOffset - TuListOffset) / 24; - TuList.resize(TuListSize); - for (uint32_t I = 0; I < TuListSize; ++I) { - uint64_t CuOffset = Data.getU64(&Offset); - uint64_t TypeOffset = Data.getU64(&Offset); - uint64_t Signature = Data.getU64(&Offset); - TuList[I] = {CuOffset, TypeOffset, Signature}; - } - - 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); -} + [&](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); + dumpTUList(OS); + dumpAddressArea(OS); + dumpSymbolTable(OS); + dumpConstantPool(OS); + } +} + +bool DWARFGdbIndex::parseImpl(DataExtractor Data) { + uint64_t Offset = 0; + + // Only version 7 is supported at this moment. + Version = Data.getU32(&Offset); + if (Version != 7) + return false; + + CuListOffset = Data.getU32(&Offset); + TuListOffset = Data.getU32(&Offset); + AddressAreaOffset = Data.getU32(&Offset); + SymbolTableOffset = Data.getU32(&Offset); + ConstantPoolOffset = Data.getU32(&Offset); + + if (Offset != CuListOffset) + return false; + + uint32_t CuListSize = (TuListOffset - 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 TuListSize = (AddressAreaOffset - TuListOffset) / 24; + TuList.resize(TuListSize); + for (uint32_t I = 0; I < TuListSize; ++I) { + uint64_t CuOffset = Data.getU64(&Offset); + uint64_t TypeOffset = Data.getU64(&Offset); + uint64_t Signature = Data.getU64(&Offset); + TuList[I] = {CuOffset, TypeOffset, Signature}; + } + + 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/libs/llvm12/lib/DebugInfo/DWARF/DWARFListTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFListTable.cpp index c876af1e9b..9aa07dd451 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFListTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -1,109 +1,109 @@ -//===- DWARFListTable.cpp ---------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFListTable.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -Error DWARFListTableHeader::extract(DWARFDataExtractor Data, - uint64_t *OffsetPtr) { - HeaderOffset = *OffsetPtr; - Error Err = Error::success(); - - std::tie(HeaderData.Length, Format) = Data.getInitialLength(OffsetPtr, &Err); - if (Err) - return createStringError( - errc::invalid_argument, "parsing %s table at offset 0x%" PRIx64 ": %s", - SectionName.data(), HeaderOffset, toString(std::move(Err)).c_str()); - - uint8_t OffsetByteSize = Format == dwarf::DWARF64 ? 8 : 4; - uint64_t FullLength = - HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format); - if (FullLength < getHeaderSize(Format)) - return createStringError(errc::invalid_argument, - "%s table at offset 0x%" PRIx64 - " has too small length (0x%" PRIx64 - ") to contain a complete header", - SectionName.data(), HeaderOffset, FullLength); - assert(FullLength == length() && "Inconsistent calculation of length."); - uint64_t End = HeaderOffset + FullLength; - if (!Data.isValidOffsetForDataOfSize(HeaderOffset, FullLength)) - return createStringError(errc::invalid_argument, - "section is not large enough to contain a %s table " - "of length 0x%" PRIx64 " at offset 0x%" PRIx64, - SectionName.data(), FullLength, HeaderOffset); - - HeaderData.Version = Data.getU16(OffsetPtr); - HeaderData.AddrSize = Data.getU8(OffsetPtr); - HeaderData.SegSize = Data.getU8(OffsetPtr); - HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); - - // Perform basic validation of the remaining header fields. - if (HeaderData.Version != 5) - return createStringError(errc::invalid_argument, - "unrecognised %s table version %" PRIu16 - " in table at offset 0x%" PRIx64, - SectionName.data(), HeaderData.Version, HeaderOffset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) - return createStringError(errc::not_supported, - "%s table at offset 0x%" PRIx64 - " has unsupported address size %" PRIu8, - SectionName.data(), HeaderOffset, HeaderData.AddrSize); - if (HeaderData.SegSize != 0) - return createStringError(errc::not_supported, - "%s table at offset 0x%" PRIx64 - " has unsupported segment selector size %" PRIu8, - SectionName.data(), HeaderOffset, HeaderData.SegSize); - if (End < HeaderOffset + getHeaderSize(Format) + - HeaderData.OffsetEntryCount * OffsetByteSize) - return createStringError(errc::invalid_argument, - "%s table at offset 0x%" PRIx64 " has more offset entries (%" PRIu32 - ") than there is space for", - SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount); - Data.setAddressSize(HeaderData.AddrSize); +//===- DWARFListTable.cpp ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFListTable.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +Error DWARFListTableHeader::extract(DWARFDataExtractor Data, + uint64_t *OffsetPtr) { + HeaderOffset = *OffsetPtr; + Error Err = Error::success(); + + std::tie(HeaderData.Length, Format) = Data.getInitialLength(OffsetPtr, &Err); + if (Err) + return createStringError( + errc::invalid_argument, "parsing %s table at offset 0x%" PRIx64 ": %s", + SectionName.data(), HeaderOffset, toString(std::move(Err)).c_str()); + + uint8_t OffsetByteSize = Format == dwarf::DWARF64 ? 8 : 4; + uint64_t FullLength = + HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format); + if (FullLength < getHeaderSize(Format)) + return createStringError(errc::invalid_argument, + "%s table at offset 0x%" PRIx64 + " has too small length (0x%" PRIx64 + ") to contain a complete header", + SectionName.data(), HeaderOffset, FullLength); + assert(FullLength == length() && "Inconsistent calculation of length."); + uint64_t End = HeaderOffset + FullLength; + if (!Data.isValidOffsetForDataOfSize(HeaderOffset, FullLength)) + return createStringError(errc::invalid_argument, + "section is not large enough to contain a %s table " + "of length 0x%" PRIx64 " at offset 0x%" PRIx64, + SectionName.data(), FullLength, HeaderOffset); + + HeaderData.Version = Data.getU16(OffsetPtr); + HeaderData.AddrSize = Data.getU8(OffsetPtr); + HeaderData.SegSize = Data.getU8(OffsetPtr); + HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr); + + // Perform basic validation of the remaining header fields. + if (HeaderData.Version != 5) + return createStringError(errc::invalid_argument, + "unrecognised %s table version %" PRIu16 + " in table at offset 0x%" PRIx64, + SectionName.data(), HeaderData.Version, HeaderOffset); + if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) + return createStringError(errc::not_supported, + "%s table at offset 0x%" PRIx64 + " has unsupported address size %" PRIu8, + SectionName.data(), HeaderOffset, HeaderData.AddrSize); + if (HeaderData.SegSize != 0) + return createStringError(errc::not_supported, + "%s table at offset 0x%" PRIx64 + " has unsupported segment selector size %" PRIu8, + SectionName.data(), HeaderOffset, HeaderData.SegSize); + if (End < HeaderOffset + getHeaderSize(Format) + + HeaderData.OffsetEntryCount * OffsetByteSize) + return createStringError(errc::invalid_argument, + "%s table at offset 0x%" PRIx64 " has more offset entries (%" PRIu32 + ") than there is space for", + SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount); + Data.setAddressSize(HeaderData.AddrSize); *OffsetPtr += HeaderData.OffsetEntryCount * OffsetByteSize; - return Error::success(); -} - + return Error::success(); +} + void DWARFListTableHeader::dump(DataExtractor Data, raw_ostream &OS, DIDumpOptions DumpOpts) const { - if (DumpOpts.Verbose) - OS << format("0x%8.8" PRIx64 ": ", HeaderOffset); - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); - OS << format("%s list header: length = 0x%0*" PRIx64, ListTypeString.data(), - OffsetDumpWidth, HeaderData.Length) - << ", format = " << dwarf::FormatString(Format) - << format(", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8 - ", seg_size = 0x%2.2" PRIx8 - ", offset_entry_count = 0x%8.8" PRIx32 "\n", - HeaderData.Version, HeaderData.AddrSize, HeaderData.SegSize, - HeaderData.OffsetEntryCount); - - if (HeaderData.OffsetEntryCount > 0) { - OS << "offsets: ["; + if (DumpOpts.Verbose) + OS << format("0x%8.8" PRIx64 ": ", HeaderOffset); + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format); + OS << format("%s list header: length = 0x%0*" PRIx64, ListTypeString.data(), + OffsetDumpWidth, HeaderData.Length) + << ", format = " << dwarf::FormatString(Format) + << format(", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8 + ", seg_size = 0x%2.2" PRIx8 + ", offset_entry_count = 0x%8.8" PRIx32 "\n", + HeaderData.Version, HeaderData.AddrSize, HeaderData.SegSize, + HeaderData.OffsetEntryCount); + + if (HeaderData.OffsetEntryCount > 0) { + OS << "offsets: ["; for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) { auto Off = *getOffsetEntry(Data, I); - OS << format("\n0x%0*" PRIx64, OffsetDumpWidth, Off); - if (DumpOpts.Verbose) - OS << format(" => 0x%08" PRIx64, - Off + HeaderOffset + getHeaderSize(Format)); - } - OS << "\n]\n"; - } -} - -uint64_t DWARFListTableHeader::length() const { - if (HeaderData.Length == 0) - return 0; - return HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format); -} + OS << format("\n0x%0*" PRIx64, OffsetDumpWidth, Off); + if (DumpOpts.Verbose) + OS << format(" => 0x%08" PRIx64, + Off + HeaderOffset + getHeaderSize(Format)); + } + OS << "\n]\n"; + } +} + +uint64_t DWARFListTableHeader::length() const { + if (HeaderData.Length == 0) + return 0; + return HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp index 1cf73a6667..880d3c2c68 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp @@ -1,19 +1,19 @@ -//===- DWARFLocationExpression.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; - -raw_ostream &llvm::operator<<(raw_ostream &OS, - const DWARFLocationExpression &Loc) { - return OS << Loc.Range << ": " - << formatv("{0}", make_range(Loc.Expr.begin(), Loc.Expr.end())); -} +//===- DWARFLocationExpression.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; + +raw_ostream &llvm::operator<<(raw_ostream &OS, + const DWARFLocationExpression &Loc) { + return OS << Loc.Range << ": " + << formatv("{0}", make_range(Loc.Expr.begin(), Loc.Expr.end())); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp index a301b65dd4..307494a0c1 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp @@ -1,53 +1,53 @@ -//===- DWARFTypeUnit.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cinttypes> - -using namespace llvm; - -void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { - DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset()); - const char *Name = TD.getName(DINameKind::ShortName); - int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat()); - - if (DumpOpts.SummarizeTypes) { - OS << "name = '" << Name << "'" - << ", type_signature = " << format("0x%016" PRIx64, getTypeHash()) - << ", length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) - << '\n'; - return; - } - - OS << format("0x%08" PRIx64, getOffset()) << ": Type Unit:" - << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) - << ", format = " << dwarf::FormatString(getFormat()) - << ", version = " << format("0x%04x", getVersion()); - if (getVersion() >= 5) - OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType()); +//===- DWARFTypeUnit.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> + +using namespace llvm; + +void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { + DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset()); + const char *Name = TD.getName(DINameKind::ShortName); + int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat()); + + if (DumpOpts.SummarizeTypes) { + OS << "name = '" << Name << "'" + << ", type_signature = " << format("0x%016" PRIx64, getTypeHash()) + << ", length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) + << '\n'; + return; + } + + OS << format("0x%08" PRIx64, getOffset()) << ": Type Unit:" + << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength()) + << ", format = " << dwarf::FormatString(getFormat()) + << ", version = " << format("0x%04x", getVersion()); + if (getVersion() >= 5) + OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType()); OS << ", abbr_offset = " << format("0x%04" PRIx64, getAbbrOffset()); if (!getAbbreviations()) OS << " (invalid)"; OS << ", addr_size = " << format("0x%02x", getAddressByteSize()) - << ", name = '" << Name << "'" - << ", type_signature = " << format("0x%016" PRIx64, getTypeHash()) - << ", type_offset = " << format("0x%04" PRIx64, getTypeOffset()) - << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset()) - << ")\n"; - - if (DWARFDie TU = getUnitDIE(false)) - TU.dump(OS, 0, DumpOpts); - else - OS << "<type unit can't be parsed!>\n\n"; -} + << ", name = '" << Name << "'" + << ", type_signature = " << format("0x%016" PRIx64, getTypeHash()) + << ", type_offset = " << format("0x%04" PRIx64, getTypeOffset()) + << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset()) + << ")\n"; + + if (DWARFDie TU = getUnitDIE(false)) + TU.dump(OS, 0, DumpOpts); + else + OS << "<type unit can't be parsed!>\n\n"; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnit.cpp index 8493950a29..7268cbd4ab 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -1,487 +1,487 @@ -//===- DWARFUnit.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.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/DWARFDebugRnglists.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/Path.h" -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <cstdio> -#include <utility> -#include <vector> - -using namespace llvm; -using namespace dwarf; - -void DWARFUnitVector::addUnitsForSection(DWARFContext &C, - const DWARFSection &Section, - DWARFSectionKind SectionKind) { - const DWARFObject &D = C.getDWARFObj(); - addUnitsImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangesSection(), - &D.getLocSection(), D.getStrSection(), - D.getStrOffsetsSection(), &D.getAddrSection(), - D.getLineSection(), D.isLittleEndian(), false, false, - SectionKind); -} - -void DWARFUnitVector::addUnitsForDWOSection(DWARFContext &C, - const DWARFSection &DWOSection, - DWARFSectionKind SectionKind, - bool Lazy) { - const DWARFObject &D = C.getDWARFObj(); - addUnitsImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangesDWOSection(), - &D.getLocDWOSection(), D.getStrDWOSection(), - D.getStrOffsetsDWOSection(), &D.getAddrSection(), - D.getLineDWOSection(), C.isLittleEndian(), true, Lazy, - SectionKind); -} - -void DWARFUnitVector::addUnitsImpl( - DWARFContext &Context, const DWARFObject &Obj, const DWARFSection &Section, - const DWARFDebugAbbrev *DA, const DWARFSection *RS, - const DWARFSection *LocSection, StringRef SS, const DWARFSection &SOS, - const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, - bool Lazy, DWARFSectionKind SectionKind) { - DWARFDataExtractor Data(Obj, Section, LE, 0); - // Lazy initialization of Parser, now that we have all section info. - if (!Parser) { - Parser = [=, &Context, &Obj, &Section, &SOS, - &LS](uint64_t Offset, DWARFSectionKind SectionKind, - const DWARFSection *CurSection, - const DWARFUnitIndex::Entry *IndexEntry) - -> std::unique_ptr<DWARFUnit> { - const DWARFSection &InfoSection = CurSection ? *CurSection : Section; - DWARFDataExtractor Data(Obj, InfoSection, LE, 0); - if (!Data.isValidOffset(Offset)) - return nullptr; - DWARFUnitHeader Header; - if (!Header.extract(Context, Data, &Offset, SectionKind)) - return nullptr; - if (!IndexEntry && IsDWO) { - const DWARFUnitIndex &Index = getDWARFUnitIndex( - Context, Header.isTypeUnit() ? DW_SECT_EXT_TYPES : DW_SECT_INFO); - IndexEntry = Index.getFromOffset(Header.getOffset()); - } - if (IndexEntry && !Header.applyIndexEntry(IndexEntry)) - return nullptr; - std::unique_ptr<DWARFUnit> U; - if (Header.isTypeUnit()) - U = std::make_unique<DWARFTypeUnit>(Context, InfoSection, Header, DA, - RS, LocSection, SS, SOS, AOS, LS, - LE, IsDWO, *this); - else - U = std::make_unique<DWARFCompileUnit>(Context, InfoSection, Header, - DA, RS, LocSection, SS, SOS, - AOS, LS, LE, IsDWO, *this); - return U; - }; - } - if (Lazy) - return; - // Find a reasonable insertion point within the vector. We skip over - // (a) units from a different section, (b) units from the same section - // but with lower offset-within-section. This keeps units in order - // within a section, although not necessarily within the object file, - // even if we do lazy parsing. - auto I = this->begin(); - uint64_t Offset = 0; - while (Data.isValidOffset(Offset)) { - if (I != this->end() && - (&(*I)->getInfoSection() != &Section || (*I)->getOffset() == Offset)) { - ++I; - continue; - } - auto U = Parser(Offset, SectionKind, &Section, nullptr); - // If parsing failed, we're done with this section. - if (!U) - break; - Offset = U->getNextUnitOffset(); - I = std::next(this->insert(I, std::move(U))); - } -} - -DWARFUnit *DWARFUnitVector::addUnit(std::unique_ptr<DWARFUnit> Unit) { - auto I = std::upper_bound(begin(), end(), Unit, - [](const std::unique_ptr<DWARFUnit> &LHS, - const std::unique_ptr<DWARFUnit> &RHS) { - return LHS->getOffset() < RHS->getOffset(); - }); - return this->insert(I, std::move(Unit))->get(); -} - -DWARFUnit *DWARFUnitVector::getUnitForOffset(uint64_t Offset) const { - auto end = begin() + getNumInfoUnits(); - auto *CU = - std::upper_bound(begin(), end, Offset, - [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) { - return LHS < RHS->getNextUnitOffset(); - }); - if (CU != end && (*CU)->getOffset() <= Offset) - return CU->get(); - return nullptr; -} - -DWARFUnit * -DWARFUnitVector::getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) { - const auto *CUOff = E.getContribution(DW_SECT_INFO); - if (!CUOff) - return nullptr; - - auto Offset = CUOff->Offset; - auto end = begin() + getNumInfoUnits(); - - auto *CU = - std::upper_bound(begin(), end, CUOff->Offset, - [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) { - return LHS < RHS->getNextUnitOffset(); - }); - if (CU != end && (*CU)->getOffset() <= Offset) - return CU->get(); - - if (!Parser) - return nullptr; - - auto U = Parser(Offset, DW_SECT_INFO, nullptr, &E); - if (!U) - U = nullptr; - - auto *NewCU = U.get(); - this->insert(CU, std::move(U)); - ++NumInfoUnits; - return NewCU; -} - -DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, - const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, - const DWARFSection *RS, const DWARFSection *LocSection, - StringRef SS, const DWARFSection &SOS, - const DWARFSection *AOS, const DWARFSection &LS, bool LE, - bool IsDWO, const DWARFUnitVector &UnitVector) - : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA), - RangeSection(RS), LineSection(LS), StringSection(SS), - StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), - IsDWO(IsDWO), UnitVector(UnitVector) { - clear(); -} - -DWARFUnit::~DWARFUnit() = default; - -DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const { - return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian, - getAddressByteSize()); -} - -Optional<object::SectionedAddress> -DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const { - if (IsDWO) { - auto R = Context.info_section_units(); - // Surprising if a DWO file has more than one skeleton unit in it - this - // probably shouldn't be valid, but if a use case is found, here's where to - // support it (probably have to linearly search for the matching skeleton CU - // here) +//===- DWARFUnit.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.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/DWARFDebugRnglists.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstdio> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace dwarf; + +void DWARFUnitVector::addUnitsForSection(DWARFContext &C, + const DWARFSection &Section, + DWARFSectionKind SectionKind) { + const DWARFObject &D = C.getDWARFObj(); + addUnitsImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangesSection(), + &D.getLocSection(), D.getStrSection(), + D.getStrOffsetsSection(), &D.getAddrSection(), + D.getLineSection(), D.isLittleEndian(), false, false, + SectionKind); +} + +void DWARFUnitVector::addUnitsForDWOSection(DWARFContext &C, + const DWARFSection &DWOSection, + DWARFSectionKind SectionKind, + bool Lazy) { + const DWARFObject &D = C.getDWARFObj(); + addUnitsImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangesDWOSection(), + &D.getLocDWOSection(), D.getStrDWOSection(), + D.getStrOffsetsDWOSection(), &D.getAddrSection(), + D.getLineDWOSection(), C.isLittleEndian(), true, Lazy, + SectionKind); +} + +void DWARFUnitVector::addUnitsImpl( + DWARFContext &Context, const DWARFObject &Obj, const DWARFSection &Section, + const DWARFDebugAbbrev *DA, const DWARFSection *RS, + const DWARFSection *LocSection, StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, + bool Lazy, DWARFSectionKind SectionKind) { + DWARFDataExtractor Data(Obj, Section, LE, 0); + // Lazy initialization of Parser, now that we have all section info. + if (!Parser) { + Parser = [=, &Context, &Obj, &Section, &SOS, + &LS](uint64_t Offset, DWARFSectionKind SectionKind, + const DWARFSection *CurSection, + const DWARFUnitIndex::Entry *IndexEntry) + -> std::unique_ptr<DWARFUnit> { + const DWARFSection &InfoSection = CurSection ? *CurSection : Section; + DWARFDataExtractor Data(Obj, InfoSection, LE, 0); + if (!Data.isValidOffset(Offset)) + return nullptr; + DWARFUnitHeader Header; + if (!Header.extract(Context, Data, &Offset, SectionKind)) + return nullptr; + if (!IndexEntry && IsDWO) { + const DWARFUnitIndex &Index = getDWARFUnitIndex( + Context, Header.isTypeUnit() ? DW_SECT_EXT_TYPES : DW_SECT_INFO); + IndexEntry = Index.getFromOffset(Header.getOffset()); + } + if (IndexEntry && !Header.applyIndexEntry(IndexEntry)) + return nullptr; + std::unique_ptr<DWARFUnit> U; + if (Header.isTypeUnit()) + U = std::make_unique<DWARFTypeUnit>(Context, InfoSection, Header, DA, + RS, LocSection, SS, SOS, AOS, LS, + LE, IsDWO, *this); + else + U = std::make_unique<DWARFCompileUnit>(Context, InfoSection, Header, + DA, RS, LocSection, SS, SOS, + AOS, LS, LE, IsDWO, *this); + return U; + }; + } + if (Lazy) + return; + // Find a reasonable insertion point within the vector. We skip over + // (a) units from a different section, (b) units from the same section + // but with lower offset-within-section. This keeps units in order + // within a section, although not necessarily within the object file, + // even if we do lazy parsing. + auto I = this->begin(); + uint64_t Offset = 0; + while (Data.isValidOffset(Offset)) { + if (I != this->end() && + (&(*I)->getInfoSection() != &Section || (*I)->getOffset() == Offset)) { + ++I; + continue; + } + auto U = Parser(Offset, SectionKind, &Section, nullptr); + // If parsing failed, we're done with this section. + if (!U) + break; + Offset = U->getNextUnitOffset(); + I = std::next(this->insert(I, std::move(U))); + } +} + +DWARFUnit *DWARFUnitVector::addUnit(std::unique_ptr<DWARFUnit> Unit) { + auto I = std::upper_bound(begin(), end(), Unit, + [](const std::unique_ptr<DWARFUnit> &LHS, + const std::unique_ptr<DWARFUnit> &RHS) { + return LHS->getOffset() < RHS->getOffset(); + }); + return this->insert(I, std::move(Unit))->get(); +} + +DWARFUnit *DWARFUnitVector::getUnitForOffset(uint64_t Offset) const { + auto end = begin() + getNumInfoUnits(); + auto *CU = + std::upper_bound(begin(), end, Offset, + [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) { + return LHS < RHS->getNextUnitOffset(); + }); + if (CU != end && (*CU)->getOffset() <= Offset) + return CU->get(); + return nullptr; +} + +DWARFUnit * +DWARFUnitVector::getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) { + const auto *CUOff = E.getContribution(DW_SECT_INFO); + if (!CUOff) + return nullptr; + + auto Offset = CUOff->Offset; + auto end = begin() + getNumInfoUnits(); + + auto *CU = + std::upper_bound(begin(), end, CUOff->Offset, + [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) { + return LHS < RHS->getNextUnitOffset(); + }); + if (CU != end && (*CU)->getOffset() <= Offset) + return CU->get(); + + if (!Parser) + return nullptr; + + auto U = Parser(Offset, DW_SECT_INFO, nullptr, &E); + if (!U) + U = nullptr; + + auto *NewCU = U.get(); + this->insert(CU, std::move(U)); + ++NumInfoUnits; + return NewCU; +} + +DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, + const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA, + const DWARFSection *RS, const DWARFSection *LocSection, + StringRef SS, const DWARFSection &SOS, + const DWARFSection *AOS, const DWARFSection &LS, bool LE, + bool IsDWO, const DWARFUnitVector &UnitVector) + : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA), + RangeSection(RS), LineSection(LS), StringSection(SS), + StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), + IsDWO(IsDWO), UnitVector(UnitVector) { + clear(); +} + +DWARFUnit::~DWARFUnit() = default; + +DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const { + return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian, + getAddressByteSize()); +} + +Optional<object::SectionedAddress> +DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const { + if (IsDWO) { + auto R = Context.info_section_units(); + // Surprising if a DWO file has more than one skeleton unit in it - this + // probably shouldn't be valid, but if a use case is found, here's where to + // support it (probably have to linearly search for the matching skeleton CU + // here) if (hasSingleElement(R)) return (*R.begin())->getAddrOffsetSectionItem(Index); - } - if (!AddrOffsetSectionBase) - return None; - uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize(); - if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) - return None; - DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection, - isLittleEndian, getAddressByteSize()); - uint64_t Section; - uint64_t Address = DA.getRelocatedAddress(&Offset, &Section); - return {{Address, Section}}; -} - -Optional<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { - if (!StringOffsetsTableContribution) - return None; - unsigned ItemSize = getDwarfStringOffsetsByteSize(); - uint64_t Offset = getStringOffsetsBase() + Index * ItemSize; - if (StringOffsetSection.Data.size() < Offset + ItemSize) - return None; - DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, - isLittleEndian, 0); - return DA.getRelocatedValue(ItemSize, &Offset); -} - -bool DWARFUnitHeader::extract(DWARFContext &Context, - const DWARFDataExtractor &debug_info, - uint64_t *offset_ptr, - DWARFSectionKind SectionKind) { - Offset = *offset_ptr; - Error Err = Error::success(); - IndexEntry = nullptr; - std::tie(Length, FormParams.Format) = - debug_info.getInitialLength(offset_ptr, &Err); - FormParams.Version = debug_info.getU16(offset_ptr, &Err); - if (FormParams.Version >= 5) { - UnitType = debug_info.getU8(offset_ptr, &Err); - FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); - } else { - AbbrOffset = debug_info.getRelocatedValue( - FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); - FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); - // Fake a unit type based on the section type. This isn't perfect, - // but distinguishing compile and type units is generally enough. - if (SectionKind == DW_SECT_EXT_TYPES) - UnitType = DW_UT_type; - else - UnitType = DW_UT_compile; - } - if (isTypeUnit()) { - TypeHash = debug_info.getU64(offset_ptr, &Err); - TypeOffset = debug_info.getUnsigned( - offset_ptr, FormParams.getDwarfOffsetByteSize(), &Err); - } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton) - DWOId = debug_info.getU64(offset_ptr, &Err); - - if (errorToBool(std::move(Err))) - return false; - - // Header fields all parsed, capture the size of this unit header. - assert(*offset_ptr - Offset <= 255 && "unexpected header size"); - Size = uint8_t(*offset_ptr - Offset); - - // Type offset is unit-relative; should be after the header and before - // the end of the current unit. - bool TypeOffsetOK = - !isTypeUnit() - ? true - : TypeOffset >= Size && - TypeOffset < getLength() + getUnitLengthFieldByteSize(); - bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); - bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); - bool AddrSizeOK = DWARFContext::isAddressSizeSupported(getAddressByteSize()); - - if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK) - return false; - - // Keep track of the highest DWARF version we encounter across all units. - Context.setMaxVersionIfGreater(getVersion()); - return true; -} - -bool DWARFUnitHeader::applyIndexEntry(const DWARFUnitIndex::Entry *Entry) { - assert(Entry); - assert(!IndexEntry); - IndexEntry = Entry; - if (AbbrOffset) - return false; - auto *UnitContrib = IndexEntry->getContribution(); - if (!UnitContrib || - UnitContrib->Length != (getLength() + getUnitLengthFieldByteSize())) - return false; - auto *AbbrEntry = IndexEntry->getContribution(DW_SECT_ABBREV); - if (!AbbrEntry) - return false; - AbbrOffset = AbbrEntry->Offset; - return true; -} - -// Parse the rangelist table header, including the optional array of offsets -// following it (DWARF v5 and later). -template<typename ListTableType> -static Expected<ListTableType> -parseListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, - DwarfFormat Format) { - // We are expected to be called with Offset 0 or pointing just past the table - // header. Correct Offset in the latter case so that it points to the start - // of the header. - if (Offset > 0) { - uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format); - if (Offset < HeaderSize) - return createStringError(errc::invalid_argument, "did not detect a valid" - " list table with base = 0x%" PRIx64 "\n", - Offset); - Offset -= HeaderSize; - } - ListTableType Table; - if (Error E = Table.extractHeaderAndOffsets(DA, &Offset)) - return std::move(E); - return Table; -} - -Error DWARFUnit::extractRangeList(uint64_t RangeListOffset, - DWARFDebugRangeList &RangeList) const { - // Require that compile unit is extracted. - assert(!DieArray.empty()); - DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, - isLittleEndian, getAddressByteSize()); - uint64_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; - return RangeList.extract(RangesData, &ActualRangeListOffset); -} - -void DWARFUnit::clear() { - Abbrevs = nullptr; - BaseAddr.reset(); - RangeSectionBase = 0; - LocSectionBase = 0; - AddrOffsetSectionBase = None; - clearDIEs(false); - DWO.reset(); -} - -const char *DWARFUnit::getCompilationDir() { - return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); -} - -void DWARFUnit::extractDIEsToVector( - bool AppendCUDie, bool AppendNonCUDies, - std::vector<DWARFDebugInfoEntry> &Dies) const { - if (!AppendCUDie && !AppendNonCUDies) - return; - - // Set the offset to that of the first DIE and calculate the start of the - // next compilation unit header. - uint64_t DIEOffset = getOffset() + getHeaderSize(); - uint64_t NextCUOffset = getNextUnitOffset(); - DWARFDebugInfoEntry DIE; - DWARFDataExtractor DebugInfoData = getDebugInfoExtractor(); - uint32_t Depth = 0; - bool IsCUDie = true; - - while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset, - Depth)) { - if (IsCUDie) { - if (AppendCUDie) - Dies.push_back(DIE); - if (!AppendNonCUDies) - break; - // The average bytes per DIE entry has been seen to be - // around 14-20 so let's pre-reserve the needed memory for - // our DIE entries accordingly. - Dies.reserve(Dies.size() + getDebugInfoSize() / 14); - IsCUDie = false; - } else { - Dies.push_back(DIE); - } - - if (const DWARFAbbreviationDeclaration *AbbrDecl = - DIE.getAbbreviationDeclarationPtr()) { - // Normal DIE - if (AbbrDecl->hasChildren()) - ++Depth; - } else { - // NULL DIE. - if (Depth > 0) - --Depth; - if (Depth == 0) - break; // We are done with this compile unit! - } - } - - // Give a little bit of info if we encounter corrupt DWARF (our offset - // should always terminate at or before the start of the next compilation - // unit header). - if (DIEOffset > NextCUOffset) - Context.getWarningHandler()( - createStringError(errc::invalid_argument, - "DWARF compile unit extends beyond its " - "bounds cu 0x%8.8" PRIx64 " " - "at 0x%8.8" PRIx64 "\n", - getOffset(), DIEOffset)); -} - -void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { - if (Error e = tryExtractDIEsIfNeeded(CUDieOnly)) - Context.getRecoverableErrorHandler()(std::move(e)); -} - -Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { - if ((CUDieOnly && !DieArray.empty()) || - DieArray.size() > 1) - return Error::success(); // Already parsed. - - bool HasCUDie = !DieArray.empty(); - extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); - - if (DieArray.empty()) - return Error::success(); - - // If CU DIE was just parsed, copy several attribute values from it. - if (HasCUDie) - return Error::success(); - - DWARFDie UnitDie(this, &DieArray[0]); - if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id))) - Header.setDWOId(*DWOId); - if (!IsDWO) { - assert(AddrOffsetSectionBase == None); - assert(RangeSectionBase == 0); - assert(LocSectionBase == 0); - AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base)); - if (!AddrOffsetSectionBase) - AddrOffsetSectionBase = - toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base)); - RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); - LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0); - } - - // In general, in DWARF v5 and beyond we derive the start of the unit's - // contribution to the string offsets table from the unit DIE's - // DW_AT_str_offsets_base attribute. Split DWARF units do not use this - // attribute, so we assume that there is a contribution to the string - // offsets table starting at offset 0 of the debug_str_offsets.dwo section. - // In both cases we need to determine the format of the contribution, - // which may differ from the unit's format. - DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, - isLittleEndian, 0); - if (IsDWO || getVersion() >= 5) { - auto StringOffsetOrError = - IsDWO ? determineStringOffsetsTableContributionDWO(DA) - : determineStringOffsetsTableContribution(DA); - if (!StringOffsetOrError) - return createStringError(errc::invalid_argument, - "invalid reference to or invalid content in " - ".debug_str_offsets[.dwo]: " + - toString(StringOffsetOrError.takeError())); - - StringOffsetsTableContribution = *StringOffsetOrError; - } - - // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to - // describe address ranges. - if (getVersion() >= 5) { - // In case of DWP, the base offset from the index has to be added. - if (IsDWO) { + } + if (!AddrOffsetSectionBase) + return None; + uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize(); + if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) + return None; + DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection, + isLittleEndian, getAddressByteSize()); + uint64_t Section; + uint64_t Address = DA.getRelocatedAddress(&Offset, &Section); + return {{Address, Section}}; +} + +Optional<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const { + if (!StringOffsetsTableContribution) + return None; + unsigned ItemSize = getDwarfStringOffsetsByteSize(); + uint64_t Offset = getStringOffsetsBase() + Index * ItemSize; + if (StringOffsetSection.Data.size() < Offset + ItemSize) + return None; + DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, + isLittleEndian, 0); + return DA.getRelocatedValue(ItemSize, &Offset); +} + +bool DWARFUnitHeader::extract(DWARFContext &Context, + const DWARFDataExtractor &debug_info, + uint64_t *offset_ptr, + DWARFSectionKind SectionKind) { + Offset = *offset_ptr; + Error Err = Error::success(); + IndexEntry = nullptr; + std::tie(Length, FormParams.Format) = + debug_info.getInitialLength(offset_ptr, &Err); + FormParams.Version = debug_info.getU16(offset_ptr, &Err); + if (FormParams.Version >= 5) { + UnitType = debug_info.getU8(offset_ptr, &Err); + FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + } else { + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); + // Fake a unit type based on the section type. This isn't perfect, + // but distinguishing compile and type units is generally enough. + if (SectionKind == DW_SECT_EXT_TYPES) + UnitType = DW_UT_type; + else + UnitType = DW_UT_compile; + } + if (isTypeUnit()) { + TypeHash = debug_info.getU64(offset_ptr, &Err); + TypeOffset = debug_info.getUnsigned( + offset_ptr, FormParams.getDwarfOffsetByteSize(), &Err); + } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton) + DWOId = debug_info.getU64(offset_ptr, &Err); + + if (errorToBool(std::move(Err))) + return false; + + // Header fields all parsed, capture the size of this unit header. + assert(*offset_ptr - Offset <= 255 && "unexpected header size"); + Size = uint8_t(*offset_ptr - Offset); + + // Type offset is unit-relative; should be after the header and before + // the end of the current unit. + bool TypeOffsetOK = + !isTypeUnit() + ? true + : TypeOffset >= Size && + TypeOffset < getLength() + getUnitLengthFieldByteSize(); + bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); + bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); + bool AddrSizeOK = DWARFContext::isAddressSizeSupported(getAddressByteSize()); + + if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK) + return false; + + // Keep track of the highest DWARF version we encounter across all units. + Context.setMaxVersionIfGreater(getVersion()); + return true; +} + +bool DWARFUnitHeader::applyIndexEntry(const DWARFUnitIndex::Entry *Entry) { + assert(Entry); + assert(!IndexEntry); + IndexEntry = Entry; + if (AbbrOffset) + return false; + auto *UnitContrib = IndexEntry->getContribution(); + if (!UnitContrib || + UnitContrib->Length != (getLength() + getUnitLengthFieldByteSize())) + return false; + auto *AbbrEntry = IndexEntry->getContribution(DW_SECT_ABBREV); + if (!AbbrEntry) + return false; + AbbrOffset = AbbrEntry->Offset; + return true; +} + +// Parse the rangelist table header, including the optional array of offsets +// following it (DWARF v5 and later). +template<typename ListTableType> +static Expected<ListTableType> +parseListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, + DwarfFormat Format) { + // We are expected to be called with Offset 0 or pointing just past the table + // header. Correct Offset in the latter case so that it points to the start + // of the header. + if (Offset > 0) { + uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format); + if (Offset < HeaderSize) + return createStringError(errc::invalid_argument, "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", + Offset); + Offset -= HeaderSize; + } + ListTableType Table; + if (Error E = Table.extractHeaderAndOffsets(DA, &Offset)) + return std::move(E); + return Table; +} + +Error DWARFUnit::extractRangeList(uint64_t RangeListOffset, + DWARFDebugRangeList &RangeList) const { + // Require that compile unit is extracted. + assert(!DieArray.empty()); + DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, + isLittleEndian, getAddressByteSize()); + uint64_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; + return RangeList.extract(RangesData, &ActualRangeListOffset); +} + +void DWARFUnit::clear() { + Abbrevs = nullptr; + BaseAddr.reset(); + RangeSectionBase = 0; + LocSectionBase = 0; + AddrOffsetSectionBase = None; + clearDIEs(false); + DWO.reset(); +} + +const char *DWARFUnit::getCompilationDir() { + return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr); +} + +void DWARFUnit::extractDIEsToVector( + bool AppendCUDie, bool AppendNonCUDies, + std::vector<DWARFDebugInfoEntry> &Dies) const { + if (!AppendCUDie && !AppendNonCUDies) + return; + + // Set the offset to that of the first DIE and calculate the start of the + // next compilation unit header. + uint64_t DIEOffset = getOffset() + getHeaderSize(); + uint64_t NextCUOffset = getNextUnitOffset(); + DWARFDebugInfoEntry DIE; + DWARFDataExtractor DebugInfoData = getDebugInfoExtractor(); + uint32_t Depth = 0; + bool IsCUDie = true; + + while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset, + Depth)) { + if (IsCUDie) { + if (AppendCUDie) + Dies.push_back(DIE); + if (!AppendNonCUDies) + break; + // The average bytes per DIE entry has been seen to be + // around 14-20 so let's pre-reserve the needed memory for + // our DIE entries accordingly. + Dies.reserve(Dies.size() + getDebugInfoSize() / 14); + IsCUDie = false; + } else { + Dies.push_back(DIE); + } + + if (const DWARFAbbreviationDeclaration *AbbrDecl = + DIE.getAbbreviationDeclarationPtr()) { + // Normal DIE + if (AbbrDecl->hasChildren()) + ++Depth; + } else { + // NULL DIE. + if (Depth > 0) + --Depth; + if (Depth == 0) + break; // We are done with this compile unit! + } + } + + // Give a little bit of info if we encounter corrupt DWARF (our offset + // should always terminate at or before the start of the next compilation + // unit header). + if (DIEOffset > NextCUOffset) + Context.getWarningHandler()( + createStringError(errc::invalid_argument, + "DWARF compile unit extends beyond its " + "bounds cu 0x%8.8" PRIx64 " " + "at 0x%8.8" PRIx64 "\n", + getOffset(), DIEOffset)); +} + +void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) { + if (Error e = tryExtractDIEsIfNeeded(CUDieOnly)) + Context.getRecoverableErrorHandler()(std::move(e)); +} + +Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { + if ((CUDieOnly && !DieArray.empty()) || + DieArray.size() > 1) + return Error::success(); // Already parsed. + + bool HasCUDie = !DieArray.empty(); + extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray); + + if (DieArray.empty()) + return Error::success(); + + // If CU DIE was just parsed, copy several attribute values from it. + if (HasCUDie) + return Error::success(); + + DWARFDie UnitDie(this, &DieArray[0]); + if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id))) + Header.setDWOId(*DWOId); + if (!IsDWO) { + assert(AddrOffsetSectionBase == None); + assert(RangeSectionBase == 0); + assert(LocSectionBase == 0); + AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base)); + if (!AddrOffsetSectionBase) + AddrOffsetSectionBase = + toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base)); + RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0); + } + + // In general, in DWARF v5 and beyond we derive the start of the unit's + // contribution to the string offsets table from the unit DIE's + // DW_AT_str_offsets_base attribute. Split DWARF units do not use this + // attribute, so we assume that there is a contribution to the string + // offsets table starting at offset 0 of the debug_str_offsets.dwo section. + // In both cases we need to determine the format of the contribution, + // which may differ from the unit's format. + DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection, + isLittleEndian, 0); + if (IsDWO || getVersion() >= 5) { + auto StringOffsetOrError = + IsDWO ? determineStringOffsetsTableContributionDWO(DA) + : determineStringOffsetsTableContribution(DA); + if (!StringOffsetOrError) + return createStringError(errc::invalid_argument, + "invalid reference to or invalid content in " + ".debug_str_offsets[.dwo]: " + + toString(StringOffsetOrError.takeError())); + + StringOffsetsTableContribution = *StringOffsetOrError; + } + + // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to + // describe address ranges. + if (getVersion() >= 5) { + // In case of DWP, the base offset from the index has to be added. + if (IsDWO) { uint64_t ContributionBaseOffset = 0; - if (auto *IndexEntry = Header.getIndexEntry()) - if (auto *Contrib = IndexEntry->getContribution(DW_SECT_RNGLISTS)) - ContributionBaseOffset = Contrib->Offset; - setRangesSection( - &Context.getDWARFObj().getRnglistsDWOSection(), - ContributionBaseOffset + - DWARFListTableHeader::getHeaderSize(Header.getFormat())); - } else - setRangesSection(&Context.getDWARFObj().getRnglistsSection(), + if (auto *IndexEntry = Header.getIndexEntry()) + if (auto *Contrib = IndexEntry->getContribution(DW_SECT_RNGLISTS)) + ContributionBaseOffset = Contrib->Offset; + setRangesSection( + &Context.getDWARFObj().getRnglistsDWOSection(), + ContributionBaseOffset + + DWARFListTableHeader::getHeaderSize(Header.getFormat())); + } else + setRangesSection(&Context.getDWARFObj().getRnglistsSection(), toSectionOffset(UnitDie.find(DW_AT_rnglists_base), DWARFListTableHeader::getHeaderSize( Header.getFormat()))); } - + if (IsDWO) { // If we are reading a package file, we need to adjust the location list // data based on the index entries. @@ -492,7 +492,7 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { if (const auto *C = IndexEntry->getContribution( Header.getVersion() >= 5 ? DW_SECT_LOCLISTS : DW_SECT_EXT_LOC)) Data = Data.substr(C->Offset, C->Length); - + DWARFDataExtractor DWARFData(Data, isLittleEndian, getAddressByteSize()); LocTable = std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion()); @@ -507,73 +507,73 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { LocTable = std::make_unique<DWARFDebugLoc>(DWARFDataExtractor( Context.getDWARFObj(), Context.getDWARFObj().getLocSection(), isLittleEndian, getAddressByteSize())); - } - - // 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. - return Error::success(); -} - -bool DWARFUnit::parseDWO() { - if (IsDWO) - return false; - if (DWO.get()) - return false; - DWARFDie UnitDie = getUnitDIE(); - if (!UnitDie) - return false; - auto DWOFileName = getVersion() >= 5 - ? dwarf::toString(UnitDie.find(DW_AT_dwo_name)) - : dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); - if (!DWOFileName) - return false; - auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); - SmallString<16> AbsolutePath; - if (sys::path::is_relative(*DWOFileName) && CompilationDir && - *CompilationDir) { - sys::path::append(AbsolutePath, *CompilationDir); - } - sys::path::append(AbsolutePath, *DWOFileName); - auto DWOId = getDWOId(); - if (!DWOId) - return false; - auto DWOContext = Context.getDWOContext(AbsolutePath); - if (!DWOContext) - return false; - - DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId); - if (!DWOCU) - return false; - DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU); - // Share .debug_addr and .debug_ranges section with compile unit in .dwo - if (AddrOffsetSectionBase) - DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase); - if (getVersion() >= 5) { + } + + // 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. + return Error::success(); +} + +bool DWARFUnit::parseDWO() { + if (IsDWO) + return false; + if (DWO.get()) + return false; + DWARFDie UnitDie = getUnitDIE(); + if (!UnitDie) + return false; + auto DWOFileName = getVersion() >= 5 + ? dwarf::toString(UnitDie.find(DW_AT_dwo_name)) + : dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); + if (!DWOFileName) + return false; + auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); + SmallString<16> AbsolutePath; + if (sys::path::is_relative(*DWOFileName) && CompilationDir && + *CompilationDir) { + sys::path::append(AbsolutePath, *CompilationDir); + } + sys::path::append(AbsolutePath, *DWOFileName); + auto DWOId = getDWOId(); + if (!DWOId) + return false; + auto DWOContext = Context.getDWOContext(AbsolutePath); + if (!DWOContext) + return false; + + DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId); + if (!DWOCU) + return false; + DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU); + // Share .debug_addr and .debug_ranges section with compile unit in .dwo + if (AddrOffsetSectionBase) + DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase); + if (getVersion() >= 5) { DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), DWARFListTableHeader::getHeaderSize(getFormat())); - } else { - auto DWORangesBase = UnitDie.getRangesBaseAttribute(); - DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); - } - - return true; -} - -void DWARFUnit::clearDIEs(bool KeepCUDie) { - if (DieArray.size() > (unsigned)KeepCUDie) { - DieArray.resize((unsigned)KeepCUDie); - DieArray.shrink_to_fit(); - } -} - -Expected<DWARFAddressRangesVector> -DWARFUnit::findRnglistFromOffset(uint64_t Offset) { - if (getVersion() <= 4) { - DWARFDebugRangeList RangeList; - if (Error E = extractRangeList(Offset, RangeList)) - return std::move(E); - return RangeList.getAbsoluteRanges(getBaseAddress()); - } + } else { + auto DWORangesBase = UnitDie.getRangesBaseAttribute(); + DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0); + } + + return true; +} + +void DWARFUnit::clearDIEs(bool KeepCUDie) { + if (DieArray.size() > (unsigned)KeepCUDie) { + DieArray.resize((unsigned)KeepCUDie); + DieArray.shrink_to_fit(); + } +} + +Expected<DWARFAddressRangesVector> +DWARFUnit::findRnglistFromOffset(uint64_t Offset) { + if (getVersion() <= 4) { + DWARFDebugRangeList RangeList; + if (Error E = extractRangeList(Offset, RangeList)) + return std::move(E); + return RangeList.getAbsoluteRanges(getBaseAddress()); + } DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection, isLittleEndian, Header.getAddressByteSize()); DWARFDebugRnglistTable RnglistTable; @@ -581,348 +581,348 @@ DWARFUnit::findRnglistFromOffset(uint64_t Offset) { if (RangeListOrError) return RangeListOrError.get().getAbsoluteRanges(getBaseAddress(), *this); return RangeListOrError.takeError(); -} - -Expected<DWARFAddressRangesVector> -DWARFUnit::findRnglistFromIndex(uint32_t Index) { - if (auto Offset = getRnglistOffset(Index)) - return findRnglistFromOffset(*Offset); - - return createStringError(errc::invalid_argument, +} + +Expected<DWARFAddressRangesVector> +DWARFUnit::findRnglistFromIndex(uint32_t Index) { + if (auto Offset = getRnglistOffset(Index)) + return findRnglistFromOffset(*Offset); + + return createStringError(errc::invalid_argument, "invalid range list table index %d (possibly " "missing the entire range list table)", Index); -} - -Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() { - DWARFDie UnitDie = getUnitDIE(); - if (!UnitDie) - return createStringError(errc::invalid_argument, "No unit DIE"); - - // First, check if unit DIE describes address ranges for the whole unit. - auto CUDIERangesOrError = UnitDie.getAddressRanges(); - if (!CUDIERangesOrError) - return createStringError(errc::invalid_argument, - "decoding address ranges: %s", - toString(CUDIERangesOrError.takeError()).c_str()); - return *CUDIERangesOrError; -} - -Expected<DWARFLocationExpressionsVector> -DWARFUnit::findLoclistFromOffset(uint64_t Offset) { - DWARFLocationExpressionsVector Result; - - Error InterpretationError = Error::success(); - - Error ParseError = getLocationTable().visitAbsoluteLocationList( - Offset, getBaseAddress(), - [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); }, - [&](Expected<DWARFLocationExpression> L) { - if (L) - Result.push_back(std::move(*L)); - else - InterpretationError = - joinErrors(L.takeError(), std::move(InterpretationError)); - return !InterpretationError; - }); - - if (ParseError || InterpretationError) - return joinErrors(std::move(ParseError), std::move(InterpretationError)); - - return Result; -} - -void DWARFUnit::updateAddressDieMap(DWARFDie Die) { - if (Die.isSubroutineDIE()) { - auto DIERangesOrError = Die.getAddressRanges(); - if (DIERangesOrError) { - for (const auto &R : DIERangesOrError.get()) { - // Ignore 0-sized ranges. - if (R.LowPC == R.HighPC) - continue; - auto B = AddrDieMap.upper_bound(R.LowPC); - if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) { - // The range is a sub-range of existing ranges, we need to split the - // existing range. - if (R.HighPC < B->second.first) - AddrDieMap[R.HighPC] = B->second; - if (R.LowPC > B->first) - AddrDieMap[B->first].first = R.LowPC; - } - AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die); - } - } else - llvm::consumeError(DIERangesOrError.takeError()); - } - // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to - // simplify the logic to update AddrDieMap. The child's range will always - // be equal or smaller than the parent's range. With this assumption, when - // adding one range into the map, it will at most split a range into 3 - // sub-ranges. - for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling()) - updateAddressDieMap(Child); -} - -DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { - extractDIEsIfNeeded(false); - if (AddrDieMap.empty()) - updateAddressDieMap(getUnitDIE()); - auto R = AddrDieMap.upper_bound(Address); - if (R == AddrDieMap.begin()) - return DWARFDie(); - // upper_bound's previous item contains Address. - --R; - if (Address >= R->second.first) - return DWARFDie(); - return R->second.second; -} - -void -DWARFUnit::getInlinedChainForAddress(uint64_t Address, - SmallVectorImpl<DWARFDie> &InlinedChain) { - assert(InlinedChain.empty()); - // Try to look for subprogram DIEs in the DWO file. - parseDWO(); - // First, find the subroutine that contains the given address (the leaf - // of inlined chain). - DWARFDie SubroutineDIE = - (DWO ? *DWO : *this).getSubroutineForAddress(Address); - - if (!SubroutineDIE) - return; - - while (!SubroutineDIE.isSubprogramDIE()) { - if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine) - InlinedChain.push_back(SubroutineDIE); - SubroutineDIE = SubroutineDIE.getParent(); - } - InlinedChain.push_back(SubroutineDIE); -} - -const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context, - DWARFSectionKind Kind) { - if (Kind == DW_SECT_INFO) - return Context.getCUIndex(); - assert(Kind == DW_SECT_EXT_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(); -} - -DWARFDie DWARFUnit::getPreviousSibling(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(); - - // Find the previous DIE whose depth is the same as the Die's depth. - for (size_t I = getDIEIndex(Die); I > 0;) { - --I; - if (DieArray[I].getDepth() == Depth - 1) - return DWARFDie(); - if (DieArray[I].getDepth() == Depth) - return DWARFDie(this, &DieArray[I]); - } - return DWARFDie(); -} - -DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) { - if (!Die->hasChildren()) - return DWARFDie(); - - // We do not want access out of bounds when parsing corrupted debug data. - size_t I = getDIEIndex(Die) + 1; - if (I >= DieArray.size()) - return DWARFDie(); - return DWARFDie(this, &DieArray[I]); -} - -DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) { - if (!Die->hasChildren()) - return DWARFDie(); - - uint32_t Depth = Die->getDepth(); - for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; - ++I) { - if (DieArray[I].getDepth() == Depth + 1 && - DieArray[I].getTag() == dwarf::DW_TAG_null) - return DWARFDie(this, &DieArray[I]); - assert(DieArray[I].getDepth() > Depth && "Not processing children?"); - } - return DWARFDie(); -} - -const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const { - if (!Abbrevs) - Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset()); - return Abbrevs; -} - -llvm::Optional<object::SectionedAddress> DWARFUnit::getBaseAddress() { - if (BaseAddr) - return BaseAddr; - - DWARFDie UnitDie = getUnitDIE(); - Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}); - BaseAddr = toSectionedAddress(PC); - return BaseAddr; -} - -Expected<StrOffsetsContributionDescriptor> -StrOffsetsContributionDescriptor::validateContributionSize( - DWARFDataExtractor &DA) { - uint8_t EntrySize = getDwarfOffsetByteSize(); - // In order to ensure that we don't read a partial record at the end of - // the section we validate for a multiple of the entry size. - uint64_t ValidationSize = alignTo(Size, EntrySize); - // Guard against overflow. - if (ValidationSize >= Size) - if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize)) - return *this; - return createStringError(errc::invalid_argument, "length exceeds section size"); -} - -// Look for a DWARF64-formatted contribution to the string offsets table -// starting at a given offset and record it in a descriptor. -static Expected<StrOffsetsContributionDescriptor> -parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) { - if (!DA.isValidOffsetForDataOfSize(Offset, 16)) - return createStringError(errc::invalid_argument, "section offset exceeds section size"); - - if (DA.getU32(&Offset) != dwarf::DW_LENGTH_DWARF64) - return createStringError(errc::invalid_argument, "32 bit contribution referenced from a 64 bit unit"); - - uint64_t Size = DA.getU64(&Offset); - uint8_t Version = DA.getU16(&Offset); - (void)DA.getU16(&Offset); // padding - // The encoded length includes the 2-byte version field and the 2-byte - // padding, so we need to subtract them out when we populate the descriptor. - return StrOffsetsContributionDescriptor(Offset, Size - 4, Version, DWARF64); -} - -// Look for a DWARF32-formatted contribution to the string offsets table -// starting at a given offset and record it in a descriptor. -static Expected<StrOffsetsContributionDescriptor> -parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) { - if (!DA.isValidOffsetForDataOfSize(Offset, 8)) - return createStringError(errc::invalid_argument, "section offset exceeds section size"); - - uint32_t ContributionSize = DA.getU32(&Offset); - if (ContributionSize >= dwarf::DW_LENGTH_lo_reserved) - return createStringError(errc::invalid_argument, "invalid length"); - - uint8_t Version = DA.getU16(&Offset); - (void)DA.getU16(&Offset); // padding - // The encoded length includes the 2-byte version field and the 2-byte - // padding, so we need to subtract them out when we populate the descriptor. - return StrOffsetsContributionDescriptor(Offset, ContributionSize - 4, Version, - DWARF32); -} - -static Expected<StrOffsetsContributionDescriptor> -parseDWARFStringOffsetsTableHeader(DWARFDataExtractor &DA, - llvm::dwarf::DwarfFormat Format, - uint64_t Offset) { - StrOffsetsContributionDescriptor Desc; - switch (Format) { - case dwarf::DwarfFormat::DWARF64: { - if (Offset < 16) - return createStringError(errc::invalid_argument, "insufficient space for 64 bit header prefix"); - auto DescOrError = parseDWARF64StringOffsetsTableHeader(DA, Offset - 16); - if (!DescOrError) - return DescOrError.takeError(); - Desc = *DescOrError; - break; - } - case dwarf::DwarfFormat::DWARF32: { - if (Offset < 8) - return createStringError(errc::invalid_argument, "insufficient space for 32 bit header prefix"); - auto DescOrError = parseDWARF32StringOffsetsTableHeader(DA, Offset - 8); - if (!DescOrError) - return DescOrError.takeError(); - Desc = *DescOrError; - break; - } - } - return Desc.validateContributionSize(DA); -} - -Expected<Optional<StrOffsetsContributionDescriptor>> -DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA) { - assert(!IsDWO); - auto OptOffset = toSectionOffset(getUnitDIE().find(DW_AT_str_offsets_base)); - if (!OptOffset) - return None; - auto DescOrError = - parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), *OptOffset); - if (!DescOrError) - return DescOrError.takeError(); - return *DescOrError; -} - -Expected<Optional<StrOffsetsContributionDescriptor>> -DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor & DA) { - assert(IsDWO); - uint64_t Offset = 0; - auto IndexEntry = Header.getIndexEntry(); - const auto *C = - IndexEntry ? IndexEntry->getContribution(DW_SECT_STR_OFFSETS) : nullptr; - if (C) - Offset = C->Offset; - if (getVersion() >= 5) { - if (DA.getData().data() == nullptr) - return None; - Offset += Header.getFormat() == dwarf::DwarfFormat::DWARF32 ? 8 : 16; - // Look for a valid contribution at the given offset. - auto DescOrError = parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), Offset); - if (!DescOrError) - return DescOrError.takeError(); - return *DescOrError; - } - // Prior to DWARF v5, we derive the contribution size from the - // index table (in a package file). In a .dwo file it is simply - // the length of the string offsets section. +} + +Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() { + DWARFDie UnitDie = getUnitDIE(); + if (!UnitDie) + return createStringError(errc::invalid_argument, "No unit DIE"); + + // First, check if unit DIE describes address ranges for the whole unit. + auto CUDIERangesOrError = UnitDie.getAddressRanges(); + if (!CUDIERangesOrError) + return createStringError(errc::invalid_argument, + "decoding address ranges: %s", + toString(CUDIERangesOrError.takeError()).c_str()); + return *CUDIERangesOrError; +} + +Expected<DWARFLocationExpressionsVector> +DWARFUnit::findLoclistFromOffset(uint64_t Offset) { + DWARFLocationExpressionsVector Result; + + Error InterpretationError = Error::success(); + + Error ParseError = getLocationTable().visitAbsoluteLocationList( + Offset, getBaseAddress(), + [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); }, + [&](Expected<DWARFLocationExpression> L) { + if (L) + Result.push_back(std::move(*L)); + else + InterpretationError = + joinErrors(L.takeError(), std::move(InterpretationError)); + return !InterpretationError; + }); + + if (ParseError || InterpretationError) + return joinErrors(std::move(ParseError), std::move(InterpretationError)); + + return Result; +} + +void DWARFUnit::updateAddressDieMap(DWARFDie Die) { + if (Die.isSubroutineDIE()) { + auto DIERangesOrError = Die.getAddressRanges(); + if (DIERangesOrError) { + for (const auto &R : DIERangesOrError.get()) { + // Ignore 0-sized ranges. + if (R.LowPC == R.HighPC) + continue; + auto B = AddrDieMap.upper_bound(R.LowPC); + if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) { + // The range is a sub-range of existing ranges, we need to split the + // existing range. + if (R.HighPC < B->second.first) + AddrDieMap[R.HighPC] = B->second; + if (R.LowPC > B->first) + AddrDieMap[B->first].first = R.LowPC; + } + AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die); + } + } else + llvm::consumeError(DIERangesOrError.takeError()); + } + // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to + // simplify the logic to update AddrDieMap. The child's range will always + // be equal or smaller than the parent's range. With this assumption, when + // adding one range into the map, it will at most split a range into 3 + // sub-ranges. + for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling()) + updateAddressDieMap(Child); +} + +DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + if (AddrDieMap.empty()) + updateAddressDieMap(getUnitDIE()); + auto R = AddrDieMap.upper_bound(Address); + if (R == AddrDieMap.begin()) + return DWARFDie(); + // upper_bound's previous item contains Address. + --R; + if (Address >= R->second.first) + return DWARFDie(); + return R->second.second; +} + +void +DWARFUnit::getInlinedChainForAddress(uint64_t Address, + SmallVectorImpl<DWARFDie> &InlinedChain) { + assert(InlinedChain.empty()); + // Try to look for subprogram DIEs in the DWO file. + parseDWO(); + // First, find the subroutine that contains the given address (the leaf + // of inlined chain). + DWARFDie SubroutineDIE = + (DWO ? *DWO : *this).getSubroutineForAddress(Address); + + if (!SubroutineDIE) + return; + + while (!SubroutineDIE.isSubprogramDIE()) { + if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine) + InlinedChain.push_back(SubroutineDIE); + SubroutineDIE = SubroutineDIE.getParent(); + } + InlinedChain.push_back(SubroutineDIE); +} + +const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context, + DWARFSectionKind Kind) { + if (Kind == DW_SECT_INFO) + return Context.getCUIndex(); + assert(Kind == DW_SECT_EXT_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(); +} + +DWARFDie DWARFUnit::getPreviousSibling(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(); + + // Find the previous DIE whose depth is the same as the Die's depth. + for (size_t I = getDIEIndex(Die); I > 0;) { + --I; + if (DieArray[I].getDepth() == Depth - 1) + return DWARFDie(); + if (DieArray[I].getDepth() == Depth) + return DWARFDie(this, &DieArray[I]); + } + return DWARFDie(); +} + +DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) { + if (!Die->hasChildren()) + return DWARFDie(); + + // We do not want access out of bounds when parsing corrupted debug data. + size_t I = getDIEIndex(Die) + 1; + if (I >= DieArray.size()) + return DWARFDie(); + return DWARFDie(this, &DieArray[I]); +} + +DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) { + if (!Die->hasChildren()) + return DWARFDie(); + + uint32_t Depth = Die->getDepth(); + for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; + ++I) { + if (DieArray[I].getDepth() == Depth + 1 && + DieArray[I].getTag() == dwarf::DW_TAG_null) + return DWARFDie(this, &DieArray[I]); + assert(DieArray[I].getDepth() > Depth && "Not processing children?"); + } + return DWARFDie(); +} + +const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const { + if (!Abbrevs) + Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset()); + return Abbrevs; +} + +llvm::Optional<object::SectionedAddress> DWARFUnit::getBaseAddress() { + if (BaseAddr) + return BaseAddr; + + DWARFDie UnitDie = getUnitDIE(); + Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}); + BaseAddr = toSectionedAddress(PC); + return BaseAddr; +} + +Expected<StrOffsetsContributionDescriptor> +StrOffsetsContributionDescriptor::validateContributionSize( + DWARFDataExtractor &DA) { + uint8_t EntrySize = getDwarfOffsetByteSize(); + // In order to ensure that we don't read a partial record at the end of + // the section we validate for a multiple of the entry size. + uint64_t ValidationSize = alignTo(Size, EntrySize); + // Guard against overflow. + if (ValidationSize >= Size) + if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize)) + return *this; + return createStringError(errc::invalid_argument, "length exceeds section size"); +} + +// Look for a DWARF64-formatted contribution to the string offsets table +// starting at a given offset and record it in a descriptor. +static Expected<StrOffsetsContributionDescriptor> +parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) { + if (!DA.isValidOffsetForDataOfSize(Offset, 16)) + return createStringError(errc::invalid_argument, "section offset exceeds section size"); + + if (DA.getU32(&Offset) != dwarf::DW_LENGTH_DWARF64) + return createStringError(errc::invalid_argument, "32 bit contribution referenced from a 64 bit unit"); + + uint64_t Size = DA.getU64(&Offset); + uint8_t Version = DA.getU16(&Offset); + (void)DA.getU16(&Offset); // padding + // The encoded length includes the 2-byte version field and the 2-byte + // padding, so we need to subtract them out when we populate the descriptor. + return StrOffsetsContributionDescriptor(Offset, Size - 4, Version, DWARF64); +} + +// Look for a DWARF32-formatted contribution to the string offsets table +// starting at a given offset and record it in a descriptor. +static Expected<StrOffsetsContributionDescriptor> +parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) { + if (!DA.isValidOffsetForDataOfSize(Offset, 8)) + return createStringError(errc::invalid_argument, "section offset exceeds section size"); + + uint32_t ContributionSize = DA.getU32(&Offset); + if (ContributionSize >= dwarf::DW_LENGTH_lo_reserved) + return createStringError(errc::invalid_argument, "invalid length"); + + uint8_t Version = DA.getU16(&Offset); + (void)DA.getU16(&Offset); // padding + // The encoded length includes the 2-byte version field and the 2-byte + // padding, so we need to subtract them out when we populate the descriptor. + return StrOffsetsContributionDescriptor(Offset, ContributionSize - 4, Version, + DWARF32); +} + +static Expected<StrOffsetsContributionDescriptor> +parseDWARFStringOffsetsTableHeader(DWARFDataExtractor &DA, + llvm::dwarf::DwarfFormat Format, + uint64_t Offset) { + StrOffsetsContributionDescriptor Desc; + switch (Format) { + case dwarf::DwarfFormat::DWARF64: { + if (Offset < 16) + return createStringError(errc::invalid_argument, "insufficient space for 64 bit header prefix"); + auto DescOrError = parseDWARF64StringOffsetsTableHeader(DA, Offset - 16); + if (!DescOrError) + return DescOrError.takeError(); + Desc = *DescOrError; + break; + } + case dwarf::DwarfFormat::DWARF32: { + if (Offset < 8) + return createStringError(errc::invalid_argument, "insufficient space for 32 bit header prefix"); + auto DescOrError = parseDWARF32StringOffsetsTableHeader(DA, Offset - 8); + if (!DescOrError) + return DescOrError.takeError(); + Desc = *DescOrError; + break; + } + } + return Desc.validateContributionSize(DA); +} + +Expected<Optional<StrOffsetsContributionDescriptor>> +DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA) { + assert(!IsDWO); + auto OptOffset = toSectionOffset(getUnitDIE().find(DW_AT_str_offsets_base)); + if (!OptOffset) + return None; + auto DescOrError = + parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), *OptOffset); + if (!DescOrError) + return DescOrError.takeError(); + return *DescOrError; +} + +Expected<Optional<StrOffsetsContributionDescriptor>> +DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor & DA) { + assert(IsDWO); + uint64_t Offset = 0; + auto IndexEntry = Header.getIndexEntry(); + const auto *C = + IndexEntry ? IndexEntry->getContribution(DW_SECT_STR_OFFSETS) : nullptr; + if (C) + Offset = C->Offset; + if (getVersion() >= 5) { + if (DA.getData().data() == nullptr) + return None; + Offset += Header.getFormat() == dwarf::DwarfFormat::DWARF32 ? 8 : 16; + // Look for a valid contribution at the given offset. + auto DescOrError = parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), Offset); + if (!DescOrError) + return DescOrError.takeError(); + return *DescOrError; + } + // Prior to DWARF v5, we derive the contribution size from the + // index table (in a package file). In a .dwo file it is simply + // the length of the string offsets section. StrOffsetsContributionDescriptor Desc; - if (C) + if (C) Desc = StrOffsetsContributionDescriptor(C->Offset, C->Length, 4, Header.getFormat()); else if (!IndexEntry && !StringOffsetSection.Data.empty()) @@ -944,8 +944,8 @@ Optional<uint64_t> DWARFUnit::getRnglistOffset(uint32_t Index) { if (Optional<uint64_t> Off = llvm::DWARFListTableHeader::getOffsetEntry( RangesData, RangeSectionBase, getFormat(), Index)) return *Off + RangeSectionBase; - return None; -} + return None; +} Optional<uint64_t> DWARFUnit::getLoclistOffset(uint32_t Index) { if (Optional<uint64_t> Off = llvm::DWARFListTableHeader::getOffsetEntry( diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp index d27fd08db1..216dbce721 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp @@ -1,300 +1,300 @@ -//===- DWARFUnitIndex.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" -#include <cinttypes> -#include <cstdint> - -using namespace llvm; - -namespace { - -enum class DWARFSectionKindV2 { - DW_SECT_INFO = 1, - DW_SECT_TYPES = 2, - DW_SECT_ABBREV = 3, - DW_SECT_LINE = 4, - DW_SECT_LOC = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8, -}; - -} // namespace - -// Return true if the section identifier is defined in the DWARFv5 standard. -constexpr bool isKnownV5SectionID(uint32_t ID) { - return ID >= DW_SECT_INFO && ID <= DW_SECT_RNGLISTS && - ID != DW_SECT_EXT_TYPES; -} - -uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind, - unsigned IndexVersion) { - if (IndexVersion == 5) { - assert(isKnownV5SectionID(Kind)); - return static_cast<uint32_t>(Kind); - } - assert(IndexVersion == 2); - switch (Kind) { -#define CASE(S,T) \ - case DW_SECT_##S: \ - return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T) - CASE(INFO, INFO); - CASE(EXT_TYPES, TYPES); - CASE(ABBREV, ABBREV); - CASE(LINE, LINE); - CASE(EXT_LOC, LOC); - CASE(STR_OFFSETS, STR_OFFSETS); - CASE(EXT_MACINFO, MACINFO); - CASE(MACRO, MACRO); -#undef CASE - default: - // All other section kinds have no corresponding values in v2 indexes. - llvm_unreachable("Invalid DWARFSectionKind"); - } -} - -DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value, - unsigned IndexVersion) { - if (IndexVersion == 5) - return isKnownV5SectionID(Value) - ? static_cast<DWARFSectionKind>(Value) - : DW_SECT_EXT_unknown; - assert(IndexVersion == 2); - switch (static_cast<DWARFSectionKindV2>(Value)) { -#define CASE(S,T) \ - case DWARFSectionKindV2::DW_SECT_##S: \ - return DW_SECT_##T - CASE(INFO, INFO); - CASE(TYPES, EXT_TYPES); - CASE(ABBREV, ABBREV); - CASE(LINE, LINE); - CASE(LOC, EXT_LOC); - CASE(STR_OFFSETS, STR_OFFSETS); - CASE(MACINFO, EXT_MACINFO); - CASE(MACRO, MACRO); -#undef CASE - } - return DW_SECT_EXT_unknown; -} - -bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, - uint64_t *OffsetPtr) { - const uint64_t BeginOffset = *OffsetPtr; - if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16)) - return false; - // GCC Debug Fission defines the version as an unsigned 32-bit field - // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP. - // DWARFv5 defines the same space as an uhalf version field with value of 5 - // and a 2 bytes long padding, see Section 7.3.5.3. - Version = IndexData.getU32(OffsetPtr); - if (Version != 2) { - *OffsetPtr = BeginOffset; - Version = IndexData.getU16(OffsetPtr); - if (Version != 5) - return false; - *OffsetPtr += 2; // Skip padding. - } - NumColumns = IndexData.getU32(OffsetPtr); - NumUnits = IndexData.getU32(OffsetPtr); - NumBuckets = IndexData.getU32(OffsetPtr); - return true; -} - -void DWARFUnitIndex::Header::dump(raw_ostream &OS) const { - OS << format("version = %u, units = %u, slots = %u\n\n", Version, NumUnits, NumBuckets); -} - -bool DWARFUnitIndex::parse(DataExtractor IndexData) { - bool b = parseImpl(IndexData); - if (!b) { - // Make sure we don't try to dump anything - Header.NumBuckets = 0; - // Release any partially initialized data. - ColumnKinds.reset(); - Rows.reset(); - } - return b; -} - -bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) { - uint64_t Offset = 0; - if (!Header.parse(IndexData, &Offset)) - return false; - - // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo. - if (Header.Version == 5) - InfoColumnKind = DW_SECT_INFO; - - if (!IndexData.isValidOffsetForDataOfSize( - Offset, Header.NumBuckets * (8 + 4) + - (2 * Header.NumUnits + 1) * 4 * Header.NumColumns)) - return false; - - Rows = std::make_unique<Entry[]>(Header.NumBuckets); - auto Contribs = - std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits); - ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns); - RawSectionIds = std::make_unique<uint32_t[]>(Header.NumColumns); - - // Read Hash Table of Signatures - for (unsigned i = 0; i != Header.NumBuckets; ++i) - Rows[i].Signature = IndexData.getU64(&Offset); - - // Read Parallel Table of Indexes - for (unsigned i = 0; i != Header.NumBuckets; ++i) { - auto Index = IndexData.getU32(&Offset); - if (!Index) - continue; - Rows[i].Index = this; - Rows[i].Contributions = - std::make_unique<Entry::SectionContribution[]>(Header.NumColumns); - Contribs[Index - 1] = Rows[i].Contributions.get(); - } - - // Read the Column Headers - for (unsigned i = 0; i != Header.NumColumns; ++i) { - RawSectionIds[i] = IndexData.getU32(&Offset); - ColumnKinds[i] = deserializeSectionKind(RawSectionIds[i], Header.Version); - if (ColumnKinds[i] == InfoColumnKind) { - if (InfoColumn != -1) - return false; - InfoColumn = i; - } - } - - if (InfoColumn == -1) - return false; - - // Read Table of Section Offsets - for (unsigned i = 0; i != Header.NumUnits; ++i) { - auto *Contrib = Contribs[i]; - for (unsigned i = 0; i != Header.NumColumns; ++i) - Contrib[i].Offset = IndexData.getU32(&Offset); - } - - // Read Table of Section Sizes - for (unsigned i = 0; i != Header.NumUnits; ++i) { - auto *Contrib = Contribs[i]; - for (unsigned i = 0; i != Header.NumColumns; ++i) - Contrib[i].Length = IndexData.getU32(&Offset); - } - - return true; -} - -StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) { - switch (DS) { -#define HANDLE_DW_SECT(ID, NAME) \ - case DW_SECT_##NAME: \ - return #NAME; -#include "llvm/BinaryFormat/Dwarf.def" - case DW_SECT_EXT_TYPES: - return "TYPES"; - case DW_SECT_EXT_LOC: - return "LOC"; - case DW_SECT_EXT_MACINFO: - return "MACINFO"; - case DW_SECT_EXT_unknown: - return StringRef(); - } - llvm_unreachable("Unknown DWARFSectionKind"); -} - -void DWARFUnitIndex::dump(raw_ostream &OS) const { - if (!*this) - return; - - Header.dump(OS); - OS << "Index Signature "; - for (unsigned i = 0; i != Header.NumColumns; ++i) { - DWARFSectionKind Kind = ColumnKinds[i]; - StringRef Name = getColumnHeader(Kind); - if (!Name.empty()) - OS << ' ' << left_justify(Name, 24); - else - OS << format(" Unknown: %-15" PRIu32, RawSectionIds[i]); - } - OS << "\n----- ------------------"; - for (unsigned i = 0; i != Header.NumColumns; ++i) - OS << " ------------------------"; - OS << '\n'; - for (unsigned i = 0; i != Header.NumBuckets; ++i) { - auto &Row = Rows[i]; - if (auto *Contribs = Row.Contributions.get()) { - OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature); - for (unsigned i = 0; i != Header.NumColumns; ++i) { - auto &Contrib = Contribs[i]; - OS << format("[0x%08x, 0x%08x) ", Contrib.Offset, - Contrib.Offset + Contrib.Length); - } - OS << '\n'; - } - } -} - -const DWARFUnitIndex::Entry::SectionContribution * -DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec) const { - uint32_t i = 0; - for (; i != Index->Header.NumColumns; ++i) - if (Index->ColumnKinds[i] == Sec) - return &Contributions[i]; - return nullptr; -} - -const DWARFUnitIndex::Entry::SectionContribution * -DWARFUnitIndex::Entry::getContribution() const { - return &Contributions[Index->InfoColumn]; -} - -const DWARFUnitIndex::Entry * -DWARFUnitIndex::getFromOffset(uint32_t Offset) const { - if (OffsetLookup.empty()) { - for (uint32_t i = 0; i != Header.NumBuckets; ++i) - if (Rows[i].Contributions) - OffsetLookup.push_back(&Rows[i]); - llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) { - return E1->Contributions[InfoColumn].Offset < - E2->Contributions[InfoColumn].Offset; - }); - } - auto I = partition_point(OffsetLookup, [&](Entry *E2) { - return E2->Contributions[InfoColumn].Offset <= Offset; - }); - if (I == OffsetLookup.begin()) - return nullptr; - --I; - const auto *E = *I; - const auto &InfoContrib = E->Contributions[InfoColumn]; - if ((InfoContrib.Offset + InfoContrib.Length) <= Offset) - return nullptr; - return E; -} - -const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const { - uint64_t Mask = Header.NumBuckets - 1; - - auto H = S & Mask; - auto HP = ((S >> 32) & Mask) | 1; - // The spec says "while 0 is a valid hash value, the row index in a used slot - // will always be non-zero". Loop until we find a match or an empty slot. - while (Rows[H].getSignature() != S && Rows[H].Index != nullptr) - H = (H + HP) & Mask; - - // If the slot is empty, we don't care whether the signature matches (it could - // be zero and still match the zeros in the empty slot). - if (Rows[H].Index == nullptr) - return nullptr; - - return &Rows[H]; -} +//===- DWARFUnitIndex.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cinttypes> +#include <cstdint> + +using namespace llvm; + +namespace { + +enum class DWARFSectionKindV2 { + DW_SECT_INFO = 1, + DW_SECT_TYPES = 2, + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOC = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACINFO = 7, + DW_SECT_MACRO = 8, +}; + +} // namespace + +// Return true if the section identifier is defined in the DWARFv5 standard. +constexpr bool isKnownV5SectionID(uint32_t ID) { + return ID >= DW_SECT_INFO && ID <= DW_SECT_RNGLISTS && + ID != DW_SECT_EXT_TYPES; +} + +uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind, + unsigned IndexVersion) { + if (IndexVersion == 5) { + assert(isKnownV5SectionID(Kind)); + return static_cast<uint32_t>(Kind); + } + assert(IndexVersion == 2); + switch (Kind) { +#define CASE(S,T) \ + case DW_SECT_##S: \ + return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T) + CASE(INFO, INFO); + CASE(EXT_TYPES, TYPES); + CASE(ABBREV, ABBREV); + CASE(LINE, LINE); + CASE(EXT_LOC, LOC); + CASE(STR_OFFSETS, STR_OFFSETS); + CASE(EXT_MACINFO, MACINFO); + CASE(MACRO, MACRO); +#undef CASE + default: + // All other section kinds have no corresponding values in v2 indexes. + llvm_unreachable("Invalid DWARFSectionKind"); + } +} + +DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value, + unsigned IndexVersion) { + if (IndexVersion == 5) + return isKnownV5SectionID(Value) + ? static_cast<DWARFSectionKind>(Value) + : DW_SECT_EXT_unknown; + assert(IndexVersion == 2); + switch (static_cast<DWARFSectionKindV2>(Value)) { +#define CASE(S,T) \ + case DWARFSectionKindV2::DW_SECT_##S: \ + return DW_SECT_##T + CASE(INFO, INFO); + CASE(TYPES, EXT_TYPES); + CASE(ABBREV, ABBREV); + CASE(LINE, LINE); + CASE(LOC, EXT_LOC); + CASE(STR_OFFSETS, STR_OFFSETS); + CASE(MACINFO, EXT_MACINFO); + CASE(MACRO, MACRO); +#undef CASE + } + return DW_SECT_EXT_unknown; +} + +bool DWARFUnitIndex::Header::parse(DataExtractor IndexData, + uint64_t *OffsetPtr) { + const uint64_t BeginOffset = *OffsetPtr; + if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16)) + return false; + // GCC Debug Fission defines the version as an unsigned 32-bit field + // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP. + // DWARFv5 defines the same space as an uhalf version field with value of 5 + // and a 2 bytes long padding, see Section 7.3.5.3. + Version = IndexData.getU32(OffsetPtr); + if (Version != 2) { + *OffsetPtr = BeginOffset; + Version = IndexData.getU16(OffsetPtr); + if (Version != 5) + return false; + *OffsetPtr += 2; // Skip padding. + } + NumColumns = IndexData.getU32(OffsetPtr); + NumUnits = IndexData.getU32(OffsetPtr); + NumBuckets = IndexData.getU32(OffsetPtr); + return true; +} + +void DWARFUnitIndex::Header::dump(raw_ostream &OS) const { + OS << format("version = %u, units = %u, slots = %u\n\n", Version, NumUnits, NumBuckets); +} + +bool DWARFUnitIndex::parse(DataExtractor IndexData) { + bool b = parseImpl(IndexData); + if (!b) { + // Make sure we don't try to dump anything + Header.NumBuckets = 0; + // Release any partially initialized data. + ColumnKinds.reset(); + Rows.reset(); + } + return b; +} + +bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) { + uint64_t Offset = 0; + if (!Header.parse(IndexData, &Offset)) + return false; + + // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo. + if (Header.Version == 5) + InfoColumnKind = DW_SECT_INFO; + + if (!IndexData.isValidOffsetForDataOfSize( + Offset, Header.NumBuckets * (8 + 4) + + (2 * Header.NumUnits + 1) * 4 * Header.NumColumns)) + return false; + + Rows = std::make_unique<Entry[]>(Header.NumBuckets); + auto Contribs = + std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits); + ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns); + RawSectionIds = std::make_unique<uint32_t[]>(Header.NumColumns); + + // Read Hash Table of Signatures + for (unsigned i = 0; i != Header.NumBuckets; ++i) + Rows[i].Signature = IndexData.getU64(&Offset); + + // Read Parallel Table of Indexes + for (unsigned i = 0; i != Header.NumBuckets; ++i) { + auto Index = IndexData.getU32(&Offset); + if (!Index) + continue; + Rows[i].Index = this; + Rows[i].Contributions = + std::make_unique<Entry::SectionContribution[]>(Header.NumColumns); + Contribs[Index - 1] = Rows[i].Contributions.get(); + } + + // Read the Column Headers + for (unsigned i = 0; i != Header.NumColumns; ++i) { + RawSectionIds[i] = IndexData.getU32(&Offset); + ColumnKinds[i] = deserializeSectionKind(RawSectionIds[i], Header.Version); + if (ColumnKinds[i] == InfoColumnKind) { + if (InfoColumn != -1) + return false; + InfoColumn = i; + } + } + + if (InfoColumn == -1) + return false; + + // Read Table of Section Offsets + for (unsigned i = 0; i != Header.NumUnits; ++i) { + auto *Contrib = Contribs[i]; + for (unsigned i = 0; i != Header.NumColumns; ++i) + Contrib[i].Offset = IndexData.getU32(&Offset); + } + + // Read Table of Section Sizes + for (unsigned i = 0; i != Header.NumUnits; ++i) { + auto *Contrib = Contribs[i]; + for (unsigned i = 0; i != Header.NumColumns; ++i) + Contrib[i].Length = IndexData.getU32(&Offset); + } + + return true; +} + +StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) { + switch (DS) { +#define HANDLE_DW_SECT(ID, NAME) \ + case DW_SECT_##NAME: \ + return #NAME; +#include "llvm/BinaryFormat/Dwarf.def" + case DW_SECT_EXT_TYPES: + return "TYPES"; + case DW_SECT_EXT_LOC: + return "LOC"; + case DW_SECT_EXT_MACINFO: + return "MACINFO"; + case DW_SECT_EXT_unknown: + return StringRef(); + } + llvm_unreachable("Unknown DWARFSectionKind"); +} + +void DWARFUnitIndex::dump(raw_ostream &OS) const { + if (!*this) + return; + + Header.dump(OS); + OS << "Index Signature "; + for (unsigned i = 0; i != Header.NumColumns; ++i) { + DWARFSectionKind Kind = ColumnKinds[i]; + StringRef Name = getColumnHeader(Kind); + if (!Name.empty()) + OS << ' ' << left_justify(Name, 24); + else + OS << format(" Unknown: %-15" PRIu32, RawSectionIds[i]); + } + OS << "\n----- ------------------"; + for (unsigned i = 0; i != Header.NumColumns; ++i) + OS << " ------------------------"; + OS << '\n'; + for (unsigned i = 0; i != Header.NumBuckets; ++i) { + auto &Row = Rows[i]; + if (auto *Contribs = Row.Contributions.get()) { + OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature); + for (unsigned i = 0; i != Header.NumColumns; ++i) { + auto &Contrib = Contribs[i]; + OS << format("[0x%08x, 0x%08x) ", Contrib.Offset, + Contrib.Offset + Contrib.Length); + } + OS << '\n'; + } + } +} + +const DWARFUnitIndex::Entry::SectionContribution * +DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec) const { + uint32_t i = 0; + for (; i != Index->Header.NumColumns; ++i) + if (Index->ColumnKinds[i] == Sec) + return &Contributions[i]; + return nullptr; +} + +const DWARFUnitIndex::Entry::SectionContribution * +DWARFUnitIndex::Entry::getContribution() const { + return &Contributions[Index->InfoColumn]; +} + +const DWARFUnitIndex::Entry * +DWARFUnitIndex::getFromOffset(uint32_t Offset) const { + if (OffsetLookup.empty()) { + for (uint32_t i = 0; i != Header.NumBuckets; ++i) + if (Rows[i].Contributions) + OffsetLookup.push_back(&Rows[i]); + llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) { + return E1->Contributions[InfoColumn].Offset < + E2->Contributions[InfoColumn].Offset; + }); + } + auto I = partition_point(OffsetLookup, [&](Entry *E2) { + return E2->Contributions[InfoColumn].Offset <= Offset; + }); + if (I == OffsetLookup.begin()) + return nullptr; + --I; + const auto *E = *I; + const auto &InfoContrib = E->Contributions[InfoColumn]; + if ((InfoContrib.Offset + InfoContrib.Length) <= Offset) + return nullptr; + return E; +} + +const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const { + uint64_t Mask = Header.NumBuckets - 1; + + auto H = S & Mask; + auto HP = ((S >> 32) & Mask) | 1; + // The spec says "while 0 is a valid hash value, the row index in a used slot + // will always be non-zero". Loop until we find a match or an empty slot. + while (Rows[H].getSignature() != S && Rows[H].Index != nullptr) + H = (H + HP) & Mask; + + // If the slot is empty, we don't care whether the signature matches (it could + // be zero and still match the zeros in the empty slot). + if (Rows[H].Index == nullptr) + return nullptr; + + return &Rows[H]; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFVerifier.cpp index ac624ec8b8..ece067244e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -1,177 +1,177 @@ -//===- DWARFVerifier.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" -#include "llvm/DebugInfo/DWARF/DWARFDie.h" -#include "llvm/DebugInfo/DWARF/DWARFExpression.h" -#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/DebugInfo/DWARF/DWARFSection.h" -#include "llvm/Support/DJB.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/WithColor.h" -#include "llvm/Support/raw_ostream.h" -#include <map> -#include <set> -#include <vector> - -using namespace llvm; -using namespace dwarf; -using namespace object; - -Optional<DWARFAddressRange> -DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { - auto Begin = Ranges.begin(); - auto End = Ranges.end(); - auto Pos = std::lower_bound(Begin, End, R); - - if (Pos != End) { - DWARFAddressRange Range(*Pos); - if (Pos->merge(R)) - return Range; - } - if (Pos != Begin) { - auto Iter = Pos - 1; - DWARFAddressRange Range(*Iter); - if (Iter->merge(R)) - return Range; - } - - Ranges.insert(Pos, R); - return None; -} - -DWARFVerifier::DieRangeInfo::die_range_info_iterator -DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { - auto End = Children.end(); - auto Iter = Children.begin(); - while (Iter != End) { - if (Iter->intersects(RI)) - return Iter; - ++Iter; - } - Children.insert(RI); - return Children.end(); -} - -bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { - auto I1 = Ranges.begin(), E1 = Ranges.end(); - auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); - if (I2 == E2) - return true; - - DWARFAddressRange R = *I2; - while (I1 != E1) { - bool Covered = I1->LowPC <= R.LowPC; - if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) { - if (++I2 == E2) - return true; - R = *I2; - continue; - } - if (!Covered) - return false; - if (R.LowPC < I1->HighPC) - R.LowPC = I1->HighPC; - ++I1; - } - return false; -} - -bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { - auto I1 = Ranges.begin(), E1 = Ranges.end(); - auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); - while (I1 != E1 && I2 != E2) { - if (I1->intersects(*I2)) - return true; - if (I1->LowPC < I2->LowPC) - ++I1; - else - ++I2; - } - return false; -} - -bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, - uint64_t *Offset, unsigned UnitIndex, - uint8_t &UnitType, bool &isUnitDWARF64) { - uint64_t AbbrOffset, Length; - uint8_t AddrSize = 0; - uint16_t Version; - bool Success = true; - - bool ValidLength = false; - bool ValidVersion = false; - bool ValidAddrSize = false; - bool ValidType = true; - bool ValidAbbrevOffset = true; - - uint64_t OffsetStart = *Offset; - DwarfFormat Format; - std::tie(Length, Format) = DebugInfoData.getInitialLength(Offset); - isUnitDWARF64 = Format == DWARF64; - Version = DebugInfoData.getU16(Offset); - - if (Version >= 5) { - UnitType = DebugInfoData.getU8(Offset); - AddrSize = DebugInfoData.getU8(Offset); - AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); - ValidType = dwarf::isUnitType(UnitType); - } else { - UnitType = 0; - AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); - AddrSize = DebugInfoData.getU8(Offset); - } - - if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) - ValidAbbrevOffset = false; - - ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); - ValidVersion = DWARFContext::isSupportedVersion(Version); - ValidAddrSize = DWARFContext::isAddressSizeSupported(AddrSize); - if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || - !ValidType) { - Success = false; - error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", UnitIndex, - OffsetStart); - if (!ValidLength) - note() << "The length for this unit is too " - "large for the .debug_info provided.\n"; - if (!ValidVersion) - note() << "The 16 bit unit header version is not valid.\n"; - if (!ValidType) - note() << "The unit type encoding is not valid.\n"; - if (!ValidAbbrevOffset) - note() << "The offset into the .debug_abbrev section is " - "not valid.\n"; - if (!ValidAddrSize) - note() << "The address size is unsupported.\n"; - } - *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4); - return Success; -} - -unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { - unsigned NumUnitErrors = 0; - unsigned NumDies = Unit.getNumDIEs(); - for (unsigned I = 0; I < NumDies; ++I) { - auto Die = Unit.getDIEAtIndex(I); - - if (Die.getTag() == DW_TAG_null) - continue; - - for (auto AttrValue : Die.attributes()) { - NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); - NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); - } - +//===- DWARFVerifier.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/DWARF/DWARFVerifier.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFSection.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <set> +#include <vector> + +using namespace llvm; +using namespace dwarf; +using namespace object; + +Optional<DWARFAddressRange> +DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) { + auto Begin = Ranges.begin(); + auto End = Ranges.end(); + auto Pos = std::lower_bound(Begin, End, R); + + if (Pos != End) { + DWARFAddressRange Range(*Pos); + if (Pos->merge(R)) + return Range; + } + if (Pos != Begin) { + auto Iter = Pos - 1; + DWARFAddressRange Range(*Iter); + if (Iter->merge(R)) + return Range; + } + + Ranges.insert(Pos, R); + return None; +} + +DWARFVerifier::DieRangeInfo::die_range_info_iterator +DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) { + auto End = Children.end(); + auto Iter = Children.begin(); + while (Iter != End) { + if (Iter->intersects(RI)) + return Iter; + ++Iter; + } + Children.insert(RI); + return Children.end(); +} + +bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const { + auto I1 = Ranges.begin(), E1 = Ranges.end(); + auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); + if (I2 == E2) + return true; + + DWARFAddressRange R = *I2; + while (I1 != E1) { + bool Covered = I1->LowPC <= R.LowPC; + if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) { + if (++I2 == E2) + return true; + R = *I2; + continue; + } + if (!Covered) + return false; + if (R.LowPC < I1->HighPC) + R.LowPC = I1->HighPC; + ++I1; + } + return false; +} + +bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const { + auto I1 = Ranges.begin(), E1 = Ranges.end(); + auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end(); + while (I1 != E1 && I2 != E2) { + if (I1->intersects(*I2)) + return true; + if (I1->LowPC < I2->LowPC) + ++I1; + else + ++I2; + } + return false; +} + +bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData, + uint64_t *Offset, unsigned UnitIndex, + uint8_t &UnitType, bool &isUnitDWARF64) { + uint64_t AbbrOffset, Length; + uint8_t AddrSize = 0; + uint16_t Version; + bool Success = true; + + bool ValidLength = false; + bool ValidVersion = false; + bool ValidAddrSize = false; + bool ValidType = true; + bool ValidAbbrevOffset = true; + + uint64_t OffsetStart = *Offset; + DwarfFormat Format; + std::tie(Length, Format) = DebugInfoData.getInitialLength(Offset); + isUnitDWARF64 = Format == DWARF64; + Version = DebugInfoData.getU16(Offset); + + if (Version >= 5) { + UnitType = DebugInfoData.getU8(Offset); + AddrSize = DebugInfoData.getU8(Offset); + AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); + ValidType = dwarf::isUnitType(UnitType); + } else { + UnitType = 0; + AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset); + AddrSize = DebugInfoData.getU8(Offset); + } + + if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset)) + ValidAbbrevOffset = false; + + ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3); + ValidVersion = DWARFContext::isSupportedVersion(Version); + ValidAddrSize = DWARFContext::isAddressSizeSupported(AddrSize); + if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset || + !ValidType) { + Success = false; + error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", UnitIndex, + OffsetStart); + if (!ValidLength) + note() << "The length for this unit is too " + "large for the .debug_info provided.\n"; + if (!ValidVersion) + note() << "The 16 bit unit header version is not valid.\n"; + if (!ValidType) + note() << "The unit type encoding is not valid.\n"; + if (!ValidAbbrevOffset) + note() << "The offset into the .debug_abbrev section is " + "not valid.\n"; + if (!ValidAddrSize) + note() << "The address size is unsupported.\n"; + } + *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4); + return Success; +} + +unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { + unsigned NumUnitErrors = 0; + unsigned NumDies = Unit.getNumDIEs(); + for (unsigned I = 0; I < NumDies; ++I) { + auto Die = Unit.getDIEAtIndex(I); + + if (Die.getTag() == DW_TAG_null) + continue; + + for (auto AttrValue : Die.attributes()) { + NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue); + NumUnitErrors += verifyDebugInfoForm(Die, AttrValue); + } + if (Die.hasChildren()) { if (Die.getFirstChild().isValid() && Die.getFirstChild().getTag() == DW_TAG_null) { @@ -181,372 +181,372 @@ unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) { } } - NumUnitErrors += verifyDebugInfoCallSite(Die); - } - - DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); - if (!Die) { - error() << "Compilation unit without DIE.\n"; - NumUnitErrors++; - return NumUnitErrors; - } - - if (!dwarf::isUnitType(Die.getTag())) { - error() << "Compilation unit root DIE is not a unit DIE: " - << dwarf::TagString(Die.getTag()) << ".\n"; - NumUnitErrors++; - } - - uint8_t UnitType = Unit.getUnitType(); - if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { - error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) - << ") and root DIE (" << dwarf::TagString(Die.getTag()) - << ") do not match.\n"; - NumUnitErrors++; - } - - // According to DWARF Debugging Information Format Version 5, - // 3.1.2 Skeleton Compilation Unit Entries: - // "A skeleton compilation unit has no children." - if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) { - error() << "Skeleton compilation unit has children.\n"; - NumUnitErrors++; - } - - DieRangeInfo RI; - NumUnitErrors += verifyDieRanges(Die, RI); - - return NumUnitErrors; -} - -unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { - if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site) - return 0; - - DWARFDie Curr = Die.getParent(); - for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) { - if (Curr.getTag() == DW_TAG_inlined_subroutine) { - error() << "Call site entry nested within inlined subroutine:"; - Curr.dump(OS); - return 1; - } - } - - if (!Curr.isValid()) { - error() << "Call site entry not nested within a valid subprogram:"; - Die.dump(OS); - return 1; - } - - Optional<DWARFFormValue> CallAttr = - Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls, - DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites, - DW_AT_GNU_all_source_call_sites, - DW_AT_GNU_all_tail_call_sites}); - if (!CallAttr) { - error() << "Subprogram with call site entry has no DW_AT_call attribute:"; - Curr.dump(OS); - Die.dump(OS, /*indent*/ 1); - return 1; - } - - return 0; -} - -unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { - unsigned NumErrors = 0; - if (Abbrev) { - const DWARFAbbreviationDeclarationSet *AbbrDecls = - Abbrev->getAbbreviationDeclarationSet(0); - for (auto AbbrDecl : *AbbrDecls) { - SmallDenseSet<uint16_t> AttributeSet; - for (auto Attribute : AbbrDecl.attributes()) { - auto Result = AttributeSet.insert(Attribute.Attr); - if (!Result.second) { - error() << "Abbreviation declaration contains multiple " - << AttributeString(Attribute.Attr) << " attributes.\n"; - AbbrDecl.dump(OS); - ++NumErrors; - } - } - } - } - return NumErrors; -} - -bool DWARFVerifier::handleDebugAbbrev() { - OS << "Verifying .debug_abbrev...\n"; - - const DWARFObject &DObj = DCtx.getDWARFObj(); - unsigned NumErrors = 0; - if (!DObj.getAbbrevSection().empty()) - NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); - if (!DObj.getAbbrevDWOSection().empty()) - NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); - - return NumErrors == 0; -} - -unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, - DWARFSectionKind SectionKind) { - const DWARFObject &DObj = DCtx.getDWARFObj(); - DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); - unsigned NumDebugInfoErrors = 0; - uint64_t OffsetStart = 0, Offset = 0, UnitIdx = 0; - uint8_t UnitType = 0; - bool isUnitDWARF64 = false; - bool isHeaderChainValid = true; - bool hasDIE = DebugInfoData.isValidOffset(Offset); - DWARFUnitVector TypeUnitVector; - DWARFUnitVector CompileUnitVector; - while (hasDIE) { - OffsetStart = Offset; - if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, - isUnitDWARF64)) { - isHeaderChainValid = false; - if (isUnitDWARF64) - break; - } else { - DWARFUnitHeader Header; - Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind); - DWARFUnit *Unit; - switch (UnitType) { - case dwarf::DW_UT_type: - case dwarf::DW_UT_split_type: { - Unit = TypeUnitVector.addUnit(std::make_unique<DWARFTypeUnit>( - DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(), - &DObj.getLocSection(), DObj.getStrSection(), - DObj.getStrOffsetsSection(), &DObj.getAddrSection(), - DObj.getLineSection(), DCtx.isLittleEndian(), false, - TypeUnitVector)); - break; - } - case dwarf::DW_UT_skeleton: - case dwarf::DW_UT_split_compile: - case dwarf::DW_UT_compile: - case dwarf::DW_UT_partial: - // UnitType = 0 means that we are verifying a compile unit in DWARF v4. - case 0: { - Unit = CompileUnitVector.addUnit(std::make_unique<DWARFCompileUnit>( - DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(), - &DObj.getLocSection(), DObj.getStrSection(), - DObj.getStrOffsetsSection(), &DObj.getAddrSection(), - DObj.getLineSection(), DCtx.isLittleEndian(), false, - CompileUnitVector)); - break; - } - default: { llvm_unreachable("Invalid UnitType."); } - } - NumDebugInfoErrors += verifyUnitContents(*Unit); - } - hasDIE = DebugInfoData.isValidOffset(Offset); - ++UnitIdx; - } - if (UnitIdx == 0 && !hasDIE) { - warn() << "Section is empty.\n"; - isHeaderChainValid = true; - } - if (!isHeaderChainValid) - ++NumDebugInfoErrors; - NumDebugInfoErrors += verifyDebugInfoReferences(); - return NumDebugInfoErrors; -} - -bool DWARFVerifier::handleDebugInfo() { - const DWARFObject &DObj = DCtx.getDWARFObj(); - unsigned NumErrors = 0; - - OS << "Verifying .debug_info Unit Header Chain...\n"; - DObj.forEachInfoSections([&](const DWARFSection &S) { - NumErrors += verifyUnitSection(S, DW_SECT_INFO); - }); - - OS << "Verifying .debug_types Unit Header Chain...\n"; - DObj.forEachTypesSections([&](const DWARFSection &S) { - NumErrors += verifyUnitSection(S, DW_SECT_EXT_TYPES); - }); - return NumErrors == 0; -} - -unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, - DieRangeInfo &ParentRI) { - unsigned NumErrors = 0; - - if (!Die.isValid()) - return NumErrors; - - auto RangesOrError = Die.getAddressRanges(); - if (!RangesOrError) { - // FIXME: Report the error. - ++NumErrors; - llvm::consumeError(RangesOrError.takeError()); - return NumErrors; - } - - DWARFAddressRangesVector Ranges = RangesOrError.get(); - // Build RI for this DIE and check that ranges within this DIE do not - // overlap. - DieRangeInfo RI(Die); - - // TODO support object files better - // - // Some object file formats (i.e. non-MachO) support COMDAT. ELF in - // particular does so by placing each function into a section. The DWARF data - // for the function at that point uses a section relative DW_FORM_addrp for - // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc. - // In such a case, when the Die is the CU, the ranges will overlap, and we - // will flag valid conflicting ranges as invalid. - // - // For such targets, we should read the ranges from the CU and partition them - // by the section id. The ranges within a particular section should be - // disjoint, although the ranges across sections may overlap. We would map - // the child die to the entity that it references and the section with which - // it is associated. The child would then be checked against the range - // information for the associated section. - // - // For now, simply elide the range verification for the CU DIEs if we are - // processing an object file. - - if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) { - bool DumpDieAfterError = false; - for (auto Range : Ranges) { - if (!Range.valid()) { - ++NumErrors; - error() << "Invalid address range " << Range << "\n"; - DumpDieAfterError = true; - continue; - } - - // Verify that ranges don't intersect and also build up the DieRangeInfo - // address ranges. Don't break out of the loop below early, or we will - // think this DIE doesn't have all of the address ranges it is supposed - // to have. Compile units often have DW_AT_ranges that can contain one or - // more dead stripped address ranges which tend to all be at the same - // address: 0 or -1. - if (auto PrevRange = RI.insert(Range)) { - ++NumErrors; - error() << "DIE has overlapping ranges in DW_AT_ranges attribute: " - << *PrevRange << " and " << Range << '\n'; - DumpDieAfterError = true; - } - } - if (DumpDieAfterError) - dump(Die, 2) << '\n'; - } - - // Verify that children don't intersect. - const auto IntersectingChild = ParentRI.insert(RI); - if (IntersectingChild != ParentRI.Children.end()) { - ++NumErrors; - error() << "DIEs have overlapping address ranges:"; - dump(Die); - dump(IntersectingChild->Die) << '\n'; - } - - // Verify that ranges are contained within their parent. - bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() && - !(Die.getTag() == DW_TAG_subprogram && - ParentRI.Die.getTag() == DW_TAG_subprogram); - if (ShouldBeContained && !ParentRI.contains(RI)) { - ++NumErrors; - error() << "DIE address ranges are not contained in its parent's ranges:"; - dump(ParentRI.Die); - dump(Die, 2) << '\n'; - } - - // Recursively check children. - for (DWARFDie Child : Die) - NumErrors += verifyDieRanges(Child, RI); - - return NumErrors; -} - -unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, - DWARFAttribute &AttrValue) { - unsigned NumErrors = 0; - auto ReportError = [&](const Twine &TitleMsg) { - ++NumErrors; - error() << TitleMsg << '\n'; - dump(Die) << '\n'; - }; - - const DWARFObject &DObj = DCtx.getDWARFObj(); - const auto Attr = AttrValue.Attr; - switch (Attr) { - case DW_AT_ranges: - // Make sure the offset in the DW_AT_ranges attribute is valid. - if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - unsigned DwarfVersion = Die.getDwarfUnit()->getVersion(); - const DWARFSection &RangeSection = DwarfVersion < 5 - ? DObj.getRangesSection() - : DObj.getRnglistsSection(); - if (*SectionOffset >= RangeSection.Data.size()) - ReportError( - "DW_AT_ranges offset is beyond " + - StringRef(DwarfVersion < 5 ? ".debug_ranges" : ".debug_rnglists") + - " bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); - break; - } - ReportError("DIE has invalid DW_AT_ranges encoding:"); - break; - case DW_AT_stmt_list: - // Make sure the offset in the DW_AT_stmt_list attribute is valid. - if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DObj.getLineSection().Data.size()) - ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + - llvm::formatv("{0:x8}", *SectionOffset)); - break; - } - ReportError("DIE has invalid DW_AT_stmt_list encoding:"); - break; - case DW_AT_location: { - if (Expected<std::vector<DWARFLocationExpression>> Loc = - Die.getLocations(DW_AT_location)) { - DWARFUnit *U = Die.getDwarfUnit(); - for (const auto &Entry : *Loc) { - DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); - DWARFExpression Expression(Data, U->getAddressByteSize(), - U->getFormParams().Format); - bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) { - return Op.isError(); - }); - if (Error || !Expression.verify(U)) - ReportError("DIE contains invalid DWARF expression:"); - } - } else - ReportError(toString(Loc.takeError())); - break; - } - case DW_AT_specification: - case DW_AT_abstract_origin: { - if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) { - auto DieTag = Die.getTag(); - auto RefTag = ReferencedDie.getTag(); - if (DieTag == RefTag) - break; - if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram) - break; - if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member) - break; - // This might be reference to a function declaration. - if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram) - break; - ReportError("DIE with tag " + TagString(DieTag) + " has " + - AttributeString(Attr) + - " that points to DIE with " - "incompatible tag " + - TagString(RefTag)); - } - break; - } - case DW_AT_type: { - DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type); - if (TypeDie && !isType(TypeDie.getTag())) { - ReportError("DIE has " + AttributeString(Attr) + - " with incompatible tag " + TagString(TypeDie.getTag())); - } - break; - } + NumUnitErrors += verifyDebugInfoCallSite(Die); + } + + DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false); + if (!Die) { + error() << "Compilation unit without DIE.\n"; + NumUnitErrors++; + return NumUnitErrors; + } + + if (!dwarf::isUnitType(Die.getTag())) { + error() << "Compilation unit root DIE is not a unit DIE: " + << dwarf::TagString(Die.getTag()) << ".\n"; + NumUnitErrors++; + } + + uint8_t UnitType = Unit.getUnitType(); + if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) { + error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType) + << ") and root DIE (" << dwarf::TagString(Die.getTag()) + << ") do not match.\n"; + NumUnitErrors++; + } + + // According to DWARF Debugging Information Format Version 5, + // 3.1.2 Skeleton Compilation Unit Entries: + // "A skeleton compilation unit has no children." + if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) { + error() << "Skeleton compilation unit has children.\n"; + NumUnitErrors++; + } + + DieRangeInfo RI; + NumUnitErrors += verifyDieRanges(Die, RI); + + return NumUnitErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) { + if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site) + return 0; + + DWARFDie Curr = Die.getParent(); + for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) { + if (Curr.getTag() == DW_TAG_inlined_subroutine) { + error() << "Call site entry nested within inlined subroutine:"; + Curr.dump(OS); + return 1; + } + } + + if (!Curr.isValid()) { + error() << "Call site entry not nested within a valid subprogram:"; + Die.dump(OS); + return 1; + } + + Optional<DWARFFormValue> CallAttr = + Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls, + DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites, + DW_AT_GNU_all_source_call_sites, + DW_AT_GNU_all_tail_call_sites}); + if (!CallAttr) { + error() << "Subprogram with call site entry has no DW_AT_call attribute:"; + Curr.dump(OS); + Die.dump(OS, /*indent*/ 1); + return 1; + } + + return 0; +} + +unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) { + unsigned NumErrors = 0; + if (Abbrev) { + const DWARFAbbreviationDeclarationSet *AbbrDecls = + Abbrev->getAbbreviationDeclarationSet(0); + for (auto AbbrDecl : *AbbrDecls) { + SmallDenseSet<uint16_t> AttributeSet; + for (auto Attribute : AbbrDecl.attributes()) { + auto Result = AttributeSet.insert(Attribute.Attr); + if (!Result.second) { + error() << "Abbreviation declaration contains multiple " + << AttributeString(Attribute.Attr) << " attributes.\n"; + AbbrDecl.dump(OS); + ++NumErrors; + } + } + } + } + return NumErrors; +} + +bool DWARFVerifier::handleDebugAbbrev() { + OS << "Verifying .debug_abbrev...\n"; + + const DWARFObject &DObj = DCtx.getDWARFObj(); + unsigned NumErrors = 0; + if (!DObj.getAbbrevSection().empty()) + NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev()); + if (!DObj.getAbbrevDWOSection().empty()) + NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO()); + + return NumErrors == 0; +} + +unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S, + DWARFSectionKind SectionKind) { + const DWARFObject &DObj = DCtx.getDWARFObj(); + DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0); + unsigned NumDebugInfoErrors = 0; + uint64_t OffsetStart = 0, Offset = 0, UnitIdx = 0; + uint8_t UnitType = 0; + bool isUnitDWARF64 = false; + bool isHeaderChainValid = true; + bool hasDIE = DebugInfoData.isValidOffset(Offset); + DWARFUnitVector TypeUnitVector; + DWARFUnitVector CompileUnitVector; + while (hasDIE) { + OffsetStart = Offset; + if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType, + isUnitDWARF64)) { + isHeaderChainValid = false; + if (isUnitDWARF64) + break; + } else { + DWARFUnitHeader Header; + Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind); + DWARFUnit *Unit; + switch (UnitType) { + case dwarf::DW_UT_type: + case dwarf::DW_UT_split_type: { + Unit = TypeUnitVector.addUnit(std::make_unique<DWARFTypeUnit>( + DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(), + &DObj.getLocSection(), DObj.getStrSection(), + DObj.getStrOffsetsSection(), &DObj.getAddrSection(), + DObj.getLineSection(), DCtx.isLittleEndian(), false, + TypeUnitVector)); + break; + } + case dwarf::DW_UT_skeleton: + case dwarf::DW_UT_split_compile: + case dwarf::DW_UT_compile: + case dwarf::DW_UT_partial: + // UnitType = 0 means that we are verifying a compile unit in DWARF v4. + case 0: { + Unit = CompileUnitVector.addUnit(std::make_unique<DWARFCompileUnit>( + DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangesSection(), + &DObj.getLocSection(), DObj.getStrSection(), + DObj.getStrOffsetsSection(), &DObj.getAddrSection(), + DObj.getLineSection(), DCtx.isLittleEndian(), false, + CompileUnitVector)); + break; + } + default: { llvm_unreachable("Invalid UnitType."); } + } + NumDebugInfoErrors += verifyUnitContents(*Unit); + } + hasDIE = DebugInfoData.isValidOffset(Offset); + ++UnitIdx; + } + if (UnitIdx == 0 && !hasDIE) { + warn() << "Section is empty.\n"; + isHeaderChainValid = true; + } + if (!isHeaderChainValid) + ++NumDebugInfoErrors; + NumDebugInfoErrors += verifyDebugInfoReferences(); + return NumDebugInfoErrors; +} + +bool DWARFVerifier::handleDebugInfo() { + const DWARFObject &DObj = DCtx.getDWARFObj(); + unsigned NumErrors = 0; + + OS << "Verifying .debug_info Unit Header Chain...\n"; + DObj.forEachInfoSections([&](const DWARFSection &S) { + NumErrors += verifyUnitSection(S, DW_SECT_INFO); + }); + + OS << "Verifying .debug_types Unit Header Chain...\n"; + DObj.forEachTypesSections([&](const DWARFSection &S) { + NumErrors += verifyUnitSection(S, DW_SECT_EXT_TYPES); + }); + return NumErrors == 0; +} + +unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, + DieRangeInfo &ParentRI) { + unsigned NumErrors = 0; + + if (!Die.isValid()) + return NumErrors; + + auto RangesOrError = Die.getAddressRanges(); + if (!RangesOrError) { + // FIXME: Report the error. + ++NumErrors; + llvm::consumeError(RangesOrError.takeError()); + return NumErrors; + } + + DWARFAddressRangesVector Ranges = RangesOrError.get(); + // Build RI for this DIE and check that ranges within this DIE do not + // overlap. + DieRangeInfo RI(Die); + + // TODO support object files better + // + // Some object file formats (i.e. non-MachO) support COMDAT. ELF in + // particular does so by placing each function into a section. The DWARF data + // for the function at that point uses a section relative DW_FORM_addrp for + // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc. + // In such a case, when the Die is the CU, the ranges will overlap, and we + // will flag valid conflicting ranges as invalid. + // + // For such targets, we should read the ranges from the CU and partition them + // by the section id. The ranges within a particular section should be + // disjoint, although the ranges across sections may overlap. We would map + // the child die to the entity that it references and the section with which + // it is associated. The child would then be checked against the range + // information for the associated section. + // + // For now, simply elide the range verification for the CU DIEs if we are + // processing an object file. + + if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) { + bool DumpDieAfterError = false; + for (auto Range : Ranges) { + if (!Range.valid()) { + ++NumErrors; + error() << "Invalid address range " << Range << "\n"; + DumpDieAfterError = true; + continue; + } + + // Verify that ranges don't intersect and also build up the DieRangeInfo + // address ranges. Don't break out of the loop below early, or we will + // think this DIE doesn't have all of the address ranges it is supposed + // to have. Compile units often have DW_AT_ranges that can contain one or + // more dead stripped address ranges which tend to all be at the same + // address: 0 or -1. + if (auto PrevRange = RI.insert(Range)) { + ++NumErrors; + error() << "DIE has overlapping ranges in DW_AT_ranges attribute: " + << *PrevRange << " and " << Range << '\n'; + DumpDieAfterError = true; + } + } + if (DumpDieAfterError) + dump(Die, 2) << '\n'; + } + + // Verify that children don't intersect. + const auto IntersectingChild = ParentRI.insert(RI); + if (IntersectingChild != ParentRI.Children.end()) { + ++NumErrors; + error() << "DIEs have overlapping address ranges:"; + dump(Die); + dump(IntersectingChild->Die) << '\n'; + } + + // Verify that ranges are contained within their parent. + bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() && + !(Die.getTag() == DW_TAG_subprogram && + ParentRI.Die.getTag() == DW_TAG_subprogram); + if (ShouldBeContained && !ParentRI.contains(RI)) { + ++NumErrors; + error() << "DIE address ranges are not contained in its parent's ranges:"; + dump(ParentRI.Die); + dump(Die, 2) << '\n'; + } + + // Recursively check children. + for (DWARFDie Child : Die) + NumErrors += verifyDieRanges(Child, RI); + + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, + DWARFAttribute &AttrValue) { + unsigned NumErrors = 0; + auto ReportError = [&](const Twine &TitleMsg) { + ++NumErrors; + error() << TitleMsg << '\n'; + dump(Die) << '\n'; + }; + + const DWARFObject &DObj = DCtx.getDWARFObj(); + const auto Attr = AttrValue.Attr; + switch (Attr) { + case DW_AT_ranges: + // Make sure the offset in the DW_AT_ranges attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + unsigned DwarfVersion = Die.getDwarfUnit()->getVersion(); + const DWARFSection &RangeSection = DwarfVersion < 5 + ? DObj.getRangesSection() + : DObj.getRnglistsSection(); + if (*SectionOffset >= RangeSection.Data.size()) + ReportError( + "DW_AT_ranges offset is beyond " + + StringRef(DwarfVersion < 5 ? ".debug_ranges" : ".debug_rnglists") + + " bounds: " + llvm::formatv("{0:x8}", *SectionOffset)); + break; + } + ReportError("DIE has invalid DW_AT_ranges encoding:"); + break; + case DW_AT_stmt_list: + // Make sure the offset in the DW_AT_stmt_list attribute is valid. + if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { + if (*SectionOffset >= DObj.getLineSection().Data.size()) + ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + + llvm::formatv("{0:x8}", *SectionOffset)); + break; + } + ReportError("DIE has invalid DW_AT_stmt_list encoding:"); + break; + case DW_AT_location: { + if (Expected<std::vector<DWARFLocationExpression>> Loc = + Die.getLocations(DW_AT_location)) { + DWARFUnit *U = Die.getDwarfUnit(); + for (const auto &Entry : *Loc) { + DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); + bool Error = any_of(Expression, [](DWARFExpression::Operation &Op) { + return Op.isError(); + }); + if (Error || !Expression.verify(U)) + ReportError("DIE contains invalid DWARF expression:"); + } + } else + ReportError(toString(Loc.takeError())); + break; + } + case DW_AT_specification: + case DW_AT_abstract_origin: { + if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) { + auto DieTag = Die.getTag(); + auto RefTag = ReferencedDie.getTag(); + if (DieTag == RefTag) + break; + if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram) + break; + if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member) + break; + // This might be reference to a function declaration. + if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram) + break; + ReportError("DIE with tag " + TagString(DieTag) + " has " + + AttributeString(Attr) + + " that points to DIE with " + "incompatible tag " + + TagString(RefTag)); + } + break; + } + case DW_AT_type: { + DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type); + if (TypeDie && !isType(TypeDie.getTag())) { + ReportError("DIE has " + AttributeString(Attr) + + " with incompatible tag " + TagString(TypeDie.getTag())); + } + break; + } case DW_AT_call_file: case DW_AT_decl_file: { if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) { @@ -580,960 +580,960 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, } break; } - default: - break; - } - return NumErrors; -} - -unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, - DWARFAttribute &AttrValue) { - const DWARFObject &DObj = DCtx.getDWARFObj(); - auto DieCU = Die.getDwarfUnit(); - unsigned NumErrors = 0; - const auto Form = AttrValue.Value.getForm(); - switch (Form) { - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: { - // Verify all CU relative references are valid CU offsets. - Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); - assert(RefVal); - if (RefVal) { - auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); - auto CUOffset = AttrValue.Value.getRawUValue(); - if (CUOffset >= CUSize) { - ++NumErrors; - error() << FormEncodingString(Form) << " CU offset " - << format("0x%08" PRIx64, CUOffset) - << " is invalid (must be less than CU size of " - << format("0x%08" PRIx64, CUSize) << "):\n"; - Die.dump(OS, 0, DumpOpts); - dump(Die) << '\n'; - } else { - // Valid reference, but we will verify it points to an actual - // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); - } - } - break; - } - case DW_FORM_ref_addr: { - // Verify all absolute DIE references have valid offsets in the - // .debug_info section. - Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); - assert(RefVal); - if (RefVal) { - if (*RefVal >= DieCU->getInfoSection().Data.size()) { - ++NumErrors; - error() << "DW_FORM_ref_addr offset beyond .debug_info " - "bounds:\n"; - dump(Die) << '\n'; - } else { - // Valid reference, but we will verify it points to an actual - // DIE later. - ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); - } - } - break; - } - case DW_FORM_strp: { - auto SecOffset = AttrValue.Value.getAsSectionOffset(); - assert(SecOffset); // DW_FORM_strp is a section offset. - if (SecOffset && *SecOffset >= DObj.getStrSection().size()) { - ++NumErrors; - error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; - dump(Die) << '\n'; - } - break; - } - case DW_FORM_strx: - case DW_FORM_strx1: - case DW_FORM_strx2: - case DW_FORM_strx3: - case DW_FORM_strx4: { - auto Index = AttrValue.Value.getRawUValue(); - auto DieCU = Die.getDwarfUnit(); - // Check that we have a valid DWARF v5 string offsets table. - if (!DieCU->getStringOffsetsTableContribution()) { - ++NumErrors; - error() << FormEncodingString(Form) - << " used without a valid string offsets table:\n"; - dump(Die) << '\n'; - break; - } - // Check that the index is within the bounds of the section. - unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize(); - // Use a 64-bit type to calculate the offset to guard against overflow. - uint64_t Offset = - (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize; - if (DObj.getStrOffsetsSection().Data.size() < Offset + ItemSize) { - ++NumErrors; - error() << FormEncodingString(Form) << " uses index " - << format("%" PRIu64, Index) << ", which is too large:\n"; - dump(Die) << '\n'; - break; - } - // Check that the string offset is valid. - uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index); - if (StringOffset >= DObj.getStrSection().size()) { - ++NumErrors; - error() << FormEncodingString(Form) << " uses index " - << format("%" PRIu64, Index) - << ", but the referenced string" - " offset is beyond .debug_str bounds:\n"; - dump(Die) << '\n'; - } - break; - } - default: - break; - } - return NumErrors; -} - -unsigned DWARFVerifier::verifyDebugInfoReferences() { - // Take all references and make sure they point to an actual DIE by - // getting the DIE by offset and emitting an error - OS << "Verifying .debug_info references...\n"; - unsigned NumErrors = 0; - for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : - ReferenceToDIEOffsets) { - if (DCtx.getDIEForOffset(Pair.first)) - continue; - ++NumErrors; - error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) - << ". Offset is in between DIEs:\n"; - for (auto Offset : Pair.second) - dump(DCtx.getDIEForOffset(Offset)) << '\n'; - OS << "\n"; - } - return NumErrors; -} - -void DWARFVerifier::verifyDebugLineStmtOffsets() { - std::map<uint64_t, DWARFDie> StmtListToDie; - for (const auto &CU : DCtx.compile_units()) { - auto Die = CU->getUnitDIE(); - // Get the attribute value as a section offset. No need to produce an - // error here if the encoding isn't correct because we validate this in - // the .debug_info verifier. - auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); - if (!StmtSectionOffset) - continue; - const uint64_t LineTableOffset = *StmtSectionOffset; - auto LineTable = DCtx.getLineTableForUnit(CU.get()); - if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { - if (!LineTable) { - ++NumDebugLineErrors; - error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset) - << "] was not able to be parsed for CU:\n"; - dump(Die) << '\n'; - continue; - } - } else { - // Make sure we don't get a valid line table back if the offset is wrong. - assert(LineTable == nullptr); - // Skip this line table as it isn't valid. No need to create an error - // here because we validate this in the .debug_info verifier. - continue; - } - auto Iter = StmtListToDie.find(LineTableOffset); - if (Iter != StmtListToDie.end()) { - ++NumDebugLineErrors; - error() << "two compile unit DIEs, " - << format("0x%08" PRIx64, Iter->second.getOffset()) << " and " - << format("0x%08" PRIx64, Die.getOffset()) - << ", have the same DW_AT_stmt_list section offset:\n"; - dump(Iter->second); - dump(Die) << '\n'; - // Already verified this line table before, no need to do it again. - continue; - } - StmtListToDie[LineTableOffset] = Die; - } -} - -void DWARFVerifier::verifyDebugLineRows() { - for (const auto &CU : DCtx.compile_units()) { - auto Die = CU->getUnitDIE(); - auto LineTable = DCtx.getLineTableForUnit(CU.get()); - // If there is no line table we will have created an error in the - // .debug_info verifier or in verifyDebugLineStmtOffsets(). - if (!LineTable) - continue; - - // Verify prologue. - uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); - uint32_t FileIndex = 1; - StringMap<uint16_t> FullPathMap; - for (const auto &FileName : LineTable->Prologue.FileNames) { - // Verify directory index. - if (FileName.DirIdx > MaxDirIndex) { - ++NumDebugLineErrors; - error() << ".debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "].prologue.file_names[" << FileIndex - << "].dir_idx contains an invalid index: " << FileName.DirIdx - << "\n"; - } - - // Check file paths for duplicates. - std::string FullPath; - const bool HasFullPath = LineTable->getFileNameByIndex( - FileIndex, CU->getCompilationDir(), - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); - assert(HasFullPath && "Invalid index?"); - (void)HasFullPath; - auto It = FullPathMap.find(FullPath); - if (It == FullPathMap.end()) - FullPathMap[FullPath] = FileIndex; - else if (It->second != FileIndex) { - warn() << ".debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "].prologue.file_names[" << FileIndex - << "] is a duplicate of file_names[" << It->second << "]\n"; - } - - FileIndex++; - } - - // Verify rows. - uint64_t PrevAddress = 0; - uint32_t RowIndex = 0; - for (const auto &Row : LineTable->Rows) { - // Verify row address. - if (Row.Address.Address < PrevAddress) { - ++NumDebugLineErrors; - error() << ".debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "] row[" << RowIndex - << "] decreases in address from previous row:\n"; - - DWARFDebugLine::Row::dumpTableHeader(OS, 0); - if (RowIndex > 0) - LineTable->Rows[RowIndex - 1].dump(OS); - Row.dump(OS); - OS << '\n'; - } - - // Verify file index. - if (!LineTable->hasFileAtIndex(Row.File)) { - ++NumDebugLineErrors; - bool isDWARF5 = LineTable->Prologue.getVersion() >= 5; - error() << ".debug_line[" - << format("0x%08" PRIx64, - *toSectionOffset(Die.find(DW_AT_stmt_list))) - << "][" << RowIndex << "] has invalid file index " << Row.File - << " (valid values are [" << (isDWARF5 ? "0," : "1,") - << LineTable->Prologue.FileNames.size() - << (isDWARF5 ? ")" : "]") << "):\n"; - DWARFDebugLine::Row::dumpTableHeader(OS, 0); - Row.dump(OS); - OS << '\n'; - } - if (Row.EndSequence) - PrevAddress = 0; - else - PrevAddress = Row.Address.Address; - ++RowIndex; - } - } -} - -DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D, - DIDumpOptions DumpOpts) - : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false), - IsMachOObject(false) { - if (const auto *F = DCtx.getDWARFObj().getFile()) { - IsObjectFile = F->isRelocatableObject(); - IsMachOObject = F->isMachO(); - } -} - -bool DWARFVerifier::handleDebugLine() { - NumDebugLineErrors = 0; - OS << "Verifying .debug_line...\n"; - verifyDebugLineStmtOffsets(); - verifyDebugLineRows(); - return NumDebugLineErrors == 0; -} - -unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection, - DataExtractor *StrData, - const char *SectionName) { - unsigned NumErrors = 0; - DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, - DCtx.isLittleEndian(), 0); - AppleAcceleratorTable AccelTable(AccelSectionData, *StrData); - - OS << "Verifying " << SectionName << "...\n"; - - // Verify that the fixed part of the header is not too short. - if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { - error() << "Section is too small to fit a section header.\n"; - return 1; - } - - // Verify that the section is not too short. - if (Error E = AccelTable.extract()) { - error() << toString(std::move(E)) << '\n'; - return 1; - } - - // Verify that all buckets have a valid hash index or are empty. - uint32_t NumBuckets = AccelTable.getNumBuckets(); - uint32_t NumHashes = AccelTable.getNumHashes(); - - uint64_t BucketsOffset = - AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); - uint64_t HashesBase = BucketsOffset + NumBuckets * 4; - uint64_t OffsetsBase = HashesBase + NumHashes * 4; - for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { - uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); - if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { - error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, - HashIdx); - ++NumErrors; - } - } - uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); - if (NumAtoms == 0) { - error() << "No atoms: failed to read HashData.\n"; - return 1; - } - if (!AccelTable.validateForms()) { - error() << "Unsupported form: failed to read HashData.\n"; - return 1; - } - - for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { - uint64_t HashOffset = HashesBase + 4 * HashIdx; - uint64_t DataOffset = OffsetsBase + 4 * HashIdx; - uint32_t Hash = AccelSectionData.getU32(&HashOffset); - uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset); - if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, - sizeof(uint64_t))) { - error() << format("Hash[%d] has invalid HashData offset: " - "0x%08" PRIx64 ".\n", - HashIdx, HashDataOffset); - ++NumErrors; - } - - uint64_t StrpOffset; - uint64_t StringOffset; - uint32_t StringCount = 0; - uint64_t Offset; - unsigned Tag; - while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { - const uint32_t NumHashDataObjects = - AccelSectionData.getU32(&HashDataOffset); - for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; - ++HashDataIdx) { - std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset); - auto Die = DCtx.getDIEForOffset(Offset); - if (!Die) { - const uint32_t BucketIdx = - NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; - StringOffset = StrpOffset; - const char *Name = StrData->getCStr(&StringOffset); - if (!Name) - Name = "<NULL>"; - - error() << format( - "%s Bucket[%d] Hash[%d] = 0x%08x " - "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " " - "is not a valid DIE offset for \"%s\".\n", - SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, - HashDataIdx, Offset, Name); - - ++NumErrors; - continue; - } - if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) { - error() << "Tag " << dwarf::TagString(Tag) - << " in accelerator table does not match Tag " - << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx - << "].\n"; - ++NumErrors; - } - } - ++StringCount; - } - } - return NumErrors; -} - -unsigned -DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) { - // A map from CU offset to the (first) Name Index offset which claims to index - // this CU. - DenseMap<uint64_t, uint64_t> CUMap; - const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max(); - - CUMap.reserve(DCtx.getNumCompileUnits()); - for (const auto &CU : DCtx.compile_units()) - CUMap[CU->getOffset()] = NotIndexed; - - unsigned NumErrors = 0; - for (const DWARFDebugNames::NameIndex &NI : AccelTable) { - if (NI.getCUCount() == 0) { - error() << formatv("Name Index @ {0:x} does not index any CU\n", - NI.getUnitOffset()); - ++NumErrors; - continue; - } - for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) { - uint64_t Offset = NI.getCUOffset(CU); - auto Iter = CUMap.find(Offset); - - if (Iter == CUMap.end()) { - error() << formatv( - "Name Index @ {0:x} references a non-existing CU @ {1:x}\n", - NI.getUnitOffset(), Offset); - ++NumErrors; - continue; - } - - if (Iter->second != NotIndexed) { - error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but " - "this CU is already indexed by Name Index @ {2:x}\n", - NI.getUnitOffset(), Offset, Iter->second); - continue; - } - Iter->second = NI.getUnitOffset(); - } - } - - for (const auto &KV : CUMap) { - if (KV.second == NotIndexed) - warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first); - } - - return NumErrors; -} - -unsigned -DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, - const DataExtractor &StrData) { - struct BucketInfo { - uint32_t Bucket; - uint32_t Index; - - constexpr BucketInfo(uint32_t Bucket, uint32_t Index) - : Bucket(Bucket), Index(Index) {} - bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; } - }; - - uint32_t NumErrors = 0; - if (NI.getBucketCount() == 0) { - warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n", - NI.getUnitOffset()); - return NumErrors; - } - - // Build up a list of (Bucket, Index) pairs. We use this later to verify that - // each Name is reachable from the appropriate bucket. - std::vector<BucketInfo> BucketStarts; - BucketStarts.reserve(NI.getBucketCount() + 1); - for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) { - uint32_t Index = NI.getBucketArrayEntry(Bucket); - if (Index > NI.getNameCount()) { - error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid " - "value {2}. Valid range is [0, {3}].\n", - Bucket, NI.getUnitOffset(), Index, NI.getNameCount()); - ++NumErrors; - continue; - } - if (Index > 0) - BucketStarts.emplace_back(Bucket, Index); - } - - // If there were any buckets with invalid values, skip further checks as they - // will likely produce many errors which will only confuse the actual root - // problem. - if (NumErrors > 0) - return NumErrors; - - // Sort the list in the order of increasing "Index" entries. - array_pod_sort(BucketStarts.begin(), BucketStarts.end()); - - // Insert a sentinel entry at the end, so we can check that the end of the - // table is covered in the loop below. - BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1); - - // Loop invariant: NextUncovered is the (1-based) index of the first Name - // which is not reachable by any of the buckets we processed so far (and - // hasn't been reported as uncovered). - uint32_t NextUncovered = 1; - for (const BucketInfo &B : BucketStarts) { - // Under normal circumstances B.Index be equal to NextUncovered, but it can - // be less if a bucket points to names which are already known to be in some - // bucket we processed earlier. In that case, we won't trigger this error, - // but report the mismatched hash value error instead. (We know the hash - // will not match because we have already verified that the name's hash - // puts it into the previous bucket.) - if (B.Index > NextUncovered) { - error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] " - "are not covered by the hash table.\n", - NI.getUnitOffset(), NextUncovered, B.Index - 1); - ++NumErrors; - } - uint32_t Idx = B.Index; - - // The rest of the checks apply only to non-sentinel entries. - if (B.Bucket == NI.getBucketCount()) - break; - - // This triggers if a non-empty bucket points to a name with a mismatched - // hash. Clients are likely to interpret this as an empty bucket, because a - // mismatched hash signals the end of a bucket, but if this is indeed an - // empty bucket, the producer should have signalled this by marking the - // bucket as empty. - uint32_t FirstHash = NI.getHashArrayEntry(Idx); - if (FirstHash % NI.getBucketCount() != B.Bucket) { - error() << formatv( - "Name Index @ {0:x}: Bucket {1} is not empty but points to a " - "mismatched hash value {2:x} (belonging to bucket {3}).\n", - NI.getUnitOffset(), B.Bucket, FirstHash, - FirstHash % NI.getBucketCount()); - ++NumErrors; - } - - // This find the end of this bucket and also verifies that all the hashes in - // this bucket are correct by comparing the stored hashes to the ones we - // compute ourselves. - while (Idx <= NI.getNameCount()) { - uint32_t Hash = NI.getHashArrayEntry(Idx); - if (Hash % NI.getBucketCount() != B.Bucket) - break; - - const char *Str = NI.getNameTableEntry(Idx).getString(); - if (caseFoldingDjbHash(Str) != Hash) { - error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} " - "hashes to {3:x}, but " - "the Name Index hash is {4:x}\n", - NI.getUnitOffset(), Str, Idx, - caseFoldingDjbHash(Str), Hash); - ++NumErrors; - } - - ++Idx; - } - NextUncovered = std::max(NextUncovered, Idx); - } - return NumErrors; -} - -unsigned DWARFVerifier::verifyNameIndexAttribute( - const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr, - DWARFDebugNames::AttributeEncoding AttrEnc) { - StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form); - if (FormName.empty()) { - error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " - "unknown form: {3}.\n", - NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, - AttrEnc.Form); - return 1; - } - - if (AttrEnc.Index == DW_IDX_type_hash) { - if (AttrEnc.Form != dwarf::DW_FORM_data8) { - error() << formatv( - "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash " - "uses an unexpected form {2} (should be {3}).\n", - NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8); - return 1; - } - } - - // A list of known index attributes and their expected form classes. - // DW_IDX_type_hash is handled specially in the check above, as it has a - // specific form (not just a form class) we should expect. - struct FormClassTable { - dwarf::Index Index; - DWARFFormValue::FormClass Class; - StringLiteral ClassName; - }; - static constexpr FormClassTable Table[] = { - {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}}, - {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}}, - {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}}, - {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}}, - }; - - ArrayRef<FormClassTable> TableRef(Table); - auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) { - return T.Index == AttrEnc.Index; - }); - if (Iter == TableRef.end()) { - warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an " - "unknown index attribute: {2}.\n", - NI.getUnitOffset(), Abbr.Code, AttrEnc.Index); - return 0; - } - - if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) { - error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " - "unexpected form {3} (expected form class {4}).\n", - NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, - AttrEnc.Form, Iter->ClassName); - return 1; - } - return 0; -} - -unsigned -DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) { - if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) { - warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is " - "not currently supported.\n", - NI.getUnitOffset()); - return 0; - } - - unsigned NumErrors = 0; - for (const auto &Abbrev : NI.getAbbrevs()) { - StringRef TagName = dwarf::TagString(Abbrev.Tag); - if (TagName.empty()) { - warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an " - "unknown tag: {2}.\n", - NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag); - } - SmallSet<unsigned, 5> Attributes; - for (const auto &AttrEnc : Abbrev.Attributes) { - if (!Attributes.insert(AttrEnc.Index).second) { - error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains " - "multiple {2} attributes.\n", - NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index); - ++NumErrors; - continue; - } - NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc); - } - - if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) { - error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units " - "and abbreviation {1:x} has no {2} attribute.\n", - NI.getUnitOffset(), Abbrev.Code, - dwarf::DW_IDX_compile_unit); - ++NumErrors; - } - if (!Attributes.count(dwarf::DW_IDX_die_offset)) { - error() << formatv( - "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n", - NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset); - ++NumErrors; - } - } - return NumErrors; -} - -static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE, - bool IncludeLinkageName = true) { - SmallVector<StringRef, 2> Result; - if (const char *Str = DIE.getName(DINameKind::ShortName)) - Result.emplace_back(Str); - else if (DIE.getTag() == dwarf::DW_TAG_namespace) - Result.emplace_back("(anonymous namespace)"); - - if (IncludeLinkageName) { - if (const char *Str = DIE.getName(DINameKind::LinkageName)) { - if (Result.empty() || Result[0] != Str) - Result.emplace_back(Str); - } - } - - return Result; -} - -unsigned DWARFVerifier::verifyNameIndexEntries( - const DWARFDebugNames::NameIndex &NI, - const DWARFDebugNames::NameTableEntry &NTE) { - // Verifying type unit indexes not supported. - if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) - return 0; - - const char *CStr = NTE.getString(); - if (!CStr) { - error() << formatv( - "Name Index @ {0:x}: Unable to get string associated with name {1}.\n", - NI.getUnitOffset(), NTE.getIndex()); - return 1; - } - StringRef Str(CStr); - - unsigned NumErrors = 0; - unsigned NumEntries = 0; - uint64_t EntryID = NTE.getEntryOffset(); - uint64_t NextEntryID = EntryID; - Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID); - for (; EntryOr; ++NumEntries, EntryID = NextEntryID, - EntryOr = NI.getEntry(&NextEntryID)) { - uint32_t CUIndex = *EntryOr->getCUIndex(); - if (CUIndex > NI.getCUCount()) { - error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " - "invalid CU index ({2}).\n", - NI.getUnitOffset(), EntryID, CUIndex); - ++NumErrors; - continue; - } - uint64_t CUOffset = NI.getCUOffset(CUIndex); - uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset(); - DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset); - if (!DIE) { - error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " - "non-existing DIE @ {2:x}.\n", - NI.getUnitOffset(), EntryID, DIEOffset); - ++NumErrors; - continue; - } - if (DIE.getDwarfUnit()->getOffset() != CUOffset) { - error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of " - "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n", - NI.getUnitOffset(), EntryID, DIEOffset, CUOffset, - DIE.getDwarfUnit()->getOffset()); - ++NumErrors; - } - if (DIE.getTag() != EntryOr->tag()) { - error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of " - "DIE @ {2:x}: index - {3}; debug_info - {4}.\n", - NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(), - DIE.getTag()); - ++NumErrors; - } - - auto EntryNames = getNames(DIE); - if (!is_contained(EntryNames, Str)) { - error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name " - "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n", - NI.getUnitOffset(), EntryID, DIEOffset, Str, - make_range(EntryNames.begin(), EntryNames.end())); - ++NumErrors; - } - } - handleAllErrors(EntryOr.takeError(), - [&](const DWARFDebugNames::SentinelError &) { - if (NumEntries > 0) - return; - error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is " - "not associated with any entries.\n", - NI.getUnitOffset(), NTE.getIndex(), Str); - ++NumErrors; - }, - [&](const ErrorInfoBase &Info) { - error() - << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n", - NI.getUnitOffset(), NTE.getIndex(), Str, - Info.message()); - ++NumErrors; - }); - return NumErrors; -} - -static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { - Expected<std::vector<DWARFLocationExpression>> Loc = - Die.getLocations(DW_AT_location); - if (!Loc) { - consumeError(Loc.takeError()); - return false; - } - DWARFUnit *U = Die.getDwarfUnit(); - for (const auto &Entry : *Loc) { - DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), - U->getAddressByteSize()); - DWARFExpression Expression(Data, U->getAddressByteSize(), - U->getFormParams().Format); - bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) { - return !Op.isError() && (Op.getCode() == DW_OP_addr || - Op.getCode() == DW_OP_form_tls_address || - Op.getCode() == DW_OP_GNU_push_tls_address); - }); - if (IsInteresting) - return true; - } - return false; -} - -unsigned DWARFVerifier::verifyNameIndexCompleteness( - const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { - - // First check, if the Die should be indexed. The code follows the DWARF v5 - // wording as closely as possible. - - // "All non-defining declarations (that is, debugging information entries - // with a DW_AT_declaration attribute) are excluded." - if (Die.find(DW_AT_declaration)) - return 0; - - // "DW_TAG_namespace debugging information entries without a DW_AT_name - // attribute are included with the name “(anonymous namespace)”. - // All other debugging information entries without a DW_AT_name attribute - // are excluded." - // "If a subprogram or inlined subroutine is included, and has a - // DW_AT_linkage_name attribute, there will be an additional index entry for - // the linkage name." - auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || - Die.getTag() == DW_TAG_inlined_subroutine; - auto EntryNames = getNames(Die, IncludeLinkageName); - if (EntryNames.empty()) - return 0; - - // We deviate from the specification here, which says: - // "The name index must contain an entry for each debugging information entry - // that defines a named subprogram, label, variable, type, or namespace, - // subject to ..." - // Explicitly exclude all TAGs that we know shouldn't be indexed. - switch (Die.getTag()) { - // Compile units and modules have names but shouldn't be indexed. - case DW_TAG_compile_unit: - case DW_TAG_module: - return 0; - - // Function and template parameters are not globally visible, so we shouldn't - // index them. - case DW_TAG_formal_parameter: - case DW_TAG_template_value_parameter: - case DW_TAG_template_type_parameter: - case DW_TAG_GNU_template_parameter_pack: - case DW_TAG_GNU_template_template_param: - return 0; - - // Object members aren't globally visible. - case DW_TAG_member: - return 0; - - // According to a strict reading of the specification, enumerators should not - // be indexed (and LLVM currently does not do that). However, this causes - // problems for the debuggers, so we may need to reconsider this. - case DW_TAG_enumerator: - return 0; - - // Imported declarations should not be indexed according to the specification - // and LLVM currently does not do that. - case DW_TAG_imported_declaration: - return 0; - - // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging - // information entries without an address attribute (DW_AT_low_pc, - // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - case DW_TAG_label: - if (Die.findRecursively( - {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) - break; - return 0; - - // "DW_TAG_variable debugging information entries with a DW_AT_location - // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are - // included; otherwise, they are excluded." - // - // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. - case DW_TAG_variable: - if (isVariableIndexable(Die, DCtx)) - break; - return 0; - - default: - break; - } - - // Now we know that our Die should be present in the Index. Let's check if - // that's the case. - unsigned NumErrors = 0; - uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); - for (StringRef Name : EntryNames) { - if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) { - return E.getDIEUnitOffset() == DieUnitOffset; - })) { - error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " - "name {3} missing.\n", - NI.getUnitOffset(), Die.getOffset(), Die.getTag(), - Name); - ++NumErrors; - } - } - return NumErrors; -} - -unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, - const DataExtractor &StrData) { - unsigned NumErrors = 0; - DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection, - DCtx.isLittleEndian(), 0); - DWARFDebugNames AccelTable(AccelSectionData, StrData); - - OS << "Verifying .debug_names...\n"; - - // This verifies that we can read individual name indices and their - // abbreviation tables. - if (Error E = AccelTable.extract()) { - error() << toString(std::move(E)) << '\n'; - return 1; - } - - NumErrors += verifyDebugNamesCULists(AccelTable); - for (const auto &NI : AccelTable) - NumErrors += verifyNameIndexBuckets(NI, StrData); - for (const auto &NI : AccelTable) - NumErrors += verifyNameIndexAbbrevs(NI); - - // Don't attempt Entry validation if any of the previous checks found errors - if (NumErrors > 0) - return NumErrors; - for (const auto &NI : AccelTable) - for (DWARFDebugNames::NameTableEntry NTE : NI) - NumErrors += verifyNameIndexEntries(NI, NTE); - - if (NumErrors > 0) - return NumErrors; - - for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) { - if (const DWARFDebugNames::NameIndex *NI = - AccelTable.getCUNameIndex(U->getOffset())) { - auto *CU = cast<DWARFCompileUnit>(U.get()); - for (const DWARFDebugInfoEntry &Die : CU->dies()) - NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI); - } - } - return NumErrors; -} - -bool DWARFVerifier::handleAccelTables() { - const DWARFObject &D = DCtx.getDWARFObj(); - DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0); - unsigned NumErrors = 0; - if (!D.getAppleNamesSection().Data.empty()) - NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, - ".apple_names"); - if (!D.getAppleTypesSection().Data.empty()) - NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, - ".apple_types"); - if (!D.getAppleNamespacesSection().Data.empty()) - NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData, - ".apple_namespaces"); - if (!D.getAppleObjCSection().Data.empty()) - NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, - ".apple_objc"); - - if (!D.getNamesSection().Data.empty()) - NumErrors += verifyDebugNames(D.getNamesSection(), StrData); - return NumErrors == 0; -} - -raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); } - -raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); } - -raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); } - -raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const { - Die.dump(OS, indent, DumpOpts); - return OS; -} + default: + break; + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die, + DWARFAttribute &AttrValue) { + const DWARFObject &DObj = DCtx.getDWARFObj(); + auto DieCU = Die.getDwarfUnit(); + unsigned NumErrors = 0; + const auto Form = AttrValue.Value.getForm(); + switch (Form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: { + // Verify all CU relative references are valid CU offsets. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset(); + auto CUOffset = AttrValue.Value.getRawUValue(); + if (CUOffset >= CUSize) { + ++NumErrors; + error() << FormEncodingString(Form) << " CU offset " + << format("0x%08" PRIx64, CUOffset) + << " is invalid (must be less than CU size of " + << format("0x%08" PRIx64, CUSize) << "):\n"; + Die.dump(OS, 0, DumpOpts); + dump(Die) << '\n'; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_ref_addr: { + // Verify all absolute DIE references have valid offsets in the + // .debug_info section. + Optional<uint64_t> RefVal = AttrValue.Value.getAsReference(); + assert(RefVal); + if (RefVal) { + if (*RefVal >= DieCU->getInfoSection().Data.size()) { + ++NumErrors; + error() << "DW_FORM_ref_addr offset beyond .debug_info " + "bounds:\n"; + dump(Die) << '\n'; + } else { + // Valid reference, but we will verify it points to an actual + // DIE later. + ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset()); + } + } + break; + } + case DW_FORM_strp: { + auto SecOffset = AttrValue.Value.getAsSectionOffset(); + assert(SecOffset); // DW_FORM_strp is a section offset. + if (SecOffset && *SecOffset >= DObj.getStrSection().size()) { + ++NumErrors; + error() << "DW_FORM_strp offset beyond .debug_str bounds:\n"; + dump(Die) << '\n'; + } + break; + } + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: { + auto Index = AttrValue.Value.getRawUValue(); + auto DieCU = Die.getDwarfUnit(); + // Check that we have a valid DWARF v5 string offsets table. + if (!DieCU->getStringOffsetsTableContribution()) { + ++NumErrors; + error() << FormEncodingString(Form) + << " used without a valid string offsets table:\n"; + dump(Die) << '\n'; + break; + } + // Check that the index is within the bounds of the section. + unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize(); + // Use a 64-bit type to calculate the offset to guard against overflow. + uint64_t Offset = + (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize; + if (DObj.getStrOffsetsSection().Data.size() < Offset + ItemSize) { + ++NumErrors; + error() << FormEncodingString(Form) << " uses index " + << format("%" PRIu64, Index) << ", which is too large:\n"; + dump(Die) << '\n'; + break; + } + // Check that the string offset is valid. + uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index); + if (StringOffset >= DObj.getStrSection().size()) { + ++NumErrors; + error() << FormEncodingString(Form) << " uses index " + << format("%" PRIu64, Index) + << ", but the referenced string" + " offset is beyond .debug_str bounds:\n"; + dump(Die) << '\n'; + } + break; + } + default: + break; + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugInfoReferences() { + // Take all references and make sure they point to an actual DIE by + // getting the DIE by offset and emitting an error + OS << "Verifying .debug_info references...\n"; + unsigned NumErrors = 0; + for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair : + ReferenceToDIEOffsets) { + if (DCtx.getDIEForOffset(Pair.first)) + continue; + ++NumErrors; + error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first) + << ". Offset is in between DIEs:\n"; + for (auto Offset : Pair.second) + dump(DCtx.getDIEForOffset(Offset)) << '\n'; + OS << "\n"; + } + return NumErrors; +} + +void DWARFVerifier::verifyDebugLineStmtOffsets() { + std::map<uint64_t, DWARFDie> StmtListToDie; + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + // Get the attribute value as a section offset. No need to produce an + // error here if the encoding isn't correct because we validate this in + // the .debug_info verifier. + auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list)); + if (!StmtSectionOffset) + continue; + const uint64_t LineTableOffset = *StmtSectionOffset; + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) { + if (!LineTable) { + ++NumDebugLineErrors; + error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset) + << "] was not able to be parsed for CU:\n"; + dump(Die) << '\n'; + continue; + } + } else { + // Make sure we don't get a valid line table back if the offset is wrong. + assert(LineTable == nullptr); + // Skip this line table as it isn't valid. No need to create an error + // here because we validate this in the .debug_info verifier. + continue; + } + auto Iter = StmtListToDie.find(LineTableOffset); + if (Iter != StmtListToDie.end()) { + ++NumDebugLineErrors; + error() << "two compile unit DIEs, " + << format("0x%08" PRIx64, Iter->second.getOffset()) << " and " + << format("0x%08" PRIx64, Die.getOffset()) + << ", have the same DW_AT_stmt_list section offset:\n"; + dump(Iter->second); + dump(Die) << '\n'; + // Already verified this line table before, no need to do it again. + continue; + } + StmtListToDie[LineTableOffset] = Die; + } +} + +void DWARFVerifier::verifyDebugLineRows() { + for (const auto &CU : DCtx.compile_units()) { + auto Die = CU->getUnitDIE(); + auto LineTable = DCtx.getLineTableForUnit(CU.get()); + // If there is no line table we will have created an error in the + // .debug_info verifier or in verifyDebugLineStmtOffsets(). + if (!LineTable) + continue; + + // Verify prologue. + uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size(); + uint32_t FileIndex = 1; + StringMap<uint16_t> FullPathMap; + for (const auto &FileName : LineTable->Prologue.FileNames) { + // Verify directory index. + if (FileName.DirIdx > MaxDirIndex) { + ++NumDebugLineErrors; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "].dir_idx contains an invalid index: " << FileName.DirIdx + << "\n"; + } + + // Check file paths for duplicates. + std::string FullPath; + const bool HasFullPath = LineTable->getFileNameByIndex( + FileIndex, CU->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath); + assert(HasFullPath && "Invalid index?"); + (void)HasFullPath; + auto It = FullPathMap.find(FullPath); + if (It == FullPathMap.end()) + FullPathMap[FullPath] = FileIndex; + else if (It->second != FileIndex) { + warn() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "].prologue.file_names[" << FileIndex + << "] is a duplicate of file_names[" << It->second << "]\n"; + } + + FileIndex++; + } + + // Verify rows. + uint64_t PrevAddress = 0; + uint32_t RowIndex = 0; + for (const auto &Row : LineTable->Rows) { + // Verify row address. + if (Row.Address.Address < PrevAddress) { + ++NumDebugLineErrors; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "] row[" << RowIndex + << "] decreases in address from previous row:\n"; + + DWARFDebugLine::Row::dumpTableHeader(OS, 0); + if (RowIndex > 0) + LineTable->Rows[RowIndex - 1].dump(OS); + Row.dump(OS); + OS << '\n'; + } + + // Verify file index. + if (!LineTable->hasFileAtIndex(Row.File)) { + ++NumDebugLineErrors; + bool isDWARF5 = LineTable->Prologue.getVersion() >= 5; + error() << ".debug_line[" + << format("0x%08" PRIx64, + *toSectionOffset(Die.find(DW_AT_stmt_list))) + << "][" << RowIndex << "] has invalid file index " << Row.File + << " (valid values are [" << (isDWARF5 ? "0," : "1,") + << LineTable->Prologue.FileNames.size() + << (isDWARF5 ? ")" : "]") << "):\n"; + DWARFDebugLine::Row::dumpTableHeader(OS, 0); + Row.dump(OS); + OS << '\n'; + } + if (Row.EndSequence) + PrevAddress = 0; + else + PrevAddress = Row.Address.Address; + ++RowIndex; + } + } +} + +DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D, + DIDumpOptions DumpOpts) + : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false), + IsMachOObject(false) { + if (const auto *F = DCtx.getDWARFObj().getFile()) { + IsObjectFile = F->isRelocatableObject(); + IsMachOObject = F->isMachO(); + } +} + +bool DWARFVerifier::handleDebugLine() { + NumDebugLineErrors = 0; + OS << "Verifying .debug_line...\n"; + verifyDebugLineStmtOffsets(); + verifyDebugLineRows(); + return NumDebugLineErrors == 0; +} + +unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection, + DataExtractor *StrData, + const char *SectionName) { + unsigned NumErrors = 0; + DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection, + DCtx.isLittleEndian(), 0); + AppleAcceleratorTable AccelTable(AccelSectionData, *StrData); + + OS << "Verifying " << SectionName << "...\n"; + + // Verify that the fixed part of the header is not too short. + if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) { + error() << "Section is too small to fit a section header.\n"; + return 1; + } + + // Verify that the section is not too short. + if (Error E = AccelTable.extract()) { + error() << toString(std::move(E)) << '\n'; + return 1; + } + + // Verify that all buckets have a valid hash index or are empty. + uint32_t NumBuckets = AccelTable.getNumBuckets(); + uint32_t NumHashes = AccelTable.getNumHashes(); + + uint64_t BucketsOffset = + AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength(); + uint64_t HashesBase = BucketsOffset + NumBuckets * 4; + uint64_t OffsetsBase = HashesBase + NumHashes * 4; + for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) { + uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset); + if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) { + error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx, + HashIdx); + ++NumErrors; + } + } + uint32_t NumAtoms = AccelTable.getAtomsDesc().size(); + if (NumAtoms == 0) { + error() << "No atoms: failed to read HashData.\n"; + return 1; + } + if (!AccelTable.validateForms()) { + error() << "Unsupported form: failed to read HashData.\n"; + return 1; + } + + for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) { + uint64_t HashOffset = HashesBase + 4 * HashIdx; + uint64_t DataOffset = OffsetsBase + 4 * HashIdx; + uint32_t Hash = AccelSectionData.getU32(&HashOffset); + uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset); + if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset, + sizeof(uint64_t))) { + error() << format("Hash[%d] has invalid HashData offset: " + "0x%08" PRIx64 ".\n", + HashIdx, HashDataOffset); + ++NumErrors; + } + + uint64_t StrpOffset; + uint64_t StringOffset; + uint32_t StringCount = 0; + uint64_t Offset; + unsigned Tag; + while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) { + const uint32_t NumHashDataObjects = + AccelSectionData.getU32(&HashDataOffset); + for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects; + ++HashDataIdx) { + std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset); + auto Die = DCtx.getDIEForOffset(Offset); + if (!Die) { + const uint32_t BucketIdx = + NumBuckets ? (Hash % NumBuckets) : UINT32_MAX; + StringOffset = StrpOffset; + const char *Name = StrData->getCStr(&StringOffset); + if (!Name) + Name = "<NULL>"; + + error() << format( + "%s Bucket[%d] Hash[%d] = 0x%08x " + "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " " + "is not a valid DIE offset for \"%s\".\n", + SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset, + HashDataIdx, Offset, Name); + + ++NumErrors; + continue; + } + if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) { + error() << "Tag " << dwarf::TagString(Tag) + << " in accelerator table does not match Tag " + << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx + << "].\n"; + ++NumErrors; + } + } + ++StringCount; + } + } + return NumErrors; +} + +unsigned +DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) { + // A map from CU offset to the (first) Name Index offset which claims to index + // this CU. + DenseMap<uint64_t, uint64_t> CUMap; + const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max(); + + CUMap.reserve(DCtx.getNumCompileUnits()); + for (const auto &CU : DCtx.compile_units()) + CUMap[CU->getOffset()] = NotIndexed; + + unsigned NumErrors = 0; + for (const DWARFDebugNames::NameIndex &NI : AccelTable) { + if (NI.getCUCount() == 0) { + error() << formatv("Name Index @ {0:x} does not index any CU\n", + NI.getUnitOffset()); + ++NumErrors; + continue; + } + for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) { + uint64_t Offset = NI.getCUOffset(CU); + auto Iter = CUMap.find(Offset); + + if (Iter == CUMap.end()) { + error() << formatv( + "Name Index @ {0:x} references a non-existing CU @ {1:x}\n", + NI.getUnitOffset(), Offset); + ++NumErrors; + continue; + } + + if (Iter->second != NotIndexed) { + error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but " + "this CU is already indexed by Name Index @ {2:x}\n", + NI.getUnitOffset(), Offset, Iter->second); + continue; + } + Iter->second = NI.getUnitOffset(); + } + } + + for (const auto &KV : CUMap) { + if (KV.second == NotIndexed) + warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first); + } + + return NumErrors; +} + +unsigned +DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI, + const DataExtractor &StrData) { + struct BucketInfo { + uint32_t Bucket; + uint32_t Index; + + constexpr BucketInfo(uint32_t Bucket, uint32_t Index) + : Bucket(Bucket), Index(Index) {} + bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; } + }; + + uint32_t NumErrors = 0; + if (NI.getBucketCount() == 0) { + warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n", + NI.getUnitOffset()); + return NumErrors; + } + + // Build up a list of (Bucket, Index) pairs. We use this later to verify that + // each Name is reachable from the appropriate bucket. + std::vector<BucketInfo> BucketStarts; + BucketStarts.reserve(NI.getBucketCount() + 1); + for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) { + uint32_t Index = NI.getBucketArrayEntry(Bucket); + if (Index > NI.getNameCount()) { + error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid " + "value {2}. Valid range is [0, {3}].\n", + Bucket, NI.getUnitOffset(), Index, NI.getNameCount()); + ++NumErrors; + continue; + } + if (Index > 0) + BucketStarts.emplace_back(Bucket, Index); + } + + // If there were any buckets with invalid values, skip further checks as they + // will likely produce many errors which will only confuse the actual root + // problem. + if (NumErrors > 0) + return NumErrors; + + // Sort the list in the order of increasing "Index" entries. + array_pod_sort(BucketStarts.begin(), BucketStarts.end()); + + // Insert a sentinel entry at the end, so we can check that the end of the + // table is covered in the loop below. + BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1); + + // Loop invariant: NextUncovered is the (1-based) index of the first Name + // which is not reachable by any of the buckets we processed so far (and + // hasn't been reported as uncovered). + uint32_t NextUncovered = 1; + for (const BucketInfo &B : BucketStarts) { + // Under normal circumstances B.Index be equal to NextUncovered, but it can + // be less if a bucket points to names which are already known to be in some + // bucket we processed earlier. In that case, we won't trigger this error, + // but report the mismatched hash value error instead. (We know the hash + // will not match because we have already verified that the name's hash + // puts it into the previous bucket.) + if (B.Index > NextUncovered) { + error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] " + "are not covered by the hash table.\n", + NI.getUnitOffset(), NextUncovered, B.Index - 1); + ++NumErrors; + } + uint32_t Idx = B.Index; + + // The rest of the checks apply only to non-sentinel entries. + if (B.Bucket == NI.getBucketCount()) + break; + + // This triggers if a non-empty bucket points to a name with a mismatched + // hash. Clients are likely to interpret this as an empty bucket, because a + // mismatched hash signals the end of a bucket, but if this is indeed an + // empty bucket, the producer should have signalled this by marking the + // bucket as empty. + uint32_t FirstHash = NI.getHashArrayEntry(Idx); + if (FirstHash % NI.getBucketCount() != B.Bucket) { + error() << formatv( + "Name Index @ {0:x}: Bucket {1} is not empty but points to a " + "mismatched hash value {2:x} (belonging to bucket {3}).\n", + NI.getUnitOffset(), B.Bucket, FirstHash, + FirstHash % NI.getBucketCount()); + ++NumErrors; + } + + // This find the end of this bucket and also verifies that all the hashes in + // this bucket are correct by comparing the stored hashes to the ones we + // compute ourselves. + while (Idx <= NI.getNameCount()) { + uint32_t Hash = NI.getHashArrayEntry(Idx); + if (Hash % NI.getBucketCount() != B.Bucket) + break; + + const char *Str = NI.getNameTableEntry(Idx).getString(); + if (caseFoldingDjbHash(Str) != Hash) { + error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} " + "hashes to {3:x}, but " + "the Name Index hash is {4:x}\n", + NI.getUnitOffset(), Str, Idx, + caseFoldingDjbHash(Str), Hash); + ++NumErrors; + } + + ++Idx; + } + NextUncovered = std::max(NextUncovered, Idx); + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyNameIndexAttribute( + const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr, + DWARFDebugNames::AttributeEncoding AttrEnc) { + StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form); + if (FormName.empty()) { + error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " + "unknown form: {3}.\n", + NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, + AttrEnc.Form); + return 1; + } + + if (AttrEnc.Index == DW_IDX_type_hash) { + if (AttrEnc.Form != dwarf::DW_FORM_data8) { + error() << formatv( + "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash " + "uses an unexpected form {2} (should be {3}).\n", + NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8); + return 1; + } + } + + // A list of known index attributes and their expected form classes. + // DW_IDX_type_hash is handled specially in the check above, as it has a + // specific form (not just a form class) we should expect. + struct FormClassTable { + dwarf::Index Index; + DWARFFormValue::FormClass Class; + StringLiteral ClassName; + }; + static constexpr FormClassTable Table[] = { + {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}}, + {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}}, + {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}}, + {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}}, + }; + + ArrayRef<FormClassTable> TableRef(Table); + auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) { + return T.Index == AttrEnc.Index; + }); + if (Iter == TableRef.end()) { + warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an " + "unknown index attribute: {2}.\n", + NI.getUnitOffset(), Abbr.Code, AttrEnc.Index); + return 0; + } + + if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) { + error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an " + "unexpected form {3} (expected form class {4}).\n", + NI.getUnitOffset(), Abbr.Code, AttrEnc.Index, + AttrEnc.Form, Iter->ClassName); + return 1; + } + return 0; +} + +unsigned +DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) { + if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) { + warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is " + "not currently supported.\n", + NI.getUnitOffset()); + return 0; + } + + unsigned NumErrors = 0; + for (const auto &Abbrev : NI.getAbbrevs()) { + StringRef TagName = dwarf::TagString(Abbrev.Tag); + if (TagName.empty()) { + warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an " + "unknown tag: {2}.\n", + NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag); + } + SmallSet<unsigned, 5> Attributes; + for (const auto &AttrEnc : Abbrev.Attributes) { + if (!Attributes.insert(AttrEnc.Index).second) { + error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains " + "multiple {2} attributes.\n", + NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index); + ++NumErrors; + continue; + } + NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc); + } + + if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) { + error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units " + "and abbreviation {1:x} has no {2} attribute.\n", + NI.getUnitOffset(), Abbrev.Code, + dwarf::DW_IDX_compile_unit); + ++NumErrors; + } + if (!Attributes.count(dwarf::DW_IDX_die_offset)) { + error() << formatv( + "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n", + NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset); + ++NumErrors; + } + } + return NumErrors; +} + +static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE, + bool IncludeLinkageName = true) { + SmallVector<StringRef, 2> Result; + if (const char *Str = DIE.getName(DINameKind::ShortName)) + Result.emplace_back(Str); + else if (DIE.getTag() == dwarf::DW_TAG_namespace) + Result.emplace_back("(anonymous namespace)"); + + if (IncludeLinkageName) { + if (const char *Str = DIE.getName(DINameKind::LinkageName)) { + if (Result.empty() || Result[0] != Str) + Result.emplace_back(Str); + } + } + + return Result; +} + +unsigned DWARFVerifier::verifyNameIndexEntries( + const DWARFDebugNames::NameIndex &NI, + const DWARFDebugNames::NameTableEntry &NTE) { + // Verifying type unit indexes not supported. + if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) + return 0; + + const char *CStr = NTE.getString(); + if (!CStr) { + error() << formatv( + "Name Index @ {0:x}: Unable to get string associated with name {1}.\n", + NI.getUnitOffset(), NTE.getIndex()); + return 1; + } + StringRef Str(CStr); + + unsigned NumErrors = 0; + unsigned NumEntries = 0; + uint64_t EntryID = NTE.getEntryOffset(); + uint64_t NextEntryID = EntryID; + Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID); + for (; EntryOr; ++NumEntries, EntryID = NextEntryID, + EntryOr = NI.getEntry(&NextEntryID)) { + uint32_t CUIndex = *EntryOr->getCUIndex(); + if (CUIndex > NI.getCUCount()) { + error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an " + "invalid CU index ({2}).\n", + NI.getUnitOffset(), EntryID, CUIndex); + ++NumErrors; + continue; + } + uint64_t CUOffset = NI.getCUOffset(CUIndex); + uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset(); + DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset); + if (!DIE) { + error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a " + "non-existing DIE @ {2:x}.\n", + NI.getUnitOffset(), EntryID, DIEOffset); + ++NumErrors; + continue; + } + if (DIE.getDwarfUnit()->getOffset() != CUOffset) { + error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of " + "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n", + NI.getUnitOffset(), EntryID, DIEOffset, CUOffset, + DIE.getDwarfUnit()->getOffset()); + ++NumErrors; + } + if (DIE.getTag() != EntryOr->tag()) { + error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of " + "DIE @ {2:x}: index - {3}; debug_info - {4}.\n", + NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(), + DIE.getTag()); + ++NumErrors; + } + + auto EntryNames = getNames(DIE); + if (!is_contained(EntryNames, Str)) { + error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name " + "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n", + NI.getUnitOffset(), EntryID, DIEOffset, Str, + make_range(EntryNames.begin(), EntryNames.end())); + ++NumErrors; + } + } + handleAllErrors(EntryOr.takeError(), + [&](const DWARFDebugNames::SentinelError &) { + if (NumEntries > 0) + return; + error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is " + "not associated with any entries.\n", + NI.getUnitOffset(), NTE.getIndex(), Str); + ++NumErrors; + }, + [&](const ErrorInfoBase &Info) { + error() + << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n", + NI.getUnitOffset(), NTE.getIndex(), Str, + Info.message()); + ++NumErrors; + }); + return NumErrors; +} + +static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) { + Expected<std::vector<DWARFLocationExpression>> Loc = + Die.getLocations(DW_AT_location); + if (!Loc) { + consumeError(Loc.takeError()); + return false; + } + DWARFUnit *U = Die.getDwarfUnit(); + for (const auto &Entry : *Loc) { + DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), + U->getAddressByteSize()); + DWARFExpression Expression(Data, U->getAddressByteSize(), + U->getFormParams().Format); + bool IsInteresting = any_of(Expression, [](DWARFExpression::Operation &Op) { + return !Op.isError() && (Op.getCode() == DW_OP_addr || + Op.getCode() == DW_OP_form_tls_address || + Op.getCode() == DW_OP_GNU_push_tls_address); + }); + if (IsInteresting) + return true; + } + return false; +} + +unsigned DWARFVerifier::verifyNameIndexCompleteness( + const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) { + + // First check, if the Die should be indexed. The code follows the DWARF v5 + // wording as closely as possible. + + // "All non-defining declarations (that is, debugging information entries + // with a DW_AT_declaration attribute) are excluded." + if (Die.find(DW_AT_declaration)) + return 0; + + // "DW_TAG_namespace debugging information entries without a DW_AT_name + // attribute are included with the name “(anonymous namespace)”. + // All other debugging information entries without a DW_AT_name attribute + // are excluded." + // "If a subprogram or inlined subroutine is included, and has a + // DW_AT_linkage_name attribute, there will be an additional index entry for + // the linkage name." + auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram || + Die.getTag() == DW_TAG_inlined_subroutine; + auto EntryNames = getNames(Die, IncludeLinkageName); + if (EntryNames.empty()) + return 0; + + // We deviate from the specification here, which says: + // "The name index must contain an entry for each debugging information entry + // that defines a named subprogram, label, variable, type, or namespace, + // subject to ..." + // Explicitly exclude all TAGs that we know shouldn't be indexed. + switch (Die.getTag()) { + // Compile units and modules have names but shouldn't be indexed. + case DW_TAG_compile_unit: + case DW_TAG_module: + return 0; + + // Function and template parameters are not globally visible, so we shouldn't + // index them. + case DW_TAG_formal_parameter: + case DW_TAG_template_value_parameter: + case DW_TAG_template_type_parameter: + case DW_TAG_GNU_template_parameter_pack: + case DW_TAG_GNU_template_template_param: + return 0; + + // Object members aren't globally visible. + case DW_TAG_member: + return 0; + + // According to a strict reading of the specification, enumerators should not + // be indexed (and LLVM currently does not do that). However, this causes + // problems for the debuggers, so we may need to reconsider this. + case DW_TAG_enumerator: + return 0; + + // Imported declarations should not be indexed according to the specification + // and LLVM currently does not do that. + case DW_TAG_imported_declaration: + return 0; + + // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging + // information entries without an address attribute (DW_AT_low_pc, + // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded." + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_label: + if (Die.findRecursively( + {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc})) + break; + return 0; + + // "DW_TAG_variable debugging information entries with a DW_AT_location + // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are + // included; otherwise, they are excluded." + // + // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list. + case DW_TAG_variable: + if (isVariableIndexable(Die, DCtx)) + break; + return 0; + + default: + break; + } + + // Now we know that our Die should be present in the Index. Let's check if + // that's the case. + unsigned NumErrors = 0; + uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset(); + for (StringRef Name : EntryNames) { + if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) { + return E.getDIEUnitOffset() == DieUnitOffset; + })) { + error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with " + "name {3} missing.\n", + NI.getUnitOffset(), Die.getOffset(), Die.getTag(), + Name); + ++NumErrors; + } + } + return NumErrors; +} + +unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection, + const DataExtractor &StrData) { + unsigned NumErrors = 0; + DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection, + DCtx.isLittleEndian(), 0); + DWARFDebugNames AccelTable(AccelSectionData, StrData); + + OS << "Verifying .debug_names...\n"; + + // This verifies that we can read individual name indices and their + // abbreviation tables. + if (Error E = AccelTable.extract()) { + error() << toString(std::move(E)) << '\n'; + return 1; + } + + NumErrors += verifyDebugNamesCULists(AccelTable); + for (const auto &NI : AccelTable) + NumErrors += verifyNameIndexBuckets(NI, StrData); + for (const auto &NI : AccelTable) + NumErrors += verifyNameIndexAbbrevs(NI); + + // Don't attempt Entry validation if any of the previous checks found errors + if (NumErrors > 0) + return NumErrors; + for (const auto &NI : AccelTable) + for (DWARFDebugNames::NameTableEntry NTE : NI) + NumErrors += verifyNameIndexEntries(NI, NTE); + + if (NumErrors > 0) + return NumErrors; + + for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) { + if (const DWARFDebugNames::NameIndex *NI = + AccelTable.getCUNameIndex(U->getOffset())) { + auto *CU = cast<DWARFCompileUnit>(U.get()); + for (const DWARFDebugInfoEntry &Die : CU->dies()) + NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI); + } + } + return NumErrors; +} + +bool DWARFVerifier::handleAccelTables() { + const DWARFObject &D = DCtx.getDWARFObj(); + DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0); + unsigned NumErrors = 0; + if (!D.getAppleNamesSection().Data.empty()) + NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, + ".apple_names"); + if (!D.getAppleTypesSection().Data.empty()) + NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, + ".apple_types"); + if (!D.getAppleNamespacesSection().Data.empty()) + NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData, + ".apple_namespaces"); + if (!D.getAppleObjCSection().Data.empty()) + NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData, + ".apple_objc"); + + if (!D.getNamesSection().Data.empty()) + NumErrors += verifyDebugNames(D.getNamesSection(), StrData); + return NumErrors == 0; +} + +raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); } + +raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); } + +raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); } + +raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const { + Die.dump(OS, indent, DumpOpts); + return OS; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/DWARF/ya.make b/contrib/libs/llvm12/lib/DebugInfo/DWARF/ya.make index 5cb9397828..1b82e134b3 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/DWARF/ya.make +++ b/contrib/libs/llvm12/lib/DebugInfo/DWARF/ya.make @@ -1,61 +1,61 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/BinaryFormat contrib/libs/llvm12/lib/MC contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/DebugInfo/DWARF ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - DWARFAbbreviationDeclaration.cpp - DWARFAcceleratorTable.cpp - DWARFAddressRange.cpp - DWARFCompileUnit.cpp - DWARFContext.cpp - DWARFDataExtractor.cpp - DWARFDebugAbbrev.cpp - DWARFDebugAddr.cpp - DWARFDebugArangeSet.cpp - DWARFDebugAranges.cpp - DWARFDebugFrame.cpp - DWARFDebugInfoEntry.cpp - DWARFDebugLine.cpp - DWARFDebugLoc.cpp - DWARFDebugMacro.cpp - DWARFDebugPubTable.cpp - DWARFDebugRangeList.cpp - DWARFDebugRnglists.cpp - DWARFDie.cpp - DWARFExpression.cpp - DWARFFormValue.cpp - DWARFGdbIndex.cpp - DWARFListTable.cpp - DWARFLocationExpression.cpp - DWARFTypeUnit.cpp - DWARFUnit.cpp - DWARFUnitIndex.cpp - DWARFVerifier.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + DWARFAbbreviationDeclaration.cpp + DWARFAcceleratorTable.cpp + DWARFAddressRange.cpp + DWARFCompileUnit.cpp + DWARFContext.cpp + DWARFDataExtractor.cpp + DWARFDebugAbbrev.cpp + DWARFDebugAddr.cpp + DWARFDebugArangeSet.cpp + DWARFDebugAranges.cpp + DWARFDebugFrame.cpp + DWARFDebugInfoEntry.cpp + DWARFDebugLine.cpp + DWARFDebugLoc.cpp + DWARFDebugMacro.cpp + DWARFDebugPubTable.cpp + DWARFDebugRangeList.cpp + DWARFDebugRnglists.cpp + DWARFDie.cpp + DWARFExpression.cpp + DWARFFormValue.cpp + DWARFGdbIndex.cpp + DWARFListTable.cpp + DWARFLocationExpression.cpp + DWARFTypeUnit.cpp + DWARFUnit.cpp + DWARFUnitIndex.cpp + DWARFVerifier.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFBuilder.cpp index f946dd4860..c9d70d77ce 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -1,379 +1,379 @@ -//===- MSFBuilder.cpp -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> -#include <memory> -#include <utility> -#include <vector> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::support; - -static const uint32_t kSuperBlockBlock = 0; -static const uint32_t kFreePageMap0Block = 1; -static const uint32_t kFreePageMap1Block = 2; -static const uint32_t kNumReservedPages = 3; - -static const uint32_t kDefaultFreePageMap = kFreePageMap1Block; -static const uint32_t kDefaultBlockMapAddr = kNumReservedPages; - -MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, - BumpPtrAllocator &Allocator) - : Allocator(Allocator), IsGrowable(CanGrow), - FreePageMap(kDefaultFreePageMap), BlockSize(BlockSize), - BlockMapAddr(kDefaultBlockMapAddr), FreeBlocks(MinBlockCount, true) { - FreeBlocks[kSuperBlockBlock] = false; - FreeBlocks[kFreePageMap0Block] = false; - FreeBlocks[kFreePageMap1Block] = false; - FreeBlocks[BlockMapAddr] = false; -} - -Expected<MSFBuilder> MSFBuilder::create(BumpPtrAllocator &Allocator, - uint32_t BlockSize, - uint32_t MinBlockCount, bool CanGrow) { - if (!isValidBlockSize(BlockSize)) - return make_error<MSFError>(msf_error_code::invalid_format, - "The requested block size is unsupported"); - - return MSFBuilder(BlockSize, - std::max(MinBlockCount, msf::getMinimumBlockCount()), - CanGrow, Allocator); -} - -Error MSFBuilder::setBlockMapAddr(uint32_t Addr) { - if (Addr == BlockMapAddr) - return Error::success(); - - if (Addr >= FreeBlocks.size()) { - if (!IsGrowable) - return make_error<MSFError>(msf_error_code::insufficient_buffer, - "Cannot grow the number of blocks"); - FreeBlocks.resize(Addr + 1, true); - } - - if (!isBlockFree(Addr)) - 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::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } - -Error MSFBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) { - for (auto B : DirectoryBlocks) - FreeBlocks[B] = true; - for (auto B : DirBlocks) { - if (!isBlockFree(B)) { - return make_error<MSFError>(msf_error_code::unspecified, - "Attempt to reuse an allocated block"); - } - FreeBlocks[B] = false; - } - - DirectoryBlocks = DirBlocks; - return Error::success(); -} - -Error MSFBuilder::allocateBlocks(uint32_t NumBlocks, - MutableArrayRef<uint32_t> Blocks) { - if (NumBlocks == 0) - return Error::success(); - - uint32_t NumFreeBlocks = FreeBlocks.count(); - if (NumFreeBlocks < NumBlocks) { - if (!IsGrowable) - return make_error<MSFError>(msf_error_code::insufficient_buffer, - "There are no free Blocks in the file"); - uint32_t AllocBlocks = NumBlocks - NumFreeBlocks; - uint32_t OldBlockCount = FreeBlocks.size(); - uint32_t NewBlockCount = AllocBlocks + OldBlockCount; - uint32_t NextFpmBlock = alignTo(OldBlockCount, BlockSize) + 1; - FreeBlocks.resize(NewBlockCount, true); - // If we crossed over an fpm page, we actually need to allocate 2 extra - // blocks for each FPM group crossed and mark both blocks from the group as - // used. FPM blocks are marked as allocated regardless of whether or not - // they ultimately describe the status of blocks in the file. This means - // that not only are extraneous blocks at the end of the main FPM marked as - // allocated, but also blocks from the alternate FPM are always marked as - // allocated. - while (NextFpmBlock < NewBlockCount) { - NewBlockCount += 2; - FreeBlocks.resize(NewBlockCount, true); - FreeBlocks.reset(NextFpmBlock, NextFpmBlock + 2); - NextFpmBlock += BlockSize; - } - } - - int I = 0; - int Block = FreeBlocks.find_first(); - do { - assert(Block != -1 && "We ran out of Blocks!"); - - uint32_t NextBlock = static_cast<uint32_t>(Block); - Blocks[I++] = NextBlock; - FreeBlocks.reset(NextBlock); - Block = FreeBlocks.find_next(Block); - } while (--NumBlocks > 0); - return Error::success(); -} - -uint32_t MSFBuilder::getNumUsedBlocks() const { - return getTotalBlockCount() - getNumFreeBlocks(); -} - -uint32_t MSFBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } - -uint32_t MSFBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } - -bool MSFBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } - -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<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<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. - for (auto Block : Blocks) { - FreeBlocks.reset(Block); - } - StreamData.push_back(std::make_pair(Size, Blocks)); - return StreamData.size() - 1; -} - -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 std::move(EC); - StreamData.push_back(std::make_pair(Size, NewBlocks)); - return StreamData.size() - 1; -} - -Error MSFBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { - uint32_t OldSize = getStreamSize(Idx); - if (OldSize == Size) - return Error::success(); - - uint32_t NewBlocks = bytesToBlocks(Size, BlockSize); - uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize); - - if (NewBlocks > OldBlocks) { - uint32_t AddedBlocks = NewBlocks - OldBlocks; - // If we're growing, we have to allocate new Blocks. - std::vector<uint32_t> AddedBlockList; - AddedBlockList.resize(AddedBlocks); - if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList)) - return EC; - auto &CurrentBlocks = StreamData[Idx].second; +//===- MSFBuilder.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <memory> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; + +static const uint32_t kSuperBlockBlock = 0; +static const uint32_t kFreePageMap0Block = 1; +static const uint32_t kFreePageMap1Block = 2; +static const uint32_t kNumReservedPages = 3; + +static const uint32_t kDefaultFreePageMap = kFreePageMap1Block; +static const uint32_t kDefaultBlockMapAddr = kNumReservedPages; + +MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, + BumpPtrAllocator &Allocator) + : Allocator(Allocator), IsGrowable(CanGrow), + FreePageMap(kDefaultFreePageMap), BlockSize(BlockSize), + BlockMapAddr(kDefaultBlockMapAddr), FreeBlocks(MinBlockCount, true) { + FreeBlocks[kSuperBlockBlock] = false; + FreeBlocks[kFreePageMap0Block] = false; + FreeBlocks[kFreePageMap1Block] = false; + FreeBlocks[BlockMapAddr] = false; +} + +Expected<MSFBuilder> MSFBuilder::create(BumpPtrAllocator &Allocator, + uint32_t BlockSize, + uint32_t MinBlockCount, bool CanGrow) { + if (!isValidBlockSize(BlockSize)) + return make_error<MSFError>(msf_error_code::invalid_format, + "The requested block size is unsupported"); + + return MSFBuilder(BlockSize, + std::max(MinBlockCount, msf::getMinimumBlockCount()), + CanGrow, Allocator); +} + +Error MSFBuilder::setBlockMapAddr(uint32_t Addr) { + if (Addr == BlockMapAddr) + return Error::success(); + + if (Addr >= FreeBlocks.size()) { + if (!IsGrowable) + return make_error<MSFError>(msf_error_code::insufficient_buffer, + "Cannot grow the number of blocks"); + FreeBlocks.resize(Addr + 1, true); + } + + if (!isBlockFree(Addr)) + 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::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } + +Error MSFBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) { + for (auto B : DirectoryBlocks) + FreeBlocks[B] = true; + for (auto B : DirBlocks) { + if (!isBlockFree(B)) { + return make_error<MSFError>(msf_error_code::unspecified, + "Attempt to reuse an allocated block"); + } + FreeBlocks[B] = false; + } + + DirectoryBlocks = DirBlocks; + return Error::success(); +} + +Error MSFBuilder::allocateBlocks(uint32_t NumBlocks, + MutableArrayRef<uint32_t> Blocks) { + if (NumBlocks == 0) + return Error::success(); + + uint32_t NumFreeBlocks = FreeBlocks.count(); + if (NumFreeBlocks < NumBlocks) { + if (!IsGrowable) + return make_error<MSFError>(msf_error_code::insufficient_buffer, + "There are no free Blocks in the file"); + uint32_t AllocBlocks = NumBlocks - NumFreeBlocks; + uint32_t OldBlockCount = FreeBlocks.size(); + uint32_t NewBlockCount = AllocBlocks + OldBlockCount; + uint32_t NextFpmBlock = alignTo(OldBlockCount, BlockSize) + 1; + FreeBlocks.resize(NewBlockCount, true); + // If we crossed over an fpm page, we actually need to allocate 2 extra + // blocks for each FPM group crossed and mark both blocks from the group as + // used. FPM blocks are marked as allocated regardless of whether or not + // they ultimately describe the status of blocks in the file. This means + // that not only are extraneous blocks at the end of the main FPM marked as + // allocated, but also blocks from the alternate FPM are always marked as + // allocated. + while (NextFpmBlock < NewBlockCount) { + NewBlockCount += 2; + FreeBlocks.resize(NewBlockCount, true); + FreeBlocks.reset(NextFpmBlock, NextFpmBlock + 2); + NextFpmBlock += BlockSize; + } + } + + int I = 0; + int Block = FreeBlocks.find_first(); + do { + assert(Block != -1 && "We ran out of Blocks!"); + + uint32_t NextBlock = static_cast<uint32_t>(Block); + Blocks[I++] = NextBlock; + FreeBlocks.reset(NextBlock); + Block = FreeBlocks.find_next(Block); + } while (--NumBlocks > 0); + return Error::success(); +} + +uint32_t MSFBuilder::getNumUsedBlocks() const { + return getTotalBlockCount() - getNumFreeBlocks(); +} + +uint32_t MSFBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } + +uint32_t MSFBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } + +bool MSFBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } + +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<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<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. + for (auto Block : Blocks) { + FreeBlocks.reset(Block); + } + StreamData.push_back(std::make_pair(Size, Blocks)); + return StreamData.size() - 1; +} + +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 std::move(EC); + StreamData.push_back(std::make_pair(Size, NewBlocks)); + return StreamData.size() - 1; +} + +Error MSFBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { + uint32_t OldSize = getStreamSize(Idx); + if (OldSize == Size) + return Error::success(); + + uint32_t NewBlocks = bytesToBlocks(Size, BlockSize); + uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize); + + if (NewBlocks > OldBlocks) { + uint32_t AddedBlocks = NewBlocks - OldBlocks; + // If we're growing, we have to allocate new Blocks. + std::vector<uint32_t> AddedBlockList; + AddedBlockList.resize(AddedBlocks); + if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList)) + return EC; + auto &CurrentBlocks = StreamData[Idx].second; llvm::append_range(CurrentBlocks, AddedBlockList); - } else if (OldBlocks > NewBlocks) { - // For shrinking, free all the Blocks in the Block map, update the stream - // data, then shrink the directory. - uint32_t RemovedBlocks = OldBlocks - NewBlocks; - auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second); - auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks); - for (auto P : RemovedBlockList) - FreeBlocks[P] = true; - StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks); - } - - StreamData[Idx].first = Size; - return Error::success(); -} - -uint32_t MSFBuilder::getNumStreams() const { return StreamData.size(); } - -uint32_t MSFBuilder::getStreamSize(uint32_t StreamIdx) const { - return StreamData[StreamIdx].first; -} - -ArrayRef<uint32_t> MSFBuilder::getStreamBlocks(uint32_t StreamIdx) const { - return StreamData[StreamIdx].second; -} - -uint32_t MSFBuilder::computeDirectoryByteSize() const { - // The directory has the following layout, where each item is a ulittle32_t: - // NumStreams - // StreamSizes[NumStreams] - // StreamBlocks[NumStreams][] - uint32_t Size = sizeof(ulittle32_t); // NumStreams - Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes - for (const auto &D : StreamData) { - uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize); - assert(ExpectedNumBlocks == D.second.size() && - "Unexpected number of blocks"); - Size += ExpectedNumBlocks * sizeof(ulittle32_t); - } - return Size; -} - -Expected<MSFLayout> MSFBuilder::generateLayout() { - 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. - std::vector<uint32_t> ExtraBlocks; - uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size(); - ExtraBlocks.resize(NumExtraBlocks); - if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks)) - return std::move(EC); + } else if (OldBlocks > NewBlocks) { + // For shrinking, free all the Blocks in the Block map, update the stream + // data, then shrink the directory. + uint32_t RemovedBlocks = OldBlocks - NewBlocks; + auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second); + auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks); + for (auto P : RemovedBlockList) + FreeBlocks[P] = true; + StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks); + } + + StreamData[Idx].first = Size; + return Error::success(); +} + +uint32_t MSFBuilder::getNumStreams() const { return StreamData.size(); } + +uint32_t MSFBuilder::getStreamSize(uint32_t StreamIdx) const { + return StreamData[StreamIdx].first; +} + +ArrayRef<uint32_t> MSFBuilder::getStreamBlocks(uint32_t StreamIdx) const { + return StreamData[StreamIdx].second; +} + +uint32_t MSFBuilder::computeDirectoryByteSize() const { + // The directory has the following layout, where each item is a ulittle32_t: + // NumStreams + // StreamSizes[NumStreams] + // StreamBlocks[NumStreams][] + uint32_t Size = sizeof(ulittle32_t); // NumStreams + Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes + for (const auto &D : StreamData) { + uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize); + assert(ExpectedNumBlocks == D.second.size() && + "Unexpected number of blocks"); + Size += ExpectedNumBlocks * sizeof(ulittle32_t); + } + return Size; +} + +Expected<MSFLayout> MSFBuilder::generateLayout() { + 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. + std::vector<uint32_t> ExtraBlocks; + uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size(); + ExtraBlocks.resize(NumExtraBlocks); + if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks)) + return std::move(EC); llvm::append_range(DirectoryBlocks, ExtraBlocks); - } else if (NumDirectoryBlocks < DirectoryBlocks.size()) { - uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks; - for (auto B : - ArrayRef<uint32_t>(DirectoryBlocks).drop_back(NumUnnecessaryBlocks)) - FreeBlocks[B] = true; - DirectoryBlocks.resize(NumDirectoryBlocks); - } - - // 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. - SB->NumBlocks = FreeBlocks.size(); - - ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks); - std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, - DirBlocks); - L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks, NumDirectoryBlocks); - - // The stream sizes should be re-allocated as a stable pointer and the stream - // map should have each of its entries allocated as a separate stable pointer. - if (!StreamData.empty()) { - ulittle32_t *Sizes = Allocator.Allocate<ulittle32_t>(StreamData.size()); - L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size()); - L.StreamMap.resize(StreamData.size()); - for (uint32_t I = 0; I < StreamData.size(); ++I) { - Sizes[I] = StreamData[I].first; - ulittle32_t *BlockList = - Allocator.Allocate<ulittle32_t>(StreamData[I].second.size()); - std::uninitialized_copy_n(StreamData[I].second.begin(), - StreamData[I].second.size(), BlockList); - L.StreamMap[I] = - ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size()); - } - } - - L.FreePageMap = FreeBlocks; - - return L; -} - -static void commitFpm(WritableBinaryStream &MsfBuffer, const MSFLayout &Layout, - BumpPtrAllocator &Allocator) { - auto FpmStream = - WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); - - // We only need to create the alt fpm stream so that it gets initialized. - WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, - true); - - uint32_t BI = 0; - BinaryStreamWriter FpmWriter(*FpmStream); - while (BI < Layout.SB->NumBlocks) { - uint8_t ThisByte = 0; - for (uint32_t I = 0; I < 8; ++I) { - bool IsFree = - (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; - uint8_t Mask = uint8_t(IsFree) << I; - ThisByte |= Mask; - ++BI; - } - cantFail(FpmWriter.writeObject(ThisByte)); - } - assert(FpmWriter.bytesRemaining() == 0); -} - -Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path, - MSFLayout &Layout) { - Expected<MSFLayout> L = generateLayout(); - if (!L) - return L.takeError(); - - Layout = std::move(*L); - - uint64_t FileSize = Layout.SB->BlockSize * Layout.SB->NumBlocks; - auto OutFileOrError = FileOutputBuffer::create(Path, FileSize); - if (auto EC = OutFileOrError.takeError()) - return std::move(EC); - - FileBufferByteStream Buffer(std::move(*OutFileOrError), - llvm::support::little); - BinaryStreamWriter Writer(Buffer); - - if (auto EC = Writer.writeObject(*Layout.SB)) - return std::move(EC); - - commitFpm(Buffer, Layout, Allocator); - - uint32_t BlockMapOffset = - msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); - Writer.setOffset(BlockMapOffset); - if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) - return std::move(EC); - - auto DirStream = WritableMappedBlockStream::createDirectoryStream( - Layout, Buffer, Allocator); - BinaryStreamWriter DW(*DirStream); - if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) - return std::move(EC); - - if (auto EC = DW.writeArray(Layout.StreamSizes)) - return std::move(EC); - - for (const auto &Blocks : Layout.StreamMap) { - if (auto EC = DW.writeArray(Blocks)) - return std::move(EC); - } - - return std::move(Buffer); -} + } else if (NumDirectoryBlocks < DirectoryBlocks.size()) { + uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks; + for (auto B : + ArrayRef<uint32_t>(DirectoryBlocks).drop_back(NumUnnecessaryBlocks)) + FreeBlocks[B] = true; + DirectoryBlocks.resize(NumDirectoryBlocks); + } + + // 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. + SB->NumBlocks = FreeBlocks.size(); + + ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks); + std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, + DirBlocks); + L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks, NumDirectoryBlocks); + + // The stream sizes should be re-allocated as a stable pointer and the stream + // map should have each of its entries allocated as a separate stable pointer. + if (!StreamData.empty()) { + ulittle32_t *Sizes = Allocator.Allocate<ulittle32_t>(StreamData.size()); + L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size()); + L.StreamMap.resize(StreamData.size()); + for (uint32_t I = 0; I < StreamData.size(); ++I) { + Sizes[I] = StreamData[I].first; + ulittle32_t *BlockList = + Allocator.Allocate<ulittle32_t>(StreamData[I].second.size()); + std::uninitialized_copy_n(StreamData[I].second.begin(), + StreamData[I].second.size(), BlockList); + L.StreamMap[I] = + ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size()); + } + } + + L.FreePageMap = FreeBlocks; + + return L; +} + +static void commitFpm(WritableBinaryStream &MsfBuffer, const MSFLayout &Layout, + BumpPtrAllocator &Allocator) { + auto FpmStream = + WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); + + // We only need to create the alt fpm stream so that it gets initialized. + WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, + true); + + uint32_t BI = 0; + BinaryStreamWriter FpmWriter(*FpmStream); + while (BI < Layout.SB->NumBlocks) { + uint8_t ThisByte = 0; + for (uint32_t I = 0; I < 8; ++I) { + bool IsFree = + (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; + uint8_t Mask = uint8_t(IsFree) << I; + ThisByte |= Mask; + ++BI; + } + cantFail(FpmWriter.writeObject(ThisByte)); + } + assert(FpmWriter.bytesRemaining() == 0); +} + +Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path, + MSFLayout &Layout) { + Expected<MSFLayout> L = generateLayout(); + if (!L) + return L.takeError(); + + Layout = std::move(*L); + + uint64_t FileSize = Layout.SB->BlockSize * Layout.SB->NumBlocks; + auto OutFileOrError = FileOutputBuffer::create(Path, FileSize); + if (auto EC = OutFileOrError.takeError()) + return std::move(EC); + + FileBufferByteStream Buffer(std::move(*OutFileOrError), + llvm::support::little); + BinaryStreamWriter Writer(Buffer); + + if (auto EC = Writer.writeObject(*Layout.SB)) + return std::move(EC); + + commitFpm(Buffer, Layout, Allocator); + + uint32_t BlockMapOffset = + msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); + Writer.setOffset(BlockMapOffset); + if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) + return std::move(EC); + + auto DirStream = WritableMappedBlockStream::createDirectoryStream( + Layout, Buffer, Allocator); + BinaryStreamWriter DW(*DirStream); + if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) + return std::move(EC); + + if (auto EC = DW.writeArray(Layout.StreamSizes)) + return std::move(EC); + + for (const auto &Blocks : Layout.StreamMap) { + if (auto EC = DW.writeArray(Blocks)) + return std::move(EC); + } + + return std::move(Buffer); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFCommon.cpp b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFCommon.cpp index fb4f070005..52b6bdc320 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFCommon.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFCommon.cpp @@ -1,82 +1,82 @@ -//===- MSFCommon.cpp - Common types and functions for MSF files -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <cstdint> -#include <cstring> - -using namespace llvm; -using namespace llvm::msf; - -Error llvm::msf::validateSuperBlock(const SuperBlock &SB) { - // Check the magic bytes. - if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0) - return make_error<MSFError>(msf_error_code::invalid_format, - "MSF magic header doesn't match"); - - if (!isValidBlockSize(SB.BlockSize)) - 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<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 - // the number of bytes it contains. - uint64_t NumDirectoryBlocks = - bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize); - - // The directory, as we understand it, is a block which consists of a list of - // 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<MSFError>(msf_error_code::invalid_format, - "Too many directory blocks."); - - if (SB.BlockMapAddr == 0) - 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(); -} - -MSFStreamLayout llvm::msf::getFpmStreamLayout(const MSFLayout &Msf, - bool IncludeUnusedFpmData, - bool AltFpm) { - MSFStreamLayout FL; - uint32_t NumFpmIntervals = - getNumFpmIntervals(Msf, IncludeUnusedFpmData, AltFpm); - - uint32_t FpmBlock = AltFpm ? Msf.alternateFpmBlock() : Msf.mainFpmBlock(); - - for (uint32_t I = 0; I < NumFpmIntervals; ++I) { - FL.Blocks.push_back(support::ulittle32_t(FpmBlock)); - FpmBlock += msf::getFpmIntervalLength(Msf); - } - - if (IncludeUnusedFpmData) - FL.Length = NumFpmIntervals * Msf.SB->BlockSize; - else - FL.Length = divideCeil(Msf.SB->NumBlocks, 8); - - return FL; -} +//===- MSFCommon.cpp - Common types and functions for MSF files -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> +#include <cstring> + +using namespace llvm; +using namespace llvm::msf; + +Error llvm::msf::validateSuperBlock(const SuperBlock &SB) { + // Check the magic bytes. + if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0) + return make_error<MSFError>(msf_error_code::invalid_format, + "MSF magic header doesn't match"); + + if (!isValidBlockSize(SB.BlockSize)) + 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<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 + // the number of bytes it contains. + uint64_t NumDirectoryBlocks = + bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize); + + // The directory, as we understand it, is a block which consists of a list of + // 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<MSFError>(msf_error_code::invalid_format, + "Too many directory blocks."); + + if (SB.BlockMapAddr == 0) + 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(); +} + +MSFStreamLayout llvm::msf::getFpmStreamLayout(const MSFLayout &Msf, + bool IncludeUnusedFpmData, + bool AltFpm) { + MSFStreamLayout FL; + uint32_t NumFpmIntervals = + getNumFpmIntervals(Msf, IncludeUnusedFpmData, AltFpm); + + uint32_t FpmBlock = AltFpm ? Msf.alternateFpmBlock() : Msf.mainFpmBlock(); + + for (uint32_t I = 0; I < NumFpmIntervals; ++I) { + FL.Blocks.push_back(support::ulittle32_t(FpmBlock)); + FpmBlock += msf::getFpmIntervalLength(Msf); + } + + if (IncludeUnusedFpmData) + FL.Length = NumFpmIntervals * Msf.SB->BlockSize; + else + FL.Length = divideCeil(Msf.SB->NumBlocks, 8); + + return FL; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFError.cpp b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFError.cpp index b368b802c5..d58721110f 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFError.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/MSF/MSFError.cpp @@ -1,47 +1,47 @@ -//===- MSFError.cpp - Error extensions for MSF files ------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#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"); - } -}; -} // namespace - -static llvm::ManagedStatic<MSFErrorCategory> MSFCategory; -const std::error_category &llvm::msf::MSFErrCategory() { return *MSFCategory; } - -char MSFError::ID; +//===- MSFError.cpp - Error extensions for MSF files ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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"); + } +}; +} // namespace + +static llvm::ManagedStatic<MSFErrorCategory> MSFCategory; +const std::error_category &llvm::msf::MSFErrCategory() { return *MSFCategory; } + +char MSFError::ID; diff --git a/contrib/libs/llvm12/lib/DebugInfo/MSF/MappedBlockStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/MSF/MappedBlockStream.cpp index 5dc9c86b34..aa831ce327 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -1,421 +1,421 @@ -//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <cstring> -#include <utility> -#include <vector> - -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)...) {} -}; - -} // end anonymous namespace - -using Interval = std::pair<uint32_t, uint32_t>; - -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, - const MSFStreamLayout &Layout, - BinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) - : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData), - Allocator(Allocator) {} - -std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream( - uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) { - return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( - BlockSize, Layout, MsfData, Allocator); -} - -std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream( - const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex, - BumpPtrAllocator &Allocator) { - assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); - MSFStreamLayout SL; - SL.Blocks = Layout.StreamMap[StreamIndex]; - SL.Length = Layout.StreamSizes[StreamIndex]; - return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( - Layout.SB->BlockSize, SL, MsfData, Allocator); -} - -std::unique_ptr<MappedBlockStream> -MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, - BinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) { - MSFStreamLayout SL; - SL.Blocks = Layout.DirectoryBlocks; - SL.Length = Layout.SB->NumDirectoryBytes; - return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); -} - -std::unique_ptr<MappedBlockStream> -MappedBlockStream::createFpmStream(const MSFLayout &Layout, - BinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) { - MSFStreamLayout SL(getFpmStreamLayout(Layout)); - return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); -} - -Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) { - // Make sure we aren't trying to read beyond the end of the stream. - if (auto EC = checkOffsetForRead(Offset, Size)) - return EC; - - 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 *>(Allocator.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) { - // Make sure we aren't trying to read beyond the end of the stream. - if (auto EC = checkOffsetForRead(Offset, 1)) - return EC; - - uint32_t First = Offset / BlockSize; - uint32_t Last = First; - - while (Last < getNumBlocks() - 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() { return StreamLayout.Length; } - -bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) { - 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 = - 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) { - 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 (auto EC = checkOffsetForRead(Offset, Buffer.size())) - return EC; - - 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(); -} - -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, const MSFStreamLayout &Layout, - WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator) - : ReadInterface(BlockSize, Layout, MsfData, Allocator), - WriteInterface(MsfData) {} - -std::unique_ptr<WritableMappedBlockStream> -WritableMappedBlockStream::createStream(uint32_t BlockSize, - const MSFStreamLayout &Layout, - WritableBinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) { - return std::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>( - BlockSize, Layout, MsfData, Allocator); -} - -std::unique_ptr<WritableMappedBlockStream> -WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, - WritableBinaryStreamRef MsfData, - uint32_t StreamIndex, - BumpPtrAllocator &Allocator) { - 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, SL, MsfData, Allocator); -} - -std::unique_ptr<WritableMappedBlockStream> -WritableMappedBlockStream::createDirectoryStream( - const MSFLayout &Layout, WritableBinaryStreamRef MsfData, - BumpPtrAllocator &Allocator) { - MSFStreamLayout SL; - SL.Blocks = Layout.DirectoryBlocks; - SL.Length = Layout.SB->NumDirectoryBytes; - return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); -} - -std::unique_ptr<WritableMappedBlockStream> -WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, - WritableBinaryStreamRef MsfData, - BumpPtrAllocator &Allocator, - bool AltFpm) { - // We only want to give the user a stream containing the bytes of the FPM that - // are actually valid, but we want to initialize all of the bytes, even those - // that come from reserved FPM blocks where the entire block is unused. To do - // this, we first create the full layout, which gives us a stream with all - // bytes and all blocks, and initialize everything to 0xFF (all blocks in the - // file are unused). Then we create the minimal layout (which contains only a - // subset of the bytes previously initialized), and return that to the user. - MSFStreamLayout MinLayout(getFpmStreamLayout(Layout, false, AltFpm)); - - MSFStreamLayout FullLayout(getFpmStreamLayout(Layout, true, AltFpm)); - auto Result = - createStream(Layout.SB->BlockSize, FullLayout, MsfData, Allocator); - if (!Result) - return Result; - std::vector<uint8_t> InitData(Layout.SB->BlockSize, 0xFF); - BinaryStreamWriter Initializer(*Result); - while (Initializer.bytesRemaining() > 0) - cantFail(Initializer.writeBytes(InitData)); - return createStream(Layout.SB->BlockSize, MinLayout, MsfData, Allocator); -} - -Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef<uint8_t> &Buffer) { - return ReadInterface.readBytes(Offset, Size, Buffer); -} - -Error WritableMappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef<uint8_t> &Buffer) { - return ReadInterface.readLongestContiguousChunk(Offset, Buffer); -} - -uint32_t WritableMappedBlockStream::getLength() { - return ReadInterface.getLength(); -} - -Error WritableMappedBlockStream::writeBytes(uint32_t Offset, - ArrayRef<uint8_t> Buffer) { - // Make sure we aren't trying to write beyond the end of the stream. - if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) - return EC; - - 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() { return WriteInterface.commit(); } +//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <cstring> +#include <utility> +#include <vector> + +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)...) {} +}; + +} // end anonymous namespace + +using Interval = std::pair<uint32_t, uint32_t>; + +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, + const MSFStreamLayout &Layout, + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) + : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData), + Allocator(Allocator) {} + +std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream( + uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { + return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( + BlockSize, Layout, MsfData, Allocator); +} + +std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream( + const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex, + BumpPtrAllocator &Allocator) { + assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); + MSFStreamLayout SL; + SL.Blocks = Layout.StreamMap[StreamIndex]; + SL.Length = Layout.StreamSizes[StreamIndex]; + return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( + Layout.SB->BlockSize, SL, MsfData, Allocator); +} + +std::unique_ptr<MappedBlockStream> +MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { + MSFStreamLayout SL; + SL.Blocks = Layout.DirectoryBlocks; + SL.Length = Layout.SB->NumDirectoryBytes; + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); +} + +std::unique_ptr<MappedBlockStream> +MappedBlockStream::createFpmStream(const MSFLayout &Layout, + BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { + MSFStreamLayout SL(getFpmStreamLayout(Layout)); + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); +} + +Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) { + // Make sure we aren't trying to read beyond the end of the stream. + if (auto EC = checkOffsetForRead(Offset, Size)) + return EC; + + 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 *>(Allocator.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) { + // Make sure we aren't trying to read beyond the end of the stream. + if (auto EC = checkOffsetForRead(Offset, 1)) + return EC; + + uint32_t First = Offset / BlockSize; + uint32_t Last = First; + + while (Last < getNumBlocks() - 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() { return StreamLayout.Length; } + +bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) { + 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 = + 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) { + 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 (auto EC = checkOffsetForRead(Offset, Buffer.size())) + return EC; + + 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(); +} + +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, const MSFStreamLayout &Layout, + WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator) + : ReadInterface(BlockSize, Layout, MsfData, Allocator), + WriteInterface(MsfData) {} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createStream(uint32_t BlockSize, + const MSFStreamLayout &Layout, + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { + return std::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>( + BlockSize, Layout, MsfData, Allocator); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, + WritableBinaryStreamRef MsfData, + uint32_t StreamIndex, + BumpPtrAllocator &Allocator) { + 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, SL, MsfData, Allocator); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createDirectoryStream( + const MSFLayout &Layout, WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator) { + MSFStreamLayout SL; + SL.Blocks = Layout.DirectoryBlocks; + SL.Length = Layout.SB->NumDirectoryBytes; + return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); +} + +std::unique_ptr<WritableMappedBlockStream> +WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator, + bool AltFpm) { + // We only want to give the user a stream containing the bytes of the FPM that + // are actually valid, but we want to initialize all of the bytes, even those + // that come from reserved FPM blocks where the entire block is unused. To do + // this, we first create the full layout, which gives us a stream with all + // bytes and all blocks, and initialize everything to 0xFF (all blocks in the + // file are unused). Then we create the minimal layout (which contains only a + // subset of the bytes previously initialized), and return that to the user. + MSFStreamLayout MinLayout(getFpmStreamLayout(Layout, false, AltFpm)); + + MSFStreamLayout FullLayout(getFpmStreamLayout(Layout, true, AltFpm)); + auto Result = + createStream(Layout.SB->BlockSize, FullLayout, MsfData, Allocator); + if (!Result) + return Result; + std::vector<uint8_t> InitData(Layout.SB->BlockSize, 0xFF); + BinaryStreamWriter Initializer(*Result); + while (Initializer.bytesRemaining() > 0) + cantFail(Initializer.writeBytes(InitData)); + return createStream(Layout.SB->BlockSize, MinLayout, MsfData, Allocator); +} + +Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) { + return ReadInterface.readBytes(Offset, Size, Buffer); +} + +Error WritableMappedBlockStream::readLongestContiguousChunk( + uint32_t Offset, ArrayRef<uint8_t> &Buffer) { + return ReadInterface.readLongestContiguousChunk(Offset, Buffer); +} + +uint32_t WritableMappedBlockStream::getLength() { + return ReadInterface.getLength(); +} + +Error WritableMappedBlockStream::writeBytes(uint32_t Offset, + ArrayRef<uint8_t> Buffer) { + // Make sure we aren't trying to write beyond the end of the stream. + if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) + return EC; + + 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() { return WriteInterface.commit(); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/MSF/ya.make b/contrib/libs/llvm12/lib/DebugInfo/MSF/ya.make index a9daa7d1aa..49655ced98 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/MSF/ya.make +++ b/contrib/libs/llvm12/lib/DebugInfo/MSF/ya.make @@ -1,34 +1,34 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/DebugInfo/MSF ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - MSFBuilder.cpp - MSFCommon.cpp - MSFError.cpp - MappedBlockStream.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + MSFBuilder.cpp + MSFCommon.cpp + MSFError.cpp + MappedBlockStream.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/GenericError.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/GenericError.cpp index 0e4cba3174..623fd9f66e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/GenericError.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/GenericError.cpp @@ -1,48 +1,48 @@ -//===- Error.cpp - system_error extensions for PDB --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/GenericError.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" - -using namespace llvm; -using namespace llvm::pdb; - -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 PDBErrorCategory : public std::error_category { -public: - const char *name() const noexcept override { return "llvm.pdb"; } - std::string message(int Condition) const override { - switch (static_cast<pdb_error_code>(Condition)) { - case pdb_error_code::unspecified: - return "An unknown error has occurred."; - case pdb_error_code::dia_sdk_not_present: - return "LLVM was not compiled with support for DIA. This usually means " - "that you are not using MSVC, or your Visual Studio " - "installation is corrupt."; - case pdb_error_code::dia_failed_loading: - return "DIA is only supported when using MSVC."; - case pdb_error_code::invalid_utf8_path: - return "The PDB file path is an invalid UTF8 sequence."; - case pdb_error_code::signature_out_of_date: - return "The signature does not match; the file(s) might be out of date."; - case pdb_error_code::no_matching_pch: - return "No matching precompiled header could be located."; - } - llvm_unreachable("Unrecognized generic_error_code"); - } -}; -} // namespace - -static llvm::ManagedStatic<PDBErrorCategory> PDBCategory; -const std::error_category &llvm::pdb::PDBErrCategory() { return *PDBCategory; } - -char PDBError::ID; +//===- Error.cpp - system_error extensions for PDB --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +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 PDBErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.pdb"; } + std::string message(int Condition) const override { + switch (static_cast<pdb_error_code>(Condition)) { + case pdb_error_code::unspecified: + return "An unknown error has occurred."; + case pdb_error_code::dia_sdk_not_present: + return "LLVM was not compiled with support for DIA. This usually means " + "that you are not using MSVC, or your Visual Studio " + "installation is corrupt."; + case pdb_error_code::dia_failed_loading: + return "DIA is only supported when using MSVC."; + case pdb_error_code::invalid_utf8_path: + return "The PDB file path is an invalid UTF8 sequence."; + case pdb_error_code::signature_out_of_date: + return "The signature does not match; the file(s) might be out of date."; + case pdb_error_code::no_matching_pch: + return "No matching precompiled header could be located."; + } + llvm_unreachable("Unrecognized generic_error_code"); + } +}; +} // namespace + +static llvm::ManagedStatic<PDBErrorCategory> PDBCategory; +const std::error_category &llvm::pdb::PDBErrCategory() { return *PDBCategory; } + +char PDBError::ID; diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/IPDBSourceFile.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/IPDBSourceFile.cpp index 113ee04bab..c92bbd4044 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/IPDBSourceFile.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/IPDBSourceFile.cpp @@ -1,34 +1,34 @@ -//===- IPDBSourceFile.cpp - base interface for a PDB source file ----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#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() = default; - -void IPDBSourceFile::dump(raw_ostream &OS, int Indent) const { - OS.indent(Indent); - PDB_Checksum ChecksumType = getChecksumType(); - OS << "["; - if (ChecksumType != PDB_Checksum::None) { - OS << ChecksumType << ": "; - std::string Checksum = getChecksum(); - for (uint8_t c : Checksum) - OS << format_hex_no_prefix(c, 2, true); - } else - OS << "No checksum"; - OS << "] " << getFileName() << "\n"; -} +//===- IPDBSourceFile.cpp - base interface for a PDB source file ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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() = default; + +void IPDBSourceFile::dump(raw_ostream &OS, int Indent) const { + OS.indent(Indent); + PDB_Checksum ChecksumType = getChecksumType(); + OS << "["; + if (ChecksumType != PDB_Checksum::None) { + OS << ChecksumType << ": "; + std::string Checksum = getChecksum(); + for (uint8_t c : Checksum) + OS << format_hex_no_prefix(c, 2, true); + } else + OS << "No checksum"; + OS << "] " << getFileName() << "\n"; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp index 9755f2ca3b..7b8cb308a8 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp @@ -1,86 +1,86 @@ -//===- DbiModuleDescriptor.cpp - PDB module information -------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <cstdint> - -using namespace llvm; -using namespace llvm::pdb; -using namespace llvm::support; - -Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream, - DbiModuleDescriptor &Info) { - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readObject(Info.Layout)) - return EC; - - if (auto EC = Reader.readCString(Info.ModuleName)) - return EC; - - if (auto EC = Reader.readCString(Info.ObjFileName)) - return EC; - return Error::success(); -} - -bool DbiModuleDescriptor::hasECInfo() const { - return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0; -} - -uint16_t DbiModuleDescriptor::getTypeServerIndex() const { - return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >> - ModInfoFlags::TypeServerIndexShift; -} - -const SectionContrib &DbiModuleDescriptor::getSectionContrib() const { - return Layout->SC; -} - -uint16_t DbiModuleDescriptor::getModuleStreamIndex() const { - return Layout->ModDiStream; -} - -uint32_t DbiModuleDescriptor::getSymbolDebugInfoByteSize() const { - return Layout->SymBytes; -} - -uint32_t DbiModuleDescriptor::getC11LineInfoByteSize() const { - return Layout->C11Bytes; -} - -uint32_t DbiModuleDescriptor::getC13LineInfoByteSize() const { - return Layout->C13Bytes; -} - -uint32_t DbiModuleDescriptor::getNumberOfFiles() const { - return Layout->NumFiles; -} - -uint32_t DbiModuleDescriptor::getSourceFileNameIndex() const { - return Layout->SrcFileNameNI; -} - -uint32_t DbiModuleDescriptor::getPdbFilePathNameIndex() const { - return Layout->PdbFilePathNI; -} - -StringRef DbiModuleDescriptor::getModuleName() const { return ModuleName; } - -StringRef DbiModuleDescriptor::getObjFileName() const { return ObjFileName; } - -uint32_t DbiModuleDescriptor::getRecordLength() const { - uint32_t M = ModuleName.str().size() + 1; - uint32_t O = ObjFileName.str().size() + 1; - uint32_t Size = sizeof(ModuleInfoHeader) + M + O; - Size = alignTo(Size, 4); - return Size; -} +//===- DbiModuleDescriptor.cpp - PDB module information -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <cstdint> + +using namespace llvm; +using namespace llvm::pdb; +using namespace llvm::support; + +Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream, + DbiModuleDescriptor &Info) { + BinaryStreamReader Reader(Stream); + if (auto EC = Reader.readObject(Info.Layout)) + return EC; + + if (auto EC = Reader.readCString(Info.ModuleName)) + return EC; + + if (auto EC = Reader.readCString(Info.ObjFileName)) + return EC; + return Error::success(); +} + +bool DbiModuleDescriptor::hasECInfo() const { + return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0; +} + +uint16_t DbiModuleDescriptor::getTypeServerIndex() const { + return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >> + ModInfoFlags::TypeServerIndexShift; +} + +const SectionContrib &DbiModuleDescriptor::getSectionContrib() const { + return Layout->SC; +} + +uint16_t DbiModuleDescriptor::getModuleStreamIndex() const { + return Layout->ModDiStream; +} + +uint32_t DbiModuleDescriptor::getSymbolDebugInfoByteSize() const { + return Layout->SymBytes; +} + +uint32_t DbiModuleDescriptor::getC11LineInfoByteSize() const { + return Layout->C11Bytes; +} + +uint32_t DbiModuleDescriptor::getC13LineInfoByteSize() const { + return Layout->C13Bytes; +} + +uint32_t DbiModuleDescriptor::getNumberOfFiles() const { + return Layout->NumFiles; +} + +uint32_t DbiModuleDescriptor::getSourceFileNameIndex() const { + return Layout->SrcFileNameNI; +} + +uint32_t DbiModuleDescriptor::getPdbFilePathNameIndex() const { + return Layout->PdbFilePathNI; +} + +StringRef DbiModuleDescriptor::getModuleName() const { return ModuleName; } + +StringRef DbiModuleDescriptor::getObjFileName() const { return ObjFileName; } + +uint32_t DbiModuleDescriptor::getRecordLength() const { + uint32_t M = ModuleName.str().size() + 1; + uint32_t O = ObjFileName.str().size() + 1; + uint32_t Size = sizeof(ModuleInfoHeader) + M + O; + Size = alignTo(Size, 4); + return Size; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index b6f11a942a..84866366e9 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -1,87 +1,87 @@ -//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamWriter.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize, - uint32_t C13Size) { - uint32_t Size = sizeof(uint32_t); // Signature - Size += alignTo(SymbolByteSize, 4); // Symbol Data - Size += 0; // TODO: Layout.C11Bytes - Size += C13Size; // C13 Debug Info Size - Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) - Size += 0; // GlobalRefs substream bytes - return Size; -} - -DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName, - uint32_t ModIndex, - msf::MSFBuilder &Msf) - : MSF(Msf), ModuleName(std::string(ModuleName)) { - ::memset(&Layout, 0, sizeof(Layout)); - Layout.Mod = ModIndex; -} - -DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {} - -uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const { - return Layout.ModDiStream; -} - -void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) { - ObjFileName = std::string(Name); -} - -void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) { - PdbFilePathNI = NI; -} - -void DbiModuleDescriptorBuilder::setFirstSectionContrib( - const SectionContrib &SC) { - Layout.SC = SC; -} - -void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { - // Defer to the bulk API. It does the same thing. - addSymbolsInBulk(Symbol.data()); -} - -void DbiModuleDescriptorBuilder::addSymbolsInBulk( - ArrayRef<uint8_t> BulkSymbols) { - // Do nothing for empty runs of symbols. - if (BulkSymbols.empty()) - return; - +//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize, + uint32_t C13Size) { + uint32_t Size = sizeof(uint32_t); // Signature + Size += alignTo(SymbolByteSize, 4); // Symbol Data + Size += 0; // TODO: Layout.C11Bytes + Size += C13Size; // C13 Debug Info Size + Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) + Size += 0; // GlobalRefs substream bytes + return Size; +} + +DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName, + uint32_t ModIndex, + msf::MSFBuilder &Msf) + : MSF(Msf), ModuleName(std::string(ModuleName)) { + ::memset(&Layout, 0, sizeof(Layout)); + Layout.Mod = ModIndex; +} + +DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {} + +uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const { + return Layout.ModDiStream; +} + +void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) { + ObjFileName = std::string(Name); +} + +void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) { + PdbFilePathNI = NI; +} + +void DbiModuleDescriptorBuilder::setFirstSectionContrib( + const SectionContrib &SC) { + Layout.SC = SC; +} + +void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { + // Defer to the bulk API. It does the same thing. + addSymbolsInBulk(Symbol.data()); +} + +void DbiModuleDescriptorBuilder::addSymbolsInBulk( + ArrayRef<uint8_t> BulkSymbols) { + // Do nothing for empty runs of symbols. + if (BulkSymbols.empty()) + return; + Symbols.push_back(SymbolListWrapper(BulkSymbols)); - // Symbols written to a PDB file are required to be 4 byte aligned. The same - // is not true of object files. - assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 && - "Invalid Symbol alignment!"); - SymbolByteSize += BulkSymbols.size(); -} - + // Symbols written to a PDB file are required to be 4 byte aligned. The same + // is not true of object files. + assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 && + "Invalid Symbol alignment!"); + SymbolByteSize += BulkSymbols.size(); +} + void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc, uint32_t SymLength) { assert(SymLength > 0); @@ -94,69 +94,69 @@ void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc, SymbolByteSize += SymLength; } -void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { - SourceFiles.push_back(std::string(Path)); -} - -uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const { - uint32_t Result = 0; - for (const auto &Builder : C13Builders) { - Result += Builder.calculateSerializedLength(); - } - return Result; -} - -uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { - uint32_t L = sizeof(Layout); - uint32_t M = ModuleName.size() + 1; - uint32_t O = ObjFileName.size() + 1; - return alignTo(L + M + O, sizeof(uint32_t)); -} - -void DbiModuleDescriptorBuilder::finalize() { - Layout.FileNameOffs = 0; // TODO: Fix this - Layout.Flags = 0; // TODO: Fix this - Layout.C11Bytes = 0; - Layout.C13Bytes = calculateC13DebugInfoSize(); - (void)Layout.Mod; // Set in constructor - (void)Layout.ModDiStream; // Set in finalizeMsfLayout - Layout.NumFiles = SourceFiles.size(); - Layout.PdbFilePathNI = PdbFilePathNI; - Layout.SrcFileNameNI = 0; - - // This value includes both the signature field as well as the record bytes - // from the symbol stream. - Layout.SymBytes = - Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset(); -} - -Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { - this->Layout.ModDiStream = kInvalidStreamIndex; - uint32_t C13Size = calculateC13DebugInfoSize(); - if (!C13Size && !SymbolByteSize) - return Error::success(); - auto ExpectedSN = - MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); - if (!ExpectedSN) - return ExpectedSN.takeError(); - Layout.ModDiStream = *ExpectedSN; - return Error::success(); -} - +void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { + SourceFiles.push_back(std::string(Path)); +} + +uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const { + uint32_t Result = 0; + for (const auto &Builder : C13Builders) { + Result += Builder.calculateSerializedLength(); + } + return Result; +} + +uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { + uint32_t L = sizeof(Layout); + uint32_t M = ModuleName.size() + 1; + uint32_t O = ObjFileName.size() + 1; + return alignTo(L + M + O, sizeof(uint32_t)); +} + +void DbiModuleDescriptorBuilder::finalize() { + Layout.FileNameOffs = 0; // TODO: Fix this + Layout.Flags = 0; // TODO: Fix this + Layout.C11Bytes = 0; + Layout.C13Bytes = calculateC13DebugInfoSize(); + (void)Layout.Mod; // Set in constructor + (void)Layout.ModDiStream; // Set in finalizeMsfLayout + Layout.NumFiles = SourceFiles.size(); + Layout.PdbFilePathNI = PdbFilePathNI; + Layout.SrcFileNameNI = 0; + + // This value includes both the signature field as well as the record bytes + // from the symbol stream. + Layout.SymBytes = + Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset(); +} + +Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { + this->Layout.ModDiStream = kInvalidStreamIndex; + uint32_t C13Size = calculateC13DebugInfoSize(); + if (!C13Size && !SymbolByteSize) + return Error::success(); + auto ExpectedSN = + MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); + if (!ExpectedSN) + return ExpectedSN.takeError(); + Layout.ModDiStream = *ExpectedSN; + return Error::success(); +} + Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) { - // We write the Modi record to the `ModiWriter`, but we additionally write its - // symbol stream to a brand new stream. - if (auto EC = ModiWriter.writeObject(Layout)) - return EC; - if (auto EC = ModiWriter.writeCString(ModuleName)) - return EC; - if (auto EC = ModiWriter.writeCString(ObjFileName)) - return EC; - if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) - return EC; + // We write the Modi record to the `ModiWriter`, but we additionally write its + // symbol stream to a brand new stream. + if (auto EC = ModiWriter.writeObject(Layout)) + return EC; + if (auto EC = ModiWriter.writeCString(ModuleName)) + return EC; + if (auto EC = ModiWriter.writeCString(ObjFileName)) + return EC; + if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) + return EC; return Error::success(); } - + Error DbiModuleDescriptorBuilder::commitSymbolStream( const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) { if (Layout.ModDiStream == kInvalidStreamIndex) @@ -173,13 +173,13 @@ Error DbiModuleDescriptorBuilder::commitSymbolStream( if (Sym.NeedsToBeMerged) { assert(MergeSymsCallback); if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter)) - return EC; + return EC; } else { if (auto EC = SymbolWriter.writeBytes(Sym.asArray())) - return EC; - } + return EC; + } } - + // Apply the string table fixups. auto SavedOffset = SymbolWriter.getOffset(); for (const StringTableFixup &Fixup : StringTableFixups) { @@ -194,8 +194,8 @@ Error DbiModuleDescriptorBuilder::commitSymbolStream( // TODO: Write C11 Line data for (const auto &Builder : C13Builders) { if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb)) - return EC; - } + return EC; + } // TODO: Figure out what GlobalRefs substream actually is and populate it. if (auto EC = SymbolWriter.writeInteger<uint32_t>(0)) @@ -203,16 +203,16 @@ Error DbiModuleDescriptorBuilder::commitSymbolStream( if (SymbolWriter.bytesRemaining() > 0) return make_error<RawError>(raw_error_code::stream_too_long); - return Error::success(); -} - -void DbiModuleDescriptorBuilder::addDebugSubsection( - std::shared_ptr<DebugSubsection> Subsection) { - assert(Subsection); - C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection))); -} - -void DbiModuleDescriptorBuilder::addDebugSubsection( - const DebugSubsectionRecord &SubsectionContents) { - C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents)); -} + return Error::success(); +} + +void DbiModuleDescriptorBuilder::addDebugSubsection( + std::shared_ptr<DebugSubsection> Subsection) { + assert(Subsection); + C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection))); +} + +void DbiModuleDescriptorBuilder::addDebugSubsection( + const DebugSubsectionRecord &SubsectionContents) { + C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents)); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleList.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleList.cpp index 5cf014e881..ed2d67a3a3 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleList.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiModuleList.cpp @@ -1,279 +1,279 @@ -//===- DbiModuleList.cpp - PDB module information list --------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstddef> -#include <cstdint> - -using namespace llvm; -using namespace llvm::pdb; - -DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator( - const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei) - : Modules(&Modules), Modi(Modi), Filei(Filei) { - setValue(); -} - -bool DbiModuleSourceFilesIterator:: -operator==(const DbiModuleSourceFilesIterator &R) const { - // incompatible iterators are never equal - if (!isCompatible(R)) - return false; - - // If they're compatible, and they're both ends, then they're equal. - if (isEnd() && R.isEnd()) - return true; - - // If one is an end and the other is not, they're not equal. - if (isEnd() != R.isEnd()) - return false; - - // Now we know: - // - They're compatible - // - They're not *both* end iterators - // - Their endness is the same. - // Thus, they're compatible iterators pointing to a valid file on the same - // module. All we need to check are the file indices. - assert(Modules == R.Modules); - assert(Modi == R.Modi); - assert(!isEnd()); - assert(!R.isEnd()); - - return (Filei == R.Filei); -} - -bool DbiModuleSourceFilesIterator:: -operator<(const DbiModuleSourceFilesIterator &R) const { - assert(isCompatible(R)); - - // It's not sufficient to compare the file indices, because default - // constructed iterators could be equal to iterators with valid indices. To - // account for this, early-out if they're equal. - if (*this == R) - return false; - - return Filei < R.Filei; -} - -std::ptrdiff_t DbiModuleSourceFilesIterator:: -operator-(const DbiModuleSourceFilesIterator &R) const { - assert(isCompatible(R)); - assert(!(*this < R)); - - // If they're both end iterators, the distance is 0. - if (isEnd() && R.isEnd()) - return 0; - - assert(!R.isEnd()); - - // At this point, R cannot be end, but *this can, which means that *this - // might be a universal end iterator with none of its fields set. So in that - // case have to rely on R as the authority to figure out how many files there - // are to compute the distance. - uint32_t Thisi = Filei; - if (isEnd()) { - uint32_t RealModi = R.Modi; - Thisi = R.Modules->getSourceFileCount(RealModi); - } - - assert(Thisi >= R.Filei); - return Thisi - R.Filei; -} - -DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: -operator+=(std::ptrdiff_t N) { - assert(!isEnd()); - - Filei += N; - assert(Filei <= Modules->getSourceFileCount(Modi)); - setValue(); - return *this; -} - -DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: -operator-=(std::ptrdiff_t N) { - // Note that we can subtract from an end iterator, but not a universal end - // iterator. - assert(!isUniversalEnd()); - - assert(N <= Filei); - - Filei -= N; - return *this; -} - -void DbiModuleSourceFilesIterator::setValue() { - if (isEnd()) { - ThisValue = ""; - return; - } - - uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei; - auto ExpectedValue = Modules->getFileName(Off); - if (!ExpectedValue) { - consumeError(ExpectedValue.takeError()); - Filei = Modules->getSourceFileCount(Modi); - } else - ThisValue = *ExpectedValue; -} - -bool DbiModuleSourceFilesIterator::isEnd() const { - if (isUniversalEnd()) - return true; - - assert(Modules); - assert(Modi <= Modules->getModuleCount()); - assert(Filei <= Modules->getSourceFileCount(Modi)); - - if (Modi == Modules->getModuleCount()) - return true; - if (Filei == Modules->getSourceFileCount(Modi)) - return true; - return false; -} - -bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; } - -bool DbiModuleSourceFilesIterator::isCompatible( - const DbiModuleSourceFilesIterator &R) const { - // Universal iterators are compatible with any other iterator. - if (isUniversalEnd() || R.isUniversalEnd()) - return true; - - // At this point, neither iterator is a universal end iterator, although one - // or both might be non-universal end iterators. Regardless, the module index - // is valid, so they are compatible if and only if they refer to the same - // module. - return Modi == R.Modi; -} - -Error DbiModuleList::initialize(BinaryStreamRef ModInfo, - BinaryStreamRef FileInfo) { - if (auto EC = initializeModInfo(ModInfo)) - return EC; - if (auto EC = initializeFileInfo(FileInfo)) - return EC; - - return Error::success(); -} - -Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) { - ModInfoSubstream = ModInfo; - - if (ModInfo.getLength() == 0) - return Error::success(); - - BinaryStreamReader Reader(ModInfo); - - if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength())) - return EC; - - return Error::success(); -} - -Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) { - FileInfoSubstream = FileInfo; - - if (FileInfo.getLength() == 0) - return Error::success(); - - BinaryStreamReader FISR(FileInfo); - if (auto EC = FISR.readObject(FileInfoHeader)) - return EC; - - // First is an array of `NumModules` module indices. This does not seem to be - // used for anything meaningful, so we ignore it. - FixedStreamArray<support::ulittle16_t> ModuleIndices; - if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules)) - return EC; - if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules)) - return EC; - - // Compute the real number of source files. We can't trust the value in - // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all - // source file counts might be larger than a unit16. So we compute the real - // count by summing up the individual counts. - uint32_t NumSourceFiles = 0; - for (auto Count : ModFileCountArray) - NumSourceFiles += Count; - - // In the reference implementation, this array is where the pointer documented - // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that - // although the field in ModuleInfoHeader is ignored this array is not, as it - // is the authority on where each filename begins in the names buffer. - if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles)) - return EC; - - if (auto EC = FISR.readStreamRef(NamesBuffer)) - return EC; - - auto DescriptorIter = Descriptors.begin(); - uint32_t NextFileIndex = 0; - ModuleInitialFileIndex.resize(FileInfoHeader->NumModules); - ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules); - for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) { - assert(DescriptorIter != Descriptors.end()); - ModuleInitialFileIndex[I] = NextFileIndex; - ModuleDescriptorOffsets[I] = DescriptorIter.offset(); - - NextFileIndex += ModFileCountArray[I]; - ++DescriptorIter; - } - - assert(DescriptorIter == Descriptors.end()); - assert(NextFileIndex == NumSourceFiles); - - return Error::success(); -} - -uint32_t DbiModuleList::getModuleCount() const { - return FileInfoHeader->NumModules; -} - -uint32_t DbiModuleList::getSourceFileCount() const { - return FileNameOffsets.size(); -} - -uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const { - return ModFileCountArray[Modi]; -} - -DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const { - assert(Modi < getModuleCount()); - uint32_t Offset = ModuleDescriptorOffsets[Modi]; - auto Iter = Descriptors.at(Offset); - assert(Iter != Descriptors.end()); - return *Iter; -} - -iterator_range<DbiModuleSourceFilesIterator> -DbiModuleList::source_files(uint32_t Modi) const { - return make_range<DbiModuleSourceFilesIterator>( - DbiModuleSourceFilesIterator(*this, Modi, 0), - DbiModuleSourceFilesIterator()); -} - -Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const { - BinaryStreamReader Names(NamesBuffer); - if (Index >= getSourceFileCount()) - return make_error<RawError>(raw_error_code::index_out_of_bounds); - - uint32_t FileOffset = FileNameOffsets[Index]; - Names.setOffset(FileOffset); - StringRef Name; - if (auto EC = Names.readCString(Name)) - return std::move(EC); - return Name; -} +//===- DbiModuleList.cpp - PDB module information list --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> + +using namespace llvm; +using namespace llvm::pdb; + +DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator( + const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei) + : Modules(&Modules), Modi(Modi), Filei(Filei) { + setValue(); +} + +bool DbiModuleSourceFilesIterator:: +operator==(const DbiModuleSourceFilesIterator &R) const { + // incompatible iterators are never equal + if (!isCompatible(R)) + return false; + + // If they're compatible, and they're both ends, then they're equal. + if (isEnd() && R.isEnd()) + return true; + + // If one is an end and the other is not, they're not equal. + if (isEnd() != R.isEnd()) + return false; + + // Now we know: + // - They're compatible + // - They're not *both* end iterators + // - Their endness is the same. + // Thus, they're compatible iterators pointing to a valid file on the same + // module. All we need to check are the file indices. + assert(Modules == R.Modules); + assert(Modi == R.Modi); + assert(!isEnd()); + assert(!R.isEnd()); + + return (Filei == R.Filei); +} + +bool DbiModuleSourceFilesIterator:: +operator<(const DbiModuleSourceFilesIterator &R) const { + assert(isCompatible(R)); + + // It's not sufficient to compare the file indices, because default + // constructed iterators could be equal to iterators with valid indices. To + // account for this, early-out if they're equal. + if (*this == R) + return false; + + return Filei < R.Filei; +} + +std::ptrdiff_t DbiModuleSourceFilesIterator:: +operator-(const DbiModuleSourceFilesIterator &R) const { + assert(isCompatible(R)); + assert(!(*this < R)); + + // If they're both end iterators, the distance is 0. + if (isEnd() && R.isEnd()) + return 0; + + assert(!R.isEnd()); + + // At this point, R cannot be end, but *this can, which means that *this + // might be a universal end iterator with none of its fields set. So in that + // case have to rely on R as the authority to figure out how many files there + // are to compute the distance. + uint32_t Thisi = Filei; + if (isEnd()) { + uint32_t RealModi = R.Modi; + Thisi = R.Modules->getSourceFileCount(RealModi); + } + + assert(Thisi >= R.Filei); + return Thisi - R.Filei; +} + +DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: +operator+=(std::ptrdiff_t N) { + assert(!isEnd()); + + Filei += N; + assert(Filei <= Modules->getSourceFileCount(Modi)); + setValue(); + return *this; +} + +DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator:: +operator-=(std::ptrdiff_t N) { + // Note that we can subtract from an end iterator, but not a universal end + // iterator. + assert(!isUniversalEnd()); + + assert(N <= Filei); + + Filei -= N; + return *this; +} + +void DbiModuleSourceFilesIterator::setValue() { + if (isEnd()) { + ThisValue = ""; + return; + } + + uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei; + auto ExpectedValue = Modules->getFileName(Off); + if (!ExpectedValue) { + consumeError(ExpectedValue.takeError()); + Filei = Modules->getSourceFileCount(Modi); + } else + ThisValue = *ExpectedValue; +} + +bool DbiModuleSourceFilesIterator::isEnd() const { + if (isUniversalEnd()) + return true; + + assert(Modules); + assert(Modi <= Modules->getModuleCount()); + assert(Filei <= Modules->getSourceFileCount(Modi)); + + if (Modi == Modules->getModuleCount()) + return true; + if (Filei == Modules->getSourceFileCount(Modi)) + return true; + return false; +} + +bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; } + +bool DbiModuleSourceFilesIterator::isCompatible( + const DbiModuleSourceFilesIterator &R) const { + // Universal iterators are compatible with any other iterator. + if (isUniversalEnd() || R.isUniversalEnd()) + return true; + + // At this point, neither iterator is a universal end iterator, although one + // or both might be non-universal end iterators. Regardless, the module index + // is valid, so they are compatible if and only if they refer to the same + // module. + return Modi == R.Modi; +} + +Error DbiModuleList::initialize(BinaryStreamRef ModInfo, + BinaryStreamRef FileInfo) { + if (auto EC = initializeModInfo(ModInfo)) + return EC; + if (auto EC = initializeFileInfo(FileInfo)) + return EC; + + return Error::success(); +} + +Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) { + ModInfoSubstream = ModInfo; + + if (ModInfo.getLength() == 0) + return Error::success(); + + BinaryStreamReader Reader(ModInfo); + + if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength())) + return EC; + + return Error::success(); +} + +Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) { + FileInfoSubstream = FileInfo; + + if (FileInfo.getLength() == 0) + return Error::success(); + + BinaryStreamReader FISR(FileInfo); + if (auto EC = FISR.readObject(FileInfoHeader)) + return EC; + + // First is an array of `NumModules` module indices. This does not seem to be + // used for anything meaningful, so we ignore it. + FixedStreamArray<support::ulittle16_t> ModuleIndices; + if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules)) + return EC; + if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules)) + return EC; + + // Compute the real number of source files. We can't trust the value in + // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all + // source file counts might be larger than a unit16. So we compute the real + // count by summing up the individual counts. + uint32_t NumSourceFiles = 0; + for (auto Count : ModFileCountArray) + NumSourceFiles += Count; + + // In the reference implementation, this array is where the pointer documented + // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that + // although the field in ModuleInfoHeader is ignored this array is not, as it + // is the authority on where each filename begins in the names buffer. + if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles)) + return EC; + + if (auto EC = FISR.readStreamRef(NamesBuffer)) + return EC; + + auto DescriptorIter = Descriptors.begin(); + uint32_t NextFileIndex = 0; + ModuleInitialFileIndex.resize(FileInfoHeader->NumModules); + ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules); + for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) { + assert(DescriptorIter != Descriptors.end()); + ModuleInitialFileIndex[I] = NextFileIndex; + ModuleDescriptorOffsets[I] = DescriptorIter.offset(); + + NextFileIndex += ModFileCountArray[I]; + ++DescriptorIter; + } + + assert(DescriptorIter == Descriptors.end()); + assert(NextFileIndex == NumSourceFiles); + + return Error::success(); +} + +uint32_t DbiModuleList::getModuleCount() const { + return FileInfoHeader->NumModules; +} + +uint32_t DbiModuleList::getSourceFileCount() const { + return FileNameOffsets.size(); +} + +uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const { + return ModFileCountArray[Modi]; +} + +DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const { + assert(Modi < getModuleCount()); + uint32_t Offset = ModuleDescriptorOffsets[Modi]; + auto Iter = Descriptors.at(Offset); + assert(Iter != Descriptors.end()); + return *Iter; +} + +iterator_range<DbiModuleSourceFilesIterator> +DbiModuleList::source_files(uint32_t Modi) const { + return make_range<DbiModuleSourceFilesIterator>( + DbiModuleSourceFilesIterator(*this, Modi, 0), + DbiModuleSourceFilesIterator()); +} + +Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const { + BinaryStreamReader Names(NamesBuffer); + if (Index >= getSourceFileCount()) + return make_error<RawError>(raw_error_code::index_out_of_bounds); + + uint32_t FileOffset = FileNameOffsets[Index]; + Names.setOffset(FileOffset); + StringRef Name; + if (auto EC = Names.readCString(Name)) + return std::move(EC); + return Name; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStream.cpp index 4eb1680417..60fedf6a9f 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -1,383 +1,383 @@ -//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/BinaryStreamArray.h" -#include "llvm/Support/BinaryStreamReader.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; - -template <typename ContribType> -static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, - BinaryStreamReader &Reader) { - if (Reader.bytesRemaining() % sizeof(ContribType) != 0) - return make_error<RawError>( - raw_error_code::corrupt_file, - "Invalid number of bytes of section contributions"); - - uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType); - if (auto EC = Reader.readArray(Output, Count)) - return EC; - return Error::success(); -} - -DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream) - : Stream(std::move(Stream)), Header(nullptr) {} - -DbiStream::~DbiStream() = default; - -Error DbiStream::reload(PDBFile *Pdb) { - BinaryStreamReader Reader(*Stream); - - 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)) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI Stream does not contain a header."); - - if (Header->VersionSignature != -1) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid DBI version signature."); - - // Require at least version 7, which should be present in all PDBs - // produced in the last decade and allows us to avoid having to - // special case all kinds of complicated arcane formats. - if (Header->VersionHeader < PdbDbiV70) - return make_error<RawError>(raw_error_code::feature_unsupported, - "Unsupported DBI version."); - - if (Stream->getLength() != - sizeof(DbiStreamHeader) + Header->ModiSubstreamSize + - Header->SecContrSubstreamSize + Header->SectionMapSize + - Header->FileInfoSize + Header->TypeServerSize + - Header->OptionalDbgHdrSize + Header->ECSubstreamSize) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI Length does not equal sum of substreams."); - - // Only certain substreams are guaranteed to be aligned. Validate - // them here. - if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI MODI substream not aligned."); - if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) - return make_error<RawError>( - raw_error_code::corrupt_file, - "DBI section contribution substream not aligned."); - if (Header->SectionMapSize % sizeof(uint32_t) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI section map substream not aligned."); - if (Header->FileInfoSize % sizeof(uint32_t) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI file info substream not aligned."); - if (Header->TypeServerSize % sizeof(uint32_t) != 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "DBI type server substream not aligned."); - - if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize)) - return EC; - - if (auto EC = Reader.readSubstream(SecContrSubstream, - Header->SecContrSubstreamSize)) - return EC; - if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize)) - return EC; - if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize)) - return EC; - if (auto EC = - Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize)) - return EC; - if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize)) - return EC; - if (auto EC = Reader.readArray( - DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t))) - return EC; - - if (auto EC = Modules.initialize(ModiSubstream.StreamData, - FileInfoSubstream.StreamData)) - return EC; - - if (auto EC = initializeSectionContributionData()) - return EC; - if (auto EC = initializeSectionHeadersData(Pdb)) - return EC; - if (auto EC = initializeSectionMapData()) - return EC; - if (auto EC = initializeOldFpoRecords(Pdb)) - return EC; - if (auto EC = initializeNewFpoRecords(Pdb)) - return EC; - - if (Reader.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Found unexpected bytes in DBI Stream."); - - if (!ECSubstream.empty()) { - BinaryStreamReader ECReader(ECSubstream.StreamData); - if (auto EC = ECNames.reload(ECReader)) - return EC; - } - - return Error::success(); -} - -PdbRaw_DbiVer DbiStream::getDbiVersion() const { - uint32_t Value = Header->VersionHeader; - return static_cast<PdbRaw_DbiVer>(Value); -} - -uint32_t DbiStream::getAge() const { return Header->Age; } - -uint16_t DbiStream::getPublicSymbolStreamIndex() const { - return Header->PublicSymbolStreamIndex; -} - -uint16_t DbiStream::getGlobalSymbolStreamIndex() const { - return Header->GlobalSymbolStreamIndex; -} - -uint16_t DbiStream::getFlags() const { return Header->Flags; } - -bool DbiStream::isIncrementallyLinked() const { - return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0; -} - -bool DbiStream::hasCTypes() const { - return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0; -} - -bool DbiStream::isStripped() const { - return (Header->Flags & DbiFlags::FlagStrippedMask) != 0; -} - -uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } - -uint16_t DbiStream::getBuildMajorVersion() const { - return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >> - DbiBuildNo::BuildMajorShift; -} - -uint16_t DbiStream::getBuildMinorVersion() const { - return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >> - DbiBuildNo::BuildMinorShift; -} - -uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } - -uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; } - -uint32_t DbiStream::getSymRecordStreamIndex() const { - return Header->SymRecordStreamIndex; -} - -PDB_Machine DbiStream::getMachineType() const { - uint16_t Machine = Header->MachineType; - return static_cast<PDB_Machine>(Machine); -} - -FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const { - return SectionHeaders; -} - -bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; } - -FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const { - return OldFpoRecords; -} - -bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; } - -const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const { - return NewFpoRecords; -} - -const DbiModuleList &DbiStream::modules() const { return Modules; } - -FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { - return SectionMap; -} - -void DbiStream::visitSectionContributions( - ISectionContribVisitor &Visitor) const { - if (!SectionContribs.empty()) { - assert(SectionContribVersion == DbiSecContribVer60); - for (auto &SC : SectionContribs) - Visitor.visit(SC); - } else if (!SectionContribs2.empty()) { - assert(SectionContribVersion == DbiSecContribV2); - for (auto &SC : SectionContribs2) - Visitor.visit(SC); - } -} - -Expected<StringRef> DbiStream::getECName(uint32_t NI) const { - return ECNames.getStringForID(NI); -} - -Error DbiStream::initializeSectionContributionData() { - if (SecContrSubstream.empty()) - return Error::success(); - - BinaryStreamReader SCReader(SecContrSubstream.StreamData); - if (auto EC = SCReader.readEnum(SectionContribVersion)) - return EC; - - if (SectionContribVersion == DbiSecContribVer60) - return loadSectionContribs<SectionContrib>(SectionContribs, SCReader); - if (SectionContribVersion == DbiSecContribV2) - return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader); - - return make_error<RawError>(raw_error_code::feature_unsupported, - "Unsupported DBI Section Contribution version"); -} - -// Initializes this->SectionHeaders. -Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) { - Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = - createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr); - if (auto EC = ExpectedStream.takeError()) - return EC; - - auto &SHS = *ExpectedStream; - if (!SHS) - return Error::success(); - - 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); - BinaryStreamReader 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); - return Error::success(); -} - -// Initializes this->Fpos. -Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) { - Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = - createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO); - if (auto EC = ExpectedStream.takeError()) - return EC; - - auto &FS = *ExpectedStream; - if (!FS) - return Error::success(); - - size_t StreamLen = FS->getLength(); - if (StreamLen % sizeof(object::FpoData)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Corrupted Old FPO stream."); - - size_t NumRecords = StreamLen / sizeof(object::FpoData); - BinaryStreamReader Reader(*FS); - if (auto EC = Reader.readArray(OldFpoRecords, NumRecords)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Corrupted Old FPO stream."); - OldFpoStream = std::move(FS); - return Error::success(); -} - -Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) { - Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = - createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO); - if (auto EC = ExpectedStream.takeError()) - return EC; - - auto &FS = *ExpectedStream; - if (!FS) - return Error::success(); - - if (auto EC = NewFpoRecords.initialize(*FS)) - return EC; - - NewFpoStream = std::move(FS); - return Error::success(); -} - -Expected<std::unique_ptr<msf::MappedBlockStream>> -DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb, - DbgHeaderType Type) const { - if (!Pdb) - return nullptr; - - if (DbgStreams.empty()) - return nullptr; - - uint32_t StreamNum = getDebugStreamIndex(Type); - - // This means there is no such stream. - if (StreamNum == kInvalidStreamIndex) - return nullptr; - - return Pdb->safelyCreateIndexedStream(StreamNum); -} - -BinarySubstreamRef DbiStream::getSectionContributionData() const { - return SecContrSubstream; -} - -BinarySubstreamRef DbiStream::getSecMapSubstreamData() const { - return SecMapSubstream; -} - -BinarySubstreamRef DbiStream::getModiSubstreamData() const { - return ModiSubstream; -} - -BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const { - return FileInfoSubstream; -} - -BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const { - return TypeServerMapSubstream; -} - -BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; } - -Error DbiStream::initializeSectionMapData() { - if (SecMapSubstream.empty()) - return Error::success(); - - BinaryStreamReader SMReader(SecMapSubstream.StreamData); - const SecMapHeader *Header; - if (auto EC = SMReader.readObject(Header)) - return EC; - if (auto EC = SMReader.readArray(SectionMap, Header->SecCount)) - return EC; - return Error::success(); -} - -uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { - uint16_t T = static_cast<uint16_t>(Type); - if (T >= DbgStreams.size()) - return kInvalidStreamIndex; - return DbgStreams[T]; -} +//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.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; + +template <typename ContribType> +static Error loadSectionContribs(FixedStreamArray<ContribType> &Output, + BinaryStreamReader &Reader) { + if (Reader.bytesRemaining() % sizeof(ContribType) != 0) + return make_error<RawError>( + raw_error_code::corrupt_file, + "Invalid number of bytes of section contributions"); + + uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType); + if (auto EC = Reader.readArray(Output, Count)) + return EC; + return Error::success(); +} + +DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} + +DbiStream::~DbiStream() = default; + +Error DbiStream::reload(PDBFile *Pdb) { + BinaryStreamReader Reader(*Stream); + + 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)) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI Stream does not contain a header."); + + if (Header->VersionSignature != -1) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid DBI version signature."); + + // Require at least version 7, which should be present in all PDBs + // produced in the last decade and allows us to avoid having to + // special case all kinds of complicated arcane formats. + if (Header->VersionHeader < PdbDbiV70) + return make_error<RawError>(raw_error_code::feature_unsupported, + "Unsupported DBI version."); + + if (Stream->getLength() != + sizeof(DbiStreamHeader) + Header->ModiSubstreamSize + + Header->SecContrSubstreamSize + Header->SectionMapSize + + Header->FileInfoSize + Header->TypeServerSize + + Header->OptionalDbgHdrSize + Header->ECSubstreamSize) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI Length does not equal sum of substreams."); + + // Only certain substreams are guaranteed to be aligned. Validate + // them here. + if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI MODI substream not aligned."); + if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) + return make_error<RawError>( + raw_error_code::corrupt_file, + "DBI section contribution substream not aligned."); + if (Header->SectionMapSize % sizeof(uint32_t) != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI section map substream not aligned."); + if (Header->FileInfoSize % sizeof(uint32_t) != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI file info substream not aligned."); + if (Header->TypeServerSize % sizeof(uint32_t) != 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "DBI type server substream not aligned."); + + if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize)) + return EC; + + if (auto EC = Reader.readSubstream(SecContrSubstream, + Header->SecContrSubstreamSize)) + return EC; + if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize)) + return EC; + if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize)) + return EC; + if (auto EC = + Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize)) + return EC; + if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize)) + return EC; + if (auto EC = Reader.readArray( + DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t))) + return EC; + + if (auto EC = Modules.initialize(ModiSubstream.StreamData, + FileInfoSubstream.StreamData)) + return EC; + + if (auto EC = initializeSectionContributionData()) + return EC; + if (auto EC = initializeSectionHeadersData(Pdb)) + return EC; + if (auto EC = initializeSectionMapData()) + return EC; + if (auto EC = initializeOldFpoRecords(Pdb)) + return EC; + if (auto EC = initializeNewFpoRecords(Pdb)) + return EC; + + if (Reader.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Found unexpected bytes in DBI Stream."); + + if (!ECSubstream.empty()) { + BinaryStreamReader ECReader(ECSubstream.StreamData); + if (auto EC = ECNames.reload(ECReader)) + return EC; + } + + return Error::success(); +} + +PdbRaw_DbiVer DbiStream::getDbiVersion() const { + uint32_t Value = Header->VersionHeader; + return static_cast<PdbRaw_DbiVer>(Value); +} + +uint32_t DbiStream::getAge() const { return Header->Age; } + +uint16_t DbiStream::getPublicSymbolStreamIndex() const { + return Header->PublicSymbolStreamIndex; +} + +uint16_t DbiStream::getGlobalSymbolStreamIndex() const { + return Header->GlobalSymbolStreamIndex; +} + +uint16_t DbiStream::getFlags() const { return Header->Flags; } + +bool DbiStream::isIncrementallyLinked() const { + return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0; +} + +bool DbiStream::hasCTypes() const { + return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0; +} + +bool DbiStream::isStripped() const { + return (Header->Flags & DbiFlags::FlagStrippedMask) != 0; +} + +uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; } + +uint16_t DbiStream::getBuildMajorVersion() const { + return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >> + DbiBuildNo::BuildMajorShift; +} + +uint16_t DbiStream::getBuildMinorVersion() const { + return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >> + DbiBuildNo::BuildMinorShift; +} + +uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; } + +uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; } + +uint32_t DbiStream::getSymRecordStreamIndex() const { + return Header->SymRecordStreamIndex; +} + +PDB_Machine DbiStream::getMachineType() const { + uint16_t Machine = Header->MachineType; + return static_cast<PDB_Machine>(Machine); +} + +FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const { + return SectionHeaders; +} + +bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; } + +FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const { + return OldFpoRecords; +} + +bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; } + +const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const { + return NewFpoRecords; +} + +const DbiModuleList &DbiStream::modules() const { return Modules; } + +FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const { + return SectionMap; +} + +void DbiStream::visitSectionContributions( + ISectionContribVisitor &Visitor) const { + if (!SectionContribs.empty()) { + assert(SectionContribVersion == DbiSecContribVer60); + for (auto &SC : SectionContribs) + Visitor.visit(SC); + } else if (!SectionContribs2.empty()) { + assert(SectionContribVersion == DbiSecContribV2); + for (auto &SC : SectionContribs2) + Visitor.visit(SC); + } +} + +Expected<StringRef> DbiStream::getECName(uint32_t NI) const { + return ECNames.getStringForID(NI); +} + +Error DbiStream::initializeSectionContributionData() { + if (SecContrSubstream.empty()) + return Error::success(); + + BinaryStreamReader SCReader(SecContrSubstream.StreamData); + if (auto EC = SCReader.readEnum(SectionContribVersion)) + return EC; + + if (SectionContribVersion == DbiSecContribVer60) + return loadSectionContribs<SectionContrib>(SectionContribs, SCReader); + if (SectionContribVersion == DbiSecContribV2) + return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader); + + return make_error<RawError>(raw_error_code::feature_unsupported, + "Unsupported DBI Section Contribution version"); +} + +// Initializes this->SectionHeaders. +Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &SHS = *ExpectedStream; + if (!SHS) + return Error::success(); + + 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); + BinaryStreamReader 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); + return Error::success(); +} + +// Initializes this->Fpos. +Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &FS = *ExpectedStream; + if (!FS) + return Error::success(); + + size_t StreamLen = FS->getLength(); + if (StreamLen % sizeof(object::FpoData)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted Old FPO stream."); + + size_t NumRecords = StreamLen / sizeof(object::FpoData); + BinaryStreamReader Reader(*FS); + if (auto EC = Reader.readArray(OldFpoRecords, NumRecords)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted Old FPO stream."); + OldFpoStream = std::move(FS); + return Error::success(); +} + +Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) { + Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream = + createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO); + if (auto EC = ExpectedStream.takeError()) + return EC; + + auto &FS = *ExpectedStream; + if (!FS) + return Error::success(); + + if (auto EC = NewFpoRecords.initialize(*FS)) + return EC; + + NewFpoStream = std::move(FS); + return Error::success(); +} + +Expected<std::unique_ptr<msf::MappedBlockStream>> +DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb, + DbgHeaderType Type) const { + if (!Pdb) + return nullptr; + + if (DbgStreams.empty()) + return nullptr; + + uint32_t StreamNum = getDebugStreamIndex(Type); + + // This means there is no such stream. + if (StreamNum == kInvalidStreamIndex) + return nullptr; + + return Pdb->safelyCreateIndexedStream(StreamNum); +} + +BinarySubstreamRef DbiStream::getSectionContributionData() const { + return SecContrSubstream; +} + +BinarySubstreamRef DbiStream::getSecMapSubstreamData() const { + return SecMapSubstream; +} + +BinarySubstreamRef DbiStream::getModiSubstreamData() const { + return ModiSubstream; +} + +BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const { + return FileInfoSubstream; +} + +BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const { + return TypeServerMapSubstream; +} + +BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; } + +Error DbiStream::initializeSectionMapData() { + if (SecMapSubstream.empty()) + return Error::success(); + + BinaryStreamReader SMReader(SecMapSubstream.StreamData); + const SecMapHeader *Header; + if (auto EC = SMReader.readObject(Header)) + return EC; + if (auto EC = SMReader.readArray(SectionMap, Header->SecCount)) + return EC; + return Error::success(); +} + +uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const { + uint16_t T = static_cast<uint16_t>(Type); + if (T >= DbgStreams.size()) + return kInvalidStreamIndex; + return DbgStreams[T]; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index 98a8acaffd..c727ba4a48 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -1,404 +1,404 @@ -//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/BinaryStreamWriter.h" +//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Parallel.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -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) {} - -DbiStreamBuilder::~DbiStreamBuilder() {} - -void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } - -void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } - -void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; } - -void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) { - BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) & - DbiBuildNo::BuildMajorMask; - BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) & - DbiBuildNo::BuildMinorMask; - BuildNumber |= DbiBuildNo::NewVersionFormatMask; -} - -void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; } - -void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; } - -void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } - -void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } - -void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) { - // These enums are mirrors of each other, so we can just cast the value. - MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M)); -} - -void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { - GlobalsStreamIndex = Index; -} - -void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { - SymRecordStreamIndex = Index; -} - -void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { - PublicsStreamIndex = Index; -} - -void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { - if (!NewFpoData.hasValue()) - NewFpoData.emplace(false); - - NewFpoData->addFrameData(FD); -} - -void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { - OldFpoData.push_back(FD); -} - -Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, - ArrayRef<uint8_t> Data) { - assert(Type != DbgHeaderType::NewFPO && - "NewFPO data should be written via addFrameData()!"); - - DbgStreams[(int)Type].emplace(); - DbgStreams[(int)Type]->Size = Data.size(); - DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { - return Writer.writeArray(Data); - }; - return Error::success(); -} - -uint32_t DbiStreamBuilder::addECName(StringRef Name) { - return ECNamesBuilder.insert(Name); -} - -uint32_t DbiStreamBuilder::calculateSerializedLength() const { - // For now we only support serializing the header. - return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + - calculateModiSubstreamSize() + calculateSectionContribsStreamSize() + - calculateSectionMapStreamSize() + calculateDbgStreamsSize() + - ECNamesBuilder.calculateSerializedSize(); -} - -Expected<DbiModuleDescriptorBuilder &> -DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { - uint32_t Index = ModiList.size(); - ModiList.push_back( - std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf)); - return *ModiList.back(); -} - -Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module, - StringRef File) { - uint32_t Index = SourceFileNames.size(); - SourceFileNames.insert(std::make_pair(File, Index)); - Module.addSourceFile(File); - return Error::success(); -} - -Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) { - auto NameIter = SourceFileNames.find(File); - if (NameIter == SourceFileNames.end()) - return make_error<RawError>(raw_error_code::no_entry, - "The specified source file was not found"); - return NameIter->getValue(); -} - -uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { - uint32_t Size = 0; - for (const auto &M : ModiList) - Size += M->calculateSerializedLength(); - return Size; -} - -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::calculateNamesOffset() const { - uint32_t Offset = 0; - Offset += sizeof(ulittle16_t); // NumModules - Offset += sizeof(ulittle16_t); // NumSourceFiles - Offset += ModiList.size() * sizeof(ulittle16_t); // ModIndices - Offset += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts - uint32_t NumFileInfos = 0; - for (const auto &M : ModiList) - NumFileInfos += M->source_files().size(); - Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets - return Offset; -} - -uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { - uint32_t Size = calculateNamesOffset(); - 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::generateFileInfoSubstream() { - uint32_t Size = calculateFileInfoSubstreamSize(); - auto Data = Allocator.Allocate<uint8_t>(Size); - uint32_t NamesOffset = calculateNamesOffset(); - - FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size), - llvm::support::little); - - WritableBinaryStreamRef MetadataBuffer = - WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); - BinaryStreamWriter MetadataWriter(MetadataBuffer); - - uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size()); - uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); - if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules - return EC; - 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 : ModiList) { - FileCount = static_cast<uint16_t>(MI->source_files().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 = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset); - BinaryStreamWriter NameBufferWriter(NamesBuffer); - for (auto &Name : SourceFileNames) { - Name.second = NameBufferWriter.getOffset(); - if (auto EC = NameBufferWriter.writeCString(Name.getKey())) - return EC; - } - - for (const auto &MI : ModiList) { - for (StringRef Name : MI->source_files()) { - auto Result = SourceFileNames.find(Name); - if (Result == SourceFileNames.end()) - return make_error<RawError>(raw_error_code::no_entry, - "The source file was not found."); - if (auto EC = MetadataWriter.writeInteger(Result->second)) - return EC; - } - } - - if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t))) - 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(); - - for (auto &MI : ModiList) - MI->finalize(); - - if (auto EC = generateFileInfoSubstream()) - return EC; - - DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); - ::memset(H, 0, sizeof(DbiStreamHeader)); - H->VersionHeader = *VerHeader; - H->VersionSignature = -1; - H->Age = Age; - H->BuildNumber = BuildNumber; - H->Flags = Flags; - H->PdbDllRbld = PdbDllRbld; - H->PdbDllVersion = PdbDllVersion; - H->MachineType = static_cast<uint16_t>(MachineType); - - H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize(); - H->FileInfoSize = FileInfoBuffer.getLength(); - H->ModiSubstreamSize = calculateModiSubstreamSize(); - H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); - H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); - H->SectionMapSize = calculateSectionMapStreamSize(); - H->TypeServerSize = 0; - H->SymRecordStreamIndex = SymRecordStreamIndex; - H->PublicSymbolStreamIndex = PublicsStreamIndex; - H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0. - H->GlobalSymbolStreamIndex = GlobalsStreamIndex; - - Header = H; - return Error::success(); -} - -Error DbiStreamBuilder::finalizeMsfLayout() { - if (NewFpoData.hasValue()) { - DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); - DbgStreams[(int)DbgHeaderType::NewFPO]->Size = - NewFpoData->calculateSerializedSize(); - DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = - [this](BinaryStreamWriter &Writer) { - return NewFpoData->commit(Writer); - }; - } - - if (!OldFpoData.empty()) { - DbgStreams[(int)DbgHeaderType::FPO].emplace(); - DbgStreams[(int)DbgHeaderType::FPO]->Size = - sizeof(object::FpoData) * OldFpoData.size(); - DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = - [this](BinaryStreamWriter &Writer) { - return Writer.writeArray(makeArrayRef(OldFpoData)); - }; - } - - for (auto &S : DbgStreams) { - if (!S.hasValue()) - continue; - auto ExpectedIndex = Msf.addStream(S->Size); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - S->StreamNumber = *ExpectedIndex; - } - - for (auto &MI : ModiList) { - if (auto EC = MI->finalizeMsfLayout()) - return EC; - } - - 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; -} - -// Populate the Section Map from COFF section headers. -// -// 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. -void DbiStreamBuilder::createSectionMap( - ArrayRef<llvm::object::coff_section> SecHdrs) { - int Idx = 0; - - auto Add = [&]() -> SecMapEntry & { - SectionMap.emplace_back(); - auto &Entry = SectionMap.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; -} - -Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, - WritableBinaryStreamRef MsfBuffer) { - if (auto EC = finalize()) - return EC; - - auto DbiS = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, StreamDBI, Allocator); - - BinaryStreamWriter Writer(*DbiS); - if (auto EC = Writer.writeObject(*Header)) - return EC; - - for (auto &M : ModiList) { + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +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) {} + +DbiStreamBuilder::~DbiStreamBuilder() {} + +void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } + +void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } + +void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; } + +void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) { + BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) & + DbiBuildNo::BuildMajorMask; + BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) & + DbiBuildNo::BuildMinorMask; + BuildNumber |= DbiBuildNo::NewVersionFormatMask; +} + +void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; } + +void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; } + +void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } + +void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } + +void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) { + // These enums are mirrors of each other, so we can just cast the value. + MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M)); +} + +void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { + GlobalsStreamIndex = Index; +} + +void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { + SymRecordStreamIndex = Index; +} + +void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { + PublicsStreamIndex = Index; +} + +void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) { + if (!NewFpoData.hasValue()) + NewFpoData.emplace(false); + + NewFpoData->addFrameData(FD); +} + +void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { + OldFpoData.push_back(FD); +} + +Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type, + ArrayRef<uint8_t> Data) { + assert(Type != DbgHeaderType::NewFPO && + "NewFPO data should be written via addFrameData()!"); + + DbgStreams[(int)Type].emplace(); + DbgStreams[(int)Type]->Size = Data.size(); + DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) { + return Writer.writeArray(Data); + }; + return Error::success(); +} + +uint32_t DbiStreamBuilder::addECName(StringRef Name) { + return ECNamesBuilder.insert(Name); +} + +uint32_t DbiStreamBuilder::calculateSerializedLength() const { + // For now we only support serializing the header. + return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() + + calculateModiSubstreamSize() + calculateSectionContribsStreamSize() + + calculateSectionMapStreamSize() + calculateDbgStreamsSize() + + ECNamesBuilder.calculateSerializedSize(); +} + +Expected<DbiModuleDescriptorBuilder &> +DbiStreamBuilder::addModuleInfo(StringRef ModuleName) { + uint32_t Index = ModiList.size(); + ModiList.push_back( + std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf)); + return *ModiList.back(); +} + +Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module, + StringRef File) { + uint32_t Index = SourceFileNames.size(); + SourceFileNames.insert(std::make_pair(File, Index)); + Module.addSourceFile(File); + return Error::success(); +} + +Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) { + auto NameIter = SourceFileNames.find(File); + if (NameIter == SourceFileNames.end()) + return make_error<RawError>(raw_error_code::no_entry, + "The specified source file was not found"); + return NameIter->getValue(); +} + +uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const { + uint32_t Size = 0; + for (const auto &M : ModiList) + Size += M->calculateSerializedLength(); + return Size; +} + +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::calculateNamesOffset() const { + uint32_t Offset = 0; + Offset += sizeof(ulittle16_t); // NumModules + Offset += sizeof(ulittle16_t); // NumSourceFiles + Offset += ModiList.size() * sizeof(ulittle16_t); // ModIndices + Offset += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts + uint32_t NumFileInfos = 0; + for (const auto &M : ModiList) + NumFileInfos += M->source_files().size(); + Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets + return Offset; +} + +uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const { + uint32_t Size = calculateNamesOffset(); + 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::generateFileInfoSubstream() { + uint32_t Size = calculateFileInfoSubstreamSize(); + auto Data = Allocator.Allocate<uint8_t>(Size); + uint32_t NamesOffset = calculateNamesOffset(); + + FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size), + llvm::support::little); + + WritableBinaryStreamRef MetadataBuffer = + WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); + BinaryStreamWriter MetadataWriter(MetadataBuffer); + + uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size()); + uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size()); + if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules + return EC; + 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 : ModiList) { + FileCount = static_cast<uint16_t>(MI->source_files().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 = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset); + BinaryStreamWriter NameBufferWriter(NamesBuffer); + for (auto &Name : SourceFileNames) { + Name.second = NameBufferWriter.getOffset(); + if (auto EC = NameBufferWriter.writeCString(Name.getKey())) + return EC; + } + + for (const auto &MI : ModiList) { + for (StringRef Name : MI->source_files()) { + auto Result = SourceFileNames.find(Name); + if (Result == SourceFileNames.end()) + return make_error<RawError>(raw_error_code::no_entry, + "The source file was not found."); + if (auto EC = MetadataWriter.writeInteger(Result->second)) + return EC; + } + } + + if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t))) + 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(); + + for (auto &MI : ModiList) + MI->finalize(); + + if (auto EC = generateFileInfoSubstream()) + return EC; + + DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>(); + ::memset(H, 0, sizeof(DbiStreamHeader)); + H->VersionHeader = *VerHeader; + H->VersionSignature = -1; + H->Age = Age; + H->BuildNumber = BuildNumber; + H->Flags = Flags; + H->PdbDllRbld = PdbDllRbld; + H->PdbDllVersion = PdbDllVersion; + H->MachineType = static_cast<uint16_t>(MachineType); + + H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize(); + H->FileInfoSize = FileInfoBuffer.getLength(); + H->ModiSubstreamSize = calculateModiSubstreamSize(); + H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t); + H->SecContrSubstreamSize = calculateSectionContribsStreamSize(); + H->SectionMapSize = calculateSectionMapStreamSize(); + H->TypeServerSize = 0; + H->SymRecordStreamIndex = SymRecordStreamIndex; + H->PublicSymbolStreamIndex = PublicsStreamIndex; + H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0. + H->GlobalSymbolStreamIndex = GlobalsStreamIndex; + + Header = H; + return Error::success(); +} + +Error DbiStreamBuilder::finalizeMsfLayout() { + if (NewFpoData.hasValue()) { + DbgStreams[(int)DbgHeaderType::NewFPO].emplace(); + DbgStreams[(int)DbgHeaderType::NewFPO]->Size = + NewFpoData->calculateSerializedSize(); + DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return NewFpoData->commit(Writer); + }; + } + + if (!OldFpoData.empty()) { + DbgStreams[(int)DbgHeaderType::FPO].emplace(); + DbgStreams[(int)DbgHeaderType::FPO]->Size = + sizeof(object::FpoData) * OldFpoData.size(); + DbgStreams[(int)DbgHeaderType::FPO]->WriteFn = + [this](BinaryStreamWriter &Writer) { + return Writer.writeArray(makeArrayRef(OldFpoData)); + }; + } + + for (auto &S : DbgStreams) { + if (!S.hasValue()) + continue; + auto ExpectedIndex = Msf.addStream(S->Size); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + S->StreamNumber = *ExpectedIndex; + } + + for (auto &MI : ModiList) { + if (auto EC = MI->finalizeMsfLayout()) + return EC; + } + + 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; +} + +// Populate the Section Map from COFF section headers. +// +// 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. +void DbiStreamBuilder::createSectionMap( + ArrayRef<llvm::object::coff_section> SecHdrs) { + int Idx = 0; + + auto Add = [&]() -> SecMapEntry & { + SectionMap.emplace_back(); + auto &Entry = SectionMap.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; +} + +Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef MsfBuffer) { + if (auto EC = finalize()) + return EC; + + auto DbiS = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, StreamDBI, Allocator); + + BinaryStreamWriter Writer(*DbiS); + if (auto EC = Writer.writeObject(*Header)) + return EC; + + for (auto &M : ModiList) { if (auto EC = M->commit(Writer)) - return EC; - } - + return EC; + } + // Commit symbol streams. This is a lot of data, so do it in parallel. if (auto EC = parallelForEachError( ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) { @@ -406,51 +406,51 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, })) return EC; - if (!SectionContribs.empty()) { - if (auto EC = Writer.writeEnum(DbiSecContribVer60)) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(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(makeArrayRef(SectionMap))) - return EC; - } - - if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) - return EC; - - if (auto EC = ECNamesBuilder.commit(Writer)) - return EC; - - for (auto &Stream : DbgStreams) { - uint16_t StreamNumber = kInvalidStreamIndex; - if (Stream.hasValue()) - StreamNumber = Stream->StreamNumber; - if (auto EC = Writer.writeInteger(StreamNumber)) - return EC; - } - - for (auto &Stream : DbgStreams) { - if (!Stream.hasValue()) - continue; - assert(Stream->StreamNumber != kInvalidStreamIndex); - - auto WritableStream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, Stream->StreamNumber, Allocator); - BinaryStreamWriter DbgStreamWriter(*WritableStream); - - if (auto EC = Stream->WriteFn(DbgStreamWriter)) - return EC; - } - - if (Writer.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::invalid_format, - "Unexpected bytes found in DBI Stream"); - return Error::success(); -} + if (!SectionContribs.empty()) { + if (auto EC = Writer.writeEnum(DbiSecContribVer60)) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(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(makeArrayRef(SectionMap))) + return EC; + } + + if (auto EC = Writer.writeStreamRef(FileInfoBuffer)) + return EC; + + if (auto EC = ECNamesBuilder.commit(Writer)) + return EC; + + for (auto &Stream : DbgStreams) { + uint16_t StreamNumber = kInvalidStreamIndex; + if (Stream.hasValue()) + StreamNumber = Stream->StreamNumber; + if (auto EC = Writer.writeInteger(StreamNumber)) + return EC; + } + + for (auto &Stream : DbgStreams) { + if (!Stream.hasValue()) + continue; + assert(Stream->StreamNumber != kInvalidStreamIndex); + + auto WritableStream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, Stream->StreamNumber, Allocator); + BinaryStreamWriter DbgStreamWriter(*WritableStream); + + if (auto EC = Stream->WriteFn(DbgStreamWriter)) + 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/libs/llvm12/lib/DebugInfo/PDB/Native/EnumTables.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/EnumTables.cpp index 37192ba36a..bb7ffe82f0 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/EnumTables.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/EnumTables.cpp @@ -1,37 +1,37 @@ -//===- EnumTables.cpp - Enum to string conversion tables --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/EnumTables.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" - -using namespace llvm; -using namespace llvm::pdb; - -#define PDB_ENUM_CLASS_ENT(enum_class, enum) \ - { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } - -#define PDB_ENUM_ENT(ns, enum) \ - { #enum, ns::enum } - -static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = { - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress), - PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup), -}; - -namespace llvm { -namespace pdb { -ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() { - return makeArrayRef(OMFSegMapDescFlagNames); -} -} -} +//===- EnumTables.cpp - Enum to string conversion tables --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/EnumTables.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" + +using namespace llvm; +using namespace llvm::pdb; + +#define PDB_ENUM_CLASS_ENT(enum_class, enum) \ + { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) } + +#define PDB_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } + +static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = { + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress), + PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup), +}; + +namespace llvm { +namespace pdb { +ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() { + return makeArrayRef(OMFSegMapDescFlagNames); +} +} +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp index 52df26b679..344304a2c1 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp @@ -1,494 +1,494 @@ -//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// 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.cpp -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/Support/BinaryItemStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Parallel.h" -#include "llvm/Support/xxhash.h" -#include <algorithm> -#include <vector> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; -using namespace llvm::codeview; - -// Helper class for building the public and global PDB hash table buckets. -struct llvm::pdb::GSIHashStreamBuilder { - // Sum of the size of all public or global records. - uint32_t RecordByteSize = 0; - - std::vector<PSHashRecord> HashRecords; - - // The hash bitmap has `ceil((IPHR_HASH + 1) / 32)` words in it. The - // reference implementation builds a hash table with IPHR_HASH buckets in it. - // The last bucket is used to link together free hash table cells in a linked - // list, but it is always empty in the compressed, on-disk format. However, - // the bitmap must have a bit for it. - std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap; - - std::vector<support::ulittle32_t> HashBuckets; - - uint32_t calculateSerializedLength() const; - Error commit(BinaryStreamWriter &Writer); - - void finalizePublicBuckets(); - void finalizeGlobalBuckets(uint32_t RecordZeroOffset); - - // Assign public and global symbol records into hash table buckets. - // Modifies the list of records to store the bucket index, but does not - // change the order. - void finalizeBuckets(uint32_t RecordZeroOffset, - MutableArrayRef<BulkPublic> Globals); -}; - -// DenseMapInfo implementation for deduplicating symbol records. -struct llvm::pdb::SymbolDenseMapInfo { - static inline CVSymbol getEmptyKey() { - static CVSymbol Empty; - return Empty; - } - static inline CVSymbol getTombstoneKey() { - static CVSymbol Tombstone( - DenseMapInfo<ArrayRef<uint8_t>>::getTombstoneKey()); - return Tombstone; - } - static unsigned getHashValue(const CVSymbol &Val) { - return xxHash64(Val.RecordData); - } - static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) { - return LHS.RecordData == RHS.RecordData; - } -}; - -namespace { -LLVM_PACKED_START -struct PublicSym32Layout { - RecordPrefix Prefix; - PublicSym32Header Pub; - // char Name[]; -}; -LLVM_PACKED_END -} // namespace - -// Calculate how much memory this public needs when serialized. -static uint32_t sizeOfPublic(const BulkPublic &Pub) { - uint32_t NameLen = Pub.NameLen; - NameLen = std::min(NameLen, - uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1)); - return alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4); -} - -static CVSymbol serializePublic(uint8_t *Mem, const BulkPublic &Pub) { - // Assume the caller has allocated sizeOfPublic bytes. - uint32_t NameLen = std::min( - Pub.NameLen, uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1)); - size_t Size = alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4); - assert(Size == sizeOfPublic(Pub)); - auto *FixedMem = reinterpret_cast<PublicSym32Layout *>(Mem); - FixedMem->Prefix.RecordKind = static_cast<uint16_t>(codeview::S_PUB32); - FixedMem->Prefix.RecordLen = static_cast<uint16_t>(Size - 2); - FixedMem->Pub.Flags = Pub.Flags; - FixedMem->Pub.Offset = Pub.Offset; - FixedMem->Pub.Segment = Pub.Segment; - char *NameMem = reinterpret_cast<char *>(FixedMem + 1); - memcpy(NameMem, Pub.Name, NameLen); - // Zero the null terminator and remaining bytes. - memset(&NameMem[NameLen], 0, Size - sizeof(PublicSym32Layout) - NameLen); - return CVSymbol(makeArrayRef(reinterpret_cast<uint8_t *>(Mem), Size)); -} - -uint32_t GSIHashStreamBuilder::calculateSerializedLength() const { - uint32_t Size = sizeof(GSIHashHeader); - Size += HashRecords.size() * sizeof(PSHashRecord); - Size += HashBitmap.size() * sizeof(uint32_t); - Size += HashBuckets.size() * sizeof(uint32_t); - return Size; -} - -Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) { - GSIHashHeader Header; - Header.VerSignature = GSIHashHeader::HdrSignature; - Header.VerHdr = GSIHashHeader::HdrVersion; - Header.HrSize = HashRecords.size() * sizeof(PSHashRecord); - Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4; - - if (auto EC = Writer.writeObject(Header)) - return EC; - - if (auto EC = Writer.writeArray(makeArrayRef(HashRecords))) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap))) - return EC; - if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets))) - return EC; - return Error::success(); -} - -static bool isAsciiString(StringRef S) { - return llvm::all_of(S, [](char C) { return unsigned(C) < 0x80; }); -} - -// See `caseInsensitiveComparePchPchCchCch` in gsi.cpp -static int gsiRecordCmp(StringRef S1, StringRef S2) { - size_t LS = S1.size(); - size_t RS = S2.size(); - // Shorter strings always compare less than longer strings. - if (LS != RS) - return LS - RS; - - // If either string contains non ascii characters, memcmp them. - if (LLVM_UNLIKELY(!isAsciiString(S1) || !isAsciiString(S2))) - return memcmp(S1.data(), S2.data(), LS); - +//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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.cpp +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Parallel.h" +#include "llvm/Support/xxhash.h" +#include <algorithm> +#include <vector> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::codeview; + +// Helper class for building the public and global PDB hash table buckets. +struct llvm::pdb::GSIHashStreamBuilder { + // Sum of the size of all public or global records. + uint32_t RecordByteSize = 0; + + std::vector<PSHashRecord> HashRecords; + + // The hash bitmap has `ceil((IPHR_HASH + 1) / 32)` words in it. The + // reference implementation builds a hash table with IPHR_HASH buckets in it. + // The last bucket is used to link together free hash table cells in a linked + // list, but it is always empty in the compressed, on-disk format. However, + // the bitmap must have a bit for it. + std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap; + + std::vector<support::ulittle32_t> HashBuckets; + + uint32_t calculateSerializedLength() const; + Error commit(BinaryStreamWriter &Writer); + + void finalizePublicBuckets(); + void finalizeGlobalBuckets(uint32_t RecordZeroOffset); + + // Assign public and global symbol records into hash table buckets. + // Modifies the list of records to store the bucket index, but does not + // change the order. + void finalizeBuckets(uint32_t RecordZeroOffset, + MutableArrayRef<BulkPublic> Globals); +}; + +// DenseMapInfo implementation for deduplicating symbol records. +struct llvm::pdb::SymbolDenseMapInfo { + static inline CVSymbol getEmptyKey() { + static CVSymbol Empty; + return Empty; + } + static inline CVSymbol getTombstoneKey() { + static CVSymbol Tombstone( + DenseMapInfo<ArrayRef<uint8_t>>::getTombstoneKey()); + return Tombstone; + } + static unsigned getHashValue(const CVSymbol &Val) { + return xxHash64(Val.RecordData); + } + static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) { + return LHS.RecordData == RHS.RecordData; + } +}; + +namespace { +LLVM_PACKED_START +struct PublicSym32Layout { + RecordPrefix Prefix; + PublicSym32Header Pub; + // char Name[]; +}; +LLVM_PACKED_END +} // namespace + +// Calculate how much memory this public needs when serialized. +static uint32_t sizeOfPublic(const BulkPublic &Pub) { + uint32_t NameLen = Pub.NameLen; + NameLen = std::min(NameLen, + uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1)); + return alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4); +} + +static CVSymbol serializePublic(uint8_t *Mem, const BulkPublic &Pub) { + // Assume the caller has allocated sizeOfPublic bytes. + uint32_t NameLen = std::min( + Pub.NameLen, uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1)); + size_t Size = alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4); + assert(Size == sizeOfPublic(Pub)); + auto *FixedMem = reinterpret_cast<PublicSym32Layout *>(Mem); + FixedMem->Prefix.RecordKind = static_cast<uint16_t>(codeview::S_PUB32); + FixedMem->Prefix.RecordLen = static_cast<uint16_t>(Size - 2); + FixedMem->Pub.Flags = Pub.Flags; + FixedMem->Pub.Offset = Pub.Offset; + FixedMem->Pub.Segment = Pub.Segment; + char *NameMem = reinterpret_cast<char *>(FixedMem + 1); + memcpy(NameMem, Pub.Name, NameLen); + // Zero the null terminator and remaining bytes. + memset(&NameMem[NameLen], 0, Size - sizeof(PublicSym32Layout) - NameLen); + return CVSymbol(makeArrayRef(reinterpret_cast<uint8_t *>(Mem), Size)); +} + +uint32_t GSIHashStreamBuilder::calculateSerializedLength() const { + uint32_t Size = sizeof(GSIHashHeader); + Size += HashRecords.size() * sizeof(PSHashRecord); + Size += HashBitmap.size() * sizeof(uint32_t); + Size += HashBuckets.size() * sizeof(uint32_t); + return Size; +} + +Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) { + GSIHashHeader Header; + Header.VerSignature = GSIHashHeader::HdrSignature; + Header.VerHdr = GSIHashHeader::HdrVersion; + Header.HrSize = HashRecords.size() * sizeof(PSHashRecord); + Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4; + + if (auto EC = Writer.writeObject(Header)) + return EC; + + if (auto EC = Writer.writeArray(makeArrayRef(HashRecords))) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap))) + return EC; + if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets))) + return EC; + return Error::success(); +} + +static bool isAsciiString(StringRef S) { + return llvm::all_of(S, [](char C) { return unsigned(C) < 0x80; }); +} + +// See `caseInsensitiveComparePchPchCchCch` in gsi.cpp +static int gsiRecordCmp(StringRef S1, StringRef S2) { + size_t LS = S1.size(); + size_t RS = S2.size(); + // Shorter strings always compare less than longer strings. + if (LS != RS) + return LS - RS; + + // If either string contains non ascii characters, memcmp them. + if (LLVM_UNLIKELY(!isAsciiString(S1) || !isAsciiString(S2))) + return memcmp(S1.data(), S2.data(), LS); + // Both strings are ascii, perform a case-insensitive comparison. - return S1.compare_lower(S2.data()); -} - -void GSIStreamBuilder::finalizePublicBuckets() { - PSH->finalizeBuckets(0, Publics); -} - -void GSIStreamBuilder::finalizeGlobalBuckets(uint32_t RecordZeroOffset) { - // Build up a list of globals to be bucketed. Use the BulkPublic data - // structure for this purpose, even though these are global records, not - // public records. Most of the same fields are required: - // - Name - // - NameLen - // - SymOffset - // - BucketIdx - // The dead fields are Offset, Segment, and Flags. - std::vector<BulkPublic> Records; - Records.resize(Globals.size()); - uint32_t SymOffset = RecordZeroOffset; - for (size_t I = 0, E = Globals.size(); I < E; ++I) { - StringRef Name = getSymbolName(Globals[I]); - Records[I].Name = Name.data(); - Records[I].NameLen = Name.size(); - Records[I].SymOffset = SymOffset; - SymOffset += Globals[I].length(); - } - - GSH->finalizeBuckets(RecordZeroOffset, Records); -} - -void GSIHashStreamBuilder::finalizeBuckets( - uint32_t RecordZeroOffset, MutableArrayRef<BulkPublic> Records) { - // Hash every name in parallel. - parallelForEachN(0, Records.size(), [&](size_t I) { - Records[I].setBucketIdx(hashStringV1(Records[I].Name) % IPHR_HASH); - }); - - // Count up the size of each bucket. Then, use an exclusive prefix sum to - // calculate the bucket start offsets. This is C++17 std::exclusive_scan, but - // we can't use it yet. - uint32_t BucketStarts[IPHR_HASH] = {0}; - for (const BulkPublic &P : Records) - ++BucketStarts[P.BucketIdx]; - uint32_t Sum = 0; - for (uint32_t &B : BucketStarts) { - uint32_t Size = B; - B = Sum; - Sum += Size; - } - - // Place globals into the hash table in bucket order. When placing a global, - // update the bucket start. Every hash table slot should be filled. Always use - // a refcount of one for now. - HashRecords.resize(Records.size()); - uint32_t BucketCursors[IPHR_HASH]; - memcpy(BucketCursors, BucketStarts, sizeof(BucketCursors)); - for (int I = 0, E = Records.size(); I < E; ++I) { - uint32_t HashIdx = BucketCursors[Records[I].BucketIdx]++; - HashRecords[HashIdx].Off = I; - HashRecords[HashIdx].CRef = 1; - } - - // Within the buckets, sort each bucket by memcmp of the symbol's name. It's - // important that we use the same sorting algorithm as is used by the - // reference implementation to ensure that the search for a record within a - // bucket can properly early-out when it detects the record won't be found. - // The algorithm used here corresponds to the function - // caseInsensitiveComparePchPchCchCch in the reference implementation. - parallelForEachN(0, IPHR_HASH, [&](size_t I) { - auto B = HashRecords.begin() + BucketStarts[I]; - auto E = HashRecords.begin() + BucketCursors[I]; - if (B == E) - return; - auto BucketCmp = [Records](const PSHashRecord &LHash, - const PSHashRecord &RHash) { - const BulkPublic &L = Records[uint32_t(LHash.Off)]; - const BulkPublic &R = Records[uint32_t(RHash.Off)]; - assert(L.BucketIdx == R.BucketIdx); - int Cmp = gsiRecordCmp(L.getName(), R.getName()); - if (Cmp != 0) - return Cmp < 0; - // This comparison is necessary to make the sorting stable in the presence - // of two static globals with the same name. The easiest way to observe - // this is with S_LDATA32 records. - return L.SymOffset < R.SymOffset; - }; - llvm::sort(B, E, BucketCmp); - - // After we are done sorting, replace the global indices with the stream - // offsets of each global. Add one when writing symbol offsets to disk. - // See GSI1::fixSymRecs. - for (PSHashRecord &HRec : make_range(B, E)) - HRec.Off = Records[uint32_t(HRec.Off)].SymOffset + 1; - }); - - // For each non-empty bucket, push the bucket start offset into HashBuckets - // and set a bit in the hash bitmap. - for (uint32_t I = 0; I < HashBitmap.size(); ++I) { - uint32_t Word = 0; - for (uint32_t J = 0; J < 32; ++J) { - // Skip empty buckets. - uint32_t BucketIdx = I * 32 + J; - if (BucketIdx >= IPHR_HASH || - BucketStarts[BucketIdx] == BucketCursors[BucketIdx]) - continue; - Word |= (1U << J); - - // Calculate what the offset of the first hash record in the chain would - // be if it were inflated to contain 32-bit pointers. On a 32-bit system, - // each record would be 12 bytes. See HROffsetCalc in gsi.h. - const int SizeOfHROffsetCalc = 12; - ulittle32_t ChainStartOff = - ulittle32_t(BucketStarts[BucketIdx] * SizeOfHROffsetCalc); - HashBuckets.push_back(ChainStartOff); - } - HashBitmap[I] = Word; - } -} - -GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf) - : Msf(Msf), PSH(std::make_unique<GSIHashStreamBuilder>()), - GSH(std::make_unique<GSIHashStreamBuilder>()) {} - -GSIStreamBuilder::~GSIStreamBuilder() {} - -uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const { - uint32_t Size = 0; - Size += sizeof(PublicsStreamHeader); - Size += PSH->calculateSerializedLength(); - Size += Publics.size() * sizeof(uint32_t); // AddrMap - // FIXME: Add thunk map and section offsets for incremental linking. - - return Size; -} - -uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const { - return GSH->calculateSerializedLength(); -} - -Error GSIStreamBuilder::finalizeMsfLayout() { - // First we write public symbol records, then we write global symbol records. - finalizePublicBuckets(); - finalizeGlobalBuckets(PSH->RecordByteSize); - - Expected<uint32_t> Idx = Msf.addStream(calculateGlobalsHashStreamSize()); - if (!Idx) - return Idx.takeError(); - GlobalsStreamIndex = *Idx; - - Idx = Msf.addStream(calculatePublicsHashStreamSize()); - if (!Idx) - return Idx.takeError(); - PublicsStreamIndex = *Idx; - - uint32_t RecordBytes = PSH->RecordByteSize + GSH->RecordByteSize; - - Idx = Msf.addStream(RecordBytes); - if (!Idx) - return Idx.takeError(); - RecordStreamIndex = *Idx; - return Error::success(); -} - -void GSIStreamBuilder::addPublicSymbols(std::vector<BulkPublic> &&PublicsIn) { - assert(Publics.empty() && PSH->RecordByteSize == 0 && - "publics can only be added once"); - Publics = std::move(PublicsIn); - - // Sort the symbols by name. PDBs contain lots of symbols, so use parallelism. - parallelSort(Publics, [](const BulkPublic &L, const BulkPublic &R) { - return L.getName() < R.getName(); - }); - - // Assign offsets and calculate the length of the public symbol records. - uint32_t SymOffset = 0; - for (BulkPublic &Pub : Publics) { - Pub.SymOffset = SymOffset; - SymOffset += sizeOfPublic(Pub); - } - - // Remember the length of the public stream records. - PSH->RecordByteSize = SymOffset; -} - -void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) { - serializeAndAddGlobal(Sym); -} - -void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) { - serializeAndAddGlobal(Sym); -} - -void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) { - serializeAndAddGlobal(Sym); -} - -template <typename T> -void GSIStreamBuilder::serializeAndAddGlobal(const T &Symbol) { - T Copy(Symbol); - addGlobalSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), - CodeViewContainer::Pdb)); -} - -void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Symbol) { - // Ignore duplicate typedefs and constants. - if (Symbol.kind() == S_UDT || Symbol.kind() == S_CONSTANT) { - auto Iter = GlobalsSeen.insert(Symbol); - if (!Iter.second) - return; - } - GSH->RecordByteSize += Symbol.length(); - Globals.push_back(Symbol); -} - -// Serialize each public and write it. -static Error writePublics(BinaryStreamWriter &Writer, - ArrayRef<BulkPublic> Publics) { - std::vector<uint8_t> Storage; - for (const BulkPublic &Pub : Publics) { - Storage.resize(sizeOfPublic(Pub)); - serializePublic(Storage.data(), Pub); - if (Error E = Writer.writeBytes(Storage)) - return E; - } - return Error::success(); -} - -static Error writeRecords(BinaryStreamWriter &Writer, - ArrayRef<CVSymbol> Records) { - BinaryItemStream<CVSymbol> ItemStream(support::endianness::little); - ItemStream.setItems(Records); - BinaryStreamRef RecordsRef(ItemStream); - return Writer.writeStreamRef(RecordsRef); -} - -Error GSIStreamBuilder::commitSymbolRecordStream( - WritableBinaryStreamRef Stream) { - BinaryStreamWriter Writer(Stream); - - // Write public symbol records first, followed by global symbol records. This - // must match the order that we assume in finalizeMsfLayout when computing - // PSHZero and GSHZero. - if (auto EC = writePublics(Writer, Publics)) - return EC; - if (auto EC = writeRecords(Writer, Globals)) - return EC; - - return Error::success(); -} - -static std::vector<support::ulittle32_t> -computeAddrMap(ArrayRef<BulkPublic> Publics) { - // Build a parallel vector of indices into the Publics vector, and sort it by - // address. - std::vector<ulittle32_t> PubAddrMap; - PubAddrMap.reserve(Publics.size()); - for (int I = 0, E = Publics.size(); I < E; ++I) - PubAddrMap.push_back(ulittle32_t(I)); - - auto AddrCmp = [Publics](const ulittle32_t &LIdx, const ulittle32_t &RIdx) { - const BulkPublic &L = Publics[LIdx]; - const BulkPublic &R = Publics[RIdx]; - if (L.Segment != R.Segment) - return L.Segment < R.Segment; - if (L.Offset != R.Offset) - return L.Offset < R.Offset; - // parallelSort is unstable, so we have to do name comparison to ensure - // that two names for the same location come out in a deterministic order. - return L.getName() < R.getName(); - }; - parallelSort(PubAddrMap, AddrCmp); - - // Rewrite the public symbol indices into symbol offsets. - for (ulittle32_t &Entry : PubAddrMap) - Entry = Publics[Entry].SymOffset; - return PubAddrMap; -} - -Error GSIStreamBuilder::commitPublicsHashStream( - WritableBinaryStreamRef Stream) { - BinaryStreamWriter Writer(Stream); - PublicsStreamHeader Header; - - // FIXME: Fill these in. They are for incremental linking. - Header.SymHash = PSH->calculateSerializedLength(); - Header.AddrMap = Publics.size() * 4; - Header.NumThunks = 0; - Header.SizeOfThunk = 0; - Header.ISectThunkTable = 0; - memset(Header.Padding, 0, sizeof(Header.Padding)); - Header.OffThunkTable = 0; - Header.NumSections = 0; - if (auto EC = Writer.writeObject(Header)) - return EC; - - if (auto EC = PSH->commit(Writer)) - return EC; - - std::vector<support::ulittle32_t> PubAddrMap = computeAddrMap(Publics); - assert(PubAddrMap.size() == Publics.size()); - if (auto EC = Writer.writeArray(makeArrayRef(PubAddrMap))) - return EC; - - return Error::success(); -} - -Error GSIStreamBuilder::commitGlobalsHashStream( - WritableBinaryStreamRef Stream) { - BinaryStreamWriter Writer(Stream); - return GSH->commit(Writer); -} - -Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout, - WritableBinaryStreamRef Buffer) { - auto GS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator()); - auto PS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator()); - auto PRS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, getRecordStreamIndex(), Msf.getAllocator()); - - if (auto EC = commitSymbolRecordStream(*PRS)) - return EC; - if (auto EC = commitGlobalsHashStream(*GS)) - return EC; - if (auto EC = commitPublicsHashStream(*PS)) - return EC; - return Error::success(); -} + return S1.compare_lower(S2.data()); +} + +void GSIStreamBuilder::finalizePublicBuckets() { + PSH->finalizeBuckets(0, Publics); +} + +void GSIStreamBuilder::finalizeGlobalBuckets(uint32_t RecordZeroOffset) { + // Build up a list of globals to be bucketed. Use the BulkPublic data + // structure for this purpose, even though these are global records, not + // public records. Most of the same fields are required: + // - Name + // - NameLen + // - SymOffset + // - BucketIdx + // The dead fields are Offset, Segment, and Flags. + std::vector<BulkPublic> Records; + Records.resize(Globals.size()); + uint32_t SymOffset = RecordZeroOffset; + for (size_t I = 0, E = Globals.size(); I < E; ++I) { + StringRef Name = getSymbolName(Globals[I]); + Records[I].Name = Name.data(); + Records[I].NameLen = Name.size(); + Records[I].SymOffset = SymOffset; + SymOffset += Globals[I].length(); + } + + GSH->finalizeBuckets(RecordZeroOffset, Records); +} + +void GSIHashStreamBuilder::finalizeBuckets( + uint32_t RecordZeroOffset, MutableArrayRef<BulkPublic> Records) { + // Hash every name in parallel. + parallelForEachN(0, Records.size(), [&](size_t I) { + Records[I].setBucketIdx(hashStringV1(Records[I].Name) % IPHR_HASH); + }); + + // Count up the size of each bucket. Then, use an exclusive prefix sum to + // calculate the bucket start offsets. This is C++17 std::exclusive_scan, but + // we can't use it yet. + uint32_t BucketStarts[IPHR_HASH] = {0}; + for (const BulkPublic &P : Records) + ++BucketStarts[P.BucketIdx]; + uint32_t Sum = 0; + for (uint32_t &B : BucketStarts) { + uint32_t Size = B; + B = Sum; + Sum += Size; + } + + // Place globals into the hash table in bucket order. When placing a global, + // update the bucket start. Every hash table slot should be filled. Always use + // a refcount of one for now. + HashRecords.resize(Records.size()); + uint32_t BucketCursors[IPHR_HASH]; + memcpy(BucketCursors, BucketStarts, sizeof(BucketCursors)); + for (int I = 0, E = Records.size(); I < E; ++I) { + uint32_t HashIdx = BucketCursors[Records[I].BucketIdx]++; + HashRecords[HashIdx].Off = I; + HashRecords[HashIdx].CRef = 1; + } + + // Within the buckets, sort each bucket by memcmp of the symbol's name. It's + // important that we use the same sorting algorithm as is used by the + // reference implementation to ensure that the search for a record within a + // bucket can properly early-out when it detects the record won't be found. + // The algorithm used here corresponds to the function + // caseInsensitiveComparePchPchCchCch in the reference implementation. + parallelForEachN(0, IPHR_HASH, [&](size_t I) { + auto B = HashRecords.begin() + BucketStarts[I]; + auto E = HashRecords.begin() + BucketCursors[I]; + if (B == E) + return; + auto BucketCmp = [Records](const PSHashRecord &LHash, + const PSHashRecord &RHash) { + const BulkPublic &L = Records[uint32_t(LHash.Off)]; + const BulkPublic &R = Records[uint32_t(RHash.Off)]; + assert(L.BucketIdx == R.BucketIdx); + int Cmp = gsiRecordCmp(L.getName(), R.getName()); + if (Cmp != 0) + return Cmp < 0; + // This comparison is necessary to make the sorting stable in the presence + // of two static globals with the same name. The easiest way to observe + // this is with S_LDATA32 records. + return L.SymOffset < R.SymOffset; + }; + llvm::sort(B, E, BucketCmp); + + // After we are done sorting, replace the global indices with the stream + // offsets of each global. Add one when writing symbol offsets to disk. + // See GSI1::fixSymRecs. + for (PSHashRecord &HRec : make_range(B, E)) + HRec.Off = Records[uint32_t(HRec.Off)].SymOffset + 1; + }); + + // For each non-empty bucket, push the bucket start offset into HashBuckets + // and set a bit in the hash bitmap. + for (uint32_t I = 0; I < HashBitmap.size(); ++I) { + uint32_t Word = 0; + for (uint32_t J = 0; J < 32; ++J) { + // Skip empty buckets. + uint32_t BucketIdx = I * 32 + J; + if (BucketIdx >= IPHR_HASH || + BucketStarts[BucketIdx] == BucketCursors[BucketIdx]) + continue; + Word |= (1U << J); + + // Calculate what the offset of the first hash record in the chain would + // be if it were inflated to contain 32-bit pointers. On a 32-bit system, + // each record would be 12 bytes. See HROffsetCalc in gsi.h. + const int SizeOfHROffsetCalc = 12; + ulittle32_t ChainStartOff = + ulittle32_t(BucketStarts[BucketIdx] * SizeOfHROffsetCalc); + HashBuckets.push_back(ChainStartOff); + } + HashBitmap[I] = Word; + } +} + +GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf) + : Msf(Msf), PSH(std::make_unique<GSIHashStreamBuilder>()), + GSH(std::make_unique<GSIHashStreamBuilder>()) {} + +GSIStreamBuilder::~GSIStreamBuilder() {} + +uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const { + uint32_t Size = 0; + Size += sizeof(PublicsStreamHeader); + Size += PSH->calculateSerializedLength(); + Size += Publics.size() * sizeof(uint32_t); // AddrMap + // FIXME: Add thunk map and section offsets for incremental linking. + + return Size; +} + +uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const { + return GSH->calculateSerializedLength(); +} + +Error GSIStreamBuilder::finalizeMsfLayout() { + // First we write public symbol records, then we write global symbol records. + finalizePublicBuckets(); + finalizeGlobalBuckets(PSH->RecordByteSize); + + Expected<uint32_t> Idx = Msf.addStream(calculateGlobalsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + GlobalsStreamIndex = *Idx; + + Idx = Msf.addStream(calculatePublicsHashStreamSize()); + if (!Idx) + return Idx.takeError(); + PublicsStreamIndex = *Idx; + + uint32_t RecordBytes = PSH->RecordByteSize + GSH->RecordByteSize; + + Idx = Msf.addStream(RecordBytes); + if (!Idx) + return Idx.takeError(); + RecordStreamIndex = *Idx; + return Error::success(); +} + +void GSIStreamBuilder::addPublicSymbols(std::vector<BulkPublic> &&PublicsIn) { + assert(Publics.empty() && PSH->RecordByteSize == 0 && + "publics can only be added once"); + Publics = std::move(PublicsIn); + + // Sort the symbols by name. PDBs contain lots of symbols, so use parallelism. + parallelSort(Publics, [](const BulkPublic &L, const BulkPublic &R) { + return L.getName() < R.getName(); + }); + + // Assign offsets and calculate the length of the public symbol records. + uint32_t SymOffset = 0; + for (BulkPublic &Pub : Publics) { + Pub.SymOffset = SymOffset; + SymOffset += sizeOfPublic(Pub); + } + + // Remember the length of the public stream records. + PSH->RecordByteSize = SymOffset; +} + +void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) { + serializeAndAddGlobal(Sym); +} + +void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) { + serializeAndAddGlobal(Sym); +} + +void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) { + serializeAndAddGlobal(Sym); +} + +template <typename T> +void GSIStreamBuilder::serializeAndAddGlobal(const T &Symbol) { + T Copy(Symbol); + addGlobalSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(), + CodeViewContainer::Pdb)); +} + +void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Symbol) { + // Ignore duplicate typedefs and constants. + if (Symbol.kind() == S_UDT || Symbol.kind() == S_CONSTANT) { + auto Iter = GlobalsSeen.insert(Symbol); + if (!Iter.second) + return; + } + GSH->RecordByteSize += Symbol.length(); + Globals.push_back(Symbol); +} + +// Serialize each public and write it. +static Error writePublics(BinaryStreamWriter &Writer, + ArrayRef<BulkPublic> Publics) { + std::vector<uint8_t> Storage; + for (const BulkPublic &Pub : Publics) { + Storage.resize(sizeOfPublic(Pub)); + serializePublic(Storage.data(), Pub); + if (Error E = Writer.writeBytes(Storage)) + return E; + } + return Error::success(); +} + +static Error writeRecords(BinaryStreamWriter &Writer, + ArrayRef<CVSymbol> Records) { + BinaryItemStream<CVSymbol> ItemStream(support::endianness::little); + ItemStream.setItems(Records); + BinaryStreamRef RecordsRef(ItemStream); + return Writer.writeStreamRef(RecordsRef); +} + +Error GSIStreamBuilder::commitSymbolRecordStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + + // Write public symbol records first, followed by global symbol records. This + // must match the order that we assume in finalizeMsfLayout when computing + // PSHZero and GSHZero. + if (auto EC = writePublics(Writer, Publics)) + return EC; + if (auto EC = writeRecords(Writer, Globals)) + return EC; + + return Error::success(); +} + +static std::vector<support::ulittle32_t> +computeAddrMap(ArrayRef<BulkPublic> Publics) { + // Build a parallel vector of indices into the Publics vector, and sort it by + // address. + std::vector<ulittle32_t> PubAddrMap; + PubAddrMap.reserve(Publics.size()); + for (int I = 0, E = Publics.size(); I < E; ++I) + PubAddrMap.push_back(ulittle32_t(I)); + + auto AddrCmp = [Publics](const ulittle32_t &LIdx, const ulittle32_t &RIdx) { + const BulkPublic &L = Publics[LIdx]; + const BulkPublic &R = Publics[RIdx]; + if (L.Segment != R.Segment) + return L.Segment < R.Segment; + if (L.Offset != R.Offset) + return L.Offset < R.Offset; + // parallelSort is unstable, so we have to do name comparison to ensure + // that two names for the same location come out in a deterministic order. + return L.getName() < R.getName(); + }; + parallelSort(PubAddrMap, AddrCmp); + + // Rewrite the public symbol indices into symbol offsets. + for (ulittle32_t &Entry : PubAddrMap) + Entry = Publics[Entry].SymOffset; + return PubAddrMap; +} + +Error GSIStreamBuilder::commitPublicsHashStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + PublicsStreamHeader Header; + + // FIXME: Fill these in. They are for incremental linking. + Header.SymHash = PSH->calculateSerializedLength(); + Header.AddrMap = Publics.size() * 4; + Header.NumThunks = 0; + Header.SizeOfThunk = 0; + Header.ISectThunkTable = 0; + memset(Header.Padding, 0, sizeof(Header.Padding)); + Header.OffThunkTable = 0; + Header.NumSections = 0; + if (auto EC = Writer.writeObject(Header)) + return EC; + + if (auto EC = PSH->commit(Writer)) + return EC; + + std::vector<support::ulittle32_t> PubAddrMap = computeAddrMap(Publics); + assert(PubAddrMap.size() == Publics.size()); + if (auto EC = Writer.writeArray(makeArrayRef(PubAddrMap))) + return EC; + + return Error::success(); +} + +Error GSIStreamBuilder::commitGlobalsHashStream( + WritableBinaryStreamRef Stream) { + BinaryStreamWriter Writer(Stream); + return GSH->commit(Writer); +} + +Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef Buffer) { + auto GS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator()); + auto PS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator()); + auto PRS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, getRecordStreamIndex(), Msf.getAllocator()); + + if (auto EC = commitSymbolRecordStream(*PRS)) + return EC; + if (auto EC = commitGlobalsHashStream(*GS)) + return EC; + if (auto EC = commitPublicsHashStream(*PS)) + return EC; + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GlobalsStream.cpp index f27d60f468..68344075d0 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GlobalsStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -1,181 +1,181 @@ -//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// The on-disk structores used 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. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" - -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" -#include "llvm/Support/BinaryStreamReader.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() { - BinaryStreamReader Reader(*Stream); - if (auto E = GlobalsTable.read(Reader)) - return E; - return Error::success(); -} - -std::vector<std::pair<uint32_t, codeview::CVSymbol>> -GlobalsStream::findRecordsByName(StringRef Name, - const SymbolStream &Symbols) const { - std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result; - - // Hash the name to figure out which bucket this goes into. - size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH; - int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex]; - if (CompressedBucketIndex == -1) - return Result; - - uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1; - uint32_t StartRecordIndex = - GlobalsTable.HashBuckets[CompressedBucketIndex] / 12; - uint32_t EndRecordIndex = 0; - if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) { - EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1]; - } else { - // If this is the last bucket, it consists of all hash records until the end - // of the HashRecords array. - EndRecordIndex = GlobalsTable.HashRecords.size() * 12; - } - - EndRecordIndex /= 12; - - assert(EndRecordIndex <= GlobalsTable.HashRecords.size()); - while (StartRecordIndex < EndRecordIndex) { - PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex]; - uint32_t Off = PSH.Off - 1; - codeview::CVSymbol Record = Symbols.readRecord(Off); - if (codeview::getSymbolName(Record) == Name) - Result.push_back(std::make_pair(Off, std::move(Record))); - ++StartRecordIndex; - } - return Result; -} - -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(); -} - -static Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - BinaryStreamReader &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(); -} - -static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, - const GSIHashHeader *HashHdr, - BinaryStreamReader &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(); -} - -static Error -readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, - FixedStreamArray<support::ulittle32_t> &HashBitmap, - const GSIHashHeader *HashHdr, - MutableArrayRef<int32_t> BucketMap, - BinaryStreamReader &Reader) { - if (auto EC = checkHashHdrVersion(HashHdr)) - return EC; - - // Before the actual hash buckets, there is a bitmap of length determined by - // IPHR_HASH. - size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); - uint32_t NumBitmapEntries = BitmapSizeInBits / 32; - if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read a bitmap.")); - uint32_t NumBuckets1 = 0; - uint32_t CompressedBucketIdx = 0; - for (uint32_t I = 0; I <= IPHR_HASH; ++I) { - uint8_t WordIdx = I / 32; - uint8_t BitIdx = I % 32; - bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx); - if (IsSet) { - ++NumBuckets1; - BucketMap[I] = CompressedBucketIdx++; - } else { - BucketMap[I] = -1; - } - } - - uint32_t NumBuckets = 0; - for (uint32_t B : HashBitmap) - 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 GSIHashTable::read(BinaryStreamReader &Reader) { - if (auto EC = readGSIHashHeader(HashHdr, Reader)) - return EC; - if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) - return EC; - if (HashHdr->HrSize > 0) - if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, - BucketMap, Reader)) - return EC; - return Error::success(); -} +//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// The on-disk structores used 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" + +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/Support/BinaryStreamReader.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() { + BinaryStreamReader Reader(*Stream); + if (auto E = GlobalsTable.read(Reader)) + return E; + return Error::success(); +} + +std::vector<std::pair<uint32_t, codeview::CVSymbol>> +GlobalsStream::findRecordsByName(StringRef Name, + const SymbolStream &Symbols) const { + std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result; + + // Hash the name to figure out which bucket this goes into. + size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH; + int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex]; + if (CompressedBucketIndex == -1) + return Result; + + uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1; + uint32_t StartRecordIndex = + GlobalsTable.HashBuckets[CompressedBucketIndex] / 12; + uint32_t EndRecordIndex = 0; + if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) { + EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1]; + } else { + // If this is the last bucket, it consists of all hash records until the end + // of the HashRecords array. + EndRecordIndex = GlobalsTable.HashRecords.size() * 12; + } + + EndRecordIndex /= 12; + + assert(EndRecordIndex <= GlobalsTable.HashRecords.size()); + while (StartRecordIndex < EndRecordIndex) { + PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex]; + uint32_t Off = PSH.Off - 1; + codeview::CVSymbol Record = Symbols.readRecord(Off); + if (codeview::getSymbolName(Record) == Name) + Result.push_back(std::make_pair(Off, std::move(Record))); + ++StartRecordIndex; + } + return Result; +} + +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(); +} + +static Error readGSIHashHeader(const GSIHashHeader *&HashHdr, + BinaryStreamReader &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(); +} + +static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, + const GSIHashHeader *HashHdr, + BinaryStreamReader &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(); +} + +static Error +readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, + FixedStreamArray<support::ulittle32_t> &HashBitmap, + const GSIHashHeader *HashHdr, + MutableArrayRef<int32_t> BucketMap, + BinaryStreamReader &Reader) { + if (auto EC = checkHashHdrVersion(HashHdr)) + return EC; + + // Before the actual hash buckets, there is a bitmap of length determined by + // IPHR_HASH. + size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); + uint32_t NumBitmapEntries = BitmapSizeInBits / 32; + if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a bitmap.")); + uint32_t NumBuckets1 = 0; + uint32_t CompressedBucketIdx = 0; + for (uint32_t I = 0; I <= IPHR_HASH; ++I) { + uint8_t WordIdx = I / 32; + uint8_t BitIdx = I % 32; + bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx); + if (IsSet) { + ++NumBuckets1; + BucketMap[I] = CompressedBucketIdx++; + } else { + BucketMap[I] = -1; + } + } + + uint32_t NumBuckets = 0; + for (uint32_t B : HashBitmap) + 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 GSIHashTable::read(BinaryStreamReader &Reader) { + if (auto EC = readGSIHashHeader(HashHdr, Reader)) + return EC; + if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) + return EC; + if (HashHdr->HrSize > 0) + if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, + BucketMap, Reader)) + return EC; + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/Hash.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/Hash.cpp index 7fb6b4bd5d..7f0c15527d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/Hash.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/Hash.cpp @@ -1,84 +1,84 @@ -//===- Hash.cpp - PDB Hash Functions --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/CRC.h" -#include "llvm/Support/Endian.h" -#include <cstdint> - -using namespace llvm; -using namespace llvm::support; - -// Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h. -// Used for name hash table and TPI/IPI hashes. -uint32_t pdb::hashStringV1(StringRef Str) { - uint32_t Result = 0; - uint32_t Size = Str.size(); - - ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()), - Size / 4); - - for (auto Value : Longs) - Result ^= Value; - - const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end()); - uint32_t RemainderSize = Size % 4; - - // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the - // possibly remaining 1 byte. - if (RemainderSize >= 2) { - uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder); - Result ^= static_cast<uint32_t>(Value); - Remainder += 2; - RemainderSize -= 2; - } - - // hash possible odd byte - if (RemainderSize == 1) { - Result ^= *(Remainder++); - } - - const uint32_t toLowerMask = 0x20202020; - Result |= toLowerMask; - Result ^= (Result >> 11); - - return Result ^ (Result >> 16); -} - -// Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h. -// Used for name hash table. -uint32_t pdb::hashStringV2(StringRef Str) { - uint32_t Hash = 0xb170a1bf; - - ArrayRef<char> Buffer(Str.begin(), Str.end()); - - ArrayRef<ulittle32_t> Items( - reinterpret_cast<const ulittle32_t *>(Buffer.data()), - Buffer.size() / sizeof(ulittle32_t)); - for (ulittle32_t Item : Items) { - Hash += Item; - Hash += (Hash << 10); - Hash ^= (Hash >> 6); - } - Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t)); - for (uint8_t Item : Buffer) { - Hash += Item; - Hash += (Hash << 10); - Hash ^= (Hash >> 6); - } - - return Hash * 1664525U + 1013904223U; -} - -// Corresponds to `SigForPbCb` in langapi/shared/crc32.h. -uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) { - JamCRC JC(/*Init=*/0U); - JC.update(Buf); - return JC.getCRC(); -} +//===- Hash.cpp - PDB Hash Functions --------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/Endian.h" +#include <cstdint> + +using namespace llvm; +using namespace llvm::support; + +// Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h. +// Used for name hash table and TPI/IPI hashes. +uint32_t pdb::hashStringV1(StringRef Str) { + uint32_t Result = 0; + uint32_t Size = Str.size(); + + ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()), + Size / 4); + + for (auto Value : Longs) + Result ^= Value; + + const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end()); + uint32_t RemainderSize = Size % 4; + + // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the + // possibly remaining 1 byte. + if (RemainderSize >= 2) { + uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder); + Result ^= static_cast<uint32_t>(Value); + Remainder += 2; + RemainderSize -= 2; + } + + // hash possible odd byte + if (RemainderSize == 1) { + Result ^= *(Remainder++); + } + + const uint32_t toLowerMask = 0x20202020; + Result |= toLowerMask; + Result ^= (Result >> 11); + + return Result ^ (Result >> 16); +} + +// Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h. +// Used for name hash table. +uint32_t pdb::hashStringV2(StringRef Str) { + uint32_t Hash = 0xb170a1bf; + + ArrayRef<char> Buffer(Str.begin(), Str.end()); + + ArrayRef<ulittle32_t> Items( + reinterpret_cast<const ulittle32_t *>(Buffer.data()), + Buffer.size() / sizeof(ulittle32_t)); + for (ulittle32_t Item : Items) { + Hash += Item; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t)); + for (uint8_t Item : Buffer) { + Hash += Item; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + + return Hash * 1664525U + 1013904223U; +} + +// Corresponds to `SigForPbCb` in langapi/shared/crc32.h. +uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) { + JamCRC JC(/*Init=*/0U); + JC.update(Buf); + return JC.getCRC(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/HashTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/HashTable.cpp index dfdcdf1f4e..aab0c8b958 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/HashTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/HashTable.cpp @@ -1,71 +1,71 @@ -//===- HashTable.cpp - PDB Hash Table -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/HashTable.h" -#include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -Error llvm::pdb::readSparseBitVector(BinaryStreamReader &Stream, - SparseBitVector<> &V) { - uint32_t NumWords; - if (auto EC = Stream.readInteger(NumWords)) - return joinErrors( - std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected hash table number of words")); - - for (uint32_t I = 0; I != NumWords; ++I) { - uint32_t Word; - if (auto EC = Stream.readInteger(Word)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected hash table word")); - for (unsigned Idx = 0; Idx < 32; ++Idx) - if (Word & (1U << Idx)) - V.set((I * 32) + Idx); - } - return Error::success(); -} - -Error llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer, - SparseBitVector<> &Vec) { - constexpr int BitsPerWord = 8 * sizeof(uint32_t); - - int ReqBits = Vec.find_last() + 1; - uint32_t ReqWords = alignTo(ReqBits, BitsPerWord) / BitsPerWord; - if (auto EC = Writer.writeInteger(ReqWords)) - return joinErrors( - std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not write linear map number of words")); - - uint32_t Idx = 0; - for (uint32_t I = 0; I != ReqWords; ++I) { - uint32_t Word = 0; - for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) { - if (Vec.test(Idx)) - Word |= (1 << WordIdx); - } - if (auto EC = Writer.writeInteger(Word)) - return joinErrors(std::move(EC), make_error<RawError>( - raw_error_code::corrupt_file, - "Could not write linear map word")); - } - return Error::success(); -} +//===- HashTable.cpp - PDB Hash Table -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +Error llvm::pdb::readSparseBitVector(BinaryStreamReader &Stream, + SparseBitVector<> &V) { + uint32_t NumWords; + if (auto EC = Stream.readInteger(NumWords)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected hash table number of words")); + + for (uint32_t I = 0; I != NumWords; ++I) { + uint32_t Word; + if (auto EC = Stream.readInteger(Word)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected hash table word")); + for (unsigned Idx = 0; Idx < 32; ++Idx) + if (Word & (1U << Idx)) + V.set((I * 32) + Idx); + } + return Error::success(); +} + +Error llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer, + SparseBitVector<> &Vec) { + constexpr int BitsPerWord = 8 * sizeof(uint32_t); + + int ReqBits = Vec.find_last() + 1; + uint32_t ReqWords = alignTo(ReqBits, BitsPerWord) / BitsPerWord; + if (auto EC = Writer.writeInteger(ReqWords)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not write linear map number of words")); + + uint32_t Idx = 0; + for (uint32_t I = 0; I != ReqWords; ++I) { + uint32_t Word = 0; + for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) { + if (Vec.test(Idx)) + Word |= (1 << WordIdx); + } + if (auto EC = Writer.writeInteger(Word)) + return joinErrors(std::move(EC), make_error<RawError>( + raw_error_code::corrupt_file, + "Could not write linear map word")); + } + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStream.cpp index f41bb32d69..ad504af60a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -1,131 +1,131 @@ -//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamReader.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream) - : Stream(std::move(Stream)), Header(nullptr) {} - -Error InfoStream::reload() { - BinaryStreamReader Reader(*Stream); - - if (auto EC = Reader.readObject(Header)) - return joinErrors( - std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "PDB Stream does not contain a header.")); - - switch (Header->Version) { - case PdbImplVC70: - case PdbImplVC80: - case PdbImplVC110: - case PdbImplVC140: - break; - default: - return make_error<RawError>(raw_error_code::corrupt_file, - "Unsupported PDB stream version."); - } - - uint32_t Offset = Reader.getOffset(); - if (auto EC = NamedStreams.load(Reader)) - return EC; - uint32_t NewOffset = Reader.getOffset(); - NamedStreamMapByteSize = NewOffset - Offset; - - Reader.setOffset(Offset); - if (auto EC = Reader.readSubstream(SubNamedStreams, NamedStreamMapByteSize)) - return EC; - - bool Stop = false; - while (!Stop && !Reader.empty()) { - PdbRaw_FeatureSig Sig; - if (auto EC = Reader.readEnum(Sig)) - return EC; - // Since this value comes from a file, it's possible we have some strange - // value which doesn't correspond to any value. We don't want to warn on - // -Wcovered-switch-default in this case, so switch on the integral value - // instead of the enumeration value. - switch (uint32_t(Sig)) { - case uint32_t(PdbRaw_FeatureSig::VC110): - // No other flags for VC110 PDB. - Stop = true; - LLVM_FALLTHROUGH; - case uint32_t(PdbRaw_FeatureSig::VC140): - Features |= PdbFeatureContainsIdStream; - break; - case uint32_t(PdbRaw_FeatureSig::NoTypeMerge): - Features |= PdbFeatureNoTypeMerging; - break; - case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo): - Features |= PdbFeatureMinimalDebugInfo; - break; - default: - continue; - } - FeatureSignatures.push_back(Sig); - } - return Error::success(); -} - -uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); } - -Expected<uint32_t> InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { - uint32_t Result; - if (!NamedStreams.get(Name, Result)) - return make_error<RawError>(raw_error_code::no_stream); - return Result; -} - -StringMap<uint32_t> InfoStream::named_streams() const { - return NamedStreams.entries(); -} - -bool InfoStream::containsIdStream() const { - return !!(Features & PdbFeatureContainsIdStream); -} - -PdbRaw_ImplVer InfoStream::getVersion() const { - return static_cast<PdbRaw_ImplVer>(uint32_t(Header->Version)); -} - -uint32_t InfoStream::getSignature() const { - return uint32_t(Header->Signature); -} - -uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); } - -GUID InfoStream::getGuid() const { return Header->Guid; } - -uint32_t InfoStream::getNamedStreamMapByteSize() const { - return NamedStreamMapByteSize; -} - -PdbRaw_Features InfoStream::getFeatures() const { return Features; } - -ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const { - return FeatureSignatures; -} - -const NamedStreamMap &InfoStream::getNamedStreams() const { - return NamedStreams; -} - -BinarySubstreamRef InfoStream::getNamedStreamsBuffer() const { - return SubNamedStreams; -} +//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream) + : Stream(std::move(Stream)), Header(nullptr) {} + +Error InfoStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readObject(Header)) + return joinErrors( + std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "PDB Stream does not contain a header.")); + + switch (Header->Version) { + case PdbImplVC70: + case PdbImplVC80: + case PdbImplVC110: + case PdbImplVC140: + break; + default: + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported PDB stream version."); + } + + uint32_t Offset = Reader.getOffset(); + if (auto EC = NamedStreams.load(Reader)) + return EC; + uint32_t NewOffset = Reader.getOffset(); + NamedStreamMapByteSize = NewOffset - Offset; + + Reader.setOffset(Offset); + if (auto EC = Reader.readSubstream(SubNamedStreams, NamedStreamMapByteSize)) + return EC; + + bool Stop = false; + while (!Stop && !Reader.empty()) { + PdbRaw_FeatureSig Sig; + if (auto EC = Reader.readEnum(Sig)) + return EC; + // Since this value comes from a file, it's possible we have some strange + // value which doesn't correspond to any value. We don't want to warn on + // -Wcovered-switch-default in this case, so switch on the integral value + // instead of the enumeration value. + switch (uint32_t(Sig)) { + case uint32_t(PdbRaw_FeatureSig::VC110): + // No other flags for VC110 PDB. + Stop = true; + LLVM_FALLTHROUGH; + case uint32_t(PdbRaw_FeatureSig::VC140): + Features |= PdbFeatureContainsIdStream; + break; + case uint32_t(PdbRaw_FeatureSig::NoTypeMerge): + Features |= PdbFeatureNoTypeMerging; + break; + case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo): + Features |= PdbFeatureMinimalDebugInfo; + break; + default: + continue; + } + FeatureSignatures.push_back(Sig); + } + return Error::success(); +} + +uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); } + +Expected<uint32_t> InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { + uint32_t Result; + if (!NamedStreams.get(Name, Result)) + return make_error<RawError>(raw_error_code::no_stream); + return Result; +} + +StringMap<uint32_t> InfoStream::named_streams() const { + return NamedStreams.entries(); +} + +bool InfoStream::containsIdStream() const { + return !!(Features & PdbFeatureContainsIdStream); +} + +PdbRaw_ImplVer InfoStream::getVersion() const { + return static_cast<PdbRaw_ImplVer>(uint32_t(Header->Version)); +} + +uint32_t InfoStream::getSignature() const { + return uint32_t(Header->Signature); +} + +uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); } + +GUID InfoStream::getGuid() const { return Header->Guid; } + +uint32_t InfoStream::getNamedStreamMapByteSize() const { + return NamedStreamMapByteSize; +} + +PdbRaw_Features InfoStream::getFeatures() const { return Features; } + +ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const { + return FeatureSignatures; +} + +const NamedStreamMap &InfoStream::getNamedStreams() const { + return NamedStreams; +} + +BinarySubstreamRef InfoStream::getNamedStreamsBuffer() const { + return SubNamedStreams; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp index 42daa7cae7..02844c4fa5 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -1,82 +1,82 @@ -//===- InfoStreamBuilder.cpp - PDB Info Stream Creation ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" - -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" -#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamWriter.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, - NamedStreamMap &NamedStreams) - : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Age(0), - NamedStreams(NamedStreams) { - ::memset(&Guid, 0, sizeof(Guid)); -} - -void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } - -void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { - Features.push_back(Sig); -} - -void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) { - HashPDBContentsToGUID = B; -} - -void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } - -void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; } - -void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } - - -Error InfoStreamBuilder::finalizeMsfLayout() { - uint32_t Length = sizeof(InfoStreamHeader) + - NamedStreams.calculateSerializedLength() + - (Features.size() + 1) * sizeof(uint32_t); - if (auto EC = Msf.setStreamSize(StreamPDB, Length)) - return EC; - return Error::success(); -} - -Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, - WritableBinaryStreamRef Buffer) const { - auto InfoS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, StreamPDB, Msf.getAllocator()); - BinaryStreamWriter Writer(*InfoS); - - InfoStreamHeader H; - // Leave the build id fields 0 so they can be set as the last step before - // committing the file to disk. - ::memset(&H, 0, sizeof(H)); - H.Version = Ver; - if (auto EC = Writer.writeObject(H)) - return EC; - - if (auto EC = NamedStreams.commit(Writer)) - return EC; - if (auto EC = Writer.writeInteger(0)) - return EC; - for (auto E : Features) { - if (auto EC = Writer.writeEnum(E)) - return EC; - } - assert(Writer.bytesRemaining() == 0); - return Error::success(); -} +//===- InfoStreamBuilder.cpp - PDB Info Stream Creation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" + +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf, + NamedStreamMap &NamedStreams) + : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Age(0), + NamedStreams(NamedStreams) { + ::memset(&Guid, 0, sizeof(Guid)); +} + +void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; } + +void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) { + Features.push_back(Sig); +} + +void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) { + HashPDBContentsToGUID = B; +} + +void InfoStreamBuilder::setAge(uint32_t A) { Age = A; } + +void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; } + +void InfoStreamBuilder::setGuid(GUID G) { Guid = G; } + + +Error InfoStreamBuilder::finalizeMsfLayout() { + uint32_t Length = sizeof(InfoStreamHeader) + + NamedStreams.calculateSerializedLength() + + (Features.size() + 1) * sizeof(uint32_t); + if (auto EC = Msf.setStreamSize(StreamPDB, Length)) + return EC; + return Error::success(); +} + +Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef Buffer) const { + auto InfoS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, StreamPDB, Msf.getAllocator()); + BinaryStreamWriter Writer(*InfoS); + + InfoStreamHeader H; + // Leave the build id fields 0 so they can be set as the last step before + // committing the file to disk. + ::memset(&H, 0, sizeof(H)); + H.Version = Ver; + if (auto EC = Writer.writeObject(H)) + return EC; + + if (auto EC = NamedStreams.commit(Writer)) + return EC; + if (auto EC = Writer.writeInteger(0)) + return EC; + for (auto E : Features) { + if (auto EC = Writer.writeEnum(E)) + return EC; + } + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp index 3f4101db7b..cc5da61b89 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp @@ -1,65 +1,65 @@ -//===- InjectedSourceStream.cpp - PDB Headerblock Stream Access -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" - -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::support; -using namespace llvm::pdb; - -InjectedSourceStream::InjectedSourceStream( - std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} - -Error InjectedSourceStream::reload(const PDBStringTable &Strings) { - BinaryStreamReader Reader(*Stream); - - if (auto EC = Reader.readObject(Header)) - return EC; - - if (Header->Version != - static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid headerblock header version"); - - if (auto EC = InjectedSourceTable.load(Reader)) - return EC; - - for (const auto& Entry : *this) { - if (Entry.second.Size != sizeof(SrcHeaderBlockEntry)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid headerbock entry size"); - if (Entry.second.Version != - static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid headerbock entry version"); - - // Check that all name references are valid. - auto Name = Strings.getStringForID(Entry.second.FileNI); - if (!Name) - return Name.takeError(); - auto ObjName = Strings.getStringForID(Entry.second.ObjNI); - if (!ObjName) - return ObjName.takeError(); - auto VName = Strings.getStringForID(Entry.second.VFileNI); - if (!VName) - return VName.takeError(); - } - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} +//===- InjectedSourceStream.cpp - PDB Headerblock Stream Access -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" + +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +InjectedSourceStream::InjectedSourceStream( + std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +Error InjectedSourceStream::reload(const PDBStringTable &Strings) { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Version != + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerblock header version"); + + if (auto EC = InjectedSourceTable.load(Reader)) + return EC; + + for (const auto& Entry : *this) { + if (Entry.second.Size != sizeof(SrcHeaderBlockEntry)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerbock entry size"); + if (Entry.second.Version != + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid headerbock entry version"); + + // Check that all name references are valid. + auto Name = Strings.getStringForID(Entry.second.FileNI); + if (!Name) + return Name.takeError(); + auto ObjName = Strings.getStringForID(Entry.second.ObjNI); + if (!ObjName) + return ObjName.takeError(); + auto VName = Strings.getStringForID(Entry.second.VFileNI); + if (!VName) + return VName.takeError(); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp index 1445f0bd9e..ba1362f689 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -1,144 +1,144 @@ -//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamRef.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; - -ModuleDebugStreamRef::ModuleDebugStreamRef( - const DbiModuleDescriptor &Module, - std::unique_ptr<MappedBlockStream> Stream) - : Mod(Module), Stream(std::move(Stream)) {} - -ModuleDebugStreamRef::~ModuleDebugStreamRef() = default; - -Error ModuleDebugStreamRef::reload() { - BinaryStreamReader Reader(*Stream); - - if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { - if (Error E = reloadSerialize(Reader)) - return E; - } - if (Reader.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Unexpected bytes in module stream."); - return Error::success(); -} - -Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) { - uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); - uint32_t C11Size = Mod.getC11LineInfoByteSize(); - uint32_t C13Size = Mod.getC13LineInfoByteSize(); - - if (C11Size > 0 && C13Size > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Module has both C11 and C13 line info"); - - BinaryStreamRef S; - - if (auto EC = Reader.readInteger(Signature)) - return EC; - Reader.setOffset(0); - if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize)) - return EC; - if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) - return EC; - if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size)) - return EC; - - BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); - if (auto EC = SymbolReader.readArray( - SymbolArray, SymbolReader.bytesRemaining(), sizeof(uint32_t))) - return EC; - - BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); - if (auto EC = SubsectionsReader.readArray(Subsections, - SubsectionsReader.bytesRemaining())) - return EC; - - uint32_t GlobalRefsSize; - if (auto EC = Reader.readInteger(GlobalRefsSize)) - return EC; - if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize)) - return EC; - return Error::success(); -} - -const codeview::CVSymbolArray -ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const { - return limitSymbolArrayToScope(SymbolArray, ScopeBegin); -} - -BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const { - return SymbolsSubstream; -} - -BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const { - return C11LinesSubstream; -} - -BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const { - return C13LinesSubstream; -} - -BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const { - return GlobalRefsSubstream; -} - -iterator_range<codeview::CVSymbolArray::Iterator> -ModuleDebugStreamRef::symbols(bool *HadError) const { - return make_range(SymbolArray.begin(HadError), SymbolArray.end()); -} - -CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const { - auto Iter = SymbolArray.at(Offset); - assert(Iter != SymbolArray.end()); - return *Iter; -} - -iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator> -ModuleDebugStreamRef::subsections() const { - return make_range(Subsections.begin(), Subsections.end()); -} - -bool ModuleDebugStreamRef::hasDebugSubsections() const { - return !C13LinesSubstream.empty(); -} - -Error ModuleDebugStreamRef::commit() { return Error::success(); } - -Expected<codeview::DebugChecksumsSubsectionRef> -ModuleDebugStreamRef::findChecksumsSubsection() const { - codeview::DebugChecksumsSubsectionRef Result; - for (const auto &SS : subsections()) { - if (SS.kind() != DebugSubsectionKind::FileChecksums) - continue; - - if (auto EC = Result.initialize(SS.getRecordData())) - return std::move(EC); - return Result; - } - return Result; -} +//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.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; + +ModuleDebugStreamRef::ModuleDebugStreamRef( + const DbiModuleDescriptor &Module, + std::unique_ptr<MappedBlockStream> Stream) + : Mod(Module), Stream(std::move(Stream)) {} + +ModuleDebugStreamRef::~ModuleDebugStreamRef() = default; + +Error ModuleDebugStreamRef::reload() { + BinaryStreamReader Reader(*Stream); + + if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) { + if (Error E = reloadSerialize(Reader)) + return E; + } + if (Reader.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unexpected bytes in module stream."); + return Error::success(); +} + +Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) { + uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); + uint32_t C11Size = Mod.getC11LineInfoByteSize(); + uint32_t C13Size = Mod.getC13LineInfoByteSize(); + + if (C11Size > 0 && C13Size > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Module has both C11 and C13 line info"); + + BinaryStreamRef S; + + if (auto EC = Reader.readInteger(Signature)) + return EC; + Reader.setOffset(0); + if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize)) + return EC; + if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) + return EC; + if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size)) + return EC; + + BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); + if (auto EC = SymbolReader.readArray( + SymbolArray, SymbolReader.bytesRemaining(), sizeof(uint32_t))) + return EC; + + BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); + if (auto EC = SubsectionsReader.readArray(Subsections, + SubsectionsReader.bytesRemaining())) + return EC; + + uint32_t GlobalRefsSize; + if (auto EC = Reader.readInteger(GlobalRefsSize)) + return EC; + if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize)) + return EC; + return Error::success(); +} + +const codeview::CVSymbolArray +ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const { + return limitSymbolArrayToScope(SymbolArray, ScopeBegin); +} + +BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const { + return SymbolsSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const { + return C11LinesSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const { + return C13LinesSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const { + return GlobalRefsSubstream; +} + +iterator_range<codeview::CVSymbolArray::Iterator> +ModuleDebugStreamRef::symbols(bool *HadError) const { + return make_range(SymbolArray.begin(HadError), SymbolArray.end()); +} + +CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const { + auto Iter = SymbolArray.at(Offset); + assert(Iter != SymbolArray.end()); + return *Iter; +} + +iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator> +ModuleDebugStreamRef::subsections() const { + return make_range(Subsections.begin(), Subsections.end()); +} + +bool ModuleDebugStreamRef::hasDebugSubsections() const { + return !C13LinesSubstream.empty(); +} + +Error ModuleDebugStreamRef::commit() { return Error::success(); } + +Expected<codeview::DebugChecksumsSubsectionRef> +ModuleDebugStreamRef::findChecksumsSubsection() const { + codeview::DebugChecksumsSubsectionRef Result; + for (const auto &SS : subsections()) { + if (SS.kind() != DebugSubsectionKind::FileChecksums) + continue; + + if (auto EC = Result.initialize(SS.getRecordData())) + return std::move(EC); + return Result; + } + return Result; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp index 1d873b87b3..f4c46f3c3b 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -1,126 +1,126 @@ -//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/HashTable.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamRef.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <tuple> - -using namespace llvm; -using namespace llvm::pdb; - -NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {} - -uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const { - // In the reference implementation, this uses - // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod). - // Here, the type HASH is a typedef of unsigned short. - // ** It is not a bug that we truncate the result of hashStringV1, in fact - // it is a bug if we do not! ** - // See NMTNI::hash() in the reference implementation. - return static_cast<uint16_t>(hashStringV1(S)); -} - -StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const { - return NS->getString(Offset); -} - -uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) { - return NS->appendStringData(S); -} - -NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {} - -Error NamedStreamMap::load(BinaryStreamReader &Stream) { - uint32_t StringBufferSize; - if (auto EC = Stream.readInteger(StringBufferSize)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Expected string buffer size")); - - StringRef Buffer; - if (auto EC = Stream.readFixedString(Buffer, StringBufferSize)) - return EC; - NamesBuffer.assign(Buffer.begin(), Buffer.end()); - - return OffsetIndexMap.load(Stream); -} - -Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { - // The first field is the number of bytes of string data. - if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size())) - return EC; - - // Then the actual string data. - StringRef Data(NamesBuffer.data(), NamesBuffer.size()); - if (auto EC = Writer.writeFixedString(Data)) - return EC; - - // And finally the Offset Index map. - if (auto EC = OffsetIndexMap.commit(Writer)) - return EC; - - return Error::success(); -} - -uint32_t NamedStreamMap::calculateSerializedLength() const { - return sizeof(uint32_t) // String data size - + NamesBuffer.size() // String data - + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map -} - -uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); } - -StringRef NamedStreamMap::getString(uint32_t Offset) const { - assert(NamesBuffer.size() > Offset); - return StringRef(NamesBuffer.data() + Offset); -} - -uint32_t NamedStreamMap::hashString(uint32_t Offset) const { - return hashStringV1(getString(Offset)); -} - -bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { - auto Iter = OffsetIndexMap.find_as(Stream, HashTraits); - if (Iter == OffsetIndexMap.end()) - return false; - StreamNo = (*Iter).second; - return true; -} - -StringMap<uint32_t> NamedStreamMap::entries() const { - StringMap<uint32_t> Result; - for (const auto &Entry : OffsetIndexMap) { - StringRef Stream(NamesBuffer.data() + Entry.first); - Result.try_emplace(Stream, Entry.second); - } - return Result; -} - -uint32_t NamedStreamMap::appendStringData(StringRef S) { - uint32_t Offset = NamesBuffer.size(); +//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <tuple> + +using namespace llvm; +using namespace llvm::pdb; + +NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {} + +uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const { + // In the reference implementation, this uses + // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod). + // Here, the type HASH is a typedef of unsigned short. + // ** It is not a bug that we truncate the result of hashStringV1, in fact + // it is a bug if we do not! ** + // See NMTNI::hash() in the reference implementation. + return static_cast<uint16_t>(hashStringV1(S)); +} + +StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const { + return NS->getString(Offset); +} + +uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) { + return NS->appendStringData(S); +} + +NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {} + +Error NamedStreamMap::load(BinaryStreamReader &Stream) { + uint32_t StringBufferSize; + if (auto EC = Stream.readInteger(StringBufferSize)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Expected string buffer size")); + + StringRef Buffer; + if (auto EC = Stream.readFixedString(Buffer, StringBufferSize)) + return EC; + NamesBuffer.assign(Buffer.begin(), Buffer.end()); + + return OffsetIndexMap.load(Stream); +} + +Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { + // The first field is the number of bytes of string data. + if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size())) + return EC; + + // Then the actual string data. + StringRef Data(NamesBuffer.data(), NamesBuffer.size()); + if (auto EC = Writer.writeFixedString(Data)) + return EC; + + // And finally the Offset Index map. + if (auto EC = OffsetIndexMap.commit(Writer)) + return EC; + + return Error::success(); +} + +uint32_t NamedStreamMap::calculateSerializedLength() const { + return sizeof(uint32_t) // String data size + + NamesBuffer.size() // String data + + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map +} + +uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); } + +StringRef NamedStreamMap::getString(uint32_t Offset) const { + assert(NamesBuffer.size() > Offset); + return StringRef(NamesBuffer.data() + Offset); +} + +uint32_t NamedStreamMap::hashString(uint32_t Offset) const { + return hashStringV1(getString(Offset)); +} + +bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { + auto Iter = OffsetIndexMap.find_as(Stream, HashTraits); + if (Iter == OffsetIndexMap.end()) + return false; + StreamNo = (*Iter).second; + return true; +} + +StringMap<uint32_t> NamedStreamMap::entries() const { + StringMap<uint32_t> Result; + for (const auto &Entry : OffsetIndexMap) { + StringRef Stream(NamesBuffer.data() + Entry.first); + Result.try_emplace(Stream, Entry.second); + } + return Result; +} + +uint32_t NamedStreamMap::appendStringData(StringRef S) { + uint32_t Offset = NamesBuffer.size(); llvm::append_range(NamesBuffer, S); - NamesBuffer.push_back('\0'); - return Offset; -} - -void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { - OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits); -} + NamesBuffer.push_back('\0'); + return Offset; +} + +void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { + OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp index 7717f062ea..a1b5027e3a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp @@ -1,60 +1,60 @@ -//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" - -#include "llvm/ADT/STLExtras.h" - -namespace llvm { -namespace pdb { - -NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, - SymIndexId SymbolId, - DbiModuleDescriptor MI) - : NativeRawSymbol(Session, PDB_SymType::Compiland, SymbolId), Module(MI) {} - -PDB_SymType NativeCompilandSymbol::getSymTag() const { - return PDB_SymType::Compiland; -} - -void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "libraryName", getLibraryName(), Indent); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(), - Indent); -} - -bool NativeCompilandSymbol::isEditAndContinueEnabled() const { - return Module.hasECInfo(); -} - -SymIndexId NativeCompilandSymbol::getLexicalParentId() const { return 0; } - -// The usage of getObjFileName for getLibraryName and getModuleName for getName -// may seem backwards, but it is consistent with DIA, which is what this API -// was modeled after. We may rename these methods later to try to eliminate -// this potential confusion. - -std::string NativeCompilandSymbol::getLibraryName() const { - return std::string(Module.getObjFileName()); -} - -std::string NativeCompilandSymbol::getName() const { - return std::string(Module.getModuleName()); -} - -} // namespace pdb -} // namespace llvm +//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +#include "llvm/ADT/STLExtras.h" + +namespace llvm { +namespace pdb { + +NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, + SymIndexId SymbolId, + DbiModuleDescriptor MI) + : NativeRawSymbol(Session, PDB_SymType::Compiland, SymbolId), Module(MI) {} + +PDB_SymType NativeCompilandSymbol::getSymTag() const { + return PDB_SymType::Compiland; +} + +void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "libraryName", getLibraryName(), Indent); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(), + Indent); +} + +bool NativeCompilandSymbol::isEditAndContinueEnabled() const { + return Module.hasECInfo(); +} + +SymIndexId NativeCompilandSymbol::getLexicalParentId() const { return 0; } + +// The usage of getObjFileName for getLibraryName and getModuleName for getName +// may seem backwards, but it is consistent with DIA, which is what this API +// was modeled after. We may rename these methods later to try to eliminate +// this potential confusion. + +std::string NativeCompilandSymbol::getLibraryName() const { + return std::string(Module.getObjFileName()); +} + +std::string NativeCompilandSymbol::getName() const { + return std::string(Module.getModuleName()); +} + +} // namespace pdb +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp index 54646867bc..3490ac89c1 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp @@ -1,54 +1,54 @@ -//==- NativeEnumGlobals.cpp - Native Global Enumerator impl ------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" - -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeEnumGlobals::NativeEnumGlobals(NativeSession &PDBSession, - std::vector<codeview::SymbolKind> Kinds) - : Index(0), Session(PDBSession) { - GlobalsStream &GS = cantFail(Session.getPDBFile().getPDBGlobalsStream()); - SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); - for (uint32_t Off : GS.getGlobalsTable()) { - CVSymbol S = SS.readRecord(Off); - if (!llvm::is_contained(Kinds, S.kind())) - continue; - MatchOffsets.push_back(Off); - } -} - -uint32_t NativeEnumGlobals::getChildCount() const { - return static_cast<uint32_t>(MatchOffsets.size()); -} - -std::unique_ptr<PDBSymbol> -NativeEnumGlobals::getChildAtIndex(uint32_t N) const { - if (N >= MatchOffsets.size()) - return nullptr; - - SymIndexId Id = - Session.getSymbolCache().getOrCreateGlobalSymbolByOffset(MatchOffsets[N]); - return Session.getSymbolCache().getSymbolById(Id); -} - -std::unique_ptr<PDBSymbol> NativeEnumGlobals::getNext() { - return getChildAtIndex(Index++); -} - -void NativeEnumGlobals::reset() { Index = 0; } +//==- NativeEnumGlobals.cpp - Native Global Enumerator impl ------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" + +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumGlobals::NativeEnumGlobals(NativeSession &PDBSession, + std::vector<codeview::SymbolKind> Kinds) + : Index(0), Session(PDBSession) { + GlobalsStream &GS = cantFail(Session.getPDBFile().getPDBGlobalsStream()); + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + for (uint32_t Off : GS.getGlobalsTable()) { + CVSymbol S = SS.readRecord(Off); + if (!llvm::is_contained(Kinds, S.kind())) + continue; + MatchOffsets.push_back(Off); + } +} + +uint32_t NativeEnumGlobals::getChildCount() const { + return static_cast<uint32_t>(MatchOffsets.size()); +} + +std::unique_ptr<PDBSymbol> +NativeEnumGlobals::getChildAtIndex(uint32_t N) const { + if (N >= MatchOffsets.size()) + return nullptr; + + SymIndexId Id = + Session.getSymbolCache().getOrCreateGlobalSymbolByOffset(MatchOffsets[N]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumGlobals::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumGlobals::reset() { Index = 0; } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp index 7a258acbd7..5e154af342 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp @@ -1,121 +1,121 @@ -//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" - -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" - -namespace llvm { -namespace pdb { - -namespace { - -Expected<std::string> readStreamData(BinaryStream &Stream, uint32_t Limit) { - uint32_t Offset = 0, DataLength = std::min(Limit, Stream.getLength()); - std::string Result; - Result.reserve(DataLength); - while (Offset < DataLength) { - ArrayRef<uint8_t> Data; - if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) - return std::move(E); - Data = Data.take_front(DataLength - Offset); - Offset += Data.size(); - Result += toStringRef(Data); - } - return Result; -} - -class NativeInjectedSource final : public IPDBInjectedSource { - const SrcHeaderBlockEntry &Entry; - const PDBStringTable &Strings; - PDBFile &File; - -public: - NativeInjectedSource(const SrcHeaderBlockEntry &Entry, - PDBFile &File, const PDBStringTable &Strings) - : Entry(Entry), Strings(Strings), File(File) {} - - uint32_t getCrc32() const override { return Entry.CRC; } - uint64_t getCodeByteSize() const override { return Entry.FileSize; } - - std::string getFileName() const override { - StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI), - "InjectedSourceStream should have rejected this"); - return std::string(Ret); - } - - std::string getObjectFileName() const override { - StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI), - "InjectedSourceStream should have rejected this"); - return std::string(Ret); - } - - std::string getVirtualFileName() const override { - StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI), - "InjectedSourceStream should have rejected this"); - return std::string(Ret); - } - - uint32_t getCompression() const override { return Entry.Compression; } - - std::string getCode() const override { - // Get name of stream storing the data. - StringRef VName = - cantFail(Strings.getStringForID(Entry.VFileNI), - "InjectedSourceStream should have rejected this"); - std::string StreamName = ("/src/files/" + VName).str(); - - // Find stream with that name and read its data. - // FIXME: Consider validating (or even loading) all this in - // InjectedSourceStream so that no error can happen here. - auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); - if (!ExpectedFileStream) { - consumeError(ExpectedFileStream.takeError()); - return "(failed to open data stream)"; - } - - auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); - if (!Data) { - consumeError(Data.takeError()); - return "(failed to read data)"; - } - return *Data; - } -}; - -} // namespace - -NativeEnumInjectedSources::NativeEnumInjectedSources( - PDBFile &File, const InjectedSourceStream &IJS, - const PDBStringTable &Strings) - : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} - -uint32_t NativeEnumInjectedSources::getChildCount() const { - return static_cast<uint32_t>(Stream.size()); -} - -std::unique_ptr<IPDBInjectedSource> -NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { - if (N >= getChildCount()) - return nullptr; - return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, - File, Strings); -} - -std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { - if (Cur == Stream.end()) - return nullptr; - return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); -} - -void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } - -} -} +//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" + +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" + +namespace llvm { +namespace pdb { + +namespace { + +Expected<std::string> readStreamData(BinaryStream &Stream, uint32_t Limit) { + uint32_t Offset = 0, DataLength = std::min(Limit, Stream.getLength()); + std::string Result; + Result.reserve(DataLength); + while (Offset < DataLength) { + ArrayRef<uint8_t> Data; + if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) + return std::move(E); + Data = Data.take_front(DataLength - Offset); + Offset += Data.size(); + Result += toStringRef(Data); + } + return Result; +} + +class NativeInjectedSource final : public IPDBInjectedSource { + const SrcHeaderBlockEntry &Entry; + const PDBStringTable &Strings; + PDBFile &File; + +public: + NativeInjectedSource(const SrcHeaderBlockEntry &Entry, + PDBFile &File, const PDBStringTable &Strings) + : Entry(Entry), Strings(Strings), File(File) {} + + uint32_t getCrc32() const override { return Entry.CRC; } + uint64_t getCodeByteSize() const override { return Entry.FileSize; } + + std::string getFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI), + "InjectedSourceStream should have rejected this"); + return std::string(Ret); + } + + std::string getObjectFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI), + "InjectedSourceStream should have rejected this"); + return std::string(Ret); + } + + std::string getVirtualFileName() const override { + StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI), + "InjectedSourceStream should have rejected this"); + return std::string(Ret); + } + + uint32_t getCompression() const override { return Entry.Compression; } + + std::string getCode() const override { + // Get name of stream storing the data. + StringRef VName = + cantFail(Strings.getStringForID(Entry.VFileNI), + "InjectedSourceStream should have rejected this"); + std::string StreamName = ("/src/files/" + VName).str(); + + // Find stream with that name and read its data. + // FIXME: Consider validating (or even loading) all this in + // InjectedSourceStream so that no error can happen here. + auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); + if (!ExpectedFileStream) { + consumeError(ExpectedFileStream.takeError()); + return "(failed to open data stream)"; + } + + auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); + if (!Data) { + consumeError(Data.takeError()); + return "(failed to read data)"; + } + return *Data; + } +}; + +} // namespace + +NativeEnumInjectedSources::NativeEnumInjectedSources( + PDBFile &File, const InjectedSourceStream &IJS, + const PDBStringTable &Strings) + : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} + +uint32_t NativeEnumInjectedSources::getChildCount() const { + return static_cast<uint32_t>(Stream.size()); +} + +std::unique_ptr<IPDBInjectedSource> +NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { + if (N >= getChildCount()) + return nullptr; + return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, + File, Strings); +} + +std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { + if (Cur == Stream.end()) + return nullptr; + return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); +} + +void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } + +} +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp index 1e4b076463..9f413be75f 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp @@ -1,42 +1,42 @@ -//==- NativeEnumLineNumbers.cpp - Native Type Enumerator impl ----*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeEnumLineNumbers::NativeEnumLineNumbers( - std::vector<NativeLineNumber> LineNums) - : Lines(std::move(LineNums)), Index(0) {} - -uint32_t NativeEnumLineNumbers::getChildCount() const { - return static_cast<uint32_t>(Lines.size()); -} - -std::unique_ptr<IPDBLineNumber> -NativeEnumLineNumbers::getChildAtIndex(uint32_t N) const { - if (N >= getChildCount()) - return nullptr; - return std::make_unique<NativeLineNumber>(Lines[N]); -} - -std::unique_ptr<IPDBLineNumber> NativeEnumLineNumbers::getNext() { - return getChildAtIndex(Index++); -} - -void NativeEnumLineNumbers::reset() { Index = 0; } +//==- NativeEnumLineNumbers.cpp - Native Type Enumerator impl ----*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumLineNumbers::NativeEnumLineNumbers( + std::vector<NativeLineNumber> LineNums) + : Lines(std::move(LineNums)), Index(0) {} + +uint32_t NativeEnumLineNumbers::getChildCount() const { + return static_cast<uint32_t>(Lines.size()); +} + +std::unique_ptr<IPDBLineNumber> +NativeEnumLineNumbers::getChildAtIndex(uint32_t N) const { + if (N >= getChildCount()) + return nullptr; + return std::make_unique<NativeLineNumber>(Lines[N]); +} + +std::unique_ptr<IPDBLineNumber> NativeEnumLineNumbers::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumLineNumbers::reset() { Index = 0; } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp index c6621924b5..7f12627205 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp @@ -1,43 +1,43 @@ -//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" - -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" - -namespace llvm { -namespace pdb { - -NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, uint32_t Index) - : Session(PDBSession), Index(Index) {} - -uint32_t NativeEnumModules::getChildCount() const { - return Session.getSymbolCache().getNumCompilands(); -} - -std::unique_ptr<PDBSymbol> -NativeEnumModules::getChildAtIndex(uint32_t N) const { - return Session.getSymbolCache().getOrCreateCompiland(N); -} - -std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() { - if (Index >= getChildCount()) - return nullptr; - return getChildAtIndex(Index++); -} - -void NativeEnumModules::reset() { Index = 0; } - -} -} +//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" + +namespace llvm { +namespace pdb { + +NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, uint32_t Index) + : Session(PDBSession), Index(Index) {} + +uint32_t NativeEnumModules::getChildCount() const { + return Session.getSymbolCache().getNumCompilands(); +} + +std::unique_ptr<PDBSymbol> +NativeEnumModules::getChildAtIndex(uint32_t N) const { + return Session.getSymbolCache().getOrCreateCompiland(N); +} + +std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() { + if (Index >= getChildCount()) + return nullptr; + return getChildAtIndex(Index++); +} + +void NativeEnumModules::reset() { Index = 0; } + +} +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp index ac217df1ee..e4026d865e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp @@ -1,70 +1,70 @@ -//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" - -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, - LazyRandomTypeCollection &Types, - std::vector<codeview::TypeLeafKind> Kinds) - : Matches(), Index(0), Session(PDBSession) { - Optional<TypeIndex> TI = Types.getFirst(); - while (TI) { - CVType CVT = Types.getType(*TI); - TypeLeafKind K = CVT.kind(); - if (llvm::is_contained(Kinds, K)) { - // Don't add forward refs, we'll find those later while enumerating. - if (!isUdtForwardRef(CVT)) - Matches.push_back(*TI); - } else if (K == TypeLeafKind::LF_MODIFIER) { - TypeIndex ModifiedTI = getModifiedType(CVT); - if (!ModifiedTI.isSimple()) { - CVType UnmodifiedCVT = Types.getType(ModifiedTI); - // LF_MODIFIERs point to forward refs, but don't worry about that - // here. We're pushing the TypeIndex of the LF_MODIFIER itself, - // so we'll worry about resolving forward refs later. - if (llvm::is_contained(Kinds, UnmodifiedCVT.kind())) - Matches.push_back(*TI); - } - } - TI = Types.getNext(*TI); - } -} - -NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, - std::vector<codeview::TypeIndex> Indices) - : Matches(std::move(Indices)), Index(0), Session(PDBSession) {} - -uint32_t NativeEnumTypes::getChildCount() const { - return static_cast<uint32_t>(Matches.size()); -} - -std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const { - if (N < Matches.size()) { - SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]); - return Session.getSymbolCache().getSymbolById(Id); - } - return nullptr; -} - -std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() { - return getChildAtIndex(Index++); -} - -void NativeEnumTypes::reset() { Index = 0; } +//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + LazyRandomTypeCollection &Types, + std::vector<codeview::TypeLeafKind> Kinds) + : Matches(), Index(0), Session(PDBSession) { + Optional<TypeIndex> TI = Types.getFirst(); + while (TI) { + CVType CVT = Types.getType(*TI); + TypeLeafKind K = CVT.kind(); + if (llvm::is_contained(Kinds, K)) { + // Don't add forward refs, we'll find those later while enumerating. + if (!isUdtForwardRef(CVT)) + Matches.push_back(*TI); + } else if (K == TypeLeafKind::LF_MODIFIER) { + TypeIndex ModifiedTI = getModifiedType(CVT); + if (!ModifiedTI.isSimple()) { + CVType UnmodifiedCVT = Types.getType(ModifiedTI); + // LF_MODIFIERs point to forward refs, but don't worry about that + // here. We're pushing the TypeIndex of the LF_MODIFIER itself, + // so we'll worry about resolving forward refs later. + if (llvm::is_contained(Kinds, UnmodifiedCVT.kind())) + Matches.push_back(*TI); + } + } + TI = Types.getNext(*TI); + } +} + +NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession, + std::vector<codeview::TypeIndex> Indices) + : Matches(std::move(Indices)), Index(0), Session(PDBSession) {} + +uint32_t NativeEnumTypes::getChildCount() const { + return static_cast<uint32_t>(Matches.size()); +} + +std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const { + if (N < Matches.size()) { + SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]); + return Session.getSymbolCache().getSymbolById(Id); + } + return nullptr; +} + +std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() { + return getChildAtIndex(Index++); +} + +void NativeEnumTypes::reset() { Index = 0; } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp index 895f894315..b64aaf2a18 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -1,101 +1,101 @@ -//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" - -using namespace llvm; -using namespace llvm::pdb; - -static DbiStream *getDbiStreamPtr(NativeSession &Session) { - Expected<DbiStream &> DbiS = Session.getPDBFile().getPDBDbiStream(); - if (DbiS) - return &DbiS.get(); - - consumeError(DbiS.takeError()); - return nullptr; -} - -NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId) - : NativeRawSymbol(Session, PDB_SymType::Exe, SymbolId), - Dbi(getDbiStreamPtr(Session)) {} - -std::unique_ptr<IPDBEnumSymbols> -NativeExeSymbol::findChildren(PDB_SymType Type) const { - switch (Type) { - case PDB_SymType::Compiland: { - return std::unique_ptr<IPDBEnumSymbols>(new NativeEnumModules(Session)); - break; - } - case PDB_SymType::ArrayType: - return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ARRAY); - case PDB_SymType::Enum: - return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM); - case PDB_SymType::PointerType: - return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER); - case PDB_SymType::UDT: - return Session.getSymbolCache().createTypeEnumerator( - {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION, - codeview::LF_INTERFACE}); - case PDB_SymType::VTableShape: - return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE); - case PDB_SymType::FunctionSig: - return Session.getSymbolCache().createTypeEnumerator( - {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION}); - case PDB_SymType::Typedef: - return Session.getSymbolCache().createGlobalsEnumerator(codeview::S_UDT); - - default: - break; - } - return nullptr; -} - -uint32_t NativeExeSymbol::getAge() const { - auto IS = Session.getPDBFile().getPDBInfoStream(); - if (IS) - return IS->getAge(); - consumeError(IS.takeError()); - return 0; -} - -std::string NativeExeSymbol::getSymbolsFileName() const { - return std::string(Session.getPDBFile().getFilePath()); -} - -codeview::GUID NativeExeSymbol::getGuid() const { - auto IS = Session.getPDBFile().getPDBInfoStream(); - if (IS) - return IS->getGuid(); - consumeError(IS.takeError()); - return codeview::GUID{{0}}; -} - -bool NativeExeSymbol::hasCTypes() const { - auto Dbi = Session.getPDBFile().getPDBDbiStream(); - if (Dbi) - return Dbi->hasCTypes(); - consumeError(Dbi.takeError()); - return false; -} - -bool NativeExeSymbol::hasPrivateSymbols() const { - auto Dbi = Session.getPDBFile().getPDBDbiStream(); - if (Dbi) - return !Dbi->isStripped(); - consumeError(Dbi.takeError()); - return false; -} +//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" + +using namespace llvm; +using namespace llvm::pdb; + +static DbiStream *getDbiStreamPtr(NativeSession &Session) { + Expected<DbiStream &> DbiS = Session.getPDBFile().getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); + + consumeError(DbiS.takeError()); + return nullptr; +} + +NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId) + : NativeRawSymbol(Session, PDB_SymType::Exe, SymbolId), + Dbi(getDbiStreamPtr(Session)) {} + +std::unique_ptr<IPDBEnumSymbols> +NativeExeSymbol::findChildren(PDB_SymType Type) const { + switch (Type) { + case PDB_SymType::Compiland: { + return std::unique_ptr<IPDBEnumSymbols>(new NativeEnumModules(Session)); + break; + } + case PDB_SymType::ArrayType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ARRAY); + case PDB_SymType::Enum: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM); + case PDB_SymType::PointerType: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER); + case PDB_SymType::UDT: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION, + codeview::LF_INTERFACE}); + case PDB_SymType::VTableShape: + return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE); + case PDB_SymType::FunctionSig: + return Session.getSymbolCache().createTypeEnumerator( + {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION}); + case PDB_SymType::Typedef: + return Session.getSymbolCache().createGlobalsEnumerator(codeview::S_UDT); + + default: + break; + } + return nullptr; +} + +uint32_t NativeExeSymbol::getAge() const { + auto IS = Session.getPDBFile().getPDBInfoStream(); + if (IS) + return IS->getAge(); + consumeError(IS.takeError()); + return 0; +} + +std::string NativeExeSymbol::getSymbolsFileName() const { + return std::string(Session.getPDBFile().getFilePath()); +} + +codeview::GUID NativeExeSymbol::getGuid() const { + auto IS = Session.getPDBFile().getPDBInfoStream(); + if (IS) + return IS->getGuid(); + consumeError(IS.takeError()); + return codeview::GUID{{0}}; +} + +bool NativeExeSymbol::hasCTypes() const { + auto Dbi = Session.getPDBFile().getPDBDbiStream(); + if (Dbi) + return Dbi->hasCTypes(); + consumeError(Dbi.takeError()); + return false; +} + +bool NativeExeSymbol::hasPrivateSymbols() const { + auto Dbi = Session.getPDBFile().getPDBDbiStream(); + if (Dbi) + return !Dbi->isStripped(); + consumeError(Dbi.takeError()); + return false; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp index 7f3b35c297..21d79b95f2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp @@ -1,60 +1,60 @@ -//===- NativeFunctionSymbol.cpp - info about function symbols----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" - +//===- NativeFunctionSymbol.cpp - info about function symbols----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" + #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session, - SymIndexId Id, +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session, + SymIndexId Id, const codeview::ProcSym &Sym, uint32_t Offset) : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym), RecordOffset(Offset) {} - -NativeFunctionSymbol::~NativeFunctionSymbol() {} - -void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolField(OS, "length", getLength(), Indent); - dumpSymbolField(OS, "offset", getAddressOffset(), Indent); - dumpSymbolField(OS, "section", getAddressSection(), Indent); -} - -uint32_t NativeFunctionSymbol::getAddressOffset() const { - return Sym.CodeOffset; -} - -uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; } -std::string NativeFunctionSymbol::getName() const { - return std::string(Sym.Name); -} - -uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; } - -uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const { - return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset); -} - -uint64_t NativeFunctionSymbol::getVirtualAddress() const { - return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset); -} + +NativeFunctionSymbol::~NativeFunctionSymbol() {} + +void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "offset", getAddressOffset(), Indent); + dumpSymbolField(OS, "section", getAddressSection(), Indent); +} + +uint32_t NativeFunctionSymbol::getAddressOffset() const { + return Sym.CodeOffset; +} + +uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; } +std::string NativeFunctionSymbol::getName() const { + return std::string(Sym.Name); +} + +uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; } + +uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const { + return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset); +} + +uint64_t NativeFunctionSymbol::getVirtualAddress() const { + return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset); +} static bool inlineSiteContainsAddress(InlineSiteSym &IS, uint32_t OffsetInFunc) { diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp index 155ed0cdb8..685d361c7b 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp @@ -1,51 +1,51 @@ -//===- NativeLineNumber.cpp - Native line number implementation -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" - -using namespace llvm; -using namespace llvm::pdb; - -NativeLineNumber::NativeLineNumber(const NativeSession &Session, - const codeview::LineInfo Line, - uint32_t ColumnNumber, uint32_t Section, - uint32_t Offset, uint32_t Length, +//===- NativeLineNumber.cpp - Native line number implementation -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h" + +using namespace llvm; +using namespace llvm::pdb; + +NativeLineNumber::NativeLineNumber(const NativeSession &Session, + const codeview::LineInfo Line, + uint32_t ColumnNumber, uint32_t Section, + uint32_t Offset, uint32_t Length, uint32_t SrcFileId, uint32_t CompilandId) - : Session(Session), Line(Line), ColumnNumber(ColumnNumber), + : Session(Session), Line(Line), ColumnNumber(ColumnNumber), Section(Section), Offset(Offset), Length(Length), SrcFileId(SrcFileId), CompilandId(CompilandId) {} - -uint32_t NativeLineNumber::getLineNumber() const { return Line.getStartLine(); } - -uint32_t NativeLineNumber::getLineNumberEnd() const { - return Line.getEndLine(); -} - -uint32_t NativeLineNumber::getColumnNumber() const { return ColumnNumber; } - -uint32_t NativeLineNumber::getColumnNumberEnd() const { return 0; } - -uint32_t NativeLineNumber::getAddressSection() const { return Section; } - -uint32_t NativeLineNumber::getAddressOffset() const { return Offset; } - -uint32_t NativeLineNumber::getRelativeVirtualAddress() const { - return Session.getRVAFromSectOffset(Section, Offset); -} - -uint64_t NativeLineNumber::getVirtualAddress() const { - return Session.getVAFromSectOffset(Section, Offset); -} - -uint32_t NativeLineNumber::getLength() const { return Length; } - -uint32_t NativeLineNumber::getSourceFileId() const { return SrcFileId; } - + +uint32_t NativeLineNumber::getLineNumber() const { return Line.getStartLine(); } + +uint32_t NativeLineNumber::getLineNumberEnd() const { + return Line.getEndLine(); +} + +uint32_t NativeLineNumber::getColumnNumber() const { return ColumnNumber; } + +uint32_t NativeLineNumber::getColumnNumberEnd() const { return 0; } + +uint32_t NativeLineNumber::getAddressSection() const { return Section; } + +uint32_t NativeLineNumber::getAddressOffset() const { return Offset; } + +uint32_t NativeLineNumber::getRelativeVirtualAddress() const { + return Session.getRVAFromSectOffset(Section, Offset); +} + +uint64_t NativeLineNumber::getVirtualAddress() const { + return Session.getVAFromSectOffset(Section, Offset); +} + +uint32_t NativeLineNumber::getLength() const { return Length; } + +uint32_t NativeLineNumber::getSourceFileId() const { return SrcFileId; } + uint32_t NativeLineNumber::getCompilandId() const { return CompilandId; } - -bool NativeLineNumber::isStatement() const { return Line.isStatement(); } + +bool NativeLineNumber::isStatement() const { return Line.isStatement(); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp index 1265e688b8..f29dc0b5f9 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp @@ -1,48 +1,48 @@ -//===- NativePublicSymbol.cpp - info about public symbols -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" - -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativePublicSymbol::NativePublicSymbol(NativeSession &Session, SymIndexId Id, - const codeview::PublicSym32 &Sym) +//===- NativePublicSymbol.cpp - info about public symbols -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativePublicSymbol::NativePublicSymbol(NativeSession &Session, SymIndexId Id, + const codeview::PublicSym32 &Sym) : NativeRawSymbol(Session, PDB_SymType::PublicSymbol, Id), Sym(Sym) {} - -NativePublicSymbol::~NativePublicSymbol() {} - -void NativePublicSymbol::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolField(OS, "offset", getAddressOffset(), Indent); - dumpSymbolField(OS, "section", getAddressSection(), Indent); -} - -uint32_t NativePublicSymbol::getAddressOffset() const { return Sym.Offset; } - -uint32_t NativePublicSymbol::getAddressSection() const { return Sym.Segment; } - -std::string NativePublicSymbol::getName() const { - return std::string(Sym.Name); -} - -uint32_t NativePublicSymbol::getRelativeVirtualAddress() const { - return Session.getRVAFromSectOffset(Sym.Segment, Sym.Offset); -} - -uint64_t NativePublicSymbol::getVirtualAddress() const { - return Session.getVAFromSectOffset(Sym.Segment, Sym.Offset); -} + +NativePublicSymbol::~NativePublicSymbol() {} + +void NativePublicSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolField(OS, "offset", getAddressOffset(), Indent); + dumpSymbolField(OS, "section", getAddressSection(), Indent); +} + +uint32_t NativePublicSymbol::getAddressOffset() const { return Sym.Offset; } + +uint32_t NativePublicSymbol::getAddressSection() const { return Sym.Segment; } + +std::string NativePublicSymbol::getName() const { + return std::string(Sym.Name); +} + +uint32_t NativePublicSymbol::getRelativeVirtualAddress() const { + return Session.getRVAFromSectOffset(Sym.Segment, Sym.Offset); +} + +uint64_t NativePublicSymbol::getVirtualAddress() const { + return Session.getVAFromSectOffset(Sym.Segment, Sym.Offset); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index 2ad552470b..a3e51c8efd 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -1,734 +1,734 @@ -//===- NativeRawSymbol.cpp - Native implementation of IPDBRawSymbol -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::pdb; - -NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, PDB_SymType Tag, - SymIndexId SymbolId) - : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {} - -void NativeRawSymbol::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session, - PdbSymbolIdField::SymIndexId, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "symTag", Tag, Indent); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findChildren(PDB_SymType Type) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags, uint64_t VA) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags, uint32_t RVA) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, - uint32_t Offset) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { - return std::make_unique<NullEnumerator<PDBSymbol>>(); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeRawSymbol::findInlineeLines() const { - return std::make_unique<NullEnumerator<IPDBLineNumber>>(); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, - uint32_t Length) const { - return std::make_unique<NullEnumerator<IPDBLineNumber>>(); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { - return std::make_unique<NullEnumerator<IPDBLineNumber>>(); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { - return std::make_unique<NullEnumerator<IPDBLineNumber>>(); -} - -void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { - bytes.clear(); -} - -PDB_MemberAccess NativeRawSymbol::getAccess() const { - return PDB_MemberAccess::Private; -} - -uint32_t NativeRawSymbol::getAddressOffset() const { - return 0; -} - -uint32_t NativeRawSymbol::getAddressSection() const { - return 0; -} - -uint32_t NativeRawSymbol::getAge() const { - return 0; -} - -SymIndexId NativeRawSymbol::getArrayIndexTypeId() const { return 0; } - -void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const { - Version.Major = 0; - Version.Minor = 0; - Version.Build = 0; - Version.QFE = 0; -} - -uint32_t NativeRawSymbol::getBaseDataOffset() const { - return 0; -} - -uint32_t NativeRawSymbol::getBaseDataSlot() const { - return 0; -} - -SymIndexId NativeRawSymbol::getBaseSymbolId() const { return 0; } - -PDB_BuiltinType NativeRawSymbol::getBuiltinType() const { - return PDB_BuiltinType::None; -} - -uint32_t NativeRawSymbol::getBitPosition() const { - return 0; -} - -PDB_CallingConv NativeRawSymbol::getCallingConvention() const { - return PDB_CallingConv::FarStdCall; -} - -SymIndexId NativeRawSymbol::getClassParentId() const { return 0; } - -std::string NativeRawSymbol::getCompilerName() const { - return {}; -} - -uint32_t NativeRawSymbol::getCount() const { - return 0; -} - -uint32_t NativeRawSymbol::getCountLiveRanges() const { - return 0; -} - -void NativeRawSymbol::getFrontEndVersion(VersionInfo &Version) const { - Version.Major = 0; - Version.Minor = 0; - Version.Build = 0; - Version.QFE = 0; -} - -PDB_Lang NativeRawSymbol::getLanguage() const { - return PDB_Lang::Cobol; -} - -SymIndexId NativeRawSymbol::getLexicalParentId() const { return 0; } - -std::string NativeRawSymbol::getLibraryName() const { - return {}; -} - -uint32_t NativeRawSymbol::getLiveRangeStartAddressOffset() const { - return 0; -} - -uint32_t NativeRawSymbol::getLiveRangeStartAddressSection() const { - return 0; -} - -uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { - return 0; -} - -codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { - return codeview::RegisterId::EAX; -} - -SymIndexId NativeRawSymbol::getLowerBoundId() const { return 0; } - -uint32_t NativeRawSymbol::getMemorySpaceKind() const { - return 0; -} - -std::string NativeRawSymbol::getName() const { - return {}; -} - -uint32_t NativeRawSymbol::getNumberOfAcceleratorPointerTags() const { - return 0; -} - -uint32_t NativeRawSymbol::getNumberOfColumns() const { - return 0; -} - -uint32_t NativeRawSymbol::getNumberOfModifiers() const { - return 0; -} - -uint32_t NativeRawSymbol::getNumberOfRegisterIndices() const { - return 0; -} - -uint32_t NativeRawSymbol::getNumberOfRows() const { - return 0; -} - -std::string NativeRawSymbol::getObjectFileName() const { - return {}; -} - -uint32_t NativeRawSymbol::getOemId() const { - return 0; -} - -SymIndexId NativeRawSymbol::getOemSymbolId() const { return 0; } - -uint32_t NativeRawSymbol::getOffsetInUdt() const { - return 0; -} - -PDB_Cpu NativeRawSymbol::getPlatform() const { - return PDB_Cpu::Intel8080; -} - -uint32_t NativeRawSymbol::getRank() const { - return 0; -} - -codeview::RegisterId NativeRawSymbol::getRegisterId() const { - return codeview::RegisterId::EAX; -} - -uint32_t NativeRawSymbol::getRegisterType() const { - return 0; -} - -uint32_t NativeRawSymbol::getRelativeVirtualAddress() const { - return 0; -} - -uint32_t NativeRawSymbol::getSamplerSlot() const { - return 0; -} - -uint32_t NativeRawSymbol::getSignature() const { - return 0; -} - -uint32_t NativeRawSymbol::getSizeInUdt() const { - return 0; -} - -uint32_t NativeRawSymbol::getSlot() const { - return 0; -} - -std::string NativeRawSymbol::getSourceFileName() const { - return {}; -} - -std::unique_ptr<IPDBLineNumber> -NativeRawSymbol::getSrcLineOnTypeDefn() const { - return nullptr; -} - -uint32_t NativeRawSymbol::getStride() const { - return 0; -} - -SymIndexId NativeRawSymbol::getSubTypeId() const { return 0; } - -std::string NativeRawSymbol::getSymbolsFileName() const { return {}; } - -SymIndexId NativeRawSymbol::getSymIndexId() const { return SymbolId; } - -uint32_t NativeRawSymbol::getTargetOffset() const { - return 0; -} - -uint32_t NativeRawSymbol::getTargetRelativeVirtualAddress() const { - return 0; -} - -uint64_t NativeRawSymbol::getTargetVirtualAddress() const { - return 0; -} - -uint32_t NativeRawSymbol::getTargetSection() const { - return 0; -} - -uint32_t NativeRawSymbol::getTextureSlot() const { - return 0; -} - -uint32_t NativeRawSymbol::getTimeStamp() const { - return 0; -} - -uint32_t NativeRawSymbol::getToken() const { - return 0; -} - -SymIndexId NativeRawSymbol::getTypeId() const { return 0; } - -uint32_t NativeRawSymbol::getUavSlot() const { - return 0; -} - -std::string NativeRawSymbol::getUndecoratedName() const { - return {}; -} - -std::string NativeRawSymbol::getUndecoratedNameEx( - PDB_UndnameFlags Flags) const { - return {}; -} - -SymIndexId NativeRawSymbol::getUnmodifiedTypeId() const { return 0; } - -SymIndexId NativeRawSymbol::getUpperBoundId() const { return 0; } - -Variant NativeRawSymbol::getValue() const { - return Variant(); -} - -uint32_t NativeRawSymbol::getVirtualBaseDispIndex() const { - return 0; -} - -uint32_t NativeRawSymbol::getVirtualBaseOffset() const { - return 0; -} - -SymIndexId NativeRawSymbol::getVirtualTableShapeId() const { return 0; } - -std::unique_ptr<PDBSymbolTypeBuiltin> -NativeRawSymbol::getVirtualBaseTableType() const { - return nullptr; -} - -PDB_DataKind NativeRawSymbol::getDataKind() const { - return PDB_DataKind::Unknown; -} - -PDB_SymType NativeRawSymbol::getSymTag() const { return Tag; } - -codeview::GUID NativeRawSymbol::getGuid() const { return codeview::GUID{{0}}; } - -int32_t NativeRawSymbol::getOffset() const { - return 0; -} - -int32_t NativeRawSymbol::getThisAdjust() const { - return 0; -} - -int32_t NativeRawSymbol::getVirtualBasePointerOffset() const { - return 0; -} - -PDB_LocType NativeRawSymbol::getLocationType() const { - return PDB_LocType::Null; -} - -PDB_Machine NativeRawSymbol::getMachineType() const { - return PDB_Machine::Invalid; -} - -codeview::ThunkOrdinal NativeRawSymbol::getThunkOrdinal() const { - return codeview::ThunkOrdinal::Standard; -} - -uint64_t NativeRawSymbol::getLength() const { - return 0; -} - -uint64_t NativeRawSymbol::getLiveRangeLength() const { - return 0; -} - -uint64_t NativeRawSymbol::getVirtualAddress() const { - return 0; -} - -PDB_UdtType NativeRawSymbol::getUdtKind() const { - return PDB_UdtType::Struct; -} - -bool NativeRawSymbol::hasConstructor() const { - return false; -} - -bool NativeRawSymbol::hasCustomCallingConvention() const { - return false; -} - -bool NativeRawSymbol::hasFarReturn() const { - return false; -} - -bool NativeRawSymbol::isCode() const { - return false; -} - -bool NativeRawSymbol::isCompilerGenerated() const { - return false; -} - -bool NativeRawSymbol::isConstType() const { - return false; -} - -bool NativeRawSymbol::isEditAndContinueEnabled() const { - return false; -} - -bool NativeRawSymbol::isFunction() const { - return false; -} - -bool NativeRawSymbol::getAddressTaken() const { - return false; -} - -bool NativeRawSymbol::getNoStackOrdering() const { - return false; -} - -bool NativeRawSymbol::hasAlloca() const { - return false; -} - -bool NativeRawSymbol::hasAssignmentOperator() const { - return false; -} - -bool NativeRawSymbol::hasCTypes() const { - return false; -} - -bool NativeRawSymbol::hasCastOperator() const { - return false; -} - -bool NativeRawSymbol::hasDebugInfo() const { - return false; -} - -bool NativeRawSymbol::hasEH() const { - return false; -} - -bool NativeRawSymbol::hasEHa() const { - return false; -} - -bool NativeRawSymbol::hasInlAsm() const { - return false; -} - -bool NativeRawSymbol::hasInlineAttribute() const { - return false; -} - -bool NativeRawSymbol::hasInterruptReturn() const { - return false; -} - -bool NativeRawSymbol::hasFramePointer() const { - return false; -} - -bool NativeRawSymbol::hasLongJump() const { - return false; -} - -bool NativeRawSymbol::hasManagedCode() const { - return false; -} - -bool NativeRawSymbol::hasNestedTypes() const { - return false; -} - -bool NativeRawSymbol::hasNoInlineAttribute() const { - return false; -} - -bool NativeRawSymbol::hasNoReturnAttribute() const { - return false; -} - -bool NativeRawSymbol::hasOptimizedCodeDebugInfo() const { - return false; -} - -bool NativeRawSymbol::hasOverloadedOperator() const { - return false; -} - -bool NativeRawSymbol::hasSEH() const { - return false; -} - -bool NativeRawSymbol::hasSecurityChecks() const { - return false; -} - -bool NativeRawSymbol::hasSetJump() const { - return false; -} - -bool NativeRawSymbol::hasStrictGSCheck() const { - return false; -} - -bool NativeRawSymbol::isAcceleratorGroupSharedLocal() const { - return false; -} - -bool NativeRawSymbol::isAcceleratorPointerTagLiveRange() const { - return false; -} - -bool NativeRawSymbol::isAcceleratorStubFunction() const { - return false; -} - -bool NativeRawSymbol::isAggregated() const { - return false; -} - -bool NativeRawSymbol::isIntroVirtualFunction() const { - return false; -} - -bool NativeRawSymbol::isCVTCIL() const { - return false; -} - -bool NativeRawSymbol::isConstructorVirtualBase() const { - return false; -} - -bool NativeRawSymbol::isCxxReturnUdt() const { - return false; -} - -bool NativeRawSymbol::isDataAligned() const { - return false; -} - -bool NativeRawSymbol::isHLSLData() const { - return false; -} - -bool NativeRawSymbol::isHotpatchable() const { - return false; -} - -bool NativeRawSymbol::isIndirectVirtualBaseClass() const { - return false; -} - -bool NativeRawSymbol::isInterfaceUdt() const { - return false; -} - -bool NativeRawSymbol::isIntrinsic() const { - return false; -} - -bool NativeRawSymbol::isLTCG() const { - return false; -} - -bool NativeRawSymbol::isLocationControlFlowDependent() const { - return false; -} - -bool NativeRawSymbol::isMSILNetmodule() const { - return false; -} - -bool NativeRawSymbol::isMatrixRowMajor() const { - return false; -} - -bool NativeRawSymbol::isManagedCode() const { - return false; -} - -bool NativeRawSymbol::isMSILCode() const { - return false; -} - -bool NativeRawSymbol::isMultipleInheritance() const { - return false; -} - -bool NativeRawSymbol::isNaked() const { - return false; -} - -bool NativeRawSymbol::isNested() const { - return false; -} - -bool NativeRawSymbol::isOptimizedAway() const { - return false; -} - -bool NativeRawSymbol::isPacked() const { - return false; -} - -bool NativeRawSymbol::isPointerBasedOnSymbolValue() const { - return false; -} - -bool NativeRawSymbol::isPointerToDataMember() const { - return false; -} - -bool NativeRawSymbol::isPointerToMemberFunction() const { - return false; -} - -bool NativeRawSymbol::isPureVirtual() const { - return false; -} - -bool NativeRawSymbol::isRValueReference() const { - return false; -} - -bool NativeRawSymbol::isRefUdt() const { - return false; -} - -bool NativeRawSymbol::isReference() const { - return false; -} - -bool NativeRawSymbol::isRestrictedType() const { - return false; -} - -bool NativeRawSymbol::isReturnValue() const { - return false; -} - -bool NativeRawSymbol::isSafeBuffers() const { - return false; -} - -bool NativeRawSymbol::isScoped() const { - return false; -} - -bool NativeRawSymbol::isSdl() const { - return false; -} - -bool NativeRawSymbol::isSingleInheritance() const { - return false; -} - -bool NativeRawSymbol::isSplitted() const { - return false; -} - -bool NativeRawSymbol::isStatic() const { - return false; -} - -bool NativeRawSymbol::hasPrivateSymbols() const { - return false; -} - -bool NativeRawSymbol::isUnalignedType() const { - return false; -} - -bool NativeRawSymbol::isUnreached() const { - return false; -} - -bool NativeRawSymbol::isValueUdt() const { - return false; -} - -bool NativeRawSymbol::isVirtual() const { - return false; -} - -bool NativeRawSymbol::isVirtualBaseClass() const { - return false; -} - -bool NativeRawSymbol::isVirtualInheritance() const { - return false; -} - -bool NativeRawSymbol::isVolatileType() const { - return false; -} - -bool NativeRawSymbol::wasInlined() const { - return false; -} - -std::string NativeRawSymbol::getUnused() const { - return {}; -} +//===- NativeRawSymbol.cpp - Native implementation of IPDBRawSymbol -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::pdb; + +NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, PDB_SymType Tag, + SymIndexId SymbolId) + : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {} + +void NativeRawSymbol::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session, + PdbSymbolIdField::SymIndexId, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "symTag", Tag, Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint64_t VA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t RVA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByAddr(uint32_t Section, + uint32_t Offset) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const { + return std::make_unique<NullEnumerator<PDBSymbol>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLines() const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { + return std::make_unique<NullEnumerator<IPDBLineNumber>>(); +} + +void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const { + bytes.clear(); +} + +PDB_MemberAccess NativeRawSymbol::getAccess() const { + return PDB_MemberAccess::Private; +} + +uint32_t NativeRawSymbol::getAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getAge() const { + return 0; +} + +SymIndexId NativeRawSymbol::getArrayIndexTypeId() const { return 0; } + +void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +uint32_t NativeRawSymbol::getBaseDataOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getBaseDataSlot() const { + return 0; +} + +SymIndexId NativeRawSymbol::getBaseSymbolId() const { return 0; } + +PDB_BuiltinType NativeRawSymbol::getBuiltinType() const { + return PDB_BuiltinType::None; +} + +uint32_t NativeRawSymbol::getBitPosition() const { + return 0; +} + +PDB_CallingConv NativeRawSymbol::getCallingConvention() const { + return PDB_CallingConv::FarStdCall; +} + +SymIndexId NativeRawSymbol::getClassParentId() const { return 0; } + +std::string NativeRawSymbol::getCompilerName() const { + return {}; +} + +uint32_t NativeRawSymbol::getCount() const { + return 0; +} + +uint32_t NativeRawSymbol::getCountLiveRanges() const { + return 0; +} + +void NativeRawSymbol::getFrontEndVersion(VersionInfo &Version) const { + Version.Major = 0; + Version.Minor = 0; + Version.Build = 0; + Version.QFE = 0; +} + +PDB_Lang NativeRawSymbol::getLanguage() const { + return PDB_Lang::Cobol; +} + +SymIndexId NativeRawSymbol::getLexicalParentId() const { return 0; } + +std::string NativeRawSymbol::getLibraryName() const { + return {}; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartAddressSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const { + return codeview::RegisterId::EAX; +} + +SymIndexId NativeRawSymbol::getLowerBoundId() const { return 0; } + +uint32_t NativeRawSymbol::getMemorySpaceKind() const { + return 0; +} + +std::string NativeRawSymbol::getName() const { + return {}; +} + +uint32_t NativeRawSymbol::getNumberOfAcceleratorPointerTags() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfColumns() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfModifiers() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRegisterIndices() const { + return 0; +} + +uint32_t NativeRawSymbol::getNumberOfRows() const { + return 0; +} + +std::string NativeRawSymbol::getObjectFileName() const { + return {}; +} + +uint32_t NativeRawSymbol::getOemId() const { + return 0; +} + +SymIndexId NativeRawSymbol::getOemSymbolId() const { return 0; } + +uint32_t NativeRawSymbol::getOffsetInUdt() const { + return 0; +} + +PDB_Cpu NativeRawSymbol::getPlatform() const { + return PDB_Cpu::Intel8080; +} + +uint32_t NativeRawSymbol::getRank() const { + return 0; +} + +codeview::RegisterId NativeRawSymbol::getRegisterId() const { + return codeview::RegisterId::EAX; +} + +uint32_t NativeRawSymbol::getRegisterType() const { + return 0; +} + +uint32_t NativeRawSymbol::getRelativeVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getSamplerSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getSignature() const { + return 0; +} + +uint32_t NativeRawSymbol::getSizeInUdt() const { + return 0; +} + +uint32_t NativeRawSymbol::getSlot() const { + return 0; +} + +std::string NativeRawSymbol::getSourceFileName() const { + return {}; +} + +std::unique_ptr<IPDBLineNumber> +NativeRawSymbol::getSrcLineOnTypeDefn() const { + return nullptr; +} + +uint32_t NativeRawSymbol::getStride() const { + return 0; +} + +SymIndexId NativeRawSymbol::getSubTypeId() const { return 0; } + +std::string NativeRawSymbol::getSymbolsFileName() const { return {}; } + +SymIndexId NativeRawSymbol::getSymIndexId() const { return SymbolId; } + +uint32_t NativeRawSymbol::getTargetOffset() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetRelativeVirtualAddress() const { + return 0; +} + +uint64_t NativeRawSymbol::getTargetVirtualAddress() const { + return 0; +} + +uint32_t NativeRawSymbol::getTargetSection() const { + return 0; +} + +uint32_t NativeRawSymbol::getTextureSlot() const { + return 0; +} + +uint32_t NativeRawSymbol::getTimeStamp() const { + return 0; +} + +uint32_t NativeRawSymbol::getToken() const { + return 0; +} + +SymIndexId NativeRawSymbol::getTypeId() const { return 0; } + +uint32_t NativeRawSymbol::getUavSlot() const { + return 0; +} + +std::string NativeRawSymbol::getUndecoratedName() const { + return {}; +} + +std::string NativeRawSymbol::getUndecoratedNameEx( + PDB_UndnameFlags Flags) const { + return {}; +} + +SymIndexId NativeRawSymbol::getUnmodifiedTypeId() const { return 0; } + +SymIndexId NativeRawSymbol::getUpperBoundId() const { return 0; } + +Variant NativeRawSymbol::getValue() const { + return Variant(); +} + +uint32_t NativeRawSymbol::getVirtualBaseDispIndex() const { + return 0; +} + +uint32_t NativeRawSymbol::getVirtualBaseOffset() const { + return 0; +} + +SymIndexId NativeRawSymbol::getVirtualTableShapeId() const { return 0; } + +std::unique_ptr<PDBSymbolTypeBuiltin> +NativeRawSymbol::getVirtualBaseTableType() const { + return nullptr; +} + +PDB_DataKind NativeRawSymbol::getDataKind() const { + return PDB_DataKind::Unknown; +} + +PDB_SymType NativeRawSymbol::getSymTag() const { return Tag; } + +codeview::GUID NativeRawSymbol::getGuid() const { return codeview::GUID{{0}}; } + +int32_t NativeRawSymbol::getOffset() const { + return 0; +} + +int32_t NativeRawSymbol::getThisAdjust() const { + return 0; +} + +int32_t NativeRawSymbol::getVirtualBasePointerOffset() const { + return 0; +} + +PDB_LocType NativeRawSymbol::getLocationType() const { + return PDB_LocType::Null; +} + +PDB_Machine NativeRawSymbol::getMachineType() const { + return PDB_Machine::Invalid; +} + +codeview::ThunkOrdinal NativeRawSymbol::getThunkOrdinal() const { + return codeview::ThunkOrdinal::Standard; +} + +uint64_t NativeRawSymbol::getLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getLiveRangeLength() const { + return 0; +} + +uint64_t NativeRawSymbol::getVirtualAddress() const { + return 0; +} + +PDB_UdtType NativeRawSymbol::getUdtKind() const { + return PDB_UdtType::Struct; +} + +bool NativeRawSymbol::hasConstructor() const { + return false; +} + +bool NativeRawSymbol::hasCustomCallingConvention() const { + return false; +} + +bool NativeRawSymbol::hasFarReturn() const { + return false; +} + +bool NativeRawSymbol::isCode() const { + return false; +} + +bool NativeRawSymbol::isCompilerGenerated() const { + return false; +} + +bool NativeRawSymbol::isConstType() const { + return false; +} + +bool NativeRawSymbol::isEditAndContinueEnabled() const { + return false; +} + +bool NativeRawSymbol::isFunction() const { + return false; +} + +bool NativeRawSymbol::getAddressTaken() const { + return false; +} + +bool NativeRawSymbol::getNoStackOrdering() const { + return false; +} + +bool NativeRawSymbol::hasAlloca() const { + return false; +} + +bool NativeRawSymbol::hasAssignmentOperator() const { + return false; +} + +bool NativeRawSymbol::hasCTypes() const { + return false; +} + +bool NativeRawSymbol::hasCastOperator() const { + return false; +} + +bool NativeRawSymbol::hasDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasEH() const { + return false; +} + +bool NativeRawSymbol::hasEHa() const { + return false; +} + +bool NativeRawSymbol::hasInlAsm() const { + return false; +} + +bool NativeRawSymbol::hasInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasInterruptReturn() const { + return false; +} + +bool NativeRawSymbol::hasFramePointer() const { + return false; +} + +bool NativeRawSymbol::hasLongJump() const { + return false; +} + +bool NativeRawSymbol::hasManagedCode() const { + return false; +} + +bool NativeRawSymbol::hasNestedTypes() const { + return false; +} + +bool NativeRawSymbol::hasNoInlineAttribute() const { + return false; +} + +bool NativeRawSymbol::hasNoReturnAttribute() const { + return false; +} + +bool NativeRawSymbol::hasOptimizedCodeDebugInfo() const { + return false; +} + +bool NativeRawSymbol::hasOverloadedOperator() const { + return false; +} + +bool NativeRawSymbol::hasSEH() const { + return false; +} + +bool NativeRawSymbol::hasSecurityChecks() const { + return false; +} + +bool NativeRawSymbol::hasSetJump() const { + return false; +} + +bool NativeRawSymbol::hasStrictGSCheck() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorGroupSharedLocal() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorPointerTagLiveRange() const { + return false; +} + +bool NativeRawSymbol::isAcceleratorStubFunction() const { + return false; +} + +bool NativeRawSymbol::isAggregated() const { + return false; +} + +bool NativeRawSymbol::isIntroVirtualFunction() const { + return false; +} + +bool NativeRawSymbol::isCVTCIL() const { + return false; +} + +bool NativeRawSymbol::isConstructorVirtualBase() const { + return false; +} + +bool NativeRawSymbol::isCxxReturnUdt() const { + return false; +} + +bool NativeRawSymbol::isDataAligned() const { + return false; +} + +bool NativeRawSymbol::isHLSLData() const { + return false; +} + +bool NativeRawSymbol::isHotpatchable() const { + return false; +} + +bool NativeRawSymbol::isIndirectVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isInterfaceUdt() const { + return false; +} + +bool NativeRawSymbol::isIntrinsic() const { + return false; +} + +bool NativeRawSymbol::isLTCG() const { + return false; +} + +bool NativeRawSymbol::isLocationControlFlowDependent() const { + return false; +} + +bool NativeRawSymbol::isMSILNetmodule() const { + return false; +} + +bool NativeRawSymbol::isMatrixRowMajor() const { + return false; +} + +bool NativeRawSymbol::isManagedCode() const { + return false; +} + +bool NativeRawSymbol::isMSILCode() const { + return false; +} + +bool NativeRawSymbol::isMultipleInheritance() const { + return false; +} + +bool NativeRawSymbol::isNaked() const { + return false; +} + +bool NativeRawSymbol::isNested() const { + return false; +} + +bool NativeRawSymbol::isOptimizedAway() const { + return false; +} + +bool NativeRawSymbol::isPacked() const { + return false; +} + +bool NativeRawSymbol::isPointerBasedOnSymbolValue() const { + return false; +} + +bool NativeRawSymbol::isPointerToDataMember() const { + return false; +} + +bool NativeRawSymbol::isPointerToMemberFunction() const { + return false; +} + +bool NativeRawSymbol::isPureVirtual() const { + return false; +} + +bool NativeRawSymbol::isRValueReference() const { + return false; +} + +bool NativeRawSymbol::isRefUdt() const { + return false; +} + +bool NativeRawSymbol::isReference() const { + return false; +} + +bool NativeRawSymbol::isRestrictedType() const { + return false; +} + +bool NativeRawSymbol::isReturnValue() const { + return false; +} + +bool NativeRawSymbol::isSafeBuffers() const { + return false; +} + +bool NativeRawSymbol::isScoped() const { + return false; +} + +bool NativeRawSymbol::isSdl() const { + return false; +} + +bool NativeRawSymbol::isSingleInheritance() const { + return false; +} + +bool NativeRawSymbol::isSplitted() const { + return false; +} + +bool NativeRawSymbol::isStatic() const { + return false; +} + +bool NativeRawSymbol::hasPrivateSymbols() const { + return false; +} + +bool NativeRawSymbol::isUnalignedType() const { + return false; +} + +bool NativeRawSymbol::isUnreached() const { + return false; +} + +bool NativeRawSymbol::isValueUdt() const { + return false; +} + +bool NativeRawSymbol::isVirtual() const { + return false; +} + +bool NativeRawSymbol::isVirtualBaseClass() const { + return false; +} + +bool NativeRawSymbol::isVirtualInheritance() const { + return false; +} + +bool NativeRawSymbol::isVolatileType() const { + return false; +} + +bool NativeRawSymbol::wasInlined() const { + return false; +} + +std::string NativeRawSymbol::getUnused() const { + return {}; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSession.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSession.cpp index 5d7946cdc2..bfefe41a00 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -1,395 +1,395 @@ -//===- NativeSession.cpp - Native implementation of IPDBSession -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +//===- NativeSession.cpp - Native implementation of IPDBSession -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" -#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" - -#include <algorithm> -#include <cassert> -#include <memory> -#include <utility> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::pdb; - -static DbiStream *getDbiStreamPtr(PDBFile &File) { - Expected<DbiStream &> DbiS = File.getPDBDbiStream(); - if (DbiS) - return &DbiS.get(); - - consumeError(DbiS.takeError()); - return nullptr; -} - -NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, - std::unique_ptr<BumpPtrAllocator> Allocator) - : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +#include <algorithm> +#include <cassert> +#include <memory> +#include <utility> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::pdb; + +static DbiStream *getDbiStreamPtr(PDBFile &File) { + Expected<DbiStream &> DbiS = File.getPDBDbiStream(); + if (DbiS) + return &DbiS.get(); + + consumeError(DbiS.takeError()); + return nullptr; +} + +NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile, + std::unique_ptr<BumpPtrAllocator> Allocator) + : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)), Cache(*this, getDbiStreamPtr(*Pdb)), AddrToModuleIndex(IMapAllocator) {} - -NativeSession::~NativeSession() = default; - -Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer, - std::unique_ptr<IPDBSession> &Session) { - StringRef Path = Buffer->getBufferIdentifier(); - auto Stream = std::make_unique<MemoryBufferByteStream>( - std::move(Buffer), llvm::support::little); - - auto Allocator = std::make_unique<BumpPtrAllocator>(); - auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator); - if (auto EC = File->parseFileHeaders()) - return EC; - if (auto EC = File->parseStreamData()) - return EC; - - Session = - std::make_unique<NativeSession>(std::move(File), std::move(Allocator)); - - return Error::success(); -} - -static Expected<std::unique_ptr<PDBFile>> -loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) { - ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = - MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return make_error<RawError>(ErrorOrBuffer.getError()); - std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); - - PdbPath = Buffer->getBufferIdentifier(); - file_magic Magic; - auto EC = identify_magic(PdbPath, Magic); - if (EC || Magic != file_magic::pdb) - return make_error<RawError>(EC); - - auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer), - llvm::support::little); - - auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator); - if (auto EC = File->parseFileHeaders()) - return std::move(EC); - - if (auto EC = File->parseStreamData()) - return std::move(EC); - - return std::move(File); -} - -Error NativeSession::createFromPdbPath(StringRef PdbPath, - std::unique_ptr<IPDBSession> &Session) { - auto Allocator = std::make_unique<BumpPtrAllocator>(); - auto PdbFile = loadPdbFile(PdbPath, Allocator); - if (!PdbFile) - return PdbFile.takeError(); - - Session = std::make_unique<NativeSession>(std::move(PdbFile.get()), - std::move(Allocator)); - return Error::success(); -} - -static Expected<std::string> getPdbPathFromExe(StringRef ExePath) { - Expected<object::OwningBinary<object::Binary>> BinaryFile = - object::createBinary(ExePath); - if (!BinaryFile) - return BinaryFile.takeError(); - - const object::COFFObjectFile *ObjFile = - dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary()); - if (!ObjFile) - return make_error<RawError>(raw_error_code::invalid_format); - - StringRef PdbPath; - const llvm::codeview::DebugInfo *PdbInfo = nullptr; - if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath)) - return std::move(E); - - return std::string(PdbPath); -} - -Error NativeSession::createFromExe(StringRef ExePath, - std::unique_ptr<IPDBSession> &Session) { - Expected<std::string> PdbPath = getPdbPathFromExe(ExePath); - if (!PdbPath) - return PdbPath.takeError(); - - file_magic Magic; - auto EC = identify_magic(PdbPath.get(), Magic); - if (EC || Magic != file_magic::pdb) - return make_error<RawError>(EC); - - auto Allocator = std::make_unique<BumpPtrAllocator>(); - auto File = loadPdbFile(PdbPath.get(), Allocator); - if (!File) - return File.takeError(); - - Session = std::make_unique<NativeSession>(std::move(File.get()), - std::move(Allocator)); - - return Error::success(); -} - -Expected<std::string> -NativeSession::searchForPdb(const PdbSearchOptions &Opts) { - Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath); - if (!PathOrErr) - return PathOrErr.takeError(); - StringRef PathFromExe = PathOrErr.get(); - sys::path::Style Style = PathFromExe.startswith("/") - ? sys::path::Style::posix - : sys::path::Style::windows; - StringRef PdbName = sys::path::filename(PathFromExe, Style); - - // Check if pdb exists in the executable directory. - SmallString<128> PdbPath = StringRef(Opts.ExePath); - sys::path::remove_filename(PdbPath); - sys::path::append(PdbPath, PdbName); - - auto Allocator = std::make_unique<BumpPtrAllocator>(); - - if (auto File = loadPdbFile(PdbPath, Allocator)) - return std::string(PdbPath); - else - consumeError(File.takeError()); - - // Check path that was in the executable. - if (auto File = loadPdbFile(PathFromExe, Allocator)) - return std::string(PathFromExe); - else - return File.takeError(); - - return make_error<RawError>("PDB not found"); -} - -uint64_t NativeSession::getLoadAddress() const { return LoadAddress; } - -bool NativeSession::setLoadAddress(uint64_t Address) { - LoadAddress = Address; - return true; -} - -std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { - return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope()); -} - -std::unique_ptr<PDBSymbol> -NativeSession::getSymbolById(SymIndexId SymbolId) const { - return Cache.getSymbolById(SymbolId); -} - -bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section, - uint32_t &Offset) const { - uint32_t RVA = VA - getLoadAddress(); - return addressForRVA(RVA, Section, Offset); -} - -bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section, - uint32_t &Offset) const { - Section = 0; - Offset = 0; - - auto Dbi = Pdb->getPDBDbiStream(); - if (!Dbi) - return false; - - if ((int32_t)RVA < 0) - return true; - - Offset = RVA; - for (; Section < Dbi->getSectionHeaders().size(); ++Section) { - auto &Sec = Dbi->getSectionHeaders()[Section]; - if (RVA < Sec.VirtualAddress) - return true; - Offset = RVA - Sec.VirtualAddress; - } - return true; -} - -std::unique_ptr<PDBSymbol> -NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) { - uint32_t Section; - uint32_t Offset; - addressForVA(Address, Section, Offset); - return findSymbolBySectOffset(Section, Offset, Type); -} - -std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA, - PDB_SymType Type) { - uint32_t Section; - uint32_t Offset; - addressForRVA(RVA, Section, Offset); - return findSymbolBySectOffset(Section, Offset, Type); -} - -std::unique_ptr<PDBSymbol> -NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, - PDB_SymType Type) { + +NativeSession::~NativeSession() = default; + +Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer, + std::unique_ptr<IPDBSession> &Session) { + StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = std::make_unique<MemoryBufferByteStream>( + std::move(Buffer), llvm::support::little); + + auto Allocator = std::make_unique<BumpPtrAllocator>(); + auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator); + if (auto EC = File->parseFileHeaders()) + return EC; + if (auto EC = File->parseStreamData()) + return EC; + + Session = + std::make_unique<NativeSession>(std::move(File), std::move(Allocator)); + + return Error::success(); +} + +static Expected<std::unique_ptr<PDBFile>> +loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = + MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return make_error<RawError>(ErrorOrBuffer.getError()); + std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer); + + PdbPath = Buffer->getBufferIdentifier(); + file_magic Magic; + auto EC = identify_magic(PdbPath, Magic); + if (EC || Magic != file_magic::pdb) + return make_error<RawError>(EC); + + auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer), + llvm::support::little); + + auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator); + if (auto EC = File->parseFileHeaders()) + return std::move(EC); + + if (auto EC = File->parseStreamData()) + return std::move(EC); + + return std::move(File); +} + +Error NativeSession::createFromPdbPath(StringRef PdbPath, + std::unique_ptr<IPDBSession> &Session) { + auto Allocator = std::make_unique<BumpPtrAllocator>(); + auto PdbFile = loadPdbFile(PdbPath, Allocator); + if (!PdbFile) + return PdbFile.takeError(); + + Session = std::make_unique<NativeSession>(std::move(PdbFile.get()), + std::move(Allocator)); + return Error::success(); +} + +static Expected<std::string> getPdbPathFromExe(StringRef ExePath) { + Expected<object::OwningBinary<object::Binary>> BinaryFile = + object::createBinary(ExePath); + if (!BinaryFile) + return BinaryFile.takeError(); + + const object::COFFObjectFile *ObjFile = + dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary()); + if (!ObjFile) + return make_error<RawError>(raw_error_code::invalid_format); + + StringRef PdbPath; + const llvm::codeview::DebugInfo *PdbInfo = nullptr; + if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath)) + return std::move(E); + + return std::string(PdbPath); +} + +Error NativeSession::createFromExe(StringRef ExePath, + std::unique_ptr<IPDBSession> &Session) { + Expected<std::string> PdbPath = getPdbPathFromExe(ExePath); + if (!PdbPath) + return PdbPath.takeError(); + + file_magic Magic; + auto EC = identify_magic(PdbPath.get(), Magic); + if (EC || Magic != file_magic::pdb) + return make_error<RawError>(EC); + + auto Allocator = std::make_unique<BumpPtrAllocator>(); + auto File = loadPdbFile(PdbPath.get(), Allocator); + if (!File) + return File.takeError(); + + Session = std::make_unique<NativeSession>(std::move(File.get()), + std::move(Allocator)); + + return Error::success(); +} + +Expected<std::string> +NativeSession::searchForPdb(const PdbSearchOptions &Opts) { + Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath); + if (!PathOrErr) + return PathOrErr.takeError(); + StringRef PathFromExe = PathOrErr.get(); + sys::path::Style Style = PathFromExe.startswith("/") + ? sys::path::Style::posix + : sys::path::Style::windows; + StringRef PdbName = sys::path::filename(PathFromExe, Style); + + // Check if pdb exists in the executable directory. + SmallString<128> PdbPath = StringRef(Opts.ExePath); + sys::path::remove_filename(PdbPath); + sys::path::append(PdbPath, PdbName); + + auto Allocator = std::make_unique<BumpPtrAllocator>(); + + if (auto File = loadPdbFile(PdbPath, Allocator)) + return std::string(PdbPath); + else + consumeError(File.takeError()); + + // Check path that was in the executable. + if (auto File = loadPdbFile(PathFromExe, Allocator)) + return std::string(PathFromExe); + else + return File.takeError(); + + return make_error<RawError>("PDB not found"); +} + +uint64_t NativeSession::getLoadAddress() const { return LoadAddress; } + +bool NativeSession::setLoadAddress(uint64_t Address) { + LoadAddress = Address; + return true; +} + +std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { + return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope()); +} + +std::unique_ptr<PDBSymbol> +NativeSession::getSymbolById(SymIndexId SymbolId) const { + return Cache.getSymbolById(SymbolId); +} + +bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section, + uint32_t &Offset) const { + uint32_t RVA = VA - getLoadAddress(); + return addressForRVA(RVA, Section, Offset); +} + +bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section, + uint32_t &Offset) const { + Section = 0; + Offset = 0; + + auto Dbi = Pdb->getPDBDbiStream(); + if (!Dbi) + return false; + + if ((int32_t)RVA < 0) + return true; + + Offset = RVA; + for (; Section < Dbi->getSectionHeaders().size(); ++Section) { + auto &Sec = Dbi->getSectionHeaders()[Section]; + if (RVA < Sec.VirtualAddress) + return true; + Offset = RVA - Sec.VirtualAddress; + } + return true; +} + +std::unique_ptr<PDBSymbol> +NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) { + uint32_t Section; + uint32_t Offset; + addressForVA(Address, Section, Offset); + return findSymbolBySectOffset(Section, Offset, Type); +} + +std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA, + PDB_SymType Type) { + uint32_t Section; + uint32_t Offset; + addressForRVA(RVA, Section, Offset); + return findSymbolBySectOffset(Section, Offset, Type); +} + +std::unique_ptr<PDBSymbol> +NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) { if (AddrToModuleIndex.empty()) parseSectionContribs(); - return Cache.findSymbolBySectOffset(Sect, Offset, Type); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland, - const IPDBSourceFile &File) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeSession::findLineNumbersByAddress(uint64_t Address, - uint32_t Length) const { - return Cache.findLineNumbersByVA(Address, Length); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { + return Cache.findSymbolBySectOffset(Sect, Offset, Type); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland, + const IPDBSourceFile &File) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersByAddress(uint64_t Address, + uint32_t Length) const { + return Cache.findLineNumbersByVA(Address, Length); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const { return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length); -} - -std::unique_ptr<IPDBEnumLineNumbers> -NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, - uint32_t Length) const { - uint64_t VA = getVAFromSectOffset(Section, Offset); +} + +std::unique_ptr<IPDBEnumLineNumbers> +NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset, + uint32_t Length) const { + uint64_t VA = getVAFromSectOffset(Section, Offset); return Cache.findLineNumbersByVA(VA, Length); -} - -std::unique_ptr<IPDBEnumSourceFiles> -NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland, - StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBSourceFile> -NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, - StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> -NativeSession::findCompilandsForSourceFile(StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<PDBSymbolCompiland> -NativeSession::findOneCompilandForSourceFile(StringRef Pattern, - PDB_NameSearchFlags Flags) const { - return nullptr; -} - -std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const { - return nullptr; -} - -std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland( - const PDBSymbolCompiland &Compiland) const { - return nullptr; -} - -std::unique_ptr<IPDBSourceFile> -NativeSession::getSourceFileById(uint32_t FileId) const { - return Cache.getSourceFileById(FileId); -} - -std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { - return nullptr; -} - -std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { - return nullptr; -} - -std::unique_ptr<IPDBEnumInjectedSources> -NativeSession::getInjectedSources() const { - auto ISS = Pdb->getInjectedSourceStream(); - if (!ISS) { - consumeError(ISS.takeError()); - return nullptr; - } - auto Strings = Pdb->getStringTable(); - if (!Strings) { - consumeError(Strings.takeError()); - return nullptr; - } - return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings); -} - -std::unique_ptr<IPDBEnumSectionContribs> -NativeSession::getSectionContribs() const { - return nullptr; -} - -std::unique_ptr<IPDBEnumFrameData> -NativeSession::getFrameData() const { - return nullptr; -} - -void NativeSession::initializeExeSymbol() { - if (ExeSymbol == 0) - ExeSymbol = Cache.createSymbol<NativeExeSymbol>(); -} - -NativeExeSymbol &NativeSession::getNativeGlobalScope() const { - const_cast<NativeSession &>(*this).initializeExeSymbol(); - - return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol); -} - -uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section, - uint32_t Offset) const { - if (Section <= 0) - return 0; - - auto Dbi = getDbiStreamPtr(*Pdb); - if (!Dbi) - return 0; - - uint32_t MaxSection = Dbi->getSectionHeaders().size(); - if (Section > MaxSection + 1) - Section = MaxSection + 1; - auto &Sec = Dbi->getSectionHeaders()[Section - 1]; - return Sec.VirtualAddress + Offset; -} - -uint64_t NativeSession::getVAFromSectOffset(uint32_t Section, - uint32_t Offset) const { - return LoadAddress + getRVAFromSectOffset(Section, Offset); -} +} + +std::unique_ptr<IPDBEnumSourceFiles> +NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland, + StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland, + StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +NativeSession::findCompilandsForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<PDBSymbolCompiland> +NativeSession::findOneCompilandForSourceFile(StringRef Pattern, + PDB_NameSearchFlags Flags) const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland( + const PDBSymbolCompiland &Compiland) const { + return nullptr; +} + +std::unique_ptr<IPDBSourceFile> +NativeSession::getSourceFileById(uint32_t FileId) const { + return Cache.getSourceFileById(FileId); +} + +std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumInjectedSources> +NativeSession::getInjectedSources() const { + auto ISS = Pdb->getInjectedSourceStream(); + if (!ISS) { + consumeError(ISS.takeError()); + return nullptr; + } + auto Strings = Pdb->getStringTable(); + if (!Strings) { + consumeError(Strings.takeError()); + return nullptr; + } + return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings); +} + +std::unique_ptr<IPDBEnumSectionContribs> +NativeSession::getSectionContribs() const { + return nullptr; +} + +std::unique_ptr<IPDBEnumFrameData> +NativeSession::getFrameData() const { + return nullptr; +} + +void NativeSession::initializeExeSymbol() { + if (ExeSymbol == 0) + ExeSymbol = Cache.createSymbol<NativeExeSymbol>(); +} + +NativeExeSymbol &NativeSession::getNativeGlobalScope() const { + const_cast<NativeSession &>(*this).initializeExeSymbol(); + + return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol); +} + +uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section, + uint32_t Offset) const { + if (Section <= 0) + return 0; + + auto Dbi = getDbiStreamPtr(*Pdb); + if (!Dbi) + return 0; + + uint32_t MaxSection = Dbi->getSectionHeaders().size(); + if (Section > MaxSection + 1) + Section = MaxSection + 1; + auto &Sec = Dbi->getSectionHeaders()[Section - 1]; + return Sec.VirtualAddress + Offset; +} + +uint64_t NativeSession::getVAFromSectOffset(uint32_t Section, + uint32_t Offset) const { + return LoadAddress + getRVAFromSectOffset(Section, Offset); +} bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const { ModuleIndex = 0; diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp index fd813dee6b..9ce65bbdd1 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp @@ -1,47 +1,47 @@ //===- NativeSourceFile.cpp - Native line number implementation -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" - -using namespace llvm; -using namespace llvm::pdb; - -NativeSourceFile::NativeSourceFile(NativeSession &Session, uint32_t FileId, - const codeview::FileChecksumEntry &Checksum) - : Session(Session), FileId(FileId), Checksum(Checksum) {} - -std::string NativeSourceFile::getFileName() const { - auto ST = Session.getPDBFile().getStringTable(); - if (!ST) { - consumeError(ST.takeError()); - return ""; - } - auto FileName = ST->getStringTable().getString(Checksum.FileNameOffset); - if (!FileName) { - consumeError(FileName.takeError()); - return ""; - } - - return std::string(FileName.get()); -} - -uint32_t NativeSourceFile::getUniqueId() const { return FileId; } - -std::string NativeSourceFile::getChecksum() const { - return toStringRef(Checksum.Checksum).str(); -} - -PDB_Checksum NativeSourceFile::getChecksumType() const { - return static_cast<PDB_Checksum>(Checksum.Kind); -} - -std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> -NativeSourceFile::getCompilands() const { - return nullptr; -} +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" + +using namespace llvm; +using namespace llvm::pdb; + +NativeSourceFile::NativeSourceFile(NativeSession &Session, uint32_t FileId, + const codeview::FileChecksumEntry &Checksum) + : Session(Session), FileId(FileId), Checksum(Checksum) {} + +std::string NativeSourceFile::getFileName() const { + auto ST = Session.getPDBFile().getStringTable(); + if (!ST) { + consumeError(ST.takeError()); + return ""; + } + auto FileName = ST->getStringTable().getString(Checksum.FileNameOffset); + if (!FileName) { + consumeError(FileName.takeError()); + return ""; + } + + return std::string(FileName.get()); +} + +uint32_t NativeSourceFile::getUniqueId() const { return FileId; } + +std::string NativeSourceFile::getChecksum() const { + return toStringRef(Checksum.Checksum).str(); +} + +PDB_Checksum NativeSourceFile::getChecksumType() const { + return static_cast<PDB_Checksum>(Checksum.Kind); +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>> +NativeSourceFile::getCompilands() const { + return nullptr; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp index e5f1dcaf80..1d262b506c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp @@ -1,124 +1,124 @@ -//===- NativeSymbolEnumerator.cpp - info about enumerators ------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" - -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeSymbolEnumerator::NativeSymbolEnumerator( - NativeSession &Session, SymIndexId Id, const NativeTypeEnum &Parent, - codeview::EnumeratorRecord Record) - : NativeRawSymbol(Session, PDB_SymType::Data, Id), Parent(Parent), - Record(std::move(Record)) {} - -NativeSymbolEnumerator::~NativeSymbolEnumerator() {} - -void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, - PdbSymbolIdField::ClassParent, ShowIdFields, - RecurseIdFields); - dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent, - Session, PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - dumpSymbolField(OS, "dataKind", getDataKind(), Indent); - dumpSymbolField(OS, "locationType", getLocationType(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); - dumpSymbolField(OS, "value", getValue(), Indent); -} - -SymIndexId NativeSymbolEnumerator::getClassParentId() const { - return Parent.getSymIndexId(); -} - -SymIndexId NativeSymbolEnumerator::getLexicalParentId() const { return 0; } - -std::string NativeSymbolEnumerator::getName() const { - return std::string(Record.Name); -} - -SymIndexId NativeSymbolEnumerator::getTypeId() const { - return Parent.getTypeId(); -} - -PDB_DataKind NativeSymbolEnumerator::getDataKind() const { - return PDB_DataKind::Constant; -} - -PDB_LocType NativeSymbolEnumerator::getLocationType() const { - return PDB_LocType::Constant; -} - -bool NativeSymbolEnumerator::isConstType() const { return false; } - -bool NativeSymbolEnumerator::isVolatileType() const { return false; } - -bool NativeSymbolEnumerator::isUnalignedType() const { return false; } - -Variant NativeSymbolEnumerator::getValue() const { - const NativeTypeBuiltin &BT = Parent.getUnderlyingBuiltinType(); - - switch (BT.getBuiltinType()) { - case PDB_BuiltinType::Int: - case PDB_BuiltinType::Long: - case PDB_BuiltinType::Char: { - assert(Record.Value.isSignedIntN(BT.getLength() * 8)); - int64_t N = Record.Value.getSExtValue(); - switch (BT.getLength()) { - case 1: - return Variant{static_cast<int8_t>(N)}; - case 2: - return Variant{static_cast<int16_t>(N)}; - case 4: - return Variant{static_cast<int32_t>(N)}; - case 8: - return Variant{static_cast<int64_t>(N)}; - } - break; - } - case PDB_BuiltinType::UInt: - case PDB_BuiltinType::ULong: { - assert(Record.Value.isIntN(BT.getLength() * 8)); - uint64_t U = Record.Value.getZExtValue(); - switch (BT.getLength()) { - case 1: - return Variant{static_cast<uint8_t>(U)}; - case 2: - return Variant{static_cast<uint16_t>(U)}; - case 4: - return Variant{static_cast<uint32_t>(U)}; - case 8: - return Variant{static_cast<uint64_t>(U)}; - } - break; - } - case PDB_BuiltinType::Bool: { - assert(Record.Value.isIntN(BT.getLength() * 8)); - uint64_t U = Record.Value.getZExtValue(); - return Variant{static_cast<bool>(U)}; - } - default: - assert(false && "Invalid enumeration type"); - break; - } - - return Variant{Record.Value.getSExtValue()}; -} +//===- NativeSymbolEnumerator.cpp - info about enumerators ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeSymbolEnumerator::NativeSymbolEnumerator( + NativeSession &Session, SymIndexId Id, const NativeTypeEnum &Parent, + codeview::EnumeratorRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Data, Id), Parent(Parent), + Record(std::move(Record)) {} + +NativeSymbolEnumerator::~NativeSymbolEnumerator() {} + +void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent, + Session, PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "dataKind", getDataKind(), Indent); + dumpSymbolField(OS, "locationType", getLocationType(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); + dumpSymbolField(OS, "value", getValue(), Indent); +} + +SymIndexId NativeSymbolEnumerator::getClassParentId() const { + return Parent.getSymIndexId(); +} + +SymIndexId NativeSymbolEnumerator::getLexicalParentId() const { return 0; } + +std::string NativeSymbolEnumerator::getName() const { + return std::string(Record.Name); +} + +SymIndexId NativeSymbolEnumerator::getTypeId() const { + return Parent.getTypeId(); +} + +PDB_DataKind NativeSymbolEnumerator::getDataKind() const { + return PDB_DataKind::Constant; +} + +PDB_LocType NativeSymbolEnumerator::getLocationType() const { + return PDB_LocType::Constant; +} + +bool NativeSymbolEnumerator::isConstType() const { return false; } + +bool NativeSymbolEnumerator::isVolatileType() const { return false; } + +bool NativeSymbolEnumerator::isUnalignedType() const { return false; } + +Variant NativeSymbolEnumerator::getValue() const { + const NativeTypeBuiltin &BT = Parent.getUnderlyingBuiltinType(); + + switch (BT.getBuiltinType()) { + case PDB_BuiltinType::Int: + case PDB_BuiltinType::Long: + case PDB_BuiltinType::Char: { + assert(Record.Value.isSignedIntN(BT.getLength() * 8)); + int64_t N = Record.Value.getSExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<int8_t>(N)}; + case 2: + return Variant{static_cast<int16_t>(N)}; + case 4: + return Variant{static_cast<int32_t>(N)}; + case 8: + return Variant{static_cast<int64_t>(N)}; + } + break; + } + case PDB_BuiltinType::UInt: + case PDB_BuiltinType::ULong: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + switch (BT.getLength()) { + case 1: + return Variant{static_cast<uint8_t>(U)}; + case 2: + return Variant{static_cast<uint16_t>(U)}; + case 4: + return Variant{static_cast<uint32_t>(U)}; + case 8: + return Variant{static_cast<uint64_t>(U)}; + } + break; + } + case PDB_BuiltinType::Bool: { + assert(Record.Value.isIntN(BT.getLength() * 8)); + uint64_t U = Record.Value.getZExtValue(); + return Variant{static_cast<bool>(U)}; + } + default: + assert(false && "Invalid enumeration type"); + break; + } + + return Variant{Record.Value.getSExtValue()}; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp index 63ac9fae0e..a8e7ac2e8d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp @@ -1,66 +1,66 @@ -//===- NativeTypeArray.cpp - info about arrays ------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" - -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeTypeArray::NativeTypeArray(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI, - codeview::ArrayRecord Record) - : NativeRawSymbol(Session, PDB_SymType::ArrayType, Id), Record(Record), - Index(TI) {} -NativeTypeArray::~NativeTypeArray() {} - -void NativeTypeArray::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolField(OS, "arrayIndexTypeId", getArrayIndexTypeId(), Indent); - dumpSymbolIdField(OS, "elementTypeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "length", getLength(), Indent); - dumpSymbolField(OS, "count", getCount(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -SymIndexId NativeTypeArray::getArrayIndexTypeId() const { - return Session.getSymbolCache().findSymbolByTypeIndex(Record.getIndexType()); -} - -bool NativeTypeArray::isConstType() const { return false; } - -bool NativeTypeArray::isUnalignedType() const { return false; } - -bool NativeTypeArray::isVolatileType() const { return false; } - -uint32_t NativeTypeArray::getCount() const { - NativeRawSymbol &Element = - Session.getSymbolCache().getNativeSymbolById(getTypeId()); - return getLength() / Element.getLength(); -} - -SymIndexId NativeTypeArray::getTypeId() const { - return Session.getSymbolCache().findSymbolByTypeIndex( - Record.getElementType()); -} - -uint64_t NativeTypeArray::getLength() const { return Record.Size; } +//===- NativeTypeArray.cpp - info about arrays ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" + +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeArray::NativeTypeArray(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::ArrayRecord Record) + : NativeRawSymbol(Session, PDB_SymType::ArrayType, Id), Record(Record), + Index(TI) {} +NativeTypeArray::~NativeTypeArray() {} + +void NativeTypeArray::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "arrayIndexTypeId", getArrayIndexTypeId(), Indent); + dumpSymbolIdField(OS, "elementTypeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypeArray::getArrayIndexTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.getIndexType()); +} + +bool NativeTypeArray::isConstType() const { return false; } + +bool NativeTypeArray::isUnalignedType() const { return false; } + +bool NativeTypeArray::isVolatileType() const { return false; } + +uint32_t NativeTypeArray::getCount() const { + NativeRawSymbol &Element = + Session.getSymbolCache().getNativeSymbolById(getTypeId()); + return getLength() / Element.getLength(); +} + +SymIndexId NativeTypeArray::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex( + Record.getElementType()); +} + +uint64_t NativeTypeArray::getLength() const { return Record.Size; } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp index a08663aa91..533a5ab254 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp @@ -1,46 +1,46 @@ -//===- NativeTypeBuiltin.cpp -------------------------------------- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id, - ModifierOptions Mods, PDB_BuiltinType T, - uint64_t L) - : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id), - Session(PDBSession), Mods(Mods), Type(T), Length(L) {} - -NativeTypeBuiltin::~NativeTypeBuiltin() {} - -void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const {} - -PDB_SymType NativeTypeBuiltin::getSymTag() const { - return PDB_SymType::BuiltinType; -} - -PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; } - -bool NativeTypeBuiltin::isConstType() const { - return (Mods & ModifierOptions::Const) != ModifierOptions::None; -} - -uint64_t NativeTypeBuiltin::getLength() const { return Length; } - -bool NativeTypeBuiltin::isUnalignedType() const { - return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None; -} - -bool NativeTypeBuiltin::isVolatileType() const { - return (Mods & ModifierOptions::Volatile) != ModifierOptions::None; -} +//===- NativeTypeBuiltin.cpp -------------------------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id, + ModifierOptions Mods, PDB_BuiltinType T, + uint64_t L) + : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id), + Session(PDBSession), Mods(Mods), Type(T), Length(L) {} + +NativeTypeBuiltin::~NativeTypeBuiltin() {} + +void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const {} + +PDB_SymType NativeTypeBuiltin::getSymTag() const { + return PDB_SymType::BuiltinType; +} + +PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; } + +bool NativeTypeBuiltin::isConstType() const { + return (Mods & ModifierOptions::Const) != ModifierOptions::None; +} + +uint64_t NativeTypeBuiltin::getLength() const { return Length; } + +bool NativeTypeBuiltin::isUnalignedType() const { + return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None; +} + +bool NativeTypeBuiltin::isVolatileType() const { + return (Mods & ModifierOptions::Volatile) != ModifierOptions::None; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp index aaec3a5e7c..15816cf604 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp @@ -1,381 +1,381 @@ -//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" -#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" - -#include "llvm/Support/FormatVariadic.h" - -#include <cassert> - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -namespace { -// Yea, this is a pretty terrible class name. But if we have an enum: -// -// enum Foo { -// A, -// B -// }; -// -// then A and B are the "enumerators" of the "enum" Foo. And we need -// to enumerate them. -class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { -public: - NativeEnumEnumEnumerators(NativeSession &Session, - const NativeTypeEnum &ClassParent); - - uint32_t getChildCount() const override; - std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; - std::unique_ptr<PDBSymbol> getNext() override; - void reset() override; - -private: - Error visitKnownMember(CVMemberRecord &CVM, - EnumeratorRecord &Record) override; - Error visitKnownMember(CVMemberRecord &CVM, - ListContinuationRecord &Record) override; - - NativeSession &Session; - const NativeTypeEnum &ClassParent; - std::vector<EnumeratorRecord> Enumerators; - Optional<TypeIndex> ContinuationIndex; - uint32_t Index = 0; -}; -} // namespace - -NativeEnumEnumEnumerators::NativeEnumEnumEnumerators( - NativeSession &Session, const NativeTypeEnum &ClassParent) - : Session(Session), ClassParent(ClassParent) { - TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); - LazyRandomTypeCollection &Types = Tpi.typeCollection(); - - ContinuationIndex = ClassParent.getEnumRecord().FieldList; - while (ContinuationIndex) { - CVType FieldList = Types.getType(*ContinuationIndex); - assert(FieldList.kind() == LF_FIELDLIST); - ContinuationIndex.reset(); - cantFail(visitMemberRecordStream(FieldList.data(), *this)); - } -} - -Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, - EnumeratorRecord &Record) { - Enumerators.push_back(Record); - return Error::success(); -} - -Error NativeEnumEnumEnumerators::visitKnownMember( - CVMemberRecord &CVM, ListContinuationRecord &Record) { - ContinuationIndex = Record.ContinuationIndex; - return Error::success(); -} - -uint32_t NativeEnumEnumEnumerators::getChildCount() const { - return Enumerators.size(); -} - -std::unique_ptr<PDBSymbol> -NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const { - if (Index >= getChildCount()) - return nullptr; - - SymIndexId Id = Session.getSymbolCache() - .getOrCreateFieldListMember<NativeSymbolEnumerator>( - ClassParent.getEnumRecord().FieldList, Index, - ClassParent, Enumerators[Index]); - return Session.getSymbolCache().getSymbolById(Id); -} - -std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { - if (Index >= getChildCount()) - return nullptr; - - return getChildAtIndex(Index++); -} - -void NativeEnumEnumEnumerators::reset() { Index = 0; } - -NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, - TypeIndex Index, EnumRecord Record) - : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index), - Record(std::move(Record)) {} - -NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, - NativeTypeEnum &UnmodifiedType, - codeview::ModifierRecord Modifier) - : NativeRawSymbol(Session, PDB_SymType::Enum, Id), - UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} - -NativeTypeEnum::~NativeTypeEnum() {} - -void NativeTypeEnum::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()), - Indent); - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - if (Modifiers.hasValue()) - dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, - Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "length", getLength(), Indent); - dumpSymbolField(OS, "constructor", hasConstructor(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); - dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); - dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); - dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); - dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); - dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); - dumpSymbolField(OS, "nested", isNested(), Indent); - dumpSymbolField(OS, "packed", isPacked(), Indent); - dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); - dumpSymbolField(OS, "scoped", isScoped(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeTypeEnum::findChildren(PDB_SymType Type) const { - if (Type != PDB_SymType::Data) - return std::make_unique<NullEnumerator<PDBSymbol>>(); - - const NativeTypeEnum *ClassParent = nullptr; - if (!Modifiers) - ClassParent = this; - else - ClassParent = UnmodifiedType; - return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent); -} - -PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } - -PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { - if (UnmodifiedType) - return UnmodifiedType->getBuiltinType(); - - Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType()); - - codeview::TypeIndex Underlying = Record->getUnderlyingType(); - - // This indicates a corrupt record. - if (!Underlying.isSimple() || - Underlying.getSimpleMode() != SimpleTypeMode::Direct) { - return PDB_BuiltinType::None; - } - - switch (Underlying.getSimpleKind()) { - case SimpleTypeKind::Boolean128: - case SimpleTypeKind::Boolean64: - case SimpleTypeKind::Boolean32: - case SimpleTypeKind::Boolean16: - case SimpleTypeKind::Boolean8: - return PDB_BuiltinType::Bool; - case SimpleTypeKind::NarrowCharacter: - case SimpleTypeKind::UnsignedCharacter: - case SimpleTypeKind::SignedCharacter: - return PDB_BuiltinType::Char; - case SimpleTypeKind::WideCharacter: - return PDB_BuiltinType::WCharT; - case SimpleTypeKind::Character16: - return PDB_BuiltinType::Char16; - case SimpleTypeKind::Character32: - return PDB_BuiltinType::Char32; - case SimpleTypeKind::Int128: - case SimpleTypeKind::Int128Oct: - case SimpleTypeKind::Int16: - case SimpleTypeKind::Int16Short: - case SimpleTypeKind::Int32: - case SimpleTypeKind::Int32Long: - case SimpleTypeKind::Int64: - case SimpleTypeKind::Int64Quad: - return PDB_BuiltinType::Int; - case SimpleTypeKind::UInt128: - case SimpleTypeKind::UInt128Oct: - case SimpleTypeKind::UInt16: - case SimpleTypeKind::UInt16Short: - case SimpleTypeKind::UInt32: - case SimpleTypeKind::UInt32Long: - case SimpleTypeKind::UInt64: - case SimpleTypeKind::UInt64Quad: - return PDB_BuiltinType::UInt; - case SimpleTypeKind::HResult: - return PDB_BuiltinType::HResult; - case SimpleTypeKind::Complex16: - case SimpleTypeKind::Complex32: - case SimpleTypeKind::Complex32PartialPrecision: - case SimpleTypeKind::Complex64: - case SimpleTypeKind::Complex80: - case SimpleTypeKind::Complex128: - return PDB_BuiltinType::Complex; - case SimpleTypeKind::Float16: - case SimpleTypeKind::Float32: - case SimpleTypeKind::Float32PartialPrecision: - case SimpleTypeKind::Float48: - case SimpleTypeKind::Float64: - case SimpleTypeKind::Float80: - case SimpleTypeKind::Float128: - return PDB_BuiltinType::Float; - default: - return PDB_BuiltinType::None; - } - llvm_unreachable("Unreachable"); -} - -SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { - return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; -} - -bool NativeTypeEnum::hasConstructor() const { - if (UnmodifiedType) - return UnmodifiedType->hasConstructor(); - - return bool(Record->getOptions() & - codeview::ClassOptions::HasConstructorOrDestructor); -} - -bool NativeTypeEnum::hasAssignmentOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasAssignmentOperator(); - - return bool(Record->getOptions() & - codeview::ClassOptions::HasOverloadedAssignmentOperator); -} - -bool NativeTypeEnum::hasNestedTypes() const { - if (UnmodifiedType) - return UnmodifiedType->hasNestedTypes(); - - return bool(Record->getOptions() & - codeview::ClassOptions::ContainsNestedClass); -} - -bool NativeTypeEnum::isIntrinsic() const { - if (UnmodifiedType) - return UnmodifiedType->isIntrinsic(); - - return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); -} - -bool NativeTypeEnum::hasCastOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasCastOperator(); - - return bool(Record->getOptions() & - codeview::ClassOptions::HasConversionOperator); -} - -uint64_t NativeTypeEnum::getLength() const { - if (UnmodifiedType) - return UnmodifiedType->getLength(); - - const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( - Record->getUnderlyingType()); - const auto UnderlyingType = - Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); - return UnderlyingType ? UnderlyingType->getLength() : 0; -} - -std::string NativeTypeEnum::getName() const { - if (UnmodifiedType) - return UnmodifiedType->getName(); - - return std::string(Record->getName()); -} - -bool NativeTypeEnum::isNested() const { - if (UnmodifiedType) - return UnmodifiedType->isNested(); - - return bool(Record->getOptions() & codeview::ClassOptions::Nested); -} - -bool NativeTypeEnum::hasOverloadedOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasOverloadedOperator(); - - return bool(Record->getOptions() & - codeview::ClassOptions::HasOverloadedOperator); -} - -bool NativeTypeEnum::isPacked() const { - if (UnmodifiedType) - return UnmodifiedType->isPacked(); - - return bool(Record->getOptions() & codeview::ClassOptions::Packed); -} - -bool NativeTypeEnum::isScoped() const { - if (UnmodifiedType) - return UnmodifiedType->isScoped(); - - return bool(Record->getOptions() & codeview::ClassOptions::Scoped); -} - -SymIndexId NativeTypeEnum::getTypeId() const { - if (UnmodifiedType) - return UnmodifiedType->getTypeId(); - - return Session.getSymbolCache().findSymbolByTypeIndex( - Record->getUnderlyingType()); -} - -bool NativeTypeEnum::isRefUdt() const { return false; } - -bool NativeTypeEnum::isValueUdt() const { return false; } - -bool NativeTypeEnum::isInterfaceUdt() const { return false; } - -bool NativeTypeEnum::isConstType() const { - if (!Modifiers) - return false; - return ((Modifiers->getModifiers() & ModifierOptions::Const) != - ModifierOptions::None); -} - -bool NativeTypeEnum::isVolatileType() const { - if (!Modifiers) - return false; - return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != - ModifierOptions::None); -} - -bool NativeTypeEnum::isUnalignedType() const { - if (!Modifiers) - return false; - return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != - ModifierOptions::None); -} - -const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { - if (UnmodifiedType) - return UnmodifiedType->getUnderlyingBuiltinType(); - - return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( - getTypeId()); -} +//===- NativeTypeEnum.cpp - info about enum type ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include "llvm/Support/FormatVariadic.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// Yea, this is a pretty terrible class name. But if we have an enum: +// +// enum Foo { +// A, +// B +// }; +// +// then A and B are the "enumerators" of the "enum" Foo. And we need +// to enumerate them. +class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks { +public: + NativeEnumEnumEnumerators(NativeSession &Session, + const NativeTypeEnum &ClassParent); + + uint32_t getChildCount() const override; + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override; + std::unique_ptr<PDBSymbol> getNext() override; + void reset() override; + +private: + Error visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) override; + Error visitKnownMember(CVMemberRecord &CVM, + ListContinuationRecord &Record) override; + + NativeSession &Session; + const NativeTypeEnum &ClassParent; + std::vector<EnumeratorRecord> Enumerators; + Optional<TypeIndex> ContinuationIndex; + uint32_t Index = 0; +}; +} // namespace + +NativeEnumEnumEnumerators::NativeEnumEnumEnumerators( + NativeSession &Session, const NativeTypeEnum &ClassParent) + : Session(Session), ClassParent(ClassParent) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + LazyRandomTypeCollection &Types = Tpi.typeCollection(); + + ContinuationIndex = ClassParent.getEnumRecord().FieldList; + while (ContinuationIndex) { + CVType FieldList = Types.getType(*ContinuationIndex); + assert(FieldList.kind() == LF_FIELDLIST); + ContinuationIndex.reset(); + cantFail(visitMemberRecordStream(FieldList.data(), *this)); + } +} + +Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM, + EnumeratorRecord &Record) { + Enumerators.push_back(Record); + return Error::success(); +} + +Error NativeEnumEnumEnumerators::visitKnownMember( + CVMemberRecord &CVM, ListContinuationRecord &Record) { + ContinuationIndex = Record.ContinuationIndex; + return Error::success(); +} + +uint32_t NativeEnumEnumEnumerators::getChildCount() const { + return Enumerators.size(); +} + +std::unique_ptr<PDBSymbol> +NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const { + if (Index >= getChildCount()) + return nullptr; + + SymIndexId Id = Session.getSymbolCache() + .getOrCreateFieldListMember<NativeSymbolEnumerator>( + ClassParent.getEnumRecord().FieldList, Index, + ClassParent, Enumerators[Index]); + return Session.getSymbolCache().getSymbolById(Id); +} + +std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() { + if (Index >= getChildCount()) + return nullptr; + + return getChildAtIndex(Index++); +} + +void NativeEnumEnumEnumerators::reset() { Index = 0; } + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + TypeIndex Index, EnumRecord Record) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index), + Record(std::move(Record)) {} + +NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id, + NativeTypeEnum &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::Enum, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeEnum::~NativeTypeEnum() {} + +void NativeTypeEnum::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()), + Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeEnum::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::Data) + return std::make_unique<NullEnumerator<PDBSymbol>>(); + + const NativeTypeEnum *ClassParent = nullptr; + if (!Modifiers) + ClassParent = this; + else + ClassParent = UnmodifiedType; + return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent); +} + +PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; } + +PDB_BuiltinType NativeTypeEnum::getBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getBuiltinType(); + + Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType()); + + codeview::TypeIndex Underlying = Record->getUnderlyingType(); + + // This indicates a corrupt record. + if (!Underlying.isSimple() || + Underlying.getSimpleMode() != SimpleTypeMode::Direct) { + return PDB_BuiltinType::None; + } + + switch (Underlying.getSimpleKind()) { + case SimpleTypeKind::Boolean128: + case SimpleTypeKind::Boolean64: + case SimpleTypeKind::Boolean32: + case SimpleTypeKind::Boolean16: + case SimpleTypeKind::Boolean8: + return PDB_BuiltinType::Bool; + case SimpleTypeKind::NarrowCharacter: + case SimpleTypeKind::UnsignedCharacter: + case SimpleTypeKind::SignedCharacter: + return PDB_BuiltinType::Char; + case SimpleTypeKind::WideCharacter: + return PDB_BuiltinType::WCharT; + case SimpleTypeKind::Character16: + return PDB_BuiltinType::Char16; + case SimpleTypeKind::Character32: + return PDB_BuiltinType::Char32; + case SimpleTypeKind::Int128: + case SimpleTypeKind::Int128Oct: + case SimpleTypeKind::Int16: + case SimpleTypeKind::Int16Short: + case SimpleTypeKind::Int32: + case SimpleTypeKind::Int32Long: + case SimpleTypeKind::Int64: + case SimpleTypeKind::Int64Quad: + return PDB_BuiltinType::Int; + case SimpleTypeKind::UInt128: + case SimpleTypeKind::UInt128Oct: + case SimpleTypeKind::UInt16: + case SimpleTypeKind::UInt16Short: + case SimpleTypeKind::UInt32: + case SimpleTypeKind::UInt32Long: + case SimpleTypeKind::UInt64: + case SimpleTypeKind::UInt64Quad: + return PDB_BuiltinType::UInt; + case SimpleTypeKind::HResult: + return PDB_BuiltinType::HResult; + case SimpleTypeKind::Complex16: + case SimpleTypeKind::Complex32: + case SimpleTypeKind::Complex32PartialPrecision: + case SimpleTypeKind::Complex64: + case SimpleTypeKind::Complex80: + case SimpleTypeKind::Complex128: + return PDB_BuiltinType::Complex; + case SimpleTypeKind::Float16: + case SimpleTypeKind::Float32: + case SimpleTypeKind::Float32PartialPrecision: + case SimpleTypeKind::Float48: + case SimpleTypeKind::Float64: + case SimpleTypeKind::Float80: + case SimpleTypeKind::Float128: + return PDB_BuiltinType::Float; + default: + return PDB_BuiltinType::None; + } + llvm_unreachable("Unreachable"); +} + +SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const { + return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0; +} + +bool NativeTypeEnum::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConstructorOrDestructor); +} + +bool NativeTypeEnum::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedAssignmentOperator); +} + +bool NativeTypeEnum::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return bool(Record->getOptions() & + codeview::ClassOptions::ContainsNestedClass); +} + +bool NativeTypeEnum::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic); +} + +bool NativeTypeEnum::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasConversionOperator); +} + +uint64_t NativeTypeEnum::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + const auto Id = Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); + const auto UnderlyingType = + Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id); + return UnderlyingType ? UnderlyingType->getLength() : 0; +} + +std::string NativeTypeEnum::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return std::string(Record->getName()); +} + +bool NativeTypeEnum::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return bool(Record->getOptions() & codeview::ClassOptions::Nested); +} + +bool NativeTypeEnum::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return bool(Record->getOptions() & + codeview::ClassOptions::HasOverloadedOperator); +} + +bool NativeTypeEnum::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return bool(Record->getOptions() & codeview::ClassOptions::Packed); +} + +bool NativeTypeEnum::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return bool(Record->getOptions() & codeview::ClassOptions::Scoped); +} + +SymIndexId NativeTypeEnum::getTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getTypeId(); + + return Session.getSymbolCache().findSymbolByTypeIndex( + Record->getUnderlyingType()); +} + +bool NativeTypeEnum::isRefUdt() const { return false; } + +bool NativeTypeEnum::isValueUdt() const { return false; } + +bool NativeTypeEnum::isInterfaceUdt() const { return false; } + +bool NativeTypeEnum::isConstType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Const) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isVolatileType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Volatile) != + ModifierOptions::None); +} + +bool NativeTypeEnum::isUnalignedType() const { + if (!Modifiers) + return false; + return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) != + ModifierOptions::None); +} + +const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const { + if (UnmodifiedType) + return UnmodifiedType->getUnderlyingBuiltinType(); + + return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>( + getTypeId()); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp index f98a4c3043..d8daab006a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp @@ -1,199 +1,199 @@ -//===- NativeTypeFunctionSig.cpp - info about function signature -*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" - -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -namespace { -// This is kind of a silly class, hence why we keep it private to the file. -// It's only purpose is to wrap the real type record. I guess this is so that -// we can have the lexical parent point to the function instead of the global -// scope. -class NativeTypeFunctionArg : public NativeRawSymbol { -public: - NativeTypeFunctionArg(NativeSession &Session, - std::unique_ptr<PDBSymbol> RealType) - : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0), - RealType(std::move(RealType)) {} - - void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const override { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - } - - SymIndexId getTypeId() const override { return RealType->getSymIndexId(); } - - std::unique_ptr<PDBSymbol> RealType; -}; - -class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> { -public: - NativeEnumFunctionArgs(NativeSession &Session, - std::unique_ptr<NativeEnumTypes> TypeEnumerator) - : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {} - - uint32_t getChildCount() const override { - return TypeEnumerator->getChildCount(); - } - std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { - return wrap(TypeEnumerator->getChildAtIndex(Index)); - } - std::unique_ptr<PDBSymbol> getNext() override { - return wrap(TypeEnumerator->getNext()); - } - - void reset() override { TypeEnumerator->reset(); } - -private: - std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const { - if (!S) - return nullptr; - auto NTFA = std::make_unique<NativeTypeFunctionArg>(Session, std::move(S)); - return PDBSymbol::create(Session, std::move(NTFA)); - } - NativeSession &Session; - std::unique_ptr<NativeEnumTypes> TypeEnumerator; -}; -} // namespace - -NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session, - SymIndexId Id, - codeview::TypeIndex Index, - codeview::ProcedureRecord Proc) - : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), - Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {} - -NativeTypeFunctionSig::NativeTypeFunctionSig( - NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index, - codeview::MemberFunctionRecord MemberFunc) - : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), - MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {} - -void NativeTypeFunctionSig::initialize() { - if (IsMemberFunction) { - ClassParentId = - Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType); - initializeArgList(MemberFunc.ArgumentList); - } else { - initializeArgList(Proc.ArgumentList); - } -} - -NativeTypeFunctionSig::~NativeTypeFunctionSig() {} - -void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) { - TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); - CVType CVT = Tpi.typeCollection().getType(ArgListTI); - - cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList)); -} - -void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - - dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent); - dumpSymbolField(OS, "count", getCount(), Indent); - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - if (IsMemberFunction) - dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent); - dumpSymbolField(OS, "constructor", hasConstructor(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(), - Indent); - dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -std::unique_ptr<IPDBEnumSymbols> -NativeTypeFunctionSig::findChildren(PDB_SymType Type) const { - if (Type != PDB_SymType::FunctionArg) - return std::make_unique<NullEnumerator<PDBSymbol>>(); - - auto NET = std::make_unique<NativeEnumTypes>(Session, - /* copy */ ArgList.ArgIndices); - return std::unique_ptr<IPDBEnumSymbols>( - new NativeEnumFunctionArgs(Session, std::move(NET))); -} - -SymIndexId NativeTypeFunctionSig::getClassParentId() const { - if (!IsMemberFunction) - return 0; - - return ClassParentId; -} - -PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const { - return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv; -} - -uint32_t NativeTypeFunctionSig::getCount() const { - return IsMemberFunction ? (1 + MemberFunc.getParameterCount()) - : Proc.getParameterCount(); -} - -SymIndexId NativeTypeFunctionSig::getTypeId() const { - TypeIndex ReturnTI = - IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType(); - - SymIndexId Result = Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI); - return Result; -} - -int32_t NativeTypeFunctionSig::getThisAdjust() const { - return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0; -} - -bool NativeTypeFunctionSig::hasConstructor() const { - if (!IsMemberFunction) - return false; - - return (MemberFunc.getOptions() & FunctionOptions::Constructor) != - FunctionOptions::None; -} - -bool NativeTypeFunctionSig::isConstType() const { return false; } - -bool NativeTypeFunctionSig::isConstructorVirtualBase() const { - if (!IsMemberFunction) - return false; - - return (MemberFunc.getOptions() & - FunctionOptions::ConstructorWithVirtualBases) != - FunctionOptions::None; -} - -bool NativeTypeFunctionSig::isCxxReturnUdt() const { - FunctionOptions Options = - IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions(); - return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None; -} - -bool NativeTypeFunctionSig::isUnalignedType() const { return false; } - -bool NativeTypeFunctionSig::isVolatileType() const { return false; } +//===- NativeTypeFunctionSig.cpp - info about function signature -*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" + +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +// This is kind of a silly class, hence why we keep it private to the file. +// It's only purpose is to wrap the real type record. I guess this is so that +// we can have the lexical parent point to the function instead of the global +// scope. +class NativeTypeFunctionArg : public NativeRawSymbol { +public: + NativeTypeFunctionArg(NativeSession &Session, + std::unique_ptr<PDBSymbol> RealType) + : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0), + RealType(std::move(RealType)) {} + + void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const override { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + } + + SymIndexId getTypeId() const override { return RealType->getSymIndexId(); } + + std::unique_ptr<PDBSymbol> RealType; +}; + +class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> { +public: + NativeEnumFunctionArgs(NativeSession &Session, + std::unique_ptr<NativeEnumTypes> TypeEnumerator) + : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {} + + uint32_t getChildCount() const override { + return TypeEnumerator->getChildCount(); + } + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { + return wrap(TypeEnumerator->getChildAtIndex(Index)); + } + std::unique_ptr<PDBSymbol> getNext() override { + return wrap(TypeEnumerator->getNext()); + } + + void reset() override { TypeEnumerator->reset(); } + +private: + std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const { + if (!S) + return nullptr; + auto NTFA = std::make_unique<NativeTypeFunctionArg>(Session, std::move(S)); + return PDBSymbol::create(Session, std::move(NTFA)); + } + NativeSession &Session; + std::unique_ptr<NativeEnumTypes> TypeEnumerator; +}; +} // namespace + +NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session, + SymIndexId Id, + codeview::TypeIndex Index, + codeview::ProcedureRecord Proc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {} + +NativeTypeFunctionSig::NativeTypeFunctionSig( + NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index, + codeview::MemberFunctionRecord MemberFunc) + : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id), + MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {} + +void NativeTypeFunctionSig::initialize() { + if (IsMemberFunction) { + ClassParentId = + Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType); + initializeArgList(MemberFunc.ArgumentList); + } else { + initializeArgList(Proc.ArgumentList); + } +} + +NativeTypeFunctionSig::~NativeTypeFunctionSig() {} + +void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) { + TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream()); + CVType CVT = Tpi.typeCollection().getType(ArgListTI); + + cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList)); +} + +void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + + dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + if (IsMemberFunction) + dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(), + Indent); + dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::unique_ptr<IPDBEnumSymbols> +NativeTypeFunctionSig::findChildren(PDB_SymType Type) const { + if (Type != PDB_SymType::FunctionArg) + return std::make_unique<NullEnumerator<PDBSymbol>>(); + + auto NET = std::make_unique<NativeEnumTypes>(Session, + /* copy */ ArgList.ArgIndices); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumFunctionArgs(Session, std::move(NET))); +} + +SymIndexId NativeTypeFunctionSig::getClassParentId() const { + if (!IsMemberFunction) + return 0; + + return ClassParentId; +} + +PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const { + return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv; +} + +uint32_t NativeTypeFunctionSig::getCount() const { + return IsMemberFunction ? (1 + MemberFunc.getParameterCount()) + : Proc.getParameterCount(); +} + +SymIndexId NativeTypeFunctionSig::getTypeId() const { + TypeIndex ReturnTI = + IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType(); + + SymIndexId Result = Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI); + return Result; +} + +int32_t NativeTypeFunctionSig::getThisAdjust() const { + return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0; +} + +bool NativeTypeFunctionSig::hasConstructor() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & FunctionOptions::Constructor) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isConstType() const { return false; } + +bool NativeTypeFunctionSig::isConstructorVirtualBase() const { + if (!IsMemberFunction) + return false; + + return (MemberFunc.getOptions() & + FunctionOptions::ConstructorWithVirtualBases) != + FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isCxxReturnUdt() const { + FunctionOptions Options = + IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions(); + return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None; +} + +bool NativeTypeFunctionSig::isUnalignedType() const { return false; } + +bool NativeTypeFunctionSig::isVolatileType() const { return false; } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp index 32dcfc2359..03a4f6cc91 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp @@ -1,193 +1,193 @@ -//===- NativeTypePointer.cpp - info about pointer type ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" - -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" - -#include <cassert> - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI) - : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) { - assert(TI.isSimple()); - assert(TI.getSimpleMode() != SimpleTypeMode::Direct); -} - -NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI, - codeview::PointerRecord Record) - : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI), - Record(std::move(Record)) {} - -NativeTypePointer::~NativeTypePointer() {} - -void NativeTypePointer::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - if (isMemberPointer()) { - dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, - PdbSymbolIdField::ClassParent, ShowIdFields, - RecurseIdFields); - } - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); - dumpSymbolField(OS, "length", getLength(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent); - dumpSymbolField(OS, "isPointerToMemberFunction", isPointerToMemberFunction(), - Indent); - dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent); - dumpSymbolField(OS, "reference", isReference(), Indent); - dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent); - if (isMemberPointer()) { - if (isSingleInheritance()) - dumpSymbolField(OS, "isSingleInheritance", 1, Indent); - else if (isMultipleInheritance()) - dumpSymbolField(OS, "isMultipleInheritance", 1, Indent); - else if (isVirtualInheritance()) - dumpSymbolField(OS, "isVirtualInheritance", 1, Indent); - } - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -SymIndexId NativeTypePointer::getClassParentId() const { - if (!isMemberPointer()) - return 0; - - assert(Record); - const MemberPointerInfo &MPI = Record->getMemberInfo(); - return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType); -} - -uint64_t NativeTypePointer::getLength() const { - if (Record) - return Record->getSize(); - - switch (TI.getSimpleMode()) { - case SimpleTypeMode::NearPointer: - case SimpleTypeMode::FarPointer: - case SimpleTypeMode::HugePointer: - return 2; - case SimpleTypeMode::NearPointer32: - case SimpleTypeMode::FarPointer32: - return 4; - case SimpleTypeMode::NearPointer64: - return 8; - case SimpleTypeMode::NearPointer128: - return 16; - default: - assert(false && "invalid simple type mode!"); - } - return 0; -} - -SymIndexId NativeTypePointer::getTypeId() const { - // This is the pointee SymIndexId. - TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect(); - - return Session.getSymbolCache().findSymbolByTypeIndex(Referent); -} - -bool NativeTypePointer::isReference() const { - if (!Record) - return false; - return Record->getMode() == PointerMode::LValueReference; -} - -bool NativeTypePointer::isRValueReference() const { - if (!Record) - return false; - return Record->getMode() == PointerMode::RValueReference; -} - -bool NativeTypePointer::isPointerToDataMember() const { - if (!Record) - return false; - return Record->getMode() == PointerMode::PointerToDataMember; -} - -bool NativeTypePointer::isPointerToMemberFunction() const { - if (!Record) - return false; - return Record->getMode() == PointerMode::PointerToMemberFunction; -} - -bool NativeTypePointer::isConstType() const { - if (!Record) - return false; - return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None; -} - -bool NativeTypePointer::isRestrictedType() const { - if (!Record) - return false; - return (Record->getOptions() & PointerOptions::Restrict) != - PointerOptions::None; -} - -bool NativeTypePointer::isVolatileType() const { - if (!Record) - return false; - return (Record->getOptions() & PointerOptions::Volatile) != - PointerOptions::None; -} - -bool NativeTypePointer::isUnalignedType() const { - if (!Record) - return false; - return (Record->getOptions() & PointerOptions::Unaligned) != - PointerOptions::None; -} - -static inline bool isInheritanceKind(const MemberPointerInfo &MPI, - PointerToMemberRepresentation P1, - PointerToMemberRepresentation P2) { - return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2); -} - -bool NativeTypePointer::isSingleInheritance() const { - if (!isMemberPointer()) - return false; - return isInheritanceKind( - Record->getMemberInfo(), - PointerToMemberRepresentation::SingleInheritanceData, - PointerToMemberRepresentation::SingleInheritanceFunction); -} - -bool NativeTypePointer::isMultipleInheritance() const { - if (!isMemberPointer()) - return false; - return isInheritanceKind( - Record->getMemberInfo(), - PointerToMemberRepresentation::MultipleInheritanceData, - PointerToMemberRepresentation::MultipleInheritanceFunction); -} - -bool NativeTypePointer::isVirtualInheritance() const { - if (!isMemberPointer()) - return false; - return isInheritanceKind( - Record->getMemberInfo(), - PointerToMemberRepresentation::VirtualInheritanceData, - PointerToMemberRepresentation::VirtualInheritanceFunction); -} - -bool NativeTypePointer::isMemberPointer() const { - return isPointerToDataMember() || isPointerToMemberFunction(); -} +//===- NativeTypePointer.cpp - info about pointer type ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) { + assert(TI.isSimple()); + assert(TI.getSimpleMode() != SimpleTypeMode::Direct); +} + +NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::PointerRecord Record) + : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI), + Record(std::move(Record)) {} + +NativeTypePointer::~NativeTypePointer() {} + +void NativeTypePointer::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + if (isMemberPointer()) { + dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session, + PdbSymbolIdField::ClassParent, ShowIdFields, + RecurseIdFields); + } + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent); + dumpSymbolField(OS, "isPointerToMemberFunction", isPointerToMemberFunction(), + Indent); + dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent); + dumpSymbolField(OS, "reference", isReference(), Indent); + dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent); + if (isMemberPointer()) { + if (isSingleInheritance()) + dumpSymbolField(OS, "isSingleInheritance", 1, Indent); + else if (isMultipleInheritance()) + dumpSymbolField(OS, "isMultipleInheritance", 1, Indent); + else if (isVirtualInheritance()) + dumpSymbolField(OS, "isVirtualInheritance", 1, Indent); + } + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +SymIndexId NativeTypePointer::getClassParentId() const { + if (!isMemberPointer()) + return 0; + + assert(Record); + const MemberPointerInfo &MPI = Record->getMemberInfo(); + return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType); +} + +uint64_t NativeTypePointer::getLength() const { + if (Record) + return Record->getSize(); + + switch (TI.getSimpleMode()) { + case SimpleTypeMode::NearPointer: + case SimpleTypeMode::FarPointer: + case SimpleTypeMode::HugePointer: + return 2; + case SimpleTypeMode::NearPointer32: + case SimpleTypeMode::FarPointer32: + return 4; + case SimpleTypeMode::NearPointer64: + return 8; + case SimpleTypeMode::NearPointer128: + return 16; + default: + assert(false && "invalid simple type mode!"); + } + return 0; +} + +SymIndexId NativeTypePointer::getTypeId() const { + // This is the pointee SymIndexId. + TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect(); + + return Session.getSymbolCache().findSymbolByTypeIndex(Referent); +} + +bool NativeTypePointer::isReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::LValueReference; +} + +bool NativeTypePointer::isRValueReference() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::RValueReference; +} + +bool NativeTypePointer::isPointerToDataMember() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToDataMember; +} + +bool NativeTypePointer::isPointerToMemberFunction() const { + if (!Record) + return false; + return Record->getMode() == PointerMode::PointerToMemberFunction; +} + +bool NativeTypePointer::isConstType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None; +} + +bool NativeTypePointer::isRestrictedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Restrict) != + PointerOptions::None; +} + +bool NativeTypePointer::isVolatileType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Volatile) != + PointerOptions::None; +} + +bool NativeTypePointer::isUnalignedType() const { + if (!Record) + return false; + return (Record->getOptions() & PointerOptions::Unaligned) != + PointerOptions::None; +} + +static inline bool isInheritanceKind(const MemberPointerInfo &MPI, + PointerToMemberRepresentation P1, + PointerToMemberRepresentation P2) { + return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2); +} + +bool NativeTypePointer::isSingleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::SingleInheritanceData, + PointerToMemberRepresentation::SingleInheritanceFunction); +} + +bool NativeTypePointer::isMultipleInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::MultipleInheritanceData, + PointerToMemberRepresentation::MultipleInheritanceFunction); +} + +bool NativeTypePointer::isVirtualInheritance() const { + if (!isMemberPointer()) + return false; + return isInheritanceKind( + Record->getMemberInfo(), + PointerToMemberRepresentation::VirtualInheritanceData, + PointerToMemberRepresentation::VirtualInheritanceFunction); +} + +bool NativeTypePointer::isMemberPointer() const { + return isPointerToDataMember() || isPointerToMemberFunction(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp index 72964a9e0d..2b25e8a9a8 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp @@ -1,29 +1,29 @@ -#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeTypeTypedef::NativeTypeTypedef(NativeSession &Session, SymIndexId Id, - codeview::UDTSym Typedef) - : NativeRawSymbol(Session, PDB_SymType::Typedef, Id), - Record(std::move(Typedef)) {} - -NativeTypeTypedef::~NativeTypeTypedef() {} - -void NativeTypeTypedef::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, - PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); -} - -std::string NativeTypeTypedef::getName() const { - return std::string(Record.Name); -} - -SymIndexId NativeTypeTypedef::getTypeId() const { - return Session.getSymbolCache().findSymbolByTypeIndex(Record.Type); -} +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeTypedef::NativeTypeTypedef(NativeSession &Session, SymIndexId Id, + codeview::UDTSym Typedef) + : NativeRawSymbol(Session, PDB_SymType::Typedef, Id), + Record(std::move(Typedef)) {} + +NativeTypeTypedef::~NativeTypeTypedef() {} + +void NativeTypeTypedef::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session, + PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields); +} + +std::string NativeTypeTypedef::getName() const { + return std::string(Record.Name); +} + +SymIndexId NativeTypeTypedef::getTypeId() const { + return Session.getSymbolCache().findSymbolByTypeIndex(Record.Type); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp index 917ec14e58..84ca5d0bea 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp @@ -1,220 +1,220 @@ -//===- NativeTypeUDT.cpp - info about class/struct type ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" - -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" - -#include <cassert> - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI, codeview::ClassRecord CR) - : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), - Class(std::move(CR)), Tag(Class.getPointer()) {} - -NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI, codeview::UnionRecord UR) - : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), - Union(std::move(UR)), Tag(Union.getPointer()) {} - -NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, - NativeTypeUDT &UnmodifiedType, - codeview::ModifierRecord Modifier) - : NativeRawSymbol(Session, PDB_SymType::UDT, Id), - UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} - -NativeTypeUDT::~NativeTypeUDT() {} - -void NativeTypeUDT::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolField(OS, "name", getName(), Indent); - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - if (Modifiers.hasValue()) - dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, - Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, - RecurseIdFields); - if (getUdtKind() != PDB_UdtType::Union) - dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(), - Indent); - dumpSymbolField(OS, "length", getLength(), Indent); - dumpSymbolField(OS, "udtKind", getUdtKind(), Indent); - dumpSymbolField(OS, "constructor", hasConstructor(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); - dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); - dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); - dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); - dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); - dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); - dumpSymbolField(OS, "nested", isNested(), Indent); - dumpSymbolField(OS, "packed", isPacked(), Indent); - dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); - dumpSymbolField(OS, "scoped", isScoped(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -std::string NativeTypeUDT::getName() const { - if (UnmodifiedType) - return UnmodifiedType->getName(); - - return std::string(Tag->getName()); -} - -SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; } - -SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const { - if (UnmodifiedType) - return UnmodifiedType->getSymIndexId(); - - return 0; -} - -SymIndexId NativeTypeUDT::getVirtualTableShapeId() const { - if (UnmodifiedType) - return UnmodifiedType->getVirtualTableShapeId(); - - if (Class) - return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape); - - return 0; -} - -uint64_t NativeTypeUDT::getLength() const { - if (UnmodifiedType) - return UnmodifiedType->getLength(); - - if (Class) - return Class->getSize(); - - return Union->getSize(); -} - -PDB_UdtType NativeTypeUDT::getUdtKind() const { - if (UnmodifiedType) - return UnmodifiedType->getUdtKind(); - - switch (Tag->Kind) { - case TypeRecordKind::Class: - return PDB_UdtType::Class; - case TypeRecordKind::Union: - return PDB_UdtType::Union; - case TypeRecordKind::Struct: - return PDB_UdtType::Struct; - case TypeRecordKind::Interface: - return PDB_UdtType::Interface; - default: +//===- NativeTypeUDT.cpp - info about class/struct type ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" + +#include <cassert> + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::ClassRecord CR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Class(std::move(CR)), Tag(Class.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, codeview::UnionRecord UR) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI), + Union(std::move(UR)), Tag(Union.getPointer()) {} + +NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id, + NativeTypeUDT &UnmodifiedType, + codeview::ModifierRecord Modifier) + : NativeRawSymbol(Session, PDB_SymType::UDT, Id), + UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {} + +NativeTypeUDT::~NativeTypeUDT() {} + +void NativeTypeUDT::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolField(OS, "name", getName(), Indent); + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + if (Modifiers.hasValue()) + dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent, + Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields, + RecurseIdFields); + if (getUdtKind() != PDB_UdtType::Union) + dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(), + Indent); + dumpSymbolField(OS, "length", getLength(), Indent); + dumpSymbolField(OS, "udtKind", getUdtKind(), Indent); + dumpSymbolField(OS, "constructor", hasConstructor(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent); + dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent); + dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent); + dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent); + dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent); + dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent); + dumpSymbolField(OS, "nested", isNested(), Indent); + dumpSymbolField(OS, "packed", isPacked(), Indent); + dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent); + dumpSymbolField(OS, "scoped", isScoped(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +std::string NativeTypeUDT::getName() const { + if (UnmodifiedType) + return UnmodifiedType->getName(); + + return std::string(Tag->getName()); +} + +SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; } + +SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const { + if (UnmodifiedType) + return UnmodifiedType->getSymIndexId(); + + return 0; +} + +SymIndexId NativeTypeUDT::getVirtualTableShapeId() const { + if (UnmodifiedType) + return UnmodifiedType->getVirtualTableShapeId(); + + if (Class) + return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape); + + return 0; +} + +uint64_t NativeTypeUDT::getLength() const { + if (UnmodifiedType) + return UnmodifiedType->getLength(); + + if (Class) + return Class->getSize(); + + return Union->getSize(); +} + +PDB_UdtType NativeTypeUDT::getUdtKind() const { + if (UnmodifiedType) + return UnmodifiedType->getUdtKind(); + + switch (Tag->Kind) { + case TypeRecordKind::Class: + return PDB_UdtType::Class; + case TypeRecordKind::Union: + return PDB_UdtType::Union; + case TypeRecordKind::Struct: + return PDB_UdtType::Struct; + case TypeRecordKind::Interface: + return PDB_UdtType::Interface; + default: llvm_unreachable("Unexpected udt kind"); - } -} - -bool NativeTypeUDT::hasConstructor() const { - if (UnmodifiedType) - return UnmodifiedType->hasConstructor(); - - return (Tag->Options & ClassOptions::HasConstructorOrDestructor) != - ClassOptions::None; -} - -bool NativeTypeUDT::isConstType() const { - if (!Modifiers) - return false; - return (Modifiers->Modifiers & ModifierOptions::Const) != - ModifierOptions::None; -} - -bool NativeTypeUDT::hasAssignmentOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasAssignmentOperator(); - - return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != - ClassOptions::None; -} - -bool NativeTypeUDT::hasCastOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasCastOperator(); - - return (Tag->Options & ClassOptions::HasConversionOperator) != - ClassOptions::None; -} - -bool NativeTypeUDT::hasNestedTypes() const { - if (UnmodifiedType) - return UnmodifiedType->hasNestedTypes(); - - return (Tag->Options & ClassOptions::ContainsNestedClass) != - ClassOptions::None; -} - -bool NativeTypeUDT::hasOverloadedOperator() const { - if (UnmodifiedType) - return UnmodifiedType->hasOverloadedOperator(); - - return (Tag->Options & ClassOptions::HasOverloadedOperator) != - ClassOptions::None; -} - -bool NativeTypeUDT::isInterfaceUdt() const { return false; } - -bool NativeTypeUDT::isIntrinsic() const { - if (UnmodifiedType) - return UnmodifiedType->isIntrinsic(); - - return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None; -} - -bool NativeTypeUDT::isNested() const { - if (UnmodifiedType) - return UnmodifiedType->isNested(); - - return (Tag->Options & ClassOptions::Nested) != ClassOptions::None; -} - -bool NativeTypeUDT::isPacked() const { - if (UnmodifiedType) - return UnmodifiedType->isPacked(); - - return (Tag->Options & ClassOptions::Packed) != ClassOptions::None; -} - -bool NativeTypeUDT::isRefUdt() const { return false; } - -bool NativeTypeUDT::isScoped() const { - if (UnmodifiedType) - return UnmodifiedType->isScoped(); - - return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None; -} - -bool NativeTypeUDT::isValueUdt() const { return false; } - -bool NativeTypeUDT::isUnalignedType() const { - if (!Modifiers) - return false; - return (Modifiers->Modifiers & ModifierOptions::Unaligned) != - ModifierOptions::None; -} - -bool NativeTypeUDT::isVolatileType() const { - if (!Modifiers) - return false; - return (Modifiers->Modifiers & ModifierOptions::Volatile) != - ModifierOptions::None; -} + } +} + +bool NativeTypeUDT::hasConstructor() const { + if (UnmodifiedType) + return UnmodifiedType->hasConstructor(); + + return (Tag->Options & ClassOptions::HasConstructorOrDestructor) != + ClassOptions::None; +} + +bool NativeTypeUDT::isConstType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Const) != + ModifierOptions::None; +} + +bool NativeTypeUDT::hasAssignmentOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasAssignmentOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasCastOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasCastOperator(); + + return (Tag->Options & ClassOptions::HasConversionOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasNestedTypes() const { + if (UnmodifiedType) + return UnmodifiedType->hasNestedTypes(); + + return (Tag->Options & ClassOptions::ContainsNestedClass) != + ClassOptions::None; +} + +bool NativeTypeUDT::hasOverloadedOperator() const { + if (UnmodifiedType) + return UnmodifiedType->hasOverloadedOperator(); + + return (Tag->Options & ClassOptions::HasOverloadedOperator) != + ClassOptions::None; +} + +bool NativeTypeUDT::isInterfaceUdt() const { return false; } + +bool NativeTypeUDT::isIntrinsic() const { + if (UnmodifiedType) + return UnmodifiedType->isIntrinsic(); + + return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None; +} + +bool NativeTypeUDT::isNested() const { + if (UnmodifiedType) + return UnmodifiedType->isNested(); + + return (Tag->Options & ClassOptions::Nested) != ClassOptions::None; +} + +bool NativeTypeUDT::isPacked() const { + if (UnmodifiedType) + return UnmodifiedType->isPacked(); + + return (Tag->Options & ClassOptions::Packed) != ClassOptions::None; +} + +bool NativeTypeUDT::isRefUdt() const { return false; } + +bool NativeTypeUDT::isScoped() const { + if (UnmodifiedType) + return UnmodifiedType->isScoped(); + + return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None; +} + +bool NativeTypeUDT::isValueUdt() const { return false; } + +bool NativeTypeUDT::isUnalignedType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Unaligned) != + ModifierOptions::None; +} + +bool NativeTypeUDT::isVolatileType() const { + if (!Modifiers) + return false; + return (Modifiers->Modifiers & ModifierOptions::Volatile) != + ModifierOptions::None; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp index 837fe19ec8..eb7bf8fa0f 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp @@ -1,35 +1,35 @@ -#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" - -using namespace llvm; -using namespace llvm::pdb; - -// Create a pointer record for a non-simple type. -NativeTypeVTShape::NativeTypeVTShape(NativeSession &Session, SymIndexId Id, - codeview::TypeIndex TI, - codeview::VFTableShapeRecord SR) - : NativeRawSymbol(Session, PDB_SymType::VTableShape, Id), TI(TI), - Record(std::move(SR)) {} - -NativeTypeVTShape::~NativeTypeVTShape() {} - -void NativeTypeVTShape::dump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowIdFields, - PdbSymbolIdField RecurseIdFields) const { - NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); - - dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, - PdbSymbolIdField::LexicalParent, ShowIdFields, - RecurseIdFields); - dumpSymbolField(OS, "count", getCount(), Indent); - dumpSymbolField(OS, "constType", isConstType(), Indent); - dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); - dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); -} - -bool NativeTypeVTShape::isConstType() const { return false; } - -bool NativeTypeVTShape::isVolatileType() const { return false; } - -bool NativeTypeVTShape::isUnalignedType() const { return false; } - -uint32_t NativeTypeVTShape::getCount() const { return Record.Slots.size(); } +#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" + +using namespace llvm; +using namespace llvm::pdb; + +// Create a pointer record for a non-simple type. +NativeTypeVTShape::NativeTypeVTShape(NativeSession &Session, SymIndexId Id, + codeview::TypeIndex TI, + codeview::VFTableShapeRecord SR) + : NativeRawSymbol(Session, PDB_SymType::VTableShape, Id), TI(TI), + Record(std::move(SR)) {} + +NativeTypeVTShape::~NativeTypeVTShape() {} + +void NativeTypeVTShape::dump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowIdFields, + PdbSymbolIdField RecurseIdFields) const { + NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields); + + dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session, + PdbSymbolIdField::LexicalParent, ShowIdFields, + RecurseIdFields); + dumpSymbolField(OS, "count", getCount(), Indent); + dumpSymbolField(OS, "constType", isConstType(), Indent); + dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent); + dumpSymbolField(OS, "volatileType", isVolatileType(), Indent); +} + +bool NativeTypeVTShape::isConstType() const { return false; } + +bool NativeTypeVTShape::isVolatileType() const { return false; } + +bool NativeTypeVTShape::isUnalignedType() const { return false; } + +uint32_t NativeTypeVTShape::getCount() const { return Record.Slots.size(); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFile.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFile.cpp index cde6452368..112b5c9fed 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -1,508 +1,508 @@ -//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" -#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/Support/BinaryStream.h" -#include "llvm/Support/BinaryStreamArray.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/Path.h" -#include <algorithm> -#include <cassert> -#include <cstdint> - -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(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, - BumpPtrAllocator &Allocator) - : FilePath(std::string(Path)), Allocator(Allocator), - Buffer(std::move(PdbFileBuffer)) {} - -PDBFile::~PDBFile() = default; - -StringRef PDBFile::getFilePath() const { return FilePath; } - -StringRef PDBFile::getFileDirectory() const { - return sys::path::parent_path(FilePath); -} - -uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } - -uint32_t PDBFile::getFreeBlockMapBlock() const { - return ContainerLayout.SB->FreeBlockMapBlock; -} - -uint32_t PDBFile::getBlockCount() const { - return ContainerLayout.SB->NumBlocks; -} - -uint32_t PDBFile::getNumDirectoryBytes() const { - return ContainerLayout.SB->NumDirectoryBytes; -} - -uint32_t PDBFile::getBlockMapIndex() const { - return ContainerLayout.SB->BlockMapAddr; -} - -uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } - -uint32_t PDBFile::getNumDirectoryBlocks() const { - return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, - ContainerLayout.SB->BlockSize); -} - -uint64_t PDBFile::getBlockMapOffset() const { - return (uint64_t)ContainerLayout.SB->BlockMapAddr * - ContainerLayout.SB->BlockSize; -} - -uint32_t PDBFile::getNumStreams() const { - return ContainerLayout.StreamSizes.size(); -} - -uint32_t PDBFile::getMaxStreamSize() const { - return *std::max_element(ContainerLayout.StreamSizes.begin(), - ContainerLayout.StreamSizes.end()); -} - -uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { - return ContainerLayout.StreamSizes[StreamIndex]; -} - -ArrayRef<support::ulittle32_t> -PDBFile::getStreamBlockList(uint32_t StreamIndex) const { - return ContainerLayout.StreamMap[StreamIndex]; -} - -uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } - -Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, - uint32_t NumBytes) const { - uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); - - ArrayRef<uint8_t> Result; - if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result)) - return std::move(EC); - return Result; -} - -Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, - ArrayRef<uint8_t> Data) const { - return make_error<RawError>(raw_error_code::not_writable, - "PDBFile is immutable"); -} - -Error PDBFile::parseFileHeaders() { - BinaryStreamReader 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, - "MSF superblock is missing"); - } - - 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, Allocator); - BinaryStreamReader FpmReader(*FpmStream); - ArrayRef<uint8_t> FpmBytes; - if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining())) - 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(ContainerLayout.DirectoryBlocks, - getNumDirectoryBlocks())) - return EC; - - return Error::success(); -} - -Error PDBFile::parseStreamData() { - assert(ContainerLayout.SB); - if (DirectoryStream) - return Error::success(); - - uint32_t NumStreams = 0; - - // Normally you can't use a MappedBlockStream without having fully parsed the - // PDB file, because it accesses the directory and various other things, which - // 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(ContainerLayout, *Buffer, - Allocator); - BinaryStreamReader Reader(*DS); - if (auto EC = Reader.readInteger(NumStreams)) - return EC; - - 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, 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 - // it with an ArrayRef instead of setting up a StreamRef. Since the - // DirectoryStream is cached in the class and thus lives for the life of the - // class, we can be guaranteed that readArray() will return a stable - // reference, even if it has to allocate from its internal pool. - ArrayRef<support::ulittle32_t> Blocks; - if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) - return EC; - for (uint32_t Block : Blocks) { - 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."); - } - ContainerLayout.StreamMap.push_back(Blocks); - } - - // We should have read exactly SB->NumDirectoryBytes bytes. - assert(Reader.bytesRemaining() == 0); - DirectoryStream = std::move(DS); - return Error::success(); -} - -ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { - return ContainerLayout.DirectoryBlocks; -} - -std::unique_ptr<MappedBlockStream> -PDBFile::createIndexedStream(uint16_t SN) const { - if (SN == kInvalidStreamIndex) - return nullptr; - return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN, - Allocator); -} - -MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { - MSFStreamLayout Result; - auto Blocks = getStreamBlockList(StreamIdx); - Result.Blocks.assign(Blocks.begin(), Blocks.end()); - Result.Length = getStreamByteSize(StreamIdx); - return Result; -} - -msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const { - return msf::getFpmStreamLayout(ContainerLayout); -} - -Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { - if (!Globals) { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return DbiS.takeError(); - - auto GlobalS = - safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex()); - if (!GlobalS) - return GlobalS.takeError(); - auto TempGlobals = std::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 = safelyCreateIndexedStream(StreamPDB); - if (!InfoS) - return InfoS.takeError(); - auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS)); - if (auto EC = TempInfo->reload()) - return std::move(EC); - Info = std::move(TempInfo); - } - return *Info; -} - -Expected<DbiStream &> PDBFile::getPDBDbiStream() { - if (!Dbi) { - auto DbiS = safelyCreateIndexedStream(StreamDBI); - if (!DbiS) - return DbiS.takeError(); - auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS)); - if (auto EC = TempDbi->reload(this)) - return std::move(EC); - Dbi = std::move(TempDbi); - } - return *Dbi; -} - -Expected<TpiStream &> PDBFile::getPDBTpiStream() { - if (!Tpi) { - auto TpiS = safelyCreateIndexedStream(StreamTPI); - if (!TpiS) - return TpiS.takeError(); - auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS)); - if (auto EC = TempTpi->reload()) - return std::move(EC); - Tpi = std::move(TempTpi); - } - return *Tpi; -} - -Expected<TpiStream &> PDBFile::getPDBIpiStream() { - if (!Ipi) { - if (!hasPDBIpiStream()) - return make_error<RawError>(raw_error_code::no_stream); - - auto IpiS = safelyCreateIndexedStream(StreamIPI); - if (!IpiS) - return IpiS.takeError(); - auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS)); - if (auto EC = TempIpi->reload()) - return std::move(EC); - Ipi = std::move(TempIpi); - } - return *Ipi; -} - -Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { - if (!Publics) { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return DbiS.takeError(); - - auto PublicS = - safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex()); - if (!PublicS) - return PublicS.takeError(); - auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS)); - if (auto EC = TempPublics->reload()) - return std::move(EC); - Publics = std::move(TempPublics); - } - return *Publics; -} - -Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { - if (!Symbols) { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return DbiS.takeError(); - - uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); - auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum); - if (!SymbolS) - return SymbolS.takeError(); - - auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS)); - if (auto EC = TempSymbols->reload()) - return std::move(EC); - Symbols = std::move(TempSymbols); - } - return *Symbols; -} - -Expected<PDBStringTable &> PDBFile::getStringTable() { - if (!Strings) { - auto NS = safelyCreateNamedStream("/names"); - if (!NS) - return NS.takeError(); - - auto N = std::make_unique<PDBStringTable>(); - BinaryStreamReader Reader(**NS); - if (auto EC = N->reload(Reader)) - return std::move(EC); - assert(Reader.bytesRemaining() == 0); - StringTableStream = std::move(*NS); - Strings = std::move(N); - } - return *Strings; -} - -Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() { - if (!InjectedSources) { - auto IJS = safelyCreateNamedStream("/src/headerblock"); - if (!IJS) - return IJS.takeError(); - - auto Strings = getStringTable(); - if (!Strings) - return Strings.takeError(); - - auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS)); - if (auto EC = IJ->reload(*Strings)) - return std::move(EC); - InjectedSources = std::move(IJ); - } - return *InjectedSources; -} - -uint32_t PDBFile::getPointerSize() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return 0; - PDB_Machine Machine = DbiS->getMachineType(); - if (Machine == PDB_Machine::Amd64) - return 8; - return 4; -} - -bool PDBFile::hasPDBDbiStream() const { - return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0; -} - -bool PDBFile::hasPDBGlobalsStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) { - consumeError(DbiS.takeError()); - return false; - } - - return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); -} - -bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); } - -bool PDBFile::hasPDBIpiStream() const { - if (!hasPDBInfoStream()) - return false; - - if (StreamIPI >= getNumStreams()) - return false; - - auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream()); - return InfoStream.containsIdStream(); -} - -bool PDBFile::hasPDBPublicsStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) { - consumeError(DbiS.takeError()); - return false; - } - return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); -} - -bool PDBFile::hasPDBSymbolStream() { - auto DbiS = getPDBDbiStream(); - if (!DbiS) - return false; - return DbiS->getSymRecordStreamIndex() < getNumStreams(); -} - -bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } - -bool PDBFile::hasPDBStringTable() { - auto IS = getPDBInfoStream(); - if (!IS) - return false; - Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); - if (!ExpectedNSI) { - consumeError(ExpectedNSI.takeError()); - return false; - } - assert(*ExpectedNSI < getNumStreams()); - return true; -} - -bool PDBFile::hasPDBInjectedSourceStream() { - auto IS = getPDBInfoStream(); - if (!IS) - return false; - Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock"); - if (!ExpectedNSI) { - consumeError(ExpectedNSI.takeError()); - return false; - } - assert(*ExpectedNSI < getNumStreams()); - return true; -} - -/// 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(uint32_t StreamIndex) const { - if (StreamIndex >= getNumStreams()) - // This rejects kInvalidStreamIndex with an error as well. - return make_error<RawError>(raw_error_code::no_stream); - return createIndexedStream(StreamIndex); -} - -Expected<std::unique_ptr<MappedBlockStream>> -PDBFile::safelyCreateNamedStream(StringRef Name) { - auto IS = getPDBInfoStream(); - if (!IS) - return IS.takeError(); - - Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name); - if (!ExpectedNSI) - return ExpectedNSI.takeError(); - uint32_t NameStreamIndex = *ExpectedNSI; - - return safelyCreateIndexedStream(NameStreamIndex); -} +//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +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(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer, + BumpPtrAllocator &Allocator) + : FilePath(std::string(Path)), Allocator(Allocator), + Buffer(std::move(PdbFileBuffer)) {} + +PDBFile::~PDBFile() = default; + +StringRef PDBFile::getFilePath() const { return FilePath; } + +StringRef PDBFile::getFileDirectory() const { + return sys::path::parent_path(FilePath); +} + +uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; } + +uint32_t PDBFile::getFreeBlockMapBlock() const { + return ContainerLayout.SB->FreeBlockMapBlock; +} + +uint32_t PDBFile::getBlockCount() const { + return ContainerLayout.SB->NumBlocks; +} + +uint32_t PDBFile::getNumDirectoryBytes() const { + return ContainerLayout.SB->NumDirectoryBytes; +} + +uint32_t PDBFile::getBlockMapIndex() const { + return ContainerLayout.SB->BlockMapAddr; +} + +uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; } + +uint32_t PDBFile::getNumDirectoryBlocks() const { + return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes, + ContainerLayout.SB->BlockSize); +} + +uint64_t PDBFile::getBlockMapOffset() const { + return (uint64_t)ContainerLayout.SB->BlockMapAddr * + ContainerLayout.SB->BlockSize; +} + +uint32_t PDBFile::getNumStreams() const { + return ContainerLayout.StreamSizes.size(); +} + +uint32_t PDBFile::getMaxStreamSize() const { + return *std::max_element(ContainerLayout.StreamSizes.begin(), + ContainerLayout.StreamSizes.end()); +} + +uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { + return ContainerLayout.StreamSizes[StreamIndex]; +} + +ArrayRef<support::ulittle32_t> +PDBFile::getStreamBlockList(uint32_t StreamIndex) const { + return ContainerLayout.StreamMap[StreamIndex]; +} + +uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } + +Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, + uint32_t NumBytes) const { + uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize()); + + ArrayRef<uint8_t> Result; + if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result)) + return std::move(EC); + return Result; +} + +Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, + ArrayRef<uint8_t> Data) const { + return make_error<RawError>(raw_error_code::not_writable, + "PDBFile is immutable"); +} + +Error PDBFile::parseFileHeaders() { + BinaryStreamReader 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, + "MSF superblock is missing"); + } + + 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, Allocator); + BinaryStreamReader FpmReader(*FpmStream); + ArrayRef<uint8_t> FpmBytes; + if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining())) + 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(ContainerLayout.DirectoryBlocks, + getNumDirectoryBlocks())) + return EC; + + return Error::success(); +} + +Error PDBFile::parseStreamData() { + assert(ContainerLayout.SB); + if (DirectoryStream) + return Error::success(); + + uint32_t NumStreams = 0; + + // Normally you can't use a MappedBlockStream without having fully parsed the + // PDB file, because it accesses the directory and various other things, which + // 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(ContainerLayout, *Buffer, + Allocator); + BinaryStreamReader Reader(*DS); + if (auto EC = Reader.readInteger(NumStreams)) + return EC; + + 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, 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 + // it with an ArrayRef instead of setting up a StreamRef. Since the + // DirectoryStream is cached in the class and thus lives for the life of the + // class, we can be guaranteed that readArray() will return a stable + // reference, even if it has to allocate from its internal pool. + ArrayRef<support::ulittle32_t> Blocks; + if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) + return EC; + for (uint32_t Block : Blocks) { + 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."); + } + ContainerLayout.StreamMap.push_back(Blocks); + } + + // We should have read exactly SB->NumDirectoryBytes bytes. + assert(Reader.bytesRemaining() == 0); + DirectoryStream = std::move(DS); + return Error::success(); +} + +ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { + return ContainerLayout.DirectoryBlocks; +} + +std::unique_ptr<MappedBlockStream> +PDBFile::createIndexedStream(uint16_t SN) const { + if (SN == kInvalidStreamIndex) + return nullptr; + return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN, + Allocator); +} + +MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { + MSFStreamLayout Result; + auto Blocks = getStreamBlockList(StreamIdx); + Result.Blocks.assign(Blocks.begin(), Blocks.end()); + Result.Length = getStreamByteSize(StreamIdx); + return Result; +} + +msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const { + return msf::getFpmStreamLayout(ContainerLayout); +} + +Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() { + if (!Globals) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto GlobalS = + safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex()); + if (!GlobalS) + return GlobalS.takeError(); + auto TempGlobals = std::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 = safelyCreateIndexedStream(StreamPDB); + if (!InfoS) + return InfoS.takeError(); + auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS)); + if (auto EC = TempInfo->reload()) + return std::move(EC); + Info = std::move(TempInfo); + } + return *Info; +} + +Expected<DbiStream &> PDBFile::getPDBDbiStream() { + if (!Dbi) { + auto DbiS = safelyCreateIndexedStream(StreamDBI); + if (!DbiS) + return DbiS.takeError(); + auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS)); + if (auto EC = TempDbi->reload(this)) + return std::move(EC); + Dbi = std::move(TempDbi); + } + return *Dbi; +} + +Expected<TpiStream &> PDBFile::getPDBTpiStream() { + if (!Tpi) { + auto TpiS = safelyCreateIndexedStream(StreamTPI); + if (!TpiS) + return TpiS.takeError(); + auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS)); + if (auto EC = TempTpi->reload()) + return std::move(EC); + Tpi = std::move(TempTpi); + } + return *Tpi; +} + +Expected<TpiStream &> PDBFile::getPDBIpiStream() { + if (!Ipi) { + if (!hasPDBIpiStream()) + return make_error<RawError>(raw_error_code::no_stream); + + auto IpiS = safelyCreateIndexedStream(StreamIPI); + if (!IpiS) + return IpiS.takeError(); + auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS)); + if (auto EC = TempIpi->reload()) + return std::move(EC); + Ipi = std::move(TempIpi); + } + return *Ipi; +} + +Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { + if (!Publics) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto PublicS = + safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex()); + if (!PublicS) + return PublicS.takeError(); + auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS)); + if (auto EC = TempPublics->reload()) + return std::move(EC); + Publics = std::move(TempPublics); + } + return *Publics; +} + +Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { + if (!Symbols) { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); + auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum); + if (!SymbolS) + return SymbolS.takeError(); + + auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS)); + if (auto EC = TempSymbols->reload()) + return std::move(EC); + Symbols = std::move(TempSymbols); + } + return *Symbols; +} + +Expected<PDBStringTable &> PDBFile::getStringTable() { + if (!Strings) { + auto NS = safelyCreateNamedStream("/names"); + if (!NS) + return NS.takeError(); + + auto N = std::make_unique<PDBStringTable>(); + BinaryStreamReader Reader(**NS); + if (auto EC = N->reload(Reader)) + return std::move(EC); + assert(Reader.bytesRemaining() == 0); + StringTableStream = std::move(*NS); + Strings = std::move(N); + } + return *Strings; +} + +Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() { + if (!InjectedSources) { + auto IJS = safelyCreateNamedStream("/src/headerblock"); + if (!IJS) + return IJS.takeError(); + + auto Strings = getStringTable(); + if (!Strings) + return Strings.takeError(); + + auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS)); + if (auto EC = IJ->reload(*Strings)) + return std::move(EC); + InjectedSources = std::move(IJ); + } + return *InjectedSources; +} + +uint32_t PDBFile::getPointerSize() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return 0; + PDB_Machine Machine = DbiS->getMachineType(); + if (Machine == PDB_Machine::Amd64) + return 8; + return 4; +} + +bool PDBFile::hasPDBDbiStream() const { + return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0; +} + +bool PDBFile::hasPDBGlobalsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) { + consumeError(DbiS.takeError()); + return false; + } + + return DbiS->getGlobalSymbolStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); } + +bool PDBFile::hasPDBIpiStream() const { + if (!hasPDBInfoStream()) + return false; + + if (StreamIPI >= getNumStreams()) + return false; + + auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream()); + return InfoStream.containsIdStream(); +} + +bool PDBFile::hasPDBPublicsStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) { + consumeError(DbiS.takeError()); + return false; + } + return DbiS->getPublicSymbolStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBSymbolStream() { + auto DbiS = getPDBDbiStream(); + if (!DbiS) + return false; + return DbiS->getSymRecordStreamIndex() < getNumStreams(); +} + +bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); } + +bool PDBFile::hasPDBStringTable() { + auto IS = getPDBInfoStream(); + if (!IS) + return false; + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; +} + +bool PDBFile::hasPDBInjectedSourceStream() { + auto IS = getPDBInfoStream(); + if (!IS) + return false; + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; +} + +/// 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(uint32_t StreamIndex) const { + if (StreamIndex >= getNumStreams()) + // This rejects kInvalidStreamIndex with an error as well. + return make_error<RawError>(raw_error_code::no_stream); + return createIndexedStream(StreamIndex); +} + +Expected<std::unique_ptr<MappedBlockStream>> +PDBFile::safelyCreateNamedStream(StringRef Name) { + auto IS = getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name); + if (!ExpectedNSI) + return ExpectedNSI.takeError(); + uint32_t NameStreamIndex = *ExpectedNSI; + + return safelyCreateIndexedStream(NameStreamIndex); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp index deb0f201a7..cc89a4ae9d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -1,356 +1,356 @@ -//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" -#include "llvm/Support/BinaryStream.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/CRC.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/xxhash.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; -using namespace llvm::support; - -PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) - : Allocator(Allocator), InjectedSourceHashTraits(Strings), - InjectedSourceTable(2) {} - -PDBFileBuilder::~PDBFileBuilder() {} - -Error PDBFileBuilder::initialize(uint32_t BlockSize) { - auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); - if (!ExpectedMsf) - return ExpectedMsf.takeError(); - Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); - return Error::success(); -} - -MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } - -InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { - if (!Info) - Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); - return *Info; -} - -DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { - if (!Dbi) - Dbi = std::make_unique<DbiStreamBuilder>(*Msf); - return *Dbi; -} - -TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { - if (!Tpi) - Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); - return *Tpi; -} - -TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { - if (!Ipi) - Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); - return *Ipi; -} - -PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { - return Strings; -} - -GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { - if (!Gsi) - Gsi = std::make_unique<GSIStreamBuilder>(*Msf); - return *Gsi; -} - -Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, - uint32_t Size) { - auto ExpectedStream = Msf->addStream(Size); - if (ExpectedStream) - NamedStreams.set(Name, *ExpectedStream); - return ExpectedStream; -} - -Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { - Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - assert(NamedStreamData.count(*ExpectedIndex) == 0); - NamedStreamData[*ExpectedIndex] = std::string(Data); - return Error::success(); -} - -void PDBFileBuilder::addInjectedSource(StringRef Name, - std::unique_ptr<MemoryBuffer> Buffer) { - // Stream names must be exact matches, since they get looked up in a hash - // table and the hash value is dependent on the exact contents of the string. - // link.exe lowercases a path and converts / to \, so we must do the same. - SmallString<64> VName; - sys::path::native(Name.lower(), VName); - - uint32_t NI = getStringTableBuilder().insert(Name); - uint32_t VNI = getStringTableBuilder().insert(VName); - - InjectedSourceDescriptor Desc; - Desc.Content = std::move(Buffer); - Desc.NameIndex = NI; - Desc.VNameIndex = VNI; - Desc.StreamName = "/src/files/"; - - Desc.StreamName += VName; - - InjectedSources.push_back(std::move(Desc)); -} - -Error PDBFileBuilder::finalizeMsfLayout() { - - if (Ipi && Ipi->getRecordCount() > 0) { - // In theory newer PDBs always have an ID stream, but by saying that we're - // only going to *really* have an ID stream if there is at least one ID - // record, we leave open the opportunity to test older PDBs such as those - // that don't have an ID stream. - auto &Info = getInfoBuilder(); - Info.addFeature(PdbRaw_FeatureSig::VC140); - } - - uint32_t StringsLen = Strings.calculateSerializedSize(); - - Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); - if (!SN) - return SN.takeError(); - - if (Gsi) { - if (auto EC = Gsi->finalizeMsfLayout()) - return EC; - if (Dbi) { - Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); - Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); - Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex()); - } - } - if (Tpi) { - if (auto EC = Tpi->finalizeMsfLayout()) - return EC; - } - if (Dbi) { - if (auto EC = Dbi->finalizeMsfLayout()) - return EC; - } - SN = allocateNamedStream("/names", StringsLen); - if (!SN) - return SN.takeError(); - - if (Ipi) { - if (auto EC = Ipi->finalizeMsfLayout()) - return EC; - } - - // Do this last, since it relies on the named stream map being complete, and - // that can be updated by previous steps in the finalization. - if (Info) { - if (auto EC = Info->finalizeMsfLayout()) - return EC; - } - - if (!InjectedSources.empty()) { - for (const auto &IS : InjectedSources) { - JamCRC CRC(0); - CRC.update(arrayRefFromStringRef(IS.Content->getBuffer())); - - SrcHeaderBlockEntry Entry; - ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); - Entry.Size = sizeof(SrcHeaderBlockEntry); - Entry.FileSize = IS.Content->getBufferSize(); - Entry.FileNI = IS.NameIndex; - Entry.VFileNI = IS.VNameIndex; - Entry.ObjNI = 1; - Entry.IsVirtual = 0; - Entry.Version = - static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); - Entry.CRC = CRC.getCRC(); - StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); - InjectedSourceTable.set_as(VName, std::move(Entry), - InjectedSourceHashTraits); - } - - uint32_t SrcHeaderBlockSize = - sizeof(SrcHeaderBlockHeader) + - InjectedSourceTable.calculateSerializedLength(); - SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); - if (!SN) - return SN.takeError(); - for (const auto &IS : InjectedSources) { - SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); - if (!SN) - return SN.takeError(); - } - } - - // Do this last, since it relies on the named stream map being complete, and - // that can be updated by previous steps in the finalization. - if (Info) { - if (auto EC = Info->finalizeMsfLayout()) - return EC; - } - - return Error::success(); -} - -Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { - uint32_t SN = 0; - if (!NamedStreams.get(Name, SN)) - return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); - return SN; -} - -void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, - const msf::MSFLayout &Layout) { - assert(!InjectedSourceTable.empty()); - - uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); - auto Stream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, SN, Allocator); - BinaryStreamWriter Writer(*Stream); - - SrcHeaderBlockHeader Header; - ::memset(&Header, 0, sizeof(Header)); - Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); - Header.Size = Writer.bytesRemaining(); - - cantFail(Writer.writeObject(Header)); - cantFail(InjectedSourceTable.commit(Writer)); - - assert(Writer.bytesRemaining() == 0); -} - -void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, - const msf::MSFLayout &Layout) { - if (InjectedSourceTable.empty()) - return; - - commitSrcHeaderBlock(MsfBuffer, Layout); - - for (const auto &IS : InjectedSources) { - uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); - - auto SourceStream = WritableMappedBlockStream::createIndexedStream( - Layout, MsfBuffer, SN, Allocator); - BinaryStreamWriter SourceWriter(*SourceStream); - assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); - cantFail(SourceWriter.writeBytes( - arrayRefFromStringRef(IS.Content->getBuffer()))); - } -} - -Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { - assert(!Filename.empty()); - if (auto EC = finalizeMsfLayout()) - return EC; - - MSFLayout Layout; - Expected<FileBufferByteStream> ExpectedMsfBuffer = - Msf->commit(Filename, Layout); - if (!ExpectedMsfBuffer) - return ExpectedMsfBuffer.takeError(); - FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); - - auto ExpectedSN = getNamedStreamIndex("/names"); - if (!ExpectedSN) - return ExpectedSN.takeError(); - - auto NS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, *ExpectedSN, Allocator); - BinaryStreamWriter NSWriter(*NS); - if (auto EC = Strings.commit(NSWriter)) - return EC; - - for (const auto &NSE : NamedStreamData) { - if (NSE.second.empty()) - continue; - - auto NS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, NSE.first, Allocator); - BinaryStreamWriter NSW(*NS); - if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) - return EC; - } - - if (Info) { - if (auto EC = Info->commit(Layout, Buffer)) - return EC; - } - - if (Dbi) { - if (auto EC = Dbi->commit(Layout, Buffer)) - return EC; - } - - if (Tpi) { - if (auto EC = Tpi->commit(Layout, Buffer)) - return EC; - } - - if (Ipi) { - if (auto EC = Ipi->commit(Layout, Buffer)) - return EC; - } - - if (Gsi) { - if (auto EC = Gsi->commit(Layout, Buffer)) - return EC; - } - - auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; - assert(!InfoStreamBlocks.empty()); - uint64_t InfoStreamFileOffset = - blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); - InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( - Buffer.getBufferStart() + InfoStreamFileOffset); - - commitInjectedSources(Buffer, Layout); - - // Set the build id at the very end, after every other byte of the PDB - // has been written. - if (Info->hashPDBContentsToGUID()) { - // Compute a hash of all sections of the output file. - uint64_t Digest = - xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); - - H->Age = 1; - - memcpy(H->Guid.Guid, &Digest, 8); - // xxhash only gives us 8 bytes, so put some fixed data in the other half. - memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); - - // Put the hash in the Signature field too. - H->Signature = static_cast<uint32_t>(Digest); - - // Return GUID to caller. - memcpy(Guid, H->Guid.Guid, 16); - } else { - H->Age = Info->getAge(); - H->Guid = Info->getGuid(); - Optional<uint32_t> Sig = Info->getSignature(); - H->Signature = Sig.hasValue() ? *Sig : time(nullptr); - } - - return Buffer.commit(); -} +//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/xxhash.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; +using namespace llvm::support; + +PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) + : Allocator(Allocator), InjectedSourceHashTraits(Strings), + InjectedSourceTable(2) {} + +PDBFileBuilder::~PDBFileBuilder() {} + +Error PDBFileBuilder::initialize(uint32_t BlockSize) { + auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); + if (!ExpectedMsf) + return ExpectedMsf.takeError(); + Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); + return Error::success(); +} + +MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } + +InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { + if (!Info) + Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); + return *Info; +} + +DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { + if (!Dbi) + Dbi = std::make_unique<DbiStreamBuilder>(*Msf); + return *Dbi; +} + +TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { + if (!Tpi) + Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); + return *Tpi; +} + +TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { + if (!Ipi) + Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); + return *Ipi; +} + +PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { + return Strings; +} + +GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { + if (!Gsi) + Gsi = std::make_unique<GSIStreamBuilder>(*Msf); + return *Gsi; +} + +Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, + uint32_t Size) { + auto ExpectedStream = Msf->addStream(Size); + if (ExpectedStream) + NamedStreams.set(Name, *ExpectedStream); + return ExpectedStream; +} + +Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { + Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + assert(NamedStreamData.count(*ExpectedIndex) == 0); + NamedStreamData[*ExpectedIndex] = std::string(Data); + return Error::success(); +} + +void PDBFileBuilder::addInjectedSource(StringRef Name, + std::unique_ptr<MemoryBuffer> Buffer) { + // Stream names must be exact matches, since they get looked up in a hash + // table and the hash value is dependent on the exact contents of the string. + // link.exe lowercases a path and converts / to \, so we must do the same. + SmallString<64> VName; + sys::path::native(Name.lower(), VName); + + uint32_t NI = getStringTableBuilder().insert(Name); + uint32_t VNI = getStringTableBuilder().insert(VName); + + InjectedSourceDescriptor Desc; + Desc.Content = std::move(Buffer); + Desc.NameIndex = NI; + Desc.VNameIndex = VNI; + Desc.StreamName = "/src/files/"; + + Desc.StreamName += VName; + + InjectedSources.push_back(std::move(Desc)); +} + +Error PDBFileBuilder::finalizeMsfLayout() { + + if (Ipi && Ipi->getRecordCount() > 0) { + // In theory newer PDBs always have an ID stream, but by saying that we're + // only going to *really* have an ID stream if there is at least one ID + // record, we leave open the opportunity to test older PDBs such as those + // that don't have an ID stream. + auto &Info = getInfoBuilder(); + Info.addFeature(PdbRaw_FeatureSig::VC140); + } + + uint32_t StringsLen = Strings.calculateSerializedSize(); + + Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); + if (!SN) + return SN.takeError(); + + if (Gsi) { + if (auto EC = Gsi->finalizeMsfLayout()) + return EC; + if (Dbi) { + Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); + Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); + Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex()); + } + } + if (Tpi) { + if (auto EC = Tpi->finalizeMsfLayout()) + return EC; + } + if (Dbi) { + if (auto EC = Dbi->finalizeMsfLayout()) + return EC; + } + SN = allocateNamedStream("/names", StringsLen); + if (!SN) + return SN.takeError(); + + if (Ipi) { + if (auto EC = Ipi->finalizeMsfLayout()) + return EC; + } + + // Do this last, since it relies on the named stream map being complete, and + // that can be updated by previous steps in the finalization. + if (Info) { + if (auto EC = Info->finalizeMsfLayout()) + return EC; + } + + if (!InjectedSources.empty()) { + for (const auto &IS : InjectedSources) { + JamCRC CRC(0); + CRC.update(arrayRefFromStringRef(IS.Content->getBuffer())); + + SrcHeaderBlockEntry Entry; + ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry)); + Entry.Size = sizeof(SrcHeaderBlockEntry); + Entry.FileSize = IS.Content->getBufferSize(); + Entry.FileNI = IS.NameIndex; + Entry.VFileNI = IS.VNameIndex; + Entry.ObjNI = 1; + Entry.IsVirtual = 0; + Entry.Version = + static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); + Entry.CRC = CRC.getCRC(); + StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex); + InjectedSourceTable.set_as(VName, std::move(Entry), + InjectedSourceHashTraits); + } + + uint32_t SrcHeaderBlockSize = + sizeof(SrcHeaderBlockHeader) + + InjectedSourceTable.calculateSerializedLength(); + SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize); + if (!SN) + return SN.takeError(); + for (const auto &IS : InjectedSources) { + SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize()); + if (!SN) + return SN.takeError(); + } + } + + // Do this last, since it relies on the named stream map being complete, and + // that can be updated by previous steps in the finalization. + if (Info) { + if (auto EC = Info->finalizeMsfLayout()) + return EC; + } + + return Error::success(); +} + +Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { + uint32_t SN = 0; + if (!NamedStreams.get(Name, SN)) + return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); + return SN; +} + +void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout) { + assert(!InjectedSourceTable.empty()); + + uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock")); + auto Stream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, SN, Allocator); + BinaryStreamWriter Writer(*Stream); + + SrcHeaderBlockHeader Header; + ::memset(&Header, 0, sizeof(Header)); + Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne); + Header.Size = Writer.bytesRemaining(); + + cantFail(Writer.writeObject(Header)); + cantFail(InjectedSourceTable.commit(Writer)); + + assert(Writer.bytesRemaining() == 0); +} + +void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer, + const msf::MSFLayout &Layout) { + if (InjectedSourceTable.empty()) + return; + + commitSrcHeaderBlock(MsfBuffer, Layout); + + for (const auto &IS : InjectedSources) { + uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName)); + + auto SourceStream = WritableMappedBlockStream::createIndexedStream( + Layout, MsfBuffer, SN, Allocator); + BinaryStreamWriter SourceWriter(*SourceStream); + assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize()); + cantFail(SourceWriter.writeBytes( + arrayRefFromStringRef(IS.Content->getBuffer()))); + } +} + +Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) { + assert(!Filename.empty()); + if (auto EC = finalizeMsfLayout()) + return EC; + + MSFLayout Layout; + Expected<FileBufferByteStream> ExpectedMsfBuffer = + Msf->commit(Filename, Layout); + if (!ExpectedMsfBuffer) + return ExpectedMsfBuffer.takeError(); + FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer); + + auto ExpectedSN = getNamedStreamIndex("/names"); + if (!ExpectedSN) + return ExpectedSN.takeError(); + + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, *ExpectedSN, Allocator); + BinaryStreamWriter NSWriter(*NS); + if (auto EC = Strings.commit(NSWriter)) + return EC; + + for (const auto &NSE : NamedStreamData) { + if (NSE.second.empty()) + continue; + + auto NS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, NSE.first, Allocator); + BinaryStreamWriter NSW(*NS); + if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) + return EC; + } + + if (Info) { + if (auto EC = Info->commit(Layout, Buffer)) + return EC; + } + + if (Dbi) { + if (auto EC = Dbi->commit(Layout, Buffer)) + return EC; + } + + if (Tpi) { + if (auto EC = Tpi->commit(Layout, Buffer)) + return EC; + } + + if (Ipi) { + if (auto EC = Ipi->commit(Layout, Buffer)) + return EC; + } + + if (Gsi) { + if (auto EC = Gsi->commit(Layout, Buffer)) + return EC; + } + + auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; + assert(!InfoStreamBlocks.empty()); + uint64_t InfoStreamFileOffset = + blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); + InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( + Buffer.getBufferStart() + InfoStreamFileOffset); + + commitInjectedSources(Buffer, Layout); + + // Set the build id at the very end, after every other byte of the PDB + // has been written. + if (Info->hashPDBContentsToGUID()) { + // Compute a hash of all sections of the output file. + uint64_t Digest = + xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()}); + + H->Age = 1; + + memcpy(H->Guid.Guid, &Digest, 8); + // xxhash only gives us 8 bytes, so put some fixed data in the other half. + memcpy(H->Guid.Guid + 8, "LLD PDB.", 8); + + // Put the hash in the Signature field too. + H->Signature = static_cast<uint32_t>(Digest); + + // Return GUID to caller. + memcpy(Guid, H->Guid.Guid, 16); + } else { + H->Age = Info->getAge(); + H->Guid = Info->getGuid(); + Optional<uint32_t> Sig = Info->getSignature(); + H->Signature = Sig.hasValue() ? *Sig : time(nullptr); + } + + return Buffer.commit(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTable.cpp index 2be1656e06..7c2f507229 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTable.cpp @@ -1,140 +1,140 @@ -//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::support; -using namespace llvm::pdb; - -uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; } -uint32_t PDBStringTable::getNameCount() const { return NameCount; } -uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } -uint32_t PDBStringTable::getSignature() const { return Header->Signature; } - -Error PDBStringTable::readHeader(BinaryStreamReader &Reader) { - if (auto EC = Reader.readObject(Header)) - return EC; - - if (Header->Signature != PDBStringTableSignature) - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid hash table signature"); - if (Header->HashVersion != 1 && Header->HashVersion != 2) - return make_error<RawError>(raw_error_code::corrupt_file, - "Unsupported hash version"); - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { - BinaryStreamRef Stream; - if (auto EC = Reader.readStreamRef(Stream)) - return EC; - - if (auto EC = Strings.initialize(Stream)) { - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Invalid hash table byte length")); - } - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} - -const codeview::DebugStringTableSubsectionRef & -PDBStringTable::getStringTable() const { - return Strings; -} - -Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { - const support::ulittle32_t *HashCount; - if (auto EC = Reader.readObject(HashCount)) - return EC; - - if (auto EC = Reader.readArray(IDs, *HashCount)) { - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read bucket array")); - } - - return Error::success(); -} - -Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { - if (auto EC = Reader.readInteger(NameCount)) - return EC; - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTable::reload(BinaryStreamReader &Reader) { - - BinaryStreamReader SectionReader; - - std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); - if (auto EC = readHeader(SectionReader)) - return EC; - - std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); - if (auto EC = readStrings(SectionReader)) - return EC; - - // We don't know how long the hash table is until we parse it, so let the - // function responsible for doing that figure it out. - if (auto EC = readHashTable(Reader)) - return EC; - - std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); - if (auto EC = readEpilogue(SectionReader)) - return EC; - - assert(Reader.bytesRemaining() == 0); - return Error::success(); -} - -Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { - return Strings.getString(ID); -} - -Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { - uint32_t Hash = - (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); - size_t Count = IDs.size(); - uint32_t Start = Hash % Count; - for (size_t I = 0; I < Count; ++I) { - // The hash is just a starting point for the search, but if it - // doesn't work we should find the string no matter what, because - // we iterate the entire array. - uint32_t Index = (Start + I) % Count; - - // If we find 0, it means the item isn't in the hash table. - uint32_t ID = IDs[Index]; - if (ID == 0) - return make_error<RawError>(raw_error_code::no_entry); - auto ExpectedStr = getStringForID(ID); - if (!ExpectedStr) - return ExpectedStr.takeError(); - - if (*ExpectedStr == Str) - return ID; - } - return make_error<RawError>(raw_error_code::no_entry); -} - -FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { - return IDs; -} +//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; } +uint32_t PDBStringTable::getNameCount() const { return NameCount; } +uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } +uint32_t PDBStringTable::getSignature() const { return Header->Signature; } + +Error PDBStringTable::readHeader(BinaryStreamReader &Reader) { + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Signature != PDBStringTableSignature) + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table signature"); + if (Header->HashVersion != 1 && Header->HashVersion != 2) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported hash version"); + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { + BinaryStreamRef Stream; + if (auto EC = Reader.readStreamRef(Stream)) + return EC; + + if (auto EC = Strings.initialize(Stream)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Invalid hash table byte length")); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +const codeview::DebugStringTableSubsectionRef & +PDBStringTable::getStringTable() const { + return Strings; +} + +Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { + const support::ulittle32_t *HashCount; + if (auto EC = Reader.readObject(HashCount)) + return EC; + + if (auto EC = Reader.readArray(IDs, *HashCount)) { + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read bucket array")); + } + + return Error::success(); +} + +Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { + if (auto EC = Reader.readInteger(NameCount)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTable::reload(BinaryStreamReader &Reader) { + + BinaryStreamReader SectionReader; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); + if (auto EC = readHeader(SectionReader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); + if (auto EC = readStrings(SectionReader)) + return EC; + + // We don't know how long the hash table is until we parse it, so let the + // function responsible for doing that figure it out. + if (auto EC = readHashTable(Reader)) + return EC; + + std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); + if (auto EC = readEpilogue(SectionReader)) + return EC; + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { + return Strings.getString(ID); +} + +Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { + uint32_t Hash = + (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); + size_t Count = IDs.size(); + uint32_t Start = Hash % Count; + for (size_t I = 0; I < Count; ++I) { + // The hash is just a starting point for the search, but if it + // doesn't work we should find the string no matter what, because + // we iterate the entire array. + uint32_t Index = (Start + I) % Count; + + // If we find 0, it means the item isn't in the hash table. + uint32_t ID = IDs[Index]; + if (ID == 0) + return make_error<RawError>(raw_error_code::no_entry); + auto ExpectedStr = getStringForID(ID); + if (!ExpectedStr) + return ExpectedStr.takeError(); + + if (*ExpectedStr == Str) + return ID; + } + return make_error<RawError>(raw_error_code::no_entry); +} + +FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { + return IDs; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp index f7f36901e4..a31025757d 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp @@ -1,229 +1,229 @@ -//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" - -#include <map> - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::support; -using namespace llvm::support::endian; -using namespace llvm::pdb; - -StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table) - : Table(&Table) {} - -uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const { - // The reference implementation doesn't include code for /src/headerblock - // handling, but it can only read natvis entries lld's PDB files if - // this hash function truncates the hash to 16 bit. - // PDB/include/misc.h in the reference implementation has a hashSz() function - // that returns an unsigned short, that seems what's being used for - // /src/headerblock. - return static_cast<uint16_t>(Table->getIdForString(S)); -} - -StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const { - return Table->getStringForId(Offset); -} - -uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) { - return Table->insert(S); -} - -uint32_t PDBStringTableBuilder::insert(StringRef S) { - return Strings.insert(S); -} - -uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const { - return Strings.getIdForString(S); -} - -StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const { - return Strings.getStringForId(Id); -} - -static uint32_t computeBucketCount(uint32_t NumStrings) { - // This is a precomputed list of Buckets given the specified number of - // strings. Matching the reference algorithm exactly is not strictly - // necessary for correctness, but it helps when comparing LLD's PDBs with - // Microsoft's PDBs so as to eliminate superfluous differences. - // The reference implementation does (in nmt.h, NMT::grow()): - // unsigned StringCount = 0; - // unsigned BucketCount = 1; - // fn insert() { - // ++StringCount; - // if (BucketCount * 3 / 4 < StringCount) - // BucketCount = BucketCount * 3 / 2 + 1; - // } - // This list contains all StringCount, BucketCount pairs where BucketCount was - // just incremented. It ends before the first BucketCount entry where - // BucketCount * 3 would overflow a 32-bit unsigned int. - static std::map<uint32_t, uint32_t> StringsToBuckets = { - {0, 1}, - {1, 2}, - {2, 4}, - {4, 7}, - {6, 11}, - {9, 17}, - {13, 26}, - {20, 40}, - {31, 61}, - {46, 92}, - {70, 139}, - {105, 209}, - {157, 314}, - {236, 472}, - {355, 709}, - {532, 1064}, - {799, 1597}, - {1198, 2396}, - {1798, 3595}, - {2697, 5393}, - {4045, 8090}, - {6068, 12136}, - {9103, 18205}, - {13654, 27308}, - {20482, 40963}, - {30723, 61445}, - {46084, 92168}, - {69127, 138253}, - {103690, 207380}, - {155536, 311071}, - {233304, 466607}, - {349956, 699911}, - {524934, 1049867}, - {787401, 1574801}, - {1181101, 2362202}, - {1771652, 3543304}, - {2657479, 5314957}, - {3986218, 7972436}, - {5979328, 11958655}, - {8968992, 17937983}, - {13453488, 26906975}, - {20180232, 40360463}, - {30270348, 60540695}, - {45405522, 90811043}, - {68108283, 136216565}, - {102162424, 204324848}, - {153243637, 306487273}, - {229865455, 459730910}, - {344798183, 689596366}, - {517197275, 1034394550}, - {775795913, 1551591826}, - {1163693870, 2327387740}}; - auto Entry = StringsToBuckets.lower_bound(NumStrings); - assert(Entry != StringsToBuckets.end()); - return Entry->second; -} - -uint32_t PDBStringTableBuilder::calculateHashTableSize() const { - uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field. - Size += sizeof(uint32_t) * computeBucketCount(Strings.size()); - - return Size; -} - -uint32_t PDBStringTableBuilder::calculateSerializedSize() const { - uint32_t Size = 0; - Size += sizeof(PDBStringTableHeader); - Size += Strings.calculateSerializedSize(); - Size += calculateHashTableSize(); - Size += sizeof(uint32_t); // The /names stream ends with the string count. - return Size; -} - -void PDBStringTableBuilder::setStrings( - const codeview::DebugStringTableSubsection &Strings) { - this->Strings = Strings; -} - -Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { - // Write a header - PDBStringTableHeader H; - H.Signature = PDBStringTableSignature; - H.HashVersion = 1; - H.ByteSize = Strings.calculateSerializedSize(); - if (auto EC = Writer.writeObject(H)) - return EC; - assert(Writer.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const { - if (auto EC = Strings.commit(Writer)) - return EC; - - assert(Writer.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { - // Write a hash table. - uint32_t BucketCount = computeBucketCount(Strings.size()); - if (auto EC = Writer.writeInteger(BucketCount)) - return EC; - std::vector<ulittle32_t> Buckets(BucketCount); - - for (auto &Pair : Strings) { - StringRef S = Pair.getKey(); - uint32_t Offset = Pair.getValue(); - uint32_t Hash = hashStringV1(S); - - for (uint32_t I = 0; I != BucketCount; ++I) { - uint32_t Slot = (Hash + I) % BucketCount; - if (Buckets[Slot] != 0) - continue; - Buckets[Slot] = Offset; - break; - } - } - - if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) - return EC; - - assert(Writer.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const { - if (auto EC = Writer.writeInteger<uint32_t>(Strings.size())) - return EC; - assert(Writer.bytesRemaining() == 0); - return Error::success(); -} - -Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const { - BinaryStreamWriter SectionWriter; - - std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader)); - if (auto EC = writeHeader(SectionWriter)) - return EC; - - std::tie(SectionWriter, Writer) = - Writer.split(Strings.calculateSerializedSize()); - if (auto EC = writeStrings(SectionWriter)) - return EC; - - std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize()); - if (auto EC = writeHashTable(SectionWriter)) - return EC; - - std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t)); - if (auto EC = writeEpilogue(SectionWriter)) - return EC; - - return Error::success(); -} +//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" + +#include <map> + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::support::endian; +using namespace llvm::pdb; + +StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table) + : Table(&Table) {} + +uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const { + // The reference implementation doesn't include code for /src/headerblock + // handling, but it can only read natvis entries lld's PDB files if + // this hash function truncates the hash to 16 bit. + // PDB/include/misc.h in the reference implementation has a hashSz() function + // that returns an unsigned short, that seems what's being used for + // /src/headerblock. + return static_cast<uint16_t>(Table->getIdForString(S)); +} + +StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const { + return Table->getStringForId(Offset); +} + +uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) { + return Table->insert(S); +} + +uint32_t PDBStringTableBuilder::insert(StringRef S) { + return Strings.insert(S); +} + +uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const { + return Strings.getIdForString(S); +} + +StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const { + return Strings.getStringForId(Id); +} + +static uint32_t computeBucketCount(uint32_t NumStrings) { + // This is a precomputed list of Buckets given the specified number of + // strings. Matching the reference algorithm exactly is not strictly + // necessary for correctness, but it helps when comparing LLD's PDBs with + // Microsoft's PDBs so as to eliminate superfluous differences. + // The reference implementation does (in nmt.h, NMT::grow()): + // unsigned StringCount = 0; + // unsigned BucketCount = 1; + // fn insert() { + // ++StringCount; + // if (BucketCount * 3 / 4 < StringCount) + // BucketCount = BucketCount * 3 / 2 + 1; + // } + // This list contains all StringCount, BucketCount pairs where BucketCount was + // just incremented. It ends before the first BucketCount entry where + // BucketCount * 3 would overflow a 32-bit unsigned int. + static std::map<uint32_t, uint32_t> StringsToBuckets = { + {0, 1}, + {1, 2}, + {2, 4}, + {4, 7}, + {6, 11}, + {9, 17}, + {13, 26}, + {20, 40}, + {31, 61}, + {46, 92}, + {70, 139}, + {105, 209}, + {157, 314}, + {236, 472}, + {355, 709}, + {532, 1064}, + {799, 1597}, + {1198, 2396}, + {1798, 3595}, + {2697, 5393}, + {4045, 8090}, + {6068, 12136}, + {9103, 18205}, + {13654, 27308}, + {20482, 40963}, + {30723, 61445}, + {46084, 92168}, + {69127, 138253}, + {103690, 207380}, + {155536, 311071}, + {233304, 466607}, + {349956, 699911}, + {524934, 1049867}, + {787401, 1574801}, + {1181101, 2362202}, + {1771652, 3543304}, + {2657479, 5314957}, + {3986218, 7972436}, + {5979328, 11958655}, + {8968992, 17937983}, + {13453488, 26906975}, + {20180232, 40360463}, + {30270348, 60540695}, + {45405522, 90811043}, + {68108283, 136216565}, + {102162424, 204324848}, + {153243637, 306487273}, + {229865455, 459730910}, + {344798183, 689596366}, + {517197275, 1034394550}, + {775795913, 1551591826}, + {1163693870, 2327387740}}; + auto Entry = StringsToBuckets.lower_bound(NumStrings); + assert(Entry != StringsToBuckets.end()); + return Entry->second; +} + +uint32_t PDBStringTableBuilder::calculateHashTableSize() const { + uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field. + Size += sizeof(uint32_t) * computeBucketCount(Strings.size()); + + return Size; +} + +uint32_t PDBStringTableBuilder::calculateSerializedSize() const { + uint32_t Size = 0; + Size += sizeof(PDBStringTableHeader); + Size += Strings.calculateSerializedSize(); + Size += calculateHashTableSize(); + Size += sizeof(uint32_t); // The /names stream ends with the string count. + return Size; +} + +void PDBStringTableBuilder::setStrings( + const codeview::DebugStringTableSubsection &Strings) { + this->Strings = Strings; +} + +Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const { + // Write a header + PDBStringTableHeader H; + H.Signature = PDBStringTableSignature; + H.HashVersion = 1; + H.ByteSize = Strings.calculateSerializedSize(); + if (auto EC = Writer.writeObject(H)) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const { + if (auto EC = Strings.commit(Writer)) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const { + // Write a hash table. + uint32_t BucketCount = computeBucketCount(Strings.size()); + if (auto EC = Writer.writeInteger(BucketCount)) + return EC; + std::vector<ulittle32_t> Buckets(BucketCount); + + for (auto &Pair : Strings) { + StringRef S = Pair.getKey(); + uint32_t Offset = Pair.getValue(); + uint32_t Hash = hashStringV1(S); + + for (uint32_t I = 0; I != BucketCount; ++I) { + uint32_t Slot = (Hash + I) % BucketCount; + if (Buckets[Slot] != 0) + continue; + Buckets[Slot] = Offset; + break; + } + } + + if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets))) + return EC; + + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const { + if (auto EC = Writer.writeInteger<uint32_t>(Strings.size())) + return EC; + assert(Writer.bytesRemaining() == 0); + return Error::success(); +} + +Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const { + BinaryStreamWriter SectionWriter; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader)); + if (auto EC = writeHeader(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = + Writer.split(Strings.calculateSerializedSize()); + if (auto EC = writeStrings(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize()); + if (auto EC = writeHashTable(SectionWriter)) + return EC; + + std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t)); + if (auto EC = writeEpilogue(SectionWriter)) + return EC; + + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PublicsStream.cpp index a33bf03bf8..2b40a335ac 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PublicsStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -1,101 +1,101 @@ -//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/BinaryStreamReader.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::support; -using namespace llvm::pdb; - -PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} - -PublicsStream::~PublicsStream() = default; - -uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } -uint16_t PublicsStream::getThunkTableSection() const { - return Header->ISectThunkTable; -} -uint32_t PublicsStream::getThunkTableOffset() const { - return Header->OffThunkTable; -} - -// Publics stream contains fixed-size headers and a serialized hash table. -// This implementation is not complete yet. It reads till the end of the -// stream so that we verify the stream is at least not corrupted. However, -// we skip over the hash table which we believe contains information about -// public symbols. -Error PublicsStream::reload() { - BinaryStreamReader Reader(*Stream); - - // Check stream size. - if (Reader.bytesRemaining() < - sizeof(PublicsStreamHeader) + sizeof(GSIHashHeader)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Publics Stream does not contain a header."); - - // Read PSGSIHDR struct. - if (Reader.readObject(Header)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Publics Stream does not contain a header."); - - // Read the hash table. - if (auto E = PublicsTable.read(Reader)) - return E; - - // Something called "address map" follows. - uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); - if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read an address map.")); - - // Something called "thunk map" follows. - if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read a thunk map.")); - - // Something called "section map" follows. - if (Reader.bytesRemaining() > 0) { - if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections)) - return joinErrors(std::move(EC), - make_error<RawError>(raw_error_code::corrupt_file, - "Could not read a section map.")); - } - - if (Reader.bytesRemaining() > 0) - return make_error<RawError>(raw_error_code::corrupt_file, - "Corrupted publics stream."); - return Error::success(); -} +//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.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::support; +using namespace llvm::pdb; + +PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +PublicsStream::~PublicsStream() = default; + +uint32_t PublicsStream::getSymHash() const { return Header->SymHash; } +uint16_t PublicsStream::getThunkTableSection() const { + return Header->ISectThunkTable; +} +uint32_t PublicsStream::getThunkTableOffset() const { + return Header->OffThunkTable; +} + +// Publics stream contains fixed-size headers and a serialized hash table. +// This implementation is not complete yet. It reads till the end of the +// stream so that we verify the stream is at least not corrupted. However, +// we skip over the hash table which we believe contains information about +// public symbols. +Error PublicsStream::reload() { + BinaryStreamReader Reader(*Stream); + + // Check stream size. + if (Reader.bytesRemaining() < + sizeof(PublicsStreamHeader) + sizeof(GSIHashHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Publics Stream does not contain a header."); + + // Read PSGSIHDR struct. + if (Reader.readObject(Header)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Publics Stream does not contain a header."); + + // Read the hash table. + if (auto E = PublicsTable.read(Reader)) + return E; + + // Something called "address map" follows. + uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t); + if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read an address map.")); + + // Something called "thunk map" follows. + if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a thunk map.")); + + // Something called "section map" follows. + if (Reader.bytesRemaining() > 0) { + if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections)) + return joinErrors(std::move(EC), + make_error<RawError>(raw_error_code::corrupt_file, + "Could not read a section map.")); + } + + if (Reader.bytesRemaining() > 0) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupted publics stream."); + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/RawError.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/RawError.cpp index ed6cf08396..dd6913cbbe 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/RawError.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/RawError.cpp @@ -1,53 +1,53 @@ -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" - -using namespace llvm; -using namespace llvm::pdb; - -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 RawErrorCategory : public std::error_category { -public: - const char *name() const noexcept override { return "llvm.pdb.raw"; } - std::string message(int Condition) const override { - switch (static_cast<raw_error_code>(Condition)) { - case raw_error_code::unspecified: - 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: - return "The buffer is not large enough to read the requested number of " - "bytes."; - case raw_error_code::no_stream: - return "The specified stream could not be loaded."; - case raw_error_code::index_out_of_bounds: - 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::stream_too_long: - return "The stream was longer than expected."; - case raw_error_code::invalid_tpi_hash: - return "The Type record has an invalid hash value."; - } - llvm_unreachable("Unrecognized raw_error_code"); - } -}; -} // namespace - -static llvm::ManagedStatic<RawErrorCategory> RawCategory; -const std::error_category &llvm::pdb::RawErrCategory() { return *RawCategory; } - -char RawError::ID; +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +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 RawErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "llvm.pdb.raw"; } + std::string message(int Condition) const override { + switch (static_cast<raw_error_code>(Condition)) { + case raw_error_code::unspecified: + 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: + return "The buffer is not large enough to read the requested number of " + "bytes."; + case raw_error_code::no_stream: + return "The specified stream could not be loaded."; + case raw_error_code::index_out_of_bounds: + 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::stream_too_long: + return "The stream was longer than expected."; + case raw_error_code::invalid_tpi_hash: + return "The Type record has an invalid hash value."; + } + llvm_unreachable("Unrecognized raw_error_code"); + } +}; +} // namespace + +static llvm::ManagedStatic<RawErrorCategory> RawCategory; +const std::error_category &llvm::pdb::RawErrCategory() { return *RawCategory; } + +char RawError::ID; diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolCache.cpp index fd9a0deb54..eca69a4a83 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolCache.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolCache.cpp @@ -1,297 +1,297 @@ -#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" - +#include "llvm/DebugInfo/PDB/Native/SymbolCache.h" + #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h" -#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" -#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" +#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" -#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary -// to instantiate a NativeBuiltinSymbol for that type. -static const struct BuiltinTypeEntry { - codeview::SimpleTypeKind Kind; - PDB_BuiltinType Type; - uint32_t Size; -} BuiltinTypes[] = { - {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0}, - {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0}, - {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4}, - {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, - {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, - {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, - {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, - {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, - {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, - {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, - {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, - {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, - {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2}, - {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2}, - {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4}, - {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, - {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, - {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4}, - {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8}, - {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10}, - {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1}, - // This table can be grown as necessary, but these are the only types we've - // needed so far. -}; - -SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) +#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h" +#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary +// to instantiate a NativeBuiltinSymbol for that type. +static const struct BuiltinTypeEntry { + codeview::SimpleTypeKind Kind; + PDB_BuiltinType Type; + uint32_t Size; +} BuiltinTypes[] = { + {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0}, + {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0}, + {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4}, + {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2}, + {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2}, + {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4}, + {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4}, + {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8}, + {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8}, + {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2}, + {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2}, + {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4}, + {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1}, + {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1}, + {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4}, + {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8}, + {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10}, + {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1}, + // This table can be grown as necessary, but these are the only types we've + // needed so far. +}; + +SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi) : Session(Session), Dbi(Dbi) { - // Id 0 is reserved for the invalid symbol. - Cache.push_back(nullptr); - SourceFiles.push_back(nullptr); - - if (Dbi) - Compilands.resize(Dbi->modules().getModuleCount()); -} - -std::unique_ptr<IPDBEnumSymbols> -SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { - return createTypeEnumerator(std::vector<TypeLeafKind>{Kind}); -} - -std::unique_ptr<IPDBEnumSymbols> -SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { - auto Tpi = Session.getPDBFile().getPDBTpiStream(); - if (!Tpi) { - consumeError(Tpi.takeError()); - return nullptr; - } - auto &Types = Tpi->typeCollection(); - return std::unique_ptr<IPDBEnumSymbols>( - new NativeEnumTypes(Session, Types, std::move(Kinds))); -} - -std::unique_ptr<IPDBEnumSymbols> -SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { - return std::unique_ptr<IPDBEnumSymbols>( - new NativeEnumGlobals(Session, {Kind})); -} - -SymIndexId SymbolCache::createSimpleType(TypeIndex Index, + // Id 0 is reserved for the invalid symbol. + Cache.push_back(nullptr); + SourceFiles.push_back(nullptr); + + if (Dbi) + Compilands.resize(Dbi->modules().getModuleCount()); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(TypeLeafKind Kind) { + return createTypeEnumerator(std::vector<TypeLeafKind>{Kind}); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) { + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return nullptr; + } + auto &Types = Tpi->typeCollection(); + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumTypes(Session, Types, std::move(Kinds))); +} + +std::unique_ptr<IPDBEnumSymbols> +SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) { + return std::unique_ptr<IPDBEnumSymbols>( + new NativeEnumGlobals(Session, {Kind})); +} + +SymIndexId SymbolCache::createSimpleType(TypeIndex Index, ModifierOptions Mods) const { - if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) - return createSymbol<NativeTypePointer>(Index); - - const auto Kind = Index.getSimpleKind(); + if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct) + return createSymbol<NativeTypePointer>(Index); + + const auto Kind = Index.getSimpleKind(); const auto It = llvm::find_if(BuiltinTypes, [Kind](const BuiltinTypeEntry &Builtin) { return Builtin.Kind == Kind; }); - if (It == std::end(BuiltinTypes)) - return 0; - return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size); -} - -SymIndexId -SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, + if (It == std::end(BuiltinTypes)) + return 0; + return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size); +} + +SymIndexId +SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI, codeview::CVType CVT) const { - ModifierRecord Record; - if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { - consumeError(std::move(EC)); - return 0; - } - - if (Record.ModifiedType.isSimple()) - return createSimpleType(Record.ModifiedType, Record.Modifiers); - - // Make sure we create and cache a record for the unmodified type. - SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType); - NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; - - switch (UnmodifiedNRS.getSymTag()) { - case PDB_SymType::Enum: - return createSymbol<NativeTypeEnum>( - static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record)); - case PDB_SymType::UDT: - return createSymbol<NativeTypeUDT>( - static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record)); - default: - // No other types can be modified. (LF_POINTER, for example, records - // its modifiers a different way. - assert(false && "Invalid LF_MODIFIER record"); - break; - } - return 0; -} - + ModifierRecord Record; + if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) { + consumeError(std::move(EC)); + return 0; + } + + if (Record.ModifiedType.isSimple()) + return createSimpleType(Record.ModifiedType, Record.Modifiers); + + // Make sure we create and cache a record for the unmodified type. + SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType); + NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId]; + + switch (UnmodifiedNRS.getSymTag()) { + case PDB_SymType::Enum: + return createSymbol<NativeTypeEnum>( + static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record)); + case PDB_SymType::UDT: + return createSymbol<NativeTypeUDT>( + static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record)); + default: + // No other types can be modified. (LF_POINTER, for example, records + // its modifiers a different way. + assert(false && "Invalid LF_MODIFIER record"); + break; + } + return 0; +} + SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const { - // First see if it's already in our cache. - const auto Entry = TypeIndexToSymbolId.find(Index); - if (Entry != TypeIndexToSymbolId.end()) - return Entry->second; - - // Symbols for built-in types are created on the fly. - if (Index.isSimple()) { - SymIndexId Result = createSimpleType(Index, ModifierOptions::None); - assert(TypeIndexToSymbolId.count(Index) == 0); - TypeIndexToSymbolId[Index] = Result; - return Result; - } - - // We need to instantiate and cache the desired type symbol. - auto Tpi = Session.getPDBFile().getPDBTpiStream(); - if (!Tpi) { - consumeError(Tpi.takeError()); - return 0; - } - codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); - codeview::CVType CVT = Types.getType(Index); - - if (isUdtForwardRef(CVT)) { - Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index); - - if (!EFD) - consumeError(EFD.takeError()); - else if (*EFD != Index) { - assert(!isUdtForwardRef(Types.getType(*EFD))); - SymIndexId Result = findSymbolByTypeIndex(*EFD); - // Record a mapping from ForwardRef -> SymIndex of complete type so that - // we'll take the fast path next time. - assert(TypeIndexToSymbolId.count(Index) == 0); - TypeIndexToSymbolId[Index] = Result; - return Result; - } - } - - // At this point if we still have a forward ref udt it means the full decl was - // not in the PDB. We just have to deal with it and use the forward ref. - SymIndexId Id = 0; - switch (CVT.kind()) { - case codeview::LF_ENUM: - Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); - break; - case codeview::LF_ARRAY: - Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index, - std::move(CVT)); - break; - case codeview::LF_CLASS: - case codeview::LF_STRUCTURE: - case codeview::LF_INTERFACE: - Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT)); - break; - case codeview::LF_UNION: - Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT)); - break; - case codeview::LF_POINTER: - Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, - std::move(CVT)); - break; - case codeview::LF_MODIFIER: - Id = createSymbolForModifiedType(Index, std::move(CVT)); - break; - case codeview::LF_PROCEDURE: - Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( - Index, std::move(CVT)); - break; - case codeview::LF_MFUNCTION: - Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( - Index, std::move(CVT)); - break; - case codeview::LF_VTSHAPE: - Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( - Index, std::move(CVT)); - break; - default: - Id = createSymbolPlaceholder(); - break; - } - if (Id != 0) { - assert(TypeIndexToSymbolId.count(Index) == 0); - TypeIndexToSymbolId[Index] = Id; - } - return Id; -} - -std::unique_ptr<PDBSymbol> -SymbolCache::getSymbolById(SymIndexId SymbolId) const { - assert(SymbolId < Cache.size()); - - // Id 0 is reserved. - if (SymbolId == 0 || SymbolId >= Cache.size()) - return nullptr; - - // Make sure to handle the case where we've inserted a placeholder symbol + // First see if it's already in our cache. + const auto Entry = TypeIndexToSymbolId.find(Index); + if (Entry != TypeIndexToSymbolId.end()) + return Entry->second; + + // Symbols for built-in types are created on the fly. + if (Index.isSimple()) { + SymIndexId Result = createSimpleType(Index, ModifierOptions::None); + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + + // We need to instantiate and cache the desired type symbol. + auto Tpi = Session.getPDBFile().getPDBTpiStream(); + if (!Tpi) { + consumeError(Tpi.takeError()); + return 0; + } + codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection(); + codeview::CVType CVT = Types.getType(Index); + + if (isUdtForwardRef(CVT)) { + Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index); + + if (!EFD) + consumeError(EFD.takeError()); + else if (*EFD != Index) { + assert(!isUdtForwardRef(Types.getType(*EFD))); + SymIndexId Result = findSymbolByTypeIndex(*EFD); + // Record a mapping from ForwardRef -> SymIndex of complete type so that + // we'll take the fast path next time. + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Result; + return Result; + } + } + + // At this point if we still have a forward ref udt it means the full decl was + // not in the PDB. We just have to deal with it and use the forward ref. + SymIndexId Id = 0; + switch (CVT.kind()) { + case codeview::LF_ENUM: + Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT)); + break; + case codeview::LF_ARRAY: + Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_CLASS: + case codeview::LF_STRUCTURE: + case codeview::LF_INTERFACE: + Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT)); + break; + case codeview::LF_UNION: + Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT)); + break; + case codeview::LF_POINTER: + Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index, + std::move(CVT)); + break; + case codeview::LF_MODIFIER: + Id = createSymbolForModifiedType(Index, std::move(CVT)); + break; + case codeview::LF_PROCEDURE: + Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_MFUNCTION: + Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>( + Index, std::move(CVT)); + break; + case codeview::LF_VTSHAPE: + Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>( + Index, std::move(CVT)); + break; + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(TypeIndexToSymbolId.count(Index) == 0); + TypeIndexToSymbolId[Index] = Id; + } + return Id; +} + +std::unique_ptr<PDBSymbol> +SymbolCache::getSymbolById(SymIndexId SymbolId) const { + assert(SymbolId < Cache.size()); + + // Id 0 is reserved. + if (SymbolId == 0 || SymbolId >= Cache.size()) + return nullptr; + + // Make sure to handle the case where we've inserted a placeholder symbol // for types we don't yet support. - NativeRawSymbol *NRS = Cache[SymbolId].get(); - if (!NRS) - return nullptr; - - return PDBSymbol::create(Session, *NRS); -} - -NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { - return *Cache[SymbolId]; -} - -uint32_t SymbolCache::getNumCompilands() const { - if (!Dbi) - return 0; - - return Dbi->modules().getModuleCount(); -} - -SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { - auto Iter = GlobalOffsetToSymbolId.find(Offset); - if (Iter != GlobalOffsetToSymbolId.end()) - return Iter->second; - - SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); - CVSymbol CVS = SS.readRecord(Offset); - SymIndexId Id = 0; - switch (CVS.kind()) { - case SymbolKind::S_UDT: { - UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); - Id = createSymbol<NativeTypeTypedef>(std::move(US)); - break; - } - default: - Id = createSymbolPlaceholder(); - break; - } - if (Id != 0) { - assert(GlobalOffsetToSymbolId.count(Offset) == 0); - GlobalOffsetToSymbolId[Offset] = Id; - } - - return Id; -} - + NativeRawSymbol *NRS = Cache[SymbolId].get(); + if (!NRS) + return nullptr; + + return PDBSymbol::create(Session, *NRS); +} + +NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const { + return *Cache[SymbolId]; +} + +uint32_t SymbolCache::getNumCompilands() const { + if (!Dbi) + return 0; + + return Dbi->modules().getModuleCount(); +} + +SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) { + auto Iter = GlobalOffsetToSymbolId.find(Offset); + if (Iter != GlobalOffsetToSymbolId.end()) + return Iter->second; + + SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream()); + CVSymbol CVS = SS.readRecord(Offset); + SymIndexId Id = 0; + switch (CVS.kind()) { + case SymbolKind::S_UDT: { + UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS)); + Id = createSymbol<NativeTypeTypedef>(std::move(US)); + break; + } + default: + Id = createSymbolPlaceholder(); + break; + } + if (Id != 0) { + assert(GlobalOffsetToSymbolId.count(Offset) == 0); + GlobalOffsetToSymbolId[Offset] = Id; + } + + return Id; +} + SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym, uint64_t ParentAddr, uint16_t Modi, @@ -299,66 +299,66 @@ SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym, auto Iter = SymTabOffsetToSymbolId.find({Modi, RecordOffset}); if (Iter != SymTabOffsetToSymbolId.end()) return Iter->second; - + SymIndexId Id = createSymbol<NativeInlineSiteSymbol>(Sym, ParentAddr); SymTabOffsetToSymbolId.insert({{Modi, RecordOffset}, Id}); return Id; -} - -std::unique_ptr<PDBSymbol> -SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, - PDB_SymType Type) { - switch (Type) { - case PDB_SymType::Function: - return findFunctionSymbolBySectOffset(Sect, Offset); - case PDB_SymType::PublicSymbol: - return findPublicSymbolBySectOffset(Sect, Offset); +} + +std::unique_ptr<PDBSymbol> +SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset, + PDB_SymType Type) { + switch (Type) { + case PDB_SymType::Function: + return findFunctionSymbolBySectOffset(Sect, Offset); + case PDB_SymType::PublicSymbol: + return findPublicSymbolBySectOffset(Sect, Offset); case PDB_SymType::Compiland: { uint16_t Modi; if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi)) return nullptr; return getOrCreateCompiland(Modi); } - case PDB_SymType::None: { + case PDB_SymType::None: { // FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but // only uses it to find the symbol length. - if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset)) - return Sym; - return nullptr; - } - default: - return nullptr; - } -} - -std::unique_ptr<PDBSymbol> -SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { + if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset)) + return Sym; + return nullptr; + } + default: + return nullptr; + } +} + +std::unique_ptr<PDBSymbol> +SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { auto Iter = AddressToSymbolId.find({Sect, Offset}); if (Iter != AddressToSymbolId.end()) - return getSymbolById(Iter->second); - - if (!Dbi) - return nullptr; - + return getSymbolById(Iter->second); + + if (!Dbi) + return nullptr; + uint16_t Modi; if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi)) - return nullptr; - + return nullptr; + Expected<ModuleDebugStreamRef> ExpectedModS = Session.getModuleDebugStream(Modi); - if (!ExpectedModS) { - consumeError(ExpectedModS.takeError()); - return nullptr; - } - CVSymbolArray Syms = ExpectedModS->getSymbolArray(); - - // Search for the symbol in this module. - for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) { - if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32) - continue; - auto PS = cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*I)); - if (Sect == PS.Segment && Offset >= PS.CodeOffset && - Offset < PS.CodeOffset + PS.CodeSize) { + if (!ExpectedModS) { + consumeError(ExpectedModS.takeError()); + return nullptr; + } + CVSymbolArray Syms = ExpectedModS->getSymbolArray(); + + // Search for the symbol in this module. + for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) { + if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32) + continue; + auto PS = cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*I)); + if (Sect == PS.Segment && Offset >= PS.CodeOffset && + Offset < PS.CodeOffset + PS.CodeSize) { // Check if the symbol is already cached. auto Found = AddressToSymbolId.find({PS.Segment, PS.CodeOffset}); if (Found != AddressToSymbolId.end()) @@ -367,121 +367,121 @@ SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { // Otherwise, create a new symbol. SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS, I.offset()); AddressToSymbolId.insert({{PS.Segment, PS.CodeOffset}, Id}); - return getSymbolById(Id); - } - - // Jump to the end of this ProcSym. - I = Syms.at(PS.End); - } - return nullptr; -} - -std::unique_ptr<PDBSymbol> -SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { - auto Iter = AddressToPublicSymId.find({Sect, Offset}); - if (Iter != AddressToPublicSymId.end()) - return getSymbolById(Iter->second); - - auto Publics = Session.getPDBFile().getPDBPublicsStream(); - if (!Publics) - return nullptr; - - auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream(); - if (!ExpectedSyms) - return nullptr; - BinaryStreamRef SymStream = - ExpectedSyms->getSymbolArray().getUnderlyingStream(); - - // Use binary search to find the first public symbol with an address greater - // than or equal to Sect, Offset. - auto AddrMap = Publics->getAddressMap(); - auto First = AddrMap.begin(); - auto It = AddrMap.begin(); - size_t Count = AddrMap.size(); - size_t Half; - while (Count > 0) { - It = First; - Half = Count / 2; - It += Half; - Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It); - if (!Sym) { - consumeError(Sym.takeError()); - return nullptr; - } - - auto PS = - cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get())); - if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) { - First = ++It; - Count -= Half + 1; - } else - Count = Half; - } - if (It == AddrMap.begin()) - return nullptr; - --It; - - Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It); - if (!Sym) { - consumeError(Sym.takeError()); - return nullptr; - } + return getSymbolById(Id); + } + + // Jump to the end of this ProcSym. + I = Syms.at(PS.End); + } + return nullptr; +} + +std::unique_ptr<PDBSymbol> +SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) { + auto Iter = AddressToPublicSymId.find({Sect, Offset}); + if (Iter != AddressToPublicSymId.end()) + return getSymbolById(Iter->second); + + auto Publics = Session.getPDBFile().getPDBPublicsStream(); + if (!Publics) + return nullptr; + + auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream(); + if (!ExpectedSyms) + return nullptr; + BinaryStreamRef SymStream = + ExpectedSyms->getSymbolArray().getUnderlyingStream(); + + // Use binary search to find the first public symbol with an address greater + // than or equal to Sect, Offset. + auto AddrMap = Publics->getAddressMap(); + auto First = AddrMap.begin(); + auto It = AddrMap.begin(); + size_t Count = AddrMap.size(); + size_t Half; + while (Count > 0) { + It = First; + Half = Count / 2; + It += Half; + Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It); + if (!Sym) { + consumeError(Sym.takeError()); + return nullptr; + } + + auto PS = + cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get())); + if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) { + First = ++It; + Count -= Half + 1; + } else + Count = Half; + } + if (It == AddrMap.begin()) + return nullptr; + --It; + + Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It); + if (!Sym) { + consumeError(Sym.takeError()); + return nullptr; + } // Check if the symbol is already cached. - auto PS = cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get())); + auto PS = cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get())); auto Found = AddressToPublicSymId.find({PS.Segment, PS.Offset}); if (Found != AddressToPublicSymId.end()) return getSymbolById(Found->second); // Otherwise, create a new symbol. - SymIndexId Id = createSymbol<NativePublicSymbol>(PS); + SymIndexId Id = createSymbol<NativePublicSymbol>(PS); AddressToPublicSymId.insert({{PS.Segment, PS.Offset}, Id}); - return getSymbolById(Id); -} - -std::vector<SymbolCache::LineTableEntry> -SymbolCache::findLineTable(uint16_t Modi) const { - // Check if this module has already been added. - auto LineTableIter = LineTable.find(Modi); - if (LineTableIter != LineTable.end()) - return LineTableIter->second; - - std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi]; - - // If there is an error or there are no lines, just return the - // empty vector. + return getSymbolById(Id); +} + +std::vector<SymbolCache::LineTableEntry> +SymbolCache::findLineTable(uint16_t Modi) const { + // Check if this module has already been added. + auto LineTableIter = LineTable.find(Modi); + if (LineTableIter != LineTable.end()) + return LineTableIter->second; + + std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi]; + + // If there is an error or there are no lines, just return the + // empty vector. Expected<ModuleDebugStreamRef> ExpectedModS = Session.getModuleDebugStream(Modi); - if (!ExpectedModS) { - consumeError(ExpectedModS.takeError()); - return ModuleLineTable; - } - - std::vector<std::vector<LineTableEntry>> EntryList; - for (const auto &SS : ExpectedModS->getSubsectionsArray()) { - if (SS.kind() != DebugSubsectionKind::Lines) - continue; - - DebugLinesSubsectionRef Lines; - BinaryStreamReader Reader(SS.getRecordData()); - if (auto EC = Lines.initialize(Reader)) { - consumeError(std::move(EC)); - continue; - } - - uint32_t RelocSegment = Lines.header()->RelocSegment; - uint32_t RelocOffset = Lines.header()->RelocOffset; - for (const LineColumnEntry &Group : Lines) { - if (Group.LineNumbers.empty()) - continue; - - std::vector<LineTableEntry> Entries; - - // If there are column numbers, then they should be in a parallel stream - // to the line numbers. - auto ColIt = Group.Columns.begin(); - auto ColsEnd = Group.Columns.end(); - + if (!ExpectedModS) { + consumeError(ExpectedModS.takeError()); + return ModuleLineTable; + } + + std::vector<std::vector<LineTableEntry>> EntryList; + for (const auto &SS : ExpectedModS->getSubsectionsArray()) { + if (SS.kind() != DebugSubsectionKind::Lines) + continue; + + DebugLinesSubsectionRef Lines; + BinaryStreamReader Reader(SS.getRecordData()); + if (auto EC = Lines.initialize(Reader)) { + consumeError(std::move(EC)); + continue; + } + + uint32_t RelocSegment = Lines.header()->RelocSegment; + uint32_t RelocOffset = Lines.header()->RelocOffset; + for (const LineColumnEntry &Group : Lines) { + if (Group.LineNumbers.empty()) + continue; + + std::vector<LineTableEntry> Entries; + + // If there are column numbers, then they should be in a parallel stream + // to the line numbers. + auto ColIt = Group.Columns.begin(); + auto ColsEnd = Group.Columns.end(); + // Add a line to mark the beginning of this section. uint64_t StartAddr = Session.getVAFromSectOffset(RelocSegment, RelocOffset); @@ -490,144 +490,144 @@ SymbolCache::findLineTable(uint16_t Modi) const { (Lines.hasColumnInfo()) ? Group.Columns.front().StartColumn : 0; Entries.push_back({StartAddr, FirstLine, ColNum, Group.NameIndex, false}); - for (const LineNumberEntry &LN : Group.LineNumbers) { - uint64_t VA = - Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset); - LineInfo Line(LN.Flags); + for (const LineNumberEntry &LN : Group.LineNumbers) { + uint64_t VA = + Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset); + LineInfo Line(LN.Flags); ColNum = 0; - - if (Lines.hasColumnInfo() && ColIt != ColsEnd) { - ColNum = ColIt->StartColumn; - ++ColIt; - } - Entries.push_back({VA, Line, ColNum, Group.NameIndex, false}); - } - - // Add a terminal entry line to mark the end of this subsection. + + if (Lines.hasColumnInfo() && ColIt != ColsEnd) { + ColNum = ColIt->StartColumn; + ++ColIt; + } + Entries.push_back({VA, Line, ColNum, Group.NameIndex, false}); + } + + // Add a terminal entry line to mark the end of this subsection. uint64_t EndAddr = StartAddr + Lines.header()->CodeSize; - LineInfo LastLine(Group.LineNumbers.back().Flags); + LineInfo LastLine(Group.LineNumbers.back().Flags); ColNum = (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0; Entries.push_back({EndAddr, LastLine, ColNum, Group.NameIndex, true}); - - EntryList.push_back(Entries); - } - } - - // Sort EntryList, and add flattened contents to the line table. + + EntryList.push_back(Entries); + } + } + + // Sort EntryList, and add flattened contents to the line table. llvm::sort(EntryList, [](const std::vector<LineTableEntry> &LHS, const std::vector<LineTableEntry> &RHS) { return LHS[0].Addr < RHS[0].Addr; }); - for (size_t I = 0; I < EntryList.size(); ++I) + for (size_t I = 0; I < EntryList.size(); ++I) llvm::append_range(ModuleLineTable, EntryList[I]); - - return ModuleLineTable; -} - -std::unique_ptr<IPDBEnumLineNumbers> -SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { + + return ModuleLineTable; +} + +std::unique_ptr<IPDBEnumLineNumbers> +SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const { uint16_t Modi; if (!Session.moduleIndexForVA(VA, Modi)) - return nullptr; - - std::vector<LineTableEntry> Lines = findLineTable(Modi); - if (Lines.empty()) - return nullptr; - - // Find the first line in the line table whose address is not greater than - // the one we are searching for. - auto LineIter = llvm::partition_point(Lines, [&](const LineTableEntry &E) { - return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry)); - }); - - // Try to back up if we've gone too far. - if (LineIter == Lines.end() || LineIter->Addr > VA) { - if (LineIter == Lines.begin() || std::prev(LineIter)->IsTerminalEntry) - return nullptr; - --LineIter; - } - + return nullptr; + + std::vector<LineTableEntry> Lines = findLineTable(Modi); + if (Lines.empty()) + return nullptr; + + // Find the first line in the line table whose address is not greater than + // the one we are searching for. + auto LineIter = llvm::partition_point(Lines, [&](const LineTableEntry &E) { + return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry)); + }); + + // Try to back up if we've gone too far. + if (LineIter == Lines.end() || LineIter->Addr > VA) { + if (LineIter == Lines.begin() || std::prev(LineIter)->IsTerminalEntry) + return nullptr; + --LineIter; + } + Expected<ModuleDebugStreamRef> ExpectedModS = Session.getModuleDebugStream(Modi); - if (!ExpectedModS) { - consumeError(ExpectedModS.takeError()); - return nullptr; - } - Expected<DebugChecksumsSubsectionRef> ExpectedChecksums = - ExpectedModS->findChecksumsSubsection(); - if (!ExpectedChecksums) { - consumeError(ExpectedChecksums.takeError()); - return nullptr; - } - - // Populate a vector of NativeLineNumbers that have addresses in the given - // address range. - std::vector<NativeLineNumber> LineNumbers; + if (!ExpectedModS) { + consumeError(ExpectedModS.takeError()); + return nullptr; + } + Expected<DebugChecksumsSubsectionRef> ExpectedChecksums = + ExpectedModS->findChecksumsSubsection(); + if (!ExpectedChecksums) { + consumeError(ExpectedChecksums.takeError()); + return nullptr; + } + + // Populate a vector of NativeLineNumbers that have addresses in the given + // address range. + std::vector<NativeLineNumber> LineNumbers; while (LineIter != Lines.end()) { - if (LineIter->IsTerminalEntry) { - ++LineIter; - continue; - } - - // If the line is still within the address range, create a NativeLineNumber - // and add to the list. - if (LineIter->Addr > VA + Length) - break; - - uint32_t LineSect, LineOff; - Session.addressForVA(LineIter->Addr, LineSect, LineOff); - uint32_t LineLength = std::next(LineIter)->Addr - LineIter->Addr; - auto ChecksumIter = - ExpectedChecksums->getArray().at(LineIter->FileNameIndex); - uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter); - NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber, + if (LineIter->IsTerminalEntry) { + ++LineIter; + continue; + } + + // If the line is still within the address range, create a NativeLineNumber + // and add to the list. + if (LineIter->Addr > VA + Length) + break; + + uint32_t LineSect, LineOff; + Session.addressForVA(LineIter->Addr, LineSect, LineOff); + uint32_t LineLength = std::next(LineIter)->Addr - LineIter->Addr; + auto ChecksumIter = + ExpectedChecksums->getArray().at(LineIter->FileNameIndex); + uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter); + NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber, LineSect, LineOff, LineLength, SrcFileId, Modi); - LineNumbers.push_back(LineNum); - ++LineIter; - } - return std::make_unique<NativeEnumLineNumbers>(std::move(LineNumbers)); -} - -std::unique_ptr<PDBSymbolCompiland> -SymbolCache::getOrCreateCompiland(uint32_t Index) { - if (!Dbi) - return nullptr; - - if (Index >= Compilands.size()) - return nullptr; - - if (Compilands[Index] == 0) { - const DbiModuleList &Modules = Dbi->modules(); - Compilands[Index] = - createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); - } - - return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); -} - -std::unique_ptr<IPDBSourceFile> -SymbolCache::getSourceFileById(SymIndexId FileId) const { - assert(FileId < SourceFiles.size()); - - // Id 0 is reserved. - if (FileId == 0) - return nullptr; - - return std::unique_ptr<NativeSourceFile>( - new NativeSourceFile(*SourceFiles[FileId].get())); -} - -SymIndexId -SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const { - auto Iter = FileNameOffsetToId.find(Checksums.FileNameOffset); - if (Iter != FileNameOffsetToId.end()) - return Iter->second; - - SymIndexId Id = SourceFiles.size(); - auto SrcFile = std::make_unique<NativeSourceFile>(Session, Id, Checksums); - SourceFiles.push_back(std::move(SrcFile)); - FileNameOffsetToId[Checksums.FileNameOffset] = Id; - return Id; -} - - + LineNumbers.push_back(LineNum); + ++LineIter; + } + return std::make_unique<NativeEnumLineNumbers>(std::move(LineNumbers)); +} + +std::unique_ptr<PDBSymbolCompiland> +SymbolCache::getOrCreateCompiland(uint32_t Index) { + if (!Dbi) + return nullptr; + + if (Index >= Compilands.size()) + return nullptr; + + if (Compilands[Index] == 0) { + const DbiModuleList &Modules = Dbi->modules(); + Compilands[Index] = + createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index)); + } + + return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]); +} + +std::unique_ptr<IPDBSourceFile> +SymbolCache::getSourceFileById(SymIndexId FileId) const { + assert(FileId < SourceFiles.size()); + + // Id 0 is reserved. + if (FileId == 0) + return nullptr; + + return std::unique_ptr<NativeSourceFile>( + new NativeSourceFile(*SourceFiles[FileId].get())); +} + +SymIndexId +SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const { + auto Iter = FileNameOffsetToId.find(Checksums.FileNameOffset); + if (Iter != FileNameOffsetToId.end()) + return Iter->second; + + SymIndexId Id = SourceFiles.size(); + auto SrcFile = std::make_unique<NativeSourceFile>(Session, Id, Checksums); + SourceFiles.push_back(std::move(SrcFile)); + FileNameOffsetToId[Checksums.FileNameOffset] = Id; + return Id; +} + + diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolStream.cpp index 003840b6e6..f07fcecbe2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -1,45 +1,45 @@ -//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" - -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" - -using namespace llvm; -using namespace llvm::msf; -using namespace llvm::support; -using namespace llvm::pdb; - -SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) - : Stream(std::move(Stream)) {} - -SymbolStream::~SymbolStream() {} - -Error SymbolStream::reload() { - BinaryStreamReader Reader(*Stream); - - if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) - return EC; - - return Error::success(); -} - -iterator_range<codeview::CVSymbolArray::Iterator> -SymbolStream::getSymbols(bool *HadError) const { - return llvm::make_range(SymbolRecords.begin(HadError), SymbolRecords.end()); -} - -Error SymbolStream::commit() { return Error::success(); } - -codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const { - return *SymbolRecords.at(Offset); -} +//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/SymbolStream.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream) + : Stream(std::move(Stream)) {} + +SymbolStream::~SymbolStream() {} + +Error SymbolStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) + return EC; + + return Error::success(); +} + +iterator_range<codeview::CVSymbolArray::Iterator> +SymbolStream::getSymbols(bool *HadError) const { + return llvm::make_range(SymbolRecords.begin(HadError), SymbolRecords.end()); +} + +Error SymbolStream::commit() { return Error::success(); } + +codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const { + return *SymbolRecords.at(Offset); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiHashing.cpp index b71b2b1581..5695e974fa 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiHashing.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiHashing.cpp @@ -1,129 +1,129 @@ -//===- TpiHashing.cpp -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" - -#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/Support/CRC.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -// Corresponds to `fUDTAnon`. -static bool isAnonymous(StringRef Name) { - return Name == "<unnamed-tag>" || Name == "__unnamed" || - Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); -} - -// Computes the hash for a user-defined type record. This could be a struct, -// class, union, or enum. -static uint32_t getHashForUdt(const TagRecord &Rec, - ArrayRef<uint8_t> FullRecord) { - ClassOptions Opts = Rec.getOptions(); - bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); - bool Scoped = bool(Opts & ClassOptions::Scoped); - bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName); - bool IsAnon = HasUniqueName && isAnonymous(Rec.getName()); - - if (!ForwardRef && !Scoped && !IsAnon) - return hashStringV1(Rec.getName()); - if (!ForwardRef && HasUniqueName && !IsAnon) - return hashStringV1(Rec.getUniqueName()); - return hashBufferV8(FullRecord); -} - -template <typename T> -static Expected<uint32_t> getHashForUdt(const CVType &Rec) { - T Deserialized; - if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), - Deserialized)) - return std::move(E); - return getHashForUdt(Deserialized, Rec.data()); -} - -template <typename T> -static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) { - T Deserialized; - if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), - Deserialized)) - return std::move(E); - - ClassOptions Opts = Deserialized.getOptions(); - - bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); - - uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data()); - - // If we don't have a forward ref we can't compute the hash of it from the - // full record because it requires hashing the entire buffer. - if (!ForwardRef) - return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0}; - - bool Scoped = bool(Opts & ClassOptions::Scoped); - - StringRef NameToHash = - Scoped ? Deserialized.getUniqueName() : Deserialized.getName(); - uint32_t FullHash = hashStringV1(NameToHash); - return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash}; -} - -template <typename T> -static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { - T Deserialized; - if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), - Deserialized)) - return std::move(E); - char Buf[4]; - support::endian::write32le(Buf, Deserialized.getUDT().getIndex()); - return hashStringV1(StringRef(Buf, 4)); -} - -Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) { - switch (Type.kind()) { - case LF_CLASS: - case LF_STRUCTURE: - case LF_INTERFACE: - return getTagRecordHashForUdt<ClassRecord>(Type); - case LF_UNION: - return getTagRecordHashForUdt<UnionRecord>(Type); - case LF_ENUM: - return getTagRecordHashForUdt<EnumRecord>(Type); - default: - assert(false && "Type is not a tag record!"); - } - return make_error<StringError>("Invalid record type", - inconvertibleErrorCode()); -} - -Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) { - switch (Rec.kind()) { - case LF_CLASS: - case LF_STRUCTURE: - case LF_INTERFACE: - return getHashForUdt<ClassRecord>(Rec); - case LF_UNION: - return getHashForUdt<UnionRecord>(Rec); - case LF_ENUM: - return getHashForUdt<EnumRecord>(Rec); - - case LF_UDT_SRC_LINE: - return getSourceLineHash<UdtSourceLineRecord>(Rec); - case LF_UDT_MOD_SRC_LINE: - return getSourceLineHash<UdtModSourceLineRecord>(Rec); - - default: - break; - } - - // Run CRC32 over the bytes. This corresponds to `hashBufv8`. - JamCRC JC(/*Init=*/0U); - JC.update(Rec.data()); - return JC.getCRC(); -} +//===- TpiHashing.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" + +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/Support/CRC.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +// Corresponds to `fUDTAnon`. +static bool isAnonymous(StringRef Name) { + return Name == "<unnamed-tag>" || Name == "__unnamed" || + Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed"); +} + +// Computes the hash for a user-defined type record. This could be a struct, +// class, union, or enum. +static uint32_t getHashForUdt(const TagRecord &Rec, + ArrayRef<uint8_t> FullRecord) { + ClassOptions Opts = Rec.getOptions(); + bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); + bool Scoped = bool(Opts & ClassOptions::Scoped); + bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName); + bool IsAnon = HasUniqueName && isAnonymous(Rec.getName()); + + if (!ForwardRef && !Scoped && !IsAnon) + return hashStringV1(Rec.getName()); + if (!ForwardRef && HasUniqueName && !IsAnon) + return hashStringV1(Rec.getUniqueName()); + return hashBufferV8(FullRecord); +} + +template <typename T> +static Expected<uint32_t> getHashForUdt(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + return getHashForUdt(Deserialized, Rec.data()); +} + +template <typename T> +static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + + ClassOptions Opts = Deserialized.getOptions(); + + bool ForwardRef = bool(Opts & ClassOptions::ForwardReference); + + uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data()); + + // If we don't have a forward ref we can't compute the hash of it from the + // full record because it requires hashing the entire buffer. + if (!ForwardRef) + return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0}; + + bool Scoped = bool(Opts & ClassOptions::Scoped); + + StringRef NameToHash = + Scoped ? Deserialized.getUniqueName() : Deserialized.getName(); + uint32_t FullHash = hashStringV1(NameToHash); + return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash}; +} + +template <typename T> +static Expected<uint32_t> getSourceLineHash(const CVType &Rec) { + T Deserialized; + if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec), + Deserialized)) + return std::move(E); + char Buf[4]; + support::endian::write32le(Buf, Deserialized.getUDT().getIndex()); + return hashStringV1(StringRef(Buf, 4)); +} + +Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) { + switch (Type.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return getTagRecordHashForUdt<ClassRecord>(Type); + case LF_UNION: + return getTagRecordHashForUdt<UnionRecord>(Type); + case LF_ENUM: + return getTagRecordHashForUdt<EnumRecord>(Type); + default: + assert(false && "Type is not a tag record!"); + } + return make_error<StringError>("Invalid record type", + inconvertibleErrorCode()); +} + +Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) { + switch (Rec.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return getHashForUdt<ClassRecord>(Rec); + case LF_UNION: + return getHashForUdt<UnionRecord>(Rec); + case LF_ENUM: + return getHashForUdt<EnumRecord>(Rec); + + case LF_UDT_SRC_LINE: + return getSourceLineHash<UdtSourceLineRecord>(Rec); + case LF_UDT_MOD_SRC_LINE: + return getSourceLineHash<UdtModSourceLineRecord>(Rec); + + default: + break; + } + + // Run CRC32 over the bytes. This corresponds to `hashBufv8`. + JamCRC JC(/*Init=*/0U); + JC.update(Rec.data()); + return JC.getCRC(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStream.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStream.cpp index ac19db03fa..e82fc1b4c2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -1,246 +1,246 @@ -//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" - -#include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/RecordName.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/Hash.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" -#include "llvm/Support/BinaryStreamReader.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; - -TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) - : Pdb(File), Stream(std::move(Stream)) {} - -TpiStream::~TpiStream() = default; - -Error TpiStream::reload() { - BinaryStreamReader Reader(*Stream); - - if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) - return make_error<RawError>(raw_error_code::corrupt_file, - "TPI Stream does not contain a header."); - - if (Reader.readObject(Header)) - return make_error<RawError>(raw_error_code::corrupt_file, - "TPI Stream does not contain a header."); - - if (Header->Version != PdbTpiV80) - return make_error<RawError>(raw_error_code::corrupt_file, - "Unsupported TPI Version."); - - if (Header->HeaderSize != sizeof(TpiStreamHeader)) - return make_error<RawError>(raw_error_code::corrupt_file, - "Corrupt TPI Header size."); - - if (Header->HashKeySize != sizeof(ulittle32_t)) - return make_error<RawError>(raw_error_code::corrupt_file, - "TPI Stream expected 4 byte hash key size."); - - if (Header->NumHashBuckets < MinTpiHashBuckets || - Header->NumHashBuckets > MaxTpiHashBuckets) - return make_error<RawError>(raw_error_code::corrupt_file, - "TPI Stream Invalid number of hash buckets."); - - // The actual type records themselves come from this stream - if (auto EC = - Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes)) - return EC; - - BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData); - if (auto EC = - RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size())) - return EC; - - // Hash indices, hash values, etc come from the hash stream. - if (Header->HashStreamIndex != kInvalidStreamIndex) { - auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex); - if (!HS) { - consumeError(HS.takeError()); - return make_error<RawError>(raw_error_code::corrupt_file, - "Invalid TPI hash stream index."); - } - BinaryStreamReader HSR(**HS); - - // There should be a hash value for every type record, or no hashes at all. - uint32_t NumHashValues = - Header->HashValueBuffer.Length / sizeof(ulittle32_t); - if (NumHashValues != getNumTypeRecords() && NumHashValues != 0) - 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; - - if (Header->HashAdjBuffer.Length > 0) { - HSR.setOffset(Header->HashAdjBuffer.Off); - if (auto EC = HashAdjusters.load(HSR)) - return EC; - } - - HashStream = std::move(*HS); - } - - Types = std::make_unique<LazyRandomTypeCollection>( - TypeRecords, getNumTypeRecords(), getTypeIndexOffsets()); - return Error::success(); -} - -PdbRaw_TpiVer TpiStream::getTpiVersion() const { - uint32_t Value = Header->Version; - return static_cast<PdbRaw_TpiVer>(Value); -} - -uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; } - -uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; } - -uint32_t TpiStream::getNumTypeRecords() const { - return TypeIndexEnd() - TypeIndexBegin(); -} - -uint16_t TpiStream::getTypeHashStreamIndex() const { - return Header->HashStreamIndex; -} - -uint16_t TpiStream::getTypeHashStreamAuxIndex() const { - return Header->HashAuxStreamIndex; -} - -uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } -uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } - -void TpiStream::buildHashMap() { - if (!HashMap.empty()) - return; - if (HashValues.empty()) - return; - - HashMap.resize(Header->NumHashBuckets); - - TypeIndex TIB{Header->TypeIndexBegin}; - TypeIndex TIE{Header->TypeIndexEnd}; - while (TIB < TIE) { - uint32_t HV = HashValues[TIB.toArrayIndex()]; - HashMap[HV].push_back(TIB++); - } -} - -std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const { - if (!supportsTypeLookup()) - const_cast<TpiStream*>(this)->buildHashMap(); - - uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets; - if (Bucket > HashMap.size()) - return {}; - - std::vector<TypeIndex> Result; - for (TypeIndex TI : HashMap[Bucket]) { - std::string ThisName = computeTypeName(*Types, TI); - if (ThisName == Name) - Result.push_back(TI); - } - return Result; -} - -bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); } - -Expected<TypeIndex> -TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { - if (!supportsTypeLookup()) - const_cast<TpiStream*>(this)->buildHashMap(); - - CVType F = Types->getType(ForwardRefTI); - if (!isUdtForwardRef(F)) - return ForwardRefTI; - - Expected<TagRecordHash> ForwardTRH = hashTagRecord(F); - if (!ForwardTRH) - return ForwardTRH.takeError(); - - uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets; - - for (TypeIndex TI : HashMap[BucketIdx]) { - CVType CVT = Types->getType(TI); - if (CVT.kind() != F.kind()) - continue; - - Expected<TagRecordHash> FullTRH = hashTagRecord(CVT); - if (!FullTRH) - return FullTRH.takeError(); - if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash) - continue; - TagRecord &ForwardTR = ForwardTRH->getRecord(); - TagRecord &FullTR = FullTRH->getRecord(); - - if (!ForwardTR.hasUniqueName()) { - if (ForwardTR.getName() == FullTR.getName()) - return TI; - continue; - } - - if (!FullTR.hasUniqueName()) - continue; - if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) - return TI; - } - return ForwardRefTI; -} - -codeview::CVType TpiStream::getType(codeview::TypeIndex Index) { - assert(!Index.isSimple()); - return Types->getType(Index); -} - -BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { - return TypeRecordsSubstream; -} - -FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const { - return HashValues; -} - -FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { - return TypeIndexOffsets; -} - -HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() { - return HashAdjusters; -} - -CVTypeRange TpiStream::types(bool *HadError) const { - return make_range(TypeRecords.begin(HadError), TypeRecords.end()); -} - -Error TpiStream::commit() { return Error::success(); } +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +#include "llvm/ADT/iterator_range.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/RecordName.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/Support/BinaryStreamReader.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; + +TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream) + : Pdb(File), Stream(std::move(Stream)) {} + +TpiStream::~TpiStream() = default; + +Error TpiStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); + + if (Reader.readObject(Header)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); + + if (Header->Version != PdbTpiV80) + return make_error<RawError>(raw_error_code::corrupt_file, + "Unsupported TPI Version."); + + if (Header->HeaderSize != sizeof(TpiStreamHeader)) + return make_error<RawError>(raw_error_code::corrupt_file, + "Corrupt TPI Header size."); + + if (Header->HashKeySize != sizeof(ulittle32_t)) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream expected 4 byte hash key size."); + + if (Header->NumHashBuckets < MinTpiHashBuckets || + Header->NumHashBuckets > MaxTpiHashBuckets) + return make_error<RawError>(raw_error_code::corrupt_file, + "TPI Stream Invalid number of hash buckets."); + + // The actual type records themselves come from this stream + if (auto EC = + Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes)) + return EC; + + BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData); + if (auto EC = + RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size())) + return EC; + + // Hash indices, hash values, etc come from the hash stream. + if (Header->HashStreamIndex != kInvalidStreamIndex) { + auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex); + if (!HS) { + consumeError(HS.takeError()); + return make_error<RawError>(raw_error_code::corrupt_file, + "Invalid TPI hash stream index."); + } + BinaryStreamReader HSR(**HS); + + // There should be a hash value for every type record, or no hashes at all. + uint32_t NumHashValues = + Header->HashValueBuffer.Length / sizeof(ulittle32_t); + if (NumHashValues != getNumTypeRecords() && NumHashValues != 0) + 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; + + if (Header->HashAdjBuffer.Length > 0) { + HSR.setOffset(Header->HashAdjBuffer.Off); + if (auto EC = HashAdjusters.load(HSR)) + return EC; + } + + HashStream = std::move(*HS); + } + + Types = std::make_unique<LazyRandomTypeCollection>( + TypeRecords, getNumTypeRecords(), getTypeIndexOffsets()); + return Error::success(); +} + +PdbRaw_TpiVer TpiStream::getTpiVersion() const { + uint32_t Value = Header->Version; + return static_cast<PdbRaw_TpiVer>(Value); +} + +uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; } + +uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; } + +uint32_t TpiStream::getNumTypeRecords() const { + return TypeIndexEnd() - TypeIndexBegin(); +} + +uint16_t TpiStream::getTypeHashStreamIndex() const { + return Header->HashStreamIndex; +} + +uint16_t TpiStream::getTypeHashStreamAuxIndex() const { + return Header->HashAuxStreamIndex; +} + +uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } +uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } + +void TpiStream::buildHashMap() { + if (!HashMap.empty()) + return; + if (HashValues.empty()) + return; + + HashMap.resize(Header->NumHashBuckets); + + TypeIndex TIB{Header->TypeIndexBegin}; + TypeIndex TIE{Header->TypeIndexEnd}; + while (TIB < TIE) { + uint32_t HV = HashValues[TIB.toArrayIndex()]; + HashMap[HV].push_back(TIB++); + } +} + +std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets; + if (Bucket > HashMap.size()) + return {}; + + std::vector<TypeIndex> Result; + for (TypeIndex TI : HashMap[Bucket]) { + std::string ThisName = computeTypeName(*Types, TI); + if (ThisName == Name) + Result.push_back(TI); + } + return Result; +} + +bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); } + +Expected<TypeIndex> +TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const { + if (!supportsTypeLookup()) + const_cast<TpiStream*>(this)->buildHashMap(); + + CVType F = Types->getType(ForwardRefTI); + if (!isUdtForwardRef(F)) + return ForwardRefTI; + + Expected<TagRecordHash> ForwardTRH = hashTagRecord(F); + if (!ForwardTRH) + return ForwardTRH.takeError(); + + uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets; + + for (TypeIndex TI : HashMap[BucketIdx]) { + CVType CVT = Types->getType(TI); + if (CVT.kind() != F.kind()) + continue; + + Expected<TagRecordHash> FullTRH = hashTagRecord(CVT); + if (!FullTRH) + return FullTRH.takeError(); + if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash) + continue; + TagRecord &ForwardTR = ForwardTRH->getRecord(); + TagRecord &FullTR = FullTRH->getRecord(); + + if (!ForwardTR.hasUniqueName()) { + if (ForwardTR.getName() == FullTR.getName()) + return TI; + continue; + } + + if (!FullTR.hasUniqueName()) + continue; + if (ForwardTR.getUniqueName() == FullTR.getUniqueName()) + return TI; + } + return ForwardRefTI; +} + +codeview::CVType TpiStream::getType(codeview::TypeIndex Index) { + assert(!Index.isSimple()); + return Types->getType(Index); +} + +BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { + return TypeRecordsSubstream; +} + +FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const { + return HashValues; +} + +FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const { + return TypeIndexOffsets; +} + +HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() { + return HashAdjusters; +} + +CVTypeRange TpiStream::types(bool *HadError) const { + return make_range(TypeRecords.begin(HadError), TypeRecords.end()); +} + +Error TpiStream::commit() { return Error::success(); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp index 5f4f497690..204ca508d4 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -1,47 +1,47 @@ -//===- TpiStreamBuilder.cpp - -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/BinaryStreamArray.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/BinaryStreamWriter.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cstdint> +//===- TpiStreamBuilder.cpp - -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <algorithm> +#include <cstdint> #include <numeric> - -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; -} - + +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::updateTypeIndexOffsets(ArrayRef<uint16_t> Sizes) { // If we just crossed an 8KB threshold, add a type index offset. for (uint16_t Size : Sizes) { @@ -58,21 +58,21 @@ void TpiStreamBuilder::updateTypeIndexOffsets(ArrayRef<uint16_t> Sizes) { } } -void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, - Optional<uint32_t> Hash) { - assert(((Record.size() & 3) == 0) && - "The type record's size is not a multiple of 4 bytes which will " - "cause misalignment in the output TPI stream!"); +void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record, + Optional<uint32_t> Hash) { + assert(((Record.size() & 3) == 0) && + "The type record's size is not a multiple of 4 bytes which will " + "cause misalignment in the output TPI stream!"); assert(Record.size() <= codeview::MaxRecordLength); uint16_t OneSize = (uint16_t)Record.size(); updateTypeIndexOffsets(makeArrayRef(&OneSize, 1)); - + TypeRecBuffers.push_back(Record); // FIXME: Require it. - if (Hash) - TypeHashes.push_back(*Hash); -} - + if (Hash) + TypeHashes.push_back(*Hash); +} + void TpiStreamBuilder::addTypeRecords(ArrayRef<uint8_t> Types, ArrayRef<uint16_t> Sizes, ArrayRef<uint32_t> Hashes) { @@ -94,121 +94,121 @@ void TpiStreamBuilder::addTypeRecords(ArrayRef<uint8_t> Types, llvm::append_range(TypeHashes, Hashes); } -Error TpiStreamBuilder::finalize() { - if (Header) - return Error::success(); - - TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); - - H->Version = VerHeader; - H->HeaderSize = sizeof(TpiStreamHeader); - H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; +Error TpiStreamBuilder::finalize() { + if (Header) + return Error::success(); + + TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>(); + + H->Version = VerHeader; + H->HeaderSize = sizeof(TpiStreamHeader); + H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex; H->TypeIndexEnd = H->TypeIndexBegin + TypeRecordCount; - H->TypeRecordBytes = TypeRecordBytes; - - H->HashStreamIndex = HashStreamIndex; - H->HashAuxStreamIndex = kInvalidStreamIndex; - H->HashKeySize = sizeof(ulittle32_t); - H->NumHashBuckets = MaxTpiHashBuckets - 1; - - // 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 = calculateHashBufferSize(); - - // We never write any adjustments into our PDBs, so this is usually some - // offset with zero length. - H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; - H->HashAdjBuffer.Length = 0; - - H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; - H->IndexOffsetBuffer.Length = calculateIndexOffsetSize(); - - Header = H; - return Error::success(); -} - -uint32_t TpiStreamBuilder::calculateSerializedLength() { - return sizeof(TpiStreamHeader) + TypeRecordBytes; -} - -uint32_t TpiStreamBuilder::calculateHashBufferSize() const { + H->TypeRecordBytes = TypeRecordBytes; + + H->HashStreamIndex = HashStreamIndex; + H->HashAuxStreamIndex = kInvalidStreamIndex; + H->HashKeySize = sizeof(ulittle32_t); + H->NumHashBuckets = MaxTpiHashBuckets - 1; + + // 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 = calculateHashBufferSize(); + + // We never write any adjustments into our PDBs, so this is usually some + // offset with zero length. + H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length; + H->HashAdjBuffer.Length = 0; + + H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length; + H->IndexOffsetBuffer.Length = calculateIndexOffsetSize(); + + Header = H; + return Error::success(); +} + +uint32_t TpiStreamBuilder::calculateSerializedLength() { + return sizeof(TpiStreamHeader) + TypeRecordBytes; +} + +uint32_t TpiStreamBuilder::calculateHashBufferSize() const { assert((TypeRecordCount == TypeHashes.size() || TypeHashes.empty()) && - "either all or no type records should have hashes"); - return TypeHashes.size() * sizeof(ulittle32_t); -} - -uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const { - return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset); -} - -Error TpiStreamBuilder::finalizeMsfLayout() { - uint32_t Length = calculateSerializedLength(); - if (auto EC = Msf.setStreamSize(Idx, Length)) - return EC; - - uint32_t HashStreamSize = - calculateHashBufferSize() + calculateIndexOffsetSize(); - - if (HashStreamSize == 0) - return Error::success(); - - auto ExpectedIndex = Msf.addStream(HashStreamSize); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - HashStreamIndex = *ExpectedIndex; - if (!TypeHashes.empty()) { - ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size()); - MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size()); - for (uint32_t I = 0; I < TypeHashes.size(); ++I) { - HashBuffer[I] = TypeHashes[I] % (MaxTpiHashBuckets - 1); - } - ArrayRef<uint8_t> Bytes( - reinterpret_cast<const uint8_t *>(HashBuffer.data()), - calculateHashBufferSize()); - HashValueStream = - std::make_unique<BinaryByteStream>(Bytes, llvm::support::little); - } - return Error::success(); -} - -Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, - WritableBinaryStreamRef Buffer) { - if (auto EC = finalize()) - return EC; - - auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, - Idx, Allocator); - - BinaryStreamWriter Writer(*InfoS); - if (auto EC = Writer.writeObject(*Header)) - return EC; - + "either all or no type records should have hashes"); + return TypeHashes.size() * sizeof(ulittle32_t); +} + +uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const { + return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset); +} + +Error TpiStreamBuilder::finalizeMsfLayout() { + uint32_t Length = calculateSerializedLength(); + if (auto EC = Msf.setStreamSize(Idx, Length)) + return EC; + + uint32_t HashStreamSize = + calculateHashBufferSize() + calculateIndexOffsetSize(); + + if (HashStreamSize == 0) + return Error::success(); + + auto ExpectedIndex = Msf.addStream(HashStreamSize); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + HashStreamIndex = *ExpectedIndex; + if (!TypeHashes.empty()) { + ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size()); + MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size()); + for (uint32_t I = 0; I < TypeHashes.size(); ++I) { + HashBuffer[I] = TypeHashes[I] % (MaxTpiHashBuckets - 1); + } + ArrayRef<uint8_t> Bytes( + reinterpret_cast<const uint8_t *>(HashBuffer.data()), + calculateHashBufferSize()); + HashValueStream = + std::make_unique<BinaryByteStream>(Bytes, llvm::support::little); + } + return Error::success(); +} + +Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, + WritableBinaryStreamRef Buffer) { + if (auto EC = finalize()) + return EC; + + auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, + Idx, Allocator); + + BinaryStreamWriter Writer(*InfoS); + if (auto EC = Writer.writeObject(*Header)) + return EC; + for (auto Rec : TypeRecBuffers) { - assert(!Rec.empty() && "Attempting to write an empty type record shifts " - "all offsets in the TPI stream!"); - assert(((Rec.size() & 3) == 0) && - "The type record's size is not a multiple of 4 bytes which will " - "cause misalignment in the output TPI stream!"); - if (auto EC = Writer.writeBytes(Rec)) - return EC; - } - - if (HashStreamIndex != kInvalidStreamIndex) { - auto HVS = WritableMappedBlockStream::createIndexedStream( - Layout, Buffer, HashStreamIndex, Allocator); - BinaryStreamWriter HW(*HVS); - if (HashValueStream) { - if (auto EC = HW.writeStreamRef(*HashValueStream)) - return EC; - } - - for (auto &IndexOffset : TypeIndexOffsets) { - if (auto EC = HW.writeObject(IndexOffset)) - return EC; - } - } - - return Error::success(); -} + assert(!Rec.empty() && "Attempting to write an empty type record shifts " + "all offsets in the TPI stream!"); + assert(((Rec.size() & 3) == 0) && + "The type record's size is not a multiple of 4 bytes which will " + "cause misalignment in the output TPI stream!"); + if (auto EC = Writer.writeBytes(Rec)) + return EC; + } + + if (HashStreamIndex != kInvalidStreamIndex) { + auto HVS = WritableMappedBlockStream::createIndexedStream( + Layout, Buffer, HashStreamIndex, Allocator); + BinaryStreamWriter HW(*HVS); + if (HashValueStream) { + if (auto EC = HW.writeStreamRef(*HashValueStream)) + return EC; + } + + for (auto &IndexOffset : TypeIndexOffsets) { + if (auto EC = HW.writeObject(IndexOffset)) + return EC; + } + } + + return Error::success(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDB.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDB.cpp index 6dc42715fb..9c1737663a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDB.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDB.cpp @@ -1,51 +1,51 @@ -//===- PDB.cpp - base header file for creating a PDB reader ---------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDB.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Config/config.h" -#include "llvm/DebugInfo/PDB/GenericError.h" -#if LLVM_ENABLE_DIA_SDK +//===- PDB.cpp - base header file for creating a PDB reader ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#if LLVM_ENABLE_DIA_SDK #error #include "llvm/DebugInfo/PDB/DIA/DIASession.h" -#endif -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MemoryBuffer.h" - -using namespace llvm; -using namespace llvm::pdb; - -Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session) { - // Create the correct concrete instance type based on the value of Type. - if (Type == PDB_ReaderType::Native) - return NativeSession::createFromPdbPath(Path, Session); - -#if LLVM_ENABLE_DIA_SDK - return DIASession::createFromPdb(Path, Session); -#else - return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); -#endif -} - -Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr<IPDBSession> &Session) { - // Create the correct concrete instance type based on the value of Type. - if (Type == PDB_ReaderType::Native) { - Expected<std::string> PdbPath = NativeSession::searchForPdb({Path}); - if (!PdbPath) - return PdbPath.takeError(); - return NativeSession::createFromPdbPath(PdbPath.get(), Session); - } - -#if LLVM_ENABLE_DIA_SDK - return DIASession::createFromExe(Path, Session); -#else - return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); -#endif -} +#endif +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm::pdb; + +Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + // Create the correct concrete instance type based on the value of Type. + if (Type == PDB_ReaderType::Native) + return NativeSession::createFromPdbPath(Path, Session); + +#if LLVM_ENABLE_DIA_SDK + return DIASession::createFromPdb(Path, Session); +#else + return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); +#endif +} + +Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr<IPDBSession> &Session) { + // Create the correct concrete instance type based on the value of Type. + if (Type == PDB_ReaderType::Native) { + Expected<std::string> PdbPath = NativeSession::searchForPdb({Path}); + if (!PdbPath) + return PdbPath.takeError(); + return NativeSession::createFromPdbPath(PdbPath.get(), Session); + } + +#if LLVM_ENABLE_DIA_SDK + return DIASession::createFromExe(Path, Session); +#else + return make_error<PDBError>(pdb_error_code::dia_sdk_not_present); +#endif +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBContext.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBContext.cpp index 0ebb70e010..886eac8eaf 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBContext.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBContext.cpp @@ -1,91 +1,91 @@ -//===-- PDBContext.cpp ------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===/ - -#include "llvm/DebugInfo/PDB/PDBContext.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" -#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" -#include "llvm/Object/COFF.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::pdb; - -PDBContext::PDBContext(const COFFObjectFile &Object, - std::unique_ptr<IPDBSession> PDBSession) - : DIContext(CK_PDB), Session(std::move(PDBSession)) { - ErrorOr<uint64_t> ImageBase = Object.getImageBase(); - if (ImageBase) - Session->setLoadAddress(ImageBase.get()); -} - -void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){} - -DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address, - DILineInfoSpecifier Specifier) { - DILineInfo Result; - Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind); - - uint32_t Length = 1; - std::unique_ptr<PDBSymbol> Symbol = - Session->findSymbolByAddress(Address.Address, PDB_SymType::None); - if (auto Func = dyn_cast_or_null<PDBSymbolFunc>(Symbol.get())) { - Length = Func->getLength(); - } else if (auto Data = dyn_cast_or_null<PDBSymbolData>(Symbol.get())) { - Length = Data->getLength(); - } - - // If we couldn't find a symbol, then just assume 1 byte, so that we get - // only the line number of the first instruction. - auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Length); - if (!LineNumbers || LineNumbers->getChildCount() == 0) - return Result; - - auto LineInfo = LineNumbers->getNext(); - assert(LineInfo); - auto SourceFile = Session->getSourceFileById(LineInfo->getSourceFileId()); - - if (SourceFile && - Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None) - Result.FileName = SourceFile->getFileName(); - Result.Column = LineInfo->getColumnNumber(); - Result.Line = LineInfo->getLineNumber(); - return Result; -} - -DILineInfoTable -PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address, - uint64_t Size, - DILineInfoSpecifier Specifier) { - if (Size == 0) - return DILineInfoTable(); - - DILineInfoTable Table; - auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Size); - if (!LineNumbers || LineNumbers->getChildCount() == 0) - return Table; - - while (auto LineInfo = LineNumbers->getNext()) { - DILineInfo LineEntry = getLineInfoForAddress( - {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier); - Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry)); - } - return Table; -} - -DIInliningInfo -PDBContext::getInliningInfoForAddress(object::SectionedAddress Address, - DILineInfoSpecifier Specifier) { - DIInliningInfo InlineInfo; +//===-- PDBContext.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/Object/COFF.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::pdb; + +PDBContext::PDBContext(const COFFObjectFile &Object, + std::unique_ptr<IPDBSession> PDBSession) + : DIContext(CK_PDB), Session(std::move(PDBSession)) { + ErrorOr<uint64_t> ImageBase = Object.getImageBase(); + if (ImageBase) + Session->setLoadAddress(ImageBase.get()); +} + +void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){} + +DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Specifier) { + DILineInfo Result; + Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind); + + uint32_t Length = 1; + std::unique_ptr<PDBSymbol> Symbol = + Session->findSymbolByAddress(Address.Address, PDB_SymType::None); + if (auto Func = dyn_cast_or_null<PDBSymbolFunc>(Symbol.get())) { + Length = Func->getLength(); + } else if (auto Data = dyn_cast_or_null<PDBSymbolData>(Symbol.get())) { + Length = Data->getLength(); + } + + // If we couldn't find a symbol, then just assume 1 byte, so that we get + // only the line number of the first instruction. + auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Length); + if (!LineNumbers || LineNumbers->getChildCount() == 0) + return Result; + + auto LineInfo = LineNumbers->getNext(); + assert(LineInfo); + auto SourceFile = Session->getSourceFileById(LineInfo->getSourceFileId()); + + if (SourceFile && + Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None) + Result.FileName = SourceFile->getFileName(); + Result.Column = LineInfo->getColumnNumber(); + Result.Line = LineInfo->getLineNumber(); + return Result; +} + +DILineInfoTable +PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address, + uint64_t Size, + DILineInfoSpecifier Specifier) { + if (Size == 0) + return DILineInfoTable(); + + DILineInfoTable Table; + auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Size); + if (!LineNumbers || LineNumbers->getChildCount() == 0) + return Table; + + while (auto LineInfo = LineNumbers->getNext()) { + DILineInfo LineEntry = getLineInfoForAddress( + {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier); + Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry)); + } + return Table; +} + +DIInliningInfo +PDBContext::getInliningInfoForAddress(object::SectionedAddress Address, + DILineInfoSpecifier Specifier) { + DIInliningInfo InlineInfo; DILineInfo CurrentLine = getLineInfoForAddress(Address, Specifier); // Find the function at this address. @@ -123,37 +123,37 @@ PDBContext::getInliningInfoForAddress(object::SectionedAddress Address, } InlineInfo.addFrame(CurrentLine); - return InlineInfo; -} - -std::vector<DILocal> -PDBContext::getLocalsForAddress(object::SectionedAddress Address) { - return std::vector<DILocal>(); -} - -std::string PDBContext::getFunctionName(uint64_t Address, - DINameKind NameKind) const { - if (NameKind == DINameKind::None) - return std::string(); - - std::unique_ptr<PDBSymbol> FuncSymbol = - Session->findSymbolByAddress(Address, PDB_SymType::Function); - auto *Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get()); - - if (NameKind == DINameKind::LinkageName) { - // It is not possible to get the mangled linkage name through a - // PDBSymbolFunc. For that we have to specifically request a - // PDBSymbolPublicSymbol. - auto PublicSym = - Session->findSymbolByAddress(Address, PDB_SymType::PublicSymbol); - if (auto *PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get())) { - // If we also have a function symbol, prefer the use of public symbol name - // only if it refers to the same address. The public symbol uses the - // linkage name while the function does not. - if (!Func || Func->getVirtualAddress() == PS->getVirtualAddress()) - return PS->getName(); - } - } - - return Func ? Func->getName() : std::string(); -} + return InlineInfo; +} + +std::vector<DILocal> +PDBContext::getLocalsForAddress(object::SectionedAddress Address) { + return std::vector<DILocal>(); +} + +std::string PDBContext::getFunctionName(uint64_t Address, + DINameKind NameKind) const { + if (NameKind == DINameKind::None) + return std::string(); + + std::unique_ptr<PDBSymbol> FuncSymbol = + Session->findSymbolByAddress(Address, PDB_SymType::Function); + auto *Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get()); + + if (NameKind == DINameKind::LinkageName) { + // It is not possible to get the mangled linkage name through a + // PDBSymbolFunc. For that we have to specifically request a + // PDBSymbolPublicSymbol. + auto PublicSym = + Session->findSymbolByAddress(Address, PDB_SymType::PublicSymbol); + if (auto *PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get())) { + // If we also have a function symbol, prefer the use of public symbol name + // only if it refers to the same address. The public symbol uses the + // linkage name while the function does not. + if (!Func || Func->getVirtualAddress() == PS->getVirtualAddress()) + return PS->getName(); + } + } + + return Func ? Func->getName() : std::string(); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBExtras.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBExtras.cpp index 25962e5152..a1bd7f6a29 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBExtras.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBExtras.cpp @@ -1,125 +1,125 @@ -//===- PDBExtras.cpp - helper functions and classes for PDBs --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::pdb; - -#define CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, Str, Stream) \ - case Class::Value: \ - Stream << Str; \ - break; - -#define CASE_OUTPUT_ENUM_CLASS_NAME(Class, Value, Stream) \ - CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, #Value, Stream) - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_VariantType &Type) { - switch (Type) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Bool, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Single, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Double, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int8, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int16, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int32, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int64, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt8, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt16, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt32, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt64, OS) - default: - OS << "Unknown"; - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_BuiltinType &Type) { - switch (Type) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, None, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Void, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, WCharT, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Int, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, UInt, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Float, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BCD, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bool, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Long, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, ULong, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Currency, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Date, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Variant, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Complex, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bitfield, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BSTR, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, HResult, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char16, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char32, OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_CallingConv &Conv) { - OS << "__"; - switch (Conv) { - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearC , "cdecl", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarC , "cdecl", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal , "pascal", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal , "pascal", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFast , "fastcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFast , "fastcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdCall, "stdcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdCall , "stdcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSysCall, "syscall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSysCall , "syscall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ThisCall , "thiscall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall , "mipscall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic , "genericcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AlphaCall , "alphacall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, PpcCall , "ppccall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SHCall , "superhcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ArmCall , "armcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33Call , "am33call", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, TriCall , "tricall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SH5Call , "sh5call", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32RCall , "m32rcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ClrCall , "clrcall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline , "inlinecall", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVector , "vectorcall", OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_DataKind &Data) { - switch (Data) { - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Unknown, "unknown", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Local, "local", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticLocal, "static local", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Param, "param", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, ObjectPtr, "this ptr", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, FileStatic, "static global", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Global, "global", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Member, "member", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticMember, "static member", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Constant, "const", OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const llvm::codeview::CPURegister &CpuReg) { +//===- PDBExtras.cpp - helper functions and classes for PDBs --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::pdb; + +#define CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, Str, Stream) \ + case Class::Value: \ + Stream << Str; \ + break; + +#define CASE_OUTPUT_ENUM_CLASS_NAME(Class, Value, Stream) \ + CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, #Value, Stream) + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_VariantType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Bool, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Single, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Double, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int8, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int32, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt8, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt32, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt64, OS) + default: + OS << "Unknown"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_BuiltinType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, None, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Void, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, WCharT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Int, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, UInt, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Float, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BCD, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bool, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Long, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, ULong, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Currency, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Date, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Variant, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Complex, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bitfield, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BSTR, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, HResult, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char32, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_CallingConv &Conv) { + OS << "__"; + switch (Conv) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearC , "cdecl", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarC , "cdecl", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal , "pascal", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal , "pascal", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFast , "fastcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFast , "fastcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdCall, "stdcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdCall , "stdcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSysCall, "syscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSysCall , "syscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ThisCall , "thiscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall , "mipscall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic , "genericcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AlphaCall , "alphacall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, PpcCall , "ppccall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SHCall , "superhcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ArmCall , "armcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33Call , "am33call", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, TriCall , "tricall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SH5Call , "sh5call", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32RCall , "m32rcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ClrCall , "clrcall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline , "inlinecall", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVector , "vectorcall", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_DataKind &Data) { + switch (Data) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Unknown, "unknown", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Local, "local", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticLocal, "static local", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Param, "param", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, ObjectPtr, "this ptr", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, FileStatic, "static global", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Global, "global", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Member, "member", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticMember, "static member", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Constant, "const", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const llvm::codeview::CPURegister &CpuReg) { if (CpuReg.Cpu == llvm::codeview::CPUType::ARMNT) { - switch (CpuReg.Reg) { + switch (CpuReg.Reg) { #define CV_REGISTERS_ARM #define CV_REGISTER(name, val) \ case codeview::RegisterId::name: \ @@ -134,274 +134,274 @@ raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, } } else if (CpuReg.Cpu == llvm::codeview::CPUType::ARM64) { switch (CpuReg.Reg) { -#define CV_REGISTERS_ARM64 -#define CV_REGISTER(name, val) \ - case codeview::RegisterId::name: \ - OS << #name; \ - return OS; -#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" -#undef CV_REGISTER -#undef CV_REGISTERS_ARM64 - - default: - break; - } - } else { - switch (CpuReg.Reg) { -#define CV_REGISTERS_X86 -#define CV_REGISTER(name, val) \ - case codeview::RegisterId::name: \ - OS << #name; \ - return OS; -#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" -#undef CV_REGISTER -#undef CV_REGISTERS_X86 - - default: - break; - } - } - OS << static_cast<int>(CpuReg.Reg); - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) { - switch (Loc) { - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Static, "static", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, TLS, "tls", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRel, "regrel", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, ThisRel, "thisrel", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Enregistered, "register", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, BitField, "bitfield", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Slot, "slot", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, IlRel, "IL rel", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, MetaData, "metadata", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Constant, "constant", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRelAliasIndir, - "regrelaliasindir", OS) - default: - OS << "Unknown"; - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const codeview::ThunkOrdinal &Thunk) { - switch (Thunk) { - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, BranchIsland, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Pcode, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Standard, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, ThisAdjustor, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, TrampIncremental, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, UnknownLoad, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Vcall, OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_Checksum &Checksum) { - switch (Checksum) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, None, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, MD5, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA1, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA256, OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Lang &Lang) { - switch (Lang) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, C, OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_Lang, Cpp, "C++", OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Fortran, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Masm, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Pascal, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Basic, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cobol, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Link, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtres, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtpgd, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, CSharp, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, VB, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, ILAsm, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Java, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, JScript, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, MSIL, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, HLSL, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, D, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Swift, OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_SymType &Tag) { - switch (Tag) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Exe, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Compiland, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandDetails, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandEnv, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Function, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Block, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Data, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Annotation, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Label, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PublicSymbol, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UDT, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Enum, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionSig, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PointerType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ArrayType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BuiltinType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Typedef, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseClass, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Friend, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionArg, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugStart, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugEnd, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UsingNamespace, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTableShape, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTable, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Custom, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Thunk, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CustomType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ManagedType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Dimension, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CallSite, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, InlineSite, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseInterface, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VectorType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, MatrixType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HLSLType, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Caller, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Callee, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Export, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HeapAllocationSite, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CoffGroup, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Inlinee, OS) - default: - OS << "Unknown SymTag " << uint32_t(Tag); - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_MemberAccess &Access) { - switch (Access) { - CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Public, "public", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Protected, "protected", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Private, "private", OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) { - switch (Type) { - CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Struct, "struct", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Interface, "interface", OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Union, "union", OS) - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const PDB_Machine &Machine) { - switch (Machine) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Am33, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Amd64, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Arm, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, ArmNT, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ebc, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, x86, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ia64, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, M32R, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Mips16, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu16, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPC, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPCFP, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, R4000, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3DSP, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH4, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH5, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Thumb, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, WceMipsV2, OS) - default: - OS << "Unknown"; - } - return OS; -} - -raw_ostream &llvm::pdb::dumpPDBSourceCompression(raw_ostream &OS, - uint32_t Compression) { - switch (Compression) { - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, None, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, Huffman, OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, LZ, OS) - CASE_OUTPUT_ENUM_CLASS_STR(PDB_SourceCompression, RunLengthEncoded, "RLE", - OS) - CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, DotNet, OS) - default: - OS << "Unknown (" << Compression << ")"; - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) { - switch (Value.Type) { - case PDB_VariantType::Bool: - OS << (Value.Value.Bool ? "true" : "false"); - break; - case PDB_VariantType::Double: - OS << Value.Value.Double; - break; - case PDB_VariantType::Int16: - OS << Value.Value.Int16; - break; - case PDB_VariantType::Int32: - OS << Value.Value.Int32; - break; - case PDB_VariantType::Int64: - OS << Value.Value.Int64; - break; - case PDB_VariantType::Int8: - OS << static_cast<int>(Value.Value.Int8); - break; - case PDB_VariantType::Single: - OS << Value.Value.Single; - break; - case PDB_VariantType::UInt16: - OS << Value.Value.UInt16; - break; - case PDB_VariantType::UInt32: - OS << Value.Value.UInt32; - break; - case PDB_VariantType::UInt64: - OS << Value.Value.UInt64; - break; - case PDB_VariantType::UInt8: - OS << static_cast<unsigned>(Value.Value.UInt8); - break; - case PDB_VariantType::String: - OS << Value.Value.String; - break; - default: - OS << Value.Type; - } - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, - const VersionInfo &Version) { - OS << Version.Major << "." << Version.Minor << "." << Version.Build; - return OS; -} - -raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const TagStats &Stats) { - for (auto Tag : Stats) { - OS << Tag.first << ":" << Tag.second << " "; - } - return OS; -} +#define CV_REGISTERS_ARM64 +#define CV_REGISTER(name, val) \ + case codeview::RegisterId::name: \ + OS << #name; \ + return OS; +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_ARM64 + + default: + break; + } + } else { + switch (CpuReg.Reg) { +#define CV_REGISTERS_X86 +#define CV_REGISTER(name, val) \ + case codeview::RegisterId::name: \ + OS << #name; \ + return OS; +#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" +#undef CV_REGISTER +#undef CV_REGISTERS_X86 + + default: + break; + } + } + OS << static_cast<int>(CpuReg.Reg); + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) { + switch (Loc) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Static, "static", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, TLS, "tls", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRel, "regrel", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, ThisRel, "thisrel", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Enregistered, "register", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, BitField, "bitfield", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Slot, "slot", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, IlRel, "IL rel", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, MetaData, "metadata", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Constant, "constant", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRelAliasIndir, + "regrelaliasindir", OS) + default: + OS << "Unknown"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const codeview::ThunkOrdinal &Thunk) { + switch (Thunk) { + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, BranchIsland, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Pcode, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Standard, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, ThisAdjustor, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, TrampIncremental, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, UnknownLoad, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Vcall, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_Checksum &Checksum) { + switch (Checksum) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, None, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, MD5, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA1, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA256, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Lang &Lang) { + switch (Lang) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, C, OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_Lang, Cpp, "C++", OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Fortran, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Masm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Pascal, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Basic, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cobol, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Link, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtres, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtpgd, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, CSharp, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, VB, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, ILAsm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Java, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, JScript, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, MSIL, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, HLSL, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, D, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Swift, OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_SymType &Tag) { + switch (Tag) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Exe, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Compiland, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandDetails, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandEnv, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Function, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Block, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Data, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Annotation, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Label, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PublicSymbol, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UDT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Enum, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionSig, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PointerType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ArrayType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BuiltinType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Typedef, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseClass, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Friend, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionArg, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugStart, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugEnd, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UsingNamespace, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTableShape, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTable, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Custom, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Thunk, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CustomType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ManagedType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Dimension, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CallSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, InlineSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseInterface, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VectorType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, MatrixType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HLSLType, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Caller, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Callee, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Export, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HeapAllocationSite, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CoffGroup, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Inlinee, OS) + default: + OS << "Unknown SymTag " << uint32_t(Tag); + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_MemberAccess &Access) { + switch (Access) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Public, "public", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Protected, "protected", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Private, "private", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) { + switch (Type) { + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Struct, "struct", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Interface, "interface", OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Union, "union", OS) + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const PDB_Machine &Machine) { + switch (Machine) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Am33, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Amd64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Arm, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, ArmNT, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ebc, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, x86, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ia64, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, M32R, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Mips16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu16, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPC, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPCFP, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, R4000, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3DSP, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH4, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH5, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Thumb, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, WceMipsV2, OS) + default: + OS << "Unknown"; + } + return OS; +} + +raw_ostream &llvm::pdb::dumpPDBSourceCompression(raw_ostream &OS, + uint32_t Compression) { + switch (Compression) { + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, None, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, Huffman, OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, LZ, OS) + CASE_OUTPUT_ENUM_CLASS_STR(PDB_SourceCompression, RunLengthEncoded, "RLE", + OS) + CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, DotNet, OS) + default: + OS << "Unknown (" << Compression << ")"; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) { + switch (Value.Type) { + case PDB_VariantType::Bool: + OS << (Value.Value.Bool ? "true" : "false"); + break; + case PDB_VariantType::Double: + OS << Value.Value.Double; + break; + case PDB_VariantType::Int16: + OS << Value.Value.Int16; + break; + case PDB_VariantType::Int32: + OS << Value.Value.Int32; + break; + case PDB_VariantType::Int64: + OS << Value.Value.Int64; + break; + case PDB_VariantType::Int8: + OS << static_cast<int>(Value.Value.Int8); + break; + case PDB_VariantType::Single: + OS << Value.Value.Single; + break; + case PDB_VariantType::UInt16: + OS << Value.Value.UInt16; + break; + case PDB_VariantType::UInt32: + OS << Value.Value.UInt32; + break; + case PDB_VariantType::UInt64: + OS << Value.Value.UInt64; + break; + case PDB_VariantType::UInt8: + OS << static_cast<unsigned>(Value.Value.UInt8); + break; + case PDB_VariantType::String: + OS << Value.Value.String; + break; + default: + OS << Value.Type; + } + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, + const VersionInfo &Version) { + OS << Version.Major << "." << Version.Minor << "." << Version.Build; + return OS; +} + +raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const TagStats &Stats) { + for (auto Tag : Stats) { + OS << Tag.first << ":" << Tag.second << " "; + } + return OS; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp index d51091d809..76324b3577 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp @@ -1,39 +1,39 @@ //===- PDBInterfaceAnchors.h - defines class anchor functions ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// Class anchors are necessary per the LLVM Coding style guide, to ensure that -// the vtable is only generated in this object file, and not in every object +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Class anchors are necessary per the LLVM Coding style guide, to ensure that +// the vtable is only generated in this object file, and not in every object // file that includes the corresponding header. -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/IPDBDataStream.h" -#include "llvm/DebugInfo/PDB/IPDBFrameData.h" -#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" -#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/IPDBTable.h" - -using namespace llvm; -using namespace llvm::pdb; - -IPDBSession::~IPDBSession() = default; - -IPDBDataStream::~IPDBDataStream() = default; - -IPDBRawSymbol::~IPDBRawSymbol() = default; - -IPDBLineNumber::~IPDBLineNumber() = default; - -IPDBTable::~IPDBTable() = default; - -IPDBInjectedSource::~IPDBInjectedSource() = default; - -IPDBSectionContrib::~IPDBSectionContrib() = default; - -IPDBFrameData::~IPDBFrameData() = default; +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/IPDBDataStream.h" +#include "llvm/DebugInfo/PDB/IPDBFrameData.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBTable.h" + +using namespace llvm; +using namespace llvm::pdb; + +IPDBSession::~IPDBSession() = default; + +IPDBDataStream::~IPDBDataStream() = default; + +IPDBRawSymbol::~IPDBRawSymbol() = default; + +IPDBLineNumber::~IPDBLineNumber() = default; + +IPDBTable::~IPDBTable() = default; + +IPDBInjectedSource::~IPDBInjectedSource() = default; + +IPDBSectionContrib::~IPDBSectionContrib() = default; + +IPDBFrameData::~IPDBFrameData() = default; diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymDumper.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymDumper.cpp index 0956a32f4a..df87f64134 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymDumper.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymDumper.cpp @@ -1,146 +1,146 @@ -//===- PDBSymDumper.cpp - ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; -using namespace llvm::pdb; - -#define PDB_SYMDUMP_UNREACHABLE(Type) \ - if (RequireImpl) \ - llvm_unreachable("Attempt to dump " #Type " with no dump implementation"); - -PDBSymDumper::PDBSymDumper(bool ShouldRequireImpl) - : RequireImpl(ShouldRequireImpl) {} - -PDBSymDumper::~PDBSymDumper() = default; - -void PDBSymDumper::dump(const PDBSymbolAnnotation &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolAnnotation) -} - -void PDBSymDumper::dump(const PDBSymbolBlock &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolBlock) -} - -void PDBSymDumper::dump(const PDBSymbolCompiland &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompiland) -} - -void PDBSymDumper::dump(const PDBSymbolCompilandDetails &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandDetails) -} - -void PDBSymDumper::dump(const PDBSymbolCompilandEnv &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandEnv) -} - -void PDBSymDumper::dump(const PDBSymbolCustom &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolCustom) -} - -void PDBSymDumper::dump(const PDBSymbolData &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolData) -} - -void PDBSymDumper::dump(const PDBSymbolExe &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolExe) -} - -void PDBSymDumper::dump(const PDBSymbolFunc &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolFunc) -} - -void PDBSymDumper::dump(const PDBSymbolFuncDebugEnd &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugEnd) -} - -void PDBSymDumper::dump(const PDBSymbolFuncDebugStart &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugStart) -} - -void PDBSymDumper::dump(const PDBSymbolLabel &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolLabel) -} - -void PDBSymDumper::dump(const PDBSymbolPublicSymbol &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolPublicSymbol) -} - -void PDBSymDumper::dump(const PDBSymbolThunk &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolThunk) -} - -void PDBSymDumper::dump(const PDBSymbolTypeArray &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeArray) -} - -void PDBSymDumper::dump(const PDBSymbolTypeBaseClass &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBaseClass) -} - -void PDBSymDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBuiltin) -} - -void PDBSymDumper::dump(const PDBSymbolTypeCustom &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeCustom) -} - -void PDBSymDumper::dump(const PDBSymbolTypeDimension &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeDimension) -} - -void PDBSymDumper::dump(const PDBSymbolTypeEnum &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeEnum) -} - -void PDBSymDumper::dump(const PDBSymbolTypeFriend &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFriend) -} - -void PDBSymDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionArg) -} - -void PDBSymDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionSig) -} - -void PDBSymDumper::dump(const PDBSymbolTypeManaged &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeManaged) -} - -void PDBSymDumper::dump(const PDBSymbolTypePointer &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypePointer) -} - -void PDBSymDumper::dump(const PDBSymbolTypeTypedef &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeTypedef) -} - -void PDBSymDumper::dump(const PDBSymbolTypeUDT &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeUDT) -} - -void PDBSymDumper::dump(const PDBSymbolTypeVTable &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTable) -} - -void PDBSymDumper::dump(const PDBSymbolTypeVTableShape &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTableShape) -} - -void PDBSymDumper::dump(const PDBSymbolUnknown &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolUnknown) -} - -void PDBSymDumper::dump(const PDBSymbolUsingNamespace &Symbol) { - PDB_SYMDUMP_UNREACHABLE(PDBSymbolUsingNamespace) -} +//===- PDBSymDumper.cpp - ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; +using namespace llvm::pdb; + +#define PDB_SYMDUMP_UNREACHABLE(Type) \ + if (RequireImpl) \ + llvm_unreachable("Attempt to dump " #Type " with no dump implementation"); + +PDBSymDumper::PDBSymDumper(bool ShouldRequireImpl) + : RequireImpl(ShouldRequireImpl) {} + +PDBSymDumper::~PDBSymDumper() = default; + +void PDBSymDumper::dump(const PDBSymbolAnnotation &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolAnnotation) +} + +void PDBSymDumper::dump(const PDBSymbolBlock &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolBlock) +} + +void PDBSymDumper::dump(const PDBSymbolCompiland &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompiland) +} + +void PDBSymDumper::dump(const PDBSymbolCompilandDetails &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandDetails) +} + +void PDBSymDumper::dump(const PDBSymbolCompilandEnv &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandEnv) +} + +void PDBSymDumper::dump(const PDBSymbolCustom &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolCustom) +} + +void PDBSymDumper::dump(const PDBSymbolData &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolData) +} + +void PDBSymDumper::dump(const PDBSymbolExe &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolExe) +} + +void PDBSymDumper::dump(const PDBSymbolFunc &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFunc) +} + +void PDBSymDumper::dump(const PDBSymbolFuncDebugEnd &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugEnd) +} + +void PDBSymDumper::dump(const PDBSymbolFuncDebugStart &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugStart) +} + +void PDBSymDumper::dump(const PDBSymbolLabel &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolLabel) +} + +void PDBSymDumper::dump(const PDBSymbolPublicSymbol &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolPublicSymbol) +} + +void PDBSymDumper::dump(const PDBSymbolThunk &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolThunk) +} + +void PDBSymDumper::dump(const PDBSymbolTypeArray &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeArray) +} + +void PDBSymDumper::dump(const PDBSymbolTypeBaseClass &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBaseClass) +} + +void PDBSymDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBuiltin) +} + +void PDBSymDumper::dump(const PDBSymbolTypeCustom &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeCustom) +} + +void PDBSymDumper::dump(const PDBSymbolTypeDimension &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeDimension) +} + +void PDBSymDumper::dump(const PDBSymbolTypeEnum &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeEnum) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFriend &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFriend) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionArg) +} + +void PDBSymDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionSig) +} + +void PDBSymDumper::dump(const PDBSymbolTypeManaged &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeManaged) +} + +void PDBSymDumper::dump(const PDBSymbolTypePointer &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypePointer) +} + +void PDBSymDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeTypedef) +} + +void PDBSymDumper::dump(const PDBSymbolTypeUDT &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeUDT) +} + +void PDBSymDumper::dump(const PDBSymbolTypeVTable &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTable) +} + +void PDBSymDumper::dump(const PDBSymbolTypeVTableShape &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTableShape) +} + +void PDBSymDumper::dump(const PDBSymbolUnknown &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolUnknown) +} + +void PDBSymDumper::dump(const PDBSymbolUsingNamespace &Symbol) { + PDB_SYMDUMP_UNREACHABLE(PDBSymbolUsingNamespace) +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbol.cpp index d6bc7ee9c9..77e3c284ef 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -1,175 +1,175 @@ -//===- PDBSymbol.cpp - base class for user-facing symbol types --*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" -#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" -#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" -#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" -#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" -#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" -#include <algorithm> -#include <memory> - -using namespace llvm; -using namespace llvm::pdb; - -PDBSymbol::PDBSymbol(const IPDBSession &PDBSession) : Session(PDBSession) {} - -PDBSymbol::PDBSymbol(PDBSymbol &&Other) - : Session(Other.Session), RawSymbol(std::move(Other.RawSymbol)) {} - -PDBSymbol::~PDBSymbol() = default; - -#define FACTORY_SYMTAG_CASE(Tag, Type) \ - case PDB_SymType::Tag: \ - return std::unique_ptr<PDBSymbol>(new Type(PDBSession)); - -std::unique_ptr<PDBSymbol> -PDBSymbol::createSymbol(const IPDBSession &PDBSession, PDB_SymType Tag) { - switch (Tag) { - FACTORY_SYMTAG_CASE(Exe, PDBSymbolExe) - FACTORY_SYMTAG_CASE(Compiland, PDBSymbolCompiland) - FACTORY_SYMTAG_CASE(CompilandDetails, PDBSymbolCompilandDetails) - FACTORY_SYMTAG_CASE(CompilandEnv, PDBSymbolCompilandEnv) - FACTORY_SYMTAG_CASE(Function, PDBSymbolFunc) - FACTORY_SYMTAG_CASE(Block, PDBSymbolBlock) - FACTORY_SYMTAG_CASE(Data, PDBSymbolData) - FACTORY_SYMTAG_CASE(Annotation, PDBSymbolAnnotation) - FACTORY_SYMTAG_CASE(Label, PDBSymbolLabel) - FACTORY_SYMTAG_CASE(PublicSymbol, PDBSymbolPublicSymbol) - FACTORY_SYMTAG_CASE(UDT, PDBSymbolTypeUDT) - FACTORY_SYMTAG_CASE(Enum, PDBSymbolTypeEnum) - FACTORY_SYMTAG_CASE(FunctionSig, PDBSymbolTypeFunctionSig) - FACTORY_SYMTAG_CASE(PointerType, PDBSymbolTypePointer) - FACTORY_SYMTAG_CASE(ArrayType, PDBSymbolTypeArray) - FACTORY_SYMTAG_CASE(BuiltinType, PDBSymbolTypeBuiltin) - FACTORY_SYMTAG_CASE(Typedef, PDBSymbolTypeTypedef) - FACTORY_SYMTAG_CASE(BaseClass, PDBSymbolTypeBaseClass) - FACTORY_SYMTAG_CASE(Friend, PDBSymbolTypeFriend) - FACTORY_SYMTAG_CASE(FunctionArg, PDBSymbolTypeFunctionArg) - FACTORY_SYMTAG_CASE(FuncDebugStart, PDBSymbolFuncDebugStart) - FACTORY_SYMTAG_CASE(FuncDebugEnd, PDBSymbolFuncDebugEnd) - FACTORY_SYMTAG_CASE(UsingNamespace, PDBSymbolUsingNamespace) - FACTORY_SYMTAG_CASE(VTableShape, PDBSymbolTypeVTableShape) - FACTORY_SYMTAG_CASE(VTable, PDBSymbolTypeVTable) - FACTORY_SYMTAG_CASE(Custom, PDBSymbolCustom) - FACTORY_SYMTAG_CASE(Thunk, PDBSymbolThunk) - FACTORY_SYMTAG_CASE(CustomType, PDBSymbolTypeCustom) - FACTORY_SYMTAG_CASE(ManagedType, PDBSymbolTypeManaged) - FACTORY_SYMTAG_CASE(Dimension, PDBSymbolTypeDimension) - default: - return std::unique_ptr<PDBSymbol>(new PDBSymbolUnknown(PDBSession)); - } -} - -std::unique_ptr<PDBSymbol> -PDBSymbol::create(const IPDBSession &PDBSession, - std::unique_ptr<IPDBRawSymbol> RawSymbol) { - auto SymbolPtr = createSymbol(PDBSession, RawSymbol->getSymTag()); - SymbolPtr->RawSymbol = RawSymbol.get(); - SymbolPtr->OwnedRawSymbol = std::move(RawSymbol); - return SymbolPtr; -} - -std::unique_ptr<PDBSymbol> PDBSymbol::create(const IPDBSession &PDBSession, - IPDBRawSymbol &RawSymbol) { - auto SymbolPtr = createSymbol(PDBSession, RawSymbol.getSymTag()); - SymbolPtr->RawSymbol = &RawSymbol; - return SymbolPtr; -} - -void PDBSymbol::defaultDump(raw_ostream &OS, int Indent, - PdbSymbolIdField ShowFlags, - PdbSymbolIdField RecurseFlags) const { - RawSymbol->dump(OS, Indent, ShowFlags, RecurseFlags); -} - -void PDBSymbol::dumpProperties() const { - outs() << "\n"; - defaultDump(outs(), 0, PdbSymbolIdField::All, PdbSymbolIdField::None); - outs().flush(); -} - -void PDBSymbol::dumpChildStats() const { - TagStats Stats; - getChildStats(Stats); - outs() << "\n"; - for (auto &Stat : Stats) { - outs() << Stat.first << ": " << Stat.second << "\n"; - } - outs().flush(); -} - -PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); } -uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); } - -std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findAllChildren() const { - return findAllChildren(PDB_SymType::None); -} - -std::unique_ptr<IPDBEnumSymbols> -PDBSymbol::findAllChildren(PDB_SymType Type) const { - return RawSymbol->findChildren(Type); -} - -std::unique_ptr<IPDBEnumSymbols> -PDBSymbol::findChildren(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags) const { - return RawSymbol->findChildren(Type, Name, Flags); -} - -std::unique_ptr<IPDBEnumSymbols> -PDBSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, - PDB_NameSearchFlags Flags, uint32_t RVA) const { - return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA); -} - -std::unique_ptr<IPDBEnumSymbols> +//===- PDBSymbol.cpp - base class for user-facing symbol types --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include <algorithm> +#include <memory> + +using namespace llvm; +using namespace llvm::pdb; + +PDBSymbol::PDBSymbol(const IPDBSession &PDBSession) : Session(PDBSession) {} + +PDBSymbol::PDBSymbol(PDBSymbol &&Other) + : Session(Other.Session), RawSymbol(std::move(Other.RawSymbol)) {} + +PDBSymbol::~PDBSymbol() = default; + +#define FACTORY_SYMTAG_CASE(Tag, Type) \ + case PDB_SymType::Tag: \ + return std::unique_ptr<PDBSymbol>(new Type(PDBSession)); + +std::unique_ptr<PDBSymbol> +PDBSymbol::createSymbol(const IPDBSession &PDBSession, PDB_SymType Tag) { + switch (Tag) { + FACTORY_SYMTAG_CASE(Exe, PDBSymbolExe) + FACTORY_SYMTAG_CASE(Compiland, PDBSymbolCompiland) + FACTORY_SYMTAG_CASE(CompilandDetails, PDBSymbolCompilandDetails) + FACTORY_SYMTAG_CASE(CompilandEnv, PDBSymbolCompilandEnv) + FACTORY_SYMTAG_CASE(Function, PDBSymbolFunc) + FACTORY_SYMTAG_CASE(Block, PDBSymbolBlock) + FACTORY_SYMTAG_CASE(Data, PDBSymbolData) + FACTORY_SYMTAG_CASE(Annotation, PDBSymbolAnnotation) + FACTORY_SYMTAG_CASE(Label, PDBSymbolLabel) + FACTORY_SYMTAG_CASE(PublicSymbol, PDBSymbolPublicSymbol) + FACTORY_SYMTAG_CASE(UDT, PDBSymbolTypeUDT) + FACTORY_SYMTAG_CASE(Enum, PDBSymbolTypeEnum) + FACTORY_SYMTAG_CASE(FunctionSig, PDBSymbolTypeFunctionSig) + FACTORY_SYMTAG_CASE(PointerType, PDBSymbolTypePointer) + FACTORY_SYMTAG_CASE(ArrayType, PDBSymbolTypeArray) + FACTORY_SYMTAG_CASE(BuiltinType, PDBSymbolTypeBuiltin) + FACTORY_SYMTAG_CASE(Typedef, PDBSymbolTypeTypedef) + FACTORY_SYMTAG_CASE(BaseClass, PDBSymbolTypeBaseClass) + FACTORY_SYMTAG_CASE(Friend, PDBSymbolTypeFriend) + FACTORY_SYMTAG_CASE(FunctionArg, PDBSymbolTypeFunctionArg) + FACTORY_SYMTAG_CASE(FuncDebugStart, PDBSymbolFuncDebugStart) + FACTORY_SYMTAG_CASE(FuncDebugEnd, PDBSymbolFuncDebugEnd) + FACTORY_SYMTAG_CASE(UsingNamespace, PDBSymbolUsingNamespace) + FACTORY_SYMTAG_CASE(VTableShape, PDBSymbolTypeVTableShape) + FACTORY_SYMTAG_CASE(VTable, PDBSymbolTypeVTable) + FACTORY_SYMTAG_CASE(Custom, PDBSymbolCustom) + FACTORY_SYMTAG_CASE(Thunk, PDBSymbolThunk) + FACTORY_SYMTAG_CASE(CustomType, PDBSymbolTypeCustom) + FACTORY_SYMTAG_CASE(ManagedType, PDBSymbolTypeManaged) + FACTORY_SYMTAG_CASE(Dimension, PDBSymbolTypeDimension) + default: + return std::unique_ptr<PDBSymbol>(new PDBSymbolUnknown(PDBSession)); + } +} + +std::unique_ptr<PDBSymbol> +PDBSymbol::create(const IPDBSession &PDBSession, + std::unique_ptr<IPDBRawSymbol> RawSymbol) { + auto SymbolPtr = createSymbol(PDBSession, RawSymbol->getSymTag()); + SymbolPtr->RawSymbol = RawSymbol.get(); + SymbolPtr->OwnedRawSymbol = std::move(RawSymbol); + return SymbolPtr; +} + +std::unique_ptr<PDBSymbol> PDBSymbol::create(const IPDBSession &PDBSession, + IPDBRawSymbol &RawSymbol) { + auto SymbolPtr = createSymbol(PDBSession, RawSymbol.getSymTag()); + SymbolPtr->RawSymbol = &RawSymbol; + return SymbolPtr; +} + +void PDBSymbol::defaultDump(raw_ostream &OS, int Indent, + PdbSymbolIdField ShowFlags, + PdbSymbolIdField RecurseFlags) const { + RawSymbol->dump(OS, Indent, ShowFlags, RecurseFlags); +} + +void PDBSymbol::dumpProperties() const { + outs() << "\n"; + defaultDump(outs(), 0, PdbSymbolIdField::All, PdbSymbolIdField::None); + outs().flush(); +} + +void PDBSymbol::dumpChildStats() const { + TagStats Stats; + getChildStats(Stats); + outs() << "\n"; + for (auto &Stat : Stats) { + outs() << Stat.first << ": " << Stat.second << "\n"; + } + outs().flush(); +} + +PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); } +uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); } + +std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findAllChildren() const { + return findAllChildren(PDB_SymType::None); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findAllChildren(PDB_SymType Type) const { + return RawSymbol->findChildren(Type); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findChildren(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags) const { + return RawSymbol->findChildren(Type, Name, Flags); +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name, + PDB_NameSearchFlags Flags, uint32_t RVA) const { + return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA); +} + +std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findInlineFramesByVA(uint64_t VA) const { return RawSymbol->findInlineFramesByVA(VA); } std::unique_ptr<IPDBEnumSymbols> -PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { - return RawSymbol->findInlineFramesByRVA(RVA); -} - +PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { + return RawSymbol->findInlineFramesByRVA(RVA); +} + std::unique_ptr<IPDBEnumLineNumbers> PDBSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const { return RawSymbol->findInlineeLinesByVA(VA, Length); @@ -182,50 +182,50 @@ PDBSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const { std::string PDBSymbol::getName() const { return RawSymbol->getName(); } -std::unique_ptr<IPDBEnumSymbols> -PDBSymbol::getChildStats(TagStats &Stats) const { - std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren()); - if (!Result) - return nullptr; - Stats.clear(); - while (auto Child = Result->getNext()) { - ++Stats[Child->getSymTag()]; - } - Result->reset(); - return Result; -} - -std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const { - return Session.getSymbolById(Id); -} - -void llvm::pdb::dumpSymbolIdField(raw_ostream &OS, StringRef Name, - SymIndexId Value, int Indent, - const IPDBSession &Session, - PdbSymbolIdField FieldId, - PdbSymbolIdField ShowFlags, - PdbSymbolIdField RecurseFlags) { - if ((FieldId & ShowFlags) == PdbSymbolIdField::None) - return; - - OS << "\n"; - OS.indent(Indent); - OS << Name << ": " << Value; - // Don't recurse unless the user requested it. - if ((FieldId & RecurseFlags) == PdbSymbolIdField::None) - return; - // And obviously don't recurse on the symbol itself. - if (FieldId == PdbSymbolIdField::SymIndexId) - return; - - auto Child = Session.getSymbolById(Value); - - // It could have been a placeholder symbol for a type we don't yet support, - // so just exit in that case. - if (!Child) - return; - - // Don't recurse more than once, so pass PdbSymbolIdField::None) for the - // recurse flags. - Child->defaultDump(OS, Indent + 2, ShowFlags, PdbSymbolIdField::None); -} +std::unique_ptr<IPDBEnumSymbols> +PDBSymbol::getChildStats(TagStats &Stats) const { + std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren()); + if (!Result) + return nullptr; + Stats.clear(); + while (auto Child = Result->getNext()) { + ++Stats[Child->getSymTag()]; + } + Result->reset(); + return Result; +} + +std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const { + return Session.getSymbolById(Id); +} + +void llvm::pdb::dumpSymbolIdField(raw_ostream &OS, StringRef Name, + SymIndexId Value, int Indent, + const IPDBSession &Session, + PdbSymbolIdField FieldId, + PdbSymbolIdField ShowFlags, + PdbSymbolIdField RecurseFlags) { + if ((FieldId & ShowFlags) == PdbSymbolIdField::None) + return; + + OS << "\n"; + OS.indent(Indent); + OS << Name << ": " << Value; + // Don't recurse unless the user requested it. + if ((FieldId & RecurseFlags) == PdbSymbolIdField::None) + return; + // And obviously don't recurse on the symbol itself. + if (FieldId == PdbSymbolIdField::SymIndexId) + return; + + auto Child = Session.getSymbolById(Value); + + // It could have been a placeholder symbol for a type we don't yet support, + // so just exit in that case. + if (!Child) + return; + + // Don't recurse more than once, so pass PdbSymbolIdField::None) for the + // recurse flags. + Child->defaultDump(OS, Indent + 2, ShowFlags, PdbSymbolIdField::None); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp index 0fa83efb7a..a9df1b387e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp @@ -1,20 +1,20 @@ -//===- PDBSymbolAnnotation.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolAnnotation::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolAnnotation.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolAnnotation::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolBlock.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolBlock.cpp index 9452282a88..97eb8970a2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolBlock.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolBlock.cpp @@ -1,19 +1,19 @@ -//===- PDBSymbolBlock.cpp - -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolBlock::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolBlock.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolBlock::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp index 9b28835463..db2fc404ac 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp @@ -1,109 +1,109 @@ -//===- PDBSymbolCompiland.cpp - compiland details ---------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" - -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Path.h" -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} - -std::string PDBSymbolCompiland::getSourceFileName() const { - return sys::path::filename(getSourceFileFullPath()).str(); -} - -std::string PDBSymbolCompiland::getSourceFileFullPath() const { - std::string SourceFileFullPath; - - // RecordedResult could be the basename, relative path or full path of the - // source file. Usually it is retrieved and recorded from the command that - // compiles this compiland. - // - // cmd FileName -> RecordedResult = .\\FileName - // cmd (Path)\\FileName -> RecordedResult = (Path)\\FileName - // - std::string RecordedResult = RawSymbol->getSourceFileName(); - - if (RecordedResult.empty()) { - if (auto Envs = findAllChildren<PDBSymbolCompilandEnv>()) { - std::string EnvWorkingDir, EnvSrc; - - while (auto Env = Envs->getNext()) { - std::string Var = Env->getName(); - if (Var == "cwd") { - EnvWorkingDir = Env->getValue(); - continue; - } - if (Var == "src") { - EnvSrc = Env->getValue(); - if (sys::path::is_absolute(EnvSrc)) - return EnvSrc; - RecordedResult = EnvSrc; - continue; - } - } - if (!EnvWorkingDir.empty() && !EnvSrc.empty()) { - auto Len = EnvWorkingDir.length(); - if (EnvWorkingDir[Len - 1] != '/' && EnvWorkingDir[Len - 1] != '\\') { - std::string Path = EnvWorkingDir + "\\" + EnvSrc; - std::replace(Path.begin(), Path.end(), '/', '\\'); - // We will return it as full path if we can't find a better one. - if (sys::path::is_absolute(Path)) - SourceFileFullPath = Path; - } - } - } - } - - if (!RecordedResult.empty()) { - if (sys::path::is_absolute(RecordedResult)) - return RecordedResult; - - // This searches name that has same basename as the one in RecordedResult. - auto OneSrcFile = Session.findOneSourceFile( - this, RecordedResult, PDB_NameSearchFlags::NS_CaseInsensitive); - if (OneSrcFile) - return OneSrcFile->getFileName(); - } - - // At this point, we have to walk through all source files of this compiland, - // and determine the right source file if any that is used to generate this - // compiland based on language indicated in compilanddetails language field. - auto Details = findOneChild<PDBSymbolCompilandDetails>(); - PDB_Lang Lang = Details ? Details->getLanguage() : PDB_Lang::Cpp; - auto SrcFiles = Session.getSourceFilesForCompiland(*this); - if (SrcFiles) { - while (auto File = SrcFiles->getNext()) { - std::string FileName = File->getFileName(); - auto file_extension = sys::path::extension(FileName); - if (StringSwitch<bool>(file_extension.lower()) - .Case(".cpp", Lang == PDB_Lang::Cpp) - .Case(".cc", Lang == PDB_Lang::Cpp) - .Case(".cxx", Lang == PDB_Lang::Cpp) - .Case(".c", Lang == PDB_Lang::C) - .Case(".asm", Lang == PDB_Lang::Masm) - .Case(".swift", Lang == PDB_Lang::Swift) - .Default(false)) - return File->getFileName(); - } - } - - return SourceFileFullPath; -} +//===- PDBSymbolCompiland.cpp - compiland details ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Path.h" +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +std::string PDBSymbolCompiland::getSourceFileName() const { + return sys::path::filename(getSourceFileFullPath()).str(); +} + +std::string PDBSymbolCompiland::getSourceFileFullPath() const { + std::string SourceFileFullPath; + + // RecordedResult could be the basename, relative path or full path of the + // source file. Usually it is retrieved and recorded from the command that + // compiles this compiland. + // + // cmd FileName -> RecordedResult = .\\FileName + // cmd (Path)\\FileName -> RecordedResult = (Path)\\FileName + // + std::string RecordedResult = RawSymbol->getSourceFileName(); + + if (RecordedResult.empty()) { + if (auto Envs = findAllChildren<PDBSymbolCompilandEnv>()) { + std::string EnvWorkingDir, EnvSrc; + + while (auto Env = Envs->getNext()) { + std::string Var = Env->getName(); + if (Var == "cwd") { + EnvWorkingDir = Env->getValue(); + continue; + } + if (Var == "src") { + EnvSrc = Env->getValue(); + if (sys::path::is_absolute(EnvSrc)) + return EnvSrc; + RecordedResult = EnvSrc; + continue; + } + } + if (!EnvWorkingDir.empty() && !EnvSrc.empty()) { + auto Len = EnvWorkingDir.length(); + if (EnvWorkingDir[Len - 1] != '/' && EnvWorkingDir[Len - 1] != '\\') { + std::string Path = EnvWorkingDir + "\\" + EnvSrc; + std::replace(Path.begin(), Path.end(), '/', '\\'); + // We will return it as full path if we can't find a better one. + if (sys::path::is_absolute(Path)) + SourceFileFullPath = Path; + } + } + } + } + + if (!RecordedResult.empty()) { + if (sys::path::is_absolute(RecordedResult)) + return RecordedResult; + + // This searches name that has same basename as the one in RecordedResult. + auto OneSrcFile = Session.findOneSourceFile( + this, RecordedResult, PDB_NameSearchFlags::NS_CaseInsensitive); + if (OneSrcFile) + return OneSrcFile->getFileName(); + } + + // At this point, we have to walk through all source files of this compiland, + // and determine the right source file if any that is used to generate this + // compiland based on language indicated in compilanddetails language field. + auto Details = findOneChild<PDBSymbolCompilandDetails>(); + PDB_Lang Lang = Details ? Details->getLanguage() : PDB_Lang::Cpp; + auto SrcFiles = Session.getSourceFilesForCompiland(*this); + if (SrcFiles) { + while (auto File = SrcFiles->getNext()) { + std::string FileName = File->getFileName(); + auto file_extension = sys::path::extension(FileName); + if (StringSwitch<bool>(file_extension.lower()) + .Case(".cpp", Lang == PDB_Lang::Cpp) + .Case(".cc", Lang == PDB_Lang::Cpp) + .Case(".cxx", Lang == PDB_Lang::Cpp) + .Case(".c", Lang == PDB_Lang::C) + .Case(".asm", Lang == PDB_Lang::Masm) + .Case(".swift", Lang == PDB_Lang::Swift) + .Default(false)) + return File->getFileName(); + } + } + + return SourceFileFullPath; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp index 0d86dfe1e6..6fc1dbaece 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolCompilandDetails.cpp - compiland details --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolCompilandDetails::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolCompilandDetails.cpp - compiland details --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolCompilandDetails::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp index 61f119405f..bfb0df0cd9 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp @@ -1,29 +1,29 @@ -//===- PDBSymbolCompilandEnv.cpp - compiland env variables ------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" - -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -std::string PDBSymbolCompilandEnv::getValue() const { - Variant Value = RawSymbol->getValue(); - if (Value.Type != PDB_VariantType::String) - return std::string(); - return std::string(Value.Value.String); -} - -void PDBSymbolCompilandEnv::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolCompilandEnv.cpp - compiland env variables ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h" + +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +std::string PDBSymbolCompilandEnv::getValue() const { + Variant Value = RawSymbol->getValue(); + if (Value.Type != PDB_VariantType::String) + return std::string(); + return std::string(Value.Value.String); +} + +void PDBSymbolCompilandEnv::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCustom.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCustom.cpp index 6c9a4aa76c..ccedff48a4 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCustom.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolCustom.cpp @@ -1,24 +1,24 @@ -//===- PDBSymbolCustom.cpp - compiler-specific types ------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" - -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolCustom::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) { - RawSymbol->getDataBytes(bytes); -} - -void PDBSymbolCustom::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolCustom.cpp - compiler-specific types ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h" + +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolCustom::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) { + RawSymbol->getDataBytes(bytes); +} + +void PDBSymbolCustom::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolData.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolData.cpp index d2b82111cc..8036765f1a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolData.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolData.cpp @@ -1,68 +1,68 @@ -//===- PDBSymbolData.cpp - PDB data (e.g. variable) accessors ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolData::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } - -std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolData::getLineNumbers() const { - auto Len = RawSymbol->getLength(); - Len = Len ? Len : 1; - if (auto RVA = RawSymbol->getRelativeVirtualAddress()) - return Session.findLineNumbersByRVA(RVA, Len); - - if (auto Section = RawSymbol->getAddressSection()) - return Session.findLineNumbersBySectOffset( - Section, RawSymbol->getAddressOffset(), Len); - - return nullptr; -} - -uint32_t PDBSymbolData::getCompilandId() const { - if (auto Lines = getLineNumbers()) { - if (auto FirstLine = Lines->getNext()) - return FirstLine->getCompilandId(); - } - - uint32_t DataSection = RawSymbol->getAddressSection(); - uint32_t DataOffset = RawSymbol->getAddressOffset(); - if (DataSection == 0) { - if (auto RVA = RawSymbol->getRelativeVirtualAddress()) - Session.addressForRVA(RVA, DataSection, DataOffset); - } - - if (DataSection) { - if (auto SecContribs = Session.getSectionContribs()) { - while (auto Section = SecContribs->getNext()) { - if (Section->getAddressSection() == DataSection && - Section->getAddressOffset() <= DataOffset && - (Section->getAddressOffset() + Section->getLength()) > DataOffset) - return Section->getCompilandId(); - } - } - } else { - auto LexParentId = RawSymbol->getLexicalParentId(); - while (auto LexParent = Session.getSymbolById(LexParentId)) { - if (LexParent->getSymTag() == PDB_SymType::Exe) - break; - if (LexParent->getSymTag() == PDB_SymType::Compiland) - return LexParentId; - LexParentId = LexParent->getRawSymbol().getLexicalParentId(); - } - } - - return 0; -} +//===- PDBSymbolData.cpp - PDB data (e.g. variable) accessors ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolData::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolData::getLineNumbers() const { + auto Len = RawSymbol->getLength(); + Len = Len ? Len : 1; + if (auto RVA = RawSymbol->getRelativeVirtualAddress()) + return Session.findLineNumbersByRVA(RVA, Len); + + if (auto Section = RawSymbol->getAddressSection()) + return Session.findLineNumbersBySectOffset( + Section, RawSymbol->getAddressOffset(), Len); + + return nullptr; +} + +uint32_t PDBSymbolData::getCompilandId() const { + if (auto Lines = getLineNumbers()) { + if (auto FirstLine = Lines->getNext()) + return FirstLine->getCompilandId(); + } + + uint32_t DataSection = RawSymbol->getAddressSection(); + uint32_t DataOffset = RawSymbol->getAddressOffset(); + if (DataSection == 0) { + if (auto RVA = RawSymbol->getRelativeVirtualAddress()) + Session.addressForRVA(RVA, DataSection, DataOffset); + } + + if (DataSection) { + if (auto SecContribs = Session.getSectionContribs()) { + while (auto Section = SecContribs->getNext()) { + if (Section->getAddressSection() == DataSection && + Section->getAddressOffset() <= DataOffset && + (Section->getAddressOffset() + Section->getLength()) > DataOffset) + return Section->getCompilandId(); + } + } + } else { + auto LexParentId = RawSymbol->getLexicalParentId(); + while (auto LexParent = Session.getSymbolById(LexParentId)) { + if (LexParent->getSymTag() == PDB_SymType::Exe) + break; + if (LexParent->getSymTag() == PDB_SymType::Compiland) + return LexParentId; + LexParentId = LexParent->getRawSymbol().getLexicalParentId(); + } + } + + return 0; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolExe.cpp index c85756c43e..042fd6ef73 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolExe.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolExe.cpp @@ -1,29 +1,29 @@ -//===- PDBSymbolExe.cpp - ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } - -uint32_t PDBSymbolExe::getPointerByteSize() const { - auto Pointer = findOneChild<PDBSymbolTypePointer>(); - if (Pointer) - return Pointer->getLength(); - - if (getMachineType() == PDB_Machine::x86) - return 4; - return 8; -} +//===- PDBSymbolExe.cpp - ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +uint32_t PDBSymbolExe::getPointerByteSize() const { + auto Pointer = findOneChild<PDBSymbolTypePointer>(); + if (Pointer) + return Pointer->getLength(); + + if (getMachineType() == PDB_Machine::x86) + return 4; + return 8; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFunc.cpp index cb0329bc0e..a191a03a02 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFunc.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFunc.cpp @@ -1,111 +1,111 @@ -//===- PDBSymbolFunc.cpp - --------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" - -#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" - -#include <unordered_set> -#include <utility> -#include <vector> - -using namespace llvm; -using namespace llvm::pdb; - -namespace { -class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> { -public: - typedef ConcreteSymbolEnumerator<PDBSymbolData> ArgEnumeratorType; - - FunctionArgEnumerator(const IPDBSession &PDBSession, - const PDBSymbolFunc &PDBFunc) - : Session(PDBSession), Func(PDBFunc) { - // Arguments can appear multiple times if they have live range - // information, so we only take the first occurrence. - std::unordered_set<std::string> SeenNames; - auto DataChildren = Func.findAllChildren<PDBSymbolData>(); - while (auto Child = DataChildren->getNext()) { - if (Child->getDataKind() == PDB_DataKind::Param) { - std::string Name = Child->getName(); - if (SeenNames.find(Name) != SeenNames.end()) - continue; - Args.push_back(std::move(Child)); - SeenNames.insert(Name); - } - } - reset(); - } - - uint32_t getChildCount() const override { return Args.size(); } - - std::unique_ptr<PDBSymbolData> - getChildAtIndex(uint32_t Index) const override { - if (Index >= Args.size()) - return nullptr; - - return Session.getConcreteSymbolById<PDBSymbolData>( - Args[Index]->getSymIndexId()); - } - - std::unique_ptr<PDBSymbolData> getNext() override { - if (CurIter == Args.end()) - return nullptr; - const auto &Result = **CurIter; - ++CurIter; - return Session.getConcreteSymbolById<PDBSymbolData>(Result.getSymIndexId()); - } - - void reset() override { CurIter = Args.empty() ? Args.end() : Args.begin(); } - -private: - typedef std::vector<std::unique_ptr<PDBSymbolData>> ArgListType; - const IPDBSession &Session; - const PDBSymbolFunc &Func; - ArgListType Args; - ArgListType::const_iterator CurIter; -}; -} - -std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> -PDBSymbolFunc::getArguments() const { - return std::make_unique<FunctionArgEnumerator>(Session, *this); -} - -void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } - -bool PDBSymbolFunc::isDestructor() const { - std::string Name = getName(); - if (Name.empty()) - return false; - if (Name[0] == '~') - return true; - if (Name == "__vecDelDtor") - return true; - return false; -} - -std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolFunc::getLineNumbers() const { - auto Len = RawSymbol->getLength(); - return Session.findLineNumbersByAddress(RawSymbol->getVirtualAddress(), - Len ? Len : 1); -} - -uint32_t PDBSymbolFunc::getCompilandId() const { - if (auto Lines = getLineNumbers()) { - if (auto FirstLine = Lines->getNext()) { - return FirstLine->getCompilandId(); - } - } - return 0; -} +//===- PDBSymbolFunc.cpp - --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" + +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include <unordered_set> +#include <utility> +#include <vector> + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> { +public: + typedef ConcreteSymbolEnumerator<PDBSymbolData> ArgEnumeratorType; + + FunctionArgEnumerator(const IPDBSession &PDBSession, + const PDBSymbolFunc &PDBFunc) + : Session(PDBSession), Func(PDBFunc) { + // Arguments can appear multiple times if they have live range + // information, so we only take the first occurrence. + std::unordered_set<std::string> SeenNames; + auto DataChildren = Func.findAllChildren<PDBSymbolData>(); + while (auto Child = DataChildren->getNext()) { + if (Child->getDataKind() == PDB_DataKind::Param) { + std::string Name = Child->getName(); + if (SeenNames.find(Name) != SeenNames.end()) + continue; + Args.push_back(std::move(Child)); + SeenNames.insert(Name); + } + } + reset(); + } + + uint32_t getChildCount() const override { return Args.size(); } + + std::unique_ptr<PDBSymbolData> + getChildAtIndex(uint32_t Index) const override { + if (Index >= Args.size()) + return nullptr; + + return Session.getConcreteSymbolById<PDBSymbolData>( + Args[Index]->getSymIndexId()); + } + + std::unique_ptr<PDBSymbolData> getNext() override { + if (CurIter == Args.end()) + return nullptr; + const auto &Result = **CurIter; + ++CurIter; + return Session.getConcreteSymbolById<PDBSymbolData>(Result.getSymIndexId()); + } + + void reset() override { CurIter = Args.empty() ? Args.end() : Args.begin(); } + +private: + typedef std::vector<std::unique_ptr<PDBSymbolData>> ArgListType; + const IPDBSession &Session; + const PDBSymbolFunc &Func; + ArgListType Args; + ArgListType::const_iterator CurIter; +}; +} + +std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> +PDBSymbolFunc::getArguments() const { + return std::make_unique<FunctionArgEnumerator>(Session, *this); +} + +void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +bool PDBSymbolFunc::isDestructor() const { + std::string Name = getName(); + if (Name.empty()) + return false; + if (Name[0] == '~') + return true; + if (Name == "__vecDelDtor") + return true; + return false; +} + +std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolFunc::getLineNumbers() const { + auto Len = RawSymbol->getLength(); + return Session.findLineNumbersByAddress(RawSymbol->getVirtualAddress(), + Len ? Len : 1); +} + +uint32_t PDBSymbolFunc::getCompilandId() const { + if (auto Lines = getLineNumbers()) { + if (auto FirstLine = Lines->getNext()) { + return FirstLine->getCompilandId(); + } + } + return 0; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp index 66433dc17b..000be3331e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolFuncDebugEnd.cpp - ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolFuncDebugEnd::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolFuncDebugEnd.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolFuncDebugEnd::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp index fe32c93c01..fcda5edf68 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolFuncDebugStart.cpp - ----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolFuncDebugStart::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolFuncDebugStart.cpp - ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolFuncDebugStart::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolLabel.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolLabel.cpp index 1fffe69a0c..3c1bc27dd5 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolLabel.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolLabel.cpp @@ -1,18 +1,18 @@ -//===- PDBSymbolLabel.cpp - -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolLabel::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolLabel.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolLabel::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp index 08697683f6..239b06a765 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolPublicSymbol.cpp - ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolPublicSymbol::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolPublicSymbol.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolPublicSymbol::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolThunk.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolThunk.cpp index 6483858183..1f023654c2 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolThunk.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolThunk.cpp @@ -1,18 +1,18 @@ -//===- PDBSymbolThunk.cpp - -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolThunk::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolThunk.cpp - -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolThunk::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp index a0d521abe4..9d80db1370 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp @@ -1,24 +1,24 @@ -//===- PDBSymbolTypeArray.cpp - ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeArray::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} - -void PDBSymbolTypeArray::dumpRight(PDBSymDumper &Dumper) const { - Dumper.dumpRight(*this); -} +//===- PDBSymbolTypeArray.cpp - ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeArray::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +void PDBSymbolTypeArray::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp index 08467059b5..9fa5530160 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolTypeBaseClass.cpp - -----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeBaseClass::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeBaseClass.cpp - -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeBaseClass::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp index a0dd9ef601..f0adad48bf 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp @@ -1,20 +1,20 @@ -//===- PDBSymbolTypeBuiltin.cpp - ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeBuiltin::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeBuiltin.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeBuiltin::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp index 6723894c90..f68f6e0022 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolTypeCustom.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeCustom::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeCustom.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeCustom::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp index 4a25a391f2..910c158e97 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolTypeDimension.cpp - --------------------------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; -void PDBSymbolTypeDimension::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeDimension.cpp - --------------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; +void PDBSymbolTypeDimension::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp index b9fdf6aec8..b1de848ffb 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp @@ -1,19 +1,19 @@ -//===- PDBSymbolTypeEnum.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeEnum::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolTypeEnum.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeEnum::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp index 4ffea42cbb..db3279e407 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolTypeFriend.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeFriend::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeFriend.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeFriend::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp index 683e93548f..5a9531061c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp @@ -1,20 +1,20 @@ -//===- PDBSymbolTypeFunctionArg.cpp - --------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeFunctionArg::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeFunctionArg.cpp - --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeFunctionArg::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp index 1373615522..2d1e78711f 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp @@ -1,93 +1,93 @@ -//===- PDBSymbolTypeFunctionSig.cpp - --------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" - -#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -namespace { -class FunctionArgEnumerator : public IPDBEnumSymbols { -public: - typedef ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg> ArgEnumeratorType; - - FunctionArgEnumerator(const IPDBSession &PDBSession, - const PDBSymbolTypeFunctionSig &Sig) - : Session(PDBSession), - Enumerator(Sig.findAllChildren<PDBSymbolTypeFunctionArg>()) {} - - FunctionArgEnumerator(const IPDBSession &PDBSession, - std::unique_ptr<ArgEnumeratorType> ArgEnumerator) - : Session(PDBSession), Enumerator(std::move(ArgEnumerator)) {} - - uint32_t getChildCount() const override { - return Enumerator->getChildCount(); - } - - std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { - auto FunctionArgSymbol = Enumerator->getChildAtIndex(Index); - if (!FunctionArgSymbol) - return nullptr; - return Session.getSymbolById(FunctionArgSymbol->getTypeId()); - } - - std::unique_ptr<PDBSymbol> getNext() override { - auto FunctionArgSymbol = Enumerator->getNext(); - if (!FunctionArgSymbol) - return nullptr; - return Session.getSymbolById(FunctionArgSymbol->getTypeId()); - } - - void reset() override { Enumerator->reset(); } - -private: - const IPDBSession &Session; - std::unique_ptr<ArgEnumeratorType> Enumerator; -}; -} - -std::unique_ptr<IPDBEnumSymbols> -PDBSymbolTypeFunctionSig::getArguments() const { - return std::make_unique<FunctionArgEnumerator>(Session, *this); -} - -void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} - -void PDBSymbolTypeFunctionSig::dumpRight(PDBSymDumper &Dumper) const { - Dumper.dumpRight(*this); -} - -bool PDBSymbolTypeFunctionSig::isCVarArgs() const { - auto SigArguments = getArguments(); - if (!SigArguments) - return false; - uint32_t NumArgs = SigArguments->getChildCount(); - if (NumArgs == 0) - return false; - auto Last = SigArguments->getChildAtIndex(NumArgs - 1); - if (auto Builtin = llvm::dyn_cast_or_null<PDBSymbolTypeBuiltin>(Last.get())) { - if (Builtin->getBuiltinType() == PDB_BuiltinType::None) - return true; - } - - // Note that for a variadic template signature, this method always returns - // false since the parameters of the template are specialized. - return false; -} +//===- PDBSymbolTypeFunctionSig.cpp - --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" + +#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +class FunctionArgEnumerator : public IPDBEnumSymbols { +public: + typedef ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg> ArgEnumeratorType; + + FunctionArgEnumerator(const IPDBSession &PDBSession, + const PDBSymbolTypeFunctionSig &Sig) + : Session(PDBSession), + Enumerator(Sig.findAllChildren<PDBSymbolTypeFunctionArg>()) {} + + FunctionArgEnumerator(const IPDBSession &PDBSession, + std::unique_ptr<ArgEnumeratorType> ArgEnumerator) + : Session(PDBSession), Enumerator(std::move(ArgEnumerator)) {} + + uint32_t getChildCount() const override { + return Enumerator->getChildCount(); + } + + std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override { + auto FunctionArgSymbol = Enumerator->getChildAtIndex(Index); + if (!FunctionArgSymbol) + return nullptr; + return Session.getSymbolById(FunctionArgSymbol->getTypeId()); + } + + std::unique_ptr<PDBSymbol> getNext() override { + auto FunctionArgSymbol = Enumerator->getNext(); + if (!FunctionArgSymbol) + return nullptr; + return Session.getSymbolById(FunctionArgSymbol->getTypeId()); + } + + void reset() override { Enumerator->reset(); } + +private: + const IPDBSession &Session; + std::unique_ptr<ArgEnumeratorType> Enumerator; +}; +} + +std::unique_ptr<IPDBEnumSymbols> +PDBSymbolTypeFunctionSig::getArguments() const { + return std::make_unique<FunctionArgEnumerator>(Session, *this); +} + +void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +void PDBSymbolTypeFunctionSig::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} + +bool PDBSymbolTypeFunctionSig::isCVarArgs() const { + auto SigArguments = getArguments(); + if (!SigArguments) + return false; + uint32_t NumArgs = SigArguments->getChildCount(); + if (NumArgs == 0) + return false; + auto Last = SigArguments->getChildAtIndex(NumArgs - 1); + if (auto Builtin = llvm::dyn_cast_or_null<PDBSymbolTypeBuiltin>(Last.get())) { + if (Builtin->getBuiltinType() == PDB_BuiltinType::None) + return true; + } + + // Note that for a variadic template signature, this method always returns + // false since the parameters of the template are specialized. + return false; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp index e80e6c7165..8ac467e303 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp @@ -1,21 +1,21 @@ -//===- PDBSymboTypelManaged.cpp - ------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeManaged::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymboTypelManaged.cpp - ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeManaged::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp index 462fc31535..6cfc89a651 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp @@ -1,25 +1,25 @@ -//===- PDBSymbolTypePointer.cpp -----------------------------------*- C++ -===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypePointer::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} - -void PDBSymbolTypePointer::dumpRight(PDBSymDumper &Dumper) const { - Dumper.dumpRight(*this); -} +//===- PDBSymbolTypePointer.cpp -----------------------------------*- C++ -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypePointer::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} + +void PDBSymbolTypePointer::dumpRight(PDBSymDumper &Dumper) const { + Dumper.dumpRight(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp index 70749d9bf5..95627d053b 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp @@ -1,20 +1,20 @@ -//===- PDBSymbolTypeTypedef.cpp ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeTypedef::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeTypedef.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeTypedef::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp index d302c29a3b..91148f9569 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp @@ -1,25 +1,25 @@ -//===- PDBSymbolTypeUDT.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeUDT::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolTypeUDT.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeUDT::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp index 4e2a45116d..6764df7778 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp @@ -1,20 +1,20 @@ -//===- PDBSymbolTypeVTable.cpp - --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeVTable::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeVTable.cpp - --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeVTable::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp index 78957620e0..b3d34c997c 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolTypeVTableShape.cpp - ---------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolTypeVTableShape::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolTypeVTableShape.cpp - ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolTypeVTableShape::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp index 650d011831..ec557ff8c7 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp @@ -1,19 +1,19 @@ -//===- PDBSymbolUnknown.cpp - -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolUnknown::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } +//===- PDBSymbolUnknown.cpp - -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolUnknown::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp index 74afbdb180..f341d48ab0 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp @@ -1,21 +1,21 @@ -//===- PDBSymbolUsingNamespace.cpp - ------------------- --------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" - -#include <utility> - -using namespace llvm; -using namespace llvm::pdb; - -void PDBSymbolUsingNamespace::dump(PDBSymDumper &Dumper) const { - Dumper.dump(*this); -} +//===- PDBSymbolUsingNamespace.cpp - ------------------- --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" + +#include <utility> + +using namespace llvm; +using namespace llvm::pdb; + +void PDBSymbolUsingNamespace::dump(PDBSymDumper &Dumper) const { + Dumper.dump(*this); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/UDTLayout.cpp b/contrib/libs/llvm12/lib/DebugInfo/PDB/UDTLayout.cpp index 55854bb498..71d0c66794 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/UDTLayout.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/UDTLayout.cpp @@ -1,302 +1,302 @@ -//===- UDTLayout.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/PDB/UDTLayout.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/Support/Casting.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <memory> - -using namespace llvm; -using namespace llvm::pdb; - -static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) { - const IPDBSession &Session = Symbol.getSession(); - const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol(); - uint32_t TypeId = RawSymbol.getTypeId(); - return Session.getSymbolById(TypeId); -} - -static uint32_t getTypeLength(const PDBSymbol &Symbol) { - auto SymbolType = getSymbolType(Symbol); - const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); - - return RawType.getLength(); -} - -LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent, - const PDBSymbol *Symbol, const std::string &Name, - uint32_t OffsetInParent, uint32_t Size, - bool IsElided) - : Symbol(Symbol), Parent(Parent), Name(Name), - OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size), - IsElided(IsElided) { - UsedBytes.resize(SizeOf, true); -} - -uint32_t LayoutItemBase::deepPaddingSize() const { - return UsedBytes.size() - UsedBytes.count(); -} - -uint32_t LayoutItemBase::tailPadding() const { - int Last = UsedBytes.find_last(); - - return UsedBytes.size() - (Last + 1); -} - -DataMemberLayoutItem::DataMemberLayoutItem( - const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member) - : LayoutItemBase(&Parent, Member.get(), Member->getName(), - Member->getOffset(), getTypeLength(*Member), false), - DataMember(std::move(Member)) { - auto Type = DataMember->getType(); - if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { - UdtLayout = std::make_unique<ClassLayout>(std::move(UDT)); - UsedBytes = UdtLayout->usedBytes(); - } -} - -VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent, - std::unique_ptr<PDBSymbolTypeBuiltin> Sym, - uint32_t Offset, uint32_t Size) - : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false), - Type(std::move(Sym)) { -} - -const PDBSymbolData &DataMemberLayoutItem::getDataMember() { - return *cast<PDBSymbolData>(Symbol); -} - -bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } - -const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { - return *UdtLayout; -} - -VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, - std::unique_ptr<PDBSymbolTypeVTable> VT) - : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false), - VTable(std::move(VT)) { - auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType()); - ElementSize = VTableType->getLength(); -} - -UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, - const std::string &Name, uint32_t OffsetInParent, - uint32_t Size, bool IsElided) - : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) { - // UDT storage comes from a union of all the children's storage, so start out - // uninitialized. - UsedBytes.reset(0, Size); - - initializeChildren(Sym); - if (LayoutSize < Size) - UsedBytes.resize(LayoutSize); -} - -uint32_t UDTLayoutBase::tailPadding() const { - uint32_t Abs = LayoutItemBase::tailPadding(); - if (!LayoutItems.empty()) { - const LayoutItemBase *Back = LayoutItems.back(); - uint32_t ChildPadding = Back->LayoutItemBase::tailPadding(); - if (Abs < ChildPadding) - Abs = 0; - else - Abs -= ChildPadding; - } - return Abs; -} - -ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) - : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false), - UDT(UDT) { - ImmediateUsedBytes.resize(SizeOf, false); - for (auto &LI : LayoutItems) { - uint32_t Begin = LI->getOffsetInParent(); - uint32_t End = Begin + LI->getLayoutSize(); - End = std::min(SizeOf, End); - ImmediateUsedBytes.set(Begin, End); - } -} - -ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) - : ClassLayout(*UDT) { - OwnedStorage = std::move(UDT); -} - -uint32_t ClassLayout::immediatePadding() const { - return SizeOf - ImmediateUsedBytes.count(); -} - -BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, - uint32_t OffsetInParent, bool Elide, - std::unique_ptr<PDBSymbolTypeBaseClass> B) - : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(), - Elide), - Base(std::move(B)) { - if (isEmptyBase()) { - // Special case an empty base so that it doesn't get treated as padding. - UsedBytes.resize(1); - UsedBytes.set(0); - } - IsVirtualBase = Base->isVirtualBaseClass(); -} - -void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { - // Handled bases first, followed by VTables, followed by data members, - // followed by functions, followed by other. This ordering is necessary - // so that bases and vtables get initialized before any functions which - // may override them. - UniquePtrVector<PDBSymbolTypeBaseClass> Bases; - UniquePtrVector<PDBSymbolTypeVTable> VTables; - UniquePtrVector<PDBSymbolData> Members; - UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms; - - auto Children = Sym.findAllChildren(); - while (auto Child = Children->getNext()) { - if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { - if (Base->isVirtualBaseClass()) - VirtualBaseSyms.push_back(std::move(Base)); - else - Bases.push_back(std::move(Base)); - } - else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { - if (Data->getDataKind() == PDB_DataKind::Member) - Members.push_back(std::move(Data)); - else - Other.push_back(std::move(Data)); - } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) - VTables.push_back(std::move(VT)); - else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child)) - Funcs.push_back(std::move(Func)); - else { - Other.push_back(std::move(Child)); - } - } - - // We don't want to have any re-allocations in the list of bases, so make - // sure to reserve enough space so that our ArrayRefs don't get invalidated. - AllBases.reserve(Bases.size() + VirtualBaseSyms.size()); - - // Only add non-virtual bases to the class first. Only at the end of the - // class, after all non-virtual bases and data members have been added do we - // add virtual bases. This way the offsets are correctly aligned when we go - // to lay out virtual bases. - for (auto &Base : Bases) { - uint32_t Offset = Base->getOffset(); - // Non-virtual bases never get elided. - auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false, - std::move(Base)); - - AllBases.push_back(BL.get()); - addChildToLayout(std::move(BL)); - } - NonVirtualBases = AllBases; - - assert(VTables.size() <= 1); - if (!VTables.empty()) { - auto VTLayout = - std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0])); - - VTable = VTLayout.get(); - - addChildToLayout(std::move(VTLayout)); - } - - for (auto &Data : Members) { - auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); - - addChildToLayout(std::move(DM)); - } - - // Make sure add virtual bases before adding functions, since functions may be - // overrides of virtual functions declared in a virtual base, so the VTables - // and virtual intros need to be correctly initialized. - for (auto &VB : VirtualBaseSyms) { - int VBPO = VB->getVirtualBasePointerOffset(); - if (!hasVBPtrAtOffset(VBPO)) { - if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) { - auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP), - VBPO, VBP->getLength()); - VBPtr = VBPL.get(); - addChildToLayout(std::move(VBPL)); - } - } - - // Virtual bases always go at the end. So just look for the last place we - // ended when writing something, and put our virtual base there. - // Note that virtual bases get elided unless this is a top-most derived - // class. - uint32_t Offset = UsedBytes.find_last() + 1; - bool Elide = (Parent != nullptr); - auto BL = - std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB)); - AllBases.push_back(BL.get()); - - // Only lay this virtual base out directly inside of *this* class if this - // is a top-most derived class. Keep track of it regardless, but only - // physically lay it out if it's a topmost derived class. - addChildToLayout(std::move(BL)); - } - VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size()); - - if (Parent != nullptr) - LayoutSize = UsedBytes.find_last() + 1; -} - -bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const { - if (VBPtr && VBPtr->getOffsetInParent() == Off) - return true; - for (BaseClassLayout *BL : AllBases) { - if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent())) - return true; - } - return false; -} - -void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) { - uint32_t Begin = Child->getOffsetInParent(); - - if (!Child->isElided()) { - BitVector ChildBytes = Child->usedBytes(); - - // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte - // class. When we call ChildBytes.resize(32), the Child's storage will - // still begin at offset 0, so we need to shift it left by offset bytes - // to get it into the right position. - ChildBytes.resize(UsedBytes.size()); - ChildBytes <<= Child->getOffsetInParent(); - UsedBytes |= ChildBytes; - - if (ChildBytes.count() > 0) { +//===- UDTLayout.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/Casting.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <memory> + +using namespace llvm; +using namespace llvm::pdb; + +static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) { + const IPDBSession &Session = Symbol.getSession(); + const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol(); + uint32_t TypeId = RawSymbol.getTypeId(); + return Session.getSymbolById(TypeId); +} + +static uint32_t getTypeLength(const PDBSymbol &Symbol) { + auto SymbolType = getSymbolType(Symbol); + const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + + return RawType.getLength(); +} + +LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent, + const PDBSymbol *Symbol, const std::string &Name, + uint32_t OffsetInParent, uint32_t Size, + bool IsElided) + : Symbol(Symbol), Parent(Parent), Name(Name), + OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size), + IsElided(IsElided) { + UsedBytes.resize(SizeOf, true); +} + +uint32_t LayoutItemBase::deepPaddingSize() const { + return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t LayoutItemBase::tailPadding() const { + int Last = UsedBytes.find_last(); + + return UsedBytes.size() - (Last + 1); +} + +DataMemberLayoutItem::DataMemberLayoutItem( + const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member) + : LayoutItemBase(&Parent, Member.get(), Member->getName(), + Member->getOffset(), getTypeLength(*Member), false), + DataMember(std::move(Member)) { + auto Type = DataMember->getType(); + if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { + UdtLayout = std::make_unique<ClassLayout>(std::move(UDT)); + UsedBytes = UdtLayout->usedBytes(); + } +} + +VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBuiltin> Sym, + uint32_t Offset, uint32_t Size) + : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false), + Type(std::move(Sym)) { +} + +const PDBSymbolData &DataMemberLayoutItem::getDataMember() { + return *cast<PDBSymbolData>(Symbol); +} + +bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } + +const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { + return *UdtLayout; +} + +VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VT) + : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false), + VTable(std::move(VT)) { + auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType()); + ElementSize = VTableType->getLength(); +} + +UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size, bool IsElided) + : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) { + // UDT storage comes from a union of all the children's storage, so start out + // uninitialized. + UsedBytes.reset(0, Size); + + initializeChildren(Sym); + if (LayoutSize < Size) + UsedBytes.resize(LayoutSize); +} + +uint32_t UDTLayoutBase::tailPadding() const { + uint32_t Abs = LayoutItemBase::tailPadding(); + if (!LayoutItems.empty()) { + const LayoutItemBase *Back = LayoutItems.back(); + uint32_t ChildPadding = Back->LayoutItemBase::tailPadding(); + if (Abs < ChildPadding) + Abs = 0; + else + Abs -= ChildPadding; + } + return Abs; +} + +ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) + : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false), + UDT(UDT) { + ImmediateUsedBytes.resize(SizeOf, false); + for (auto &LI : LayoutItems) { + uint32_t Begin = LI->getOffsetInParent(); + uint32_t End = Begin + LI->getLayoutSize(); + End = std::min(SizeOf, End); + ImmediateUsedBytes.set(Begin, End); + } +} + +ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) + : ClassLayout(*UDT) { + OwnedStorage = std::move(UDT); +} + +uint32_t ClassLayout::immediatePadding() const { + return SizeOf - ImmediateUsedBytes.count(); +} + +BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, + uint32_t OffsetInParent, bool Elide, + std::unique_ptr<PDBSymbolTypeBaseClass> B) + : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(), + Elide), + Base(std::move(B)) { + if (isEmptyBase()) { + // Special case an empty base so that it doesn't get treated as padding. + UsedBytes.resize(1); + UsedBytes.set(0); + } + IsVirtualBase = Base->isVirtualBaseClass(); +} + +void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { + // Handled bases first, followed by VTables, followed by data members, + // followed by functions, followed by other. This ordering is necessary + // so that bases and vtables get initialized before any functions which + // may override them. + UniquePtrVector<PDBSymbolTypeBaseClass> Bases; + UniquePtrVector<PDBSymbolTypeVTable> VTables; + UniquePtrVector<PDBSymbolData> Members; + UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms; + + auto Children = Sym.findAllChildren(); + while (auto Child = Children->getNext()) { + if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { + if (Base->isVirtualBaseClass()) + VirtualBaseSyms.push_back(std::move(Base)); + else + Bases.push_back(std::move(Base)); + } + else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { + if (Data->getDataKind() == PDB_DataKind::Member) + Members.push_back(std::move(Data)); + else + Other.push_back(std::move(Data)); + } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) + VTables.push_back(std::move(VT)); + else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child)) + Funcs.push_back(std::move(Func)); + else { + Other.push_back(std::move(Child)); + } + } + + // We don't want to have any re-allocations in the list of bases, so make + // sure to reserve enough space so that our ArrayRefs don't get invalidated. + AllBases.reserve(Bases.size() + VirtualBaseSyms.size()); + + // Only add non-virtual bases to the class first. Only at the end of the + // class, after all non-virtual bases and data members have been added do we + // add virtual bases. This way the offsets are correctly aligned when we go + // to lay out virtual bases. + for (auto &Base : Bases) { + uint32_t Offset = Base->getOffset(); + // Non-virtual bases never get elided. + auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false, + std::move(Base)); + + AllBases.push_back(BL.get()); + addChildToLayout(std::move(BL)); + } + NonVirtualBases = AllBases; + + assert(VTables.size() <= 1); + if (!VTables.empty()) { + auto VTLayout = + std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0])); + + VTable = VTLayout.get(); + + addChildToLayout(std::move(VTLayout)); + } + + for (auto &Data : Members) { + auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); + + addChildToLayout(std::move(DM)); + } + + // Make sure add virtual bases before adding functions, since functions may be + // overrides of virtual functions declared in a virtual base, so the VTables + // and virtual intros need to be correctly initialized. + for (auto &VB : VirtualBaseSyms) { + int VBPO = VB->getVirtualBasePointerOffset(); + if (!hasVBPtrAtOffset(VBPO)) { + if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) { + auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP), + VBPO, VBP->getLength()); + VBPtr = VBPL.get(); + addChildToLayout(std::move(VBPL)); + } + } + + // Virtual bases always go at the end. So just look for the last place we + // ended when writing something, and put our virtual base there. + // Note that virtual bases get elided unless this is a top-most derived + // class. + uint32_t Offset = UsedBytes.find_last() + 1; + bool Elide = (Parent != nullptr); + auto BL = + std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB)); + AllBases.push_back(BL.get()); + + // Only lay this virtual base out directly inside of *this* class if this + // is a top-most derived class. Keep track of it regardless, but only + // physically lay it out if it's a topmost derived class. + addChildToLayout(std::move(BL)); + } + VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size()); + + if (Parent != nullptr) + LayoutSize = UsedBytes.find_last() + 1; +} + +bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const { + if (VBPtr && VBPtr->getOffsetInParent() == Off) + return true; + for (BaseClassLayout *BL : AllBases) { + if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent())) + return true; + } + return false; +} + +void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) { + uint32_t Begin = Child->getOffsetInParent(); + + if (!Child->isElided()) { + BitVector ChildBytes = Child->usedBytes(); + + // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte + // class. When we call ChildBytes.resize(32), the Child's storage will + // still begin at offset 0, so we need to shift it left by offset bytes + // to get it into the right position. + ChildBytes.resize(UsedBytes.size()); + ChildBytes <<= Child->getOffsetInParent(); + UsedBytes |= ChildBytes; + + if (ChildBytes.count() > 0) { auto Loc = llvm::upper_bound( LayoutItems, Begin, [](uint32_t Off, const LayoutItemBase *Item) { return (Off < Item->getOffsetInParent()); }); - - LayoutItems.insert(Loc, Child.get()); - } - } - - ChildStorage.push_back(std::move(Child)); -} + + LayoutItems.insert(Loc, Child.get()); + } + } + + ChildStorage.push_back(std::move(Child)); +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/PDB/ya.make b/contrib/libs/llvm12/lib/DebugInfo/PDB/ya.make index daa2f8ed3a..348345134a 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/PDB/ya.make +++ b/contrib/libs/llvm12/lib/DebugInfo/PDB/ya.make @@ -1,124 +1,124 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/BinaryFormat contrib/libs/llvm12/lib/DebugInfo/CodeView contrib/libs/llvm12/lib/DebugInfo/MSF contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/DebugInfo/PDB ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - GenericError.cpp - IPDBSourceFile.cpp - Native/DbiModuleDescriptor.cpp - Native/DbiModuleDescriptorBuilder.cpp - Native/DbiModuleList.cpp - Native/DbiStream.cpp - Native/DbiStreamBuilder.cpp - Native/EnumTables.cpp - Native/GSIStreamBuilder.cpp - Native/GlobalsStream.cpp - Native/Hash.cpp - Native/HashTable.cpp - Native/InfoStream.cpp - Native/InfoStreamBuilder.cpp - Native/InjectedSourceStream.cpp - Native/ModuleDebugStream.cpp - Native/NamedStreamMap.cpp - Native/NativeCompilandSymbol.cpp - Native/NativeEnumGlobals.cpp - Native/NativeEnumInjectedSources.cpp - Native/NativeEnumLineNumbers.cpp - Native/NativeEnumModules.cpp + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + GenericError.cpp + IPDBSourceFile.cpp + Native/DbiModuleDescriptor.cpp + Native/DbiModuleDescriptorBuilder.cpp + Native/DbiModuleList.cpp + Native/DbiStream.cpp + Native/DbiStreamBuilder.cpp + Native/EnumTables.cpp + Native/GSIStreamBuilder.cpp + Native/GlobalsStream.cpp + Native/Hash.cpp + Native/HashTable.cpp + Native/InfoStream.cpp + Native/InfoStreamBuilder.cpp + Native/InjectedSourceStream.cpp + Native/ModuleDebugStream.cpp + Native/NamedStreamMap.cpp + Native/NativeCompilandSymbol.cpp + Native/NativeEnumGlobals.cpp + Native/NativeEnumInjectedSources.cpp + Native/NativeEnumLineNumbers.cpp + Native/NativeEnumModules.cpp Native/NativeEnumSymbols.cpp - Native/NativeEnumTypes.cpp - Native/NativeExeSymbol.cpp - Native/NativeFunctionSymbol.cpp + Native/NativeEnumTypes.cpp + Native/NativeExeSymbol.cpp + Native/NativeFunctionSymbol.cpp Native/NativeInlineSiteSymbol.cpp - Native/NativeLineNumber.cpp - Native/NativePublicSymbol.cpp - Native/NativeRawSymbol.cpp - Native/NativeSession.cpp - Native/NativeSourceFile.cpp - Native/NativeSymbolEnumerator.cpp - Native/NativeTypeArray.cpp - Native/NativeTypeBuiltin.cpp - Native/NativeTypeEnum.cpp - Native/NativeTypeFunctionSig.cpp - Native/NativeTypePointer.cpp - Native/NativeTypeTypedef.cpp - Native/NativeTypeUDT.cpp - Native/NativeTypeVTShape.cpp - Native/PDBFile.cpp - Native/PDBFileBuilder.cpp - Native/PDBStringTable.cpp - Native/PDBStringTableBuilder.cpp - Native/PublicsStream.cpp - Native/RawError.cpp - Native/SymbolCache.cpp - Native/SymbolStream.cpp - Native/TpiHashing.cpp - Native/TpiStream.cpp - Native/TpiStreamBuilder.cpp - PDB.cpp - PDBContext.cpp - PDBExtras.cpp - PDBInterfaceAnchors.cpp - PDBSymDumper.cpp - PDBSymbol.cpp - PDBSymbolAnnotation.cpp - PDBSymbolBlock.cpp - PDBSymbolCompiland.cpp - PDBSymbolCompilandDetails.cpp - PDBSymbolCompilandEnv.cpp - PDBSymbolCustom.cpp - PDBSymbolData.cpp - PDBSymbolExe.cpp - PDBSymbolFunc.cpp - PDBSymbolFuncDebugEnd.cpp - PDBSymbolFuncDebugStart.cpp - PDBSymbolLabel.cpp - PDBSymbolPublicSymbol.cpp - PDBSymbolThunk.cpp - PDBSymbolTypeArray.cpp - PDBSymbolTypeBaseClass.cpp - PDBSymbolTypeBuiltin.cpp - PDBSymbolTypeCustom.cpp - PDBSymbolTypeDimension.cpp - PDBSymbolTypeEnum.cpp - PDBSymbolTypeFriend.cpp - PDBSymbolTypeFunctionArg.cpp - PDBSymbolTypeFunctionSig.cpp - PDBSymbolTypeManaged.cpp - PDBSymbolTypePointer.cpp - PDBSymbolTypeTypedef.cpp - PDBSymbolTypeUDT.cpp - PDBSymbolTypeVTable.cpp - PDBSymbolTypeVTableShape.cpp - PDBSymbolUnknown.cpp - PDBSymbolUsingNamespace.cpp - UDTLayout.cpp -) - -END() + Native/NativeLineNumber.cpp + Native/NativePublicSymbol.cpp + Native/NativeRawSymbol.cpp + Native/NativeSession.cpp + Native/NativeSourceFile.cpp + Native/NativeSymbolEnumerator.cpp + Native/NativeTypeArray.cpp + Native/NativeTypeBuiltin.cpp + Native/NativeTypeEnum.cpp + Native/NativeTypeFunctionSig.cpp + Native/NativeTypePointer.cpp + Native/NativeTypeTypedef.cpp + Native/NativeTypeUDT.cpp + Native/NativeTypeVTShape.cpp + Native/PDBFile.cpp + Native/PDBFileBuilder.cpp + Native/PDBStringTable.cpp + Native/PDBStringTableBuilder.cpp + Native/PublicsStream.cpp + Native/RawError.cpp + Native/SymbolCache.cpp + Native/SymbolStream.cpp + Native/TpiHashing.cpp + Native/TpiStream.cpp + Native/TpiStreamBuilder.cpp + PDB.cpp + PDBContext.cpp + PDBExtras.cpp + PDBInterfaceAnchors.cpp + PDBSymDumper.cpp + PDBSymbol.cpp + PDBSymbolAnnotation.cpp + PDBSymbolBlock.cpp + PDBSymbolCompiland.cpp + PDBSymbolCompilandDetails.cpp + PDBSymbolCompilandEnv.cpp + PDBSymbolCustom.cpp + PDBSymbolData.cpp + PDBSymbolExe.cpp + PDBSymbolFunc.cpp + PDBSymbolFuncDebugEnd.cpp + PDBSymbolFuncDebugStart.cpp + PDBSymbolLabel.cpp + PDBSymbolPublicSymbol.cpp + PDBSymbolThunk.cpp + PDBSymbolTypeArray.cpp + PDBSymbolTypeBaseClass.cpp + PDBSymbolTypeBuiltin.cpp + PDBSymbolTypeCustom.cpp + PDBSymbolTypeDimension.cpp + PDBSymbolTypeEnum.cpp + PDBSymbolTypeFriend.cpp + PDBSymbolTypeFunctionArg.cpp + PDBSymbolTypeFunctionSig.cpp + PDBSymbolTypeManaged.cpp + PDBSymbolTypePointer.cpp + PDBSymbolTypeTypedef.cpp + PDBSymbolTypeUDT.cpp + PDBSymbolTypeVTable.cpp + PDBSymbolTypeVTableShape.cpp + PDBSymbolUnknown.cpp + PDBSymbolUsingNamespace.cpp + UDTLayout.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/DIPrinter.cpp b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/DIPrinter.cpp index 01dc31d849..84bf1c177e 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/DIPrinter.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/DIPrinter.cpp @@ -1,157 +1,157 @@ -//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the DIPrinter class, which is responsible for printing -// structures defined in DebugInfo/DIContext.h -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/Symbolize/DIPrinter.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/LineIterator.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cmath> -#include <cstddef> -#include <cstdint> -#include <memory> -#include <string> - -namespace llvm { -namespace symbolize { - -// Prints source code around in the FileName the Line. -void DIPrinter::printContext(const std::string &FileName, int64_t Line) { - if (PrintSourceContext <= 0) - return; - - ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = - MemoryBuffer::getFile(FileName); - if (!BufOrErr) - return; - - std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); - int64_t FirstLine = - std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2); - int64_t LastLine = FirstLine + PrintSourceContext; - size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); - - for (line_iterator I = line_iterator(*Buf, false); - !I.is_at_eof() && I.line_number() <= LastLine; ++I) { - int64_t L = I.line_number(); - if (L >= FirstLine && L <= LastLine) { - OS << format_decimal(L, MaxLineNumberWidth); - if (L == Line) - OS << " >: "; - else - OS << " : "; - OS << *I << "\n"; - } - } -} - -void DIPrinter::print(const DILineInfo &Info, bool Inlined) { - if (PrintFunctionNames) { - std::string FunctionName = Info.FunctionName; - if (FunctionName == DILineInfo::BadString) - FunctionName = DILineInfo::Addr2LineBadString; - - StringRef Delimiter = PrintPretty ? " at " : "\n"; - StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : ""; - OS << Prefix << FunctionName << Delimiter; - } - std::string Filename = Info.FileName; - if (Filename == DILineInfo::BadString) - Filename = DILineInfo::Addr2LineBadString; - if (!Verbose) { - OS << Filename << ":" << Info.Line; - if (Style == OutputStyle::LLVM) - OS << ":" << Info.Column; - else if (Style == OutputStyle::GNU && Info.Discriminator != 0) - OS << " (discriminator " << Info.Discriminator << ")"; - OS << "\n"; - printContext(Filename, Info.Line); - return; - } - OS << " Filename: " << Filename << "\n"; +//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the DIPrinter class, which is responsible for printing +// structures defined in DebugInfo/DIContext.h +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Symbolize/DIPrinter.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <string> + +namespace llvm { +namespace symbolize { + +// Prints source code around in the FileName the Line. +void DIPrinter::printContext(const std::string &FileName, int64_t Line) { + if (PrintSourceContext <= 0) + return; + + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFile(FileName); + if (!BufOrErr) + return; + + std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get()); + int64_t FirstLine = + std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2); + int64_t LastLine = FirstLine + PrintSourceContext; + size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine)); + + for (line_iterator I = line_iterator(*Buf, false); + !I.is_at_eof() && I.line_number() <= LastLine; ++I) { + int64_t L = I.line_number(); + if (L >= FirstLine && L <= LastLine) { + OS << format_decimal(L, MaxLineNumberWidth); + if (L == Line) + OS << " >: "; + else + OS << " : "; + OS << *I << "\n"; + } + } +} + +void DIPrinter::print(const DILineInfo &Info, bool Inlined) { + if (PrintFunctionNames) { + std::string FunctionName = Info.FunctionName; + if (FunctionName == DILineInfo::BadString) + FunctionName = DILineInfo::Addr2LineBadString; + + StringRef Delimiter = PrintPretty ? " at " : "\n"; + StringRef Prefix = (PrintPretty && Inlined) ? " (inlined by) " : ""; + OS << Prefix << FunctionName << Delimiter; + } + std::string Filename = Info.FileName; + if (Filename == DILineInfo::BadString) + Filename = DILineInfo::Addr2LineBadString; + if (!Verbose) { + OS << Filename << ":" << Info.Line; + if (Style == OutputStyle::LLVM) + OS << ":" << Info.Column; + else if (Style == OutputStyle::GNU && Info.Discriminator != 0) + OS << " (discriminator " << Info.Discriminator << ")"; + OS << "\n"; + printContext(Filename, Info.Line); + return; + } + OS << " Filename: " << Filename << "\n"; if (Info.StartLine) { OS << " Function start filename: " << Info.StartFileName << "\n"; OS << " Function start line: " << Info.StartLine << "\n"; } - OS << " Line: " << Info.Line << "\n"; - OS << " Column: " << Info.Column << "\n"; - if (Info.Discriminator) - OS << " Discriminator: " << Info.Discriminator << "\n"; -} - -DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { - print(Info, false); - return *this; -} - -DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { - uint32_t FramesNum = Info.getNumberOfFrames(); - if (FramesNum == 0) { - print(DILineInfo(), false); - return *this; - } - for (uint32_t i = 0; i < FramesNum; i++) - print(Info.getFrame(i), i > 0); - return *this; -} - -DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { - std::string Name = Global.Name; - if (Name == DILineInfo::BadString) - Name = DILineInfo::Addr2LineBadString; - OS << Name << "\n"; - OS << Global.Start << " " << Global.Size << "\n"; - return *this; -} - -DIPrinter &DIPrinter::operator<<(const DILocal &Local) { - if (Local.FunctionName.empty()) - OS << "??\n"; - else - OS << Local.FunctionName << '\n'; - - if (Local.Name.empty()) - OS << "??\n"; - else - OS << Local.Name << '\n'; - - if (Local.DeclFile.empty()) - OS << "??"; - else - OS << Local.DeclFile; - OS << ':' << Local.DeclLine << '\n'; - - if (Local.FrameOffset) - OS << *Local.FrameOffset << ' '; - else - OS << "?? "; - - if (Local.Size) - OS << *Local.Size << ' '; - else - OS << "?? "; - - if (Local.TagOffset) - OS << *Local.TagOffset << '\n'; - else - OS << "??\n"; - return *this; -} - -} // end namespace symbolize -} // end namespace llvm + OS << " Line: " << Info.Line << "\n"; + OS << " Column: " << Info.Column << "\n"; + if (Info.Discriminator) + OS << " Discriminator: " << Info.Discriminator << "\n"; +} + +DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) { + print(Info, false); + return *this; +} + +DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) { + uint32_t FramesNum = Info.getNumberOfFrames(); + if (FramesNum == 0) { + print(DILineInfo(), false); + return *this; + } + for (uint32_t i = 0; i < FramesNum; i++) + print(Info.getFrame(i), i > 0); + return *this; +} + +DIPrinter &DIPrinter::operator<<(const DIGlobal &Global) { + std::string Name = Global.Name; + if (Name == DILineInfo::BadString) + Name = DILineInfo::Addr2LineBadString; + OS << Name << "\n"; + OS << Global.Start << " " << Global.Size << "\n"; + return *this; +} + +DIPrinter &DIPrinter::operator<<(const DILocal &Local) { + if (Local.FunctionName.empty()) + OS << "??\n"; + else + OS << Local.FunctionName << '\n'; + + if (Local.Name.empty()) + OS << "??\n"; + else + OS << Local.Name << '\n'; + + if (Local.DeclFile.empty()) + OS << "??"; + else + OS << Local.DeclFile; + OS << ':' << Local.DeclLine << '\n'; + + if (Local.FrameOffset) + OS << *Local.FrameOffset << ' '; + else + OS << "?? "; + + if (Local.Size) + OS << *Local.Size << ' '; + else + OS << "?? "; + + if (Local.TagOffset) + OS << *Local.TagOffset << '\n'; + else + OS << "??\n"; + return *this; +} + +} // end namespace symbolize +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp index 93d05e4e27..604cd7e393 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp @@ -1,318 +1,318 @@ -//===- SymbolizableObjectFile.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of SymbolizableObjectFile class. -// -//===----------------------------------------------------------------------===// - -#include "SymbolizableObjectFile.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/SymbolSize.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/DataExtractor.h" -#include <algorithm> - -using namespace llvm; -using namespace object; -using namespace symbolize; - -Expected<std::unique_ptr<SymbolizableObjectFile>> -SymbolizableObjectFile::create(const object::ObjectFile *Obj, - std::unique_ptr<DIContext> DICtx, - bool UntagAddresses) { - assert(DICtx); - std::unique_ptr<SymbolizableObjectFile> res( - new SymbolizableObjectFile(Obj, std::move(DICtx), UntagAddresses)); - std::unique_ptr<DataExtractor> OpdExtractor; - uint64_t OpdAddress = 0; - // Find the .opd (function descriptor) section if any, for big-endian - // PowerPC64 ELF. - if (Obj->getArch() == Triple::ppc64) { - for (section_iterator Section : Obj->sections()) { - Expected<StringRef> NameOrErr = Section->getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - - if (*NameOrErr == ".opd") { - Expected<StringRef> E = Section->getContents(); - if (!E) - return E.takeError(); - OpdExtractor.reset(new DataExtractor(*E, Obj->isLittleEndian(), - Obj->getBytesInAddress())); - OpdAddress = Section->getAddress(); - break; - } - } - } - std::vector<std::pair<SymbolRef, uint64_t>> Symbols = - computeSymbolSizes(*Obj); - for (auto &P : Symbols) - if (Error E = - res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress)) - return std::move(E); - - // If this is a COFF object and we didn't find any symbols, try the export - // table. - if (Symbols.empty()) { - if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj)) - if (Error E = res->addCoffExportSymbols(CoffObj)) - return std::move(E); - } - - std::vector<std::pair<SymbolDesc, StringRef>> &Fs = res->Functions, - &Os = res->Objects; - auto Uniquify = [](std::vector<std::pair<SymbolDesc, StringRef>> &S) { - // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr, - // pick the one with the largest Size. This helps us avoid symbols with no - // size information (Size=0). - llvm::sort(S); - auto I = S.begin(), E = S.end(), J = S.begin(); - while (I != E) { - auto OI = I; - while (++I != E && OI->first.Addr == I->first.Addr) { - } - *J++ = I[-1]; - } - S.erase(J, S.end()); - }; - Uniquify(Fs); - Uniquify(Os); - - return std::move(res); -} - -SymbolizableObjectFile::SymbolizableObjectFile(const ObjectFile *Obj, - std::unique_ptr<DIContext> DICtx, - bool UntagAddresses) - : Module(Obj), DebugInfoContext(std::move(DICtx)), - UntagAddresses(UntagAddresses) {} - -namespace { - -struct OffsetNamePair { - uint32_t Offset; - StringRef Name; - - bool operator<(const OffsetNamePair &R) const { - return Offset < R.Offset; - } -}; - -} // end anonymous namespace - -Error SymbolizableObjectFile::addCoffExportSymbols( - const COFFObjectFile *CoffObj) { - // Get all export names and offsets. - std::vector<OffsetNamePair> ExportSyms; - for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) { - StringRef Name; - uint32_t Offset; - if (auto EC = Ref.getSymbolName(Name)) - return EC; - if (auto EC = Ref.getExportRVA(Offset)) - return EC; - ExportSyms.push_back(OffsetNamePair{Offset, Name}); - } - if (ExportSyms.empty()) - return Error::success(); - - // Sort by ascending offset. - array_pod_sort(ExportSyms.begin(), ExportSyms.end()); - - // Approximate the symbol sizes by assuming they run to the next symbol. - // FIXME: This assumes all exports are functions. - uint64_t ImageBase = CoffObj->getImageBase(); - for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) { - OffsetNamePair &Export = *I; - // FIXME: The last export has a one byte size now. - uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1; - uint64_t SymbolStart = ImageBase + Export.Offset; - uint64_t SymbolSize = NextOffset - Export.Offset; - SymbolDesc SD = {SymbolStart, SymbolSize}; - Functions.emplace_back(SD, Export.Name); - } - return Error::success(); -} - -Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol, - uint64_t SymbolSize, - DataExtractor *OpdExtractor, - uint64_t OpdAddress) { - // Avoid adding symbols from an unknown/undefined section. - const ObjectFile *Obj = Symbol.getObject(); - Expected<section_iterator> Sec = Symbol.getSection(); - if (!Sec || (Obj && Obj->section_end() == *Sec)) - return Error::success(); - Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType(); - if (!SymbolTypeOrErr) - return SymbolTypeOrErr.takeError(); - SymbolRef::Type SymbolType = *SymbolTypeOrErr; - if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) - return Error::success(); - Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress(); - if (!SymbolAddressOrErr) - return SymbolAddressOrErr.takeError(); - uint64_t SymbolAddress = *SymbolAddressOrErr; - if (UntagAddresses) { - // For kernel addresses, bits 56-63 need to be set, so we sign extend bit 55 - // into bits 56-63 instead of masking them out. - SymbolAddress &= (1ull << 56) - 1; - SymbolAddress = (int64_t(SymbolAddress) << 8) >> 8; - } - if (OpdExtractor) { - // For big-endian PowerPC64 ELF, symbols in the .opd section refer to - // function descriptors. The first word of the descriptor is a pointer to - // the function's code. - // For the purposes of symbolization, pretend the symbol's address is that - // of the function's code, not the descriptor. - uint64_t OpdOffset = SymbolAddress - OpdAddress; - if (OpdExtractor->isValidOffsetForAddress(OpdOffset)) - SymbolAddress = OpdExtractor->getAddress(&OpdOffset); - } - Expected<StringRef> SymbolNameOrErr = Symbol.getName(); - if (!SymbolNameOrErr) - return SymbolNameOrErr.takeError(); - StringRef SymbolName = *SymbolNameOrErr; - // Mach-O symbol table names have leading underscore, skip it. - if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_') - SymbolName = SymbolName.drop_front(); - // FIXME: If a function has alias, there are two entries in symbol table - // with same address size. Make sure we choose the correct one. - auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; - SymbolDesc SD = { SymbolAddress, SymbolSize }; - M.emplace_back(SD, SymbolName); - return Error::success(); -} - -// Return true if this is a 32-bit x86 PE COFF module. -bool SymbolizableObjectFile::isWin32Module() const { - auto *CoffObject = dyn_cast<COFFObjectFile>(Module); - return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386; -} - -uint64_t SymbolizableObjectFile::getModulePreferredBase() const { - if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module)) - return CoffObject->getImageBase(); - return 0; -} - -bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type, - uint64_t Address, - std::string &Name, - uint64_t &Addr, - uint64_t &Size) const { - const auto &Symbols = Type == SymbolRef::ST_Function ? Functions : Objects; - std::pair<SymbolDesc, StringRef> SD{{Address, UINT64_C(-1)}, StringRef()}; - auto SymbolIterator = llvm::upper_bound(Symbols, SD); - if (SymbolIterator == Symbols.begin()) - return false; - --SymbolIterator; - if (SymbolIterator->first.Size != 0 && - SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) - return false; - Name = SymbolIterator->second.str(); - Addr = SymbolIterator->first.Addr; - Size = SymbolIterator->first.Size; - return true; -} - -bool SymbolizableObjectFile::shouldOverrideWithSymbolTable( - FunctionNameKind FNKind, bool UseSymbolTable) const { - // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives - // better answers for linkage names than the DIContext. Otherwise, we are - // probably using PEs and PDBs, and we shouldn't do the override. PE files - // generally only contain the names of exported symbols. - return FNKind == FunctionNameKind::LinkageName && UseSymbolTable && - isa<DWARFContext>(DebugInfoContext.get()); -} - -DILineInfo -SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset, - DILineInfoSpecifier LineInfoSpecifier, - bool UseSymbolTable) const { - if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) - ModuleOffset.SectionIndex = - getModuleSectionIndexForAddress(ModuleOffset.Address); - DILineInfo LineInfo = - DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier); - - // Override function name from symbol table if necessary. - if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address, - FunctionName, Start, Size)) { - LineInfo.FunctionName = FunctionName; - } - } - return LineInfo; -} - -DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode( - object::SectionedAddress ModuleOffset, - DILineInfoSpecifier LineInfoSpecifier, bool UseSymbolTable) const { - if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) - ModuleOffset.SectionIndex = - getModuleSectionIndexForAddress(ModuleOffset.Address); - DIInliningInfo InlinedContext = DebugInfoContext->getInliningInfoForAddress( - ModuleOffset, LineInfoSpecifier); - - // Make sure there is at least one frame in context. - if (InlinedContext.getNumberOfFrames() == 0) - InlinedContext.addFrame(DILineInfo()); - - // Override the function name in lower frame with name from symbol table. - if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) { - std::string FunctionName; - uint64_t Start, Size; - if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address, - FunctionName, Start, Size)) { - InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1) - ->FunctionName = FunctionName; - } - } - - return InlinedContext; -} - -DIGlobal SymbolizableObjectFile::symbolizeData( - object::SectionedAddress ModuleOffset) const { - DIGlobal Res; - getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name, - Res.Start, Res.Size); - return Res; -} - -std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame( - object::SectionedAddress ModuleOffset) const { - if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) - ModuleOffset.SectionIndex = - getModuleSectionIndexForAddress(ModuleOffset.Address); - return DebugInfoContext->getLocalsForAddress(ModuleOffset); -} - -/// Search for the first occurence of specified Address in ObjectFile. -uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress( - uint64_t Address) const { - - for (SectionRef Sec : Module->sections()) { - if (!Sec.isText() || Sec.isVirtual()) - continue; - - if (Address >= Sec.getAddress() && - Address < Sec.getAddress() + Sec.getSize()) - return Sec.getIndex(); - } - - return object::SectionedAddress::UndefSection; -} +//===- SymbolizableObjectFile.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of SymbolizableObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "SymbolizableObjectFile.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolSize.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/DataExtractor.h" +#include <algorithm> + +using namespace llvm; +using namespace object; +using namespace symbolize; + +Expected<std::unique_ptr<SymbolizableObjectFile>> +SymbolizableObjectFile::create(const object::ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx, + bool UntagAddresses) { + assert(DICtx); + std::unique_ptr<SymbolizableObjectFile> res( + new SymbolizableObjectFile(Obj, std::move(DICtx), UntagAddresses)); + std::unique_ptr<DataExtractor> OpdExtractor; + uint64_t OpdAddress = 0; + // Find the .opd (function descriptor) section if any, for big-endian + // PowerPC64 ELF. + if (Obj->getArch() == Triple::ppc64) { + for (section_iterator Section : Obj->sections()) { + Expected<StringRef> NameOrErr = Section->getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + + if (*NameOrErr == ".opd") { + Expected<StringRef> E = Section->getContents(); + if (!E) + return E.takeError(); + OpdExtractor.reset(new DataExtractor(*E, Obj->isLittleEndian(), + Obj->getBytesInAddress())); + OpdAddress = Section->getAddress(); + break; + } + } + } + std::vector<std::pair<SymbolRef, uint64_t>> Symbols = + computeSymbolSizes(*Obj); + for (auto &P : Symbols) + if (Error E = + res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress)) + return std::move(E); + + // If this is a COFF object and we didn't find any symbols, try the export + // table. + if (Symbols.empty()) { + if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj)) + if (Error E = res->addCoffExportSymbols(CoffObj)) + return std::move(E); + } + + std::vector<std::pair<SymbolDesc, StringRef>> &Fs = res->Functions, + &Os = res->Objects; + auto Uniquify = [](std::vector<std::pair<SymbolDesc, StringRef>> &S) { + // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr, + // pick the one with the largest Size. This helps us avoid symbols with no + // size information (Size=0). + llvm::sort(S); + auto I = S.begin(), E = S.end(), J = S.begin(); + while (I != E) { + auto OI = I; + while (++I != E && OI->first.Addr == I->first.Addr) { + } + *J++ = I[-1]; + } + S.erase(J, S.end()); + }; + Uniquify(Fs); + Uniquify(Os); + + return std::move(res); +} + +SymbolizableObjectFile::SymbolizableObjectFile(const ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx, + bool UntagAddresses) + : Module(Obj), DebugInfoContext(std::move(DICtx)), + UntagAddresses(UntagAddresses) {} + +namespace { + +struct OffsetNamePair { + uint32_t Offset; + StringRef Name; + + bool operator<(const OffsetNamePair &R) const { + return Offset < R.Offset; + } +}; + +} // end anonymous namespace + +Error SymbolizableObjectFile::addCoffExportSymbols( + const COFFObjectFile *CoffObj) { + // Get all export names and offsets. + std::vector<OffsetNamePair> ExportSyms; + for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) { + StringRef Name; + uint32_t Offset; + if (auto EC = Ref.getSymbolName(Name)) + return EC; + if (auto EC = Ref.getExportRVA(Offset)) + return EC; + ExportSyms.push_back(OffsetNamePair{Offset, Name}); + } + if (ExportSyms.empty()) + return Error::success(); + + // Sort by ascending offset. + array_pod_sort(ExportSyms.begin(), ExportSyms.end()); + + // Approximate the symbol sizes by assuming they run to the next symbol. + // FIXME: This assumes all exports are functions. + uint64_t ImageBase = CoffObj->getImageBase(); + for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) { + OffsetNamePair &Export = *I; + // FIXME: The last export has a one byte size now. + uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1; + uint64_t SymbolStart = ImageBase + Export.Offset; + uint64_t SymbolSize = NextOffset - Export.Offset; + SymbolDesc SD = {SymbolStart, SymbolSize}; + Functions.emplace_back(SD, Export.Name); + } + return Error::success(); +} + +Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol, + uint64_t SymbolSize, + DataExtractor *OpdExtractor, + uint64_t OpdAddress) { + // Avoid adding symbols from an unknown/undefined section. + const ObjectFile *Obj = Symbol.getObject(); + Expected<section_iterator> Sec = Symbol.getSection(); + if (!Sec || (Obj && Obj->section_end() == *Sec)) + return Error::success(); + Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType(); + if (!SymbolTypeOrErr) + return SymbolTypeOrErr.takeError(); + SymbolRef::Type SymbolType = *SymbolTypeOrErr; + if (SymbolType != SymbolRef::ST_Function && SymbolType != SymbolRef::ST_Data) + return Error::success(); + Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress(); + if (!SymbolAddressOrErr) + return SymbolAddressOrErr.takeError(); + uint64_t SymbolAddress = *SymbolAddressOrErr; + if (UntagAddresses) { + // For kernel addresses, bits 56-63 need to be set, so we sign extend bit 55 + // into bits 56-63 instead of masking them out. + SymbolAddress &= (1ull << 56) - 1; + SymbolAddress = (int64_t(SymbolAddress) << 8) >> 8; + } + if (OpdExtractor) { + // For big-endian PowerPC64 ELF, symbols in the .opd section refer to + // function descriptors. The first word of the descriptor is a pointer to + // the function's code. + // For the purposes of symbolization, pretend the symbol's address is that + // of the function's code, not the descriptor. + uint64_t OpdOffset = SymbolAddress - OpdAddress; + if (OpdExtractor->isValidOffsetForAddress(OpdOffset)) + SymbolAddress = OpdExtractor->getAddress(&OpdOffset); + } + Expected<StringRef> SymbolNameOrErr = Symbol.getName(); + if (!SymbolNameOrErr) + return SymbolNameOrErr.takeError(); + StringRef SymbolName = *SymbolNameOrErr; + // Mach-O symbol table names have leading underscore, skip it. + if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_') + SymbolName = SymbolName.drop_front(); + // FIXME: If a function has alias, there are two entries in symbol table + // with same address size. Make sure we choose the correct one. + auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; + SymbolDesc SD = { SymbolAddress, SymbolSize }; + M.emplace_back(SD, SymbolName); + return Error::success(); +} + +// Return true if this is a 32-bit x86 PE COFF module. +bool SymbolizableObjectFile::isWin32Module() const { + auto *CoffObject = dyn_cast<COFFObjectFile>(Module); + return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386; +} + +uint64_t SymbolizableObjectFile::getModulePreferredBase() const { + if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module)) + return CoffObject->getImageBase(); + return 0; +} + +bool SymbolizableObjectFile::getNameFromSymbolTable(SymbolRef::Type Type, + uint64_t Address, + std::string &Name, + uint64_t &Addr, + uint64_t &Size) const { + const auto &Symbols = Type == SymbolRef::ST_Function ? Functions : Objects; + std::pair<SymbolDesc, StringRef> SD{{Address, UINT64_C(-1)}, StringRef()}; + auto SymbolIterator = llvm::upper_bound(Symbols, SD); + if (SymbolIterator == Symbols.begin()) + return false; + --SymbolIterator; + if (SymbolIterator->first.Size != 0 && + SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address) + return false; + Name = SymbolIterator->second.str(); + Addr = SymbolIterator->first.Addr; + Size = SymbolIterator->first.Size; + return true; +} + +bool SymbolizableObjectFile::shouldOverrideWithSymbolTable( + FunctionNameKind FNKind, bool UseSymbolTable) const { + // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives + // better answers for linkage names than the DIContext. Otherwise, we are + // probably using PEs and PDBs, and we shouldn't do the override. PE files + // generally only contain the names of exported symbols. + return FNKind == FunctionNameKind::LinkageName && UseSymbolTable && + isa<DWARFContext>(DebugInfoContext.get()); +} + +DILineInfo +SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset, + DILineInfoSpecifier LineInfoSpecifier, + bool UseSymbolTable) const { + if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) + ModuleOffset.SectionIndex = + getModuleSectionIndexForAddress(ModuleOffset.Address); + DILineInfo LineInfo = + DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier); + + // Override function name from symbol table if necessary. + if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address, + FunctionName, Start, Size)) { + LineInfo.FunctionName = FunctionName; + } + } + return LineInfo; +} + +DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode( + object::SectionedAddress ModuleOffset, + DILineInfoSpecifier LineInfoSpecifier, bool UseSymbolTable) const { + if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) + ModuleOffset.SectionIndex = + getModuleSectionIndexForAddress(ModuleOffset.Address); + DIInliningInfo InlinedContext = DebugInfoContext->getInliningInfoForAddress( + ModuleOffset, LineInfoSpecifier); + + // Make sure there is at least one frame in context. + if (InlinedContext.getNumberOfFrames() == 0) + InlinedContext.addFrame(DILineInfo()); + + // Override the function name in lower frame with name from symbol table. + if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset.Address, + FunctionName, Start, Size)) { + InlinedContext.getMutableFrame(InlinedContext.getNumberOfFrames() - 1) + ->FunctionName = FunctionName; + } + } + + return InlinedContext; +} + +DIGlobal SymbolizableObjectFile::symbolizeData( + object::SectionedAddress ModuleOffset) const { + DIGlobal Res; + getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset.Address, Res.Name, + Res.Start, Res.Size); + return Res; +} + +std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame( + object::SectionedAddress ModuleOffset) const { + if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection) + ModuleOffset.SectionIndex = + getModuleSectionIndexForAddress(ModuleOffset.Address); + return DebugInfoContext->getLocalsForAddress(ModuleOffset); +} + +/// Search for the first occurence of specified Address in ObjectFile. +uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress( + uint64_t Address) const { + + for (SectionRef Sec : Module->sections()) { + if (!Sec.isText() || Sec.isVirtual()) + continue; + + if (Address >= Sec.getAddress() && + Address < Sec.getAddress() + Sec.getSize()) + return Sec.getIndex(); + } + + return object::SectionedAddress::UndefSection; +} diff --git a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h index be3c66df05..cdab521100 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h +++ b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h @@ -1,97 +1,97 @@ -//===- SymbolizableObjectFile.h ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file declares the SymbolizableObjectFile class. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H -#define LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" +//===- SymbolizableObjectFile.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the SymbolizableObjectFile class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H +#define LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" #include "llvm/Support/Error.h" -#include <cstdint> -#include <memory> -#include <string> +#include <cstdint> +#include <memory> +#include <string> #include <utility> #include <vector> - -namespace llvm { - -class DataExtractor; - -namespace symbolize { - -class SymbolizableObjectFile : public SymbolizableModule { -public: - static Expected<std::unique_ptr<SymbolizableObjectFile>> - create(const object::ObjectFile *Obj, std::unique_ptr<DIContext> DICtx, - bool UntagAddresses); - - DILineInfo symbolizeCode(object::SectionedAddress ModuleOffset, - DILineInfoSpecifier LineInfoSpecifier, - bool UseSymbolTable) const override; - DIInliningInfo symbolizeInlinedCode(object::SectionedAddress ModuleOffset, - DILineInfoSpecifier LineInfoSpecifier, - bool UseSymbolTable) const override; - DIGlobal symbolizeData(object::SectionedAddress ModuleOffset) const override; - std::vector<DILocal> - symbolizeFrame(object::SectionedAddress ModuleOffset) const override; - - // Return true if this is a 32-bit x86 PE COFF module. - bool isWin32Module() const override; - - // Returns the preferred base of the module, i.e. where the loader would place - // it in memory assuming there were no conflicts. - uint64_t getModulePreferredBase() const override; - -private: - bool shouldOverrideWithSymbolTable(FunctionNameKind FNKind, - bool UseSymbolTable) const; - - bool getNameFromSymbolTable(object::SymbolRef::Type Type, uint64_t Address, - std::string &Name, uint64_t &Addr, - uint64_t &Size) const; - // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd - // (function descriptor) section and OpdExtractor refers to its contents. - Error addSymbol(const object::SymbolRef &Symbol, uint64_t SymbolSize, - DataExtractor *OpdExtractor = nullptr, - uint64_t OpdAddress = 0); - Error addCoffExportSymbols(const object::COFFObjectFile *CoffObj); - - /// Search for the first occurence of specified Address in ObjectFile. - uint64_t getModuleSectionIndexForAddress(uint64_t Address) const; - - const object::ObjectFile *Module; - std::unique_ptr<DIContext> DebugInfoContext; - bool UntagAddresses; - - struct SymbolDesc { - uint64_t Addr; - // If size is 0, assume that symbol occupies the whole memory range up to - // the following symbol. - uint64_t Size; - - bool operator<(const SymbolDesc &RHS) const { - return Addr != RHS.Addr ? Addr < RHS.Addr : Size < RHS.Size; - } - }; - std::vector<std::pair<SymbolDesc, StringRef>> Functions; - std::vector<std::pair<SymbolDesc, StringRef>> Objects; - - SymbolizableObjectFile(const object::ObjectFile *Obj, - std::unique_ptr<DIContext> DICtx, - bool UntagAddresses); -}; - -} // end namespace symbolize - -} // end namespace llvm - -#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H + +namespace llvm { + +class DataExtractor; + +namespace symbolize { + +class SymbolizableObjectFile : public SymbolizableModule { +public: + static Expected<std::unique_ptr<SymbolizableObjectFile>> + create(const object::ObjectFile *Obj, std::unique_ptr<DIContext> DICtx, + bool UntagAddresses); + + DILineInfo symbolizeCode(object::SectionedAddress ModuleOffset, + DILineInfoSpecifier LineInfoSpecifier, + bool UseSymbolTable) const override; + DIInliningInfo symbolizeInlinedCode(object::SectionedAddress ModuleOffset, + DILineInfoSpecifier LineInfoSpecifier, + bool UseSymbolTable) const override; + DIGlobal symbolizeData(object::SectionedAddress ModuleOffset) const override; + std::vector<DILocal> + symbolizeFrame(object::SectionedAddress ModuleOffset) const override; + + // Return true if this is a 32-bit x86 PE COFF module. + bool isWin32Module() const override; + + // Returns the preferred base of the module, i.e. where the loader would place + // it in memory assuming there were no conflicts. + uint64_t getModulePreferredBase() const override; + +private: + bool shouldOverrideWithSymbolTable(FunctionNameKind FNKind, + bool UseSymbolTable) const; + + bool getNameFromSymbolTable(object::SymbolRef::Type Type, uint64_t Address, + std::string &Name, uint64_t &Addr, + uint64_t &Size) const; + // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd + // (function descriptor) section and OpdExtractor refers to its contents. + Error addSymbol(const object::SymbolRef &Symbol, uint64_t SymbolSize, + DataExtractor *OpdExtractor = nullptr, + uint64_t OpdAddress = 0); + Error addCoffExportSymbols(const object::COFFObjectFile *CoffObj); + + /// Search for the first occurence of specified Address in ObjectFile. + uint64_t getModuleSectionIndexForAddress(uint64_t Address) const; + + const object::ObjectFile *Module; + std::unique_ptr<DIContext> DebugInfoContext; + bool UntagAddresses; + + struct SymbolDesc { + uint64_t Addr; + // If size is 0, assume that symbol occupies the whole memory range up to + // the following symbol. + uint64_t Size; + + bool operator<(const SymbolDesc &RHS) const { + return Addr != RHS.Addr ? Addr < RHS.Addr : Size < RHS.Size; + } + }; + std::vector<std::pair<SymbolDesc, StringRef>> Functions; + std::vector<std::pair<SymbolDesc, StringRef>> Objects; + + SymbolizableObjectFile(const object::ObjectFile *Obj, + std::unique_ptr<DIContext> DICtx, + bool UntagAddresses); +}; + +} // end namespace symbolize + +} // end namespace llvm + +#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H diff --git a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/Symbolize.cpp b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/Symbolize.cpp index da157a5a25..6142d0ed38 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/Symbolize.cpp +++ b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/Symbolize.cpp @@ -1,640 +1,640 @@ -//===-- LLVMSymbolize.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation for LLVM symbolization library. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/Symbolize/Symbolize.h" - -#include "SymbolizableObjectFile.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/BinaryFormat/COFF.h" +//===-- LLVMSymbolize.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation for LLVM symbolization library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Symbolize/Symbolize.h" + +#include "SymbolizableObjectFile.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Config/config.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/DebugInfo/PDB/PDB.h" -#include "llvm/DebugInfo/PDB/PDBContext.h" -#include "llvm/Demangle/Demangle.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/MachOUniversal.h" -#include "llvm/Support/CRC.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include <algorithm> -#include <cassert> -#include <cstring> - -namespace llvm { -namespace symbolize { - -Expected<DILineInfo> -LLVMSymbolizer::symbolizeCodeCommon(SymbolizableModule *Info, - object::SectionedAddress ModuleOffset) { - // A null module means an error has already been reported. Return an empty - // result. - if (!Info) - return DILineInfo(); - - // If the user is giving us relative addresses, add the preferred base of the - // object to the offset before we do the query. It's what DIContext expects. - if (Opts.RelativeAddresses) - ModuleOffset.Address += Info->getModulePreferredBase(); - - DILineInfo LineInfo = Info->symbolizeCode( - ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), - Opts.UseSymbolTable); - if (Opts.Demangle) - LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); - return LineInfo; -} - -Expected<DILineInfo> -LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj, - object::SectionedAddress ModuleOffset) { - StringRef ModuleName = Obj.getFileName(); - auto I = Modules.find(ModuleName); - if (I != Modules.end()) - return symbolizeCodeCommon(I->second.get(), ModuleOffset); - - std::unique_ptr<DIContext> Context = DWARFContext::create(Obj); - Expected<SymbolizableModule *> InfoOrErr = - createModuleInfo(&Obj, std::move(Context), ModuleName); - if (!InfoOrErr) - return InfoOrErr.takeError(); - return symbolizeCodeCommon(*InfoOrErr, ModuleOffset); -} - -Expected<DILineInfo> -LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, - object::SectionedAddress ModuleOffset) { - Expected<SymbolizableModule *> InfoOrErr = getOrCreateModuleInfo(ModuleName); - if (!InfoOrErr) - return InfoOrErr.takeError(); - return symbolizeCodeCommon(*InfoOrErr, ModuleOffset); -} - -Expected<DIInliningInfo> -LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, - object::SectionedAddress ModuleOffset) { - SymbolizableModule *Info; - if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) - Info = InfoOrErr.get(); - else - return InfoOrErr.takeError(); - - // A null module means an error has already been reported. Return an empty - // result. - if (!Info) - return DIInliningInfo(); - - // If the user is giving us relative addresses, add the preferred base of the - // object to the offset before we do the query. It's what DIContext expects. - if (Opts.RelativeAddresses) - ModuleOffset.Address += Info->getModulePreferredBase(); - - DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( - ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), - Opts.UseSymbolTable); - if (Opts.Demangle) { - for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { - auto *Frame = InlinedContext.getMutableFrame(i); - Frame->FunctionName = DemangleName(Frame->FunctionName, Info); - } - } - return InlinedContext; -} - -Expected<DIGlobal> -LLVMSymbolizer::symbolizeData(const std::string &ModuleName, - object::SectionedAddress ModuleOffset) { - SymbolizableModule *Info; - if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) - Info = InfoOrErr.get(); - else - return InfoOrErr.takeError(); - - // A null module means an error has already been reported. Return an empty - // result. - if (!Info) - return DIGlobal(); - - // If the user is giving us relative addresses, add the preferred base of - // the object to the offset before we do the query. It's what DIContext - // expects. - if (Opts.RelativeAddresses) - ModuleOffset.Address += Info->getModulePreferredBase(); - - DIGlobal Global = Info->symbolizeData(ModuleOffset); - if (Opts.Demangle) - Global.Name = DemangleName(Global.Name, Info); - return Global; -} - -Expected<std::vector<DILocal>> -LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName, - object::SectionedAddress ModuleOffset) { - SymbolizableModule *Info; - if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) - Info = InfoOrErr.get(); - else - return InfoOrErr.takeError(); - - // A null module means an error has already been reported. Return an empty - // result. - if (!Info) - return std::vector<DILocal>(); - - // If the user is giving us relative addresses, add the preferred base of - // the object to the offset before we do the query. It's what DIContext - // expects. - if (Opts.RelativeAddresses) - ModuleOffset.Address += Info->getModulePreferredBase(); - - return Info->symbolizeFrame(ModuleOffset); -} - -void LLVMSymbolizer::flush() { - ObjectForUBPathAndArch.clear(); - BinaryForPath.clear(); - ObjectPairForPathArch.clear(); - Modules.clear(); -} - -namespace { - -// For Path="/path/to/foo" and Basename="foo" assume that debug info is in -// /path/to/foo.dSYM/Contents/Resources/DWARF/foo. -// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in -// /path/to/bar.dSYM/Contents/Resources/DWARF/foo. -std::string getDarwinDWARFResourceForPath( - const std::string &Path, const std::string &Basename) { - SmallString<16> ResourceName = StringRef(Path); - if (sys::path::extension(Path) != ".dSYM") { - ResourceName += ".dSYM"; - } - sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); - sys::path::append(ResourceName, Basename); - return std::string(ResourceName.str()); -} - -bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - ErrorOr<std::unique_ptr<MemoryBuffer>> MB = - MemoryBuffer::getFileOrSTDIN(Path); - if (!MB) - return false; - return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer())); -} - -bool findDebugBinary(const std::string &OrigPath, - const std::string &DebuglinkName, uint32_t CRCHash, - const std::string &FallbackDebugPath, - std::string &Result) { - SmallString<16> OrigDir(OrigPath); - llvm::sys::path::remove_filename(OrigDir); - SmallString<16> DebugPath = OrigDir; - // Try relative/path/to/original_binary/debuglink_name - llvm::sys::path::append(DebugPath, DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = std::string(DebugPath.str()); - return true; - } - // Try relative/path/to/original_binary/.debug/debuglink_name - DebugPath = OrigDir; - llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = std::string(DebugPath.str()); - return true; - } - // Make the path absolute so that lookups will go to - // "/usr/lib/debug/full/path/to/debug", not - // "/usr/lib/debug/to/debug" - llvm::sys::fs::make_absolute(OrigDir); - if (!FallbackDebugPath.empty()) { - // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name - DebugPath = FallbackDebugPath; - } else { -#if defined(__NetBSD__) - // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name - DebugPath = "/usr/libdata/debug"; -#else - // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name - DebugPath = "/usr/lib/debug"; -#endif - } - llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), - DebuglinkName); - if (checkFileCRC(DebugPath, CRCHash)) { - Result = std::string(DebugPath.str()); - return true; - } - return false; -} - -bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, - uint32_t &CRCHash) { - if (!Obj) - return false; - for (const SectionRef &Section : Obj->sections()) { - StringRef Name; - if (Expected<StringRef> NameOrErr = Section.getName()) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - Name = Name.substr(Name.find_first_not_of("._")); - if (Name == "gnu_debuglink") { - Expected<StringRef> ContentsOrErr = Section.getContents(); - if (!ContentsOrErr) { - consumeError(ContentsOrErr.takeError()); - return false; - } - DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0); - uint64_t Offset = 0; - if (const char *DebugNameStr = DE.getCStr(&Offset)) { - // 4-byte align the offset. - Offset = (Offset + 3) & ~0x3; - if (DE.isValidOffsetForDataOfSize(Offset, 4)) { - DebugName = DebugNameStr; - CRCHash = DE.getU32(&Offset); - return true; - } - } - break; - } - } - return false; -} - -bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, - const MachOObjectFile *Obj) { - ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); - ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); - if (dbg_uuid.empty() || bin_uuid.empty()) - return false; - return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); -} - -template <typename ELFT> +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBContext.h" +#include "llvm/Demangle/Demangle.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Support/CRC.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include <algorithm> +#include <cassert> +#include <cstring> + +namespace llvm { +namespace symbolize { + +Expected<DILineInfo> +LLVMSymbolizer::symbolizeCodeCommon(SymbolizableModule *Info, + object::SectionedAddress ModuleOffset) { + // A null module means an error has already been reported. Return an empty + // result. + if (!Info) + return DILineInfo(); + + // If the user is giving us relative addresses, add the preferred base of the + // object to the offset before we do the query. It's what DIContext expects. + if (Opts.RelativeAddresses) + ModuleOffset.Address += Info->getModulePreferredBase(); + + DILineInfo LineInfo = Info->symbolizeCode( + ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), + Opts.UseSymbolTable); + if (Opts.Demangle) + LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info); + return LineInfo; +} + +Expected<DILineInfo> +LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj, + object::SectionedAddress ModuleOffset) { + StringRef ModuleName = Obj.getFileName(); + auto I = Modules.find(ModuleName); + if (I != Modules.end()) + return symbolizeCodeCommon(I->second.get(), ModuleOffset); + + std::unique_ptr<DIContext> Context = DWARFContext::create(Obj); + Expected<SymbolizableModule *> InfoOrErr = + createModuleInfo(&Obj, std::move(Context), ModuleName); + if (!InfoOrErr) + return InfoOrErr.takeError(); + return symbolizeCodeCommon(*InfoOrErr, ModuleOffset); +} + +Expected<DILineInfo> +LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, + object::SectionedAddress ModuleOffset) { + Expected<SymbolizableModule *> InfoOrErr = getOrCreateModuleInfo(ModuleName); + if (!InfoOrErr) + return InfoOrErr.takeError(); + return symbolizeCodeCommon(*InfoOrErr, ModuleOffset); +} + +Expected<DIInliningInfo> +LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName, + object::SectionedAddress ModuleOffset) { + SymbolizableModule *Info; + if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) + Info = InfoOrErr.get(); + else + return InfoOrErr.takeError(); + + // A null module means an error has already been reported. Return an empty + // result. + if (!Info) + return DIInliningInfo(); + + // If the user is giving us relative addresses, add the preferred base of the + // object to the offset before we do the query. It's what DIContext expects. + if (Opts.RelativeAddresses) + ModuleOffset.Address += Info->getModulePreferredBase(); + + DIInliningInfo InlinedContext = Info->symbolizeInlinedCode( + ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions), + Opts.UseSymbolTable); + if (Opts.Demangle) { + for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { + auto *Frame = InlinedContext.getMutableFrame(i); + Frame->FunctionName = DemangleName(Frame->FunctionName, Info); + } + } + return InlinedContext; +} + +Expected<DIGlobal> +LLVMSymbolizer::symbolizeData(const std::string &ModuleName, + object::SectionedAddress ModuleOffset) { + SymbolizableModule *Info; + if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) + Info = InfoOrErr.get(); + else + return InfoOrErr.takeError(); + + // A null module means an error has already been reported. Return an empty + // result. + if (!Info) + return DIGlobal(); + + // If the user is giving us relative addresses, add the preferred base of + // the object to the offset before we do the query. It's what DIContext + // expects. + if (Opts.RelativeAddresses) + ModuleOffset.Address += Info->getModulePreferredBase(); + + DIGlobal Global = Info->symbolizeData(ModuleOffset); + if (Opts.Demangle) + Global.Name = DemangleName(Global.Name, Info); + return Global; +} + +Expected<std::vector<DILocal>> +LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName, + object::SectionedAddress ModuleOffset) { + SymbolizableModule *Info; + if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName)) + Info = InfoOrErr.get(); + else + return InfoOrErr.takeError(); + + // A null module means an error has already been reported. Return an empty + // result. + if (!Info) + return std::vector<DILocal>(); + + // If the user is giving us relative addresses, add the preferred base of + // the object to the offset before we do the query. It's what DIContext + // expects. + if (Opts.RelativeAddresses) + ModuleOffset.Address += Info->getModulePreferredBase(); + + return Info->symbolizeFrame(ModuleOffset); +} + +void LLVMSymbolizer::flush() { + ObjectForUBPathAndArch.clear(); + BinaryForPath.clear(); + ObjectPairForPathArch.clear(); + Modules.clear(); +} + +namespace { + +// For Path="/path/to/foo" and Basename="foo" assume that debug info is in +// /path/to/foo.dSYM/Contents/Resources/DWARF/foo. +// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in +// /path/to/bar.dSYM/Contents/Resources/DWARF/foo. +std::string getDarwinDWARFResourceForPath( + const std::string &Path, const std::string &Basename) { + SmallString<16> ResourceName = StringRef(Path); + if (sys::path::extension(Path) != ".dSYM") { + ResourceName += ".dSYM"; + } + sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); + sys::path::append(ResourceName, Basename); + return std::string(ResourceName.str()); +} + +bool checkFileCRC(StringRef Path, uint32_t CRCHash) { + ErrorOr<std::unique_ptr<MemoryBuffer>> MB = + MemoryBuffer::getFileOrSTDIN(Path); + if (!MB) + return false; + return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer())); +} + +bool findDebugBinary(const std::string &OrigPath, + const std::string &DebuglinkName, uint32_t CRCHash, + const std::string &FallbackDebugPath, + std::string &Result) { + SmallString<16> OrigDir(OrigPath); + llvm::sys::path::remove_filename(OrigDir); + SmallString<16> DebugPath = OrigDir; + // Try relative/path/to/original_binary/debuglink_name + llvm::sys::path::append(DebugPath, DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + // Try relative/path/to/original_binary/.debug/debuglink_name + DebugPath = OrigDir; + llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + // Make the path absolute so that lookups will go to + // "/usr/lib/debug/full/path/to/debug", not + // "/usr/lib/debug/to/debug" + llvm::sys::fs::make_absolute(OrigDir); + if (!FallbackDebugPath.empty()) { + // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name + DebugPath = FallbackDebugPath; + } else { +#if defined(__NetBSD__) + // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name + DebugPath = "/usr/libdata/debug"; +#else + // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name + DebugPath = "/usr/lib/debug"; +#endif + } + llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), + DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = std::string(DebugPath.str()); + return true; + } + return false; +} + +bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName, + uint32_t &CRCHash) { + if (!Obj) + return false; + for (const SectionRef &Section : Obj->sections()) { + StringRef Name; + if (Expected<StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + Name = Name.substr(Name.find_first_not_of("._")); + if (Name == "gnu_debuglink") { + Expected<StringRef> ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) { + consumeError(ContentsOrErr.takeError()); + return false; + } + DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0); + uint64_t Offset = 0; + if (const char *DebugNameStr = DE.getCStr(&Offset)) { + // 4-byte align the offset. + Offset = (Offset + 3) & ~0x3; + if (DE.isValidOffsetForDataOfSize(Offset, 4)) { + DebugName = DebugNameStr; + CRCHash = DE.getU32(&Offset); + return true; + } + } + break; + } + } + return false; +} + +bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj, + const MachOObjectFile *Obj) { + ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid(); + ArrayRef<uint8_t> bin_uuid = Obj->getUuid(); + if (dbg_uuid.empty() || bin_uuid.empty()) + return false; + return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size()); +} + +template <typename ELFT> Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) { auto PhdrsOrErr = Obj.program_headers(); - if (!PhdrsOrErr) { - consumeError(PhdrsOrErr.takeError()); - return {}; - } - for (const auto &P : *PhdrsOrErr) { - if (P.p_type != ELF::PT_NOTE) - continue; - Error Err = Error::success(); + if (!PhdrsOrErr) { + consumeError(PhdrsOrErr.takeError()); + return {}; + } + for (const auto &P : *PhdrsOrErr) { + if (P.p_type != ELF::PT_NOTE) + continue; + Error Err = Error::success(); for (auto N : Obj.notes(P, Err)) - if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU) - return N.getDesc(); - consumeError(std::move(Err)); - } - return {}; -} - -Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) { - Optional<ArrayRef<uint8_t>> BuildID; - if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) - BuildID = getBuildID(O->getELFFile()); - else - llvm_unreachable("unsupported file format"); - return BuildID; -} - -bool findDebugBinary(const std::vector<std::string> &DebugFileDirectory, - const ArrayRef<uint8_t> BuildID, - std::string &Result) { - auto getDebugPath = [&](StringRef Directory) { - SmallString<128> Path{Directory}; - sys::path::append(Path, ".build-id", - llvm::toHex(BuildID[0], /*LowerCase=*/true), - llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); - Path += ".debug"; - return Path; - }; - if (DebugFileDirectory.empty()) { - SmallString<128> Path = getDebugPath( -#if defined(__NetBSD__) - // Try /usr/libdata/debug/.build-id/../... - "/usr/libdata/debug" -#else - // Try /usr/lib/debug/.build-id/../... - "/usr/lib/debug" -#endif - ); - if (llvm::sys::fs::exists(Path)) { - Result = std::string(Path.str()); - return true; - } - } else { - for (const auto &Directory : DebugFileDirectory) { - // Try <debug-file-directory>/.build-id/../... - SmallString<128> Path = getDebugPath(Directory); - if (llvm::sys::fs::exists(Path)) { - Result = std::string(Path.str()); - return true; - } - } - } - return false; -} - -} // end anonymous namespace - -ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, - const MachOObjectFile *MachExeObj, const std::string &ArchName) { - // On Darwin we may find DWARF in separate object file in - // resource directory. - std::vector<std::string> DsymPaths; - StringRef Filename = sys::path::filename(ExePath); - DsymPaths.push_back( - getDarwinDWARFResourceForPath(ExePath, std::string(Filename))); - for (const auto &Path : Opts.DsymHints) { - DsymPaths.push_back( - getDarwinDWARFResourceForPath(Path, std::string(Filename))); - } - for (const auto &Path : DsymPaths) { - auto DbgObjOrErr = getOrCreateObject(Path, ArchName); - if (!DbgObjOrErr) { - // Ignore errors, the file might not exist. - consumeError(DbgObjOrErr.takeError()); - continue; - } - ObjectFile *DbgObj = DbgObjOrErr.get(); - if (!DbgObj) - continue; - const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj); - if (!MachDbgObj) - continue; - if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) - return DbgObj; - } - return nullptr; -} - -ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, - const ObjectFile *Obj, - const std::string &ArchName) { - std::string DebuglinkName; - uint32_t CRCHash; - std::string DebugBinaryPath; - if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) - return nullptr; - if (!findDebugBinary(Path, DebuglinkName, CRCHash, Opts.FallbackDebugPath, - DebugBinaryPath)) - return nullptr; - auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); - if (!DbgObjOrErr) { - // Ignore errors, the file might not exist. - consumeError(DbgObjOrErr.takeError()); - return nullptr; - } - return DbgObjOrErr.get(); -} - -ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path, - const ELFObjectFileBase *Obj, - const std::string &ArchName) { - auto BuildID = getBuildID(Obj); - if (!BuildID) - return nullptr; - if (BuildID->size() < 2) - return nullptr; - std::string DebugBinaryPath; - if (!findDebugBinary(Opts.DebugFileDirectory, *BuildID, DebugBinaryPath)) - return nullptr; - auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); - if (!DbgObjOrErr) { - consumeError(DbgObjOrErr.takeError()); - return nullptr; - } - return DbgObjOrErr.get(); -} - -Expected<LLVMSymbolizer::ObjectPair> -LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, - const std::string &ArchName) { - auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); - if (I != ObjectPairForPathArch.end()) - return I->second; - - auto ObjOrErr = getOrCreateObject(Path, ArchName); - if (!ObjOrErr) { - ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), - ObjectPair(nullptr, nullptr)); - return ObjOrErr.takeError(); - } - - ObjectFile *Obj = ObjOrErr.get(); - assert(Obj != nullptr); - ObjectFile *DbgObj = nullptr; - - if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) - DbgObj = lookUpDsymFile(Path, MachObj, ArchName); - else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj)) - DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName); - if (!DbgObj) - DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); - if (!DbgObj) - DbgObj = Obj; - ObjectPair Res = std::make_pair(Obj, DbgObj); - ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); - return Res; -} - -Expected<ObjectFile *> -LLVMSymbolizer::getOrCreateObject(const std::string &Path, - const std::string &ArchName) { - Binary *Bin; - auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); - if (!Pair.second) { - Bin = Pair.first->second.getBinary(); - } else { - Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); - if (!BinOrErr) - return BinOrErr.takeError(); - Pair.first->second = std::move(BinOrErr.get()); - Bin = Pair.first->second.getBinary(); - } - - if (!Bin) - return static_cast<ObjectFile *>(nullptr); - - if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { - auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); - if (I != ObjectForUBPathAndArch.end()) - return I->second.get(); - - Expected<std::unique_ptr<ObjectFile>> ObjOrErr = - UB->getMachOObjectForArch(ArchName); - if (!ObjOrErr) { - ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), - std::unique_ptr<ObjectFile>()); - return ObjOrErr.takeError(); - } - ObjectFile *Res = ObjOrErr->get(); - ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), - std::move(ObjOrErr.get())); - return Res; - } - if (Bin->isObject()) { - return cast<ObjectFile>(Bin); - } - return errorCodeToError(object_error::arch_not_found); -} - -Expected<SymbolizableModule *> -LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj, - std::unique_ptr<DIContext> Context, - StringRef ModuleName) { - auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context), - Opts.UntagAddresses); - std::unique_ptr<SymbolizableModule> SymMod; - if (InfoOrErr) - SymMod = std::move(*InfoOrErr); - auto InsertResult = Modules.insert( - std::make_pair(std::string(ModuleName), std::move(SymMod))); - assert(InsertResult.second); - if (!InfoOrErr) - return InfoOrErr.takeError(); - return InsertResult.first->second.get(); -} - -Expected<SymbolizableModule *> -LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { - auto I = Modules.find(ModuleName); - if (I != Modules.end()) - return I->second.get(); - - std::string BinaryName = ModuleName; - std::string ArchName = Opts.DefaultArch; - size_t ColonPos = ModuleName.find_last_of(':'); - // Verify that substring after colon form a valid arch name. - if (ColonPos != std::string::npos) { - std::string ArchStr = ModuleName.substr(ColonPos + 1); - if (Triple(ArchStr).getArch() != Triple::UnknownArch) { - BinaryName = ModuleName.substr(0, ColonPos); - ArchName = ArchStr; - } - } - auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); - if (!ObjectsOrErr) { - // Failed to find valid object file. - Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); - return ObjectsOrErr.takeError(); - } - ObjectPair Objects = ObjectsOrErr.get(); - - std::unique_ptr<DIContext> Context; - // 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 codeview::DebugInfo *DebugInfo; - StringRef PDBFileName; - auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName); - if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) { - using namespace pdb; - std::unique_ptr<IPDBSession> Session; + if (N.getType() == ELF::NT_GNU_BUILD_ID && N.getName() == ELF::ELF_NOTE_GNU) + return N.getDesc(); + consumeError(std::move(Err)); + } + return {}; +} + +Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) { + Optional<ArrayRef<uint8_t>> BuildID; + if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj)) + BuildID = getBuildID(O->getELFFile()); + else + llvm_unreachable("unsupported file format"); + return BuildID; +} + +bool findDebugBinary(const std::vector<std::string> &DebugFileDirectory, + const ArrayRef<uint8_t> BuildID, + std::string &Result) { + auto getDebugPath = [&](StringRef Directory) { + SmallString<128> Path{Directory}; + sys::path::append(Path, ".build-id", + llvm::toHex(BuildID[0], /*LowerCase=*/true), + llvm::toHex(BuildID.slice(1), /*LowerCase=*/true)); + Path += ".debug"; + return Path; + }; + if (DebugFileDirectory.empty()) { + SmallString<128> Path = getDebugPath( +#if defined(__NetBSD__) + // Try /usr/libdata/debug/.build-id/../... + "/usr/libdata/debug" +#else + // Try /usr/lib/debug/.build-id/../... + "/usr/lib/debug" +#endif + ); + if (llvm::sys::fs::exists(Path)) { + Result = std::string(Path.str()); + return true; + } + } else { + for (const auto &Directory : DebugFileDirectory) { + // Try <debug-file-directory>/.build-id/../... + SmallString<128> Path = getDebugPath(Directory); + if (llvm::sys::fs::exists(Path)) { + Result = std::string(Path.str()); + return true; + } + } + } + return false; +} + +} // end anonymous namespace + +ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath, + const MachOObjectFile *MachExeObj, const std::string &ArchName) { + // On Darwin we may find DWARF in separate object file in + // resource directory. + std::vector<std::string> DsymPaths; + StringRef Filename = sys::path::filename(ExePath); + DsymPaths.push_back( + getDarwinDWARFResourceForPath(ExePath, std::string(Filename))); + for (const auto &Path : Opts.DsymHints) { + DsymPaths.push_back( + getDarwinDWARFResourceForPath(Path, std::string(Filename))); + } + for (const auto &Path : DsymPaths) { + auto DbgObjOrErr = getOrCreateObject(Path, ArchName); + if (!DbgObjOrErr) { + // Ignore errors, the file might not exist. + consumeError(DbgObjOrErr.takeError()); + continue; + } + ObjectFile *DbgObj = DbgObjOrErr.get(); + if (!DbgObj) + continue; + const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj); + if (!MachDbgObj) + continue; + if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) + return DbgObj; + } + return nullptr; +} + +ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path, + const ObjectFile *Obj, + const std::string &ArchName) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash)) + return nullptr; + if (!findDebugBinary(Path, DebuglinkName, CRCHash, Opts.FallbackDebugPath, + DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) { + // Ignore errors, the file might not exist. + consumeError(DbgObjOrErr.takeError()); + return nullptr; + } + return DbgObjOrErr.get(); +} + +ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path, + const ELFObjectFileBase *Obj, + const std::string &ArchName) { + auto BuildID = getBuildID(Obj); + if (!BuildID) + return nullptr; + if (BuildID->size() < 2) + return nullptr; + std::string DebugBinaryPath; + if (!findDebugBinary(Opts.DebugFileDirectory, *BuildID, DebugBinaryPath)) + return nullptr; + auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName); + if (!DbgObjOrErr) { + consumeError(DbgObjOrErr.takeError()); + return nullptr; + } + return DbgObjOrErr.get(); +} + +Expected<LLVMSymbolizer::ObjectPair> +LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path, + const std::string &ArchName) { + auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectPairForPathArch.end()) + return I->second; + + auto ObjOrErr = getOrCreateObject(Path, ArchName); + if (!ObjOrErr) { + ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), + ObjectPair(nullptr, nullptr)); + return ObjOrErr.takeError(); + } + + ObjectFile *Obj = ObjOrErr.get(); + assert(Obj != nullptr); + ObjectFile *DbgObj = nullptr; + + if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj)) + DbgObj = lookUpDsymFile(Path, MachObj, ArchName); + else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj)) + DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName); + if (!DbgObj) + DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName); + if (!DbgObj) + DbgObj = Obj; + ObjectPair Res = std::make_pair(Obj, DbgObj); + ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res); + return Res; +} + +Expected<ObjectFile *> +LLVMSymbolizer::getOrCreateObject(const std::string &Path, + const std::string &ArchName) { + Binary *Bin; + auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>()); + if (!Pair.second) { + Bin = Pair.first->second.getBinary(); + } else { + Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); + if (!BinOrErr) + return BinOrErr.takeError(); + Pair.first->second = std::move(BinOrErr.get()); + Bin = Pair.first->second.getBinary(); + } + + if (!Bin) + return static_cast<ObjectFile *>(nullptr); + + if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) { + auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); + if (I != ObjectForUBPathAndArch.end()) + return I->second.get(); + + Expected<std::unique_ptr<ObjectFile>> ObjOrErr = + UB->getMachOObjectForArch(ArchName); + if (!ObjOrErr) { + ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), + std::unique_ptr<ObjectFile>()); + return ObjOrErr.takeError(); + } + ObjectFile *Res = ObjOrErr->get(); + ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName), + std::move(ObjOrErr.get())); + return Res; + } + if (Bin->isObject()) { + return cast<ObjectFile>(Bin); + } + return errorCodeToError(object_error::arch_not_found); +} + +Expected<SymbolizableModule *> +LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj, + std::unique_ptr<DIContext> Context, + StringRef ModuleName) { + auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context), + Opts.UntagAddresses); + std::unique_ptr<SymbolizableModule> SymMod; + if (InfoOrErr) + SymMod = std::move(*InfoOrErr); + auto InsertResult = Modules.insert( + std::make_pair(std::string(ModuleName), std::move(SymMod))); + assert(InsertResult.second); + if (!InfoOrErr) + return InfoOrErr.takeError(); + return InsertResult.first->second.get(); +} + +Expected<SymbolizableModule *> +LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { + auto I = Modules.find(ModuleName); + if (I != Modules.end()) + return I->second.get(); + + std::string BinaryName = ModuleName; + std::string ArchName = Opts.DefaultArch; + size_t ColonPos = ModuleName.find_last_of(':'); + // Verify that substring after colon form a valid arch name. + if (ColonPos != std::string::npos) { + std::string ArchStr = ModuleName.substr(ColonPos + 1); + if (Triple(ArchStr).getArch() != Triple::UnknownArch) { + BinaryName = ModuleName.substr(0, ColonPos); + ArchName = ArchStr; + } + } + auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName); + if (!ObjectsOrErr) { + // Failed to find valid object file. + Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); + return ObjectsOrErr.takeError(); + } + ObjectPair Objects = ObjectsOrErr.get(); + + std::unique_ptr<DIContext> Context; + // 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 codeview::DebugInfo *DebugInfo; + StringRef PDBFileName; + auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName); + if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) { + using namespace pdb; + std::unique_ptr<IPDBSession> Session; PDB_ReaderType ReaderType = Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native; - if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(), - Session)) { - Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); - // Return along the PDB filename to provide more context - return createFileError(PDBFileName, std::move(Err)); - } - Context.reset(new PDBContext(*CoffObject, std::move(Session))); - } - } - if (!Context) - Context = DWARFContext::create(*Objects.second, nullptr, Opts.DWPName); - return createModuleInfo(Objects.first, std::move(Context), ModuleName); -} - -namespace { - -// Undo these various manglings for Win32 extern "C" functions: -// cdecl - _foo -// stdcall - _foo@12 -// fastcall - @foo@12 -// vectorcall - foo@@12 -// These are all different linkage names for 'foo'. -StringRef demanglePE32ExternCFunc(StringRef SymbolName) { - // Remove any '_' or '@' prefix. - char Front = SymbolName.empty() ? '\0' : SymbolName[0]; - if (Front == '_' || Front == '@') - SymbolName = SymbolName.drop_front(); - - // Remove any '@[0-9]+' suffix. - if (Front != '?') { - size_t AtPos = SymbolName.rfind('@'); - if (AtPos != StringRef::npos && + if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(), + Session)) { + Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>()); + // Return along the PDB filename to provide more context + return createFileError(PDBFileName, std::move(Err)); + } + Context.reset(new PDBContext(*CoffObject, std::move(Session))); + } + } + if (!Context) + Context = DWARFContext::create(*Objects.second, nullptr, Opts.DWPName); + return createModuleInfo(Objects.first, std::move(Context), ModuleName); +} + +namespace { + +// Undo these various manglings for Win32 extern "C" functions: +// cdecl - _foo +// stdcall - _foo@12 +// fastcall - @foo@12 +// vectorcall - foo@@12 +// These are all different linkage names for 'foo'. +StringRef demanglePE32ExternCFunc(StringRef SymbolName) { + // Remove any '_' or '@' prefix. + char Front = SymbolName.empty() ? '\0' : SymbolName[0]; + if (Front == '_' || Front == '@') + SymbolName = SymbolName.drop_front(); + + // Remove any '@[0-9]+' suffix. + if (Front != '?') { + size_t AtPos = SymbolName.rfind('@'); + if (AtPos != StringRef::npos && all_of(drop_begin(SymbolName, AtPos + 1), isDigit)) - SymbolName = SymbolName.substr(0, AtPos); - } - - // Remove any ending '@' for vectorcall. - if (SymbolName.endswith("@")) - SymbolName = SymbolName.drop_back(); - - return SymbolName; -} - -} // end anonymous namespace - -std::string -LLVMSymbolizer::DemangleName(const std::string &Name, - const SymbolizableModule *DbiModuleDescriptor) { - // We can spoil names of symbols with C linkage, so use an heuristic - // approach to check if the name should be demangled. - if (Name.substr(0, 2) == "_Z") { - int status = 0; - char *DemangledName = itaniumDemangle(Name.c_str(), nullptr, nullptr, &status); - if (status != 0) - return Name; - std::string Result = DemangledName; - free(DemangledName); - return Result; - } - - if (!Name.empty() && Name.front() == '?') { - // Only do MSVC C++ demangling on symbols starting with '?'. - int status = 0; - char *DemangledName = microsoftDemangle( - Name.c_str(), nullptr, nullptr, nullptr, &status, - MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention | - MSDF_NoMemberType | MSDF_NoReturnType)); - if (status != 0) - return Name; - std::string Result = DemangledName; - free(DemangledName); - return Result; - } - - if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) - return std::string(demanglePE32ExternCFunc(Name)); - return Name; -} - -} // namespace symbolize -} // namespace llvm + SymbolName = SymbolName.substr(0, AtPos); + } + + // Remove any ending '@' for vectorcall. + if (SymbolName.endswith("@")) + SymbolName = SymbolName.drop_back(); + + return SymbolName; +} + +} // end anonymous namespace + +std::string +LLVMSymbolizer::DemangleName(const std::string &Name, + const SymbolizableModule *DbiModuleDescriptor) { + // We can spoil names of symbols with C linkage, so use an heuristic + // approach to check if the name should be demangled. + if (Name.substr(0, 2) == "_Z") { + int status = 0; + char *DemangledName = itaniumDemangle(Name.c_str(), nullptr, nullptr, &status); + if (status != 0) + return Name; + std::string Result = DemangledName; + free(DemangledName); + return Result; + } + + if (!Name.empty() && Name.front() == '?') { + // Only do MSVC C++ demangling on symbols starting with '?'. + int status = 0; + char *DemangledName = microsoftDemangle( + Name.c_str(), nullptr, nullptr, nullptr, &status, + MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention | + MSDF_NoMemberType | MSDF_NoReturnType)); + if (status != 0) + return Name; + std::string Result = DemangledName; + free(DemangledName); + return Result; + } + + if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module()) + return std::string(demanglePE32ExternCFunc(Name)); + return Name; +} + +} // namespace symbolize +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/ya.make b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/ya.make index b627533f82..a64d342a87 100644 --- a/contrib/libs/llvm12/lib/DebugInfo/Symbolize/ya.make +++ b/contrib/libs/llvm12/lib/DebugInfo/Symbolize/ya.make @@ -1,37 +1,37 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/DebugInfo/DWARF contrib/libs/llvm12/lib/DebugInfo/PDB contrib/libs/llvm12/lib/Demangle contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/DebugInfo/Symbolize ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - DIPrinter.cpp - SymbolizableObjectFile.cpp - Symbolize.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + DIPrinter.cpp + SymbolizableObjectFile.cpp + Symbolize.cpp +) + +END() |