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