diff --git a/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index fe0e1efe41b7..930ac6930c24 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -11,151 +11,31 @@ #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H #include "llvm/DebugInfo/CodeView/CVRecord.h" -#include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/Support/ErrorOr.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Error.h" namespace llvm { namespace codeview { -template class CVTypeVisitor { public: - CVTypeVisitor() {} + explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks); - bool hadError() const { return HadError; } - - template - bool consumeObject(ArrayRef &Data, const T *&Res) { - if (Data.size() < sizeof(*Res)) { - HadError = true; - return false; - } - Res = reinterpret_cast(Data.data()); - Data = Data.drop_front(sizeof(*Res)); - return true; - } - - /// Actions to take on known types. By default, they do nothing. Visit methods - /// for member records take the FieldData by non-const reference and are - /// expected to consume the trailing bytes used by the field. - /// FIXME: Make the visitor interpret the trailing bytes so that clients don't - /// need to. -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record) {} -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record) {} -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "TypeRecords.def" - - void visitTypeRecord(const CVRecord &Record) { - ArrayRef LeafData = Record.Data; - auto *DerivedThis = static_cast(this); - DerivedThis->visitTypeBegin(Record); - switch (Record.Type) { - default: - DerivedThis->visitUnknownType(Record); - break; - case LF_FIELDLIST: - DerivedThis->visitFieldList(Record.Type, LeafData); - break; -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - TypeRecordKind RK = static_cast(EnumName); \ - auto Result = Name##Record::deserialize(RK, LeafData); \ - if (Result.getError()) \ - return parseError(); \ - DerivedThis->visit##Name(*Result); \ - break; \ - } -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - TYPE_RECORD(EnumVal, EnumVal, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) -#include "TypeRecords.def" - } - DerivedThis->visitTypeEnd(Record); - } + Error visitTypeRecord(const CVRecord &Record); /// Visits the type records in Data. Sets the error flag on parse failures. - void visitTypeStream(const CVTypeArray &Types) { - for (const auto &I : Types) { - visitTypeRecord(I); - if (hadError()) - break; - } - } + Error visitTypeStream(const CVTypeArray &Types); - /// Action to take on unknown types. By default, they are ignored. - void visitUnknownType(const CVRecord &Record) {} - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - void visitTypeBegin(const CVRecord &Record) {} - void visitTypeEnd(const CVRecord &Record) {} - - ArrayRef skipPadding(ArrayRef Data) { - if (Data.empty()) - return Data; - uint8_t Leaf = Data.front(); - if (Leaf < LF_PAD0) - return Data; - // Leaf is greater than 0xf0. We should advance by the number of bytes in - // the low 4 bits. - unsigned BytesToAdvance = Leaf & 0x0F; - if (Data.size() < BytesToAdvance) { - parseError(); - return None; - } - return Data.drop_front(BytesToAdvance); - } + Error skipPadding(ArrayRef &Data); /// Visits individual member records of a field list record. Member records do /// not describe their own length, and need special handling. - void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData) { - auto *DerivedThis = static_cast(this); - while (!FieldData.empty()) { - const ulittle16_t *LeafPtr; - if (!CVTypeVisitor::consumeObject(FieldData, LeafPtr)) - return; - TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); - switch (Leaf) { - default: - // Field list records do not describe their own length, so we cannot - // continue parsing past an unknown member type. - DerivedThis->visitUnknownMember(Leaf); - return parseError(); -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - TypeRecordKind RK = static_cast(EnumName); \ - auto Result = Name##Record::deserialize(RK, FieldData); \ - if (Result.getError()) \ - return parseError(); \ - DerivedThis->visit##Name(*Result); \ - break; \ - } -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - MEMBER_RECORD(EnumVal, EnumVal, AliasName) -#include "TypeRecords.def" - } - FieldData = skipPadding(FieldData); - if (hadError()) - break; - } - } - - /// Action to take on unknown members. By default, they are ignored. Member - /// record parsing cannot recover from an unknown member record, so this - /// method is only called at most once per field list record. - void visitUnknownMember(TypeLeafKind Leaf) {} - - /// Helper for returning from a void function when the stream is corrupted. - void parseError() { HadError = true; } + Error visitFieldList(const CVRecord &Record); private: - /// Whether a type stream parsing error was encountered. - bool HadError = false; + /// The interface to the class that gets notified of each visitation. + TypeVisitorCallbacks &Callbacks; }; } // end namespace codeview diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeDumper.h b/llvm/include/llvm/DebugInfo/CodeView/TypeDumper.h index a5e359fd5867..ca79ab076e5e 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeDumper.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -14,6 +14,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" namespace llvm { class ScopedPrinter; @@ -21,7 +22,7 @@ class ScopedPrinter; namespace codeview { /// Dumper for CodeView type streams found in COFF object files and PDB files. -class CVTypeDumper { +class CVTypeDumper : public TypeVisitorCallbacks { public: CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes) : W(W), PrintRecordBytes(PrintRecordBytes) {} @@ -33,17 +34,17 @@ public: /// and true otherwise. This should be called in order, since the dumper /// maintains state about previous records which are necessary for cross /// type references. - bool dump(const CVRecord &Record); + Error dump(const CVRecord &Record); /// Dumps the type records in Types. Returns false if there was a type stream /// parse error, and true otherwise. - bool dump(const CVTypeArray &Types); + Error dump(const CVTypeArray &Types); /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. Use this method instead of the /// CVTypeArray overload when type records are laid out contiguously in /// memory. - bool dump(ArrayRef Data); + Error dump(ArrayRef Data); /// Gets the type index for the next type record. unsigned getNextTypeIndex() const { @@ -61,11 +62,35 @@ public: void setPrinter(ScopedPrinter *P); ScopedPrinter *getPrinter() { return W; } + /// Action to take on unknown types. By default, they are ignored. + Error visitUnknownType(const CVRecord &Record) override; + Error visitUnknownMember(const CVRecord &Record) override; + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(const CVRecord &Record) override; + Error visitTypeEnd(const CVRecord &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visit##Name(Name##Record &Record) override; +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" + private: + void printMemberAttributes(MemberAttributes Attrs); + void printMemberAttributes(MemberAccess Access, MethodKind Kind, + MethodOptions Options); + ScopedPrinter *W; bool PrintRecordBytes = false; + /// Name of the current type. Only valid before visitTypeEnd. + StringRef Name; + /// All user defined type records in .debug$T live in here. Type indices /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to /// index into this vector. diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def b/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def index 5f10b72c5301..41fbeaa5be6d 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecords.def @@ -83,6 +83,7 @@ TYPE_RECORD(LF_STRING_ID, 0x1605, StringId) TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine) TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine) + TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList) @@ -195,6 +196,8 @@ CV_TYPE(LF_MODIFIER_EX, 0x1518) CV_TYPE(LF_VECTOR, 0x151b) CV_TYPE(LF_MATRIX, 0x151c) +// ID leaf records. Subsequent leaf types may be referenced from .debug$S. + // Numeric leaf types. These are generally contained in other records, and not // encountered in the main type stream. diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h b/llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h new file mode 100644 index 000000000000..51aae4fb8edf --- /dev/null +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h @@ -0,0 +1,61 @@ +//===- TypeVisitorCallbacks.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace codeview { +class TypeVisitorCallbacks { + friend class CVTypeVisitor; + +public: + virtual ~TypeVisitorCallbacks() {} + + /// Action to take on unknown types. By default, they are ignored. + virtual Error visitUnknownType(const CVRecord &Record) { + return Error::success(); + } + virtual Error visitUnknownMember(const CVRecord &Record) { + return Error::success(); + } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + virtual Error visitTypeBegin(const CVRecord &Record) { + return Error::success(); + } + virtual Error visitTypeEnd(const CVRecord &Record) { + return Error::success(); + } + + virtual Error visitFieldListBegin(const CVRecord &Record) { + return Error::success(); + } + + virtual Error visitFieldListEnd(const CVRecord &Record) { + return Error::success(); + } + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + virtual Error visit##Name(Name##Record &Record) { return Error::success(); } +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#include "TypeRecords.def" +}; +} +} + +#endif \ No newline at end of file diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h b/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h index 076f75ba0319..b0687cddbf48 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -25,6 +25,7 @@ enum class raw_error_code { index_out_of_bounds, invalid_block_address, not_writable, + invalid_tpi_hash, }; /// Base class for errors originating when parsing raw PDB files diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index ff719b242c4f..d798901be1c2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -322,10 +322,9 @@ void CodeViewDebug::emitTypeInformation() { ScopedPrinter SP(CommentOS); SP.setPrefix(CommentPrefix); CVTD.setPrinter(&SP); - bool DumpSuccess = - CVTD.dump({Record.bytes_begin(), Record.bytes_end()}); - (void)DumpSuccess; - assert(DumpSuccess && "produced malformed type record"); + Error EC = CVTD.dump({Record.bytes_begin(), Record.bytes_end()}); + assert(!EC && "produced malformed type record"); + consumeError(std::move(EC)); // emitRawComment will insert its own tab and comment string before // the first line, so strip off our first one. It also prints its own // newline. diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 4393f9c52ee4..47297a9131ee 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMDebugInfoCodeView ByteStream.cpp CodeViewError.cpp + CVTypeVisitor.cpp EnumTables.cpp FieldListRecordBuilder.cpp Line.cpp diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp new file mode 100644 index 000000000000..09f72214c52b --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -0,0 +1,123 @@ +//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" + +using namespace llvm; +using namespace llvm::codeview; + +template +static Error takeObject(ArrayRef &Data, const T *&Res) { + if (Data.size() < sizeof(*Res)) + return llvm::make_error(cv_error_code::insufficient_buffer); + Res = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(*Res)); + return Error::success(); +} + +CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) + : Callbacks(Callbacks) {} + +Error CVTypeVisitor::visitTypeRecord(const CVRecord &Record) { + ArrayRef LeafData = Record.Data; + if (auto EC = Callbacks.visitTypeBegin(Record)) + return EC; + switch (Record.Type) { + default: + if (auto EC = Callbacks.visitUnknownType(Record)) + return EC; + break; + case LF_FIELDLIST: + if (auto EC = Callbacks.visitFieldListBegin(Record)) + return EC; + if (auto EC = visitFieldList(Record)) + return EC; + if (auto EC = Callbacks.visitFieldListEnd(Record)) + return EC; + break; +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + TypeRecordKind RK = static_cast(EnumName); \ + auto Result = Name##Record::deserialize(RK, LeafData); \ + if (Result.getError()) \ + return llvm::make_error(cv_error_code::corrupt_record); \ + if (auto EC = Callbacks.visit##Name(*Result)) \ + return EC; \ + break; \ + } +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + TYPE_RECORD(EnumVal, EnumVal, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + } + if (auto EC = Callbacks.visitTypeEnd(Record)) + return EC; + return Error::success(); +} + +/// Visits the type records in Data. Sets the error flag on parse failures. +Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { + for (const auto &I : Types) { + if (auto EC = visitTypeRecord(I)) + return EC; + } + return Error::success(); +} + +Error CVTypeVisitor::skipPadding(ArrayRef &Data) { + if (Data.empty()) + return Error::success(); + uint8_t Leaf = Data.front(); + if (Leaf < LF_PAD0) + return Error::success(); + // Leaf is greater than 0xf0. We should advance by the number of bytes in + // the low 4 bits. + unsigned BytesToAdvance = Leaf & 0x0F; + if (Data.size() < BytesToAdvance) { + return llvm::make_error(cv_error_code::corrupt_record, + "Invalid padding bytes!"); + } + Data = Data.drop_front(BytesToAdvance); + return Error::success(); +} + +/// Visits individual member records of a field list record. Member records do +/// not describe their own length, and need special handling. +Error CVTypeVisitor::visitFieldList(const CVRecord &Record) { + ArrayRef RecordData = Record.Data; + while (!RecordData.empty()) { + const ulittle16_t *LeafPtr; + if (auto EC = takeObject(RecordData, LeafPtr)) + return EC; + TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); + switch (Leaf) { + default: + // Field list records do not describe their own length, so we cannot + // continue parsing past an unknown member type. + if (auto EC = Callbacks.visitUnknownMember(Record)) + return llvm::make_error(cv_error_code::corrupt_record); +#define MEMBER_RECORD(EnumName, EnumVal, Name) \ + case EnumName: { \ + TypeRecordKind RK = static_cast(EnumName); \ + auto Result = Name##Record::deserialize(RK, RecordData); \ + if (Result.getError()) \ + return llvm::make_error(cv_error_code::corrupt_record); \ + if (auto EC = Callbacks.visit##Name(*Result)) \ + return EC; \ + break; \ + } +#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ + MEMBER_RECORD(EnumVal, EnumVal, AliasName) +#include "llvm/DebugInfo/CodeView/TypeRecords.def" + } + if (auto EC = skipPadding(RecordData)) + return EC; + } + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index b181ffb7c4dc..0653d8141555 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -189,55 +189,6 @@ static const EnumEntry FunctionOptionEnum[] = { #undef ENUM_ENTRY - -namespace { - -/// Use this private dumper implementation to keep implementation details about -/// the visitor out of TypeDumper.h. -class CVTypeDumperImpl : public CVTypeVisitor { -public: - CVTypeDumperImpl(CVTypeDumper &CVTD, ScopedPrinter &W, bool PrintRecordBytes) - : CVTD(CVTD), W(W), PrintRecordBytes(PrintRecordBytes) {} - - /// CVTypeVisitor overrides. -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record); -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record); -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - - void visitUnknownMember(TypeLeafKind Leaf); - void visitUnknownType(const CVRecord &Record); - - void visitTypeBegin(const CVRecord &Record); - void visitTypeEnd(const CVRecord &Record); - - void printMemberAttributes(MemberAttributes Attrs); - void printMemberAttributes(MemberAccess Access, MethodKind Kind, - MethodOptions Options); - -private: - /// Forwards to the dumper, which holds the persistent state from visitation. - StringRef getTypeName(TypeIndex TI) { - return CVTD.getTypeName(TI); - } - - void printTypeIndex(StringRef FieldName, TypeIndex TI) { - CVTD.printTypeIndex(FieldName, TI); - } - - CVTypeDumper &CVTD; - ScopedPrinter &W; - bool PrintRecordBytes = false; - - /// Name of the current type. Only valid before visitTypeEnd. - StringRef Name; -}; - -} // end anonymous namespace - static StringRef getLeafTypeName(TypeLeafKind LT) { switch (LT) { #define TYPE_RECORD(ename, value, name) \ @@ -250,39 +201,44 @@ static StringRef getLeafTypeName(TypeLeafKind LT) { return "UnknownLeaf"; } -void CVTypeDumperImpl::visitTypeBegin(const CVRecord &Rec) { +Error CVTypeDumper::visitTypeBegin(const CVRecord &Record) { // Reset Name to the empty string. If the visitor sets it, we know it. Name = ""; - W.startLine() << getLeafTypeName(Rec.Type) << " (" - << HexNumber(CVTD.getNextTypeIndex()) << ") {\n"; - W.indent(); - W.printEnum("TypeLeafKind", unsigned(Rec.Type), makeArrayRef(LeafTypeNames)); + W->startLine() << getLeafTypeName(Record.Type) << " (" + << HexNumber(getNextTypeIndex()) << ") {\n"; + W->indent(); + W->printEnum("TypeLeafKind", unsigned(Record.Type), + makeArrayRef(LeafTypeNames)); + return Error::success(); } -void CVTypeDumperImpl::visitTypeEnd(const CVRecord &Rec) { +Error CVTypeDumper::visitTypeEnd(const CVRecord &Record) { // Always record some name for every type, even if Name is empty. CVUDTNames // is indexed by type index, and must have one entry for every type. - CVTD.recordType(Name); - if (PrintRecordBytes) - W.printBinaryBlock("LeafData", getBytesAsCharacters(Rec.Data)); + recordType(Name); - W.unindent(); - W.startLine() << "}\n"; + if (PrintRecordBytes) + W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data)); + + W->unindent(); + W->startLine() << "}\n"; + return Error::success(); } -void CVTypeDumperImpl::visitStringId(StringIdRecord &String) { +Error CVTypeDumper::visitStringId(StringIdRecord &String) { printTypeIndex("Id", String.getId()); - W.printString("StringData", String.getString()); + W->printString("StringData", String.getString()); // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. Name = String.getString(); + return Error::success(); } -void CVTypeDumperImpl::visitArgList(ArgListRecord &Args) { +Error CVTypeDumper::visitArgList(ArgListRecord &Args) { auto Indices = Args.getIndices(); uint32_t Size = Indices.size(); - W.printNumber("NumArgs", Size); - ListScope Arguments(W, "Arguments"); + W->printNumber("NumArgs", Size); + ListScope Arguments(*W, "Arguments"); SmallString<256> TypeName("("); for (uint32_t I = 0; I < Size; ++I) { printTypeIndex("ArgType", Indices[I]); @@ -292,77 +248,84 @@ void CVTypeDumperImpl::visitArgList(ArgListRecord &Args) { TypeName.append(", "); } TypeName.push_back(')'); - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); + return Error::success(); } -void CVTypeDumperImpl::visitClass(ClassRecord &Class) { +Error CVTypeDumper::visitClass(ClassRecord &Class) { uint16_t Props = static_cast(Class.getOptions()); - W.printNumber("MemberCount", Class.getMemberCount()); - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + 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()); + W->printNumber("SizeOf", Class.getSize()); + W->printString("Name", Class.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) - W.printString("LinkageName", Class.getUniqueName()); + W->printString("LinkageName", Class.getUniqueName()); Name = Class.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitUnion(UnionRecord &Union) { +Error CVTypeDumper::visitUnion(UnionRecord &Union) { uint16_t Props = static_cast(Union.getOptions()); - W.printNumber("MemberCount", Union.getMemberCount()); - W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames)); + 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()); + W->printNumber("SizeOf", Union.getSize()); + W->printString("Name", Union.getName()); if (Props & uint16_t(ClassOptions::HasUniqueName)) - W.printString("LinkageName", Union.getUniqueName()); + W->printString("LinkageName", Union.getUniqueName()); Name = Union.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitEnum(EnumRecord &Enum) { - W.printNumber("NumEnumerators", Enum.getMemberCount()); - W.printFlags("Properties", uint16_t(Enum.getOptions()), - makeArrayRef(ClassOptionNames)); +Error CVTypeDumper::visitEnum(EnumRecord &Enum) { + 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()); + W->printString("Name", Enum.getName()); Name = Enum.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitArray(ArrayRecord &AT) { +Error CVTypeDumper::visitArray(ArrayRecord &AT) { printTypeIndex("ElementType", AT.getElementType()); printTypeIndex("IndexType", AT.getIndexType()); - W.printNumber("SizeOf", AT.getSize()); - W.printString("Name", AT.getName()); + W->printNumber("SizeOf", AT.getSize()); + W->printString("Name", AT.getName()); Name = AT.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitVFTable(VFTableRecord &VFT) { +Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) { printTypeIndex("CompleteClass", VFT.getCompleteClass()); printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable()); - W.printHex("VFPtrOffset", VFT.getVFPtrOffset()); - W.printString("VFTableName", VFT.getName()); + W->printHex("VFPtrOffset", VFT.getVFPtrOffset()); + W->printString("VFTableName", VFT.getName()); for (auto N : VFT.getMethodNames()) - W.printString("MethodName", N); + W->printString("MethodName", N); Name = VFT.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitMemberFuncId(MemberFuncIdRecord &Id) { +Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) { printTypeIndex("ClassType", Id.getClassType()); printTypeIndex("FunctionType", Id.getFunctionType()); - W.printString("Name", Id.getName()); + W->printString("Name", Id.getName()); Name = Id.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitProcedure(ProcedureRecord &Proc) { +Error CVTypeDumper::visitProcedure(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()); + 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()); StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); @@ -370,20 +333,21 @@ void CVTypeDumperImpl::visitProcedure(ProcedureRecord &Proc) { SmallString<256> TypeName(ReturnTypeName); TypeName.push_back(' '); TypeName.append(ArgListTypeName); - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); + return Error::success(); } -void CVTypeDumperImpl::visitMemberFunction(MemberFunctionRecord &MF) { +Error CVTypeDumper::visitMemberFunction(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()); + 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()); + W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); StringRef ReturnTypeName = getTypeName(MF.getReturnType()); StringRef ClassTypeName = getTypeName(MF.getClassType()); @@ -393,52 +357,56 @@ void CVTypeDumperImpl::visitMemberFunction(MemberFunctionRecord &MF) { TypeName.append(ClassTypeName); TypeName.append("::"); TypeName.append(ArgListTypeName); - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); + return Error::success(); } -void CVTypeDumperImpl::visitMethodOverloadList( +Error CVTypeDumper::visitMethodOverloadList( MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { - ListScope S(W, "Method"); + ListScope S(*W, "Method"); printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions()); printTypeIndex("Type", M.getType()); if (M.isIntroducingVirtual()) - W.printHex("VFTableOffset", M.getVFTableOffset()); + W->printHex("VFTableOffset", M.getVFTableOffset()); } + return Error::success(); } -void CVTypeDumperImpl::visitFuncId(FuncIdRecord &Func) { +Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) { printTypeIndex("ParentScope", Func.getParentScope()); printTypeIndex("FunctionType", Func.getFunctionType()); - W.printString("Name", Func.getName()); + W->printString("Name", Func.getName()); Name = Func.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitTypeServer2(TypeServer2Record &TS) { - W.printBinary("Signature", TS.getGuid()); - W.printNumber("Age", TS.getAge()); - W.printString("Name", TS.getName()); +Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) { + W->printBinary("Signature", TS.getGuid()); + W->printNumber("Age", TS.getAge()); + W->printString("Name", TS.getName()); Name = TS.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitPointer(PointerRecord &Ptr) { +Error CVTypeDumper::visitPointer(PointerRecord &Ptr) { printTypeIndex("PointeeType", Ptr.getReferentType()); - W.printHex("PointerAttributes", uint32_t(Ptr.getOptions())); - W.printEnum("PtrType", unsigned(Ptr.getPointerKind()), - makeArrayRef(PtrKindNames)); - W.printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames)); + W->printHex("PointerAttributes", uint32_t(Ptr.getOptions())); + 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("IsFlat", Ptr.isFlat()); + W->printNumber("IsConst", Ptr.isConst()); + W->printNumber("IsVolatile", Ptr.isVolatile()); + W->printNumber("IsUnaligned", Ptr.isUnaligned()); if (Ptr.isPointerToMember()) { const MemberPointerInfo &MI = Ptr.getMemberInfo(); printTypeIndex("ClassType", MI.getContainingType()); - W.printEnum("Representation", uint16_t(MI.getRepresentation()), - makeArrayRef(PtrMemberRepNames)); + W->printEnum("Representation", uint16_t(MI.getRepresentation()), + makeArrayRef(PtrMemberRepNames)); StringRef PointeeName = getTypeName(Ptr.getReferentType()); StringRef ClassName = getTypeName(MI.getContainingType()); @@ -446,7 +414,7 @@ void CVTypeDumperImpl::visitPointer(PointerRecord &Ptr) { TypeName.push_back(' '); TypeName.append(ClassName); TypeName.append("::*"); - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); } else { SmallString<256> TypeName; if (Ptr.isConst()) @@ -466,14 +434,15 @@ void CVTypeDumperImpl::visitPointer(PointerRecord &Ptr) { TypeName.append("*"); if (!TypeName.empty()) - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); } + return Error::success(); } -void CVTypeDumperImpl::visitModifier(ModifierRecord &Mod) { +Error CVTypeDumper::visitModifier(ModifierRecord &Mod) { uint16_t Mods = static_cast(Mod.getModifiers()); printTypeIndex("ModifiedType", Mod.getModifiedType()); - W.printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); + W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames)); StringRef ModifiedName = getTypeName(Mod.getModifiedType()); SmallString<256> TypeName; @@ -484,146 +453,162 @@ void CVTypeDumperImpl::visitModifier(ModifierRecord &Mod) { if (Mods & uint16_t(ModifierOptions::Unaligned)) TypeName.append("__unaligned "); TypeName.append(ModifiedName); - Name = CVTD.saveName(TypeName); + Name = saveName(TypeName); + return Error::success(); } -void CVTypeDumperImpl::visitBitField(BitFieldRecord &BitField) { +Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) { printTypeIndex("Type", BitField.getType()); - W.printNumber("BitSize", BitField.getBitSize()); - W.printNumber("BitOffset", BitField.getBitOffset()); + W->printNumber("BitSize", BitField.getBitSize()); + W->printNumber("BitOffset", BitField.getBitOffset()); + return Error::success(); } -void CVTypeDumperImpl::visitVFTableShape(VFTableShapeRecord &Shape) { - W.printNumber("VFEntryCount", Shape.getEntryCount()); +Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) { + W->printNumber("VFEntryCount", Shape.getEntryCount()); + return Error::success(); } -void CVTypeDumperImpl::visitUdtSourceLine(UdtSourceLineRecord &Line) { +Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); - W.printNumber("LineNumber", Line.getLineNumber()); + W->printNumber("LineNumber", Line.getLineNumber()); + return Error::success(); } -void CVTypeDumperImpl::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { +Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) { printTypeIndex("UDT", Line.getUDT()); printTypeIndex("SourceFile", Line.getSourceFile()); - W.printNumber("LineNumber", Line.getLineNumber()); - W.printNumber("Module", Line.getModule()); + W->printNumber("LineNumber", Line.getLineNumber()); + W->printNumber("Module", Line.getModule()); + return Error::success(); } -void CVTypeDumperImpl::visitBuildInfo(BuildInfoRecord &Args) { - W.printNumber("NumArgs", static_cast(Args.getArgs().size())); +Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) { + W->printNumber("NumArgs", static_cast(Args.getArgs().size())); - ListScope Arguments(W, "Arguments"); + ListScope Arguments(*W, "Arguments"); for (auto Arg : Args.getArgs()) { printTypeIndex("ArgType", Arg); } + return Error::success(); } -void CVTypeDumperImpl::printMemberAttributes(MemberAttributes Attrs) { +void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) { return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(), Attrs.getFlags()); } -void CVTypeDumperImpl::printMemberAttributes(MemberAccess Access, - MethodKind Kind, - MethodOptions Options) { - W.printEnum("AccessSpecifier", uint8_t(Access), - makeArrayRef(MemberAccessNames)); +void CVTypeDumper::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)); + W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames)); if (Options != MethodOptions::None) { - W.printFlags("MethodOptions", unsigned(Options), - makeArrayRef(MethodOptionNames)); + W->printFlags("MethodOptions", unsigned(Options), + makeArrayRef(MethodOptionNames)); } } -void CVTypeDumperImpl::visitUnknownMember(TypeLeafKind Leaf) { - W.printHex("UnknownMember", unsigned(Leaf)); +Error CVTypeDumper::visitUnknownMember(const CVRecord &Record) { + W->printHex("UnknownMember", unsigned(Record.Type)); + return Error::success(); } -void CVTypeDumperImpl::visitUnknownType(const CVRecord &Rec) { - DictScope S(W, "UnknownType"); - W.printEnum("Kind", uint16_t(Rec.Type), makeArrayRef(LeafTypeNames)); - W.printNumber("Length", uint32_t(Rec.Data.size())); +Error CVTypeDumper::visitUnknownType(const CVRecord &Record) { + DictScope S(*W, "UnknownType"); + W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames)); + W->printNumber("Length", uint32_t(Record.Data.size())); + return Error::success(); } -void CVTypeDumperImpl::visitNestedType(NestedTypeRecord &Nested) { - DictScope S(W, "NestedType"); +Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) { + DictScope S(*W, "NestedType"); printTypeIndex("Type", Nested.getNestedType()); - W.printString("Name", Nested.getName()); + W->printString("Name", Nested.getName()); Name = Nested.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitOneMethod(OneMethodRecord &Method) { - DictScope S(W, "OneMethod"); +Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) { + DictScope S(*W, "OneMethod"); MethodKind K = Method.getKind(); 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()); + W->printHex("VFTableOffset", Method.getVFTableOffset()); + W->printString("Name", Method.getName()); Name = Method.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitOverloadedMethod(OverloadedMethodRecord &Method) { - DictScope S(W, "OverloadedMethod"); - W.printHex("MethodCount", Method.getNumOverloads()); +Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) { + DictScope S(*W, "OverloadedMethod"); + W->printHex("MethodCount", Method.getNumOverloads()); printTypeIndex("MethodListIndex", Method.getMethodList()); - W.printString("Name", Method.getName()); + W->printString("Name", Method.getName()); Name = Method.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitDataMember(DataMemberRecord &Field) { - DictScope S(W, "DataMember"); +Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) { + DictScope S(*W, "DataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); - W.printHex("FieldOffset", Field.getFieldOffset()); - W.printString("Name", Field.getName()); + W->printHex("FieldOffset", Field.getFieldOffset()); + W->printString("Name", Field.getName()); Name = Field.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitStaticDataMember(StaticDataMemberRecord &Field) { - DictScope S(W, "StaticDataMember"); +Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) { + DictScope S(*W, "StaticDataMember"); printMemberAttributes(Field.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("Type", Field.getType()); - W.printString("Name", Field.getName()); + W->printString("Name", Field.getName()); Name = Field.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitVFPtr(VFPtrRecord &VFTable) { - DictScope S(W, "VFPtr"); +Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) { + DictScope S(*W, "VFPtr"); printTypeIndex("Type", VFTable.getType()); + return Error::success(); } -void CVTypeDumperImpl::visitEnumerator(EnumeratorRecord &Enum) { - DictScope S(W, "Enumerator"); +Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) { + DictScope S(*W, "Enumerator"); printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla, MethodOptions::None); - W.printNumber("EnumValue", Enum.getValue()); - W.printString("Name", Enum.getName()); + W->printNumber("EnumValue", Enum.getValue()); + W->printString("Name", Enum.getName()); Name = Enum.getName(); + return Error::success(); } -void CVTypeDumperImpl::visitBaseClass(BaseClassRecord &Base) { - DictScope S(W, "BaseClass"); +Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) { + DictScope S(*W, "BaseClass"); printMemberAttributes(Base.getAccess(), MethodKind::Vanilla, MethodOptions::None); printTypeIndex("BaseType", Base.getBaseType()); - W.printHex("BaseOffset", Base.getBaseOffset()); + W->printHex("BaseOffset", Base.getBaseOffset()); + return Error::success(); } -void CVTypeDumperImpl::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { - DictScope S(W, "VirtualBaseClass"); +Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) { + DictScope S(*W, "VirtualBaseClass"); 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()); + W->printHex("VBPtrOffset", Base.getVBPtrOffset()); + W->printHex("VBTableIndex", Base.getVTableIndex()); + return Error::success(); } StringRef CVTypeDumper::getTypeName(TypeIndex TI) { @@ -663,28 +648,29 @@ void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { W->printHex(FieldName, TI.getIndex()); } -bool CVTypeDumper::dump(const CVRecord &Record) { +Error CVTypeDumper::dump(const CVRecord &Record) { assert(W && "printer should not be null"); - CVTypeDumperImpl Dumper(*this, *W, PrintRecordBytes); - Dumper.visitTypeRecord(Record); - return !Dumper.hadError(); + CVTypeVisitor Visitor(*this); + + if (auto EC = Visitor.visitTypeRecord(Record)) + return EC; + return Error::success(); } -bool CVTypeDumper::dump(const CVTypeArray &Types) { +Error CVTypeDumper::dump(const CVTypeArray &Types) { assert(W && "printer should not be null"); - CVTypeDumperImpl Dumper(*this, *W, PrintRecordBytes); - Dumper.visitTypeStream(Types); - return !Dumper.hadError(); + CVTypeVisitor Visitor(*this); + if (auto EC = Visitor.visitTypeStream(Types)) + return EC; + return Error::success(); } -bool CVTypeDumper::dump(ArrayRef Data) { +Error CVTypeDumper::dump(ArrayRef Data) { ByteStream<> Stream(Data); CVTypeArray Types; StreamReader Reader(Stream); - if (auto EC = Reader.readArray(Types, Reader.getLength())) { - consumeError(std::move(EC)); - return false; - } + if (auto EC = Reader.readArray(Types, Reader.getLength())) + return EC; return dump(Types); } diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index f71a31d6e387..ebfda2462be1 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -15,6 +15,8 @@ #include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" using namespace llvm; @@ -49,32 +51,32 @@ namespace { /// - If the type record already exists in the destination stream, discard it /// and update the type index map to forward the source type index to the /// existing destination type index. -class TypeStreamMerger : public CVTypeVisitor { +class TypeStreamMerger : public TypeVisitorCallbacks { public: TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) { assert(!hadError()); } - /// CVTypeVisitor overrides. +/// TypeVisitorCallbacks overrides. #define TYPE_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record); -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) + Error visit##Name(Name##Record &Record) override; #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - void visit##Name(Name##Record &Record); + TYPE_RECORD(EnumName, EnumVal, Name) +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" - void visitUnknownType(const CVRecord &Record); + Error visitUnknownType(const CVRecord &Record) override; - void visitTypeBegin(const CVRecord &Record); - void visitTypeEnd(const CVRecord &Record); + Error visitTypeBegin(const CVRecord &Record) override; + Error visitTypeEnd(const CVRecord &Record) override; - void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData); + Error visitFieldListEnd(const CVRecord &Record) override; bool mergeStream(const CVTypeArray &Types); private: - bool hadError() { return FoundBadTypeIndex || CVTypeVisitor::hadError(); } + bool hadError() { return FoundBadTypeIndex; } bool FoundBadTypeIndex = false; @@ -91,45 +93,52 @@ private: } // end anonymous namespace -void TypeStreamMerger::visitTypeBegin(const CVRecord &Rec) { +Error TypeStreamMerger::visitTypeBegin(const CVRecord &Rec) { BeginIndexMapSize = IndexMap.size(); + return Error::success(); } -void TypeStreamMerger::visitTypeEnd(const CVRecord &Rec) { +Error TypeStreamMerger::visitTypeEnd(const CVRecord &Rec) { assert(IndexMap.size() == BeginIndexMapSize + 1); + return Error::success(); } -void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf, - ArrayRef FieldData) { - CVTypeVisitor::visitFieldList(Leaf, FieldData); +Error TypeStreamMerger::visitFieldListEnd(const CVRecord &Rec) { IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); FieldBuilder.reset(); + return Error::success(); } #define TYPE_RECORD(EnumName, EnumVal, Name) \ - void TypeStreamMerger::visit##Name(Name##Record &Record) { \ + Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ IndexMap.push_back(DestStream.write##Name(Record)); \ + return Error::success(); \ } #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #define MEMBER_RECORD(EnumName, EnumVal, Name) \ - void TypeStreamMerger::visit##Name(Name##Record &Record) { \ + Error TypeStreamMerger::visit##Name(Name##Record &Record) { \ FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \ FieldBuilder.write##Name(Record); \ + return Error::success(); \ } #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/TypeRecords.def" -void TypeStreamMerger::visitUnknownType(const CVRecord &Rec) { +Error TypeStreamMerger::visitUnknownType(const CVRecord &Rec) { // We failed to translate a type. Translate this index as "not translated". IndexMap.push_back( TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct)); - parseError(); + return llvm::make_error(cv_error_code::corrupt_record); } bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) { assert(IndexMap.empty()); - visitTypeStream(Types); + CVTypeVisitor Visitor(*this); + if (auto EC = Visitor.visitTypeStream(Types)) { + consumeError(std::move(EC)); + return false; + } IndexMap.clear(); return !hadError(); } diff --git a/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp b/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp index 07aebb7d739c..eb169f70e11c 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/RawError.cpp @@ -32,6 +32,8 @@ public: return "The specified block address is not valid."; case raw_error_code::not_writable: return "The PDB does not support writing."; + case raw_error_code::invalid_tpi_hash: + return "The Type record has an invalid hash value."; } llvm_unreachable("Unrecognized raw_error_code"); } diff --git a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp index 99e5037ad636..46717f23a63d 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -84,39 +84,44 @@ template static uint32_t getTpiHash(T &Rec) { } namespace { -class TpiHashVerifier : public CVTypeVisitor { +class TpiHashVerifier : public TypeVisitorCallbacks { public: TpiHashVerifier(FixedStreamArray &HashValues, uint32_t NumHashBuckets) : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} - void visitUdtSourceLine(UdtSourceLineRecord &Rec) { verifySourceLine(Rec); } - - void visitUdtModSourceLine(UdtModSourceLineRecord &Rec) { - verifySourceLine(Rec); + Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override { + return verifySourceLine(Rec); } - void visitClass(ClassRecord &Rec) { verify(Rec); } - void visitEnum(EnumRecord &Rec) { verify(Rec); } - void visitInterface(ClassRecord &Rec) { verify(Rec); } - void visitStruct(ClassRecord &Rec) { verify(Rec); } - void visitUnion(UnionRecord &Rec) { verify(Rec); } + Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override { + return verifySourceLine(Rec); + } - void visitTypeEnd(const CVRecord &Record) { ++Index; } + Error visitClass(ClassRecord &Rec) override { return verify(Rec); } + Error visitEnum(EnumRecord &Rec) override { return verify(Rec); } + Error visitUnion(UnionRecord &Rec) override { return verify(Rec); } + + Error visitTypeEnd(const CVRecord &Record) override { + ++Index; + return Error::success(); + } private: - template void verify(T &Rec) { + template Error verify(T &Rec) { uint32_t Hash = getTpiHash(Rec); if (Hash && Hash % NumHashBuckets != HashValues[Index]) - parseError(); + return make_error(raw_error_code::invalid_tpi_hash); + return Error::success(); } - template void verifySourceLine(T &Rec) { + template Error verifySourceLine(T &Rec) { char Buf[4]; support::endian::write32le(Buf, Rec.getUDT().getIndex()); uint32_t Hash = hashStringV1(StringRef(Buf, 4)); if (Hash % NumHashBuckets != HashValues[Index]) - parseError(); + return make_error(raw_error_code::invalid_tpi_hash); + return Error::success(); } FixedStreamArray HashValues; @@ -129,11 +134,8 @@ private: // Currently we only verify SRC_LINE records. Error TpiStream::verifyHashValues() { TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets); - Verifier.visitTypeStream(TypeRecords); - if (Verifier.hadError()) - return make_error(raw_error_code::corrupt_file, - "Corrupt TPI hash table."); - return Error::success(); + CVTypeVisitor Visitor(Verifier); + return Visitor.visitTypeStream(TypeRecords); } Error TpiStream::reload() { diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 4df324f34440..2ae63e04882a 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -328,8 +328,10 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { for (auto &Type : Tpi->types(&HadError)) { DictScope DD(P, ""); - if (DumpRecords) - TD.dump(Type); + if (DumpRecords) { + if (auto EC = TD.dump(Type)) + return EC; + } if (DumpRecordBytes) P.printBinaryBlock("Bytes", Type.Data); @@ -347,8 +349,10 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { TD.setPrinter(nullptr); bool HadError = false; - for (auto &Type : Tpi->types(&HadError)) - TD.dump(Type); + for (auto &Type : Tpi->types(&HadError)) { + if (auto EC = TD.dump(Type)) + return EC; + } TD.setPrinter(OldP); dumpTpiHash(P, *Tpi); diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index dc7fe0e33ecf..0202e0316ee8 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -1108,9 +1108,9 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName, if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - if (!CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) { + if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) { W.flush(); - error(object_error::parse_failed); + error(llvm::errorToErrorCode(std::move(EC))); } } @@ -1555,8 +1555,8 @@ void llvm::dumpCodeViewMergedTypes( Buf.append(Record.begin(), Record.end()); }); CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes); - if (!CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) { + if (auto EC = CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) { Writer.flush(); - error(object_error::parse_failed); + error(llvm::errorToErrorCode(std::move(EC))); } }