#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.
#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;
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);
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);
type = Library
name = DebugInfoPDB
parent = DebugInfo
-required_libraries = Object Support
+required_libraries = Object Support DebugInfoCodeView
-; 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
; 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
; 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
set(LLVM_LINK_COMPONENTS
+ DebugInfoCodeView
DebugInfoPDB
Object
Support
#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"
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",
}
static Error dumpTpiStream(ScopedPrinter &P, PDBFile &File) {
- if (!opts::DumpTypeStream)
+ if (!opts::DumpTpiRecordBytes && !opts::DumpTpiRecords)
return Error::success();
DictScope D(P, "Type Info Stream");
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);
+
+ for (auto &Type : Tpi.types()) {
+ DictScope DD(P, "");
- ListScope L(P, "Records");
- for (auto &Type : Tpi.types()) {
- DictScope DD(P, "");
- P.printHex("Kind", unsigned(Type.Leaf));
- P.printBinaryBlock("Bytes", Type.LeafData);
+ if (opts::DumpTpiRecords)
+ TD.dump(Type);
+
+ if (opts::DumpTpiRecordBytes)
+ P.printBinaryBlock("Bytes", Type.LeafData);
+ }
}
return Error::success();
}