mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-16 00:17:32 +00:00
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:
parent
815a884f59
commit
b7d84117e3
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -19,5 +19,5 @@
|
||||
type = Library
|
||||
name = DebugInfoPDB
|
||||
parent = DebugInfo
|
||||
required_libraries = Object Support
|
||||
required_libraries = Object Support DebugInfoCodeView
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
DebugInfoCodeView
|
||||
DebugInfoPDB
|
||||
Object
|
||||
Support
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user