xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric //===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "DumpOutputStyle.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "FormatUtil.h"
120b57cec5SDimitry Andric #include "InputFile.h"
130b57cec5SDimitry Andric #include "MinimalSymbolDumper.h"
140b57cec5SDimitry Andric #include "MinimalTypeDumper.h"
150b57cec5SDimitry Andric #include "StreamUtil.h"
160b57cec5SDimitry Andric #include "TypeReferenceTracker.h"
170b57cec5SDimitry Andric #include "llvm-pdbutil.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
220b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
230b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
240b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
250b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
260b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
270b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
280b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
290b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
300b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Formatters.h"
310b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
320b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Line.h"
330b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
340b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
350b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
360b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeHashing.h"
370b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
380b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
390b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
400b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
410b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
420b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
430b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
440b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
450b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
460b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
470b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
480b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
490b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
500b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
510b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
520b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
530b57cec5SDimitry Andric #include "llvm/Support/FormatAdapters.h"
540b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric #include <cctype>
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric using namespace llvm;
590b57cec5SDimitry Andric using namespace llvm::codeview;
600b57cec5SDimitry Andric using namespace llvm::msf;
610b57cec5SDimitry Andric using namespace llvm::pdb;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric DumpOutputStyle::DumpOutputStyle(InputFile &File)
640b57cec5SDimitry Andric     : File(File), P(2, false, outs()) {
650b57cec5SDimitry Andric   if (opts::dump::DumpTypeRefStats)
660b57cec5SDimitry Andric     RefTracker.reset(new TypeReferenceTracker(File));
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric DumpOutputStyle::~DumpOutputStyle() {}
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
720b57cec5SDimitry Andric object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotValidForObj() {
750b57cec5SDimitry Andric   AutoIndent Indent(P, 4);
760b57cec5SDimitry Andric   P.formatLine("Dumping this stream is not valid for object files");
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
800b57cec5SDimitry Andric   AutoIndent Indent(P, 4);
810b57cec5SDimitry Andric   P.formatLine("{0} stream not present", StreamName);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric Error DumpOutputStyle::dump() {
850b57cec5SDimitry Andric   // Walk symbols & globals if we are supposed to mark types referenced.
860b57cec5SDimitry Andric   if (opts::dump::DumpTypeRefStats)
870b57cec5SDimitry Andric     RefTracker->mark();
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   if (opts::dump::DumpSummary) {
900b57cec5SDimitry Andric     if (auto EC = dumpFileSummary())
910b57cec5SDimitry Andric       return EC;
920b57cec5SDimitry Andric     P.NewLine();
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   if (opts::dump::DumpStreams) {
960b57cec5SDimitry Andric     if (auto EC = dumpStreamSummary())
970b57cec5SDimitry Andric       return EC;
980b57cec5SDimitry Andric     P.NewLine();
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   if (opts::dump::DumpSymbolStats) {
1020b57cec5SDimitry Andric     if (auto EC = dumpSymbolStats())
1030b57cec5SDimitry Andric       return EC;
1040b57cec5SDimitry Andric     P.NewLine();
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   if (opts::dump::DumpUdtStats) {
1080b57cec5SDimitry Andric     if (auto EC = dumpUdtStats())
1090b57cec5SDimitry Andric       return EC;
1100b57cec5SDimitry Andric     P.NewLine();
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric 
113*5ffd83dbSDimitry Andric   if (opts::dump::DumpTypeStats || opts::dump::DumpIDStats) {
1140b57cec5SDimitry Andric     if (auto EC = dumpTypeStats())
1150b57cec5SDimitry Andric       return EC;
1160b57cec5SDimitry Andric     P.NewLine();
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   if (opts::dump::DumpNamedStreams) {
1200b57cec5SDimitry Andric     if (auto EC = dumpNamedStreams())
1210b57cec5SDimitry Andric       return EC;
1220b57cec5SDimitry Andric     P.NewLine();
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) {
1260b57cec5SDimitry Andric     if (auto EC = dumpStringTable())
1270b57cec5SDimitry Andric       return EC;
1280b57cec5SDimitry Andric     P.NewLine();
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   if (opts::dump::DumpModules) {
1320b57cec5SDimitry Andric     if (auto EC = dumpModules())
1330b57cec5SDimitry Andric       return EC;
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   if (opts::dump::DumpModuleFiles) {
1370b57cec5SDimitry Andric     if (auto EC = dumpModuleFiles())
1380b57cec5SDimitry Andric       return EC;
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   if (opts::dump::DumpLines) {
1420b57cec5SDimitry Andric     if (auto EC = dumpLines())
1430b57cec5SDimitry Andric       return EC;
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric   if (opts::dump::DumpInlineeLines) {
1470b57cec5SDimitry Andric     if (auto EC = dumpInlineeLines())
1480b57cec5SDimitry Andric       return EC;
1490b57cec5SDimitry Andric   }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   if (opts::dump::DumpXmi) {
1520b57cec5SDimitry Andric     if (auto EC = dumpXmi())
1530b57cec5SDimitry Andric       return EC;
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   if (opts::dump::DumpXme) {
1570b57cec5SDimitry Andric     if (auto EC = dumpXme())
1580b57cec5SDimitry Andric       return EC;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   if (opts::dump::DumpFpo) {
1620b57cec5SDimitry Andric     if (auto EC = dumpFpo())
1630b57cec5SDimitry Andric       return EC;
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   if (File.isObj()) {
1670b57cec5SDimitry Andric     if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
1680b57cec5SDimitry Andric         opts::dump::DumpTypeExtras)
1690b57cec5SDimitry Andric       if (auto EC = dumpTypesFromObjectFile())
1700b57cec5SDimitry Andric         return EC;
1710b57cec5SDimitry Andric   } else {
1720b57cec5SDimitry Andric     if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
1730b57cec5SDimitry Andric         opts::dump::DumpTypeExtras) {
1740b57cec5SDimitry Andric       if (auto EC = dumpTpiStream(StreamTPI))
1750b57cec5SDimitry Andric         return EC;
1760b57cec5SDimitry Andric     }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric     if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
1790b57cec5SDimitry Andric         opts::dump::DumpIdExtras) {
1800b57cec5SDimitry Andric       if (auto EC = dumpTpiStream(StreamIPI))
1810b57cec5SDimitry Andric         return EC;
1820b57cec5SDimitry Andric     }
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   if (opts::dump::DumpGSIRecords) {
1860b57cec5SDimitry Andric     if (auto EC = dumpGSIRecords())
1870b57cec5SDimitry Andric       return EC;
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   if (opts::dump::DumpGlobals) {
1910b57cec5SDimitry Andric     if (auto EC = dumpGlobals())
1920b57cec5SDimitry Andric       return EC;
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   if (opts::dump::DumpPublics) {
1960b57cec5SDimitry Andric     if (auto EC = dumpPublics())
1970b57cec5SDimitry Andric       return EC;
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   if (opts::dump::DumpSymbols) {
2010b57cec5SDimitry Andric     auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj();
2020b57cec5SDimitry Andric     if (EC)
2030b57cec5SDimitry Andric       return EC;
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   if (opts::dump::DumpTypeRefStats) {
2070b57cec5SDimitry Andric     if (auto EC = dumpTypeRefStats())
2080b57cec5SDimitry Andric       return EC;
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   if (opts::dump::DumpSectionHeaders) {
2120b57cec5SDimitry Andric     if (auto EC = dumpSectionHeaders())
2130b57cec5SDimitry Andric       return EC;
2140b57cec5SDimitry Andric   }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   if (opts::dump::DumpSectionContribs) {
2170b57cec5SDimitry Andric     if (auto EC = dumpSectionContribs())
2180b57cec5SDimitry Andric       return EC;
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   if (opts::dump::DumpSectionMap) {
2220b57cec5SDimitry Andric     if (auto EC = dumpSectionMap())
2230b57cec5SDimitry Andric       return EC;
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   P.NewLine();
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   return Error::success();
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric static void printHeader(LinePrinter &P, const Twine &S) {
2320b57cec5SDimitry Andric   P.NewLine();
2330b57cec5SDimitry Andric   P.formatLine("{0,=60}", S);
2340b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('=', 60));
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric Error DumpOutputStyle::dumpFileSummary() {
2380b57cec5SDimitry Andric   printHeader(P, "Summary");
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   if (File.isObj()) {
2410b57cec5SDimitry Andric     printStreamNotValidForObj();
2420b57cec5SDimitry Andric     return Error::success();
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   AutoIndent Indent(P);
2460b57cec5SDimitry Andric   ExitOnError Err("Invalid PDB Format: ");
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   P.formatLine("Block Size: {0}", getPdb().getBlockSize());
2490b57cec5SDimitry Andric   P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
2500b57cec5SDimitry Andric   P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   auto &PS = Err(getPdb().getPDBInfoStream());
2530b57cec5SDimitry Andric   P.formatLine("Signature: {0}", PS.getSignature());
2540b57cec5SDimitry Andric   P.formatLine("Age: {0}", PS.getAge());
2550b57cec5SDimitry Andric   P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
2560b57cec5SDimitry Andric   P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
2570b57cec5SDimitry Andric   P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
2580b57cec5SDimitry Andric   P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
2590b57cec5SDimitry Andric   P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
2600b57cec5SDimitry Andric   P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
2610b57cec5SDimitry Andric   P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
2620b57cec5SDimitry Andric   if (getPdb().hasPDBDbiStream()) {
2630b57cec5SDimitry Andric     auto &DBI = Err(getPdb().getPDBDbiStream());
2640b57cec5SDimitry Andric     P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
2650b57cec5SDimitry Andric     P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
2660b57cec5SDimitry Andric     P.formatLine("Is stripped: {0}", DBI.isStripped());
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   return Error::success();
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric static StatCollection getSymbolStats(const SymbolGroup &SG,
2730b57cec5SDimitry Andric                                      StatCollection &CumulativeStats) {
2740b57cec5SDimitry Andric   StatCollection Stats;
2750b57cec5SDimitry Andric   if (SG.getFile().isPdb() && SG.hasDebugStream()) {
2760b57cec5SDimitry Andric     // For PDB files, all symbols are packed into one stream.
2770b57cec5SDimitry Andric     for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
2780b57cec5SDimitry Andric       Stats.update(S.kind(), S.length());
2790b57cec5SDimitry Andric       CumulativeStats.update(S.kind(), S.length());
2800b57cec5SDimitry Andric     }
2810b57cec5SDimitry Andric     return Stats;
2820b57cec5SDimitry Andric   }
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   for (const auto &SS : SG.getDebugSubsections()) {
2850b57cec5SDimitry Andric     // For object files, all symbols are spread across multiple Symbol
2860b57cec5SDimitry Andric     // subsections of a given .debug$S section.
2870b57cec5SDimitry Andric     if (SS.kind() != DebugSubsectionKind::Symbols)
2880b57cec5SDimitry Andric       continue;
2890b57cec5SDimitry Andric     DebugSymbolsSubsectionRef Symbols;
2900b57cec5SDimitry Andric     BinaryStreamReader Reader(SS.getRecordData());
2910b57cec5SDimitry Andric     cantFail(Symbols.initialize(Reader));
2920b57cec5SDimitry Andric     for (const auto &S : Symbols) {
2930b57cec5SDimitry Andric       Stats.update(S.kind(), S.length());
2940b57cec5SDimitry Andric       CumulativeStats.update(S.kind(), S.length());
2950b57cec5SDimitry Andric     }
2960b57cec5SDimitry Andric   }
2970b57cec5SDimitry Andric   return Stats;
2980b57cec5SDimitry Andric }
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric static StatCollection getChunkStats(const SymbolGroup &SG,
3010b57cec5SDimitry Andric                                     StatCollection &CumulativeStats) {
3020b57cec5SDimitry Andric   StatCollection Stats;
3030b57cec5SDimitry Andric   for (const auto &Chunk : SG.getDebugSubsections()) {
3040b57cec5SDimitry Andric     Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
3050b57cec5SDimitry Andric     CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
3060b57cec5SDimitry Andric   }
3070b57cec5SDimitry Andric   return Stats;
3080b57cec5SDimitry Andric }
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
3110b57cec5SDimitry Andric   return formatChunkKind(K, false);
3120b57cec5SDimitry Andric }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(SymbolKind K) {
3150b57cec5SDimitry Andric   return formatSymbolKind(K);
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric // Get the stats sorted by size, descending.
3190b57cec5SDimitry Andric std::vector<StatCollection::KindAndStat>
3200b57cec5SDimitry Andric StatCollection::getStatsSortedBySize() const {
3210b57cec5SDimitry Andric   std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end());
3220b57cec5SDimitry Andric   llvm::stable_sort(SortedStats,
3230b57cec5SDimitry Andric                     [](const KindAndStat &LHS, const KindAndStat &RHS) {
3240b57cec5SDimitry Andric                       return LHS.second.Size > RHS.second.Size;
3250b57cec5SDimitry Andric                     });
3260b57cec5SDimitry Andric   return SortedStats;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric template <typename Kind>
3300b57cec5SDimitry Andric static void printModuleDetailStats(LinePrinter &P, StringRef Label,
3310b57cec5SDimitry Andric                                    const StatCollection &Stats) {
3320b57cec5SDimitry Andric   P.NewLine();
3330b57cec5SDimitry Andric   P.formatLine("  {0}", Label);
3340b57cec5SDimitry Andric   AutoIndent Indent(P);
3350b57cec5SDimitry Andric   P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total",
3360b57cec5SDimitry Andric                Stats.Totals.Count, Stats.Totals.Size);
3370b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('-', 74));
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   for (const auto &K : Stats.getStatsSortedBySize()) {
3400b57cec5SDimitry Andric     std::string KindName = formatModuleDetailKind(Kind(K.first));
3410b57cec5SDimitry Andric     P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName,
3420b57cec5SDimitry Andric                  K.second.Count, K.second.Size);
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric static bool isMyCode(const SymbolGroup &Group) {
3470b57cec5SDimitry Andric   if (Group.getFile().isObj())
3480b57cec5SDimitry Andric     return true;
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   StringRef Name = Group.name();
3510b57cec5SDimitry Andric   if (Name.startswith("Import:"))
3520b57cec5SDimitry Andric     return false;
3530b57cec5SDimitry Andric   if (Name.endswith_lower(".dll"))
3540b57cec5SDimitry Andric     return false;
3550b57cec5SDimitry Andric   if (Name.equals_lower("* linker *"))
3560b57cec5SDimitry Andric     return false;
3570b57cec5SDimitry Andric   if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools"))
3580b57cec5SDimitry Andric     return false;
3590b57cec5SDimitry Andric   if (Name.startswith_lower("f:\\dd\\vctools\\crt"))
3600b57cec5SDimitry Andric     return false;
3610b57cec5SDimitry Andric   return true;
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) {
3650b57cec5SDimitry Andric   if (opts::dump::JustMyCode && !isMyCode(Group))
3660b57cec5SDimitry Andric     return false;
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   // If the arg was not specified on the command line, always dump all modules.
3690b57cec5SDimitry Andric   if (opts::dump::DumpModi.getNumOccurrences() == 0)
3700b57cec5SDimitry Andric     return true;
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   // Otherwise, only dump if this is the same module specified.
3730b57cec5SDimitry Andric   return (opts::dump::DumpModi == Idx);
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric Error DumpOutputStyle::dumpStreamSummary() {
3770b57cec5SDimitry Andric   printHeader(P, "Streams");
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric   if (File.isObj()) {
3800b57cec5SDimitry Andric     printStreamNotValidForObj();
3810b57cec5SDimitry Andric     return Error::success();
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   AutoIndent Indent(P);
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric   if (StreamPurposes.empty())
3870b57cec5SDimitry Andric     discoverStreamPurposes(getPdb(), StreamPurposes);
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   uint32_t StreamCount = getPdb().getNumStreams();
3900b57cec5SDimitry Andric   uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
3930b57cec5SDimitry Andric     P.formatLine(
3940b57cec5SDimitry Andric         "Stream {0} ({1} bytes): [{2}]",
3950b57cec5SDimitry Andric         fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
3960b57cec5SDimitry Andric         fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
3970b57cec5SDimitry Andric                   NumDigits(MaxStreamSize)),
3980b57cec5SDimitry Andric         StreamPurposes[StreamIdx].getLongName());
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric     if (opts::dump::DumpStreamBlocks) {
4010b57cec5SDimitry Andric       auto Blocks = getPdb().getStreamBlockList(StreamIdx);
4020b57cec5SDimitry Andric       std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
4030b57cec5SDimitry Andric       P.formatLine("       {0}  Blocks: [{1}]",
4040b57cec5SDimitry Andric                    fmt_repeat(' ', NumDigits(StreamCount)),
4050b57cec5SDimitry Andric                    make_range(BV.begin(), BV.end()));
4060b57cec5SDimitry Andric     }
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   return Error::success();
4100b57cec5SDimitry Andric }
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
4130b57cec5SDimitry Andric                                                            uint32_t Index) {
4140b57cec5SDimitry Andric   ExitOnError Err("Unexpected error: ");
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   auto &Dbi = Err(File.getPDBDbiStream());
4170b57cec5SDimitry Andric   const auto &Modules = Dbi.modules();
4180b57cec5SDimitry Andric   auto Modi = Modules.getModuleDescriptor(Index);
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   uint16_t ModiStream = Modi.getModuleStreamIndex();
4210b57cec5SDimitry Andric   if (ModiStream == kInvalidStreamIndex)
4220b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::no_stream,
4230b57cec5SDimitry Andric                                 "Module stream not present");
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   auto ModStreamData = File.createIndexedStream(ModiStream);
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
4280b57cec5SDimitry Andric   if (auto EC = ModS.reload())
4290b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
4300b57cec5SDimitry Andric                                 "Invalid module stream");
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric   return std::move(ModS);
4330b57cec5SDimitry Andric }
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric template <typename CallbackT>
4360b57cec5SDimitry Andric static void
4370b57cec5SDimitry Andric iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope,
4380b57cec5SDimitry Andric                  const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) {
4390b57cec5SDimitry Andric   if (HeaderScope) {
4400b57cec5SDimitry Andric     HeaderScope->P.formatLine(
4410b57cec5SDimitry Andric         "Mod {0:4} | `{1}`: ",
4420b57cec5SDimitry Andric         fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name());
4430b57cec5SDimitry Andric   }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric   AutoIndent Indent(HeaderScope);
4460b57cec5SDimitry Andric   Callback(Modi, SG);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric template <typename CallbackT>
4500b57cec5SDimitry Andric static void iterateSymbolGroups(InputFile &Input,
4510b57cec5SDimitry Andric                                 const Optional<PrintScope> &HeaderScope,
4520b57cec5SDimitry Andric                                 CallbackT Callback) {
4530b57cec5SDimitry Andric   AutoIndent Indent(HeaderScope);
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing modules: ");
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   if (opts::dump::DumpModi.getNumOccurrences() > 0) {
4580b57cec5SDimitry Andric     assert(opts::dump::DumpModi.getNumOccurrences() == 1);
4590b57cec5SDimitry Andric     uint32_t Modi = opts::dump::DumpModi;
4600b57cec5SDimitry Andric     SymbolGroup SG(&Input, Modi);
4610b57cec5SDimitry Andric     iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG,
4620b57cec5SDimitry Andric                      Modi, Callback);
4630b57cec5SDimitry Andric     return;
4640b57cec5SDimitry Andric   }
4650b57cec5SDimitry Andric 
4660b57cec5SDimitry Andric   uint32_t I = 0;
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   for (const auto &SG : Input.symbol_groups()) {
4690b57cec5SDimitry Andric     if (shouldDumpSymbolGroup(I, SG))
4700b57cec5SDimitry Andric       iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I,
4710b57cec5SDimitry Andric                        Callback);
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric     ++I;
4740b57cec5SDimitry Andric   }
4750b57cec5SDimitry Andric }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric template <typename SubsectionT>
4780b57cec5SDimitry Andric static void iterateModuleSubsections(
4790b57cec5SDimitry Andric     InputFile &File, const Optional<PrintScope> &HeaderScope,
4800b57cec5SDimitry Andric     llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)>
4810b57cec5SDimitry Andric         Callback) {
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   iterateSymbolGroups(File, HeaderScope,
4840b57cec5SDimitry Andric                       [&](uint32_t Modi, const SymbolGroup &SG) {
4850b57cec5SDimitry Andric                         for (const auto &SS : SG.getDebugSubsections()) {
4860b57cec5SDimitry Andric                           SubsectionT Subsection;
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric                           if (SS.kind() != Subsection.kind())
4890b57cec5SDimitry Andric                             continue;
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric                           BinaryStreamReader Reader(SS.getRecordData());
4920b57cec5SDimitry Andric                           if (auto EC = Subsection.initialize(Reader))
4930b57cec5SDimitry Andric                             continue;
4940b57cec5SDimitry Andric                           Callback(Modi, SG, Subsection);
4950b57cec5SDimitry Andric                         }
4960b57cec5SDimitry Andric                       });
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
5000b57cec5SDimitry Andric                           ArrayRef<llvm::object::coff_section>>>
5010b57cec5SDimitry Andric loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
5020b57cec5SDimitry Andric   if (!File.hasPDBDbiStream())
5030b57cec5SDimitry Andric     return make_error<StringError>(
5040b57cec5SDimitry Andric         "Section headers require a DBI Stream, which could not be loaded",
5050b57cec5SDimitry Andric         inconvertibleErrorCode());
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   auto &Dbi = cantFail(File.getPDBDbiStream());
5080b57cec5SDimitry Andric   uint32_t SI = Dbi.getDebugStreamIndex(Type);
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   if (SI == kInvalidStreamIndex)
5110b57cec5SDimitry Andric     return make_error<StringError>(
5120b57cec5SDimitry Andric         "PDB does not contain the requested image section header type",
5130b57cec5SDimitry Andric         inconvertibleErrorCode());
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric   auto Stream = File.createIndexedStream(SI);
5160b57cec5SDimitry Andric   if (!Stream)
5170b57cec5SDimitry Andric     return make_error<StringError>("Could not load the required stream data",
5180b57cec5SDimitry Andric                                    inconvertibleErrorCode());
5190b57cec5SDimitry Andric 
5200b57cec5SDimitry Andric   ArrayRef<object::coff_section> Headers;
5210b57cec5SDimitry Andric   if (Stream->getLength() % sizeof(object::coff_section) != 0)
5220b57cec5SDimitry Andric     return make_error<StringError>(
5230b57cec5SDimitry Andric         "Section header array size is not a multiple of section header size",
5240b57cec5SDimitry Andric         inconvertibleErrorCode());
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric   uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
5270b57cec5SDimitry Andric   BinaryStreamReader Reader(*Stream);
5280b57cec5SDimitry Andric   cantFail(Reader.readArray(Headers, NumHeaders));
5290b57cec5SDimitry Andric   return std::make_pair(std::move(Stream), Headers);
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric static std::vector<std::string> getSectionNames(PDBFile &File) {
5330b57cec5SDimitry Andric   auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
5340b57cec5SDimitry Andric   if (!ExpectedHeaders)
5350b57cec5SDimitry Andric     return {};
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric   std::unique_ptr<MappedBlockStream> Stream;
5380b57cec5SDimitry Andric   ArrayRef<object::coff_section> Headers;
5390b57cec5SDimitry Andric   std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
5400b57cec5SDimitry Andric   std::vector<std::string> Names;
5410b57cec5SDimitry Andric   for (const auto &H : Headers)
5420b57cec5SDimitry Andric     Names.push_back(H.Name);
5430b57cec5SDimitry Andric   return Names;
5440b57cec5SDimitry Andric }
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC,
5470b57cec5SDimitry Andric                                ArrayRef<std::string> SectionNames,
5480b57cec5SDimitry Andric                                uint32_t FieldWidth) {
5490b57cec5SDimitry Andric   std::string NameInsert;
5500b57cec5SDimitry Andric   if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) {
5510b57cec5SDimitry Andric     StringRef SectionName = SectionNames[SC.ISect - 1];
5520b57cec5SDimitry Andric     NameInsert = formatv("[{0}]", SectionName).str();
5530b57cec5SDimitry Andric   } else
5540b57cec5SDimitry Andric     NameInsert = "[???]";
5550b57cec5SDimitry Andric   P.formatLine("SC{5}  | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
5560b57cec5SDimitry Andric                "crc = {4}",
5570b57cec5SDimitry Andric                formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
5580b57cec5SDimitry Andric                fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
5590b57cec5SDimitry Andric                fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2));
5600b57cec5SDimitry Andric   AutoIndent Indent(P, FieldWidth + 2);
5610b57cec5SDimitry Andric   P.formatLine("      {0}",
5620b57cec5SDimitry Andric                formatSectionCharacteristics(P.getIndentLevel() + 6,
5630b57cec5SDimitry Andric                                             SC.Characteristics, 3, " | "));
5640b57cec5SDimitry Andric }
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC,
5670b57cec5SDimitry Andric                                ArrayRef<std::string> SectionNames,
5680b57cec5SDimitry Andric                                uint32_t FieldWidth) {
5690b57cec5SDimitry Andric   P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
5700b57cec5SDimitry Andric                "crc = {4}, coff section = {5}",
5710b57cec5SDimitry Andric                formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
5720b57cec5SDimitry Andric                fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc),
5730b57cec5SDimitry Andric                fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff));
5740b57cec5SDimitry Andric   P.formatLine("      {0}",
5750b57cec5SDimitry Andric                formatSectionCharacteristics(P.getIndentLevel() + 6,
5760b57cec5SDimitry Andric                                             SC.Base.Characteristics, 3, " | "));
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric Error DumpOutputStyle::dumpModules() {
5800b57cec5SDimitry Andric   printHeader(P, "Modules");
5810b57cec5SDimitry Andric 
5820b57cec5SDimitry Andric   if (File.isObj()) {
5830b57cec5SDimitry Andric     printStreamNotValidForObj();
5840b57cec5SDimitry Andric     return Error::success();
5850b57cec5SDimitry Andric   }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   if (!getPdb().hasPDBDbiStream()) {
5880b57cec5SDimitry Andric     printStreamNotPresent("DBI");
5890b57cec5SDimitry Andric     return Error::success();
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   AutoIndent Indent(P);
5930b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing modules: ");
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   auto &Stream = Err(getPdb().getPDBDbiStream());
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric   const DbiModuleList &Modules = Stream.modules();
5980b57cec5SDimitry Andric   iterateSymbolGroups(
5990b57cec5SDimitry Andric       File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
6000b57cec5SDimitry Andric         auto Desc = Modules.getModuleDescriptor(Modi);
6010b57cec5SDimitry Andric         if (opts::dump::DumpSectionContribs) {
6020b57cec5SDimitry Andric           std::vector<std::string> Sections = getSectionNames(getPdb());
6030b57cec5SDimitry Andric           dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0);
6040b57cec5SDimitry Andric         }
6050b57cec5SDimitry Andric         P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
6060b57cec5SDimitry Andric         P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
6070b57cec5SDimitry Andric                      Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
6080b57cec5SDimitry Andric                      Desc.hasECInfo());
6090b57cec5SDimitry Andric         StringRef PdbFilePath =
6100b57cec5SDimitry Andric             Err(Stream.getECName(Desc.getPdbFilePathNameIndex()));
6110b57cec5SDimitry Andric         StringRef SrcFilePath =
6120b57cec5SDimitry Andric             Err(Stream.getECName(Desc.getSourceFileNameIndex()));
6130b57cec5SDimitry Andric         P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
6140b57cec5SDimitry Andric                      Desc.getPdbFilePathNameIndex(), PdbFilePath,
6150b57cec5SDimitry Andric                      Desc.getSourceFileNameIndex(), SrcFilePath);
6160b57cec5SDimitry Andric       });
6170b57cec5SDimitry Andric   return Error::success();
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleFiles() {
6210b57cec5SDimitry Andric   printHeader(P, "Files");
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   if (File.isObj()) {
6240b57cec5SDimitry Andric     printStreamNotValidForObj();
6250b57cec5SDimitry Andric     return Error::success();
6260b57cec5SDimitry Andric   }
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric   if (!getPdb().hasPDBDbiStream()) {
6290b57cec5SDimitry Andric     printStreamNotPresent("DBI");
6300b57cec5SDimitry Andric     return Error::success();
6310b57cec5SDimitry Andric   }
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing modules: ");
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric   iterateSymbolGroups(File, PrintScope{P, 11},
6360b57cec5SDimitry Andric                       [this, &Err](uint32_t Modi, const SymbolGroup &Strings) {
6370b57cec5SDimitry Andric                         auto &Stream = Err(getPdb().getPDBDbiStream());
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric                         const DbiModuleList &Modules = Stream.modules();
6400b57cec5SDimitry Andric                         for (const auto &F : Modules.source_files(Modi)) {
6410b57cec5SDimitry Andric                           Strings.formatFromFileName(P, F);
6420b57cec5SDimitry Andric                         }
6430b57cec5SDimitry Andric                       });
6440b57cec5SDimitry Andric   return Error::success();
6450b57cec5SDimitry Andric }
6460b57cec5SDimitry Andric 
6470b57cec5SDimitry Andric Error DumpOutputStyle::dumpSymbolStats() {
6480b57cec5SDimitry Andric   printHeader(P, "Module Stats");
6490b57cec5SDimitry Andric 
6500b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
6510b57cec5SDimitry Andric     printStreamNotPresent("DBI");
6520b57cec5SDimitry Andric     return Error::success();
6530b57cec5SDimitry Andric   }
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing modules: ");
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric   StatCollection SymStats;
6580b57cec5SDimitry Andric   StatCollection ChunkStats;
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric   Optional<PrintScope> Scope;
6610b57cec5SDimitry Andric   if (File.isPdb())
6620b57cec5SDimitry Andric     Scope.emplace(P, 2);
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric   iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) {
6650b57cec5SDimitry Andric     StatCollection SS = getSymbolStats(SG, SymStats);
6660b57cec5SDimitry Andric     StatCollection CS = getChunkStats(SG, ChunkStats);
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric     if (SG.getFile().isPdb()) {
6690b57cec5SDimitry Andric       AutoIndent Indent(P);
6700b57cec5SDimitry Andric       auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
6710b57cec5SDimitry Andric       uint32_t ModCount = Modules.getModuleCount();
6720b57cec5SDimitry Andric       DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
6730b57cec5SDimitry Andric       uint32_t StreamIdx = Desc.getModuleStreamIndex();
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric       if (StreamIdx == kInvalidStreamIndex) {
6760b57cec5SDimitry Andric         P.formatLine("Mod {0} (debug info not present): [{1}]",
6770b57cec5SDimitry Andric                      fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
6780b57cec5SDimitry Andric                      Desc.getModuleName());
6790b57cec5SDimitry Andric         return;
6800b57cec5SDimitry Andric       }
6810b57cec5SDimitry Andric       P.formatLine("Stream {0}, {1} bytes", StreamIdx,
6820b57cec5SDimitry Andric                    getPdb().getStreamByteSize(StreamIdx));
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric       printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
6850b57cec5SDimitry Andric       printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
6860b57cec5SDimitry Andric     }
6870b57cec5SDimitry Andric   });
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   if (SymStats.Totals.Count > 0) {
6900b57cec5SDimitry Andric     P.printLine("  Summary |");
6910b57cec5SDimitry Andric     AutoIndent Indent(P, 4);
6920b57cec5SDimitry Andric     printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
6930b57cec5SDimitry Andric     printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
6940b57cec5SDimitry Andric   }
6950b57cec5SDimitry Andric 
6960b57cec5SDimitry Andric   return Error::success();
6970b57cec5SDimitry Andric }
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypeStats() {
7000b57cec5SDimitry Andric   printHeader(P, "Type Record Stats");
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric   // Iterate the types, categorize by kind, accumulate size stats.
7030b57cec5SDimitry Andric   StatCollection TypeStats;
704*5ffd83dbSDimitry Andric   LazyRandomTypeCollection &Types =
705*5ffd83dbSDimitry Andric       opts::dump::DumpTypeStats ? File.types() : File.ids();
7060b57cec5SDimitry Andric   for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
7070b57cec5SDimitry Andric     CVType Type = Types.getType(*TI);
7080b57cec5SDimitry Andric     TypeStats.update(uint32_t(Type.kind()), Type.length());
7090b57cec5SDimitry Andric   }
7100b57cec5SDimitry Andric 
7110b57cec5SDimitry Andric   P.NewLine();
7120b57cec5SDimitry Andric   P.formatLine("  Types");
7130b57cec5SDimitry Andric   AutoIndent Indent(P);
714*5ffd83dbSDimitry Andric   P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total",
7150b57cec5SDimitry Andric                TypeStats.Totals.Count, TypeStats.Totals.Size,
7160b57cec5SDimitry Andric                (double)TypeStats.Totals.Size / TypeStats.Totals.Count);
7170b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('-', 74));
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric   for (const auto &K : TypeStats.getStatsSortedBySize()) {
720*5ffd83dbSDimitry Andric     P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)",
7210b57cec5SDimitry Andric                  formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count,
7220b57cec5SDimitry Andric                  K.second.Size, (double)K.second.Size / K.second.Count);
7230b57cec5SDimitry Andric   }
7240b57cec5SDimitry Andric   return Error::success();
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric static bool isValidNamespaceIdentifier(StringRef S) {
7280b57cec5SDimitry Andric   if (S.empty())
7290b57cec5SDimitry Andric     return false;
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric   if (std::isdigit(S[0]))
7320b57cec5SDimitry Andric     return false;
7330b57cec5SDimitry Andric 
7340b57cec5SDimitry Andric   return llvm::all_of(S, [](char C) { return std::isalnum(C); });
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric namespace {
7380b57cec5SDimitry Andric constexpr uint32_t kNoneUdtKind = 0;
7390b57cec5SDimitry Andric constexpr uint32_t kSimpleUdtKind = 1;
7400b57cec5SDimitry Andric constexpr uint32_t kUnknownUdtKind = 2;
7410b57cec5SDimitry Andric const StringRef NoneLabel("<none type>");
7420b57cec5SDimitry Andric const StringRef SimpleLabel("<simple type>");
7430b57cec5SDimitry Andric const StringRef UnknownLabel("<unknown type>");
7440b57cec5SDimitry Andric 
7450b57cec5SDimitry Andric } // namespace
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric static StringRef getUdtStatLabel(uint32_t Kind) {
7480b57cec5SDimitry Andric   if (Kind == kNoneUdtKind)
7490b57cec5SDimitry Andric     return NoneLabel;
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric   if (Kind == kSimpleUdtKind)
7520b57cec5SDimitry Andric     return SimpleLabel;
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric   if (Kind == kUnknownUdtKind)
7550b57cec5SDimitry Andric     return UnknownLabel;
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
7610b57cec5SDimitry Andric   size_t L = 0;
7620b57cec5SDimitry Andric   for (const auto &Stat : Stats.Individual) {
7630b57cec5SDimitry Andric     StringRef Label = getUdtStatLabel(Stat.first);
7640b57cec5SDimitry Andric     L = std::max(L, Label.size());
7650b57cec5SDimitry Andric   }
7660b57cec5SDimitry Andric   return static_cast<uint32_t>(L);
7670b57cec5SDimitry Andric }
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric Error DumpOutputStyle::dumpUdtStats() {
7700b57cec5SDimitry Andric   printHeader(P, "S_UDT Record Stats");
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) {
7730b57cec5SDimitry Andric     printStreamNotPresent("Globals");
7740b57cec5SDimitry Andric     return Error::success();
7750b57cec5SDimitry Andric   }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   StatCollection UdtStats;
7780b57cec5SDimitry Andric   StatCollection UdtTargetStats;
7790b57cec5SDimitry Andric   AutoIndent Indent(P, 4);
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric   auto &TpiTypes = File.types();
7820b57cec5SDimitry Andric 
7830b57cec5SDimitry Andric   StringMap<StatCollection::Stat> NamespacedStats;
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric   size_t LongestNamespace = 0;
7860b57cec5SDimitry Andric   auto HandleOneSymbol = [&](const CVSymbol &Sym) {
7870b57cec5SDimitry Andric     if (Sym.kind() != SymbolKind::S_UDT)
7880b57cec5SDimitry Andric       return;
7890b57cec5SDimitry Andric     UdtStats.update(SymbolKind::S_UDT, Sym.length());
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric     UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric     uint32_t Kind = 0;
7940b57cec5SDimitry Andric     uint32_t RecordSize = 0;
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric     if (UDT.Type.isNoneType())
7970b57cec5SDimitry Andric       Kind = kNoneUdtKind;
7980b57cec5SDimitry Andric     else if (UDT.Type.isSimple())
7990b57cec5SDimitry Andric       Kind = kSimpleUdtKind;
8000b57cec5SDimitry Andric     else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
8010b57cec5SDimitry Andric       Kind = T->kind();
8020b57cec5SDimitry Andric       RecordSize = T->length();
8030b57cec5SDimitry Andric     } else
8040b57cec5SDimitry Andric       Kind = kUnknownUdtKind;
8050b57cec5SDimitry Andric 
8060b57cec5SDimitry Andric     UdtTargetStats.update(Kind, RecordSize);
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric     size_t Pos = UDT.Name.find("::");
8090b57cec5SDimitry Andric     if (Pos == StringRef::npos)
8100b57cec5SDimitry Andric       return;
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric     StringRef Scope = UDT.Name.take_front(Pos);
8130b57cec5SDimitry Andric     if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
8140b57cec5SDimitry Andric       return;
8150b57cec5SDimitry Andric 
8160b57cec5SDimitry Andric     LongestNamespace = std::max(LongestNamespace, Scope.size());
8170b57cec5SDimitry Andric     NamespacedStats[Scope].update(RecordSize);
8180b57cec5SDimitry Andric   };
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   P.NewLine();
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   if (File.isPdb()) {
8230b57cec5SDimitry Andric     auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
8240b57cec5SDimitry Andric     auto ExpGlobals = getPdb().getPDBGlobalsStream();
8250b57cec5SDimitry Andric     if (!ExpGlobals)
8260b57cec5SDimitry Andric       return ExpGlobals.takeError();
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric     for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
8290b57cec5SDimitry Andric       CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
8300b57cec5SDimitry Andric       HandleOneSymbol(Sym);
8310b57cec5SDimitry Andric     }
8320b57cec5SDimitry Andric   } else {
8330b57cec5SDimitry Andric     for (const auto &Sec : File.symbol_groups()) {
8340b57cec5SDimitry Andric       for (const auto &SS : Sec.getDebugSubsections()) {
8350b57cec5SDimitry Andric         if (SS.kind() != DebugSubsectionKind::Symbols)
8360b57cec5SDimitry Andric           continue;
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric         DebugSymbolsSubsectionRef Symbols;
8390b57cec5SDimitry Andric         BinaryStreamReader Reader(SS.getRecordData());
8400b57cec5SDimitry Andric         cantFail(Symbols.initialize(Reader));
8410b57cec5SDimitry Andric         for (const auto &S : Symbols)
8420b57cec5SDimitry Andric           HandleOneSymbol(S);
8430b57cec5SDimitry Andric       }
8440b57cec5SDimitry Andric     }
8450b57cec5SDimitry Andric   }
8460b57cec5SDimitry Andric 
8470b57cec5SDimitry Andric   LongestNamespace += StringRef(" namespace ''").size();
8480b57cec5SDimitry Andric   size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
8490b57cec5SDimitry Andric   size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric   // Compute the max number of digits for count and size fields, including comma
8520b57cec5SDimitry Andric   // separators.
8530b57cec5SDimitry Andric   StringRef CountHeader("Count");
8540b57cec5SDimitry Andric   StringRef SizeHeader("Size");
8550b57cec5SDimitry Andric   size_t CD = NumDigits(UdtStats.Totals.Count);
8560b57cec5SDimitry Andric   CD += (CD - 1) / 3;
8570b57cec5SDimitry Andric   CD = std::max(CD, CountHeader.size());
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric   size_t SD = NumDigits(UdtStats.Totals.Size);
8600b57cec5SDimitry Andric   SD += (SD - 1) / 3;
8610b57cec5SDimitry Andric   SD = std::max(SD, SizeHeader.size());
8620b57cec5SDimitry Andric 
8630b57cec5SDimitry Andric   uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric   P.formatLine("{0} | {1}  {2}",
8660b57cec5SDimitry Andric                fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
8670b57cec5SDimitry Andric                fmt_align(CountHeader, AlignStyle::Right, CD),
8680b57cec5SDimitry Andric                fmt_align(SizeHeader, AlignStyle::Right, SD));
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('-', TableWidth));
8710b57cec5SDimitry Andric   for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) {
8720b57cec5SDimitry Andric     StringRef Label = getUdtStatLabel(Stat.first);
8730b57cec5SDimitry Andric     P.formatLine("{0} | {1:N}  {2:N}",
8740b57cec5SDimitry Andric                  fmt_align(Label, AlignStyle::Right, FieldWidth),
8750b57cec5SDimitry Andric                  fmt_align(Stat.second.Count, AlignStyle::Right, CD),
8760b57cec5SDimitry Andric                  fmt_align(Stat.second.Size, AlignStyle::Right, SD));
8770b57cec5SDimitry Andric   }
8780b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('-', TableWidth));
8790b57cec5SDimitry Andric   P.formatLine("{0} | {1:N}  {2:N}",
8800b57cec5SDimitry Andric                fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
8810b57cec5SDimitry Andric                fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
8820b57cec5SDimitry Andric                fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
8830b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('-', TableWidth));
8840b57cec5SDimitry Andric   struct StrAndStat {
8850b57cec5SDimitry Andric     StringRef Key;
8860b57cec5SDimitry Andric     StatCollection::Stat Stat;
8870b57cec5SDimitry Andric   };
8880b57cec5SDimitry Andric 
8890b57cec5SDimitry Andric   // Print namespace stats in descending order of size.
8900b57cec5SDimitry Andric   std::vector<StrAndStat> NamespacedStatsSorted;
8910b57cec5SDimitry Andric   for (const auto &Stat : NamespacedStats)
8920b57cec5SDimitry Andric     NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second});
8930b57cec5SDimitry Andric   llvm::stable_sort(NamespacedStatsSorted,
8940b57cec5SDimitry Andric                     [](const StrAndStat &L, const StrAndStat &R) {
8950b57cec5SDimitry Andric                       return L.Stat.Size > R.Stat.Size;
8960b57cec5SDimitry Andric                     });
8970b57cec5SDimitry Andric   for (const auto &Stat : NamespacedStatsSorted) {
898*5ffd83dbSDimitry Andric     std::string Label = std::string(formatv("namespace '{0}'", Stat.Key));
8990b57cec5SDimitry Andric     P.formatLine("{0} | {1:N}  {2:N}",
9000b57cec5SDimitry Andric                  fmt_align(Label, AlignStyle::Right, FieldWidth),
9010b57cec5SDimitry Andric                  fmt_align(Stat.Stat.Count, AlignStyle::Right, CD),
9020b57cec5SDimitry Andric                  fmt_align(Stat.Stat.Size, AlignStyle::Right, SD));
9030b57cec5SDimitry Andric   }
9040b57cec5SDimitry Andric   return Error::success();
9050b57cec5SDimitry Andric }
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
9080b57cec5SDimitry Andric                                    const LineColumnEntry &E) {
9090b57cec5SDimitry Andric   const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
9100b57cec5SDimitry Andric   uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric   // Let's try to keep it under 100 characters
9130b57cec5SDimitry Andric   constexpr uint32_t kMaxRowLength = 100;
9140b57cec5SDimitry Andric   // At least 3 spaces between columns.
9150b57cec5SDimitry Andric   uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
9160b57cec5SDimitry Andric   uint32_t ItemsLeft = E.LineNumbers.size();
9170b57cec5SDimitry Andric   auto LineIter = E.LineNumbers.begin();
9180b57cec5SDimitry Andric   while (ItemsLeft != 0) {
9190b57cec5SDimitry Andric     uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
9200b57cec5SDimitry Andric     for (uint32_t I = 0; I < RowColumns; ++I) {
9210b57cec5SDimitry Andric       LineInfo Line(LineIter->Flags);
9220b57cec5SDimitry Andric       std::string LineStr;
9230b57cec5SDimitry Andric       if (Line.isAlwaysStepInto())
9240b57cec5SDimitry Andric         LineStr = "ASI";
9250b57cec5SDimitry Andric       else if (Line.isNeverStepInto())
9260b57cec5SDimitry Andric         LineStr = "NSI";
9270b57cec5SDimitry Andric       else
9280b57cec5SDimitry Andric         LineStr = utostr(Line.getStartLine());
9290b57cec5SDimitry Andric       char Statement = Line.isStatement() ? ' ' : '!';
9300b57cec5SDimitry Andric       P.format("{0} {1:X-} {2} ",
9310b57cec5SDimitry Andric                fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
9320b57cec5SDimitry Andric                fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
9330b57cec5SDimitry Andric                Statement);
9340b57cec5SDimitry Andric       ++LineIter;
9350b57cec5SDimitry Andric       --ItemsLeft;
9360b57cec5SDimitry Andric     }
9370b57cec5SDimitry Andric     P.NewLine();
9380b57cec5SDimitry Andric   }
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric 
9410b57cec5SDimitry Andric Error DumpOutputStyle::dumpLines() {
9420b57cec5SDimitry Andric   printHeader(P, "Lines");
9430b57cec5SDimitry Andric 
9440b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
9450b57cec5SDimitry Andric     printStreamNotPresent("DBI");
9460b57cec5SDimitry Andric     return Error::success();
9470b57cec5SDimitry Andric   }
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric   uint32_t LastModi = UINT32_MAX;
9500b57cec5SDimitry Andric   uint32_t LastNameIndex = UINT32_MAX;
9510b57cec5SDimitry Andric   iterateModuleSubsections<DebugLinesSubsectionRef>(
9520b57cec5SDimitry Andric       File, PrintScope{P, 4},
9530b57cec5SDimitry Andric       [this, &LastModi, &LastNameIndex](uint32_t Modi,
9540b57cec5SDimitry Andric                                         const SymbolGroup &Strings,
9550b57cec5SDimitry Andric                                         DebugLinesSubsectionRef &Lines) {
9560b57cec5SDimitry Andric         uint16_t Segment = Lines.header()->RelocSegment;
9570b57cec5SDimitry Andric         uint32_t Begin = Lines.header()->RelocOffset;
9580b57cec5SDimitry Andric         uint32_t End = Begin + Lines.header()->CodeSize;
9590b57cec5SDimitry Andric         for (const auto &Block : Lines) {
9600b57cec5SDimitry Andric           if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
9610b57cec5SDimitry Andric             LastModi = Modi;
9620b57cec5SDimitry Andric             LastNameIndex = Block.NameIndex;
9630b57cec5SDimitry Andric             Strings.formatFromChecksumsOffset(P, Block.NameIndex);
9640b57cec5SDimitry Andric           }
9650b57cec5SDimitry Andric 
9660b57cec5SDimitry Andric           AutoIndent Indent(P, 2);
9670b57cec5SDimitry Andric           P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
9680b57cec5SDimitry Andric           uint32_t Count = Block.LineNumbers.size();
9690b57cec5SDimitry Andric           if (Lines.hasColumnInfo())
9700b57cec5SDimitry Andric             P.format("line/column/addr entries = {0}", Count);
9710b57cec5SDimitry Andric           else
9720b57cec5SDimitry Andric             P.format("line/addr entries = {0}", Count);
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric           P.NewLine();
9750b57cec5SDimitry Andric           typesetLinesAndColumns(P, Begin, Block);
9760b57cec5SDimitry Andric         }
9770b57cec5SDimitry Andric       });
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric   return Error::success();
9800b57cec5SDimitry Andric }
9810b57cec5SDimitry Andric 
9820b57cec5SDimitry Andric Error DumpOutputStyle::dumpInlineeLines() {
9830b57cec5SDimitry Andric   printHeader(P, "Inlinee Lines");
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
9860b57cec5SDimitry Andric     printStreamNotPresent("DBI");
9870b57cec5SDimitry Andric     return Error::success();
9880b57cec5SDimitry Andric   }
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric   iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
9910b57cec5SDimitry Andric       File, PrintScope{P, 2},
9920b57cec5SDimitry Andric       [this](uint32_t Modi, const SymbolGroup &Strings,
9930b57cec5SDimitry Andric              DebugInlineeLinesSubsectionRef &Lines) {
9940b57cec5SDimitry Andric         P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
9950b57cec5SDimitry Andric         for (const auto &Entry : Lines) {
9960b57cec5SDimitry Andric           P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
9970b57cec5SDimitry Andric                        fmtle(Entry.Header->SourceLineNum));
9980b57cec5SDimitry Andric           Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
9990b57cec5SDimitry Andric           for (const auto &ExtraFileID : Entry.ExtraFiles) {
10000b57cec5SDimitry Andric             P.formatLine("                   ");
10010b57cec5SDimitry Andric             Strings.formatFromChecksumsOffset(P, ExtraFileID, true);
10020b57cec5SDimitry Andric           }
10030b57cec5SDimitry Andric         }
10040b57cec5SDimitry Andric         P.NewLine();
10050b57cec5SDimitry Andric       });
10060b57cec5SDimitry Andric 
10070b57cec5SDimitry Andric   return Error::success();
10080b57cec5SDimitry Andric }
10090b57cec5SDimitry Andric 
10100b57cec5SDimitry Andric Error DumpOutputStyle::dumpXmi() {
10110b57cec5SDimitry Andric   printHeader(P, "Cross Module Imports");
10120b57cec5SDimitry Andric 
10130b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
10140b57cec5SDimitry Andric     printStreamNotPresent("DBI");
10150b57cec5SDimitry Andric     return Error::success();
10160b57cec5SDimitry Andric   }
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric   iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
10190b57cec5SDimitry Andric       File, PrintScope{P, 2},
10200b57cec5SDimitry Andric       [this](uint32_t Modi, const SymbolGroup &Strings,
10210b57cec5SDimitry Andric              DebugCrossModuleImportsSubsectionRef &Imports) {
10220b57cec5SDimitry Andric         P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric         for (const auto &Xmi : Imports) {
10250b57cec5SDimitry Andric           auto ExpectedModule =
10260b57cec5SDimitry Andric               Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
10270b57cec5SDimitry Andric           StringRef Module;
10280b57cec5SDimitry Andric           SmallString<32> ModuleStorage;
10290b57cec5SDimitry Andric           if (!ExpectedModule) {
10300b57cec5SDimitry Andric             Module = "(unknown module)";
10310b57cec5SDimitry Andric             consumeError(ExpectedModule.takeError());
10320b57cec5SDimitry Andric           } else
10330b57cec5SDimitry Andric             Module = *ExpectedModule;
10340b57cec5SDimitry Andric           if (Module.size() > 32) {
10350b57cec5SDimitry Andric             ModuleStorage = "...";
10360b57cec5SDimitry Andric             ModuleStorage += Module.take_back(32 - 3);
10370b57cec5SDimitry Andric             Module = ModuleStorage;
10380b57cec5SDimitry Andric           }
10390b57cec5SDimitry Andric           std::vector<std::string> TIs;
10400b57cec5SDimitry Andric           for (const auto I : Xmi.Imports)
1041*5ffd83dbSDimitry Andric             TIs.push_back(std::string(formatv("{0,+10:X+}", fmtle(I))));
10420b57cec5SDimitry Andric           std::string Result =
10430b57cec5SDimitry Andric               typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
10440b57cec5SDimitry Andric           P.formatLine("{0,+32} | {1}", Module, Result);
10450b57cec5SDimitry Andric         }
10460b57cec5SDimitry Andric       });
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric   return Error::success();
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric Error DumpOutputStyle::dumpXme() {
10520b57cec5SDimitry Andric   printHeader(P, "Cross Module Exports");
10530b57cec5SDimitry Andric 
10540b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
10550b57cec5SDimitry Andric     printStreamNotPresent("DBI");
10560b57cec5SDimitry Andric     return Error::success();
10570b57cec5SDimitry Andric   }
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric   iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
10600b57cec5SDimitry Andric       File, PrintScope{P, 2},
10610b57cec5SDimitry Andric       [this](uint32_t Modi, const SymbolGroup &Strings,
10620b57cec5SDimitry Andric              DebugCrossModuleExportsSubsectionRef &Exports) {
10630b57cec5SDimitry Andric         P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
10640b57cec5SDimitry Andric         for (const auto &Export : Exports) {
10650b57cec5SDimitry Andric           P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
10660b57cec5SDimitry Andric                        TypeIndex(Export.Global));
10670b57cec5SDimitry Andric         }
10680b57cec5SDimitry Andric       });
10690b57cec5SDimitry Andric 
10700b57cec5SDimitry Andric   return Error::success();
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric 
10730b57cec5SDimitry Andric std::string formatFrameType(object::frame_type FT) {
10740b57cec5SDimitry Andric   switch (FT) {
10750b57cec5SDimitry Andric   case object::frame_type::Fpo:
10760b57cec5SDimitry Andric     return "FPO";
10770b57cec5SDimitry Andric   case object::frame_type::NonFpo:
10780b57cec5SDimitry Andric     return "Non-FPO";
10790b57cec5SDimitry Andric   case object::frame_type::Trap:
10800b57cec5SDimitry Andric     return "Trap";
10810b57cec5SDimitry Andric   case object::frame_type::Tss:
10820b57cec5SDimitry Andric     return "TSS";
10830b57cec5SDimitry Andric   }
10840b57cec5SDimitry Andric   return "<unknown>";
10850b57cec5SDimitry Andric }
10860b57cec5SDimitry Andric 
10870b57cec5SDimitry Andric Error DumpOutputStyle::dumpOldFpo(PDBFile &File) {
10880b57cec5SDimitry Andric   printHeader(P, "Old FPO Data");
10890b57cec5SDimitry Andric 
10900b57cec5SDimitry Andric   ExitOnError Err("Error dumping old fpo data:");
10910b57cec5SDimitry Andric   auto &Dbi = Err(File.getPDBDbiStream());
10920b57cec5SDimitry Andric 
10930b57cec5SDimitry Andric   if (!Dbi.hasOldFpoRecords()) {
10940b57cec5SDimitry Andric     printStreamNotPresent("FPO");
10950b57cec5SDimitry Andric     return Error::success();
10960b57cec5SDimitry Andric   }
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric   const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords();
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric   P.printLine("  RVA    | Code | Locals | Params | Prolog | Saved Regs | Use "
11010b57cec5SDimitry Andric               "BP | Has SEH | Frame Type");
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric   for (const object::FpoData &FD : Records) {
11040b57cec5SDimitry Andric     P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | "
11050b57cec5SDimitry Andric                  "{7,7} | {8,9}",
11060b57cec5SDimitry Andric                  uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals),
11070b57cec5SDimitry Andric                  uint32_t(FD.NumParams), FD.getPrologSize(),
11080b57cec5SDimitry Andric                  FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(),
11090b57cec5SDimitry Andric                  formatFrameType(FD.getFP()));
11100b57cec5SDimitry Andric   }
11110b57cec5SDimitry Andric   return Error::success();
11120b57cec5SDimitry Andric }
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric Error DumpOutputStyle::dumpNewFpo(PDBFile &File) {
11150b57cec5SDimitry Andric   printHeader(P, "New FPO Data");
11160b57cec5SDimitry Andric 
11170b57cec5SDimitry Andric   ExitOnError Err("Error dumping new fpo data:");
11180b57cec5SDimitry Andric   auto &Dbi = Err(File.getPDBDbiStream());
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric   if (!Dbi.hasNewFpoRecords()) {
11210b57cec5SDimitry Andric     printStreamNotPresent("New FPO");
11220b57cec5SDimitry Andric     return Error::success();
11230b57cec5SDimitry Andric   }
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric   const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords();
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric   P.printLine("  RVA    | Code | Locals | Params | Stack | Prolog | Saved Regs "
11280b57cec5SDimitry Andric               "| Has SEH | Has C++EH | Start | Program");
11290b57cec5SDimitry Andric   for (const FrameData &FD : FDS) {
11300b57cec5SDimitry Andric     bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart;
11310b57cec5SDimitry Andric     bool HasEH = FD.Flags & FrameData::HasEH;
11320b57cec5SDimitry Andric     bool HasSEH = FD.Flags & FrameData::HasSEH;
11330b57cec5SDimitry Andric 
11340b57cec5SDimitry Andric     auto &StringTable = Err(File.getStringTable());
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric     auto Program = Err(StringTable.getStringForID(FD.FrameFunc));
11370b57cec5SDimitry Andric     P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | "
11380b57cec5SDimitry Andric                  "{7,7} | {8,9} | {9,5} | {10}",
11390b57cec5SDimitry Andric                  uint32_t(FD.RvaStart), uint32_t(FD.CodeSize),
11400b57cec5SDimitry Andric                  uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize),
11410b57cec5SDimitry Andric                  uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize),
11420b57cec5SDimitry Andric                  uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart,
11430b57cec5SDimitry Andric                  Program);
11440b57cec5SDimitry Andric   }
11450b57cec5SDimitry Andric   return Error::success();
11460b57cec5SDimitry Andric }
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric Error DumpOutputStyle::dumpFpo() {
11490b57cec5SDimitry Andric   if (!File.isPdb()) {
11500b57cec5SDimitry Andric     printStreamNotValidForObj();
11510b57cec5SDimitry Andric     return Error::success();
11520b57cec5SDimitry Andric   }
11530b57cec5SDimitry Andric 
11540b57cec5SDimitry Andric   PDBFile &File = getPdb();
11550b57cec5SDimitry Andric   if (!File.hasPDBDbiStream()) {
11560b57cec5SDimitry Andric     printStreamNotPresent("DBI");
11570b57cec5SDimitry Andric     return Error::success();
11580b57cec5SDimitry Andric   }
11590b57cec5SDimitry Andric 
11600b57cec5SDimitry Andric   if (auto EC = dumpOldFpo(File))
11610b57cec5SDimitry Andric     return EC;
11620b57cec5SDimitry Andric   if (auto EC = dumpNewFpo(File))
11630b57cec5SDimitry Andric     return EC;
11640b57cec5SDimitry Andric   return Error::success();
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTableFromPdb() {
11680b57cec5SDimitry Andric   AutoIndent Indent(P);
11690b57cec5SDimitry Andric   auto IS = getPdb().getStringTable();
11700b57cec5SDimitry Andric   if (!IS) {
11710b57cec5SDimitry Andric     P.formatLine("Not present in file");
11720b57cec5SDimitry Andric     consumeError(IS.takeError());
11730b57cec5SDimitry Andric     return Error::success();
11740b57cec5SDimitry Andric   }
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric   if (opts::dump::DumpStringTable) {
11770b57cec5SDimitry Andric     if (IS->name_ids().empty())
11780b57cec5SDimitry Andric       P.formatLine("Empty");
11790b57cec5SDimitry Andric     else {
11800b57cec5SDimitry Andric       auto MaxID =
11810b57cec5SDimitry Andric           std::max_element(IS->name_ids().begin(), IS->name_ids().end());
11820b57cec5SDimitry Andric       uint32_t Digits = NumDigits(*MaxID);
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric       P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
11850b57cec5SDimitry Andric                    "String");
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric       std::vector<uint32_t> SortedIDs(IS->name_ids().begin(),
11880b57cec5SDimitry Andric                                       IS->name_ids().end());
11890b57cec5SDimitry Andric       llvm::sort(SortedIDs);
11900b57cec5SDimitry Andric       for (uint32_t I : SortedIDs) {
11910b57cec5SDimitry Andric         auto ES = IS->getStringForID(I);
11920b57cec5SDimitry Andric         llvm::SmallString<32> Str;
11930b57cec5SDimitry Andric         if (!ES) {
11940b57cec5SDimitry Andric           consumeError(ES.takeError());
11950b57cec5SDimitry Andric           Str = "Error reading string";
11960b57cec5SDimitry Andric         } else if (!ES->empty()) {
11970b57cec5SDimitry Andric           Str.append("'");
11980b57cec5SDimitry Andric           Str.append(*ES);
11990b57cec5SDimitry Andric           Str.append("'");
12000b57cec5SDimitry Andric         }
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric         if (!Str.empty())
12030b57cec5SDimitry Andric           P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits),
12040b57cec5SDimitry Andric                        Str);
12050b57cec5SDimitry Andric       }
12060b57cec5SDimitry Andric     }
12070b57cec5SDimitry Andric   }
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric   if (opts::dump::DumpStringTableDetails) {
12100b57cec5SDimitry Andric     P.NewLine();
12110b57cec5SDimitry Andric     {
12120b57cec5SDimitry Andric       P.printLine("String Table Header:");
12130b57cec5SDimitry Andric       AutoIndent Indent(P);
12140b57cec5SDimitry Andric       P.formatLine("Signature: {0}", IS->getSignature());
12150b57cec5SDimitry Andric       P.formatLine("Hash Version: {0}", IS->getHashVersion());
12160b57cec5SDimitry Andric       P.formatLine("Name Buffer Size: {0}", IS->getByteSize());
12170b57cec5SDimitry Andric       P.NewLine();
12180b57cec5SDimitry Andric     }
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric     BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer();
12210b57cec5SDimitry Andric     ArrayRef<uint8_t> Contents;
12220b57cec5SDimitry Andric     cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents));
12230b57cec5SDimitry Andric     P.formatBinary("Name Buffer", Contents, 0);
12240b57cec5SDimitry Andric     P.NewLine();
12250b57cec5SDimitry Andric     {
12260b57cec5SDimitry Andric       P.printLine("Hash Table:");
12270b57cec5SDimitry Andric       AutoIndent Indent(P);
12280b57cec5SDimitry Andric       P.formatLine("Bucket Count: {0}", IS->name_ids().size());
12290b57cec5SDimitry Andric       for (const auto &Entry : enumerate(IS->name_ids()))
12300b57cec5SDimitry Andric         P.formatLine("Bucket[{0}] : {1}", Entry.index(),
12310b57cec5SDimitry Andric                      uint32_t(Entry.value()));
12320b57cec5SDimitry Andric       P.formatLine("Name Count: {0}", IS->getNameCount());
12330b57cec5SDimitry Andric     }
12340b57cec5SDimitry Andric   }
12350b57cec5SDimitry Andric   return Error::success();
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTableFromObj() {
12390b57cec5SDimitry Andric   iterateModuleSubsections<DebugStringTableSubsectionRef>(
12400b57cec5SDimitry Andric       File, PrintScope{P, 4},
12410b57cec5SDimitry Andric       [&](uint32_t Modi, const SymbolGroup &Strings,
12420b57cec5SDimitry Andric           DebugStringTableSubsectionRef &Strings2) {
12430b57cec5SDimitry Andric         BinaryStreamRef StringTableBuffer = Strings2.getBuffer();
12440b57cec5SDimitry Andric         BinaryStreamReader Reader(StringTableBuffer);
12450b57cec5SDimitry Andric         while (Reader.bytesRemaining() > 0) {
12460b57cec5SDimitry Andric           StringRef Str;
12470b57cec5SDimitry Andric           uint32_t Offset = Reader.getOffset();
12480b57cec5SDimitry Andric           cantFail(Reader.readCString(Str));
12490b57cec5SDimitry Andric           if (Str.empty())
12500b57cec5SDimitry Andric             continue;
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric           P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4),
12530b57cec5SDimitry Andric                        Str);
12540b57cec5SDimitry Andric         }
12550b57cec5SDimitry Andric       });
12560b57cec5SDimitry Andric   return Error::success();
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric 
12590b57cec5SDimitry Andric Error DumpOutputStyle::dumpNamedStreams() {
12600b57cec5SDimitry Andric   printHeader(P, "Named Streams");
12610b57cec5SDimitry Andric 
12620b57cec5SDimitry Andric   if (File.isObj()) {
12630b57cec5SDimitry Andric     printStreamNotValidForObj();
12640b57cec5SDimitry Andric     return Error::success();
12650b57cec5SDimitry Andric   }
12660b57cec5SDimitry Andric 
12670b57cec5SDimitry Andric   AutoIndent Indent(P);
12680b57cec5SDimitry Andric   ExitOnError Err("Invalid PDB File: ");
12690b57cec5SDimitry Andric 
12700b57cec5SDimitry Andric   auto &IS = Err(File.pdb().getPDBInfoStream());
12710b57cec5SDimitry Andric   const NamedStreamMap &NS = IS.getNamedStreams();
12720b57cec5SDimitry Andric   for (const auto &Entry : NS.entries()) {
12730b57cec5SDimitry Andric     P.printLine(Entry.getKey());
12740b57cec5SDimitry Andric     AutoIndent Indent2(P, 2);
12750b57cec5SDimitry Andric     P.formatLine("Index: {0}", Entry.getValue());
12760b57cec5SDimitry Andric     P.formatLine("Size in bytes: {0}",
12770b57cec5SDimitry Andric                  File.pdb().getStreamByteSize(Entry.getValue()));
12780b57cec5SDimitry Andric   }
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric   return Error::success();
12810b57cec5SDimitry Andric }
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTable() {
12840b57cec5SDimitry Andric   printHeader(P, "String Table");
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric   if (File.isPdb())
12870b57cec5SDimitry Andric     return dumpStringTableFromPdb();
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric   return dumpStringTableFromObj();
12900b57cec5SDimitry Andric }
12910b57cec5SDimitry Andric 
12920b57cec5SDimitry Andric static void buildDepSet(LazyRandomTypeCollection &Types,
12930b57cec5SDimitry Andric                         ArrayRef<TypeIndex> Indices,
12940b57cec5SDimitry Andric                         std::map<TypeIndex, CVType> &DepSet) {
12950b57cec5SDimitry Andric   SmallVector<TypeIndex, 4> DepList;
12960b57cec5SDimitry Andric   for (const auto &I : Indices) {
12970b57cec5SDimitry Andric     TypeIndex TI(I);
12980b57cec5SDimitry Andric     if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
12990b57cec5SDimitry Andric       continue;
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric     CVType Type = Types.getType(TI);
13020b57cec5SDimitry Andric     DepSet[TI] = Type;
13030b57cec5SDimitry Andric     codeview::discoverTypeIndices(Type, DepList);
13040b57cec5SDimitry Andric     buildDepSet(Types, DepList, DepSet);
13050b57cec5SDimitry Andric   }
13060b57cec5SDimitry Andric }
13070b57cec5SDimitry Andric 
13080b57cec5SDimitry Andric static void
13090b57cec5SDimitry Andric dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
13100b57cec5SDimitry Andric                    TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
13110b57cec5SDimitry Andric                    uint32_t NumHashBuckets,
13120b57cec5SDimitry Andric                    FixedStreamArray<support::ulittle32_t> HashValues,
13130b57cec5SDimitry Andric                    TpiStream *Stream, bool Bytes, bool Extras) {
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric   Printer.formatLine("Showing {0:N} records", NumTypeRecords);
13160b57cec5SDimitry Andric   uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
13190b57cec5SDimitry Andric                            NumHashBuckets, HashValues, Stream);
13200b57cec5SDimitry Andric 
13210b57cec5SDimitry Andric   if (auto EC = codeview::visitTypeStream(Types, V)) {
13220b57cec5SDimitry Andric     Printer.formatLine("An error occurred dumping type records: {0}",
13230b57cec5SDimitry Andric                        toString(std::move(EC)));
13240b57cec5SDimitry Andric   }
13250b57cec5SDimitry Andric }
13260b57cec5SDimitry Andric 
13270b57cec5SDimitry Andric static void dumpPartialTypeStream(LinePrinter &Printer,
13280b57cec5SDimitry Andric                                   LazyRandomTypeCollection &Types,
13290b57cec5SDimitry Andric                                   TypeReferenceTracker *RefTracker,
13300b57cec5SDimitry Andric                                   TpiStream &Stream, ArrayRef<TypeIndex> TiList,
13310b57cec5SDimitry Andric                                   bool Bytes, bool Extras, bool Deps) {
13320b57cec5SDimitry Andric   uint32_t Width =
13330b57cec5SDimitry Andric       NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
13340b57cec5SDimitry Andric 
13350b57cec5SDimitry Andric   MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
13360b57cec5SDimitry Andric                            Stream.getNumHashBuckets(), Stream.getHashValues(),
13370b57cec5SDimitry Andric                            &Stream);
13380b57cec5SDimitry Andric 
13390b57cec5SDimitry Andric   if (opts::dump::DumpTypeDependents) {
13400b57cec5SDimitry Andric     // If we need to dump all dependents, then iterate each index and find
13410b57cec5SDimitry Andric     // all dependents, adding them to a map ordered by TypeIndex.
13420b57cec5SDimitry Andric     std::map<TypeIndex, CVType> DepSet;
13430b57cec5SDimitry Andric     buildDepSet(Types, TiList, DepSet);
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric     Printer.formatLine(
13460b57cec5SDimitry Andric         "Showing {0:N} records and their dependents ({1:N} records total)",
13470b57cec5SDimitry Andric         TiList.size(), DepSet.size());
13480b57cec5SDimitry Andric 
13490b57cec5SDimitry Andric     for (auto &Dep : DepSet) {
13500b57cec5SDimitry Andric       if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
13510b57cec5SDimitry Andric         Printer.formatLine("An error occurred dumping type record {0}: {1}",
13520b57cec5SDimitry Andric                            Dep.first, toString(std::move(EC)));
13530b57cec5SDimitry Andric     }
13540b57cec5SDimitry Andric   } else {
13550b57cec5SDimitry Andric     Printer.formatLine("Showing {0:N} records.", TiList.size());
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric     for (const auto &I : TiList) {
13580b57cec5SDimitry Andric       TypeIndex TI(I);
13590b57cec5SDimitry Andric       CVType Type = Types.getType(TI);
13600b57cec5SDimitry Andric       if (auto EC = codeview::visitTypeRecord(Type, TI, V))
13610b57cec5SDimitry Andric         Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
13620b57cec5SDimitry Andric                            toString(std::move(EC)));
13630b57cec5SDimitry Andric     }
13640b57cec5SDimitry Andric   }
13650b57cec5SDimitry Andric }
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypesFromObjectFile() {
13680b57cec5SDimitry Andric   LazyRandomTypeCollection Types(100);
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric   for (const auto &S : getObj().sections()) {
13718bcb0991SDimitry Andric     Expected<StringRef> NameOrErr = S.getName();
13728bcb0991SDimitry Andric     if (!NameOrErr)
13738bcb0991SDimitry Andric       return NameOrErr.takeError();
13748bcb0991SDimitry Andric     StringRef SectionName = *NameOrErr;
13750b57cec5SDimitry Andric 
13760b57cec5SDimitry Andric     // .debug$T is a standard CodeView type section, while .debug$P is the same
13770b57cec5SDimitry Andric     // format but used for MSVC precompiled header object files.
13780b57cec5SDimitry Andric     if (SectionName == ".debug$T")
13790b57cec5SDimitry Andric       printHeader(P, "Types (.debug$T)");
13800b57cec5SDimitry Andric     else if (SectionName == ".debug$P")
13810b57cec5SDimitry Andric       printHeader(P, "Precompiled Types (.debug$P)");
13820b57cec5SDimitry Andric     else
13830b57cec5SDimitry Andric       continue;
13840b57cec5SDimitry Andric 
13850b57cec5SDimitry Andric     Expected<StringRef> ContentsOrErr = S.getContents();
13860b57cec5SDimitry Andric     if (!ContentsOrErr)
13870b57cec5SDimitry Andric       return ContentsOrErr.takeError();
13880b57cec5SDimitry Andric 
13890b57cec5SDimitry Andric     uint32_t Magic;
13900b57cec5SDimitry Andric     BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little);
13910b57cec5SDimitry Andric     if (auto EC = Reader.readInteger(Magic))
13920b57cec5SDimitry Andric       return EC;
13930b57cec5SDimitry Andric     if (Magic != COFF::DEBUG_SECTION_MAGIC)
13940b57cec5SDimitry Andric       return make_error<StringError>("Invalid CodeView debug section.",
13950b57cec5SDimitry Andric                                      inconvertibleErrorCode());
13960b57cec5SDimitry Andric 
13970b57cec5SDimitry Andric     Types.reset(Reader, 100);
13980b57cec5SDimitry Andric 
13990b57cec5SDimitry Andric     if (opts::dump::DumpTypes) {
14000b57cec5SDimitry Andric       dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
14010b57cec5SDimitry Andric                          opts::dump::DumpTypeData, false);
14020b57cec5SDimitry Andric     } else if (opts::dump::DumpTypeExtras) {
14030b57cec5SDimitry Andric       auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
14040b57cec5SDimitry Andric       auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
14050b57cec5SDimitry Andric       assert(LocalHashes.size() == GlobalHashes.size());
14060b57cec5SDimitry Andric 
14070b57cec5SDimitry Andric       P.formatLine("Local / Global hashes:");
14080b57cec5SDimitry Andric       TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
1409480093f4SDimitry Andric       for (auto H : zip(LocalHashes, GlobalHashes)) {
14100b57cec5SDimitry Andric         AutoIndent Indent2(P);
14110b57cec5SDimitry Andric         LocallyHashedType &L = std::get<0>(H);
14120b57cec5SDimitry Andric         GloballyHashedType &G = std::get<1>(H);
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric         P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric         ++TI;
14170b57cec5SDimitry Andric       }
14180b57cec5SDimitry Andric       P.NewLine();
14190b57cec5SDimitry Andric     }
14200b57cec5SDimitry Andric   }
14210b57cec5SDimitry Andric 
14220b57cec5SDimitry Andric   return Error::success();
14230b57cec5SDimitry Andric }
14240b57cec5SDimitry Andric 
14250b57cec5SDimitry Andric Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
14260b57cec5SDimitry Andric   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
14270b57cec5SDimitry Andric 
14280b57cec5SDimitry Andric   if (StreamIdx == StreamTPI) {
14290b57cec5SDimitry Andric     printHeader(P, "Types (TPI Stream)");
14300b57cec5SDimitry Andric   } else if (StreamIdx == StreamIPI) {
14310b57cec5SDimitry Andric     printHeader(P, "Types (IPI Stream)");
14320b57cec5SDimitry Andric   }
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric   assert(!File.isObj());
14350b57cec5SDimitry Andric 
14360b57cec5SDimitry Andric   bool Present = false;
14370b57cec5SDimitry Andric   bool DumpTypes = false;
14380b57cec5SDimitry Andric   bool DumpBytes = false;
14390b57cec5SDimitry Andric   bool DumpExtras = false;
14400b57cec5SDimitry Andric   std::vector<uint32_t> Indices;
14410b57cec5SDimitry Andric   if (StreamIdx == StreamTPI) {
14420b57cec5SDimitry Andric     Present = getPdb().hasPDBTpiStream();
14430b57cec5SDimitry Andric     DumpTypes = opts::dump::DumpTypes;
14440b57cec5SDimitry Andric     DumpBytes = opts::dump::DumpTypeData;
14450b57cec5SDimitry Andric     DumpExtras = opts::dump::DumpTypeExtras;
14460b57cec5SDimitry Andric     Indices.assign(opts::dump::DumpTypeIndex.begin(),
14470b57cec5SDimitry Andric                    opts::dump::DumpTypeIndex.end());
14480b57cec5SDimitry Andric   } else if (StreamIdx == StreamIPI) {
14490b57cec5SDimitry Andric     Present = getPdb().hasPDBIpiStream();
14500b57cec5SDimitry Andric     DumpTypes = opts::dump::DumpIds;
14510b57cec5SDimitry Andric     DumpBytes = opts::dump::DumpIdData;
14520b57cec5SDimitry Andric     DumpExtras = opts::dump::DumpIdExtras;
14530b57cec5SDimitry Andric     Indices.assign(opts::dump::DumpIdIndex.begin(),
14540b57cec5SDimitry Andric                    opts::dump::DumpIdIndex.end());
14550b57cec5SDimitry Andric   }
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   if (!Present) {
14580b57cec5SDimitry Andric     printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI");
14590b57cec5SDimitry Andric     return Error::success();
14600b57cec5SDimitry Andric   }
14610b57cec5SDimitry Andric 
14620b57cec5SDimitry Andric   AutoIndent Indent(P);
14630b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing types: ");
14640b57cec5SDimitry Andric 
14650b57cec5SDimitry Andric   auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
14660b57cec5SDimitry Andric                                               : getPdb().getPDBIpiStream());
14670b57cec5SDimitry Andric 
14680b57cec5SDimitry Andric   auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
14690b57cec5SDimitry Andric 
14700b57cec5SDimitry Andric   // Only emit notes about referenced/unreferenced for types.
14710b57cec5SDimitry Andric   TypeReferenceTracker *MaybeTracker =
14720b57cec5SDimitry Andric       (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
14730b57cec5SDimitry Andric 
14740b57cec5SDimitry Andric   // Enable resolving forward decls.
14750b57cec5SDimitry Andric   Stream.buildHashMap();
14760b57cec5SDimitry Andric 
14770b57cec5SDimitry Andric   if (DumpTypes || !Indices.empty()) {
14780b57cec5SDimitry Andric     if (Indices.empty())
14790b57cec5SDimitry Andric       dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
14800b57cec5SDimitry Andric                          Stream.getNumHashBuckets(), Stream.getHashValues(),
14810b57cec5SDimitry Andric                          &Stream, DumpBytes, DumpExtras);
14820b57cec5SDimitry Andric     else {
14830b57cec5SDimitry Andric       std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
14840b57cec5SDimitry Andric       dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
14850b57cec5SDimitry Andric                             DumpExtras, opts::dump::DumpTypeDependents);
14860b57cec5SDimitry Andric     }
14870b57cec5SDimitry Andric   }
14880b57cec5SDimitry Andric 
14890b57cec5SDimitry Andric   if (DumpExtras) {
14900b57cec5SDimitry Andric     P.NewLine();
14910b57cec5SDimitry Andric 
14920b57cec5SDimitry Andric     P.formatLine("Header Version: {0}",
14930b57cec5SDimitry Andric                  static_cast<uint32_t>(Stream.getTpiVersion()));
14940b57cec5SDimitry Andric     P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex());
14950b57cec5SDimitry Andric     P.formatLine("Aux Hash Stream Index: {0}",
14960b57cec5SDimitry Andric                  Stream.getTypeHashStreamAuxIndex());
14970b57cec5SDimitry Andric     P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize());
14980b57cec5SDimitry Andric     P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets());
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric     auto IndexOffsets = Stream.getTypeIndexOffsets();
15010b57cec5SDimitry Andric     P.formatLine("Type Index Offsets:");
15020b57cec5SDimitry Andric     for (const auto &IO : IndexOffsets) {
15030b57cec5SDimitry Andric       AutoIndent Indent2(P);
15040b57cec5SDimitry Andric       P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
15050b57cec5SDimitry Andric     }
15060b57cec5SDimitry Andric 
15070b57cec5SDimitry Andric     if (getPdb().hasPDBStringTable()) {
15080b57cec5SDimitry Andric       P.NewLine();
15090b57cec5SDimitry Andric       P.formatLine("Hash Adjusters:");
15100b57cec5SDimitry Andric       auto &Adjusters = Stream.getHashAdjusters();
15110b57cec5SDimitry Andric       auto &Strings = Err(getPdb().getStringTable());
15120b57cec5SDimitry Andric       for (const auto &A : Adjusters) {
15130b57cec5SDimitry Andric         AutoIndent Indent2(P);
15140b57cec5SDimitry Andric         auto ExpectedStr = Strings.getStringForID(A.first);
15150b57cec5SDimitry Andric         TypeIndex TI(A.second);
15160b57cec5SDimitry Andric         if (ExpectedStr)
15170b57cec5SDimitry Andric           P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
15180b57cec5SDimitry Andric         else {
15190b57cec5SDimitry Andric           P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
15200b57cec5SDimitry Andric           consumeError(ExpectedStr.takeError());
15210b57cec5SDimitry Andric         }
15220b57cec5SDimitry Andric       }
15230b57cec5SDimitry Andric     }
15240b57cec5SDimitry Andric   }
15250b57cec5SDimitry Andric   return Error::success();
15260b57cec5SDimitry Andric }
15270b57cec5SDimitry Andric 
15280b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleSymsForObj() {
15290b57cec5SDimitry Andric   printHeader(P, "Symbols");
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric   AutoIndent Indent(P);
15320b57cec5SDimitry Andric 
15330b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing symbols: ");
15340b57cec5SDimitry Andric 
15350b57cec5SDimitry Andric   auto &Types = File.types();
15360b57cec5SDimitry Andric 
15370b57cec5SDimitry Andric   SymbolVisitorCallbackPipeline Pipeline;
15380b57cec5SDimitry Andric   SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
15390b57cec5SDimitry Andric   MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
15400b57cec5SDimitry Andric 
15410b57cec5SDimitry Andric   Pipeline.addCallbackToPipeline(Deserializer);
15420b57cec5SDimitry Andric   Pipeline.addCallbackToPipeline(Dumper);
15430b57cec5SDimitry Andric   CVSymbolVisitor Visitor(Pipeline);
15440b57cec5SDimitry Andric 
15450b57cec5SDimitry Andric   std::unique_ptr<llvm::Error> SymbolError;
15460b57cec5SDimitry Andric 
15470b57cec5SDimitry Andric   iterateModuleSubsections<DebugSymbolsSubsectionRef>(
15480b57cec5SDimitry Andric       File, PrintScope{P, 2},
15490b57cec5SDimitry Andric       [&](uint32_t Modi, const SymbolGroup &Strings,
15500b57cec5SDimitry Andric           DebugSymbolsSubsectionRef &Symbols) {
15510b57cec5SDimitry Andric         Dumper.setSymbolGroup(&Strings);
15520b57cec5SDimitry Andric         for (auto Symbol : Symbols) {
15530b57cec5SDimitry Andric           if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
15548bcb0991SDimitry Andric             SymbolError = std::make_unique<Error>(std::move(EC));
15550b57cec5SDimitry Andric             return;
15560b57cec5SDimitry Andric           }
15570b57cec5SDimitry Andric         }
15580b57cec5SDimitry Andric       });
15590b57cec5SDimitry Andric 
15600b57cec5SDimitry Andric   if (SymbolError)
15610b57cec5SDimitry Andric     return std::move(*SymbolError);
15620b57cec5SDimitry Andric 
15630b57cec5SDimitry Andric   return Error::success();
15640b57cec5SDimitry Andric }
15650b57cec5SDimitry Andric 
15660b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleSymsForPdb() {
15670b57cec5SDimitry Andric   printHeader(P, "Symbols");
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric   if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
15700b57cec5SDimitry Andric     printStreamNotPresent("DBI");
15710b57cec5SDimitry Andric     return Error::success();
15720b57cec5SDimitry Andric   }
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric   AutoIndent Indent(P);
15750b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing symbols: ");
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric   auto &Ids = File.ids();
15780b57cec5SDimitry Andric   auto &Types = File.types();
15790b57cec5SDimitry Andric 
15800b57cec5SDimitry Andric   iterateSymbolGroups(
15810b57cec5SDimitry Andric       File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
15820b57cec5SDimitry Andric         auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
15830b57cec5SDimitry Andric         if (!ExpectedModS) {
15840b57cec5SDimitry Andric           P.formatLine("Error loading module stream {0}.  {1}", I,
15850b57cec5SDimitry Andric                        toString(ExpectedModS.takeError()));
15860b57cec5SDimitry Andric           return;
15870b57cec5SDimitry Andric         }
15880b57cec5SDimitry Andric 
15890b57cec5SDimitry Andric         ModuleDebugStreamRef &ModS = *ExpectedModS;
15900b57cec5SDimitry Andric 
15910b57cec5SDimitry Andric         SymbolVisitorCallbackPipeline Pipeline;
15920b57cec5SDimitry Andric         SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
15930b57cec5SDimitry Andric         MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings,
15940b57cec5SDimitry Andric                                    Ids, Types);
15950b57cec5SDimitry Andric 
15960b57cec5SDimitry Andric         Pipeline.addCallbackToPipeline(Deserializer);
15970b57cec5SDimitry Andric         Pipeline.addCallbackToPipeline(Dumper);
15980b57cec5SDimitry Andric         CVSymbolVisitor Visitor(Pipeline);
15990b57cec5SDimitry Andric         auto SS = ModS.getSymbolsSubstream();
16000b57cec5SDimitry Andric         if (auto EC =
16010b57cec5SDimitry Andric                 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
16020b57cec5SDimitry Andric           P.formatLine("Error while processing symbol records.  {0}",
16030b57cec5SDimitry Andric                        toString(std::move(EC)));
16040b57cec5SDimitry Andric           return;
16050b57cec5SDimitry Andric         }
16060b57cec5SDimitry Andric       });
16070b57cec5SDimitry Andric   return Error::success();
16080b57cec5SDimitry Andric }
16090b57cec5SDimitry Andric 
16100b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypeRefStats() {
16110b57cec5SDimitry Andric   printHeader(P, "Type Reference Statistics");
16120b57cec5SDimitry Andric   AutoIndent Indent(P);
16130b57cec5SDimitry Andric 
16140b57cec5SDimitry Andric   // Sum the byte size of all type records, and the size and count of all
16150b57cec5SDimitry Andric   // referenced records.
16160b57cec5SDimitry Andric   size_t TotalRecs = File.types().size();
16170b57cec5SDimitry Andric   size_t RefRecs = 0;
16180b57cec5SDimitry Andric   size_t TotalBytes = 0;
16190b57cec5SDimitry Andric   size_t RefBytes = 0;
16200b57cec5SDimitry Andric   auto &Types = File.types();
16210b57cec5SDimitry Andric   for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
16220b57cec5SDimitry Andric     CVType Type = File.types().getType(*TI);
16230b57cec5SDimitry Andric     TotalBytes += Type.length();
16240b57cec5SDimitry Andric     if (RefTracker->isTypeReferenced(*TI)) {
16250b57cec5SDimitry Andric       ++RefRecs;
16260b57cec5SDimitry Andric       RefBytes += Type.length();
16270b57cec5SDimitry Andric     }
16280b57cec5SDimitry Andric   }
16290b57cec5SDimitry Andric 
16300b57cec5SDimitry Andric   P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
16310b57cec5SDimitry Andric                (double)RefRecs / TotalRecs);
16320b57cec5SDimitry Andric   P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
16330b57cec5SDimitry Andric                (double)RefBytes / TotalBytes);
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric   return Error::success();
16360b57cec5SDimitry Andric }
16370b57cec5SDimitry Andric 
16380b57cec5SDimitry Andric Error DumpOutputStyle::dumpGSIRecords() {
16390b57cec5SDimitry Andric   printHeader(P, "GSI Records");
16400b57cec5SDimitry Andric 
16410b57cec5SDimitry Andric   if (File.isObj()) {
16420b57cec5SDimitry Andric     printStreamNotValidForObj();
16430b57cec5SDimitry Andric     return Error::success();
16440b57cec5SDimitry Andric   }
16450b57cec5SDimitry Andric 
16460b57cec5SDimitry Andric   if (!getPdb().hasPDBSymbolStream()) {
16470b57cec5SDimitry Andric     printStreamNotPresent("GSI Common Symbol");
16480b57cec5SDimitry Andric     return Error::success();
16490b57cec5SDimitry Andric   }
16500b57cec5SDimitry Andric 
16510b57cec5SDimitry Andric   AutoIndent Indent(P);
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric   auto &Records = cantFail(getPdb().getPDBSymbolStream());
16540b57cec5SDimitry Andric   auto &Types = File.types();
16550b57cec5SDimitry Andric   auto &Ids = File.ids();
16560b57cec5SDimitry Andric 
16570b57cec5SDimitry Andric   P.printLine("Records");
16580b57cec5SDimitry Andric   SymbolVisitorCallbackPipeline Pipeline;
16590b57cec5SDimitry Andric   SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
16600b57cec5SDimitry Andric   MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
16610b57cec5SDimitry Andric 
16620b57cec5SDimitry Andric   Pipeline.addCallbackToPipeline(Deserializer);
16630b57cec5SDimitry Andric   Pipeline.addCallbackToPipeline(Dumper);
16640b57cec5SDimitry Andric   CVSymbolVisitor Visitor(Pipeline);
16650b57cec5SDimitry Andric 
16660b57cec5SDimitry Andric   BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream();
16670b57cec5SDimitry Andric   if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0))
16680b57cec5SDimitry Andric     return E;
16690b57cec5SDimitry Andric   return Error::success();
16700b57cec5SDimitry Andric }
16710b57cec5SDimitry Andric 
16720b57cec5SDimitry Andric Error DumpOutputStyle::dumpGlobals() {
16730b57cec5SDimitry Andric   printHeader(P, "Global Symbols");
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric   if (File.isObj()) {
16760b57cec5SDimitry Andric     printStreamNotValidForObj();
16770b57cec5SDimitry Andric     return Error::success();
16780b57cec5SDimitry Andric   }
16790b57cec5SDimitry Andric 
16800b57cec5SDimitry Andric   if (!getPdb().hasPDBGlobalsStream()) {
16810b57cec5SDimitry Andric     printStreamNotPresent("Globals");
16820b57cec5SDimitry Andric     return Error::success();
16830b57cec5SDimitry Andric   }
16840b57cec5SDimitry Andric 
16850b57cec5SDimitry Andric   AutoIndent Indent(P);
16860b57cec5SDimitry Andric   ExitOnError Err("Error dumping globals stream: ");
16870b57cec5SDimitry Andric   auto &Globals = Err(getPdb().getPDBGlobalsStream());
16880b57cec5SDimitry Andric 
16890b57cec5SDimitry Andric   if (opts::dump::DumpGlobalNames.empty()) {
16900b57cec5SDimitry Andric     const GSIHashTable &Table = Globals.getGlobalsTable();
16910b57cec5SDimitry Andric     Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
16920b57cec5SDimitry Andric   } else {
16930b57cec5SDimitry Andric     SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream());
16940b57cec5SDimitry Andric     auto &Types = File.types();
16950b57cec5SDimitry Andric     auto &Ids = File.ids();
16960b57cec5SDimitry Andric 
16970b57cec5SDimitry Andric     SymbolVisitorCallbackPipeline Pipeline;
16980b57cec5SDimitry Andric     SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
16990b57cec5SDimitry Andric     MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
17000b57cec5SDimitry Andric 
17010b57cec5SDimitry Andric     Pipeline.addCallbackToPipeline(Deserializer);
17020b57cec5SDimitry Andric     Pipeline.addCallbackToPipeline(Dumper);
17030b57cec5SDimitry Andric     CVSymbolVisitor Visitor(Pipeline);
17040b57cec5SDimitry Andric 
17050b57cec5SDimitry Andric     using ResultEntryType = std::pair<uint32_t, CVSymbol>;
17060b57cec5SDimitry Andric     for (StringRef Name : opts::dump::DumpGlobalNames) {
17070b57cec5SDimitry Andric       AutoIndent Indent(P);
17080b57cec5SDimitry Andric       P.formatLine("Global Name `{0}`", Name);
17090b57cec5SDimitry Andric       std::vector<ResultEntryType> Results =
17100b57cec5SDimitry Andric           Globals.findRecordsByName(Name, SymRecords);
17110b57cec5SDimitry Andric       if (Results.empty()) {
17120b57cec5SDimitry Andric         AutoIndent Indent(P);
17130b57cec5SDimitry Andric         P.printLine("(no matching records found)");
17140b57cec5SDimitry Andric         continue;
17150b57cec5SDimitry Andric       }
17160b57cec5SDimitry Andric 
17170b57cec5SDimitry Andric       for (ResultEntryType Result : Results) {
17180b57cec5SDimitry Andric         if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first))
17190b57cec5SDimitry Andric           return E;
17200b57cec5SDimitry Andric       }
17210b57cec5SDimitry Andric     }
17220b57cec5SDimitry Andric   }
17230b57cec5SDimitry Andric   return Error::success();
17240b57cec5SDimitry Andric }
17250b57cec5SDimitry Andric 
17260b57cec5SDimitry Andric Error DumpOutputStyle::dumpPublics() {
17270b57cec5SDimitry Andric   printHeader(P, "Public Symbols");
17280b57cec5SDimitry Andric 
17290b57cec5SDimitry Andric   if (File.isObj()) {
17300b57cec5SDimitry Andric     printStreamNotValidForObj();
17310b57cec5SDimitry Andric     return Error::success();
17320b57cec5SDimitry Andric   }
17330b57cec5SDimitry Andric 
17340b57cec5SDimitry Andric   if (!getPdb().hasPDBPublicsStream()) {
17350b57cec5SDimitry Andric     printStreamNotPresent("Publics");
17360b57cec5SDimitry Andric     return Error::success();
17370b57cec5SDimitry Andric   }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric   AutoIndent Indent(P);
17400b57cec5SDimitry Andric   ExitOnError Err("Error dumping publics stream: ");
17410b57cec5SDimitry Andric   auto &Publics = Err(getPdb().getPDBPublicsStream());
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric   const GSIHashTable &PublicsTable = Publics.getPublicsTable();
17440b57cec5SDimitry Andric   if (opts::dump::DumpPublicExtras) {
17450b57cec5SDimitry Andric     P.printLine("Publics Header");
17460b57cec5SDimitry Andric     AutoIndent Indent(P);
17470b57cec5SDimitry Andric     P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
17480b57cec5SDimitry Andric                  formatSegmentOffset(Publics.getThunkTableSection(),
17490b57cec5SDimitry Andric                                      Publics.getThunkTableOffset()));
17500b57cec5SDimitry Andric   }
17510b57cec5SDimitry Andric   Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric   // Skip the rest if we aren't dumping extras.
17540b57cec5SDimitry Andric   if (!opts::dump::DumpPublicExtras)
17550b57cec5SDimitry Andric     return Error::success();
17560b57cec5SDimitry Andric 
17570b57cec5SDimitry Andric   P.formatLine("Address Map");
17580b57cec5SDimitry Andric   {
17590b57cec5SDimitry Andric     // These are offsets into the publics stream sorted by secidx:secrel.
17600b57cec5SDimitry Andric     AutoIndent Indent2(P);
17610b57cec5SDimitry Andric     for (uint32_t Addr : Publics.getAddressMap())
17620b57cec5SDimitry Andric       P.formatLine("off = {0}", Addr);
17630b57cec5SDimitry Andric   }
17640b57cec5SDimitry Andric 
17650b57cec5SDimitry Andric   // The thunk map is optional debug info used for ILT thunks.
17660b57cec5SDimitry Andric   if (!Publics.getThunkMap().empty()) {
17670b57cec5SDimitry Andric     P.formatLine("Thunk Map");
17680b57cec5SDimitry Andric     AutoIndent Indent2(P);
17690b57cec5SDimitry Andric     for (uint32_t Addr : Publics.getThunkMap())
17700b57cec5SDimitry Andric       P.formatLine("{0:x8}", Addr);
17710b57cec5SDimitry Andric   }
17720b57cec5SDimitry Andric 
17730b57cec5SDimitry Andric   // The section offsets table appears to be empty when incremental linking
17740b57cec5SDimitry Andric   // isn't in use.
17750b57cec5SDimitry Andric   if (!Publics.getSectionOffsets().empty()) {
17760b57cec5SDimitry Andric     P.formatLine("Section Offsets");
17770b57cec5SDimitry Andric     AutoIndent Indent2(P);
17780b57cec5SDimitry Andric     for (const SectionOffset &SO : Publics.getSectionOffsets())
17790b57cec5SDimitry Andric       P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
17800b57cec5SDimitry Andric   }
17810b57cec5SDimitry Andric 
17820b57cec5SDimitry Andric   return Error::success();
17830b57cec5SDimitry Andric }
17840b57cec5SDimitry Andric 
17850b57cec5SDimitry Andric Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
17860b57cec5SDimitry Andric                                           bool HashExtras) {
17870b57cec5SDimitry Andric   auto ExpectedSyms = getPdb().getPDBSymbolStream();
17880b57cec5SDimitry Andric   if (!ExpectedSyms)
17890b57cec5SDimitry Andric     return ExpectedSyms.takeError();
17900b57cec5SDimitry Andric   auto &Types = File.types();
17910b57cec5SDimitry Andric   auto &Ids = File.ids();
17920b57cec5SDimitry Andric 
17930b57cec5SDimitry Andric   if (HashExtras) {
17940b57cec5SDimitry Andric     P.printLine("GSI Header");
17950b57cec5SDimitry Andric     AutoIndent Indent(P);
17960b57cec5SDimitry Andric     P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
17970b57cec5SDimitry Andric                  Table.getVerSignature(), Table.getVerHeader(),
17980b57cec5SDimitry Andric                  Table.getHashRecordSize(), Table.getNumBuckets());
17990b57cec5SDimitry Andric   }
18000b57cec5SDimitry Andric 
18010b57cec5SDimitry Andric   {
18020b57cec5SDimitry Andric     P.printLine("Records");
18030b57cec5SDimitry Andric     SymbolVisitorCallbackPipeline Pipeline;
18040b57cec5SDimitry Andric     SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
18050b57cec5SDimitry Andric     MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
18060b57cec5SDimitry Andric 
18070b57cec5SDimitry Andric     Pipeline.addCallbackToPipeline(Deserializer);
18080b57cec5SDimitry Andric     Pipeline.addCallbackToPipeline(Dumper);
18090b57cec5SDimitry Andric     CVSymbolVisitor Visitor(Pipeline);
18100b57cec5SDimitry Andric 
18110b57cec5SDimitry Andric 
18120b57cec5SDimitry Andric     BinaryStreamRef SymStream =
18130b57cec5SDimitry Andric         ExpectedSyms->getSymbolArray().getUnderlyingStream();
18140b57cec5SDimitry Andric     for (uint32_t PubSymOff : Table) {
18150b57cec5SDimitry Andric       Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
18160b57cec5SDimitry Andric       if (!Sym)
18170b57cec5SDimitry Andric         return Sym.takeError();
18180b57cec5SDimitry Andric       if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
18190b57cec5SDimitry Andric         return E;
18200b57cec5SDimitry Andric     }
18210b57cec5SDimitry Andric   }
18220b57cec5SDimitry Andric 
18230b57cec5SDimitry Andric   // Return early if we aren't dumping public hash table and address map info.
18240b57cec5SDimitry Andric   if (HashExtras) {
18250b57cec5SDimitry Andric     P.formatLine("Hash Entries");
18260b57cec5SDimitry Andric     {
18270b57cec5SDimitry Andric       AutoIndent Indent2(P);
18280b57cec5SDimitry Andric       for (const PSHashRecord &HR : Table.HashRecords)
18290b57cec5SDimitry Andric         P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
18300b57cec5SDimitry Andric           uint32_t(HR.CRef));
18310b57cec5SDimitry Andric     }
18320b57cec5SDimitry Andric 
18330b57cec5SDimitry Andric     P.formatLine("Hash Buckets");
18340b57cec5SDimitry Andric     {
18350b57cec5SDimitry Andric       AutoIndent Indent2(P);
18360b57cec5SDimitry Andric       for (uint32_t Hash : Table.HashBuckets)
18370b57cec5SDimitry Andric         P.formatLine("{0:x8}", Hash);
18380b57cec5SDimitry Andric     }
18390b57cec5SDimitry Andric   }
18400b57cec5SDimitry Andric 
18410b57cec5SDimitry Andric   return Error::success();
18420b57cec5SDimitry Andric }
18430b57cec5SDimitry Andric 
18440b57cec5SDimitry Andric static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
18450b57cec5SDimitry Andric                                               OMFSegDescFlags Flags) {
18460b57cec5SDimitry Andric   std::vector<std::string> Opts;
18470b57cec5SDimitry Andric   if (Flags == OMFSegDescFlags::None)
18480b57cec5SDimitry Andric     return "none";
18490b57cec5SDimitry Andric 
18500b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
18510b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
18520b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
18530b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
18540b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
18550b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
18560b57cec5SDimitry Andric   PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
18570b57cec5SDimitry Andric   return typesetItemList(Opts, IndentLevel, 4, " | ");
18580b57cec5SDimitry Andric }
18590b57cec5SDimitry Andric 
18600b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionHeaders() {
18610b57cec5SDimitry Andric   dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
18620b57cec5SDimitry Andric   dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
18630b57cec5SDimitry Andric   return Error::success();
18640b57cec5SDimitry Andric }
18650b57cec5SDimitry Andric 
18660b57cec5SDimitry Andric void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
18670b57cec5SDimitry Andric   printHeader(P, Label);
18680b57cec5SDimitry Andric 
18690b57cec5SDimitry Andric   if (File.isObj()) {
18700b57cec5SDimitry Andric     printStreamNotValidForObj();
18710b57cec5SDimitry Andric     return;
18720b57cec5SDimitry Andric   }
18730b57cec5SDimitry Andric 
18740b57cec5SDimitry Andric   if (!getPdb().hasPDBDbiStream()) {
18750b57cec5SDimitry Andric     printStreamNotPresent("DBI");
18760b57cec5SDimitry Andric     return;
18770b57cec5SDimitry Andric   }
18780b57cec5SDimitry Andric 
18790b57cec5SDimitry Andric   AutoIndent Indent(P);
18800b57cec5SDimitry Andric   ExitOnError Err("Error dumping section headers: ");
18810b57cec5SDimitry Andric   std::unique_ptr<MappedBlockStream> Stream;
18820b57cec5SDimitry Andric   ArrayRef<object::coff_section> Headers;
18830b57cec5SDimitry Andric   auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
18840b57cec5SDimitry Andric   if (!ExpectedHeaders) {
18850b57cec5SDimitry Andric     P.printLine(toString(ExpectedHeaders.takeError()));
18860b57cec5SDimitry Andric     return;
18870b57cec5SDimitry Andric   }
18880b57cec5SDimitry Andric   std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
18890b57cec5SDimitry Andric 
18900b57cec5SDimitry Andric   uint32_t I = 1;
18910b57cec5SDimitry Andric   for (const auto &Header : Headers) {
18920b57cec5SDimitry Andric     P.NewLine();
18930b57cec5SDimitry Andric     P.formatLine("SECTION HEADER #{0}", I);
18940b57cec5SDimitry Andric     P.formatLine("{0,8} name", Header.Name);
18950b57cec5SDimitry Andric     P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
18960b57cec5SDimitry Andric     P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
18970b57cec5SDimitry Andric     P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
18980b57cec5SDimitry Andric     P.formatLine("{0,8:X-} file pointer to raw data",
18990b57cec5SDimitry Andric                  uint32_t(Header.PointerToRawData));
19000b57cec5SDimitry Andric     P.formatLine("{0,8:X-} file pointer to relocation table",
19010b57cec5SDimitry Andric                  uint32_t(Header.PointerToRelocations));
19020b57cec5SDimitry Andric     P.formatLine("{0,8:X-} file pointer to line numbers",
19030b57cec5SDimitry Andric                  uint32_t(Header.PointerToLinenumbers));
19040b57cec5SDimitry Andric     P.formatLine("{0,8:X-} number of relocations",
19050b57cec5SDimitry Andric                  uint32_t(Header.NumberOfRelocations));
19060b57cec5SDimitry Andric     P.formatLine("{0,8:X-} number of line numbers",
19070b57cec5SDimitry Andric                  uint32_t(Header.NumberOfLinenumbers));
19080b57cec5SDimitry Andric     P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
19090b57cec5SDimitry Andric     AutoIndent IndentMore(P, 9);
19100b57cec5SDimitry Andric     P.formatLine("{0}", formatSectionCharacteristics(
19110b57cec5SDimitry Andric                             P.getIndentLevel(), Header.Characteristics, 1, ""));
19120b57cec5SDimitry Andric     ++I;
19130b57cec5SDimitry Andric   }
19140b57cec5SDimitry Andric   return;
19150b57cec5SDimitry Andric }
19160b57cec5SDimitry Andric 
19170b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionContribs() {
19180b57cec5SDimitry Andric   printHeader(P, "Section Contributions");
19190b57cec5SDimitry Andric 
19200b57cec5SDimitry Andric   if (File.isObj()) {
19210b57cec5SDimitry Andric     printStreamNotValidForObj();
19220b57cec5SDimitry Andric     return Error::success();
19230b57cec5SDimitry Andric   }
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric   if (!getPdb().hasPDBDbiStream()) {
19260b57cec5SDimitry Andric     printStreamNotPresent("DBI");
19270b57cec5SDimitry Andric     return Error::success();
19280b57cec5SDimitry Andric   }
19290b57cec5SDimitry Andric 
19300b57cec5SDimitry Andric   AutoIndent Indent(P);
19310b57cec5SDimitry Andric   ExitOnError Err("Error dumping section contributions: ");
19320b57cec5SDimitry Andric 
19330b57cec5SDimitry Andric   auto &Dbi = Err(getPdb().getPDBDbiStream());
19340b57cec5SDimitry Andric 
19350b57cec5SDimitry Andric   class Visitor : public ISectionContribVisitor {
19360b57cec5SDimitry Andric   public:
19370b57cec5SDimitry Andric     Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
19380b57cec5SDimitry Andric       auto Max = std::max_element(
19390b57cec5SDimitry Andric           Names.begin(), Names.end(),
19400b57cec5SDimitry Andric           [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
19410b57cec5SDimitry Andric       MaxNameLen = (Max == Names.end() ? 0 : Max->size());
19420b57cec5SDimitry Andric     }
19430b57cec5SDimitry Andric     void visit(const SectionContrib &SC) override {
19440b57cec5SDimitry Andric       dumpSectionContrib(P, SC, Names, MaxNameLen);
19450b57cec5SDimitry Andric     }
19460b57cec5SDimitry Andric     void visit(const SectionContrib2 &SC) override {
19470b57cec5SDimitry Andric       dumpSectionContrib(P, SC, Names, MaxNameLen);
19480b57cec5SDimitry Andric     }
19490b57cec5SDimitry Andric 
19500b57cec5SDimitry Andric   private:
19510b57cec5SDimitry Andric     LinePrinter &P;
19520b57cec5SDimitry Andric     uint32_t MaxNameLen;
19530b57cec5SDimitry Andric     ArrayRef<std::string> Names;
19540b57cec5SDimitry Andric   };
19550b57cec5SDimitry Andric 
19560b57cec5SDimitry Andric   std::vector<std::string> Names = getSectionNames(getPdb());
19570b57cec5SDimitry Andric   Visitor V(P, makeArrayRef(Names));
19580b57cec5SDimitry Andric   Dbi.visitSectionContributions(V);
19590b57cec5SDimitry Andric   return Error::success();
19600b57cec5SDimitry Andric }
19610b57cec5SDimitry Andric 
19620b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionMap() {
19630b57cec5SDimitry Andric   printHeader(P, "Section Map");
19640b57cec5SDimitry Andric 
19650b57cec5SDimitry Andric   if (File.isObj()) {
19660b57cec5SDimitry Andric     printStreamNotValidForObj();
19670b57cec5SDimitry Andric     return Error::success();
19680b57cec5SDimitry Andric   }
19690b57cec5SDimitry Andric 
19700b57cec5SDimitry Andric   if (!getPdb().hasPDBDbiStream()) {
19710b57cec5SDimitry Andric     printStreamNotPresent("DBI");
19720b57cec5SDimitry Andric     return Error::success();
19730b57cec5SDimitry Andric   }
19740b57cec5SDimitry Andric 
19750b57cec5SDimitry Andric   AutoIndent Indent(P);
19760b57cec5SDimitry Andric   ExitOnError Err("Error dumping section map: ");
19770b57cec5SDimitry Andric 
19780b57cec5SDimitry Andric   auto &Dbi = Err(getPdb().getPDBDbiStream());
19790b57cec5SDimitry Andric 
19800b57cec5SDimitry Andric   uint32_t I = 0;
19810b57cec5SDimitry Andric   for (auto &M : Dbi.getSectionMap()) {
19820b57cec5SDimitry Andric     P.formatLine(
19830b57cec5SDimitry Andric         "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
19840b57cec5SDimitry Andric         fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
19850b57cec5SDimitry Andric     P.formatLine("               class = {0}, offset = {1}, size = {2}",
19860b57cec5SDimitry Andric                  fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
19870b57cec5SDimitry Andric     P.formatLine("               flags = {0}",
19880b57cec5SDimitry Andric                  formatSegMapDescriptorFlag(
19890b57cec5SDimitry Andric                      P.getIndentLevel() + 13,
19900b57cec5SDimitry Andric                      static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
19910b57cec5SDimitry Andric     ++I;
19920b57cec5SDimitry Andric   }
19930b57cec5SDimitry Andric   return Error::success();
19940b57cec5SDimitry Andric }
1995