Make llvm-pdbdump print CV type records

This reuses the CVTypeDumper from libcodeview to dump full
information about type records within a PDB file.

Differential Revision: http://reviews.llvm.org/D20022
Reviewed By: rnk

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268808 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Zachary Turner 2016-05-06 22:15:42 +00:00
parent 815a884f59
commit b7d84117e3
7 changed files with 122 additions and 56 deletions

View File

@ -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<uint8_t> Data) {
for (const auto &I : makeTypeRange(Data)) {
ArrayRef<uint8_t> LeafData = I.LeafData;
ArrayRef<uint8_t> RecordData = LeafData;
auto *DerivedThis = static_cast<Derived *>(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<uint8_t> LeafData = Record.LeafData;
ArrayRef<uint8_t> RecordData = LeafData;
auto *DerivedThis = static_cast<Derived *>(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<uint8_t> Data) {
for (const auto &I : makeTypeRange(Data))
visitTypeRecord(I);
}
/// Action to take on unknown types. By default, they are ignored.

View File

@ -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<uint8_t> Data);

View File

@ -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<uint8_t> Data) {
CVTypeDumperImpl Dumper(*this, W, PrintRecordBytes);
Dumper.visitTypeStream(Data);

View File

@ -19,5 +19,5 @@
type = Library
name = DebugInfoPDB
parent = DebugInfo
required_libraries = Object Support
required_libraries = Object Support DebugInfoCodeView

View File

@ -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

View File

@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
DebugInfoPDB
Object
Support

View File

@ -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<bool> DumpStreamSizes("dump-stream-sizes",
cl::opt<bool> DumpStreamBlocks("dump-stream-blocks",
cl::desc("dump PDB stream blocks"),
cl::cat(OtherOptions));
cl::opt<bool> DumpTypeStream("dump-tpi-stream",
cl::desc("dump PDB TPI (Type Info) stream"),
cl::opt<bool> DumpTpiRecords("dump-tpi-records",
cl::desc("dump CodeView type records"),
cl::cat(OtherOptions));
cl::opt<bool>
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();
}