brintos

brintos / llvm-project-archived public Read only

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