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