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