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