mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-22 21:41:38 +00:00
[llvm-pdbutil] Add the ability to dump the dependency tree for a type
Previously we had the -type-index option which would dump the record of a single, but we had no way to follow the dependency graph backwards and also dump all dependent types. Having this option makes test-writing better, because we can limit the test to only those records that are of importance for the thing we're trying to test, which allows us to use things like CHECK-NEXT to reduce fragility. Differential Revision: https://reviews.llvm.org/D34899 llvm-svn: 306852
This commit is contained in:
parent
0d22b63ef8
commit
13ebe41aea
@ -28,6 +28,8 @@ void discoverTypeIndices(ArrayRef<uint8_t> RecordData,
|
||||
SmallVectorImpl<TiReference> &Refs);
|
||||
void discoverTypeIndices(const CVType &Type,
|
||||
SmallVectorImpl<TiReference> &Refs);
|
||||
void discoverTypeIndices(const CVType &Type,
|
||||
SmallVectorImpl<TypeIndex> &Indices);
|
||||
|
||||
/// Discover type indices in symbol records. Returns false if this is an unknown
|
||||
/// record.
|
||||
|
@ -438,6 +438,25 @@ void llvm::codeview::discoverTypeIndices(const CVType &Type,
|
||||
::discoverTypeIndices(Type.content(), Type.kind(), Refs);
|
||||
}
|
||||
|
||||
void llvm::codeview::discoverTypeIndices(const CVType &Type,
|
||||
SmallVectorImpl<TypeIndex> &Indices) {
|
||||
|
||||
Indices.clear();
|
||||
|
||||
SmallVector<TiReference, 4> Refs;
|
||||
discoverTypeIndices(Type, Refs);
|
||||
if (Refs.empty())
|
||||
return;
|
||||
|
||||
BinaryStreamReader Reader(Type.content(), support::little);
|
||||
for (const auto &Ref : Refs) {
|
||||
Reader.setOffset(Ref.Offset);
|
||||
FixedStreamArray<TypeIndex> Run;
|
||||
cantFail(Reader.readArray(Run, Ref.Count));
|
||||
Indices.append(Run.begin(), Run.end());
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
|
||||
SmallVectorImpl<TiReference> &Refs) {
|
||||
const RecordPrefix *P =
|
||||
|
30
test/tools/llvm-pdbdump/partial-type-stream.test
Normal file
30
test/tools/llvm-pdbdump/partial-type-stream.test
Normal file
@ -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: <no type>, base list: <no type>, field list: <no type>
|
||||
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
|
@ -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 @@ Error DumpOutputStyle::dump() {
|
||||
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 @@ Error DumpOutputStyle::dumpStringTable() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static void buildDepSet(LazyRandomTypeCollection &Types,
|
||||
ArrayRef<TypeIndex> Indices,
|
||||
std::map<TypeIndex, CVType> &DepSet) {
|
||||
SmallVector<TypeIndex, 4> 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<TypeIndex> 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<TypeIndex, CVType> 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 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
||||
|
||||
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<TypeIndex> TiList(Indices.begin(), Indices.end());
|
||||
dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
|
||||
opts::dump::DumpTypeDependents);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,6 @@ private:
|
||||
|
||||
Error dumpFileSummary();
|
||||
Error dumpStreamSummary();
|
||||
Error dumpBlockRanges();
|
||||
Error dumpStreamBytes();
|
||||
Error dumpStringTable();
|
||||
Error dumpLines();
|
||||
Error dumpInlineeLines();
|
||||
|
@ -377,7 +377,7 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
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}",
|
||||
|
@ -419,6 +419,13 @@ cl::list<uint32_t> DumpIdIndex(
|
||||
cl::desc("only dump ids with the specified hexadecimal type index"),
|
||||
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
||||
|
||||
cl::opt<bool> 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<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
|
||||
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
||||
|
@ -135,6 +135,7 @@ extern llvm::cl::opt<bool> DumpTypes;
|
||||
extern llvm::cl::opt<bool> DumpTypeData;
|
||||
extern llvm::cl::opt<bool> DumpTypeExtras;
|
||||
extern llvm::cl::list<uint32_t> DumpTypeIndex;
|
||||
extern llvm::cl::opt<bool> DumpTypeDependents;
|
||||
|
||||
extern llvm::cl::opt<bool> DumpIds;
|
||||
extern llvm::cl::opt<bool> DumpIdData;
|
||||
|
Loading…
x
Reference in New Issue
Block a user