10b57cec5SDimitry Andric //===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "DumpOutputStyle.h" 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "MinimalSymbolDumper.h" 120b57cec5SDimitry Andric #include "MinimalTypeDumper.h" 130b57cec5SDimitry Andric #include "StreamUtil.h" 140b57cec5SDimitry Andric #include "TypeReferenceTracker.h" 150b57cec5SDimitry Andric #include "llvm-pdbutil.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 180b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 190b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 200b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 210b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" 220b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" 230b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" 240b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" 250b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 260b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 270b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" 280b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Formatters.h" 290b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 300b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Line.h" 310b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 320b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" 330b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" 340b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeHashing.h" 350b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" 360b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 370b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 380b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 3981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/FormatUtil.h" 400b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 410b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 420b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 4381ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InputFile.h" 440b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 4581ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeSession.h" 460b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 470b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 480b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h" 490b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 500b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" 510b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 520b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 530b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 540b57cec5SDimitry Andric #include "llvm/Support/FormatAdapters.h" 550b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric #include <cctype> 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric using namespace llvm; 600b57cec5SDimitry Andric using namespace llvm::codeview; 610b57cec5SDimitry Andric using namespace llvm::msf; 620b57cec5SDimitry Andric using namespace llvm::pdb; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric DumpOutputStyle::DumpOutputStyle(InputFile &File) 6581ad6265SDimitry Andric : File(File), P(2, false, outs(), opts::Filters) { 660b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) 670b57cec5SDimitry Andric RefTracker.reset(new TypeReferenceTracker(File)); 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric DumpOutputStyle::~DumpOutputStyle() {} 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); } 730b57cec5SDimitry Andric object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotValidForObj() { 760b57cec5SDimitry Andric AutoIndent Indent(P, 4); 770b57cec5SDimitry Andric P.formatLine("Dumping this stream is not valid for object files"); 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) { 810b57cec5SDimitry Andric AutoIndent Indent(P, 4); 820b57cec5SDimitry Andric P.formatLine("{0} stream not present", StreamName); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric Error DumpOutputStyle::dump() { 860b57cec5SDimitry Andric // Walk symbols & globals if we are supposed to mark types referenced. 870b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) 880b57cec5SDimitry Andric RefTracker->mark(); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric if (opts::dump::DumpSummary) { 910b57cec5SDimitry Andric if (auto EC = dumpFileSummary()) 920b57cec5SDimitry Andric return EC; 930b57cec5SDimitry Andric P.NewLine(); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric if (opts::dump::DumpStreams) { 970b57cec5SDimitry Andric if (auto EC = dumpStreamSummary()) 980b57cec5SDimitry Andric return EC; 990b57cec5SDimitry Andric P.NewLine(); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric if (opts::dump::DumpSymbolStats) { 10381ad6265SDimitry Andric ExitOnError Err("Unexpected error processing module stats: "); 10481ad6265SDimitry Andric Err(dumpSymbolStats()); 1050b57cec5SDimitry Andric P.NewLine(); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric if (opts::dump::DumpUdtStats) { 1090b57cec5SDimitry Andric if (auto EC = dumpUdtStats()) 1100b57cec5SDimitry Andric return EC; 1110b57cec5SDimitry Andric P.NewLine(); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1145ffd83dbSDimitry Andric if (opts::dump::DumpTypeStats || opts::dump::DumpIDStats) { 1150b57cec5SDimitry Andric if (auto EC = dumpTypeStats()) 1160b57cec5SDimitry Andric return EC; 1170b57cec5SDimitry Andric P.NewLine(); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric if (opts::dump::DumpNamedStreams) { 1210b57cec5SDimitry Andric if (auto EC = dumpNamedStreams()) 1220b57cec5SDimitry Andric return EC; 1230b57cec5SDimitry Andric P.NewLine(); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) { 1270b57cec5SDimitry Andric if (auto EC = dumpStringTable()) 1280b57cec5SDimitry Andric return EC; 1290b57cec5SDimitry Andric P.NewLine(); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric if (opts::dump::DumpModules) { 13381ad6265SDimitry Andric ExitOnError Err("Unexpected error processing modules: "); 13481ad6265SDimitry Andric Err(dumpModules()); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric if (opts::dump::DumpModuleFiles) { 13881ad6265SDimitry Andric ExitOnError Err("Unexpected error processing files: "); 13981ad6265SDimitry Andric Err(dumpModuleFiles()); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric if (opts::dump::DumpLines) { 14381ad6265SDimitry Andric ExitOnError Err("Unexpected error processing lines: "); 14481ad6265SDimitry Andric Err(dumpLines()); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric if (opts::dump::DumpInlineeLines) { 14881ad6265SDimitry Andric ExitOnError Err("Unexpected error processing inlinee lines: "); 14981ad6265SDimitry Andric Err(dumpInlineeLines()); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric if (opts::dump::DumpXmi) { 15381ad6265SDimitry Andric ExitOnError Err("Unexpected error processing cross module imports: "); 15481ad6265SDimitry Andric Err(dumpXmi()); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric if (opts::dump::DumpXme) { 15881ad6265SDimitry Andric ExitOnError Err("Unexpected error processing cross module exports: "); 15981ad6265SDimitry Andric Err(dumpXme()); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric if (opts::dump::DumpFpo) { 1630b57cec5SDimitry Andric if (auto EC = dumpFpo()) 1640b57cec5SDimitry Andric return EC; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric if (File.isObj()) { 1680b57cec5SDimitry Andric if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 1690b57cec5SDimitry Andric opts::dump::DumpTypeExtras) 1700b57cec5SDimitry Andric if (auto EC = dumpTypesFromObjectFile()) 1710b57cec5SDimitry Andric return EC; 1720b57cec5SDimitry Andric } else { 1730b57cec5SDimitry Andric if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 1740b57cec5SDimitry Andric opts::dump::DumpTypeExtras) { 1750b57cec5SDimitry Andric if (auto EC = dumpTpiStream(StreamTPI)) 1760b57cec5SDimitry Andric return EC; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() || 1800b57cec5SDimitry Andric opts::dump::DumpIdExtras) { 1810b57cec5SDimitry Andric if (auto EC = dumpTpiStream(StreamIPI)) 1820b57cec5SDimitry Andric return EC; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric if (opts::dump::DumpGSIRecords) { 1870b57cec5SDimitry Andric if (auto EC = dumpGSIRecords()) 1880b57cec5SDimitry Andric return EC; 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric if (opts::dump::DumpGlobals) { 1920b57cec5SDimitry Andric if (auto EC = dumpGlobals()) 1930b57cec5SDimitry Andric return EC; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric if (opts::dump::DumpPublics) { 1970b57cec5SDimitry Andric if (auto EC = dumpPublics()) 1980b57cec5SDimitry Andric return EC; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric if (opts::dump::DumpSymbols) { 20281ad6265SDimitry Andric ExitOnError Err("Unexpected error processing symbols: "); 20381ad6265SDimitry Andric Err(File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj()); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) { 2070b57cec5SDimitry Andric if (auto EC = dumpTypeRefStats()) 2080b57cec5SDimitry Andric return EC; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric if (opts::dump::DumpSectionHeaders) { 2120b57cec5SDimitry Andric if (auto EC = dumpSectionHeaders()) 2130b57cec5SDimitry Andric return EC; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric if (opts::dump::DumpSectionContribs) { 2170b57cec5SDimitry Andric if (auto EC = dumpSectionContribs()) 2180b57cec5SDimitry Andric return EC; 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric if (opts::dump::DumpSectionMap) { 2220b57cec5SDimitry Andric if (auto EC = dumpSectionMap()) 2230b57cec5SDimitry Andric return EC; 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric P.NewLine(); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric return Error::success(); 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric static void printHeader(LinePrinter &P, const Twine &S) { 2320b57cec5SDimitry Andric P.NewLine(); 2330b57cec5SDimitry Andric P.formatLine("{0,=60}", S); 2340b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('=', 60)); 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric Error DumpOutputStyle::dumpFileSummary() { 2380b57cec5SDimitry Andric printHeader(P, "Summary"); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric if (File.isObj()) { 2410b57cec5SDimitry Andric printStreamNotValidForObj(); 2420b57cec5SDimitry Andric return Error::success(); 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric AutoIndent Indent(P); 2460b57cec5SDimitry Andric ExitOnError Err("Invalid PDB Format: "); 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric P.formatLine("Block Size: {0}", getPdb().getBlockSize()); 2490b57cec5SDimitry Andric P.formatLine("Number of blocks: {0}", getPdb().getBlockCount()); 2500b57cec5SDimitry Andric P.formatLine("Number of streams: {0}", getPdb().getNumStreams()); 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric auto &PS = Err(getPdb().getPDBInfoStream()); 2530b57cec5SDimitry Andric P.formatLine("Signature: {0}", PS.getSignature()); 2540b57cec5SDimitry Andric P.formatLine("Age: {0}", PS.getAge()); 2550b57cec5SDimitry Andric P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid)); 2560b57cec5SDimitry Andric P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures())); 2570b57cec5SDimitry Andric P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream()); 2580b57cec5SDimitry Andric P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream()); 2590b57cec5SDimitry Andric P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream()); 2600b57cec5SDimitry Andric P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream()); 2610b57cec5SDimitry Andric P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream()); 2620b57cec5SDimitry Andric if (getPdb().hasPDBDbiStream()) { 26381ad6265SDimitry Andric DbiStream &DBI = Err(getPdb().getPDBDbiStream()); 2640b57cec5SDimitry Andric P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked()); 2650b57cec5SDimitry Andric P.formatLine("Has conflicting types: {0}", DBI.hasCTypes()); 2660b57cec5SDimitry Andric P.formatLine("Is stripped: {0}", DBI.isStripped()); 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric return Error::success(); 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric static StatCollection getSymbolStats(const SymbolGroup &SG, 2730b57cec5SDimitry Andric StatCollection &CumulativeStats) { 2740b57cec5SDimitry Andric StatCollection Stats; 2750b57cec5SDimitry Andric if (SG.getFile().isPdb() && SG.hasDebugStream()) { 2760b57cec5SDimitry Andric // For PDB files, all symbols are packed into one stream. 2770b57cec5SDimitry Andric for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) { 2780b57cec5SDimitry Andric Stats.update(S.kind(), S.length()); 2790b57cec5SDimitry Andric CumulativeStats.update(S.kind(), S.length()); 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric return Stats; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric for (const auto &SS : SG.getDebugSubsections()) { 2850b57cec5SDimitry Andric // For object files, all symbols are spread across multiple Symbol 2860b57cec5SDimitry Andric // subsections of a given .debug$S section. 2870b57cec5SDimitry Andric if (SS.kind() != DebugSubsectionKind::Symbols) 2880b57cec5SDimitry Andric continue; 2890b57cec5SDimitry Andric DebugSymbolsSubsectionRef Symbols; 2900b57cec5SDimitry Andric BinaryStreamReader Reader(SS.getRecordData()); 2910b57cec5SDimitry Andric cantFail(Symbols.initialize(Reader)); 2920b57cec5SDimitry Andric for (const auto &S : Symbols) { 2930b57cec5SDimitry Andric Stats.update(S.kind(), S.length()); 2940b57cec5SDimitry Andric CumulativeStats.update(S.kind(), S.length()); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric return Stats; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric static StatCollection getChunkStats(const SymbolGroup &SG, 3010b57cec5SDimitry Andric StatCollection &CumulativeStats) { 3020b57cec5SDimitry Andric StatCollection Stats; 3030b57cec5SDimitry Andric for (const auto &Chunk : SG.getDebugSubsections()) { 3040b57cec5SDimitry Andric Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 3050b57cec5SDimitry Andric CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric return Stats; 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(DebugSubsectionKind K) { 3110b57cec5SDimitry Andric return formatChunkKind(K, false); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(SymbolKind K) { 3150b57cec5SDimitry Andric return formatSymbolKind(K); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Get the stats sorted by size, descending. 3190b57cec5SDimitry Andric std::vector<StatCollection::KindAndStat> 3200b57cec5SDimitry Andric StatCollection::getStatsSortedBySize() const { 3210b57cec5SDimitry Andric std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end()); 3220b57cec5SDimitry Andric llvm::stable_sort(SortedStats, 3230b57cec5SDimitry Andric [](const KindAndStat &LHS, const KindAndStat &RHS) { 3240b57cec5SDimitry Andric return LHS.second.Size > RHS.second.Size; 3250b57cec5SDimitry Andric }); 3260b57cec5SDimitry Andric return SortedStats; 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric template <typename Kind> 3300b57cec5SDimitry Andric static void printModuleDetailStats(LinePrinter &P, StringRef Label, 3310b57cec5SDimitry Andric const StatCollection &Stats) { 3320b57cec5SDimitry Andric P.NewLine(); 3330b57cec5SDimitry Andric P.formatLine(" {0}", Label); 3340b57cec5SDimitry Andric AutoIndent Indent(P); 3350b57cec5SDimitry Andric P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total", 3360b57cec5SDimitry Andric Stats.Totals.Count, Stats.Totals.Size); 3370b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', 74)); 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric for (const auto &K : Stats.getStatsSortedBySize()) { 3400b57cec5SDimitry Andric std::string KindName = formatModuleDetailKind(Kind(K.first)); 3410b57cec5SDimitry Andric P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName, 3420b57cec5SDimitry Andric K.second.Count, K.second.Size); 3430b57cec5SDimitry Andric } 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric Error DumpOutputStyle::dumpStreamSummary() { 3470b57cec5SDimitry Andric printHeader(P, "Streams"); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric if (File.isObj()) { 3500b57cec5SDimitry Andric printStreamNotValidForObj(); 3510b57cec5SDimitry Andric return Error::success(); 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric AutoIndent Indent(P); 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric if (StreamPurposes.empty()) 3570b57cec5SDimitry Andric discoverStreamPurposes(getPdb(), StreamPurposes); 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric uint32_t StreamCount = getPdb().getNumStreams(); 3600b57cec5SDimitry Andric uint32_t MaxStreamSize = getPdb().getMaxStreamSize(); 3610b57cec5SDimitry Andric 36281ad6265SDimitry Andric for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 3630b57cec5SDimitry Andric P.formatLine( 3640b57cec5SDimitry Andric "Stream {0} ({1} bytes): [{2}]", 3650b57cec5SDimitry Andric fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), 3660b57cec5SDimitry Andric fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right, 3670b57cec5SDimitry Andric NumDigits(MaxStreamSize)), 3680b57cec5SDimitry Andric StreamPurposes[StreamIdx].getLongName()); 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric if (opts::dump::DumpStreamBlocks) { 3710b57cec5SDimitry Andric auto Blocks = getPdb().getStreamBlockList(StreamIdx); 3720b57cec5SDimitry Andric std::vector<uint32_t> BV(Blocks.begin(), Blocks.end()); 3730b57cec5SDimitry Andric P.formatLine(" {0} Blocks: [{1}]", 3740b57cec5SDimitry Andric fmt_repeat(' ', NumDigits(StreamCount)), 3750b57cec5SDimitry Andric make_range(BV.begin(), BV.end())); 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric } 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric return Error::success(); 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric static Expected<std::pair<std::unique_ptr<MappedBlockStream>, 3830b57cec5SDimitry Andric ArrayRef<llvm::object::coff_section>>> 3840b57cec5SDimitry Andric loadSectionHeaders(PDBFile &File, DbgHeaderType Type) { 3850b57cec5SDimitry Andric if (!File.hasPDBDbiStream()) 3860b57cec5SDimitry Andric return make_error<StringError>( 3870b57cec5SDimitry Andric "Section headers require a DBI Stream, which could not be loaded", 3880b57cec5SDimitry Andric inconvertibleErrorCode()); 3890b57cec5SDimitry Andric 39081ad6265SDimitry Andric DbiStream &Dbi = cantFail(File.getPDBDbiStream()); 3910b57cec5SDimitry Andric uint32_t SI = Dbi.getDebugStreamIndex(Type); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric if (SI == kInvalidStreamIndex) 3940b57cec5SDimitry Andric return make_error<StringError>( 3950b57cec5SDimitry Andric "PDB does not contain the requested image section header type", 3960b57cec5SDimitry Andric inconvertibleErrorCode()); 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric auto Stream = File.createIndexedStream(SI); 3990b57cec5SDimitry Andric if (!Stream) 4000b57cec5SDimitry Andric return make_error<StringError>("Could not load the required stream data", 4010b57cec5SDimitry Andric inconvertibleErrorCode()); 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric ArrayRef<object::coff_section> Headers; 4040b57cec5SDimitry Andric if (Stream->getLength() % sizeof(object::coff_section) != 0) 4050b57cec5SDimitry Andric return make_error<StringError>( 4060b57cec5SDimitry Andric "Section header array size is not a multiple of section header size", 4070b57cec5SDimitry Andric inconvertibleErrorCode()); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section); 4100b57cec5SDimitry Andric BinaryStreamReader Reader(*Stream); 4110b57cec5SDimitry Andric cantFail(Reader.readArray(Headers, NumHeaders)); 4120b57cec5SDimitry Andric return std::make_pair(std::move(Stream), Headers); 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 41581ad6265SDimitry Andric static Expected<std::vector<std::string>> getSectionNames(PDBFile &File) { 4160b57cec5SDimitry Andric auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr); 4170b57cec5SDimitry Andric if (!ExpectedHeaders) 41881ad6265SDimitry Andric return ExpectedHeaders.takeError(); 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric std::unique_ptr<MappedBlockStream> Stream; 4210b57cec5SDimitry Andric ArrayRef<object::coff_section> Headers; 4220b57cec5SDimitry Andric std::tie(Stream, Headers) = std::move(*ExpectedHeaders); 4230b57cec5SDimitry Andric std::vector<std::string> Names; 4240b57cec5SDimitry Andric for (const auto &H : Headers) 4250b57cec5SDimitry Andric Names.push_back(H.Name); 4260b57cec5SDimitry Andric return Names; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC, 4300b57cec5SDimitry Andric ArrayRef<std::string> SectionNames, 4310b57cec5SDimitry Andric uint32_t FieldWidth) { 4320b57cec5SDimitry Andric std::string NameInsert; 4330b57cec5SDimitry Andric if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) { 4340b57cec5SDimitry Andric StringRef SectionName = SectionNames[SC.ISect - 1]; 4350b57cec5SDimitry Andric NameInsert = formatv("[{0}]", SectionName).str(); 4360b57cec5SDimitry Andric } else 4370b57cec5SDimitry Andric NameInsert = "[???]"; 4380b57cec5SDimitry Andric P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 4390b57cec5SDimitry Andric "crc = {4}", 4400b57cec5SDimitry Andric formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), 4410b57cec5SDimitry Andric fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc), 4420b57cec5SDimitry Andric fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2)); 4430b57cec5SDimitry Andric AutoIndent Indent(P, FieldWidth + 2); 4440b57cec5SDimitry Andric P.formatLine(" {0}", 4450b57cec5SDimitry Andric formatSectionCharacteristics(P.getIndentLevel() + 6, 4460b57cec5SDimitry Andric SC.Characteristics, 3, " | ")); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC, 4500b57cec5SDimitry Andric ArrayRef<std::string> SectionNames, 4510b57cec5SDimitry Andric uint32_t FieldWidth) { 4520b57cec5SDimitry Andric P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 4530b57cec5SDimitry Andric "crc = {4}, coff section = {5}", 4540b57cec5SDimitry Andric formatSegmentOffset(SC.Base.ISect, SC.Base.Off), 4550b57cec5SDimitry Andric fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), 4560b57cec5SDimitry Andric fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff)); 4570b57cec5SDimitry Andric P.formatLine(" {0}", 4580b57cec5SDimitry Andric formatSectionCharacteristics(P.getIndentLevel() + 6, 4590b57cec5SDimitry Andric SC.Base.Characteristics, 3, " | ")); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric Error DumpOutputStyle::dumpModules() { 4630b57cec5SDimitry Andric printHeader(P, "Modules"); 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric if (File.isObj()) { 4660b57cec5SDimitry Andric printStreamNotValidForObj(); 4670b57cec5SDimitry Andric return Error::success(); 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 4710b57cec5SDimitry Andric printStreamNotPresent("DBI"); 4720b57cec5SDimitry Andric return Error::success(); 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric AutoIndent Indent(P); 4760b57cec5SDimitry Andric 47781ad6265SDimitry Andric Expected<DbiStream &> StreamOrErr = getPdb().getPDBDbiStream(); 47881ad6265SDimitry Andric if (!StreamOrErr) 47981ad6265SDimitry Andric return StreamOrErr.takeError(); 48081ad6265SDimitry Andric DbiStream &Stream = *StreamOrErr; 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric const DbiModuleList &Modules = Stream.modules(); 48381ad6265SDimitry Andric return iterateSymbolGroups( 48481ad6265SDimitry Andric File, PrintScope{P, 11}, 48581ad6265SDimitry Andric [&](uint32_t Modi, const SymbolGroup &Strings) -> Error { 4860b57cec5SDimitry Andric auto Desc = Modules.getModuleDescriptor(Modi); 4870b57cec5SDimitry Andric if (opts::dump::DumpSectionContribs) { 48881ad6265SDimitry Andric auto SectionsOrErr = getSectionNames(getPdb()); 48981ad6265SDimitry Andric if (!SectionsOrErr) 49081ad6265SDimitry Andric return SectionsOrErr.takeError(); 49181ad6265SDimitry Andric ArrayRef<std::string> Sections = *SectionsOrErr; 4920b57cec5SDimitry Andric dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0); 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric P.formatLine("Obj: `{0}`: ", Desc.getObjFileName()); 4950b57cec5SDimitry Andric P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}", 4960b57cec5SDimitry Andric Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(), 4970b57cec5SDimitry Andric Desc.hasECInfo()); 49881ad6265SDimitry Andric 49981ad6265SDimitry Andric auto PdbPathOrErr = Stream.getECName(Desc.getPdbFilePathNameIndex()); 50081ad6265SDimitry Andric if (!PdbPathOrErr) 50181ad6265SDimitry Andric return PdbPathOrErr.takeError(); 50281ad6265SDimitry Andric StringRef PdbFilePath = *PdbPathOrErr; 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric auto SrcPathOrErr = Stream.getECName(Desc.getSourceFileNameIndex()); 50581ad6265SDimitry Andric if (!SrcPathOrErr) 50681ad6265SDimitry Andric return SrcPathOrErr.takeError(); 50781ad6265SDimitry Andric StringRef SrcFilePath = *SrcPathOrErr; 50881ad6265SDimitry Andric 5090b57cec5SDimitry Andric P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`", 5100b57cec5SDimitry Andric Desc.getPdbFilePathNameIndex(), PdbFilePath, 5110b57cec5SDimitry Andric Desc.getSourceFileNameIndex(), SrcFilePath); 5120b57cec5SDimitry Andric return Error::success(); 51381ad6265SDimitry Andric }); 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleFiles() { 5170b57cec5SDimitry Andric printHeader(P, "Files"); 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric if (File.isObj()) { 5200b57cec5SDimitry Andric printStreamNotValidForObj(); 5210b57cec5SDimitry Andric return Error::success(); 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 5250b57cec5SDimitry Andric printStreamNotPresent("DBI"); 5260b57cec5SDimitry Andric return Error::success(); 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 52981ad6265SDimitry Andric return iterateSymbolGroups( 53081ad6265SDimitry Andric File, PrintScope{P, 11}, 53181ad6265SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings) -> Error { 53281ad6265SDimitry Andric Expected<DbiStream &> StreamOrErr = getPdb().getPDBDbiStream(); 53381ad6265SDimitry Andric if (!StreamOrErr) 53481ad6265SDimitry Andric return StreamOrErr.takeError(); 53581ad6265SDimitry Andric DbiStream &Stream = *StreamOrErr; 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric const DbiModuleList &Modules = Stream.modules(); 5380b57cec5SDimitry Andric for (const auto &F : Modules.source_files(Modi)) { 5390b57cec5SDimitry Andric Strings.formatFromFileName(P, F); 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric return Error::success(); 54281ad6265SDimitry Andric }); 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric Error DumpOutputStyle::dumpSymbolStats() { 5460b57cec5SDimitry Andric printHeader(P, "Module Stats"); 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 5490b57cec5SDimitry Andric printStreamNotPresent("DBI"); 5500b57cec5SDimitry Andric return Error::success(); 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric StatCollection SymStats; 5540b57cec5SDimitry Andric StatCollection ChunkStats; 55581ad6265SDimitry Andric PrintScope Scope(P, 2); 5560b57cec5SDimitry Andric 55781ad6265SDimitry Andric if (Error Err = iterateSymbolGroups( 55881ad6265SDimitry Andric File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error { 5590b57cec5SDimitry Andric StatCollection SS = getSymbolStats(SG, SymStats); 5600b57cec5SDimitry Andric StatCollection CS = getChunkStats(SG, ChunkStats); 5610b57cec5SDimitry Andric 56281ad6265SDimitry Andric if (!SG.getFile().isPdb()) 56381ad6265SDimitry Andric return Error::success(); 56481ad6265SDimitry Andric 5650b57cec5SDimitry Andric AutoIndent Indent(P); 5660b57cec5SDimitry Andric auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules(); 5670b57cec5SDimitry Andric uint32_t ModCount = Modules.getModuleCount(); 5680b57cec5SDimitry Andric DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi); 5690b57cec5SDimitry Andric uint32_t StreamIdx = Desc.getModuleStreamIndex(); 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric if (StreamIdx == kInvalidStreamIndex) { 57281ad6265SDimitry Andric P.formatLine( 57381ad6265SDimitry Andric "Mod {0} (debug info not present): [{1}]", 5740b57cec5SDimitry Andric fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)), 5750b57cec5SDimitry Andric Desc.getModuleName()); 57681ad6265SDimitry Andric return Error::success(); 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric P.formatLine("Stream {0}, {1} bytes", StreamIdx, 5790b57cec5SDimitry Andric getPdb().getStreamByteSize(StreamIdx)); 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric printModuleDetailStats<SymbolKind>(P, "Symbols", SS); 5820b57cec5SDimitry Andric printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS); 58381ad6265SDimitry Andric 58481ad6265SDimitry Andric return Error::success(); 58581ad6265SDimitry Andric })) 58681ad6265SDimitry Andric return Err; 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric if (SymStats.Totals.Count > 0) { 5890b57cec5SDimitry Andric P.printLine(" Summary |"); 5900b57cec5SDimitry Andric AutoIndent Indent(P, 4); 5910b57cec5SDimitry Andric printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats); 5920b57cec5SDimitry Andric printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats); 5930b57cec5SDimitry Andric } 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric return Error::success(); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypeStats() { 5990b57cec5SDimitry Andric printHeader(P, "Type Record Stats"); 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric // Iterate the types, categorize by kind, accumulate size stats. 6020b57cec5SDimitry Andric StatCollection TypeStats; 6035ffd83dbSDimitry Andric LazyRandomTypeCollection &Types = 6045ffd83dbSDimitry Andric opts::dump::DumpTypeStats ? File.types() : File.ids(); 605*bdd1243dSDimitry Andric for (std::optional<TypeIndex> TI = Types.getFirst(); TI; 606*bdd1243dSDimitry Andric TI = Types.getNext(*TI)) { 6070b57cec5SDimitry Andric CVType Type = Types.getType(*TI); 6080b57cec5SDimitry Andric TypeStats.update(uint32_t(Type.kind()), Type.length()); 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric P.NewLine(); 6120b57cec5SDimitry Andric P.formatLine(" Types"); 6130b57cec5SDimitry Andric AutoIndent Indent(P); 6145ffd83dbSDimitry Andric P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total", 6150b57cec5SDimitry Andric TypeStats.Totals.Count, TypeStats.Totals.Size, 6160b57cec5SDimitry Andric (double)TypeStats.Totals.Size / TypeStats.Totals.Count); 6170b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', 74)); 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric for (const auto &K : TypeStats.getStatsSortedBySize()) { 6205ffd83dbSDimitry Andric P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", 6210b57cec5SDimitry Andric formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count, 6220b57cec5SDimitry Andric K.second.Size, (double)K.second.Size / K.second.Count); 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric return Error::success(); 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric static bool isValidNamespaceIdentifier(StringRef S) { 6280b57cec5SDimitry Andric if (S.empty()) 6290b57cec5SDimitry Andric return false; 6300b57cec5SDimitry Andric 6310b57cec5SDimitry Andric if (std::isdigit(S[0])) 6320b57cec5SDimitry Andric return false; 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric return llvm::all_of(S, [](char C) { return std::isalnum(C); }); 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric namespace { 6380b57cec5SDimitry Andric constexpr uint32_t kNoneUdtKind = 0; 6390b57cec5SDimitry Andric constexpr uint32_t kSimpleUdtKind = 1; 6400b57cec5SDimitry Andric constexpr uint32_t kUnknownUdtKind = 2; 6410b57cec5SDimitry Andric } // namespace 6420b57cec5SDimitry Andric 643e8d8bef9SDimitry Andric static std::string getUdtStatLabel(uint32_t Kind) { 6440b57cec5SDimitry Andric if (Kind == kNoneUdtKind) 645e8d8bef9SDimitry Andric return "<none type>"; 6460b57cec5SDimitry Andric 6470b57cec5SDimitry Andric if (Kind == kSimpleUdtKind) 648e8d8bef9SDimitry Andric return "<simple type>"; 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric if (Kind == kUnknownUdtKind) 651e8d8bef9SDimitry Andric return "<unknown type>"; 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind)); 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric static uint32_t getLongestTypeLeafName(const StatCollection &Stats) { 6570b57cec5SDimitry Andric size_t L = 0; 6580b57cec5SDimitry Andric for (const auto &Stat : Stats.Individual) { 659e8d8bef9SDimitry Andric std::string Label = getUdtStatLabel(Stat.first); 6600b57cec5SDimitry Andric L = std::max(L, Label.size()); 6610b57cec5SDimitry Andric } 6620b57cec5SDimitry Andric return static_cast<uint32_t>(L); 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric Error DumpOutputStyle::dumpUdtStats() { 6660b57cec5SDimitry Andric printHeader(P, "S_UDT Record Stats"); 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) { 6690b57cec5SDimitry Andric printStreamNotPresent("Globals"); 6700b57cec5SDimitry Andric return Error::success(); 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric StatCollection UdtStats; 6740b57cec5SDimitry Andric StatCollection UdtTargetStats; 6750b57cec5SDimitry Andric AutoIndent Indent(P, 4); 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric auto &TpiTypes = File.types(); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric StringMap<StatCollection::Stat> NamespacedStats; 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric size_t LongestNamespace = 0; 6820b57cec5SDimitry Andric auto HandleOneSymbol = [&](const CVSymbol &Sym) { 6830b57cec5SDimitry Andric if (Sym.kind() != SymbolKind::S_UDT) 6840b57cec5SDimitry Andric return; 6850b57cec5SDimitry Andric UdtStats.update(SymbolKind::S_UDT, Sym.length()); 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym)); 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric uint32_t Kind = 0; 6900b57cec5SDimitry Andric uint32_t RecordSize = 0; 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric if (UDT.Type.isNoneType()) 6930b57cec5SDimitry Andric Kind = kNoneUdtKind; 6940b57cec5SDimitry Andric else if (UDT.Type.isSimple()) 6950b57cec5SDimitry Andric Kind = kSimpleUdtKind; 696*bdd1243dSDimitry Andric else if (std::optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) { 6970b57cec5SDimitry Andric Kind = T->kind(); 6980b57cec5SDimitry Andric RecordSize = T->length(); 6990b57cec5SDimitry Andric } else 7000b57cec5SDimitry Andric Kind = kUnknownUdtKind; 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric UdtTargetStats.update(Kind, RecordSize); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric size_t Pos = UDT.Name.find("::"); 7050b57cec5SDimitry Andric if (Pos == StringRef::npos) 7060b57cec5SDimitry Andric return; 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric StringRef Scope = UDT.Name.take_front(Pos); 7090b57cec5SDimitry Andric if (Scope.empty() || !isValidNamespaceIdentifier(Scope)) 7100b57cec5SDimitry Andric return; 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric LongestNamespace = std::max(LongestNamespace, Scope.size()); 7130b57cec5SDimitry Andric NamespacedStats[Scope].update(RecordSize); 7140b57cec5SDimitry Andric }; 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric P.NewLine(); 7170b57cec5SDimitry Andric 7180b57cec5SDimitry Andric if (File.isPdb()) { 7190b57cec5SDimitry Andric auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream()); 7200b57cec5SDimitry Andric auto ExpGlobals = getPdb().getPDBGlobalsStream(); 7210b57cec5SDimitry Andric if (!ExpGlobals) 7220b57cec5SDimitry Andric return ExpGlobals.takeError(); 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) { 7250b57cec5SDimitry Andric CVSymbol Sym = SymbolRecords.readRecord(PubSymOff); 7260b57cec5SDimitry Andric HandleOneSymbol(Sym); 7270b57cec5SDimitry Andric } 7280b57cec5SDimitry Andric } else { 7290b57cec5SDimitry Andric for (const auto &Sec : File.symbol_groups()) { 7300b57cec5SDimitry Andric for (const auto &SS : Sec.getDebugSubsections()) { 7310b57cec5SDimitry Andric if (SS.kind() != DebugSubsectionKind::Symbols) 7320b57cec5SDimitry Andric continue; 7330b57cec5SDimitry Andric 7340b57cec5SDimitry Andric DebugSymbolsSubsectionRef Symbols; 7350b57cec5SDimitry Andric BinaryStreamReader Reader(SS.getRecordData()); 7360b57cec5SDimitry Andric cantFail(Symbols.initialize(Reader)); 7370b57cec5SDimitry Andric for (const auto &S : Symbols) 7380b57cec5SDimitry Andric HandleOneSymbol(S); 7390b57cec5SDimitry Andric } 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric LongestNamespace += StringRef(" namespace ''").size(); 7440b57cec5SDimitry Andric size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats); 7450b57cec5SDimitry Andric size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind); 7460b57cec5SDimitry Andric 7470b57cec5SDimitry Andric // Compute the max number of digits for count and size fields, including comma 7480b57cec5SDimitry Andric // separators. 7490b57cec5SDimitry Andric StringRef CountHeader("Count"); 7500b57cec5SDimitry Andric StringRef SizeHeader("Size"); 7510b57cec5SDimitry Andric size_t CD = NumDigits(UdtStats.Totals.Count); 7520b57cec5SDimitry Andric CD += (CD - 1) / 3; 7530b57cec5SDimitry Andric CD = std::max(CD, CountHeader.size()); 7540b57cec5SDimitry Andric 7550b57cec5SDimitry Andric size_t SD = NumDigits(UdtStats.Totals.Size); 7560b57cec5SDimitry Andric SD += (SD - 1) / 3; 7570b57cec5SDimitry Andric SD = std::max(SD, SizeHeader.size()); 7580b57cec5SDimitry Andric 7590b57cec5SDimitry Andric uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1; 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric P.formatLine("{0} | {1} {2}", 7620b57cec5SDimitry Andric fmt_align("Record Kind", AlignStyle::Right, FieldWidth), 7630b57cec5SDimitry Andric fmt_align(CountHeader, AlignStyle::Right, CD), 7640b57cec5SDimitry Andric fmt_align(SizeHeader, AlignStyle::Right, SD)); 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 7670b57cec5SDimitry Andric for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) { 768e8d8bef9SDimitry Andric std::string Label = getUdtStatLabel(Stat.first); 7690b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 7700b57cec5SDimitry Andric fmt_align(Label, AlignStyle::Right, FieldWidth), 7710b57cec5SDimitry Andric fmt_align(Stat.second.Count, AlignStyle::Right, CD), 7720b57cec5SDimitry Andric fmt_align(Stat.second.Size, AlignStyle::Right, SD)); 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 7750b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 7760b57cec5SDimitry Andric fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth), 7770b57cec5SDimitry Andric fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD), 7780b57cec5SDimitry Andric fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD)); 7790b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 7800b57cec5SDimitry Andric struct StrAndStat { 7810b57cec5SDimitry Andric StringRef Key; 7820b57cec5SDimitry Andric StatCollection::Stat Stat; 7830b57cec5SDimitry Andric }; 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric // Print namespace stats in descending order of size. 7860b57cec5SDimitry Andric std::vector<StrAndStat> NamespacedStatsSorted; 7870b57cec5SDimitry Andric for (const auto &Stat : NamespacedStats) 7880b57cec5SDimitry Andric NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second}); 7890b57cec5SDimitry Andric llvm::stable_sort(NamespacedStatsSorted, 7900b57cec5SDimitry Andric [](const StrAndStat &L, const StrAndStat &R) { 7910b57cec5SDimitry Andric return L.Stat.Size > R.Stat.Size; 7920b57cec5SDimitry Andric }); 7930b57cec5SDimitry Andric for (const auto &Stat : NamespacedStatsSorted) { 7945ffd83dbSDimitry Andric std::string Label = std::string(formatv("namespace '{0}'", Stat.Key)); 7950b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 7960b57cec5SDimitry Andric fmt_align(Label, AlignStyle::Right, FieldWidth), 7970b57cec5SDimitry Andric fmt_align(Stat.Stat.Count, AlignStyle::Right, CD), 7980b57cec5SDimitry Andric fmt_align(Stat.Stat.Size, AlignStyle::Right, SD)); 7990b57cec5SDimitry Andric } 8000b57cec5SDimitry Andric return Error::success(); 8010b57cec5SDimitry Andric } 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start, 8040b57cec5SDimitry Andric const LineColumnEntry &E) { 8050b57cec5SDimitry Andric const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number 8060b57cec5SDimitry Andric uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5; 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric // Let's try to keep it under 100 characters 8090b57cec5SDimitry Andric constexpr uint32_t kMaxRowLength = 100; 8100b57cec5SDimitry Andric // At least 3 spaces between columns. 8110b57cec5SDimitry Andric uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3); 8120b57cec5SDimitry Andric uint32_t ItemsLeft = E.LineNumbers.size(); 8130b57cec5SDimitry Andric auto LineIter = E.LineNumbers.begin(); 8140b57cec5SDimitry Andric while (ItemsLeft != 0) { 8150b57cec5SDimitry Andric uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow); 8160b57cec5SDimitry Andric for (uint32_t I = 0; I < RowColumns; ++I) { 8170b57cec5SDimitry Andric LineInfo Line(LineIter->Flags); 8180b57cec5SDimitry Andric std::string LineStr; 8190b57cec5SDimitry Andric if (Line.isAlwaysStepInto()) 8200b57cec5SDimitry Andric LineStr = "ASI"; 8210b57cec5SDimitry Andric else if (Line.isNeverStepInto()) 8220b57cec5SDimitry Andric LineStr = "NSI"; 8230b57cec5SDimitry Andric else 8240b57cec5SDimitry Andric LineStr = utostr(Line.getStartLine()); 8250b57cec5SDimitry Andric char Statement = Line.isStatement() ? ' ' : '!'; 8260b57cec5SDimitry Andric P.format("{0} {1:X-} {2} ", 8270b57cec5SDimitry Andric fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber), 8280b57cec5SDimitry Andric fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'), 8290b57cec5SDimitry Andric Statement); 8300b57cec5SDimitry Andric ++LineIter; 8310b57cec5SDimitry Andric --ItemsLeft; 8320b57cec5SDimitry Andric } 8330b57cec5SDimitry Andric P.NewLine(); 8340b57cec5SDimitry Andric } 8350b57cec5SDimitry Andric } 8360b57cec5SDimitry Andric 8370b57cec5SDimitry Andric Error DumpOutputStyle::dumpLines() { 8380b57cec5SDimitry Andric printHeader(P, "Lines"); 8390b57cec5SDimitry Andric 8400b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 8410b57cec5SDimitry Andric printStreamNotPresent("DBI"); 8420b57cec5SDimitry Andric return Error::success(); 8430b57cec5SDimitry Andric } 8440b57cec5SDimitry Andric 8450b57cec5SDimitry Andric uint32_t LastModi = UINT32_MAX; 8460b57cec5SDimitry Andric uint32_t LastNameIndex = UINT32_MAX; 84781ad6265SDimitry Andric return iterateModuleSubsections<DebugLinesSubsectionRef>( 8480b57cec5SDimitry Andric File, PrintScope{P, 4}, 84981ad6265SDimitry Andric [this, &LastModi, 85081ad6265SDimitry Andric &LastNameIndex](uint32_t Modi, const SymbolGroup &Strings, 85181ad6265SDimitry Andric DebugLinesSubsectionRef &Lines) -> Error { 8520b57cec5SDimitry Andric uint16_t Segment = Lines.header()->RelocSegment; 8530b57cec5SDimitry Andric uint32_t Begin = Lines.header()->RelocOffset; 8540b57cec5SDimitry Andric uint32_t End = Begin + Lines.header()->CodeSize; 8550b57cec5SDimitry Andric for (const auto &Block : Lines) { 8560b57cec5SDimitry Andric if (LastModi != Modi || LastNameIndex != Block.NameIndex) { 8570b57cec5SDimitry Andric LastModi = Modi; 8580b57cec5SDimitry Andric LastNameIndex = Block.NameIndex; 8590b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, Block.NameIndex); 8600b57cec5SDimitry Andric } 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric AutoIndent Indent(P, 2); 8630b57cec5SDimitry Andric P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End); 8640b57cec5SDimitry Andric uint32_t Count = Block.LineNumbers.size(); 8650b57cec5SDimitry Andric if (Lines.hasColumnInfo()) 8660b57cec5SDimitry Andric P.format("line/column/addr entries = {0}", Count); 8670b57cec5SDimitry Andric else 8680b57cec5SDimitry Andric P.format("line/addr entries = {0}", Count); 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric P.NewLine(); 8710b57cec5SDimitry Andric typesetLinesAndColumns(P, Begin, Block); 8720b57cec5SDimitry Andric } 8730b57cec5SDimitry Andric return Error::success(); 87481ad6265SDimitry Andric }); 8750b57cec5SDimitry Andric } 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric Error DumpOutputStyle::dumpInlineeLines() { 8780b57cec5SDimitry Andric printHeader(P, "Inlinee Lines"); 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 8810b57cec5SDimitry Andric printStreamNotPresent("DBI"); 8820b57cec5SDimitry Andric return Error::success(); 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 88581ad6265SDimitry Andric return iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( 8860b57cec5SDimitry Andric File, PrintScope{P, 2}, 8870b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 88881ad6265SDimitry Andric DebugInlineeLinesSubsectionRef &Lines) -> Error { 8890b57cec5SDimitry Andric P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File"); 8900b57cec5SDimitry Andric for (const auto &Entry : Lines) { 8910b57cec5SDimitry Andric P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, 8920b57cec5SDimitry Andric fmtle(Entry.Header->SourceLineNum)); 8930b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); 8940b57cec5SDimitry Andric for (const auto &ExtraFileID : Entry.ExtraFiles) { 8950b57cec5SDimitry Andric P.formatLine(" "); 8960b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, ExtraFileID, true); 8970b57cec5SDimitry Andric } 8980b57cec5SDimitry Andric } 8990b57cec5SDimitry Andric P.NewLine(); 9000b57cec5SDimitry Andric return Error::success(); 90181ad6265SDimitry Andric }); 9020b57cec5SDimitry Andric } 9030b57cec5SDimitry Andric 9040b57cec5SDimitry Andric Error DumpOutputStyle::dumpXmi() { 9050b57cec5SDimitry Andric printHeader(P, "Cross Module Imports"); 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 9080b57cec5SDimitry Andric printStreamNotPresent("DBI"); 9090b57cec5SDimitry Andric return Error::success(); 9100b57cec5SDimitry Andric } 9110b57cec5SDimitry Andric 91281ad6265SDimitry Andric return iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>( 9130b57cec5SDimitry Andric File, PrintScope{P, 2}, 9140b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 91581ad6265SDimitry Andric DebugCrossModuleImportsSubsectionRef &Imports) -> Error { 9160b57cec5SDimitry Andric P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs"); 9170b57cec5SDimitry Andric 9180b57cec5SDimitry Andric for (const auto &Xmi : Imports) { 9190b57cec5SDimitry Andric auto ExpectedModule = 9200b57cec5SDimitry Andric Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset); 9210b57cec5SDimitry Andric StringRef Module; 9220b57cec5SDimitry Andric SmallString<32> ModuleStorage; 9230b57cec5SDimitry Andric if (!ExpectedModule) { 9240b57cec5SDimitry Andric Module = "(unknown module)"; 9250b57cec5SDimitry Andric consumeError(ExpectedModule.takeError()); 9260b57cec5SDimitry Andric } else 9270b57cec5SDimitry Andric Module = *ExpectedModule; 9280b57cec5SDimitry Andric if (Module.size() > 32) { 9290b57cec5SDimitry Andric ModuleStorage = "..."; 9300b57cec5SDimitry Andric ModuleStorage += Module.take_back(32 - 3); 9310b57cec5SDimitry Andric Module = ModuleStorage; 9320b57cec5SDimitry Andric } 9330b57cec5SDimitry Andric std::vector<std::string> TIs; 9340b57cec5SDimitry Andric for (const auto I : Xmi.Imports) 9355ffd83dbSDimitry Andric TIs.push_back(std::string(formatv("{0,+10:X+}", fmtle(I)))); 9360b57cec5SDimitry Andric std::string Result = 9370b57cec5SDimitry Andric typesetItemList(TIs, P.getIndentLevel() + 35, 12, " "); 9380b57cec5SDimitry Andric P.formatLine("{0,+32} | {1}", Module, Result); 9390b57cec5SDimitry Andric } 9400b57cec5SDimitry Andric return Error::success(); 94181ad6265SDimitry Andric }); 9420b57cec5SDimitry Andric } 9430b57cec5SDimitry Andric 9440b57cec5SDimitry Andric Error DumpOutputStyle::dumpXme() { 9450b57cec5SDimitry Andric printHeader(P, "Cross Module Exports"); 9460b57cec5SDimitry Andric 9470b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 9480b57cec5SDimitry Andric printStreamNotPresent("DBI"); 9490b57cec5SDimitry Andric return Error::success(); 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric 95281ad6265SDimitry Andric return iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>( 9530b57cec5SDimitry Andric File, PrintScope{P, 2}, 9540b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 95581ad6265SDimitry Andric DebugCrossModuleExportsSubsectionRef &Exports) -> Error { 9560b57cec5SDimitry Andric P.formatLine("{0,-10} | {1}", "Local ID", "Global ID"); 9570b57cec5SDimitry Andric for (const auto &Export : Exports) { 9580b57cec5SDimitry Andric P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local), 9590b57cec5SDimitry Andric TypeIndex(Export.Global)); 9600b57cec5SDimitry Andric } 9610b57cec5SDimitry Andric return Error::success(); 96281ad6265SDimitry Andric }); 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric std::string formatFrameType(object::frame_type FT) { 9660b57cec5SDimitry Andric switch (FT) { 9670b57cec5SDimitry Andric case object::frame_type::Fpo: 9680b57cec5SDimitry Andric return "FPO"; 9690b57cec5SDimitry Andric case object::frame_type::NonFpo: 9700b57cec5SDimitry Andric return "Non-FPO"; 9710b57cec5SDimitry Andric case object::frame_type::Trap: 9720b57cec5SDimitry Andric return "Trap"; 9730b57cec5SDimitry Andric case object::frame_type::Tss: 9740b57cec5SDimitry Andric return "TSS"; 9750b57cec5SDimitry Andric } 9760b57cec5SDimitry Andric return "<unknown>"; 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { 9800b57cec5SDimitry Andric printHeader(P, "Old FPO Data"); 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric ExitOnError Err("Error dumping old fpo data:"); 98381ad6265SDimitry Andric DbiStream &Dbi = Err(File.getPDBDbiStream()); 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric if (!Dbi.hasOldFpoRecords()) { 9860b57cec5SDimitry Andric printStreamNotPresent("FPO"); 9870b57cec5SDimitry Andric return Error::success(); 9880b57cec5SDimitry Andric } 9890b57cec5SDimitry Andric 9900b57cec5SDimitry Andric const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords(); 9910b57cec5SDimitry Andric 9920b57cec5SDimitry Andric P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " 9930b57cec5SDimitry Andric "BP | Has SEH | Frame Type"); 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric for (const object::FpoData &FD : Records) { 9960b57cec5SDimitry Andric P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | " 9970b57cec5SDimitry Andric "{7,7} | {8,9}", 9980b57cec5SDimitry Andric uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals), 9990b57cec5SDimitry Andric uint32_t(FD.NumParams), FD.getPrologSize(), 10000b57cec5SDimitry Andric FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(), 10010b57cec5SDimitry Andric formatFrameType(FD.getFP())); 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric return Error::success(); 10040b57cec5SDimitry Andric } 10050b57cec5SDimitry Andric 10060b57cec5SDimitry Andric Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { 10070b57cec5SDimitry Andric printHeader(P, "New FPO Data"); 10080b57cec5SDimitry Andric 10090b57cec5SDimitry Andric ExitOnError Err("Error dumping new fpo data:"); 101081ad6265SDimitry Andric DbiStream &Dbi = Err(File.getPDBDbiStream()); 10110b57cec5SDimitry Andric 10120b57cec5SDimitry Andric if (!Dbi.hasNewFpoRecords()) { 10130b57cec5SDimitry Andric printStreamNotPresent("New FPO"); 10140b57cec5SDimitry Andric return Error::success(); 10150b57cec5SDimitry Andric } 10160b57cec5SDimitry Andric 10170b57cec5SDimitry Andric const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords(); 10180b57cec5SDimitry Andric 10190b57cec5SDimitry Andric P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " 10200b57cec5SDimitry Andric "| Has SEH | Has C++EH | Start | Program"); 10210b57cec5SDimitry Andric for (const FrameData &FD : FDS) { 10220b57cec5SDimitry Andric bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart; 10230b57cec5SDimitry Andric bool HasEH = FD.Flags & FrameData::HasEH; 10240b57cec5SDimitry Andric bool HasSEH = FD.Flags & FrameData::HasSEH; 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric auto &StringTable = Err(File.getStringTable()); 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric auto Program = Err(StringTable.getStringForID(FD.FrameFunc)); 10290b57cec5SDimitry Andric P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | " 10300b57cec5SDimitry Andric "{7,7} | {8,9} | {9,5} | {10}", 10310b57cec5SDimitry Andric uint32_t(FD.RvaStart), uint32_t(FD.CodeSize), 10320b57cec5SDimitry Andric uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize), 10330b57cec5SDimitry Andric uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize), 10340b57cec5SDimitry Andric uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart, 10350b57cec5SDimitry Andric Program); 10360b57cec5SDimitry Andric } 10370b57cec5SDimitry Andric return Error::success(); 10380b57cec5SDimitry Andric } 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric Error DumpOutputStyle::dumpFpo() { 10410b57cec5SDimitry Andric if (!File.isPdb()) { 10420b57cec5SDimitry Andric printStreamNotValidForObj(); 10430b57cec5SDimitry Andric return Error::success(); 10440b57cec5SDimitry Andric } 10450b57cec5SDimitry Andric 10460b57cec5SDimitry Andric PDBFile &File = getPdb(); 10470b57cec5SDimitry Andric if (!File.hasPDBDbiStream()) { 10480b57cec5SDimitry Andric printStreamNotPresent("DBI"); 10490b57cec5SDimitry Andric return Error::success(); 10500b57cec5SDimitry Andric } 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric if (auto EC = dumpOldFpo(File)) 10530b57cec5SDimitry Andric return EC; 10540b57cec5SDimitry Andric if (auto EC = dumpNewFpo(File)) 10550b57cec5SDimitry Andric return EC; 10560b57cec5SDimitry Andric return Error::success(); 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTableFromPdb() { 10600b57cec5SDimitry Andric AutoIndent Indent(P); 10610b57cec5SDimitry Andric auto IS = getPdb().getStringTable(); 10620b57cec5SDimitry Andric if (!IS) { 10630b57cec5SDimitry Andric P.formatLine("Not present in file"); 10640b57cec5SDimitry Andric consumeError(IS.takeError()); 10650b57cec5SDimitry Andric return Error::success(); 10660b57cec5SDimitry Andric } 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric if (opts::dump::DumpStringTable) { 10690b57cec5SDimitry Andric if (IS->name_ids().empty()) 10700b57cec5SDimitry Andric P.formatLine("Empty"); 10710b57cec5SDimitry Andric else { 10720b57cec5SDimitry Andric auto MaxID = 10730b57cec5SDimitry Andric std::max_element(IS->name_ids().begin(), IS->name_ids().end()); 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)); 1254*bdd1243dSDimitry 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; 12880b57cec5SDimitry Andric BinaryStreamReader Reader(*ContentsOrErr, llvm::support::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}", 14970b57cec5SDimitry Andric toString(std::move(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}", 150381ad6265SDimitry Andric toString(std::move(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(); 1521*bdd1243dSDimitry Andric for (std::optional<TypeIndex> TI = Types.getFirst(); TI; 1522*bdd1243dSDimitry 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) { 18380b57cec5SDimitry Andric auto Max = std::max_element( 18390b57cec5SDimitry Andric Names.begin(), Names.end(), 18400b57cec5SDimitry Andric [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); }); 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