1*0b57cec5SDimitry Andric //===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "DumpOutputStyle.h" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "FormatUtil.h" 12*0b57cec5SDimitry Andric #include "InputFile.h" 13*0b57cec5SDimitry Andric #include "MinimalSymbolDumper.h" 14*0b57cec5SDimitry Andric #include "MinimalTypeDumper.h" 15*0b57cec5SDimitry Andric #include "StreamUtil.h" 16*0b57cec5SDimitry Andric #include "TypeReferenceTracker.h" 17*0b57cec5SDimitry Andric #include "llvm-pdbutil.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 20*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" 21*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 22*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 23*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" 24*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" 25*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" 26*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" 27*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 28*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" 29*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" 30*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Formatters.h" 31*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 32*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Line.h" 33*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" 34*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" 35*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" 36*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeHashing.h" 37*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" 38*0b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 39*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 40*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 41*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" 42*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" 43*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 44*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" 45*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 46*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" 47*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h" 48*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" 49*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" 50*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 51*0b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 52*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 53*0b57cec5SDimitry Andric #include "llvm/Support/FormatAdapters.h" 54*0b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h" 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric #include <cctype> 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric using namespace llvm; 59*0b57cec5SDimitry Andric using namespace llvm::codeview; 60*0b57cec5SDimitry Andric using namespace llvm::msf; 61*0b57cec5SDimitry Andric using namespace llvm::pdb; 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric DumpOutputStyle::DumpOutputStyle(InputFile &File) 64*0b57cec5SDimitry Andric : File(File), P(2, false, outs()) { 65*0b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) 66*0b57cec5SDimitry Andric RefTracker.reset(new TypeReferenceTracker(File)); 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric DumpOutputStyle::~DumpOutputStyle() {} 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); } 72*0b57cec5SDimitry Andric object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); } 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotValidForObj() { 75*0b57cec5SDimitry Andric AutoIndent Indent(P, 4); 76*0b57cec5SDimitry Andric P.formatLine("Dumping this stream is not valid for object files"); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) { 80*0b57cec5SDimitry Andric AutoIndent Indent(P, 4); 81*0b57cec5SDimitry Andric P.formatLine("{0} stream not present", StreamName); 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric Error DumpOutputStyle::dump() { 85*0b57cec5SDimitry Andric // Walk symbols & globals if we are supposed to mark types referenced. 86*0b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) 87*0b57cec5SDimitry Andric RefTracker->mark(); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric if (opts::dump::DumpSummary) { 90*0b57cec5SDimitry Andric if (auto EC = dumpFileSummary()) 91*0b57cec5SDimitry Andric return EC; 92*0b57cec5SDimitry Andric P.NewLine(); 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric if (opts::dump::DumpStreams) { 96*0b57cec5SDimitry Andric if (auto EC = dumpStreamSummary()) 97*0b57cec5SDimitry Andric return EC; 98*0b57cec5SDimitry Andric P.NewLine(); 99*0b57cec5SDimitry Andric } 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric if (opts::dump::DumpSymbolStats) { 102*0b57cec5SDimitry Andric if (auto EC = dumpSymbolStats()) 103*0b57cec5SDimitry Andric return EC; 104*0b57cec5SDimitry Andric P.NewLine(); 105*0b57cec5SDimitry Andric } 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric if (opts::dump::DumpUdtStats) { 108*0b57cec5SDimitry Andric if (auto EC = dumpUdtStats()) 109*0b57cec5SDimitry Andric return EC; 110*0b57cec5SDimitry Andric P.NewLine(); 111*0b57cec5SDimitry Andric } 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric if (opts::dump::DumpTypeStats) { 114*0b57cec5SDimitry Andric if (auto EC = dumpTypeStats()) 115*0b57cec5SDimitry Andric return EC; 116*0b57cec5SDimitry Andric P.NewLine(); 117*0b57cec5SDimitry Andric } 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric if (opts::dump::DumpNamedStreams) { 120*0b57cec5SDimitry Andric if (auto EC = dumpNamedStreams()) 121*0b57cec5SDimitry Andric return EC; 122*0b57cec5SDimitry Andric P.NewLine(); 123*0b57cec5SDimitry Andric } 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) { 126*0b57cec5SDimitry Andric if (auto EC = dumpStringTable()) 127*0b57cec5SDimitry Andric return EC; 128*0b57cec5SDimitry Andric P.NewLine(); 129*0b57cec5SDimitry Andric } 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric if (opts::dump::DumpModules) { 132*0b57cec5SDimitry Andric if (auto EC = dumpModules()) 133*0b57cec5SDimitry Andric return EC; 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric if (opts::dump::DumpModuleFiles) { 137*0b57cec5SDimitry Andric if (auto EC = dumpModuleFiles()) 138*0b57cec5SDimitry Andric return EC; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric if (opts::dump::DumpLines) { 142*0b57cec5SDimitry Andric if (auto EC = dumpLines()) 143*0b57cec5SDimitry Andric return EC; 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric if (opts::dump::DumpInlineeLines) { 147*0b57cec5SDimitry Andric if (auto EC = dumpInlineeLines()) 148*0b57cec5SDimitry Andric return EC; 149*0b57cec5SDimitry Andric } 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric if (opts::dump::DumpXmi) { 152*0b57cec5SDimitry Andric if (auto EC = dumpXmi()) 153*0b57cec5SDimitry Andric return EC; 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric if (opts::dump::DumpXme) { 157*0b57cec5SDimitry Andric if (auto EC = dumpXme()) 158*0b57cec5SDimitry Andric return EC; 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric if (opts::dump::DumpFpo) { 162*0b57cec5SDimitry Andric if (auto EC = dumpFpo()) 163*0b57cec5SDimitry Andric return EC; 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric if (File.isObj()) { 167*0b57cec5SDimitry Andric if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 168*0b57cec5SDimitry Andric opts::dump::DumpTypeExtras) 169*0b57cec5SDimitry Andric if (auto EC = dumpTypesFromObjectFile()) 170*0b57cec5SDimitry Andric return EC; 171*0b57cec5SDimitry Andric } else { 172*0b57cec5SDimitry Andric if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() || 173*0b57cec5SDimitry Andric opts::dump::DumpTypeExtras) { 174*0b57cec5SDimitry Andric if (auto EC = dumpTpiStream(StreamTPI)) 175*0b57cec5SDimitry Andric return EC; 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() || 179*0b57cec5SDimitry Andric opts::dump::DumpIdExtras) { 180*0b57cec5SDimitry Andric if (auto EC = dumpTpiStream(StreamIPI)) 181*0b57cec5SDimitry Andric return EC; 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric if (opts::dump::DumpGSIRecords) { 186*0b57cec5SDimitry Andric if (auto EC = dumpGSIRecords()) 187*0b57cec5SDimitry Andric return EC; 188*0b57cec5SDimitry Andric } 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric if (opts::dump::DumpGlobals) { 191*0b57cec5SDimitry Andric if (auto EC = dumpGlobals()) 192*0b57cec5SDimitry Andric return EC; 193*0b57cec5SDimitry Andric } 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric if (opts::dump::DumpPublics) { 196*0b57cec5SDimitry Andric if (auto EC = dumpPublics()) 197*0b57cec5SDimitry Andric return EC; 198*0b57cec5SDimitry Andric } 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric if (opts::dump::DumpSymbols) { 201*0b57cec5SDimitry Andric auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj(); 202*0b57cec5SDimitry Andric if (EC) 203*0b57cec5SDimitry Andric return EC; 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric if (opts::dump::DumpTypeRefStats) { 207*0b57cec5SDimitry Andric if (auto EC = dumpTypeRefStats()) 208*0b57cec5SDimitry Andric return EC; 209*0b57cec5SDimitry Andric } 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric if (opts::dump::DumpSectionHeaders) { 212*0b57cec5SDimitry Andric if (auto EC = dumpSectionHeaders()) 213*0b57cec5SDimitry Andric return EC; 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric if (opts::dump::DumpSectionContribs) { 217*0b57cec5SDimitry Andric if (auto EC = dumpSectionContribs()) 218*0b57cec5SDimitry Andric return EC; 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric if (opts::dump::DumpSectionMap) { 222*0b57cec5SDimitry Andric if (auto EC = dumpSectionMap()) 223*0b57cec5SDimitry Andric return EC; 224*0b57cec5SDimitry Andric } 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric P.NewLine(); 227*0b57cec5SDimitry Andric 228*0b57cec5SDimitry Andric return Error::success(); 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric static void printHeader(LinePrinter &P, const Twine &S) { 232*0b57cec5SDimitry Andric P.NewLine(); 233*0b57cec5SDimitry Andric P.formatLine("{0,=60}", S); 234*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('=', 60)); 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpFileSummary() { 238*0b57cec5SDimitry Andric printHeader(P, "Summary"); 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric if (File.isObj()) { 241*0b57cec5SDimitry Andric printStreamNotValidForObj(); 242*0b57cec5SDimitry Andric return Error::success(); 243*0b57cec5SDimitry Andric } 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric AutoIndent Indent(P); 246*0b57cec5SDimitry Andric ExitOnError Err("Invalid PDB Format: "); 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric P.formatLine("Block Size: {0}", getPdb().getBlockSize()); 249*0b57cec5SDimitry Andric P.formatLine("Number of blocks: {0}", getPdb().getBlockCount()); 250*0b57cec5SDimitry Andric P.formatLine("Number of streams: {0}", getPdb().getNumStreams()); 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric auto &PS = Err(getPdb().getPDBInfoStream()); 253*0b57cec5SDimitry Andric P.formatLine("Signature: {0}", PS.getSignature()); 254*0b57cec5SDimitry Andric P.formatLine("Age: {0}", PS.getAge()); 255*0b57cec5SDimitry Andric P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid)); 256*0b57cec5SDimitry Andric P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures())); 257*0b57cec5SDimitry Andric P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream()); 258*0b57cec5SDimitry Andric P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream()); 259*0b57cec5SDimitry Andric P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream()); 260*0b57cec5SDimitry Andric P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream()); 261*0b57cec5SDimitry Andric P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream()); 262*0b57cec5SDimitry Andric if (getPdb().hasPDBDbiStream()) { 263*0b57cec5SDimitry Andric auto &DBI = Err(getPdb().getPDBDbiStream()); 264*0b57cec5SDimitry Andric P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked()); 265*0b57cec5SDimitry Andric P.formatLine("Has conflicting types: {0}", DBI.hasCTypes()); 266*0b57cec5SDimitry Andric P.formatLine("Is stripped: {0}", DBI.isStripped()); 267*0b57cec5SDimitry Andric } 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric return Error::success(); 270*0b57cec5SDimitry Andric } 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric static StatCollection getSymbolStats(const SymbolGroup &SG, 273*0b57cec5SDimitry Andric StatCollection &CumulativeStats) { 274*0b57cec5SDimitry Andric StatCollection Stats; 275*0b57cec5SDimitry Andric if (SG.getFile().isPdb() && SG.hasDebugStream()) { 276*0b57cec5SDimitry Andric // For PDB files, all symbols are packed into one stream. 277*0b57cec5SDimitry Andric for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) { 278*0b57cec5SDimitry Andric Stats.update(S.kind(), S.length()); 279*0b57cec5SDimitry Andric CumulativeStats.update(S.kind(), S.length()); 280*0b57cec5SDimitry Andric } 281*0b57cec5SDimitry Andric return Stats; 282*0b57cec5SDimitry Andric } 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric for (const auto &SS : SG.getDebugSubsections()) { 285*0b57cec5SDimitry Andric // For object files, all symbols are spread across multiple Symbol 286*0b57cec5SDimitry Andric // subsections of a given .debug$S section. 287*0b57cec5SDimitry Andric if (SS.kind() != DebugSubsectionKind::Symbols) 288*0b57cec5SDimitry Andric continue; 289*0b57cec5SDimitry Andric DebugSymbolsSubsectionRef Symbols; 290*0b57cec5SDimitry Andric BinaryStreamReader Reader(SS.getRecordData()); 291*0b57cec5SDimitry Andric cantFail(Symbols.initialize(Reader)); 292*0b57cec5SDimitry Andric for (const auto &S : Symbols) { 293*0b57cec5SDimitry Andric Stats.update(S.kind(), S.length()); 294*0b57cec5SDimitry Andric CumulativeStats.update(S.kind(), S.length()); 295*0b57cec5SDimitry Andric } 296*0b57cec5SDimitry Andric } 297*0b57cec5SDimitry Andric return Stats; 298*0b57cec5SDimitry Andric } 299*0b57cec5SDimitry Andric 300*0b57cec5SDimitry Andric static StatCollection getChunkStats(const SymbolGroup &SG, 301*0b57cec5SDimitry Andric StatCollection &CumulativeStats) { 302*0b57cec5SDimitry Andric StatCollection Stats; 303*0b57cec5SDimitry Andric for (const auto &Chunk : SG.getDebugSubsections()) { 304*0b57cec5SDimitry Andric Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 305*0b57cec5SDimitry Andric CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength()); 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric return Stats; 308*0b57cec5SDimitry Andric } 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(DebugSubsectionKind K) { 311*0b57cec5SDimitry Andric return formatChunkKind(K, false); 312*0b57cec5SDimitry Andric } 313*0b57cec5SDimitry Andric 314*0b57cec5SDimitry Andric static inline std::string formatModuleDetailKind(SymbolKind K) { 315*0b57cec5SDimitry Andric return formatSymbolKind(K); 316*0b57cec5SDimitry Andric } 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric // Get the stats sorted by size, descending. 319*0b57cec5SDimitry Andric std::vector<StatCollection::KindAndStat> 320*0b57cec5SDimitry Andric StatCollection::getStatsSortedBySize() const { 321*0b57cec5SDimitry Andric std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end()); 322*0b57cec5SDimitry Andric llvm::stable_sort(SortedStats, 323*0b57cec5SDimitry Andric [](const KindAndStat &LHS, const KindAndStat &RHS) { 324*0b57cec5SDimitry Andric return LHS.second.Size > RHS.second.Size; 325*0b57cec5SDimitry Andric }); 326*0b57cec5SDimitry Andric return SortedStats; 327*0b57cec5SDimitry Andric } 328*0b57cec5SDimitry Andric 329*0b57cec5SDimitry Andric template <typename Kind> 330*0b57cec5SDimitry Andric static void printModuleDetailStats(LinePrinter &P, StringRef Label, 331*0b57cec5SDimitry Andric const StatCollection &Stats) { 332*0b57cec5SDimitry Andric P.NewLine(); 333*0b57cec5SDimitry Andric P.formatLine(" {0}", Label); 334*0b57cec5SDimitry Andric AutoIndent Indent(P); 335*0b57cec5SDimitry Andric P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total", 336*0b57cec5SDimitry Andric Stats.Totals.Count, Stats.Totals.Size); 337*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', 74)); 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric for (const auto &K : Stats.getStatsSortedBySize()) { 340*0b57cec5SDimitry Andric std::string KindName = formatModuleDetailKind(Kind(K.first)); 341*0b57cec5SDimitry Andric P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName, 342*0b57cec5SDimitry Andric K.second.Count, K.second.Size); 343*0b57cec5SDimitry Andric } 344*0b57cec5SDimitry Andric } 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric static bool isMyCode(const SymbolGroup &Group) { 347*0b57cec5SDimitry Andric if (Group.getFile().isObj()) 348*0b57cec5SDimitry Andric return true; 349*0b57cec5SDimitry Andric 350*0b57cec5SDimitry Andric StringRef Name = Group.name(); 351*0b57cec5SDimitry Andric if (Name.startswith("Import:")) 352*0b57cec5SDimitry Andric return false; 353*0b57cec5SDimitry Andric if (Name.endswith_lower(".dll")) 354*0b57cec5SDimitry Andric return false; 355*0b57cec5SDimitry Andric if (Name.equals_lower("* linker *")) 356*0b57cec5SDimitry Andric return false; 357*0b57cec5SDimitry Andric if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools")) 358*0b57cec5SDimitry Andric return false; 359*0b57cec5SDimitry Andric if (Name.startswith_lower("f:\\dd\\vctools\\crt")) 360*0b57cec5SDimitry Andric return false; 361*0b57cec5SDimitry Andric return true; 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric 364*0b57cec5SDimitry Andric static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) { 365*0b57cec5SDimitry Andric if (opts::dump::JustMyCode && !isMyCode(Group)) 366*0b57cec5SDimitry Andric return false; 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric // If the arg was not specified on the command line, always dump all modules. 369*0b57cec5SDimitry Andric if (opts::dump::DumpModi.getNumOccurrences() == 0) 370*0b57cec5SDimitry Andric return true; 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric // Otherwise, only dump if this is the same module specified. 373*0b57cec5SDimitry Andric return (opts::dump::DumpModi == Idx); 374*0b57cec5SDimitry Andric } 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpStreamSummary() { 377*0b57cec5SDimitry Andric printHeader(P, "Streams"); 378*0b57cec5SDimitry Andric 379*0b57cec5SDimitry Andric if (File.isObj()) { 380*0b57cec5SDimitry Andric printStreamNotValidForObj(); 381*0b57cec5SDimitry Andric return Error::success(); 382*0b57cec5SDimitry Andric } 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric AutoIndent Indent(P); 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric if (StreamPurposes.empty()) 387*0b57cec5SDimitry Andric discoverStreamPurposes(getPdb(), StreamPurposes); 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric uint32_t StreamCount = getPdb().getNumStreams(); 390*0b57cec5SDimitry Andric uint32_t MaxStreamSize = getPdb().getMaxStreamSize(); 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { 393*0b57cec5SDimitry Andric P.formatLine( 394*0b57cec5SDimitry Andric "Stream {0} ({1} bytes): [{2}]", 395*0b57cec5SDimitry Andric fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), 396*0b57cec5SDimitry Andric fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right, 397*0b57cec5SDimitry Andric NumDigits(MaxStreamSize)), 398*0b57cec5SDimitry Andric StreamPurposes[StreamIdx].getLongName()); 399*0b57cec5SDimitry Andric 400*0b57cec5SDimitry Andric if (opts::dump::DumpStreamBlocks) { 401*0b57cec5SDimitry Andric auto Blocks = getPdb().getStreamBlockList(StreamIdx); 402*0b57cec5SDimitry Andric std::vector<uint32_t> BV(Blocks.begin(), Blocks.end()); 403*0b57cec5SDimitry Andric P.formatLine(" {0} Blocks: [{1}]", 404*0b57cec5SDimitry Andric fmt_repeat(' ', NumDigits(StreamCount)), 405*0b57cec5SDimitry Andric make_range(BV.begin(), BV.end())); 406*0b57cec5SDimitry Andric } 407*0b57cec5SDimitry Andric } 408*0b57cec5SDimitry Andric 409*0b57cec5SDimitry Andric return Error::success(); 410*0b57cec5SDimitry Andric } 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File, 413*0b57cec5SDimitry Andric uint32_t Index) { 414*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error: "); 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric auto &Dbi = Err(File.getPDBDbiStream()); 417*0b57cec5SDimitry Andric const auto &Modules = Dbi.modules(); 418*0b57cec5SDimitry Andric auto Modi = Modules.getModuleDescriptor(Index); 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric uint16_t ModiStream = Modi.getModuleStreamIndex(); 421*0b57cec5SDimitry Andric if (ModiStream == kInvalidStreamIndex) 422*0b57cec5SDimitry Andric return make_error<RawError>(raw_error_code::no_stream, 423*0b57cec5SDimitry Andric "Module stream not present"); 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric auto ModStreamData = File.createIndexedStream(ModiStream); 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); 428*0b57cec5SDimitry Andric if (auto EC = ModS.reload()) 429*0b57cec5SDimitry Andric return make_error<RawError>(raw_error_code::corrupt_file, 430*0b57cec5SDimitry Andric "Invalid module stream"); 431*0b57cec5SDimitry Andric 432*0b57cec5SDimitry Andric return std::move(ModS); 433*0b57cec5SDimitry Andric } 434*0b57cec5SDimitry Andric 435*0b57cec5SDimitry Andric template <typename CallbackT> 436*0b57cec5SDimitry Andric static void 437*0b57cec5SDimitry Andric iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope, 438*0b57cec5SDimitry Andric const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) { 439*0b57cec5SDimitry Andric if (HeaderScope) { 440*0b57cec5SDimitry Andric HeaderScope->P.formatLine( 441*0b57cec5SDimitry Andric "Mod {0:4} | `{1}`: ", 442*0b57cec5SDimitry Andric fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name()); 443*0b57cec5SDimitry Andric } 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric AutoIndent Indent(HeaderScope); 446*0b57cec5SDimitry Andric Callback(Modi, SG); 447*0b57cec5SDimitry Andric } 448*0b57cec5SDimitry Andric 449*0b57cec5SDimitry Andric template <typename CallbackT> 450*0b57cec5SDimitry Andric static void iterateSymbolGroups(InputFile &Input, 451*0b57cec5SDimitry Andric const Optional<PrintScope> &HeaderScope, 452*0b57cec5SDimitry Andric CallbackT Callback) { 453*0b57cec5SDimitry Andric AutoIndent Indent(HeaderScope); 454*0b57cec5SDimitry Andric 455*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing modules: "); 456*0b57cec5SDimitry Andric 457*0b57cec5SDimitry Andric if (opts::dump::DumpModi.getNumOccurrences() > 0) { 458*0b57cec5SDimitry Andric assert(opts::dump::DumpModi.getNumOccurrences() == 1); 459*0b57cec5SDimitry Andric uint32_t Modi = opts::dump::DumpModi; 460*0b57cec5SDimitry Andric SymbolGroup SG(&Input, Modi); 461*0b57cec5SDimitry Andric iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG, 462*0b57cec5SDimitry Andric Modi, Callback); 463*0b57cec5SDimitry Andric return; 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric uint32_t I = 0; 467*0b57cec5SDimitry Andric 468*0b57cec5SDimitry Andric for (const auto &SG : Input.symbol_groups()) { 469*0b57cec5SDimitry Andric if (shouldDumpSymbolGroup(I, SG)) 470*0b57cec5SDimitry Andric iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I, 471*0b57cec5SDimitry Andric Callback); 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric ++I; 474*0b57cec5SDimitry Andric } 475*0b57cec5SDimitry Andric } 476*0b57cec5SDimitry Andric 477*0b57cec5SDimitry Andric template <typename SubsectionT> 478*0b57cec5SDimitry Andric static void iterateModuleSubsections( 479*0b57cec5SDimitry Andric InputFile &File, const Optional<PrintScope> &HeaderScope, 480*0b57cec5SDimitry Andric llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)> 481*0b57cec5SDimitry Andric Callback) { 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric iterateSymbolGroups(File, HeaderScope, 484*0b57cec5SDimitry Andric [&](uint32_t Modi, const SymbolGroup &SG) { 485*0b57cec5SDimitry Andric for (const auto &SS : SG.getDebugSubsections()) { 486*0b57cec5SDimitry Andric SubsectionT Subsection; 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric if (SS.kind() != Subsection.kind()) 489*0b57cec5SDimitry Andric continue; 490*0b57cec5SDimitry Andric 491*0b57cec5SDimitry Andric BinaryStreamReader Reader(SS.getRecordData()); 492*0b57cec5SDimitry Andric if (auto EC = Subsection.initialize(Reader)) 493*0b57cec5SDimitry Andric continue; 494*0b57cec5SDimitry Andric Callback(Modi, SG, Subsection); 495*0b57cec5SDimitry Andric } 496*0b57cec5SDimitry Andric }); 497*0b57cec5SDimitry Andric } 498*0b57cec5SDimitry Andric 499*0b57cec5SDimitry Andric static Expected<std::pair<std::unique_ptr<MappedBlockStream>, 500*0b57cec5SDimitry Andric ArrayRef<llvm::object::coff_section>>> 501*0b57cec5SDimitry Andric loadSectionHeaders(PDBFile &File, DbgHeaderType Type) { 502*0b57cec5SDimitry Andric if (!File.hasPDBDbiStream()) 503*0b57cec5SDimitry Andric return make_error<StringError>( 504*0b57cec5SDimitry Andric "Section headers require a DBI Stream, which could not be loaded", 505*0b57cec5SDimitry Andric inconvertibleErrorCode()); 506*0b57cec5SDimitry Andric 507*0b57cec5SDimitry Andric auto &Dbi = cantFail(File.getPDBDbiStream()); 508*0b57cec5SDimitry Andric uint32_t SI = Dbi.getDebugStreamIndex(Type); 509*0b57cec5SDimitry Andric 510*0b57cec5SDimitry Andric if (SI == kInvalidStreamIndex) 511*0b57cec5SDimitry Andric return make_error<StringError>( 512*0b57cec5SDimitry Andric "PDB does not contain the requested image section header type", 513*0b57cec5SDimitry Andric inconvertibleErrorCode()); 514*0b57cec5SDimitry Andric 515*0b57cec5SDimitry Andric auto Stream = File.createIndexedStream(SI); 516*0b57cec5SDimitry Andric if (!Stream) 517*0b57cec5SDimitry Andric return make_error<StringError>("Could not load the required stream data", 518*0b57cec5SDimitry Andric inconvertibleErrorCode()); 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric ArrayRef<object::coff_section> Headers; 521*0b57cec5SDimitry Andric if (Stream->getLength() % sizeof(object::coff_section) != 0) 522*0b57cec5SDimitry Andric return make_error<StringError>( 523*0b57cec5SDimitry Andric "Section header array size is not a multiple of section header size", 524*0b57cec5SDimitry Andric inconvertibleErrorCode()); 525*0b57cec5SDimitry Andric 526*0b57cec5SDimitry Andric uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section); 527*0b57cec5SDimitry Andric BinaryStreamReader Reader(*Stream); 528*0b57cec5SDimitry Andric cantFail(Reader.readArray(Headers, NumHeaders)); 529*0b57cec5SDimitry Andric return std::make_pair(std::move(Stream), Headers); 530*0b57cec5SDimitry Andric } 531*0b57cec5SDimitry Andric 532*0b57cec5SDimitry Andric static std::vector<std::string> getSectionNames(PDBFile &File) { 533*0b57cec5SDimitry Andric auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr); 534*0b57cec5SDimitry Andric if (!ExpectedHeaders) 535*0b57cec5SDimitry Andric return {}; 536*0b57cec5SDimitry Andric 537*0b57cec5SDimitry Andric std::unique_ptr<MappedBlockStream> Stream; 538*0b57cec5SDimitry Andric ArrayRef<object::coff_section> Headers; 539*0b57cec5SDimitry Andric std::tie(Stream, Headers) = std::move(*ExpectedHeaders); 540*0b57cec5SDimitry Andric std::vector<std::string> Names; 541*0b57cec5SDimitry Andric for (const auto &H : Headers) 542*0b57cec5SDimitry Andric Names.push_back(H.Name); 543*0b57cec5SDimitry Andric return Names; 544*0b57cec5SDimitry Andric } 545*0b57cec5SDimitry Andric 546*0b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC, 547*0b57cec5SDimitry Andric ArrayRef<std::string> SectionNames, 548*0b57cec5SDimitry Andric uint32_t FieldWidth) { 549*0b57cec5SDimitry Andric std::string NameInsert; 550*0b57cec5SDimitry Andric if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) { 551*0b57cec5SDimitry Andric StringRef SectionName = SectionNames[SC.ISect - 1]; 552*0b57cec5SDimitry Andric NameInsert = formatv("[{0}]", SectionName).str(); 553*0b57cec5SDimitry Andric } else 554*0b57cec5SDimitry Andric NameInsert = "[???]"; 555*0b57cec5SDimitry Andric P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 556*0b57cec5SDimitry Andric "crc = {4}", 557*0b57cec5SDimitry Andric formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), 558*0b57cec5SDimitry Andric fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc), 559*0b57cec5SDimitry Andric fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2)); 560*0b57cec5SDimitry Andric AutoIndent Indent(P, FieldWidth + 2); 561*0b57cec5SDimitry Andric P.formatLine(" {0}", 562*0b57cec5SDimitry Andric formatSectionCharacteristics(P.getIndentLevel() + 6, 563*0b57cec5SDimitry Andric SC.Characteristics, 3, " | ")); 564*0b57cec5SDimitry Andric } 565*0b57cec5SDimitry Andric 566*0b57cec5SDimitry Andric static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC, 567*0b57cec5SDimitry Andric ArrayRef<std::string> SectionNames, 568*0b57cec5SDimitry Andric uint32_t FieldWidth) { 569*0b57cec5SDimitry Andric P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc " 570*0b57cec5SDimitry Andric "crc = {4}, coff section = {5}", 571*0b57cec5SDimitry Andric formatSegmentOffset(SC.Base.ISect, SC.Base.Off), 572*0b57cec5SDimitry Andric fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), 573*0b57cec5SDimitry Andric fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff)); 574*0b57cec5SDimitry Andric P.formatLine(" {0}", 575*0b57cec5SDimitry Andric formatSectionCharacteristics(P.getIndentLevel() + 6, 576*0b57cec5SDimitry Andric SC.Base.Characteristics, 3, " | ")); 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric 579*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpModules() { 580*0b57cec5SDimitry Andric printHeader(P, "Modules"); 581*0b57cec5SDimitry Andric 582*0b57cec5SDimitry Andric if (File.isObj()) { 583*0b57cec5SDimitry Andric printStreamNotValidForObj(); 584*0b57cec5SDimitry Andric return Error::success(); 585*0b57cec5SDimitry Andric } 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 588*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 589*0b57cec5SDimitry Andric return Error::success(); 590*0b57cec5SDimitry Andric } 591*0b57cec5SDimitry Andric 592*0b57cec5SDimitry Andric AutoIndent Indent(P); 593*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing modules: "); 594*0b57cec5SDimitry Andric 595*0b57cec5SDimitry Andric auto &Stream = Err(getPdb().getPDBDbiStream()); 596*0b57cec5SDimitry Andric 597*0b57cec5SDimitry Andric const DbiModuleList &Modules = Stream.modules(); 598*0b57cec5SDimitry Andric iterateSymbolGroups( 599*0b57cec5SDimitry Andric File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) { 600*0b57cec5SDimitry Andric auto Desc = Modules.getModuleDescriptor(Modi); 601*0b57cec5SDimitry Andric if (opts::dump::DumpSectionContribs) { 602*0b57cec5SDimitry Andric std::vector<std::string> Sections = getSectionNames(getPdb()); 603*0b57cec5SDimitry Andric dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0); 604*0b57cec5SDimitry Andric } 605*0b57cec5SDimitry Andric P.formatLine("Obj: `{0}`: ", Desc.getObjFileName()); 606*0b57cec5SDimitry Andric P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}", 607*0b57cec5SDimitry Andric Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(), 608*0b57cec5SDimitry Andric Desc.hasECInfo()); 609*0b57cec5SDimitry Andric StringRef PdbFilePath = 610*0b57cec5SDimitry Andric Err(Stream.getECName(Desc.getPdbFilePathNameIndex())); 611*0b57cec5SDimitry Andric StringRef SrcFilePath = 612*0b57cec5SDimitry Andric Err(Stream.getECName(Desc.getSourceFileNameIndex())); 613*0b57cec5SDimitry Andric P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`", 614*0b57cec5SDimitry Andric Desc.getPdbFilePathNameIndex(), PdbFilePath, 615*0b57cec5SDimitry Andric Desc.getSourceFileNameIndex(), SrcFilePath); 616*0b57cec5SDimitry Andric }); 617*0b57cec5SDimitry Andric return Error::success(); 618*0b57cec5SDimitry Andric } 619*0b57cec5SDimitry Andric 620*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleFiles() { 621*0b57cec5SDimitry Andric printHeader(P, "Files"); 622*0b57cec5SDimitry Andric 623*0b57cec5SDimitry Andric if (File.isObj()) { 624*0b57cec5SDimitry Andric printStreamNotValidForObj(); 625*0b57cec5SDimitry Andric return Error::success(); 626*0b57cec5SDimitry Andric } 627*0b57cec5SDimitry Andric 628*0b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 629*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 630*0b57cec5SDimitry Andric return Error::success(); 631*0b57cec5SDimitry Andric } 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing modules: "); 634*0b57cec5SDimitry Andric 635*0b57cec5SDimitry Andric iterateSymbolGroups(File, PrintScope{P, 11}, 636*0b57cec5SDimitry Andric [this, &Err](uint32_t Modi, const SymbolGroup &Strings) { 637*0b57cec5SDimitry Andric auto &Stream = Err(getPdb().getPDBDbiStream()); 638*0b57cec5SDimitry Andric 639*0b57cec5SDimitry Andric const DbiModuleList &Modules = Stream.modules(); 640*0b57cec5SDimitry Andric for (const auto &F : Modules.source_files(Modi)) { 641*0b57cec5SDimitry Andric Strings.formatFromFileName(P, F); 642*0b57cec5SDimitry Andric } 643*0b57cec5SDimitry Andric }); 644*0b57cec5SDimitry Andric return Error::success(); 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric 647*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpSymbolStats() { 648*0b57cec5SDimitry Andric printHeader(P, "Module Stats"); 649*0b57cec5SDimitry Andric 650*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 651*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 652*0b57cec5SDimitry Andric return Error::success(); 653*0b57cec5SDimitry Andric } 654*0b57cec5SDimitry Andric 655*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing modules: "); 656*0b57cec5SDimitry Andric 657*0b57cec5SDimitry Andric StatCollection SymStats; 658*0b57cec5SDimitry Andric StatCollection ChunkStats; 659*0b57cec5SDimitry Andric 660*0b57cec5SDimitry Andric Optional<PrintScope> Scope; 661*0b57cec5SDimitry Andric if (File.isPdb()) 662*0b57cec5SDimitry Andric Scope.emplace(P, 2); 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) { 665*0b57cec5SDimitry Andric StatCollection SS = getSymbolStats(SG, SymStats); 666*0b57cec5SDimitry Andric StatCollection CS = getChunkStats(SG, ChunkStats); 667*0b57cec5SDimitry Andric 668*0b57cec5SDimitry Andric if (SG.getFile().isPdb()) { 669*0b57cec5SDimitry Andric AutoIndent Indent(P); 670*0b57cec5SDimitry Andric auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules(); 671*0b57cec5SDimitry Andric uint32_t ModCount = Modules.getModuleCount(); 672*0b57cec5SDimitry Andric DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi); 673*0b57cec5SDimitry Andric uint32_t StreamIdx = Desc.getModuleStreamIndex(); 674*0b57cec5SDimitry Andric 675*0b57cec5SDimitry Andric if (StreamIdx == kInvalidStreamIndex) { 676*0b57cec5SDimitry Andric P.formatLine("Mod {0} (debug info not present): [{1}]", 677*0b57cec5SDimitry Andric fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)), 678*0b57cec5SDimitry Andric Desc.getModuleName()); 679*0b57cec5SDimitry Andric return; 680*0b57cec5SDimitry Andric } 681*0b57cec5SDimitry Andric P.formatLine("Stream {0}, {1} bytes", StreamIdx, 682*0b57cec5SDimitry Andric getPdb().getStreamByteSize(StreamIdx)); 683*0b57cec5SDimitry Andric 684*0b57cec5SDimitry Andric printModuleDetailStats<SymbolKind>(P, "Symbols", SS); 685*0b57cec5SDimitry Andric printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS); 686*0b57cec5SDimitry Andric } 687*0b57cec5SDimitry Andric }); 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric if (SymStats.Totals.Count > 0) { 690*0b57cec5SDimitry Andric P.printLine(" Summary |"); 691*0b57cec5SDimitry Andric AutoIndent Indent(P, 4); 692*0b57cec5SDimitry Andric printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats); 693*0b57cec5SDimitry Andric printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats); 694*0b57cec5SDimitry Andric } 695*0b57cec5SDimitry Andric 696*0b57cec5SDimitry Andric return Error::success(); 697*0b57cec5SDimitry Andric } 698*0b57cec5SDimitry Andric 699*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypeStats() { 700*0b57cec5SDimitry Andric printHeader(P, "Type Record Stats"); 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric // Iterate the types, categorize by kind, accumulate size stats. 703*0b57cec5SDimitry Andric StatCollection TypeStats; 704*0b57cec5SDimitry Andric LazyRandomTypeCollection &Types = File.types(); 705*0b57cec5SDimitry Andric for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { 706*0b57cec5SDimitry Andric CVType Type = Types.getType(*TI); 707*0b57cec5SDimitry Andric TypeStats.update(uint32_t(Type.kind()), Type.length()); 708*0b57cec5SDimitry Andric } 709*0b57cec5SDimitry Andric 710*0b57cec5SDimitry Andric P.NewLine(); 711*0b57cec5SDimitry Andric P.formatLine(" Types"); 712*0b57cec5SDimitry Andric AutoIndent Indent(P); 713*0b57cec5SDimitry Andric P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total", 714*0b57cec5SDimitry Andric TypeStats.Totals.Count, TypeStats.Totals.Size, 715*0b57cec5SDimitry Andric (double)TypeStats.Totals.Size / TypeStats.Totals.Count); 716*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', 74)); 717*0b57cec5SDimitry Andric 718*0b57cec5SDimitry Andric for (const auto &K : TypeStats.getStatsSortedBySize()) { 719*0b57cec5SDimitry Andric P.formatLine("{0,14}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", 720*0b57cec5SDimitry Andric formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count, 721*0b57cec5SDimitry Andric K.second.Size, (double)K.second.Size / K.second.Count); 722*0b57cec5SDimitry Andric } 723*0b57cec5SDimitry Andric 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric return Error::success(); 726*0b57cec5SDimitry Andric } 727*0b57cec5SDimitry Andric 728*0b57cec5SDimitry Andric static bool isValidNamespaceIdentifier(StringRef S) { 729*0b57cec5SDimitry Andric if (S.empty()) 730*0b57cec5SDimitry Andric return false; 731*0b57cec5SDimitry Andric 732*0b57cec5SDimitry Andric if (std::isdigit(S[0])) 733*0b57cec5SDimitry Andric return false; 734*0b57cec5SDimitry Andric 735*0b57cec5SDimitry Andric return llvm::all_of(S, [](char C) { return std::isalnum(C); }); 736*0b57cec5SDimitry Andric } 737*0b57cec5SDimitry Andric 738*0b57cec5SDimitry Andric namespace { 739*0b57cec5SDimitry Andric constexpr uint32_t kNoneUdtKind = 0; 740*0b57cec5SDimitry Andric constexpr uint32_t kSimpleUdtKind = 1; 741*0b57cec5SDimitry Andric constexpr uint32_t kUnknownUdtKind = 2; 742*0b57cec5SDimitry Andric const StringRef NoneLabel("<none type>"); 743*0b57cec5SDimitry Andric const StringRef SimpleLabel("<simple type>"); 744*0b57cec5SDimitry Andric const StringRef UnknownLabel("<unknown type>"); 745*0b57cec5SDimitry Andric 746*0b57cec5SDimitry Andric } // namespace 747*0b57cec5SDimitry Andric 748*0b57cec5SDimitry Andric static StringRef getUdtStatLabel(uint32_t Kind) { 749*0b57cec5SDimitry Andric if (Kind == kNoneUdtKind) 750*0b57cec5SDimitry Andric return NoneLabel; 751*0b57cec5SDimitry Andric 752*0b57cec5SDimitry Andric if (Kind == kSimpleUdtKind) 753*0b57cec5SDimitry Andric return SimpleLabel; 754*0b57cec5SDimitry Andric 755*0b57cec5SDimitry Andric if (Kind == kUnknownUdtKind) 756*0b57cec5SDimitry Andric return UnknownLabel; 757*0b57cec5SDimitry Andric 758*0b57cec5SDimitry Andric return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind)); 759*0b57cec5SDimitry Andric } 760*0b57cec5SDimitry Andric 761*0b57cec5SDimitry Andric static uint32_t getLongestTypeLeafName(const StatCollection &Stats) { 762*0b57cec5SDimitry Andric size_t L = 0; 763*0b57cec5SDimitry Andric for (const auto &Stat : Stats.Individual) { 764*0b57cec5SDimitry Andric StringRef Label = getUdtStatLabel(Stat.first); 765*0b57cec5SDimitry Andric L = std::max(L, Label.size()); 766*0b57cec5SDimitry Andric } 767*0b57cec5SDimitry Andric return static_cast<uint32_t>(L); 768*0b57cec5SDimitry Andric } 769*0b57cec5SDimitry Andric 770*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpUdtStats() { 771*0b57cec5SDimitry Andric printHeader(P, "S_UDT Record Stats"); 772*0b57cec5SDimitry Andric 773*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) { 774*0b57cec5SDimitry Andric printStreamNotPresent("Globals"); 775*0b57cec5SDimitry Andric return Error::success(); 776*0b57cec5SDimitry Andric } 777*0b57cec5SDimitry Andric 778*0b57cec5SDimitry Andric StatCollection UdtStats; 779*0b57cec5SDimitry Andric StatCollection UdtTargetStats; 780*0b57cec5SDimitry Andric AutoIndent Indent(P, 4); 781*0b57cec5SDimitry Andric 782*0b57cec5SDimitry Andric auto &TpiTypes = File.types(); 783*0b57cec5SDimitry Andric 784*0b57cec5SDimitry Andric StringMap<StatCollection::Stat> NamespacedStats; 785*0b57cec5SDimitry Andric 786*0b57cec5SDimitry Andric size_t LongestNamespace = 0; 787*0b57cec5SDimitry Andric auto HandleOneSymbol = [&](const CVSymbol &Sym) { 788*0b57cec5SDimitry Andric if (Sym.kind() != SymbolKind::S_UDT) 789*0b57cec5SDimitry Andric return; 790*0b57cec5SDimitry Andric UdtStats.update(SymbolKind::S_UDT, Sym.length()); 791*0b57cec5SDimitry Andric 792*0b57cec5SDimitry Andric UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym)); 793*0b57cec5SDimitry Andric 794*0b57cec5SDimitry Andric uint32_t Kind = 0; 795*0b57cec5SDimitry Andric uint32_t RecordSize = 0; 796*0b57cec5SDimitry Andric 797*0b57cec5SDimitry Andric if (UDT.Type.isNoneType()) 798*0b57cec5SDimitry Andric Kind = kNoneUdtKind; 799*0b57cec5SDimitry Andric else if (UDT.Type.isSimple()) 800*0b57cec5SDimitry Andric Kind = kSimpleUdtKind; 801*0b57cec5SDimitry Andric else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) { 802*0b57cec5SDimitry Andric Kind = T->kind(); 803*0b57cec5SDimitry Andric RecordSize = T->length(); 804*0b57cec5SDimitry Andric } else 805*0b57cec5SDimitry Andric Kind = kUnknownUdtKind; 806*0b57cec5SDimitry Andric 807*0b57cec5SDimitry Andric UdtTargetStats.update(Kind, RecordSize); 808*0b57cec5SDimitry Andric 809*0b57cec5SDimitry Andric size_t Pos = UDT.Name.find("::"); 810*0b57cec5SDimitry Andric if (Pos == StringRef::npos) 811*0b57cec5SDimitry Andric return; 812*0b57cec5SDimitry Andric 813*0b57cec5SDimitry Andric StringRef Scope = UDT.Name.take_front(Pos); 814*0b57cec5SDimitry Andric if (Scope.empty() || !isValidNamespaceIdentifier(Scope)) 815*0b57cec5SDimitry Andric return; 816*0b57cec5SDimitry Andric 817*0b57cec5SDimitry Andric LongestNamespace = std::max(LongestNamespace, Scope.size()); 818*0b57cec5SDimitry Andric NamespacedStats[Scope].update(RecordSize); 819*0b57cec5SDimitry Andric }; 820*0b57cec5SDimitry Andric 821*0b57cec5SDimitry Andric P.NewLine(); 822*0b57cec5SDimitry Andric 823*0b57cec5SDimitry Andric if (File.isPdb()) { 824*0b57cec5SDimitry Andric auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream()); 825*0b57cec5SDimitry Andric auto ExpGlobals = getPdb().getPDBGlobalsStream(); 826*0b57cec5SDimitry Andric if (!ExpGlobals) 827*0b57cec5SDimitry Andric return ExpGlobals.takeError(); 828*0b57cec5SDimitry Andric 829*0b57cec5SDimitry Andric for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) { 830*0b57cec5SDimitry Andric CVSymbol Sym = SymbolRecords.readRecord(PubSymOff); 831*0b57cec5SDimitry Andric HandleOneSymbol(Sym); 832*0b57cec5SDimitry Andric } 833*0b57cec5SDimitry Andric } else { 834*0b57cec5SDimitry Andric for (const auto &Sec : File.symbol_groups()) { 835*0b57cec5SDimitry Andric for (const auto &SS : Sec.getDebugSubsections()) { 836*0b57cec5SDimitry Andric if (SS.kind() != DebugSubsectionKind::Symbols) 837*0b57cec5SDimitry Andric continue; 838*0b57cec5SDimitry Andric 839*0b57cec5SDimitry Andric DebugSymbolsSubsectionRef Symbols; 840*0b57cec5SDimitry Andric BinaryStreamReader Reader(SS.getRecordData()); 841*0b57cec5SDimitry Andric cantFail(Symbols.initialize(Reader)); 842*0b57cec5SDimitry Andric for (const auto &S : Symbols) 843*0b57cec5SDimitry Andric HandleOneSymbol(S); 844*0b57cec5SDimitry Andric } 845*0b57cec5SDimitry Andric } 846*0b57cec5SDimitry Andric } 847*0b57cec5SDimitry Andric 848*0b57cec5SDimitry Andric LongestNamespace += StringRef(" namespace ''").size(); 849*0b57cec5SDimitry Andric size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats); 850*0b57cec5SDimitry Andric size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind); 851*0b57cec5SDimitry Andric 852*0b57cec5SDimitry Andric // Compute the max number of digits for count and size fields, including comma 853*0b57cec5SDimitry Andric // separators. 854*0b57cec5SDimitry Andric StringRef CountHeader("Count"); 855*0b57cec5SDimitry Andric StringRef SizeHeader("Size"); 856*0b57cec5SDimitry Andric size_t CD = NumDigits(UdtStats.Totals.Count); 857*0b57cec5SDimitry Andric CD += (CD - 1) / 3; 858*0b57cec5SDimitry Andric CD = std::max(CD, CountHeader.size()); 859*0b57cec5SDimitry Andric 860*0b57cec5SDimitry Andric size_t SD = NumDigits(UdtStats.Totals.Size); 861*0b57cec5SDimitry Andric SD += (SD - 1) / 3; 862*0b57cec5SDimitry Andric SD = std::max(SD, SizeHeader.size()); 863*0b57cec5SDimitry Andric 864*0b57cec5SDimitry Andric uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1; 865*0b57cec5SDimitry Andric 866*0b57cec5SDimitry Andric P.formatLine("{0} | {1} {2}", 867*0b57cec5SDimitry Andric fmt_align("Record Kind", AlignStyle::Right, FieldWidth), 868*0b57cec5SDimitry Andric fmt_align(CountHeader, AlignStyle::Right, CD), 869*0b57cec5SDimitry Andric fmt_align(SizeHeader, AlignStyle::Right, SD)); 870*0b57cec5SDimitry Andric 871*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 872*0b57cec5SDimitry Andric for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) { 873*0b57cec5SDimitry Andric StringRef Label = getUdtStatLabel(Stat.first); 874*0b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 875*0b57cec5SDimitry Andric fmt_align(Label, AlignStyle::Right, FieldWidth), 876*0b57cec5SDimitry Andric fmt_align(Stat.second.Count, AlignStyle::Right, CD), 877*0b57cec5SDimitry Andric fmt_align(Stat.second.Size, AlignStyle::Right, SD)); 878*0b57cec5SDimitry Andric } 879*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 880*0b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 881*0b57cec5SDimitry Andric fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth), 882*0b57cec5SDimitry Andric fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD), 883*0b57cec5SDimitry Andric fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD)); 884*0b57cec5SDimitry Andric P.formatLine("{0}", fmt_repeat('-', TableWidth)); 885*0b57cec5SDimitry Andric struct StrAndStat { 886*0b57cec5SDimitry Andric StringRef Key; 887*0b57cec5SDimitry Andric StatCollection::Stat Stat; 888*0b57cec5SDimitry Andric }; 889*0b57cec5SDimitry Andric 890*0b57cec5SDimitry Andric // Print namespace stats in descending order of size. 891*0b57cec5SDimitry Andric std::vector<StrAndStat> NamespacedStatsSorted; 892*0b57cec5SDimitry Andric for (const auto &Stat : NamespacedStats) 893*0b57cec5SDimitry Andric NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second}); 894*0b57cec5SDimitry Andric llvm::stable_sort(NamespacedStatsSorted, 895*0b57cec5SDimitry Andric [](const StrAndStat &L, const StrAndStat &R) { 896*0b57cec5SDimitry Andric return L.Stat.Size > R.Stat.Size; 897*0b57cec5SDimitry Andric }); 898*0b57cec5SDimitry Andric for (const auto &Stat : NamespacedStatsSorted) { 899*0b57cec5SDimitry Andric std::string Label = formatv("namespace '{0}'", Stat.Key); 900*0b57cec5SDimitry Andric P.formatLine("{0} | {1:N} {2:N}", 901*0b57cec5SDimitry Andric fmt_align(Label, AlignStyle::Right, FieldWidth), 902*0b57cec5SDimitry Andric fmt_align(Stat.Stat.Count, AlignStyle::Right, CD), 903*0b57cec5SDimitry Andric fmt_align(Stat.Stat.Size, AlignStyle::Right, SD)); 904*0b57cec5SDimitry Andric } 905*0b57cec5SDimitry Andric return Error::success(); 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start, 909*0b57cec5SDimitry Andric const LineColumnEntry &E) { 910*0b57cec5SDimitry Andric const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number 911*0b57cec5SDimitry Andric uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5; 912*0b57cec5SDimitry Andric 913*0b57cec5SDimitry Andric // Let's try to keep it under 100 characters 914*0b57cec5SDimitry Andric constexpr uint32_t kMaxRowLength = 100; 915*0b57cec5SDimitry Andric // At least 3 spaces between columns. 916*0b57cec5SDimitry Andric uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3); 917*0b57cec5SDimitry Andric uint32_t ItemsLeft = E.LineNumbers.size(); 918*0b57cec5SDimitry Andric auto LineIter = E.LineNumbers.begin(); 919*0b57cec5SDimitry Andric while (ItemsLeft != 0) { 920*0b57cec5SDimitry Andric uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow); 921*0b57cec5SDimitry Andric for (uint32_t I = 0; I < RowColumns; ++I) { 922*0b57cec5SDimitry Andric LineInfo Line(LineIter->Flags); 923*0b57cec5SDimitry Andric std::string LineStr; 924*0b57cec5SDimitry Andric if (Line.isAlwaysStepInto()) 925*0b57cec5SDimitry Andric LineStr = "ASI"; 926*0b57cec5SDimitry Andric else if (Line.isNeverStepInto()) 927*0b57cec5SDimitry Andric LineStr = "NSI"; 928*0b57cec5SDimitry Andric else 929*0b57cec5SDimitry Andric LineStr = utostr(Line.getStartLine()); 930*0b57cec5SDimitry Andric char Statement = Line.isStatement() ? ' ' : '!'; 931*0b57cec5SDimitry Andric P.format("{0} {1:X-} {2} ", 932*0b57cec5SDimitry Andric fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber), 933*0b57cec5SDimitry Andric fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'), 934*0b57cec5SDimitry Andric Statement); 935*0b57cec5SDimitry Andric ++LineIter; 936*0b57cec5SDimitry Andric --ItemsLeft; 937*0b57cec5SDimitry Andric } 938*0b57cec5SDimitry Andric P.NewLine(); 939*0b57cec5SDimitry Andric } 940*0b57cec5SDimitry Andric } 941*0b57cec5SDimitry Andric 942*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpLines() { 943*0b57cec5SDimitry Andric printHeader(P, "Lines"); 944*0b57cec5SDimitry Andric 945*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 946*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 947*0b57cec5SDimitry Andric return Error::success(); 948*0b57cec5SDimitry Andric } 949*0b57cec5SDimitry Andric 950*0b57cec5SDimitry Andric uint32_t LastModi = UINT32_MAX; 951*0b57cec5SDimitry Andric uint32_t LastNameIndex = UINT32_MAX; 952*0b57cec5SDimitry Andric iterateModuleSubsections<DebugLinesSubsectionRef>( 953*0b57cec5SDimitry Andric File, PrintScope{P, 4}, 954*0b57cec5SDimitry Andric [this, &LastModi, &LastNameIndex](uint32_t Modi, 955*0b57cec5SDimitry Andric const SymbolGroup &Strings, 956*0b57cec5SDimitry Andric DebugLinesSubsectionRef &Lines) { 957*0b57cec5SDimitry Andric uint16_t Segment = Lines.header()->RelocSegment; 958*0b57cec5SDimitry Andric uint32_t Begin = Lines.header()->RelocOffset; 959*0b57cec5SDimitry Andric uint32_t End = Begin + Lines.header()->CodeSize; 960*0b57cec5SDimitry Andric for (const auto &Block : Lines) { 961*0b57cec5SDimitry Andric if (LastModi != Modi || LastNameIndex != Block.NameIndex) { 962*0b57cec5SDimitry Andric LastModi = Modi; 963*0b57cec5SDimitry Andric LastNameIndex = Block.NameIndex; 964*0b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, Block.NameIndex); 965*0b57cec5SDimitry Andric } 966*0b57cec5SDimitry Andric 967*0b57cec5SDimitry Andric AutoIndent Indent(P, 2); 968*0b57cec5SDimitry Andric P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End); 969*0b57cec5SDimitry Andric uint32_t Count = Block.LineNumbers.size(); 970*0b57cec5SDimitry Andric if (Lines.hasColumnInfo()) 971*0b57cec5SDimitry Andric P.format("line/column/addr entries = {0}", Count); 972*0b57cec5SDimitry Andric else 973*0b57cec5SDimitry Andric P.format("line/addr entries = {0}", Count); 974*0b57cec5SDimitry Andric 975*0b57cec5SDimitry Andric P.NewLine(); 976*0b57cec5SDimitry Andric typesetLinesAndColumns(P, Begin, Block); 977*0b57cec5SDimitry Andric } 978*0b57cec5SDimitry Andric }); 979*0b57cec5SDimitry Andric 980*0b57cec5SDimitry Andric return Error::success(); 981*0b57cec5SDimitry Andric } 982*0b57cec5SDimitry Andric 983*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpInlineeLines() { 984*0b57cec5SDimitry Andric printHeader(P, "Inlinee Lines"); 985*0b57cec5SDimitry Andric 986*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 987*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 988*0b57cec5SDimitry Andric return Error::success(); 989*0b57cec5SDimitry Andric } 990*0b57cec5SDimitry Andric 991*0b57cec5SDimitry Andric iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( 992*0b57cec5SDimitry Andric File, PrintScope{P, 2}, 993*0b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 994*0b57cec5SDimitry Andric DebugInlineeLinesSubsectionRef &Lines) { 995*0b57cec5SDimitry Andric P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File"); 996*0b57cec5SDimitry Andric for (const auto &Entry : Lines) { 997*0b57cec5SDimitry Andric P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee, 998*0b57cec5SDimitry Andric fmtle(Entry.Header->SourceLineNum)); 999*0b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true); 1000*0b57cec5SDimitry Andric for (const auto &ExtraFileID : Entry.ExtraFiles) { 1001*0b57cec5SDimitry Andric P.formatLine(" "); 1002*0b57cec5SDimitry Andric Strings.formatFromChecksumsOffset(P, ExtraFileID, true); 1003*0b57cec5SDimitry Andric } 1004*0b57cec5SDimitry Andric } 1005*0b57cec5SDimitry Andric P.NewLine(); 1006*0b57cec5SDimitry Andric }); 1007*0b57cec5SDimitry Andric 1008*0b57cec5SDimitry Andric return Error::success(); 1009*0b57cec5SDimitry Andric } 1010*0b57cec5SDimitry Andric 1011*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpXmi() { 1012*0b57cec5SDimitry Andric printHeader(P, "Cross Module Imports"); 1013*0b57cec5SDimitry Andric 1014*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 1015*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1016*0b57cec5SDimitry Andric return Error::success(); 1017*0b57cec5SDimitry Andric } 1018*0b57cec5SDimitry Andric 1019*0b57cec5SDimitry Andric iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>( 1020*0b57cec5SDimitry Andric File, PrintScope{P, 2}, 1021*0b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 1022*0b57cec5SDimitry Andric DebugCrossModuleImportsSubsectionRef &Imports) { 1023*0b57cec5SDimitry Andric P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs"); 1024*0b57cec5SDimitry Andric 1025*0b57cec5SDimitry Andric for (const auto &Xmi : Imports) { 1026*0b57cec5SDimitry Andric auto ExpectedModule = 1027*0b57cec5SDimitry Andric Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset); 1028*0b57cec5SDimitry Andric StringRef Module; 1029*0b57cec5SDimitry Andric SmallString<32> ModuleStorage; 1030*0b57cec5SDimitry Andric if (!ExpectedModule) { 1031*0b57cec5SDimitry Andric Module = "(unknown module)"; 1032*0b57cec5SDimitry Andric consumeError(ExpectedModule.takeError()); 1033*0b57cec5SDimitry Andric } else 1034*0b57cec5SDimitry Andric Module = *ExpectedModule; 1035*0b57cec5SDimitry Andric if (Module.size() > 32) { 1036*0b57cec5SDimitry Andric ModuleStorage = "..."; 1037*0b57cec5SDimitry Andric ModuleStorage += Module.take_back(32 - 3); 1038*0b57cec5SDimitry Andric Module = ModuleStorage; 1039*0b57cec5SDimitry Andric } 1040*0b57cec5SDimitry Andric std::vector<std::string> TIs; 1041*0b57cec5SDimitry Andric for (const auto I : Xmi.Imports) 1042*0b57cec5SDimitry Andric TIs.push_back(formatv("{0,+10:X+}", fmtle(I))); 1043*0b57cec5SDimitry Andric std::string Result = 1044*0b57cec5SDimitry Andric typesetItemList(TIs, P.getIndentLevel() + 35, 12, " "); 1045*0b57cec5SDimitry Andric P.formatLine("{0,+32} | {1}", Module, Result); 1046*0b57cec5SDimitry Andric } 1047*0b57cec5SDimitry Andric }); 1048*0b57cec5SDimitry Andric 1049*0b57cec5SDimitry Andric return Error::success(); 1050*0b57cec5SDimitry Andric } 1051*0b57cec5SDimitry Andric 1052*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpXme() { 1053*0b57cec5SDimitry Andric printHeader(P, "Cross Module Exports"); 1054*0b57cec5SDimitry Andric 1055*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 1056*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1057*0b57cec5SDimitry Andric return Error::success(); 1058*0b57cec5SDimitry Andric } 1059*0b57cec5SDimitry Andric 1060*0b57cec5SDimitry Andric iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>( 1061*0b57cec5SDimitry Andric File, PrintScope{P, 2}, 1062*0b57cec5SDimitry Andric [this](uint32_t Modi, const SymbolGroup &Strings, 1063*0b57cec5SDimitry Andric DebugCrossModuleExportsSubsectionRef &Exports) { 1064*0b57cec5SDimitry Andric P.formatLine("{0,-10} | {1}", "Local ID", "Global ID"); 1065*0b57cec5SDimitry Andric for (const auto &Export : Exports) { 1066*0b57cec5SDimitry Andric P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local), 1067*0b57cec5SDimitry Andric TypeIndex(Export.Global)); 1068*0b57cec5SDimitry Andric } 1069*0b57cec5SDimitry Andric }); 1070*0b57cec5SDimitry Andric 1071*0b57cec5SDimitry Andric return Error::success(); 1072*0b57cec5SDimitry Andric } 1073*0b57cec5SDimitry Andric 1074*0b57cec5SDimitry Andric std::string formatFrameType(object::frame_type FT) { 1075*0b57cec5SDimitry Andric switch (FT) { 1076*0b57cec5SDimitry Andric case object::frame_type::Fpo: 1077*0b57cec5SDimitry Andric return "FPO"; 1078*0b57cec5SDimitry Andric case object::frame_type::NonFpo: 1079*0b57cec5SDimitry Andric return "Non-FPO"; 1080*0b57cec5SDimitry Andric case object::frame_type::Trap: 1081*0b57cec5SDimitry Andric return "Trap"; 1082*0b57cec5SDimitry Andric case object::frame_type::Tss: 1083*0b57cec5SDimitry Andric return "TSS"; 1084*0b57cec5SDimitry Andric } 1085*0b57cec5SDimitry Andric return "<unknown>"; 1086*0b57cec5SDimitry Andric } 1087*0b57cec5SDimitry Andric 1088*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpOldFpo(PDBFile &File) { 1089*0b57cec5SDimitry Andric printHeader(P, "Old FPO Data"); 1090*0b57cec5SDimitry Andric 1091*0b57cec5SDimitry Andric ExitOnError Err("Error dumping old fpo data:"); 1092*0b57cec5SDimitry Andric auto &Dbi = Err(File.getPDBDbiStream()); 1093*0b57cec5SDimitry Andric 1094*0b57cec5SDimitry Andric if (!Dbi.hasOldFpoRecords()) { 1095*0b57cec5SDimitry Andric printStreamNotPresent("FPO"); 1096*0b57cec5SDimitry Andric return Error::success(); 1097*0b57cec5SDimitry Andric } 1098*0b57cec5SDimitry Andric 1099*0b57cec5SDimitry Andric const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords(); 1100*0b57cec5SDimitry Andric 1101*0b57cec5SDimitry Andric P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use " 1102*0b57cec5SDimitry Andric "BP | Has SEH | Frame Type"); 1103*0b57cec5SDimitry Andric 1104*0b57cec5SDimitry Andric for (const object::FpoData &FD : Records) { 1105*0b57cec5SDimitry Andric P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | " 1106*0b57cec5SDimitry Andric "{7,7} | {8,9}", 1107*0b57cec5SDimitry Andric uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals), 1108*0b57cec5SDimitry Andric uint32_t(FD.NumParams), FD.getPrologSize(), 1109*0b57cec5SDimitry Andric FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(), 1110*0b57cec5SDimitry Andric formatFrameType(FD.getFP())); 1111*0b57cec5SDimitry Andric } 1112*0b57cec5SDimitry Andric return Error::success(); 1113*0b57cec5SDimitry Andric } 1114*0b57cec5SDimitry Andric 1115*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpNewFpo(PDBFile &File) { 1116*0b57cec5SDimitry Andric printHeader(P, "New FPO Data"); 1117*0b57cec5SDimitry Andric 1118*0b57cec5SDimitry Andric ExitOnError Err("Error dumping new fpo data:"); 1119*0b57cec5SDimitry Andric auto &Dbi = Err(File.getPDBDbiStream()); 1120*0b57cec5SDimitry Andric 1121*0b57cec5SDimitry Andric if (!Dbi.hasNewFpoRecords()) { 1122*0b57cec5SDimitry Andric printStreamNotPresent("New FPO"); 1123*0b57cec5SDimitry Andric return Error::success(); 1124*0b57cec5SDimitry Andric } 1125*0b57cec5SDimitry Andric 1126*0b57cec5SDimitry Andric const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords(); 1127*0b57cec5SDimitry Andric 1128*0b57cec5SDimitry Andric P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs " 1129*0b57cec5SDimitry Andric "| Has SEH | Has C++EH | Start | Program"); 1130*0b57cec5SDimitry Andric for (const FrameData &FD : FDS) { 1131*0b57cec5SDimitry Andric bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart; 1132*0b57cec5SDimitry Andric bool HasEH = FD.Flags & FrameData::HasEH; 1133*0b57cec5SDimitry Andric bool HasSEH = FD.Flags & FrameData::HasSEH; 1134*0b57cec5SDimitry Andric 1135*0b57cec5SDimitry Andric auto &StringTable = Err(File.getStringTable()); 1136*0b57cec5SDimitry Andric 1137*0b57cec5SDimitry Andric auto Program = Err(StringTable.getStringForID(FD.FrameFunc)); 1138*0b57cec5SDimitry Andric P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | " 1139*0b57cec5SDimitry Andric "{7,7} | {8,9} | {9,5} | {10}", 1140*0b57cec5SDimitry Andric uint32_t(FD.RvaStart), uint32_t(FD.CodeSize), 1141*0b57cec5SDimitry Andric uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize), 1142*0b57cec5SDimitry Andric uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize), 1143*0b57cec5SDimitry Andric uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart, 1144*0b57cec5SDimitry Andric Program); 1145*0b57cec5SDimitry Andric } 1146*0b57cec5SDimitry Andric return Error::success(); 1147*0b57cec5SDimitry Andric } 1148*0b57cec5SDimitry Andric 1149*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpFpo() { 1150*0b57cec5SDimitry Andric if (!File.isPdb()) { 1151*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1152*0b57cec5SDimitry Andric return Error::success(); 1153*0b57cec5SDimitry Andric } 1154*0b57cec5SDimitry Andric 1155*0b57cec5SDimitry Andric PDBFile &File = getPdb(); 1156*0b57cec5SDimitry Andric if (!File.hasPDBDbiStream()) { 1157*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1158*0b57cec5SDimitry Andric return Error::success(); 1159*0b57cec5SDimitry Andric } 1160*0b57cec5SDimitry Andric 1161*0b57cec5SDimitry Andric if (auto EC = dumpOldFpo(File)) 1162*0b57cec5SDimitry Andric return EC; 1163*0b57cec5SDimitry Andric if (auto EC = dumpNewFpo(File)) 1164*0b57cec5SDimitry Andric return EC; 1165*0b57cec5SDimitry Andric return Error::success(); 1166*0b57cec5SDimitry Andric } 1167*0b57cec5SDimitry Andric 1168*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTableFromPdb() { 1169*0b57cec5SDimitry Andric AutoIndent Indent(P); 1170*0b57cec5SDimitry Andric auto IS = getPdb().getStringTable(); 1171*0b57cec5SDimitry Andric if (!IS) { 1172*0b57cec5SDimitry Andric P.formatLine("Not present in file"); 1173*0b57cec5SDimitry Andric consumeError(IS.takeError()); 1174*0b57cec5SDimitry Andric return Error::success(); 1175*0b57cec5SDimitry Andric } 1176*0b57cec5SDimitry Andric 1177*0b57cec5SDimitry Andric if (opts::dump::DumpStringTable) { 1178*0b57cec5SDimitry Andric if (IS->name_ids().empty()) 1179*0b57cec5SDimitry Andric P.formatLine("Empty"); 1180*0b57cec5SDimitry Andric else { 1181*0b57cec5SDimitry Andric auto MaxID = 1182*0b57cec5SDimitry Andric std::max_element(IS->name_ids().begin(), IS->name_ids().end()); 1183*0b57cec5SDimitry Andric uint32_t Digits = NumDigits(*MaxID); 1184*0b57cec5SDimitry Andric 1185*0b57cec5SDimitry Andric P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits), 1186*0b57cec5SDimitry Andric "String"); 1187*0b57cec5SDimitry Andric 1188*0b57cec5SDimitry Andric std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), 1189*0b57cec5SDimitry Andric IS->name_ids().end()); 1190*0b57cec5SDimitry Andric llvm::sort(SortedIDs); 1191*0b57cec5SDimitry Andric for (uint32_t I : SortedIDs) { 1192*0b57cec5SDimitry Andric auto ES = IS->getStringForID(I); 1193*0b57cec5SDimitry Andric llvm::SmallString<32> Str; 1194*0b57cec5SDimitry Andric if (!ES) { 1195*0b57cec5SDimitry Andric consumeError(ES.takeError()); 1196*0b57cec5SDimitry Andric Str = "Error reading string"; 1197*0b57cec5SDimitry Andric } else if (!ES->empty()) { 1198*0b57cec5SDimitry Andric Str.append("'"); 1199*0b57cec5SDimitry Andric Str.append(*ES); 1200*0b57cec5SDimitry Andric Str.append("'"); 1201*0b57cec5SDimitry Andric } 1202*0b57cec5SDimitry Andric 1203*0b57cec5SDimitry Andric if (!Str.empty()) 1204*0b57cec5SDimitry Andric P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), 1205*0b57cec5SDimitry Andric Str); 1206*0b57cec5SDimitry Andric } 1207*0b57cec5SDimitry Andric } 1208*0b57cec5SDimitry Andric } 1209*0b57cec5SDimitry Andric 1210*0b57cec5SDimitry Andric if (opts::dump::DumpStringTableDetails) { 1211*0b57cec5SDimitry Andric P.NewLine(); 1212*0b57cec5SDimitry Andric { 1213*0b57cec5SDimitry Andric P.printLine("String Table Header:"); 1214*0b57cec5SDimitry Andric AutoIndent Indent(P); 1215*0b57cec5SDimitry Andric P.formatLine("Signature: {0}", IS->getSignature()); 1216*0b57cec5SDimitry Andric P.formatLine("Hash Version: {0}", IS->getHashVersion()); 1217*0b57cec5SDimitry Andric P.formatLine("Name Buffer Size: {0}", IS->getByteSize()); 1218*0b57cec5SDimitry Andric P.NewLine(); 1219*0b57cec5SDimitry Andric } 1220*0b57cec5SDimitry Andric 1221*0b57cec5SDimitry Andric BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer(); 1222*0b57cec5SDimitry Andric ArrayRef<uint8_t> Contents; 1223*0b57cec5SDimitry Andric cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents)); 1224*0b57cec5SDimitry Andric P.formatBinary("Name Buffer", Contents, 0); 1225*0b57cec5SDimitry Andric P.NewLine(); 1226*0b57cec5SDimitry Andric { 1227*0b57cec5SDimitry Andric P.printLine("Hash Table:"); 1228*0b57cec5SDimitry Andric AutoIndent Indent(P); 1229*0b57cec5SDimitry Andric P.formatLine("Bucket Count: {0}", IS->name_ids().size()); 1230*0b57cec5SDimitry Andric for (const auto &Entry : enumerate(IS->name_ids())) 1231*0b57cec5SDimitry Andric P.formatLine("Bucket[{0}] : {1}", Entry.index(), 1232*0b57cec5SDimitry Andric uint32_t(Entry.value())); 1233*0b57cec5SDimitry Andric P.formatLine("Name Count: {0}", IS->getNameCount()); 1234*0b57cec5SDimitry Andric } 1235*0b57cec5SDimitry Andric } 1236*0b57cec5SDimitry Andric return Error::success(); 1237*0b57cec5SDimitry Andric } 1238*0b57cec5SDimitry Andric 1239*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTableFromObj() { 1240*0b57cec5SDimitry Andric iterateModuleSubsections<DebugStringTableSubsectionRef>( 1241*0b57cec5SDimitry Andric File, PrintScope{P, 4}, 1242*0b57cec5SDimitry Andric [&](uint32_t Modi, const SymbolGroup &Strings, 1243*0b57cec5SDimitry Andric DebugStringTableSubsectionRef &Strings2) { 1244*0b57cec5SDimitry Andric BinaryStreamRef StringTableBuffer = Strings2.getBuffer(); 1245*0b57cec5SDimitry Andric BinaryStreamReader Reader(StringTableBuffer); 1246*0b57cec5SDimitry Andric while (Reader.bytesRemaining() > 0) { 1247*0b57cec5SDimitry Andric StringRef Str; 1248*0b57cec5SDimitry Andric uint32_t Offset = Reader.getOffset(); 1249*0b57cec5SDimitry Andric cantFail(Reader.readCString(Str)); 1250*0b57cec5SDimitry Andric if (Str.empty()) 1251*0b57cec5SDimitry Andric continue; 1252*0b57cec5SDimitry Andric 1253*0b57cec5SDimitry Andric P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4), 1254*0b57cec5SDimitry Andric Str); 1255*0b57cec5SDimitry Andric } 1256*0b57cec5SDimitry Andric }); 1257*0b57cec5SDimitry Andric return Error::success(); 1258*0b57cec5SDimitry Andric } 1259*0b57cec5SDimitry Andric 1260*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpNamedStreams() { 1261*0b57cec5SDimitry Andric printHeader(P, "Named Streams"); 1262*0b57cec5SDimitry Andric 1263*0b57cec5SDimitry Andric if (File.isObj()) { 1264*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1265*0b57cec5SDimitry Andric return Error::success(); 1266*0b57cec5SDimitry Andric } 1267*0b57cec5SDimitry Andric 1268*0b57cec5SDimitry Andric AutoIndent Indent(P); 1269*0b57cec5SDimitry Andric ExitOnError Err("Invalid PDB File: "); 1270*0b57cec5SDimitry Andric 1271*0b57cec5SDimitry Andric auto &IS = Err(File.pdb().getPDBInfoStream()); 1272*0b57cec5SDimitry Andric const NamedStreamMap &NS = IS.getNamedStreams(); 1273*0b57cec5SDimitry Andric for (const auto &Entry : NS.entries()) { 1274*0b57cec5SDimitry Andric P.printLine(Entry.getKey()); 1275*0b57cec5SDimitry Andric AutoIndent Indent2(P, 2); 1276*0b57cec5SDimitry Andric P.formatLine("Index: {0}", Entry.getValue()); 1277*0b57cec5SDimitry Andric P.formatLine("Size in bytes: {0}", 1278*0b57cec5SDimitry Andric File.pdb().getStreamByteSize(Entry.getValue())); 1279*0b57cec5SDimitry Andric } 1280*0b57cec5SDimitry Andric 1281*0b57cec5SDimitry Andric return Error::success(); 1282*0b57cec5SDimitry Andric } 1283*0b57cec5SDimitry Andric 1284*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpStringTable() { 1285*0b57cec5SDimitry Andric printHeader(P, "String Table"); 1286*0b57cec5SDimitry Andric 1287*0b57cec5SDimitry Andric if (File.isPdb()) 1288*0b57cec5SDimitry Andric return dumpStringTableFromPdb(); 1289*0b57cec5SDimitry Andric 1290*0b57cec5SDimitry Andric return dumpStringTableFromObj(); 1291*0b57cec5SDimitry Andric } 1292*0b57cec5SDimitry Andric 1293*0b57cec5SDimitry Andric static void buildDepSet(LazyRandomTypeCollection &Types, 1294*0b57cec5SDimitry Andric ArrayRef<TypeIndex> Indices, 1295*0b57cec5SDimitry Andric std::map<TypeIndex, CVType> &DepSet) { 1296*0b57cec5SDimitry Andric SmallVector<TypeIndex, 4> DepList; 1297*0b57cec5SDimitry Andric for (const auto &I : Indices) { 1298*0b57cec5SDimitry Andric TypeIndex TI(I); 1299*0b57cec5SDimitry Andric if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType()) 1300*0b57cec5SDimitry Andric continue; 1301*0b57cec5SDimitry Andric 1302*0b57cec5SDimitry Andric CVType Type = Types.getType(TI); 1303*0b57cec5SDimitry Andric DepSet[TI] = Type; 1304*0b57cec5SDimitry Andric codeview::discoverTypeIndices(Type, DepList); 1305*0b57cec5SDimitry Andric buildDepSet(Types, DepList, DepSet); 1306*0b57cec5SDimitry Andric } 1307*0b57cec5SDimitry Andric } 1308*0b57cec5SDimitry Andric 1309*0b57cec5SDimitry Andric static void 1310*0b57cec5SDimitry Andric dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types, 1311*0b57cec5SDimitry Andric TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords, 1312*0b57cec5SDimitry Andric uint32_t NumHashBuckets, 1313*0b57cec5SDimitry Andric FixedStreamArray<support::ulittle32_t> HashValues, 1314*0b57cec5SDimitry Andric TpiStream *Stream, bool Bytes, bool Extras) { 1315*0b57cec5SDimitry Andric 1316*0b57cec5SDimitry Andric Printer.formatLine("Showing {0:N} records", NumTypeRecords); 1317*0b57cec5SDimitry Andric uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords); 1318*0b57cec5SDimitry Andric 1319*0b57cec5SDimitry Andric MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, 1320*0b57cec5SDimitry Andric NumHashBuckets, HashValues, Stream); 1321*0b57cec5SDimitry Andric 1322*0b57cec5SDimitry Andric if (auto EC = codeview::visitTypeStream(Types, V)) { 1323*0b57cec5SDimitry Andric Printer.formatLine("An error occurred dumping type records: {0}", 1324*0b57cec5SDimitry Andric toString(std::move(EC))); 1325*0b57cec5SDimitry Andric } 1326*0b57cec5SDimitry Andric } 1327*0b57cec5SDimitry Andric 1328*0b57cec5SDimitry Andric static void dumpPartialTypeStream(LinePrinter &Printer, 1329*0b57cec5SDimitry Andric LazyRandomTypeCollection &Types, 1330*0b57cec5SDimitry Andric TypeReferenceTracker *RefTracker, 1331*0b57cec5SDimitry Andric TpiStream &Stream, ArrayRef<TypeIndex> TiList, 1332*0b57cec5SDimitry Andric bool Bytes, bool Extras, bool Deps) { 1333*0b57cec5SDimitry Andric uint32_t Width = 1334*0b57cec5SDimitry Andric NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords()); 1335*0b57cec5SDimitry Andric 1336*0b57cec5SDimitry Andric MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker, 1337*0b57cec5SDimitry Andric Stream.getNumHashBuckets(), Stream.getHashValues(), 1338*0b57cec5SDimitry Andric &Stream); 1339*0b57cec5SDimitry Andric 1340*0b57cec5SDimitry Andric if (opts::dump::DumpTypeDependents) { 1341*0b57cec5SDimitry Andric // If we need to dump all dependents, then iterate each index and find 1342*0b57cec5SDimitry Andric // all dependents, adding them to a map ordered by TypeIndex. 1343*0b57cec5SDimitry Andric std::map<TypeIndex, CVType> DepSet; 1344*0b57cec5SDimitry Andric buildDepSet(Types, TiList, DepSet); 1345*0b57cec5SDimitry Andric 1346*0b57cec5SDimitry Andric Printer.formatLine( 1347*0b57cec5SDimitry Andric "Showing {0:N} records and their dependents ({1:N} records total)", 1348*0b57cec5SDimitry Andric TiList.size(), DepSet.size()); 1349*0b57cec5SDimitry Andric 1350*0b57cec5SDimitry Andric for (auto &Dep : DepSet) { 1351*0b57cec5SDimitry Andric if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V)) 1352*0b57cec5SDimitry Andric Printer.formatLine("An error occurred dumping type record {0}: {1}", 1353*0b57cec5SDimitry Andric Dep.first, toString(std::move(EC))); 1354*0b57cec5SDimitry Andric } 1355*0b57cec5SDimitry Andric } else { 1356*0b57cec5SDimitry Andric Printer.formatLine("Showing {0:N} records.", TiList.size()); 1357*0b57cec5SDimitry Andric 1358*0b57cec5SDimitry Andric for (const auto &I : TiList) { 1359*0b57cec5SDimitry Andric TypeIndex TI(I); 1360*0b57cec5SDimitry Andric CVType Type = Types.getType(TI); 1361*0b57cec5SDimitry Andric if (auto EC = codeview::visitTypeRecord(Type, TI, V)) 1362*0b57cec5SDimitry Andric Printer.formatLine("An error occurred dumping type record {0}: {1}", TI, 1363*0b57cec5SDimitry Andric toString(std::move(EC))); 1364*0b57cec5SDimitry Andric } 1365*0b57cec5SDimitry Andric } 1366*0b57cec5SDimitry Andric } 1367*0b57cec5SDimitry Andric 1368*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypesFromObjectFile() { 1369*0b57cec5SDimitry Andric LazyRandomTypeCollection Types(100); 1370*0b57cec5SDimitry Andric 1371*0b57cec5SDimitry Andric for (const auto &S : getObj().sections()) { 1372*0b57cec5SDimitry Andric StringRef SectionName; 1373*0b57cec5SDimitry Andric if (auto EC = S.getName(SectionName)) 1374*0b57cec5SDimitry Andric return errorCodeToError(EC); 1375*0b57cec5SDimitry Andric 1376*0b57cec5SDimitry Andric // .debug$T is a standard CodeView type section, while .debug$P is the same 1377*0b57cec5SDimitry Andric // format but used for MSVC precompiled header object files. 1378*0b57cec5SDimitry Andric if (SectionName == ".debug$T") 1379*0b57cec5SDimitry Andric printHeader(P, "Types (.debug$T)"); 1380*0b57cec5SDimitry Andric else if (SectionName == ".debug$P") 1381*0b57cec5SDimitry Andric printHeader(P, "Precompiled Types (.debug$P)"); 1382*0b57cec5SDimitry Andric else 1383*0b57cec5SDimitry Andric continue; 1384*0b57cec5SDimitry Andric 1385*0b57cec5SDimitry Andric Expected<StringRef> ContentsOrErr = S.getContents(); 1386*0b57cec5SDimitry Andric if (!ContentsOrErr) 1387*0b57cec5SDimitry Andric return ContentsOrErr.takeError(); 1388*0b57cec5SDimitry Andric 1389*0b57cec5SDimitry Andric uint32_t Magic; 1390*0b57cec5SDimitry Andric BinaryStreamReader Reader(*ContentsOrErr, llvm::support::little); 1391*0b57cec5SDimitry Andric if (auto EC = Reader.readInteger(Magic)) 1392*0b57cec5SDimitry Andric return EC; 1393*0b57cec5SDimitry Andric if (Magic != COFF::DEBUG_SECTION_MAGIC) 1394*0b57cec5SDimitry Andric return make_error<StringError>("Invalid CodeView debug section.", 1395*0b57cec5SDimitry Andric inconvertibleErrorCode()); 1396*0b57cec5SDimitry Andric 1397*0b57cec5SDimitry Andric Types.reset(Reader, 100); 1398*0b57cec5SDimitry Andric 1399*0b57cec5SDimitry Andric if (opts::dump::DumpTypes) { 1400*0b57cec5SDimitry Andric dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr, 1401*0b57cec5SDimitry Andric opts::dump::DumpTypeData, false); 1402*0b57cec5SDimitry Andric } else if (opts::dump::DumpTypeExtras) { 1403*0b57cec5SDimitry Andric auto LocalHashes = LocallyHashedType::hashTypeCollection(Types); 1404*0b57cec5SDimitry Andric auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types); 1405*0b57cec5SDimitry Andric assert(LocalHashes.size() == GlobalHashes.size()); 1406*0b57cec5SDimitry Andric 1407*0b57cec5SDimitry Andric P.formatLine("Local / Global hashes:"); 1408*0b57cec5SDimitry Andric TypeIndex TI(TypeIndex::FirstNonSimpleIndex); 1409*0b57cec5SDimitry Andric for (const auto &H : zip(LocalHashes, GlobalHashes)) { 1410*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1411*0b57cec5SDimitry Andric LocallyHashedType &L = std::get<0>(H); 1412*0b57cec5SDimitry Andric GloballyHashedType &G = std::get<1>(H); 1413*0b57cec5SDimitry Andric 1414*0b57cec5SDimitry Andric P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G); 1415*0b57cec5SDimitry Andric 1416*0b57cec5SDimitry Andric ++TI; 1417*0b57cec5SDimitry Andric } 1418*0b57cec5SDimitry Andric P.NewLine(); 1419*0b57cec5SDimitry Andric } 1420*0b57cec5SDimitry Andric } 1421*0b57cec5SDimitry Andric 1422*0b57cec5SDimitry Andric return Error::success(); 1423*0b57cec5SDimitry Andric } 1424*0b57cec5SDimitry Andric 1425*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { 1426*0b57cec5SDimitry Andric assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); 1427*0b57cec5SDimitry Andric 1428*0b57cec5SDimitry Andric if (StreamIdx == StreamTPI) { 1429*0b57cec5SDimitry Andric printHeader(P, "Types (TPI Stream)"); 1430*0b57cec5SDimitry Andric } else if (StreamIdx == StreamIPI) { 1431*0b57cec5SDimitry Andric printHeader(P, "Types (IPI Stream)"); 1432*0b57cec5SDimitry Andric } 1433*0b57cec5SDimitry Andric 1434*0b57cec5SDimitry Andric assert(!File.isObj()); 1435*0b57cec5SDimitry Andric 1436*0b57cec5SDimitry Andric bool Present = false; 1437*0b57cec5SDimitry Andric bool DumpTypes = false; 1438*0b57cec5SDimitry Andric bool DumpBytes = false; 1439*0b57cec5SDimitry Andric bool DumpExtras = false; 1440*0b57cec5SDimitry Andric std::vector<uint32_t> Indices; 1441*0b57cec5SDimitry Andric if (StreamIdx == StreamTPI) { 1442*0b57cec5SDimitry Andric Present = getPdb().hasPDBTpiStream(); 1443*0b57cec5SDimitry Andric DumpTypes = opts::dump::DumpTypes; 1444*0b57cec5SDimitry Andric DumpBytes = opts::dump::DumpTypeData; 1445*0b57cec5SDimitry Andric DumpExtras = opts::dump::DumpTypeExtras; 1446*0b57cec5SDimitry Andric Indices.assign(opts::dump::DumpTypeIndex.begin(), 1447*0b57cec5SDimitry Andric opts::dump::DumpTypeIndex.end()); 1448*0b57cec5SDimitry Andric } else if (StreamIdx == StreamIPI) { 1449*0b57cec5SDimitry Andric Present = getPdb().hasPDBIpiStream(); 1450*0b57cec5SDimitry Andric DumpTypes = opts::dump::DumpIds; 1451*0b57cec5SDimitry Andric DumpBytes = opts::dump::DumpIdData; 1452*0b57cec5SDimitry Andric DumpExtras = opts::dump::DumpIdExtras; 1453*0b57cec5SDimitry Andric Indices.assign(opts::dump::DumpIdIndex.begin(), 1454*0b57cec5SDimitry Andric opts::dump::DumpIdIndex.end()); 1455*0b57cec5SDimitry Andric } 1456*0b57cec5SDimitry Andric 1457*0b57cec5SDimitry Andric if (!Present) { 1458*0b57cec5SDimitry Andric printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI"); 1459*0b57cec5SDimitry Andric return Error::success(); 1460*0b57cec5SDimitry Andric } 1461*0b57cec5SDimitry Andric 1462*0b57cec5SDimitry Andric AutoIndent Indent(P); 1463*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing types: "); 1464*0b57cec5SDimitry Andric 1465*0b57cec5SDimitry Andric auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream() 1466*0b57cec5SDimitry Andric : getPdb().getPDBIpiStream()); 1467*0b57cec5SDimitry Andric 1468*0b57cec5SDimitry Andric auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids(); 1469*0b57cec5SDimitry Andric 1470*0b57cec5SDimitry Andric // Only emit notes about referenced/unreferenced for types. 1471*0b57cec5SDimitry Andric TypeReferenceTracker *MaybeTracker = 1472*0b57cec5SDimitry Andric (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr; 1473*0b57cec5SDimitry Andric 1474*0b57cec5SDimitry Andric // Enable resolving forward decls. 1475*0b57cec5SDimitry Andric Stream.buildHashMap(); 1476*0b57cec5SDimitry Andric 1477*0b57cec5SDimitry Andric if (DumpTypes || !Indices.empty()) { 1478*0b57cec5SDimitry Andric if (Indices.empty()) 1479*0b57cec5SDimitry Andric dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(), 1480*0b57cec5SDimitry Andric Stream.getNumHashBuckets(), Stream.getHashValues(), 1481*0b57cec5SDimitry Andric &Stream, DumpBytes, DumpExtras); 1482*0b57cec5SDimitry Andric else { 1483*0b57cec5SDimitry Andric std::vector<TypeIndex> TiList(Indices.begin(), Indices.end()); 1484*0b57cec5SDimitry Andric dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes, 1485*0b57cec5SDimitry Andric DumpExtras, opts::dump::DumpTypeDependents); 1486*0b57cec5SDimitry Andric } 1487*0b57cec5SDimitry Andric } 1488*0b57cec5SDimitry Andric 1489*0b57cec5SDimitry Andric if (DumpExtras) { 1490*0b57cec5SDimitry Andric P.NewLine(); 1491*0b57cec5SDimitry Andric 1492*0b57cec5SDimitry Andric P.formatLine("Header Version: {0}", 1493*0b57cec5SDimitry Andric static_cast<uint32_t>(Stream.getTpiVersion())); 1494*0b57cec5SDimitry Andric P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex()); 1495*0b57cec5SDimitry Andric P.formatLine("Aux Hash Stream Index: {0}", 1496*0b57cec5SDimitry Andric Stream.getTypeHashStreamAuxIndex()); 1497*0b57cec5SDimitry Andric P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize()); 1498*0b57cec5SDimitry Andric P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets()); 1499*0b57cec5SDimitry Andric 1500*0b57cec5SDimitry Andric auto IndexOffsets = Stream.getTypeIndexOffsets(); 1501*0b57cec5SDimitry Andric P.formatLine("Type Index Offsets:"); 1502*0b57cec5SDimitry Andric for (const auto &IO : IndexOffsets) { 1503*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1504*0b57cec5SDimitry Andric P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset)); 1505*0b57cec5SDimitry Andric } 1506*0b57cec5SDimitry Andric 1507*0b57cec5SDimitry Andric if (getPdb().hasPDBStringTable()) { 1508*0b57cec5SDimitry Andric P.NewLine(); 1509*0b57cec5SDimitry Andric P.formatLine("Hash Adjusters:"); 1510*0b57cec5SDimitry Andric auto &Adjusters = Stream.getHashAdjusters(); 1511*0b57cec5SDimitry Andric auto &Strings = Err(getPdb().getStringTable()); 1512*0b57cec5SDimitry Andric for (const auto &A : Adjusters) { 1513*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1514*0b57cec5SDimitry Andric auto ExpectedStr = Strings.getStringForID(A.first); 1515*0b57cec5SDimitry Andric TypeIndex TI(A.second); 1516*0b57cec5SDimitry Andric if (ExpectedStr) 1517*0b57cec5SDimitry Andric P.formatLine("`{0}` -> {1}", *ExpectedStr, TI); 1518*0b57cec5SDimitry Andric else { 1519*0b57cec5SDimitry Andric P.formatLine("unknown str id ({0}) -> {1}", A.first, TI); 1520*0b57cec5SDimitry Andric consumeError(ExpectedStr.takeError()); 1521*0b57cec5SDimitry Andric } 1522*0b57cec5SDimitry Andric } 1523*0b57cec5SDimitry Andric } 1524*0b57cec5SDimitry Andric } 1525*0b57cec5SDimitry Andric return Error::success(); 1526*0b57cec5SDimitry Andric } 1527*0b57cec5SDimitry Andric 1528*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleSymsForObj() { 1529*0b57cec5SDimitry Andric printHeader(P, "Symbols"); 1530*0b57cec5SDimitry Andric 1531*0b57cec5SDimitry Andric AutoIndent Indent(P); 1532*0b57cec5SDimitry Andric 1533*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing symbols: "); 1534*0b57cec5SDimitry Andric 1535*0b57cec5SDimitry Andric auto &Types = File.types(); 1536*0b57cec5SDimitry Andric 1537*0b57cec5SDimitry Andric SymbolVisitorCallbackPipeline Pipeline; 1538*0b57cec5SDimitry Andric SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile); 1539*0b57cec5SDimitry Andric MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types); 1540*0b57cec5SDimitry Andric 1541*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer); 1542*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Dumper); 1543*0b57cec5SDimitry Andric CVSymbolVisitor Visitor(Pipeline); 1544*0b57cec5SDimitry Andric 1545*0b57cec5SDimitry Andric std::unique_ptr<llvm::Error> SymbolError; 1546*0b57cec5SDimitry Andric 1547*0b57cec5SDimitry Andric iterateModuleSubsections<DebugSymbolsSubsectionRef>( 1548*0b57cec5SDimitry Andric File, PrintScope{P, 2}, 1549*0b57cec5SDimitry Andric [&](uint32_t Modi, const SymbolGroup &Strings, 1550*0b57cec5SDimitry Andric DebugSymbolsSubsectionRef &Symbols) { 1551*0b57cec5SDimitry Andric Dumper.setSymbolGroup(&Strings); 1552*0b57cec5SDimitry Andric for (auto Symbol : Symbols) { 1553*0b57cec5SDimitry Andric if (auto EC = Visitor.visitSymbolRecord(Symbol)) { 1554*0b57cec5SDimitry Andric SymbolError = llvm::make_unique<Error>(std::move(EC)); 1555*0b57cec5SDimitry Andric return; 1556*0b57cec5SDimitry Andric } 1557*0b57cec5SDimitry Andric } 1558*0b57cec5SDimitry Andric }); 1559*0b57cec5SDimitry Andric 1560*0b57cec5SDimitry Andric if (SymbolError) 1561*0b57cec5SDimitry Andric return std::move(*SymbolError); 1562*0b57cec5SDimitry Andric 1563*0b57cec5SDimitry Andric return Error::success(); 1564*0b57cec5SDimitry Andric } 1565*0b57cec5SDimitry Andric 1566*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpModuleSymsForPdb() { 1567*0b57cec5SDimitry Andric printHeader(P, "Symbols"); 1568*0b57cec5SDimitry Andric 1569*0b57cec5SDimitry Andric if (File.isPdb() && !getPdb().hasPDBDbiStream()) { 1570*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1571*0b57cec5SDimitry Andric return Error::success(); 1572*0b57cec5SDimitry Andric } 1573*0b57cec5SDimitry Andric 1574*0b57cec5SDimitry Andric AutoIndent Indent(P); 1575*0b57cec5SDimitry Andric ExitOnError Err("Unexpected error processing symbols: "); 1576*0b57cec5SDimitry Andric 1577*0b57cec5SDimitry Andric auto &Ids = File.ids(); 1578*0b57cec5SDimitry Andric auto &Types = File.types(); 1579*0b57cec5SDimitry Andric 1580*0b57cec5SDimitry Andric iterateSymbolGroups( 1581*0b57cec5SDimitry Andric File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) { 1582*0b57cec5SDimitry Andric auto ExpectedModS = getModuleDebugStream(File.pdb(), I); 1583*0b57cec5SDimitry Andric if (!ExpectedModS) { 1584*0b57cec5SDimitry Andric P.formatLine("Error loading module stream {0}. {1}", I, 1585*0b57cec5SDimitry Andric toString(ExpectedModS.takeError())); 1586*0b57cec5SDimitry Andric return; 1587*0b57cec5SDimitry Andric } 1588*0b57cec5SDimitry Andric 1589*0b57cec5SDimitry Andric ModuleDebugStreamRef &ModS = *ExpectedModS; 1590*0b57cec5SDimitry Andric 1591*0b57cec5SDimitry Andric SymbolVisitorCallbackPipeline Pipeline; 1592*0b57cec5SDimitry Andric SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1593*0b57cec5SDimitry Andric MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings, 1594*0b57cec5SDimitry Andric Ids, Types); 1595*0b57cec5SDimitry Andric 1596*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer); 1597*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Dumper); 1598*0b57cec5SDimitry Andric CVSymbolVisitor Visitor(Pipeline); 1599*0b57cec5SDimitry Andric auto SS = ModS.getSymbolsSubstream(); 1600*0b57cec5SDimitry Andric if (auto EC = 1601*0b57cec5SDimitry Andric Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) { 1602*0b57cec5SDimitry Andric P.formatLine("Error while processing symbol records. {0}", 1603*0b57cec5SDimitry Andric toString(std::move(EC))); 1604*0b57cec5SDimitry Andric return; 1605*0b57cec5SDimitry Andric } 1606*0b57cec5SDimitry Andric }); 1607*0b57cec5SDimitry Andric return Error::success(); 1608*0b57cec5SDimitry Andric } 1609*0b57cec5SDimitry Andric 1610*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpTypeRefStats() { 1611*0b57cec5SDimitry Andric printHeader(P, "Type Reference Statistics"); 1612*0b57cec5SDimitry Andric AutoIndent Indent(P); 1613*0b57cec5SDimitry Andric 1614*0b57cec5SDimitry Andric // Sum the byte size of all type records, and the size and count of all 1615*0b57cec5SDimitry Andric // referenced records. 1616*0b57cec5SDimitry Andric size_t TotalRecs = File.types().size(); 1617*0b57cec5SDimitry Andric size_t RefRecs = 0; 1618*0b57cec5SDimitry Andric size_t TotalBytes = 0; 1619*0b57cec5SDimitry Andric size_t RefBytes = 0; 1620*0b57cec5SDimitry Andric auto &Types = File.types(); 1621*0b57cec5SDimitry Andric for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) { 1622*0b57cec5SDimitry Andric CVType Type = File.types().getType(*TI); 1623*0b57cec5SDimitry Andric TotalBytes += Type.length(); 1624*0b57cec5SDimitry Andric if (RefTracker->isTypeReferenced(*TI)) { 1625*0b57cec5SDimitry Andric ++RefRecs; 1626*0b57cec5SDimitry Andric RefBytes += Type.length(); 1627*0b57cec5SDimitry Andric } 1628*0b57cec5SDimitry Andric } 1629*0b57cec5SDimitry Andric 1630*0b57cec5SDimitry Andric P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs, 1631*0b57cec5SDimitry Andric (double)RefRecs / TotalRecs); 1632*0b57cec5SDimitry Andric P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes, 1633*0b57cec5SDimitry Andric (double)RefBytes / TotalBytes); 1634*0b57cec5SDimitry Andric 1635*0b57cec5SDimitry Andric return Error::success(); 1636*0b57cec5SDimitry Andric } 1637*0b57cec5SDimitry Andric 1638*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpGSIRecords() { 1639*0b57cec5SDimitry Andric printHeader(P, "GSI Records"); 1640*0b57cec5SDimitry Andric 1641*0b57cec5SDimitry Andric if (File.isObj()) { 1642*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1643*0b57cec5SDimitry Andric return Error::success(); 1644*0b57cec5SDimitry Andric } 1645*0b57cec5SDimitry Andric 1646*0b57cec5SDimitry Andric if (!getPdb().hasPDBSymbolStream()) { 1647*0b57cec5SDimitry Andric printStreamNotPresent("GSI Common Symbol"); 1648*0b57cec5SDimitry Andric return Error::success(); 1649*0b57cec5SDimitry Andric } 1650*0b57cec5SDimitry Andric 1651*0b57cec5SDimitry Andric AutoIndent Indent(P); 1652*0b57cec5SDimitry Andric 1653*0b57cec5SDimitry Andric auto &Records = cantFail(getPdb().getPDBSymbolStream()); 1654*0b57cec5SDimitry Andric auto &Types = File.types(); 1655*0b57cec5SDimitry Andric auto &Ids = File.ids(); 1656*0b57cec5SDimitry Andric 1657*0b57cec5SDimitry Andric P.printLine("Records"); 1658*0b57cec5SDimitry Andric SymbolVisitorCallbackPipeline Pipeline; 1659*0b57cec5SDimitry Andric SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1660*0b57cec5SDimitry Andric MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1661*0b57cec5SDimitry Andric 1662*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer); 1663*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Dumper); 1664*0b57cec5SDimitry Andric CVSymbolVisitor Visitor(Pipeline); 1665*0b57cec5SDimitry Andric 1666*0b57cec5SDimitry Andric BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream(); 1667*0b57cec5SDimitry Andric if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0)) 1668*0b57cec5SDimitry Andric return E; 1669*0b57cec5SDimitry Andric return Error::success(); 1670*0b57cec5SDimitry Andric } 1671*0b57cec5SDimitry Andric 1672*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpGlobals() { 1673*0b57cec5SDimitry Andric printHeader(P, "Global Symbols"); 1674*0b57cec5SDimitry Andric 1675*0b57cec5SDimitry Andric if (File.isObj()) { 1676*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1677*0b57cec5SDimitry Andric return Error::success(); 1678*0b57cec5SDimitry Andric } 1679*0b57cec5SDimitry Andric 1680*0b57cec5SDimitry Andric if (!getPdb().hasPDBGlobalsStream()) { 1681*0b57cec5SDimitry Andric printStreamNotPresent("Globals"); 1682*0b57cec5SDimitry Andric return Error::success(); 1683*0b57cec5SDimitry Andric } 1684*0b57cec5SDimitry Andric 1685*0b57cec5SDimitry Andric AutoIndent Indent(P); 1686*0b57cec5SDimitry Andric ExitOnError Err("Error dumping globals stream: "); 1687*0b57cec5SDimitry Andric auto &Globals = Err(getPdb().getPDBGlobalsStream()); 1688*0b57cec5SDimitry Andric 1689*0b57cec5SDimitry Andric if (opts::dump::DumpGlobalNames.empty()) { 1690*0b57cec5SDimitry Andric const GSIHashTable &Table = Globals.getGlobalsTable(); 1691*0b57cec5SDimitry Andric Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras)); 1692*0b57cec5SDimitry Andric } else { 1693*0b57cec5SDimitry Andric SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream()); 1694*0b57cec5SDimitry Andric auto &Types = File.types(); 1695*0b57cec5SDimitry Andric auto &Ids = File.ids(); 1696*0b57cec5SDimitry Andric 1697*0b57cec5SDimitry Andric SymbolVisitorCallbackPipeline Pipeline; 1698*0b57cec5SDimitry Andric SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1699*0b57cec5SDimitry Andric MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1700*0b57cec5SDimitry Andric 1701*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer); 1702*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Dumper); 1703*0b57cec5SDimitry Andric CVSymbolVisitor Visitor(Pipeline); 1704*0b57cec5SDimitry Andric 1705*0b57cec5SDimitry Andric using ResultEntryType = std::pair<uint32_t, CVSymbol>; 1706*0b57cec5SDimitry Andric for (StringRef Name : opts::dump::DumpGlobalNames) { 1707*0b57cec5SDimitry Andric AutoIndent Indent(P); 1708*0b57cec5SDimitry Andric P.formatLine("Global Name `{0}`", Name); 1709*0b57cec5SDimitry Andric std::vector<ResultEntryType> Results = 1710*0b57cec5SDimitry Andric Globals.findRecordsByName(Name, SymRecords); 1711*0b57cec5SDimitry Andric if (Results.empty()) { 1712*0b57cec5SDimitry Andric AutoIndent Indent(P); 1713*0b57cec5SDimitry Andric P.printLine("(no matching records found)"); 1714*0b57cec5SDimitry Andric continue; 1715*0b57cec5SDimitry Andric } 1716*0b57cec5SDimitry Andric 1717*0b57cec5SDimitry Andric for (ResultEntryType Result : Results) { 1718*0b57cec5SDimitry Andric if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first)) 1719*0b57cec5SDimitry Andric return E; 1720*0b57cec5SDimitry Andric } 1721*0b57cec5SDimitry Andric } 1722*0b57cec5SDimitry Andric } 1723*0b57cec5SDimitry Andric return Error::success(); 1724*0b57cec5SDimitry Andric } 1725*0b57cec5SDimitry Andric 1726*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpPublics() { 1727*0b57cec5SDimitry Andric printHeader(P, "Public Symbols"); 1728*0b57cec5SDimitry Andric 1729*0b57cec5SDimitry Andric if (File.isObj()) { 1730*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1731*0b57cec5SDimitry Andric return Error::success(); 1732*0b57cec5SDimitry Andric } 1733*0b57cec5SDimitry Andric 1734*0b57cec5SDimitry Andric if (!getPdb().hasPDBPublicsStream()) { 1735*0b57cec5SDimitry Andric printStreamNotPresent("Publics"); 1736*0b57cec5SDimitry Andric return Error::success(); 1737*0b57cec5SDimitry Andric } 1738*0b57cec5SDimitry Andric 1739*0b57cec5SDimitry Andric AutoIndent Indent(P); 1740*0b57cec5SDimitry Andric ExitOnError Err("Error dumping publics stream: "); 1741*0b57cec5SDimitry Andric auto &Publics = Err(getPdb().getPDBPublicsStream()); 1742*0b57cec5SDimitry Andric 1743*0b57cec5SDimitry Andric const GSIHashTable &PublicsTable = Publics.getPublicsTable(); 1744*0b57cec5SDimitry Andric if (opts::dump::DumpPublicExtras) { 1745*0b57cec5SDimitry Andric P.printLine("Publics Header"); 1746*0b57cec5SDimitry Andric AutoIndent Indent(P); 1747*0b57cec5SDimitry Andric P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(), 1748*0b57cec5SDimitry Andric formatSegmentOffset(Publics.getThunkTableSection(), 1749*0b57cec5SDimitry Andric Publics.getThunkTableOffset())); 1750*0b57cec5SDimitry Andric } 1751*0b57cec5SDimitry Andric Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras)); 1752*0b57cec5SDimitry Andric 1753*0b57cec5SDimitry Andric // Skip the rest if we aren't dumping extras. 1754*0b57cec5SDimitry Andric if (!opts::dump::DumpPublicExtras) 1755*0b57cec5SDimitry Andric return Error::success(); 1756*0b57cec5SDimitry Andric 1757*0b57cec5SDimitry Andric P.formatLine("Address Map"); 1758*0b57cec5SDimitry Andric { 1759*0b57cec5SDimitry Andric // These are offsets into the publics stream sorted by secidx:secrel. 1760*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1761*0b57cec5SDimitry Andric for (uint32_t Addr : Publics.getAddressMap()) 1762*0b57cec5SDimitry Andric P.formatLine("off = {0}", Addr); 1763*0b57cec5SDimitry Andric } 1764*0b57cec5SDimitry Andric 1765*0b57cec5SDimitry Andric // The thunk map is optional debug info used for ILT thunks. 1766*0b57cec5SDimitry Andric if (!Publics.getThunkMap().empty()) { 1767*0b57cec5SDimitry Andric P.formatLine("Thunk Map"); 1768*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1769*0b57cec5SDimitry Andric for (uint32_t Addr : Publics.getThunkMap()) 1770*0b57cec5SDimitry Andric P.formatLine("{0:x8}", Addr); 1771*0b57cec5SDimitry Andric } 1772*0b57cec5SDimitry Andric 1773*0b57cec5SDimitry Andric // The section offsets table appears to be empty when incremental linking 1774*0b57cec5SDimitry Andric // isn't in use. 1775*0b57cec5SDimitry Andric if (!Publics.getSectionOffsets().empty()) { 1776*0b57cec5SDimitry Andric P.formatLine("Section Offsets"); 1777*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1778*0b57cec5SDimitry Andric for (const SectionOffset &SO : Publics.getSectionOffsets()) 1779*0b57cec5SDimitry Andric P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off)); 1780*0b57cec5SDimitry Andric } 1781*0b57cec5SDimitry Andric 1782*0b57cec5SDimitry Andric return Error::success(); 1783*0b57cec5SDimitry Andric } 1784*0b57cec5SDimitry Andric 1785*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table, 1786*0b57cec5SDimitry Andric bool HashExtras) { 1787*0b57cec5SDimitry Andric auto ExpectedSyms = getPdb().getPDBSymbolStream(); 1788*0b57cec5SDimitry Andric if (!ExpectedSyms) 1789*0b57cec5SDimitry Andric return ExpectedSyms.takeError(); 1790*0b57cec5SDimitry Andric auto &Types = File.types(); 1791*0b57cec5SDimitry Andric auto &Ids = File.ids(); 1792*0b57cec5SDimitry Andric 1793*0b57cec5SDimitry Andric if (HashExtras) { 1794*0b57cec5SDimitry Andric P.printLine("GSI Header"); 1795*0b57cec5SDimitry Andric AutoIndent Indent(P); 1796*0b57cec5SDimitry Andric P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}", 1797*0b57cec5SDimitry Andric Table.getVerSignature(), Table.getVerHeader(), 1798*0b57cec5SDimitry Andric Table.getHashRecordSize(), Table.getNumBuckets()); 1799*0b57cec5SDimitry Andric } 1800*0b57cec5SDimitry Andric 1801*0b57cec5SDimitry Andric { 1802*0b57cec5SDimitry Andric P.printLine("Records"); 1803*0b57cec5SDimitry Andric SymbolVisitorCallbackPipeline Pipeline; 1804*0b57cec5SDimitry Andric SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); 1805*0b57cec5SDimitry Andric MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types); 1806*0b57cec5SDimitry Andric 1807*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Deserializer); 1808*0b57cec5SDimitry Andric Pipeline.addCallbackToPipeline(Dumper); 1809*0b57cec5SDimitry Andric CVSymbolVisitor Visitor(Pipeline); 1810*0b57cec5SDimitry Andric 1811*0b57cec5SDimitry Andric 1812*0b57cec5SDimitry Andric BinaryStreamRef SymStream = 1813*0b57cec5SDimitry Andric ExpectedSyms->getSymbolArray().getUnderlyingStream(); 1814*0b57cec5SDimitry Andric for (uint32_t PubSymOff : Table) { 1815*0b57cec5SDimitry Andric Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff); 1816*0b57cec5SDimitry Andric if (!Sym) 1817*0b57cec5SDimitry Andric return Sym.takeError(); 1818*0b57cec5SDimitry Andric if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff)) 1819*0b57cec5SDimitry Andric return E; 1820*0b57cec5SDimitry Andric } 1821*0b57cec5SDimitry Andric } 1822*0b57cec5SDimitry Andric 1823*0b57cec5SDimitry Andric // Return early if we aren't dumping public hash table and address map info. 1824*0b57cec5SDimitry Andric if (HashExtras) { 1825*0b57cec5SDimitry Andric P.formatLine("Hash Entries"); 1826*0b57cec5SDimitry Andric { 1827*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1828*0b57cec5SDimitry Andric for (const PSHashRecord &HR : Table.HashRecords) 1829*0b57cec5SDimitry Andric P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off), 1830*0b57cec5SDimitry Andric uint32_t(HR.CRef)); 1831*0b57cec5SDimitry Andric } 1832*0b57cec5SDimitry Andric 1833*0b57cec5SDimitry Andric P.formatLine("Hash Buckets"); 1834*0b57cec5SDimitry Andric { 1835*0b57cec5SDimitry Andric AutoIndent Indent2(P); 1836*0b57cec5SDimitry Andric for (uint32_t Hash : Table.HashBuckets) 1837*0b57cec5SDimitry Andric P.formatLine("{0:x8}", Hash); 1838*0b57cec5SDimitry Andric } 1839*0b57cec5SDimitry Andric } 1840*0b57cec5SDimitry Andric 1841*0b57cec5SDimitry Andric return Error::success(); 1842*0b57cec5SDimitry Andric } 1843*0b57cec5SDimitry Andric 1844*0b57cec5SDimitry Andric static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel, 1845*0b57cec5SDimitry Andric OMFSegDescFlags Flags) { 1846*0b57cec5SDimitry Andric std::vector<std::string> Opts; 1847*0b57cec5SDimitry Andric if (Flags == OMFSegDescFlags::None) 1848*0b57cec5SDimitry Andric return "none"; 1849*0b57cec5SDimitry Andric 1850*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read"); 1851*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write"); 1852*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute"); 1853*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr"); 1854*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector"); 1855*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr"); 1856*0b57cec5SDimitry Andric PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group"); 1857*0b57cec5SDimitry Andric return typesetItemList(Opts, IndentLevel, 4, " | "); 1858*0b57cec5SDimitry Andric } 1859*0b57cec5SDimitry Andric 1860*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionHeaders() { 1861*0b57cec5SDimitry Andric dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr); 1862*0b57cec5SDimitry Andric dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig); 1863*0b57cec5SDimitry Andric return Error::success(); 1864*0b57cec5SDimitry Andric } 1865*0b57cec5SDimitry Andric 1866*0b57cec5SDimitry Andric void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) { 1867*0b57cec5SDimitry Andric printHeader(P, Label); 1868*0b57cec5SDimitry Andric 1869*0b57cec5SDimitry Andric if (File.isObj()) { 1870*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1871*0b57cec5SDimitry Andric return; 1872*0b57cec5SDimitry Andric } 1873*0b57cec5SDimitry Andric 1874*0b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 1875*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1876*0b57cec5SDimitry Andric return; 1877*0b57cec5SDimitry Andric } 1878*0b57cec5SDimitry Andric 1879*0b57cec5SDimitry Andric AutoIndent Indent(P); 1880*0b57cec5SDimitry Andric ExitOnError Err("Error dumping section headers: "); 1881*0b57cec5SDimitry Andric std::unique_ptr<MappedBlockStream> Stream; 1882*0b57cec5SDimitry Andric ArrayRef<object::coff_section> Headers; 1883*0b57cec5SDimitry Andric auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type); 1884*0b57cec5SDimitry Andric if (!ExpectedHeaders) { 1885*0b57cec5SDimitry Andric P.printLine(toString(ExpectedHeaders.takeError())); 1886*0b57cec5SDimitry Andric return; 1887*0b57cec5SDimitry Andric } 1888*0b57cec5SDimitry Andric std::tie(Stream, Headers) = std::move(*ExpectedHeaders); 1889*0b57cec5SDimitry Andric 1890*0b57cec5SDimitry Andric uint32_t I = 1; 1891*0b57cec5SDimitry Andric for (const auto &Header : Headers) { 1892*0b57cec5SDimitry Andric P.NewLine(); 1893*0b57cec5SDimitry Andric P.formatLine("SECTION HEADER #{0}", I); 1894*0b57cec5SDimitry Andric P.formatLine("{0,8} name", Header.Name); 1895*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize)); 1896*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress)); 1897*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData)); 1898*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} file pointer to raw data", 1899*0b57cec5SDimitry Andric uint32_t(Header.PointerToRawData)); 1900*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} file pointer to relocation table", 1901*0b57cec5SDimitry Andric uint32_t(Header.PointerToRelocations)); 1902*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} file pointer to line numbers", 1903*0b57cec5SDimitry Andric uint32_t(Header.PointerToLinenumbers)); 1904*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} number of relocations", 1905*0b57cec5SDimitry Andric uint32_t(Header.NumberOfRelocations)); 1906*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} number of line numbers", 1907*0b57cec5SDimitry Andric uint32_t(Header.NumberOfLinenumbers)); 1908*0b57cec5SDimitry Andric P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics)); 1909*0b57cec5SDimitry Andric AutoIndent IndentMore(P, 9); 1910*0b57cec5SDimitry Andric P.formatLine("{0}", formatSectionCharacteristics( 1911*0b57cec5SDimitry Andric P.getIndentLevel(), Header.Characteristics, 1, "")); 1912*0b57cec5SDimitry Andric ++I; 1913*0b57cec5SDimitry Andric } 1914*0b57cec5SDimitry Andric return; 1915*0b57cec5SDimitry Andric } 1916*0b57cec5SDimitry Andric 1917*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionContribs() { 1918*0b57cec5SDimitry Andric printHeader(P, "Section Contributions"); 1919*0b57cec5SDimitry Andric 1920*0b57cec5SDimitry Andric if (File.isObj()) { 1921*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1922*0b57cec5SDimitry Andric return Error::success(); 1923*0b57cec5SDimitry Andric } 1924*0b57cec5SDimitry Andric 1925*0b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 1926*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1927*0b57cec5SDimitry Andric return Error::success(); 1928*0b57cec5SDimitry Andric } 1929*0b57cec5SDimitry Andric 1930*0b57cec5SDimitry Andric AutoIndent Indent(P); 1931*0b57cec5SDimitry Andric ExitOnError Err("Error dumping section contributions: "); 1932*0b57cec5SDimitry Andric 1933*0b57cec5SDimitry Andric auto &Dbi = Err(getPdb().getPDBDbiStream()); 1934*0b57cec5SDimitry Andric 1935*0b57cec5SDimitry Andric class Visitor : public ISectionContribVisitor { 1936*0b57cec5SDimitry Andric public: 1937*0b57cec5SDimitry Andric Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) { 1938*0b57cec5SDimitry Andric auto Max = std::max_element( 1939*0b57cec5SDimitry Andric Names.begin(), Names.end(), 1940*0b57cec5SDimitry Andric [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); }); 1941*0b57cec5SDimitry Andric MaxNameLen = (Max == Names.end() ? 0 : Max->size()); 1942*0b57cec5SDimitry Andric } 1943*0b57cec5SDimitry Andric void visit(const SectionContrib &SC) override { 1944*0b57cec5SDimitry Andric dumpSectionContrib(P, SC, Names, MaxNameLen); 1945*0b57cec5SDimitry Andric } 1946*0b57cec5SDimitry Andric void visit(const SectionContrib2 &SC) override { 1947*0b57cec5SDimitry Andric dumpSectionContrib(P, SC, Names, MaxNameLen); 1948*0b57cec5SDimitry Andric } 1949*0b57cec5SDimitry Andric 1950*0b57cec5SDimitry Andric private: 1951*0b57cec5SDimitry Andric LinePrinter &P; 1952*0b57cec5SDimitry Andric uint32_t MaxNameLen; 1953*0b57cec5SDimitry Andric ArrayRef<std::string> Names; 1954*0b57cec5SDimitry Andric }; 1955*0b57cec5SDimitry Andric 1956*0b57cec5SDimitry Andric std::vector<std::string> Names = getSectionNames(getPdb()); 1957*0b57cec5SDimitry Andric Visitor V(P, makeArrayRef(Names)); 1958*0b57cec5SDimitry Andric Dbi.visitSectionContributions(V); 1959*0b57cec5SDimitry Andric return Error::success(); 1960*0b57cec5SDimitry Andric } 1961*0b57cec5SDimitry Andric 1962*0b57cec5SDimitry Andric Error DumpOutputStyle::dumpSectionMap() { 1963*0b57cec5SDimitry Andric printHeader(P, "Section Map"); 1964*0b57cec5SDimitry Andric 1965*0b57cec5SDimitry Andric if (File.isObj()) { 1966*0b57cec5SDimitry Andric printStreamNotValidForObj(); 1967*0b57cec5SDimitry Andric return Error::success(); 1968*0b57cec5SDimitry Andric } 1969*0b57cec5SDimitry Andric 1970*0b57cec5SDimitry Andric if (!getPdb().hasPDBDbiStream()) { 1971*0b57cec5SDimitry Andric printStreamNotPresent("DBI"); 1972*0b57cec5SDimitry Andric return Error::success(); 1973*0b57cec5SDimitry Andric } 1974*0b57cec5SDimitry Andric 1975*0b57cec5SDimitry Andric AutoIndent Indent(P); 1976*0b57cec5SDimitry Andric ExitOnError Err("Error dumping section map: "); 1977*0b57cec5SDimitry Andric 1978*0b57cec5SDimitry Andric auto &Dbi = Err(getPdb().getPDBDbiStream()); 1979*0b57cec5SDimitry Andric 1980*0b57cec5SDimitry Andric uint32_t I = 0; 1981*0b57cec5SDimitry Andric for (auto &M : Dbi.getSectionMap()) { 1982*0b57cec5SDimitry Andric P.formatLine( 1983*0b57cec5SDimitry Andric "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I, 1984*0b57cec5SDimitry Andric fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName)); 1985*0b57cec5SDimitry Andric P.formatLine(" class = {0}, offset = {1}, size = {2}", 1986*0b57cec5SDimitry Andric fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength)); 1987*0b57cec5SDimitry Andric P.formatLine(" flags = {0}", 1988*0b57cec5SDimitry Andric formatSegMapDescriptorFlag( 1989*0b57cec5SDimitry Andric P.getIndentLevel() + 13, 1990*0b57cec5SDimitry Andric static_cast<OMFSegDescFlags>(uint16_t(M.Flags)))); 1991*0b57cec5SDimitry Andric ++I; 1992*0b57cec5SDimitry Andric } 1993*0b57cec5SDimitry Andric return Error::success(); 1994*0b57cec5SDimitry Andric } 1995