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