Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h @@ -28,6 +28,8 @@ SmallVectorImpl &Refs); void discoverTypeIndices(const CVType &Type, SmallVectorImpl &Refs); +void discoverTypeIndices(const CVType &Type, + SmallVectorImpl &Indices); /// Discover type indices in symbol records. Returns false if this is an unknown /// record. Index: llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -438,6 +438,25 @@ ::discoverTypeIndices(Type.content(), Type.kind(), Refs); } +void llvm::codeview::discoverTypeIndices(const CVType &Type, + SmallVectorImpl &Indices) { + + Indices.clear(); + + SmallVector Refs; + discoverTypeIndices(Type, Refs); + if (Refs.empty()) + return; + + BinaryStreamReader Reader(Type.content(), support::little); + for (const auto &Ref : Refs) { + Reader.setOffset(Ref.Offset); + FixedStreamArray Run; + cantFail(Reader.readArray(Run, Ref.Count)); + Indices.append(Run.begin(), Run.end()); + } +} + void llvm::codeview::discoverTypeIndices(ArrayRef RecordData, SmallVectorImpl &Refs) { const RecordPrefix *P = Index: llvm/trunk/test/tools/llvm-pdbdump/partial-type-stream.test =================================================================== --- llvm/trunk/test/tools/llvm-pdbdump/partial-type-stream.test +++ llvm/trunk/test/tools/llvm-pdbdump/partial-type-stream.test @@ -0,0 +1,30 @@ +; RUN: llvm-pdbutil dump -type-index=0x1019 %p/Inputs/ClassLayoutTest.pdb \ +; RUN: | FileCheck --check-prefix=NODEPS %s +; RUN: llvm-pdbutil dump -type-index=0x1019 -dependents %p/Inputs/ClassLayoutTest.pdb \ +; RUN: | FileCheck --check-prefix=DEPS %s + + +NODEPS: Types (TPI Stream) +NODEPS-NEXT: ============================================================ +NODEPS-NEXT: Showing 1 records. +NODEPS-NEXT: 0x1019 | LF_MFUNCTION [size = 28] +NODEPS-NEXT: return type = 0x0003 (void), # args = 0, param list = 0x100E +NODEPS-NEXT: class type = 0x1017, this type = 0x1018, this adjust = 0 +NODEPS-NEXT: calling conv = thiscall, options = None + + +DEPS: Types (TPI Stream) +DEPS-NEXT: ============================================================ +DEPS-NEXT: Showing 1 records and their dependents (4 records total) +DEPS-NEXT: 0x100E | LF_ARGLIST [size = 8] +DEPS-NEXT: 0x1017 | LF_CLASS [size = 60] +DEPS-NEXT: class name: `MembersTest::A` +DEPS-NEXT: unique name: `.?AVA@MembersTest@@` +DEPS-NEXT: vtable: , base list: , field list: +DEPS-NEXT: options: forward ref | has unique name +DEPS-NEXT: 0x1018 | LF_POINTER [size = 12] +DEPS-NEXT: referent = 0x1017, mode = pointer, opts = const, kind = ptr32 +DEPS-NEXT: 0x1019 | LF_MFUNCTION [size = 28] +DEPS-NEXT: return type = 0x0003 (void), # args = 0, param list = 0x100E +DEPS-NEXT: class type = 0x1017, this type = 0x1018, this adjust = 0 +DEPS-NEXT: calling conv = thiscall, options = None Index: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h =================================================================== --- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h +++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h @@ -37,8 +37,6 @@ Error dumpFileSummary(); Error dumpStreamSummary(); - Error dumpBlockRanges(); - Error dumpStreamBytes(); Error dumpStringTable(); Error dumpLines(); Error dumpInlineeLines(); Index: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -37,6 +37,7 @@ #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" @@ -116,12 +117,14 @@ return EC; } - if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) { + if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || + opts::dump::DumpTypeExtras) { if (auto EC = dumpTpiStream(StreamTPI)) return EC; } - if (opts::dump::DumpIds || opts::dump::DumpIdExtras) { + if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() || + opts::dump::DumpIdExtras) { if (auto EC = dumpTpiStream(StreamIPI)) return EC; } @@ -620,6 +623,76 @@ return Error::success(); } +static void buildDepSet(LazyRandomTypeCollection &Types, + ArrayRef Indices, + std::map &DepSet) { + SmallVector DepList; + for (const auto &I : Indices) { + TypeIndex TI(I); + if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType()) + continue; + + CVType Type = Types.getType(TI); + DepSet[TI] = Type; + codeview::discoverTypeIndices(Type, DepList); + buildDepSet(Types, DepList, DepSet); + } +} + +static void dumpFullTypeStream(LinePrinter &Printer, + LazyRandomTypeCollection &Types, + TpiStream &Stream, bool Bytes, bool Extras) { + Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords()); + uint32_t Width = + NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); + + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, + Stream.getHashValues()); + + if (auto EC = codeview::visitTypeStream(Types, V)) { + Printer.formatLine("An error occurred dumping type records: {0}", + toString(std::move(EC))); + } +} + +static void dumpPartialTypeStream(LinePrinter &Printer, + LazyRandomTypeCollection &Types, + TpiStream &Stream, ArrayRef TiList, + bool Bytes, bool Extras, bool Deps) { + uint32_t Width = + NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); + + MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, + Stream.getHashValues()); + + if (opts::dump::DumpTypeDependents) { + // If we need to dump all dependents, then iterate each index and find + // all dependents, adding them to a map ordered by TypeIndex. + std::map DepSet; + buildDepSet(Types, TiList, DepSet); + + Printer.formatLine( + "Showing {0:N} records and their dependents ({1:N} records total)", + TiList.size(), DepSet.size()); + + for (auto &Dep : DepSet) { + if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V)) + Printer.formatLine("An error occurred dumping type record {0}: {1}", + Dep.first, toString(std::move(EC))); + } + } else { + Printer.formatLine("Showing {0:N} records.", TiList.size()); + + for (const auto &I : TiList) { + TypeIndex TI(I); + CVType Type = Types.getType(TI); + if (auto EC = codeview::visitTypeRecord(Type, TI, V)) + Printer.formatLine("An error occurred dumping type record {0}: {1}", TI, + toString(std::move(EC))); + } + } +} + Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); @@ -659,27 +732,13 @@ auto &Types = Err(initializeTypes(StreamIdx)); - if (DumpTypes) { - P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords()); - uint32_t Width = - NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); - - MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types, - Stream.getHashValues()); - - if (Indices.empty()) { - if (auto EC = codeview::visitTypeStream(Types, V)) { - P.formatLine("An error occurred dumping type records: {0}", - toString(std::move(EC))); - } - } else { - for (const auto &I : Indices) { - TypeIndex TI(I); - CVType Type = Types.getType(TI); - if (auto EC = codeview::visitTypeRecord(Type, TI, V)) - P.formatLine("An error occurred dumping type record {0}: {1}", TI, - toString(std::move(EC))); - } + if (DumpTypes || !Indices.empty()) { + if (Indices.empty()) + dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras); + else { + std::vector TiList(Indices.begin(), Indices.end()); + dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras, + opts::dump::DumpTypeDependents); } } Index: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp +++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -377,7 +377,7 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) { P.formatLine("return type = {0}, # args = {1}, param list = {2}", - MF.ParameterCount, MF.ArgumentList, MF.ReturnType); + MF.ReturnType, MF.ParameterCount, MF.ArgumentList); P.formatLine("class type = {0}, this type = {1}, this adjust = {2}", MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment); P.formatLine("calling conv = {0}, options = {1}", Index: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h =================================================================== --- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h +++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h @@ -135,6 +135,7 @@ extern llvm::cl::opt DumpTypeData; extern llvm::cl::opt DumpTypeExtras; extern llvm::cl::list DumpTypeIndex; +extern llvm::cl::opt DumpTypeDependents; extern llvm::cl::opt DumpIds; extern llvm::cl::opt DumpIdData; Index: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -419,6 +419,13 @@ cl::desc("only dump ids with the specified hexadecimal type index"), cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::opt DumpTypeDependents( + "dependents", + cl::desc("In conjunection with -type-index and -id-index, dumps the entire " + "dependency graph for the specified index instead of " + "just the single record with the specified index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + // SYMBOL OPTIONS cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"), cl::cat(SymbolOptions), cl::sub(DumpSubcommand));