diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index 385ba3969b7..06d817126fa 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -51,36 +51,38 @@ public: #define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) #include "TypeRecords.def" - /// Visits the type records in Data and returns remaining data. Sets the - /// error flag on parse failures. - void visitTypeStream(ArrayRef Data) { - for (const auto &I : makeTypeRange(Data)) { - ArrayRef LeafData = I.LeafData; - ArrayRef RecordData = LeafData; - auto *DerivedThis = static_cast(this); - DerivedThis->visitTypeBegin(I.Leaf, RecordData); - switch (I.Leaf) { - default: - DerivedThis->visitUnknownType(I.Leaf); - break; - case LF_FIELDLIST: - DerivedThis->visitFieldList(I.Leaf, LeafData); - break; - case LF_METHODLIST: - DerivedThis->visitMethodList(I.Leaf, LeafData); - break; + void visitTypeRecord(const TypeIterator::TypeRecord &Record) { + ArrayRef LeafData = Record.LeafData; + ArrayRef RecordData = LeafData; + auto *DerivedThis = static_cast(this); + DerivedThis->visitTypeBegin(Record.Leaf, RecordData); + switch (Record.Leaf) { + default: + DerivedThis->visitUnknownType(Record.Leaf); + break; + case LF_FIELDLIST: + DerivedThis->visitFieldList(Record.Leaf, LeafData); + break; + case LF_METHODLIST: + DerivedThis->visitMethodList(Record.Leaf, LeafData); + break; #define TYPE_RECORD(ClassName, LeafEnum) \ case LeafEnum: { \ const ClassName *Rec; \ if (!CVTypeVisitor::consumeObject(LeafData, Rec)) \ return; \ - DerivedThis->visit##ClassName(I.Leaf, Rec, LeafData); \ + DerivedThis->visit##ClassName(Record.Leaf, Rec, LeafData); \ break; \ } #include "TypeRecords.def" } - DerivedThis->visitTypeEnd(I.Leaf, RecordData); - } + DerivedThis->visitTypeEnd(Record.Leaf, RecordData); + } + + /// Visits the type records in Data. Sets the error flag on parse failures. + void visitTypeStream(ArrayRef Data) { + for (const auto &I : makeTypeRange(Data)) + visitTypeRecord(I); } /// Action to take on unknown types. By default, they are ignored. diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h index 9f7b8555c91..87a03ad70c0 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDumper.h +++ b/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/TypeStream.h" namespace llvm { class ScopedPrinter; @@ -29,6 +30,12 @@ public: StringRef getTypeName(TypeIndex TI); void printTypeIndex(StringRef FieldName, TypeIndex TI); + /// Dumps one type record. Returns false if there was a type parsing error, + /// 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 TypeIterator::TypeRecord &Record); + /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. bool dump(ArrayRef Data); diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp index bb3859a0590..2aae7f5a84d 100644 --- a/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -755,6 +755,12 @@ void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { W.printHex(FieldName, TI.getIndex()); } +bool CVTypeDumper::dump(const TypeIterator::TypeRecord &Record) { + CVTypeDumperImpl Dumper(*this, W, PrintRecordBytes); + Dumper.visitTypeRecord(Record); + return !Dumper.hadError(); +} + bool CVTypeDumper::dump(ArrayRef Data) { CVTypeDumperImpl Dumper(*this, W, PrintRecordBytes); Dumper.visitTypeStream(Data); diff --git a/lib/DebugInfo/PDB/LLVMBuild.txt b/lib/DebugInfo/PDB/LLVMBuild.txt index 9ee9f4067e9..76e537a57fc 100644 --- a/lib/DebugInfo/PDB/LLVMBuild.txt +++ b/lib/DebugInfo/PDB/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = DebugInfoPDB parent = DebugInfo -required_libraries = Object Support +required_libraries = Object Support DebugInfoCodeView diff --git a/test/DebugInfo/PDB/pdbdump-headers.test b/test/DebugInfo/PDB/pdbdump-headers.test index dc5099be75a..f62f79e4037 100644 --- a/test/DebugInfo/PDB/pdbdump-headers.test +++ b/test/DebugInfo/PDB/pdbdump-headers.test @@ -1,4 +1,5 @@ -; RUN: llvm-pdbdump --dump-headers -dump-tpi-stream -dump-tpi-record-bytes %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s +; RUN: llvm-pdbdump --dump-headers -dump-tpi-records -dump-tpi-record-bytes \ +; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s ; RUN: llvm-pdbdump --dump-headers %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s ; RUN: llvm-pdbdump --dump-headers %p/Inputs/bad-block-size.pdb | FileCheck -check-prefix=BAD-BLOCK-SIZE %s @@ -78,28 +79,71 @@ ; EMPTY-NEXT: TPI Version: 20040203 ; EMPTY-NEXT: Record count: 75 ; EMPTY-NEXT: Records [ -; EMPTY-NEXT: { -; EMPTY-NEXT: Kind: 0x1201 -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 00000000 |....| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Kind: 0x1008 -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 74000000 00000000 00100000 |t...........| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } -; EMPTY-NEXT: { -; EMPTY-NEXT: Kind: 0x1203 -; EMPTY-NEXT: Bytes ( -; EMPTY-NEXT: 0000: 02150300 01006170 6172746D 656E7400 |......apartment.| -; EMPTY-NEXT: 0010: 02150300 02007369 6E676C65 00F3F2F1 |......single....| -; EMPTY-NEXT: 0020: 02150300 03006672 656500F1 02150300 |......free......| -; EMPTY-NEXT: 0030: 04006E65 75747261 6C00F2F1 02150300 |..neutral.......| -; EMPTY-NEXT: 0040: 0500626F 746800F1 |..both..| -; EMPTY-NEXT: ) -; EMPTY-NEXT: } +; EMPTY-NEXT: { +; EMPTY-NEXT: ArgList { +; EMPTY-NEXT: TypeLeafKind: LF_ARGLIST (0x1201) +; EMPTY-NEXT: TypeIndex: 0x1000 +; EMPTY-NEXT: NumArgs: 0 +; EMPTY-NEXT: Arguments [ +; EMPTY-NEXT: ] +; EMPTY-NEXT: } +; EMPTY-NEXT: Bytes ( +; EMPTY-NEXT: 0000: 00000000 |....| +; EMPTY-NEXT: ) +; EMPTY-NEXT: } +; EMPTY-NEXT: { +; EMPTY-NEXT: ProcedureType { +; EMPTY-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008) +; EMPTY-NEXT: TypeIndex: 0x1001 +; EMPTY-NEXT: ReturnType: int (0x74) +; EMPTY-NEXT: CallingConvention: NearC (0x0) +; EMPTY-NEXT: FunctionOptions [ (0x0) +; EMPTY-NEXT: ] +; EMPTY-NEXT: NumParameters: 0 +; EMPTY-NEXT: ArgListType: () (0x1000) +; EMPTY-NEXT: } +; EMPTY-NEXT: Bytes ( +; EMPTY-NEXT: 0000: 74000000 00000000 00100000 |t...........| +; EMPTY-NEXT: ) +; EMPTY-NEXT: } +; EMPTY-NEXT: { +; EMPTY-NEXT: UnknownLeaf { +; EMPTY-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203) +; EMPTY-NEXT: TypeIndex: 0x1002 +; EMPTY-NEXT: Enumerator { +; EMPTY-NEXT: AccessSpecifier: Public (0x3) +; EMPTY-NEXT: EnumValue: 1 +; EMPTY-NEXT: Name: apartment +; EMPTY-NEXT: } +; EMPTY-NEXT: Enumerator { +; EMPTY-NEXT: AccessSpecifier: Public (0x3) +; EMPTY-NEXT: EnumValue: 2 +; EMPTY-NEXT: Name: single +; EMPTY-NEXT: } +; EMPTY-NEXT: Enumerator { +; EMPTY-NEXT: AccessSpecifier: Public (0x3) +; EMPTY-NEXT: EnumValue: 3 +; EMPTY-NEXT: Name: free +; EMPTY-NEXT: } +; EMPTY-NEXT: Enumerator { +; EMPTY-NEXT: AccessSpecifier: Public (0x3) +; EMPTY-NEXT: EnumValue: 4 +; EMPTY-NEXT: Name: neutral +; EMPTY-NEXT: } +; EMPTY-NEXT: Enumerator { +; EMPTY-NEXT: AccessSpecifier: Public (0x3) +; EMPTY-NEXT: EnumValue: 5 +; EMPTY-NEXT: Name: both +; EMPTY-NEXT: } +; EMPTY-NEXT: } +; EMPTY-NEXT: Bytes ( +; EMPTY-NEXT: 0000: 02150300 01006170 6172746D 656E7400 |......apartment.| +; EMPTY-NEXT: 0010: 02150300 02007369 6E676C65 00F3F2F1 |......single....| +; EMPTY-NEXT: 0020: 02150300 03006672 656500F1 02150300 |......free......| +; EMPTY-NEXT: 0030: 04006E65 75747261 6C00F2F1 02150300 |..neutral.......| +; EMPTY-NEXT: 0040: 0500626F 746800F1 |..both..| +; EMPTY-NEXT: ) +; EMPTY-NEXT: } ; BIG: FileHeaders { ; BIG-NEXT: BlockSize: 4096 @@ -1238,4 +1282,4 @@ ; BIG-NEXT: ] ; BIG-NEXT: } -; BAD-BLOCK-SIZE: The PDB file is corrupt. Does not contain superblock +; BAD-BLOCK-SIZE: Native PDB Error: The PDB file is corrupt. Does not contain superblock diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt index 212b9563b04..02f386efe03 100644 --- a/tools/llvm-pdbdump/CMakeLists.txt +++ b/tools/llvm-pdbdump/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + DebugInfoCodeView DebugInfoPDB Object Support diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 202e18d504a..05b06428470 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" @@ -106,8 +107,8 @@ cl::opt DumpStreamSizes("dump-stream-sizes", cl::opt DumpStreamBlocks("dump-stream-blocks", cl::desc("dump PDB stream blocks"), cl::cat(OtherOptions)); -cl::opt DumpTypeStream("dump-tpi-stream", - cl::desc("dump PDB TPI (Type Info) stream"), +cl::opt DumpTpiRecords("dump-tpi-records", + cl::desc("dump CodeView type records"), cl::cat(OtherOptions)); cl::opt DumpTpiRecordBytes("dump-tpi-record-bytes", @@ -338,7 +339,7 @@ static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File) { } static Error dumpTpiStream(ScopedPrinter &P, PDBFile &File) { - if (!opts::DumpTypeStream) + if (!opts::DumpTpiRecordBytes && !opts::DumpTpiRecords) return Error::success(); DictScope D(P, "Type Info Stream"); @@ -351,14 +352,19 @@ static Error dumpTpiStream(ScopedPrinter &P, PDBFile &File) { P.printNumber("TPI Version", Tpi.getTpiVersion()); P.printNumber("Record count", Tpi.NumTypeRecords()); - if (!opts::DumpTpiRecordBytes) - return Error::success(); + if (opts::DumpTpiRecordBytes || opts::DumpTpiRecords) { + ListScope L(P, "Records"); + codeview::CVTypeDumper TD(P, false); - ListScope L(P, "Records"); - for (auto &Type : Tpi.types()) { - DictScope DD(P, ""); - P.printHex("Kind", unsigned(Type.Leaf)); - P.printBinaryBlock("Bytes", Type.LeafData); + for (auto &Type : Tpi.types()) { + DictScope DD(P, ""); + + if (opts::DumpTpiRecords) + TD.dump(Type); + + if (opts::DumpTpiRecordBytes) + P.printBinaryBlock("Bytes", Type.LeafData); + } } return Error::success(); }