aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-pdbutil/DumpOutputStyle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-pdbutil/DumpOutputStyle.cpp')
-rw-r--r--tools/llvm-pdbutil/DumpOutputStyle.cpp192
1 files changed, 152 insertions, 40 deletions
diff --git a/tools/llvm-pdbutil/DumpOutputStyle.cpp b/tools/llvm-pdbutil/DumpOutputStyle.cpp
index e4f6aa7f6ec5..962d4cf88a8a 100644
--- a/tools/llvm-pdbutil/DumpOutputStyle.cpp
+++ b/tools/llvm-pdbutil/DumpOutputStyle.cpp
@@ -1,9 +1,8 @@
//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -14,6 +13,7 @@
#include "MinimalSymbolDumper.h"
#include "MinimalTypeDumper.h"
#include "StreamUtil.h"
+#include "TypeReferenceTracker.h"
#include "llvm-pdbutil.h"
#include "llvm/ADT/STLExtras.h"
@@ -61,7 +61,12 @@ using namespace llvm::msf;
using namespace llvm::pdb;
DumpOutputStyle::DumpOutputStyle(InputFile &File)
- : File(File), P(2, false, outs()) {}
+ : File(File), P(2, false, outs()) {
+ if (opts::dump::DumpTypeRefStats)
+ RefTracker.reset(new TypeReferenceTracker(File));
+}
+
+DumpOutputStyle::~DumpOutputStyle() {}
PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
@@ -77,6 +82,10 @@ void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
}
Error DumpOutputStyle::dump() {
+ // Walk symbols & globals if we are supposed to mark types referenced.
+ if (opts::dump::DumpTypeRefStats)
+ RefTracker->mark();
+
if (opts::dump::DumpSummary) {
if (auto EC = dumpFileSummary())
return EC;
@@ -101,6 +110,12 @@ Error DumpOutputStyle::dump() {
P.NewLine();
}
+ if (opts::dump::DumpTypeStats) {
+ if (auto EC = dumpTypeStats())
+ return EC;
+ P.NewLine();
+ }
+
if (opts::dump::DumpNamedStreams) {
if (auto EC = dumpNamedStreams())
return EC;
@@ -188,6 +203,11 @@ Error DumpOutputStyle::dump() {
return EC;
}
+ if (opts::dump::DumpTypeRefStats) {
+ if (auto EC = dumpTypeRefStats())
+ return EC;
+ }
+
if (opts::dump::DumpSectionHeaders) {
if (auto EC = dumpSectionHeaders())
return EC;
@@ -203,6 +223,8 @@ Error DumpOutputStyle::dump() {
return EC;
}
+ P.NewLine();
+
return Error::success();
}
@@ -293,18 +315,30 @@ static inline std::string formatModuleDetailKind(SymbolKind K) {
return formatSymbolKind(K);
}
+// Get the stats sorted by size, descending.
+std::vector<StatCollection::KindAndStat>
+StatCollection::getStatsSortedBySize() const {
+ std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end());
+ llvm::stable_sort(SortedStats,
+ [](const KindAndStat &LHS, const KindAndStat &RHS) {
+ return LHS.second.Size > RHS.second.Size;
+ });
+ return SortedStats;
+}
+
template <typename Kind>
static void printModuleDetailStats(LinePrinter &P, StringRef Label,
const StatCollection &Stats) {
P.NewLine();
P.formatLine(" {0}", Label);
AutoIndent Indent(P);
- P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total",
+ P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total",
Stats.Totals.Count, Stats.Totals.Size);
P.formatLine("{0}", fmt_repeat('-', 74));
- for (const auto &K : Stats.Individual) {
+
+ for (const auto &K : Stats.getStatsSortedBySize()) {
std::string KindName = formatModuleDetailKind(Kind(K.first));
- P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName,
+ P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName,
K.second.Count, K.second.Size);
}
}
@@ -662,6 +696,35 @@ Error DumpOutputStyle::dumpSymbolStats() {
return Error::success();
}
+Error DumpOutputStyle::dumpTypeStats() {
+ printHeader(P, "Type Record Stats");
+
+ // Iterate the types, categorize by kind, accumulate size stats.
+ StatCollection TypeStats;
+ LazyRandomTypeCollection &Types = File.types();
+ for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ CVType Type = Types.getType(*TI);
+ TypeStats.update(uint32_t(Type.kind()), Type.length());
+ }
+
+ P.NewLine();
+ P.formatLine(" Types");
+ AutoIndent Indent(P);
+ P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total",
+ TypeStats.Totals.Count, TypeStats.Totals.Size,
+ (double)TypeStats.Totals.Size / TypeStats.Totals.Count);
+ P.formatLine("{0}", fmt_repeat('-', 74));
+
+ for (const auto &K : TypeStats.getStatsSortedBySize()) {
+ P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)",
+ formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count,
+ K.second.Size, (double)K.second.Size / K.second.Count);
+ }
+
+
+ return Error::success();
+}
+
static bool isValidNamespaceIdentifier(StringRef S) {
if (S.empty())
return false;
@@ -806,7 +869,7 @@ Error DumpOutputStyle::dumpUdtStats() {
fmt_align(SizeHeader, AlignStyle::Right, SD));
P.formatLine("{0}", fmt_repeat('-', TableWidth));
- for (const auto &Stat : UdtTargetStats.Individual) {
+ for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) {
StringRef Label = getUdtStatLabel(Stat.first);
P.formatLine("{0} | {1:N} {2:N}",
fmt_align(Label, AlignStyle::Right, FieldWidth),
@@ -819,12 +882,25 @@ Error DumpOutputStyle::dumpUdtStats() {
fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
P.formatLine("{0}", fmt_repeat('-', TableWidth));
- for (const auto &Stat : NamespacedStats) {
- std::string Label = formatv("namespace '{0}'", Stat.getKey());
+ struct StrAndStat {
+ StringRef Key;
+ StatCollection::Stat Stat;
+ };
+
+ // Print namespace stats in descending order of size.
+ std::vector<StrAndStat> NamespacedStatsSorted;
+ for (const auto &Stat : NamespacedStats)
+ NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second});
+ llvm::stable_sort(NamespacedStatsSorted,
+ [](const StrAndStat &L, const StrAndStat &R) {
+ return L.Stat.Size > R.Stat.Size;
+ });
+ for (const auto &Stat : NamespacedStatsSorted) {
+ std::string Label = formatv("namespace '{0}'", Stat.Key);
P.formatLine("{0} | {1:N} {2:N}",
fmt_align(Label, AlignStyle::Right, FieldWidth),
- fmt_align(Stat.second.Count, AlignStyle::Right, CD),
- fmt_align(Stat.second.Size, AlignStyle::Right, SD));
+ fmt_align(Stat.Stat.Count, AlignStyle::Right, CD),
+ fmt_align(Stat.Stat.Size, AlignStyle::Right, SD));
}
return Error::success();
}
@@ -921,6 +997,10 @@ Error DumpOutputStyle::dumpInlineeLines() {
P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
fmtle(Entry.Header->SourceLineNum));
Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
+ for (const auto &ExtraFileID : Entry.ExtraFiles) {
+ P.formatLine(" ");
+ Strings.formatFromChecksumsOffset(P, ExtraFileID, true);
+ }
}
P.NewLine();
});
@@ -1011,17 +1091,12 @@ Error DumpOutputStyle::dumpOldFpo(PDBFile &File) {
ExitOnError Err("Error dumping old fpo data:");
auto &Dbi = Err(File.getPDBDbiStream());
- uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::FPO);
- if (Index == kInvalidStreamIndex) {
+ if (!Dbi.hasOldFpoRecords()) {
printStreamNotPresent("FPO");
return Error::success();
}
- std::unique_ptr<MappedBlockStream> OldFpo = File.createIndexedStream(Index);
- BinaryStreamReader Reader(*OldFpo);
- FixedStreamArray<object::FpoData> Records;
- Err(Reader.readArray(Records,
- Reader.bytesRemaining() / sizeof(object::FpoData)));
+ const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords();
P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use "
"BP | Has SEH | Frame Type");
@@ -1043,18 +1118,12 @@ Error DumpOutputStyle::dumpNewFpo(PDBFile &File) {
ExitOnError Err("Error dumping new fpo data:");
auto &Dbi = Err(File.getPDBDbiStream());
- uint32_t Index = Dbi.getDebugStreamIndex(DbgHeaderType::NewFPO);
- if (Index == kInvalidStreamIndex) {
+ if (!Dbi.hasNewFpoRecords()) {
printStreamNotPresent("New FPO");
return Error::success();
}
- std::unique_ptr<MappedBlockStream> NewFpo = File.createIndexedStream(Index);
-
- DebugFrameDataSubsectionRef FDS;
- if (auto EC = FDS.initialize(*NewFpo))
- return make_error<RawError>(raw_error_code::corrupt_file,
- "Invalid new fpo stream");
+ const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords();
P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs "
"| Has SEH | Has C++EH | Start | Program");
@@ -1239,14 +1308,15 @@ static void buildDepSet(LazyRandomTypeCollection &Types,
static void
dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
- uint32_t NumTypeRecords, uint32_t NumHashBuckets,
+ TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
+ uint32_t NumHashBuckets,
FixedStreamArray<support::ulittle32_t> HashValues,
TpiStream *Stream, bool Bytes, bool Extras) {
Printer.formatLine("Showing {0:N} records", NumTypeRecords);
uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
- MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
NumHashBuckets, HashValues, Stream);
if (auto EC = codeview::visitTypeStream(Types, V)) {
@@ -1257,12 +1327,13 @@ dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
static void dumpPartialTypeStream(LinePrinter &Printer,
LazyRandomTypeCollection &Types,
+ TypeReferenceTracker *RefTracker,
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,
+ MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream);
@@ -1311,12 +1382,12 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {
else
continue;
- StringRef Contents;
- if (auto EC = S.getContents(Contents))
- return errorCodeToError(EC);
+ Expected<StringRef> ContentsOrErr = S.getContents();
+ if (!ContentsOrErr)
+ return ContentsOrErr.takeError();
uint32_t Magic;
- BinaryStreamReader Reader(Contents, llvm::support::little);
+ BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little);
if (auto EC = Reader.readInteger(Magic))
return EC;
if (Magic != COFF::DEBUG_SECTION_MAGIC)
@@ -1326,8 +1397,8 @@ Error DumpOutputStyle::dumpTypesFromObjectFile() {
Types.reset(Reader, 100);
if (opts::dump::DumpTypes) {
- dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
- false);
+ dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
+ opts::dump::DumpTypeData, false);
} else if (opts::dump::DumpTypeExtras) {
auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
@@ -1396,23 +1467,36 @@ Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
+ // Only emit notes about referenced/unreferenced for types.
+ TypeReferenceTracker *MaybeTracker =
+ (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
+
// Enable resolving forward decls.
Stream.buildHashMap();
if (DumpTypes || !Indices.empty()) {
if (Indices.empty())
- dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
+ dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
Stream.getNumHashBuckets(), Stream.getHashValues(),
&Stream, DumpBytes, DumpExtras);
else {
std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
- dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
- opts::dump::DumpTypeDependents);
+ dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
+ DumpExtras, opts::dump::DumpTypeDependents);
}
}
if (DumpExtras) {
P.NewLine();
+
+ P.formatLine("Header Version: {0}",
+ static_cast<uint32_t>(Stream.getTpiVersion()));
+ P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex());
+ P.formatLine("Aux Hash Stream Index: {0}",
+ Stream.getTypeHashStreamAuxIndex());
+ P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize());
+ P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets());
+
auto IndexOffsets = Stream.getTypeIndexOffsets();
P.formatLine("Type Index Offsets:");
for (const auto &IO : IndexOffsets) {
@@ -1523,6 +1607,34 @@ Error DumpOutputStyle::dumpModuleSymsForPdb() {
return Error::success();
}
+Error DumpOutputStyle::dumpTypeRefStats() {
+ printHeader(P, "Type Reference Statistics");
+ AutoIndent Indent(P);
+
+ // Sum the byte size of all type records, and the size and count of all
+ // referenced records.
+ size_t TotalRecs = File.types().size();
+ size_t RefRecs = 0;
+ size_t TotalBytes = 0;
+ size_t RefBytes = 0;
+ auto &Types = File.types();
+ for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+ CVType Type = File.types().getType(*TI);
+ TotalBytes += Type.length();
+ if (RefTracker->isTypeReferenced(*TI)) {
+ ++RefRecs;
+ RefBytes += Type.length();
+ }
+ }
+
+ P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
+ (double)RefRecs / TotalRecs);
+ P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
+ (double)RefBytes / TotalBytes);
+
+ return Error::success();
+}
+
Error DumpOutputStyle::dumpGSIRecords() {
printHeader(P, "GSI Records");