Home | History | Annotate | Download | only in llvm-pdbdump
      1 //===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "LLVMOutputStyle.h"
     11 
     12 #include "llvm-pdbdump.h"
     13 #include "llvm/DebugInfo/CodeView/EnumTables.h"
     14 #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
     15 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
     16 #include "llvm/DebugInfo/PDB/PDBExtras.h"
     17 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
     18 #include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
     19 #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
     20 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h"
     21 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
     22 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
     23 #include "llvm/DebugInfo/PDB/Raw/ModStream.h"
     24 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
     25 #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
     26 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
     27 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
     28 #include "llvm/Object/COFF.h"
     29 
     30 #include <unordered_map>
     31 
     32 using namespace llvm;
     33 using namespace llvm::codeview;
     34 using namespace llvm::pdb;
     35 
     36 static void printSectionOffset(llvm::raw_ostream &OS,
     37                                const SectionOffset &Off) {
     38   OS << Off.Off << ", " << Off.Isect;
     39 }
     40 
     41 LLVMOutputStyle::LLVMOutputStyle(PDBFile &File)
     42     : File(File), P(outs()), TD(&P, false) {}
     43 
     44 Error LLVMOutputStyle::dump() {
     45   if (auto EC = dumpFileHeaders())
     46     return EC;
     47 
     48   if (auto EC = dumpStreamSummary())
     49     return EC;
     50 
     51   if (auto EC = dumpStreamBlocks())
     52     return EC;
     53 
     54   if (auto EC = dumpStreamData())
     55     return EC;
     56 
     57   if (auto EC = dumpInfoStream())
     58     return EC;
     59 
     60   if (auto EC = dumpNamedStream())
     61     return EC;
     62 
     63   if (auto EC = dumpTpiStream(StreamTPI))
     64     return EC;
     65 
     66   if (auto EC = dumpTpiStream(StreamIPI))
     67     return EC;
     68 
     69   if (auto EC = dumpDbiStream())
     70     return EC;
     71 
     72   if (auto EC = dumpSectionContribs())
     73     return EC;
     74 
     75   if (auto EC = dumpSectionMap())
     76     return EC;
     77 
     78   if (auto EC = dumpPublicsStream())
     79     return EC;
     80 
     81   if (auto EC = dumpSectionHeaders())
     82     return EC;
     83 
     84   if (auto EC = dumpFpoStream())
     85     return EC;
     86 
     87   flush();
     88 
     89   return Error::success();
     90 }
     91 
     92 Error LLVMOutputStyle::dumpFileHeaders() {
     93   if (!opts::raw::DumpHeaders)
     94     return Error::success();
     95 
     96   DictScope D(P, "FileHeaders");
     97   P.printNumber("BlockSize", File.getBlockSize());
     98   P.printNumber("Unknown0", File.getUnknown0());
     99   P.printNumber("NumBlocks", File.getBlockCount());
    100   P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
    101   P.printNumber("Unknown1", File.getUnknown1());
    102   P.printNumber("BlockMapAddr", File.getBlockMapIndex());
    103   P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
    104   P.printNumber("BlockMapOffset", File.getBlockMapOffset());
    105 
    106   // The directory is not contiguous.  Instead, the block map contains a
    107   // contiguous list of block numbers whose contents, when concatenated in
    108   // order, make up the directory.
    109   P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
    110   P.printNumber("NumStreams", File.getNumStreams());
    111   return Error::success();
    112 }
    113 
    114 Error LLVMOutputStyle::dumpStreamSummary() {
    115   if (!opts::raw::DumpStreamSummary)
    116     return Error::success();
    117 
    118   // It's OK if we fail to load some of these streams, we still attempt to print
    119   // what we can.
    120   auto Dbi = File.getPDBDbiStream();
    121   auto Tpi = File.getPDBTpiStream();
    122   auto Ipi = File.getPDBIpiStream();
    123   auto Info = File.getPDBInfoStream();
    124 
    125   ListScope L(P, "Streams");
    126   uint32_t StreamCount = File.getNumStreams();
    127   std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
    128   std::unordered_map<uint16_t, std::string> NamedStreams;
    129 
    130   if (Dbi) {
    131     for (auto &ModI : Dbi->modules()) {
    132       uint16_t SN = ModI.Info.getModuleStreamIndex();
    133       ModStreams[SN] = &ModI;
    134     }
    135   }
    136   if (Info) {
    137     for (auto &NSE : Info->named_streams()) {
    138       NamedStreams[NSE.second] = NSE.first();
    139     }
    140   }
    141 
    142   for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
    143     std::string Label("Stream ");
    144     Label += to_string(StreamIdx);
    145     std::string Value;
    146     if (StreamIdx == OldMSFDirectory)
    147       Value = "Old MSF Directory";
    148     else if (StreamIdx == StreamPDB)
    149       Value = "PDB Stream";
    150     else if (StreamIdx == StreamDBI)
    151       Value = "DBI Stream";
    152     else if (StreamIdx == StreamTPI)
    153       Value = "TPI Stream";
    154     else if (StreamIdx == StreamIPI)
    155       Value = "IPI Stream";
    156     else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
    157       Value = "Global Symbol Hash";
    158     else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
    159       Value = "Public Symbol Hash";
    160     else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
    161       Value = "Public Symbol Records";
    162     else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
    163       Value = "TPI Hash";
    164     else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
    165       Value = "TPI Aux Hash";
    166     else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
    167       Value = "IPI Hash";
    168     else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
    169       Value = "IPI Aux Hash";
    170     else if (Dbi &&
    171              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
    172       Value = "Exception Data";
    173     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
    174       Value = "Fixup Data";
    175     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
    176       Value = "FPO Data";
    177     else if (Dbi &&
    178              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
    179       Value = "New FPO Data";
    180     else if (Dbi &&
    181              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
    182       Value = "Omap From Source Data";
    183     else if (Dbi &&
    184              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
    185       Value = "Omap To Source Data";
    186     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
    187       Value = "Pdata";
    188     else if (Dbi &&
    189              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
    190       Value = "Section Header Data";
    191     else if (Dbi &&
    192              StreamIdx ==
    193                  Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
    194       Value = "Section Header Original Data";
    195     else if (Dbi &&
    196              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
    197       Value = "Token Rid Data";
    198     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
    199       Value = "Xdata";
    200     else {
    201       auto ModIter = ModStreams.find(StreamIdx);
    202       auto NSIter = NamedStreams.find(StreamIdx);
    203       if (ModIter != ModStreams.end()) {
    204         Value = "Module \"";
    205         Value += ModIter->second->Info.getModuleName().str();
    206         Value += "\"";
    207       } else if (NSIter != NamedStreams.end()) {
    208         Value = "Named Stream \"";
    209         Value += NSIter->second;
    210         Value += "\"";
    211       } else {
    212         Value = "???";
    213       }
    214     }
    215     Value = "[" + Value + "]";
    216     Value =
    217         Value + " (" + to_string(File.getStreamByteSize(StreamIdx)) + " bytes)";
    218 
    219     P.printString(Label, Value);
    220   }
    221 
    222   // Consume errors from missing streams.
    223   if (!Dbi)
    224     consumeError(Dbi.takeError());
    225   if (!Tpi)
    226     consumeError(Tpi.takeError());
    227   if (!Ipi)
    228     consumeError(Ipi.takeError());
    229   if (!Info)
    230     consumeError(Info.takeError());
    231 
    232   P.flush();
    233   return Error::success();
    234 }
    235 
    236 Error LLVMOutputStyle::dumpStreamBlocks() {
    237   if (!opts::raw::DumpStreamBlocks)
    238     return Error::success();
    239 
    240   ListScope L(P, "StreamBlocks");
    241   uint32_t StreamCount = File.getNumStreams();
    242   for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
    243     std::string Name("Stream ");
    244     Name += to_string(StreamIdx);
    245     auto StreamBlocks = File.getStreamBlockList(StreamIdx);
    246     P.printList(Name, StreamBlocks);
    247   }
    248   return Error::success();
    249 }
    250 
    251 Error LLVMOutputStyle::dumpStreamData() {
    252   uint32_t StreamCount = File.getNumStreams();
    253   StringRef DumpStreamStr = opts::raw::DumpStreamDataIdx;
    254   uint32_t DumpStreamNum;
    255   if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum))
    256     return Error::success();
    257 
    258   if (DumpStreamNum >= StreamCount)
    259     return make_error<RawError>(raw_error_code::no_stream);
    260 
    261   auto S = MappedBlockStream::createIndexedStream(DumpStreamNum, File);
    262   if (!S)
    263     return S.takeError();
    264   codeview::StreamReader R(**S);
    265   while (R.bytesRemaining() > 0) {
    266     ArrayRef<uint8_t> Data;
    267     uint32_t BytesToReadInBlock = std::min(
    268         R.bytesRemaining(), static_cast<uint32_t>(File.getBlockSize()));
    269     if (auto EC = R.readBytes(Data, BytesToReadInBlock))
    270       return EC;
    271     P.printBinaryBlock(
    272         "Data",
    273         StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size()));
    274   }
    275   return Error::success();
    276 }
    277 
    278 Error LLVMOutputStyle::dumpInfoStream() {
    279   if (!opts::raw::DumpHeaders)
    280     return Error::success();
    281   auto IS = File.getPDBInfoStream();
    282   if (!IS)
    283     return IS.takeError();
    284 
    285   DictScope D(P, "PDB Stream");
    286   P.printNumber("Version", IS->getVersion());
    287   P.printHex("Signature", IS->getSignature());
    288   P.printNumber("Age", IS->getAge());
    289   P.printObject("Guid", IS->getGuid());
    290   return Error::success();
    291 }
    292 
    293 Error LLVMOutputStyle::dumpNamedStream() {
    294   if (opts::raw::DumpStreamDataName.empty())
    295     return Error::success();
    296 
    297   auto IS = File.getPDBInfoStream();
    298   if (!IS)
    299     return IS.takeError();
    300 
    301   uint32_t NameStreamIndex =
    302       IS->getNamedStreamIndex(opts::raw::DumpStreamDataName);
    303   if (NameStreamIndex == 0 || NameStreamIndex >= File.getNumStreams())
    304     return make_error<RawError>(raw_error_code::no_stream);
    305 
    306   if (NameStreamIndex != 0) {
    307     std::string Name("Stream '");
    308     Name += opts::raw::DumpStreamDataName;
    309     Name += "'";
    310     DictScope D(P, Name);
    311     P.printNumber("Index", NameStreamIndex);
    312 
    313     auto NameStream =
    314         MappedBlockStream::createIndexedStream(NameStreamIndex, File);
    315     if (!NameStream)
    316       return NameStream.takeError();
    317     codeview::StreamReader Reader(**NameStream);
    318 
    319     NameHashTable NameTable;
    320     if (auto EC = NameTable.load(Reader))
    321       return EC;
    322 
    323     P.printHex("Signature", NameTable.getSignature());
    324     P.printNumber("Version", NameTable.getHashVersion());
    325     P.printNumber("Name Count", NameTable.getNameCount());
    326     ListScope L(P, "Names");
    327     for (uint32_t ID : NameTable.name_ids()) {
    328       StringRef Str = NameTable.getStringForID(ID);
    329       if (!Str.empty())
    330         P.printString(to_string(ID), Str);
    331     }
    332   }
    333   return Error::success();
    334 }
    335 
    336 static void printTypeIndexOffset(raw_ostream &OS,
    337                                  const TypeIndexOffset &TIOff) {
    338   OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
    339 }
    340 
    341 static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
    342   if (!opts::raw::DumpTpiHash)
    343     return;
    344   DictScope DD(P, "Hash");
    345   P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
    346   P.printNumber("Hash Key Size", Tpi.getHashKeySize());
    347   P.printList("Values", Tpi.getHashValues());
    348   P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
    349               printTypeIndexOffset);
    350   P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
    351               printTypeIndexOffset);
    352 }
    353 
    354 Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
    355   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
    356 
    357   bool DumpRecordBytes = false;
    358   bool DumpRecords = false;
    359   StringRef Label;
    360   StringRef VerLabel;
    361   if (StreamIdx == StreamTPI) {
    362     DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
    363     DumpRecords = opts::raw::DumpTpiRecords;
    364     Label = "Type Info Stream (TPI)";
    365     VerLabel = "TPI Version";
    366   } else if (StreamIdx == StreamIPI) {
    367     DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
    368     DumpRecords = opts::raw::DumpIpiRecords;
    369     Label = "Type Info Stream (IPI)";
    370     VerLabel = "IPI Version";
    371   }
    372   if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
    373     return Error::success();
    374 
    375   auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
    376                                       : File.getPDBIpiStream();
    377   if (!Tpi)
    378     return Tpi.takeError();
    379 
    380   if (DumpRecords || DumpRecordBytes) {
    381     DictScope D(P, Label);
    382 
    383     P.printNumber(VerLabel, Tpi->getTpiVersion());
    384     P.printNumber("Record count", Tpi->NumTypeRecords());
    385 
    386     ListScope L(P, "Records");
    387 
    388     bool HadError = false;
    389     for (auto &Type : Tpi->types(&HadError)) {
    390       DictScope DD(P, "");
    391 
    392       if (DumpRecords) {
    393         if (auto EC = TD.dump(Type))
    394           return EC;
    395       }
    396 
    397       if (DumpRecordBytes)
    398         P.printBinaryBlock("Bytes", Type.Data);
    399     }
    400     dumpTpiHash(P, *Tpi);
    401     if (HadError)
    402       return make_error<RawError>(raw_error_code::corrupt_file,
    403                                   "TPI stream contained corrupt record");
    404   } else if (opts::raw::DumpModuleSyms) {
    405     // Even if the user doesn't want to dump type records, we still need to
    406     // iterate them in order to build the list of types so that we can print
    407     // them when dumping module symbols. So when they want to dump symbols
    408     // but not types, use a null output stream.
    409     ScopedPrinter *OldP = TD.getPrinter();
    410     TD.setPrinter(nullptr);
    411 
    412     bool HadError = false;
    413     for (auto &Type : Tpi->types(&HadError)) {
    414       if (auto EC = TD.dump(Type))
    415         return EC;
    416     }
    417 
    418     TD.setPrinter(OldP);
    419     dumpTpiHash(P, *Tpi);
    420     if (HadError)
    421       return make_error<RawError>(raw_error_code::corrupt_file,
    422                                   "TPI stream contained corrupt record");
    423   }
    424   P.flush();
    425   return Error::success();
    426 }
    427 
    428 Error LLVMOutputStyle::dumpDbiStream() {
    429   bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms ||
    430                      opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo;
    431   if (!opts::raw::DumpHeaders && !DumpModules)
    432     return Error::success();
    433 
    434   auto DS = File.getPDBDbiStream();
    435   if (!DS)
    436     return DS.takeError();
    437 
    438   DictScope D(P, "DBI Stream");
    439   P.printNumber("Dbi Version", DS->getDbiVersion());
    440   P.printNumber("Age", DS->getAge());
    441   P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
    442   P.printBoolean("Has CTypes", DS->hasCTypes());
    443   P.printBoolean("Is Stripped", DS->isStripped());
    444   P.printObject("Machine Type", DS->getMachineType());
    445   P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
    446   P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
    447   P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
    448 
    449   uint16_t Major = DS->getBuildMajorVersion();
    450   uint16_t Minor = DS->getBuildMinorVersion();
    451   P.printVersion("Toolchain Version", Major, Minor);
    452 
    453   std::string DllName;
    454   raw_string_ostream DllStream(DllName);
    455   DllStream << "mspdb" << Major << Minor << ".dll version";
    456   DllStream.flush();
    457   P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
    458 
    459   if (DumpModules) {
    460     ListScope L(P, "Modules");
    461     for (auto &Modi : DS->modules()) {
    462       DictScope DD(P);
    463       P.printString("Name", Modi.Info.getModuleName().str());
    464       P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
    465       P.printString("Object File Name", Modi.Info.getObjFileName().str());
    466       P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
    467       P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
    468       P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
    469       P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize());
    470       P.printNumber("C13 Line Info Byte Size",
    471                     Modi.Info.getC13LineInfoByteSize());
    472       P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize());
    473       P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex());
    474       P.printBoolean("Has EC Info", Modi.Info.hasECInfo());
    475       if (opts::raw::DumpModuleFiles) {
    476         std::string FileListName =
    477             to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
    478         ListScope LL(P, FileListName);
    479         for (auto File : Modi.SourceFiles)
    480           P.printString(File.str());
    481       }
    482       bool HasModuleDI =
    483           (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
    484       bool ShouldDumpSymbols =
    485           (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
    486       if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) {
    487         auto ModStreamData = MappedBlockStream::createIndexedStream(
    488             Modi.Info.getModuleStreamIndex(), File);
    489         if (!ModStreamData)
    490           return ModStreamData.takeError();
    491         ModStream ModS(Modi.Info, std::move(*ModStreamData));
    492         if (auto EC = ModS.reload())
    493           return EC;
    494 
    495         if (ShouldDumpSymbols) {
    496           ListScope SS(P, "Symbols");
    497           codeview::CVSymbolDumper SD(P, TD, nullptr, false);
    498           bool HadError = false;
    499           for (const auto &S : ModS.symbols(&HadError)) {
    500             DictScope DD(P, "");
    501 
    502             if (opts::raw::DumpModuleSyms)
    503               SD.dump(S);
    504             if (opts::raw::DumpSymRecordBytes)
    505               P.printBinaryBlock("Bytes", S.Data);
    506           }
    507           if (HadError)
    508             return make_error<RawError>(
    509                 raw_error_code::corrupt_file,
    510                 "DBI stream contained corrupt symbol record");
    511         }
    512         if (opts::raw::DumpLineInfo) {
    513           ListScope SS(P, "LineInfo");
    514           bool HadError = false;
    515           // Define a locally scoped visitor to print the different
    516           // substream types types.
    517           class RecordVisitor : public codeview::IModuleSubstreamVisitor {
    518           public:
    519             RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
    520             Error visitUnknown(ModuleSubstreamKind Kind,
    521                                StreamRef Stream) override {
    522               DictScope DD(P, "Unknown");
    523               ArrayRef<uint8_t> Data;
    524               StreamReader R(Stream);
    525               if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
    526                 return make_error<RawError>(
    527                     raw_error_code::corrupt_file,
    528                     "DBI stream contained corrupt line info record");
    529               }
    530               P.printBinaryBlock("Data", Data);
    531               return Error::success();
    532             }
    533             Error
    534             visitFileChecksums(StreamRef Data,
    535                                const FileChecksumArray &Checksums) override {
    536               DictScope DD(P, "FileChecksums");
    537               for (const auto &C : Checksums) {
    538                 DictScope DDD(P, "Checksum");
    539                 if (auto Result = getFileNameForOffset(C.FileNameOffset))
    540                   P.printString("FileName", Result.get());
    541                 else
    542                   return Result.takeError();
    543                 P.flush();
    544                 P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames());
    545                 P.printBinaryBlock("Checksum", C.Checksum);
    546               }
    547               return Error::success();
    548             }
    549 
    550             Error visitLines(StreamRef Data, const LineSubstreamHeader *Header,
    551                              const LineInfoArray &Lines) override {
    552               DictScope DD(P, "Lines");
    553               for (const auto &L : Lines) {
    554                 if (auto Result = getFileNameForOffset2(L.NameIndex))
    555                   P.printString("FileName", Result.get());
    556                 else
    557                   return Result.takeError();
    558                 P.flush();
    559                 for (const auto &N : L.LineNumbers) {
    560                   DictScope DDD(P, "Line");
    561                   LineInfo LI(N.Flags);
    562                   P.printNumber("Offset", N.Offset);
    563                   if (LI.isAlwaysStepInto())
    564                     P.printString("StepInto", StringRef("Always"));
    565                   else if (LI.isNeverStepInto())
    566                     P.printString("StepInto", StringRef("Never"));
    567                   else
    568                     P.printNumber("LineNumberStart", LI.getStartLine());
    569                   P.printNumber("EndDelta", LI.getLineDelta());
    570                   P.printBoolean("IsStatement", LI.isStatement());
    571                 }
    572                 for (const auto &C : L.Columns) {
    573                   DictScope DDD(P, "Column");
    574                   P.printNumber("Start", C.StartColumn);
    575                   P.printNumber("End", C.EndColumn);
    576                 }
    577               }
    578               return Error::success();
    579             }
    580 
    581           private:
    582             Expected<StringRef> getFileNameForOffset(uint32_t Offset) {
    583               auto ST = F.getStringTable();
    584               if (!ST)
    585                 return ST.takeError();
    586 
    587               return ST->getStringForID(Offset);
    588             }
    589             Expected<StringRef> getFileNameForOffset2(uint32_t Offset) {
    590               auto DS = F.getPDBDbiStream();
    591               if (!DS)
    592                 return DS.takeError();
    593               return DS->getFileNameForIndex(Offset);
    594             }
    595             ScopedPrinter &P;
    596             PDBFile &F;
    597           };
    598 
    599           RecordVisitor V(P, File);
    600           for (const auto &L : ModS.lines(&HadError)) {
    601             if (auto EC = codeview::visitModuleSubstream(L, V))
    602               return EC;
    603           }
    604         }
    605       }
    606     }
    607   }
    608   return Error::success();
    609 }
    610 
    611 Error LLVMOutputStyle::dumpSectionContribs() {
    612   if (!opts::raw::DumpSectionContribs)
    613     return Error::success();
    614 
    615   auto Dbi = File.getPDBDbiStream();
    616   if (!Dbi)
    617     return Dbi.takeError();
    618 
    619   ListScope L(P, "Section Contributions");
    620   class Visitor : public ISectionContribVisitor {
    621   public:
    622     Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
    623     void visit(const SectionContrib &SC) override {
    624       DictScope D(P, "Contribution");
    625       P.printNumber("ISect", SC.ISect);
    626       P.printNumber("Off", SC.Off);
    627       P.printNumber("Size", SC.Size);
    628       P.printFlags("Characteristics", SC.Characteristics,
    629                    codeview::getImageSectionCharacteristicNames(),
    630                    COFF::SectionCharacteristics(0x00F00000));
    631       {
    632         DictScope DD(P, "Module");
    633         P.printNumber("Index", SC.Imod);
    634         auto M = DS.modules();
    635         if (M.size() > SC.Imod) {
    636           P.printString("Name", M[SC.Imod].Info.getModuleName());
    637         }
    638       }
    639       P.printNumber("Data CRC", SC.DataCrc);
    640       P.printNumber("Reloc CRC", SC.RelocCrc);
    641       P.flush();
    642     }
    643     void visit(const SectionContrib2 &SC) override {
    644       visit(SC.Base);
    645       P.printNumber("ISect Coff", SC.ISectCoff);
    646       P.flush();
    647     }
    648 
    649   private:
    650     ScopedPrinter &P;
    651     DbiStream &DS;
    652   };
    653   Visitor V(P, *Dbi);
    654   Dbi->visitSectionContributions(V);
    655   return Error::success();
    656 }
    657 
    658 Error LLVMOutputStyle::dumpSectionMap() {
    659   if (!opts::raw::DumpSectionMap)
    660     return Error::success();
    661 
    662   auto Dbi = File.getPDBDbiStream();
    663   if (!Dbi)
    664     return Dbi.takeError();
    665 
    666   ListScope L(P, "Section Map");
    667   for (auto &M : Dbi->getSectionMap()) {
    668     DictScope D(P, "Entry");
    669     P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
    670     P.printNumber("Flags", M.Flags);
    671     P.printNumber("Ovl", M.Ovl);
    672     P.printNumber("Group", M.Group);
    673     P.printNumber("Frame", M.Frame);
    674     P.printNumber("SecName", M.SecName);
    675     P.printNumber("ClassName", M.ClassName);
    676     P.printNumber("Offset", M.Offset);
    677     P.printNumber("SecByteLength", M.SecByteLength);
    678     P.flush();
    679   }
    680   return Error::success();
    681 }
    682 
    683 Error LLVMOutputStyle::dumpPublicsStream() {
    684   if (!opts::raw::DumpPublics)
    685     return Error::success();
    686 
    687   DictScope D(P, "Publics Stream");
    688   auto Publics = File.getPDBPublicsStream();
    689   if (!Publics)
    690     return Publics.takeError();
    691 
    692   auto Dbi = File.getPDBDbiStream();
    693   if (!Dbi)
    694     return Dbi.takeError();
    695 
    696   P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
    697   P.printNumber("SymHash", Publics->getSymHash());
    698   P.printNumber("AddrMap", Publics->getAddrMap());
    699   P.printNumber("Number of buckets", Publics->getNumBuckets());
    700   P.printList("Hash Buckets", Publics->getHashBuckets());
    701   P.printList("Address Map", Publics->getAddressMap());
    702   P.printList("Thunk Map", Publics->getThunkMap());
    703   P.printList("Section Offsets", Publics->getSectionOffsets(),
    704               printSectionOffset);
    705   ListScope L(P, "Symbols");
    706   codeview::CVSymbolDumper SD(P, TD, nullptr, false);
    707   bool HadError = false;
    708   for (auto S : Publics->getSymbols(&HadError)) {
    709     DictScope DD(P, "");
    710 
    711     SD.dump(S);
    712     if (opts::raw::DumpSymRecordBytes)
    713       P.printBinaryBlock("Bytes", S.Data);
    714   }
    715   if (HadError)
    716     return make_error<RawError>(
    717         raw_error_code::corrupt_file,
    718         "Public symbol stream contained corrupt record");
    719 
    720   return Error::success();
    721 }
    722 
    723 Error LLVMOutputStyle::dumpSectionHeaders() {
    724   if (!opts::raw::DumpSectionHeaders)
    725     return Error::success();
    726 
    727   auto Dbi = File.getPDBDbiStream();
    728   if (!Dbi)
    729     return Dbi.takeError();
    730 
    731   ListScope D(P, "Section Headers");
    732   for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
    733     DictScope DD(P, "");
    734 
    735     // If a name is 8 characters long, there is no NUL character at end.
    736     StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
    737     P.printString("Name", Name);
    738     P.printNumber("Virtual Size", Section.VirtualSize);
    739     P.printNumber("Virtual Address", Section.VirtualAddress);
    740     P.printNumber("Size of Raw Data", Section.SizeOfRawData);
    741     P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
    742     P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
    743     P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
    744     P.printNumber("Number of Relocations", Section.NumberOfRelocations);
    745     P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
    746     P.printFlags("Characteristics", Section.Characteristics,
    747                  getImageSectionCharacteristicNames());
    748   }
    749   return Error::success();
    750 }
    751 
    752 Error LLVMOutputStyle::dumpFpoStream() {
    753   if (!opts::raw::DumpFpo)
    754     return Error::success();
    755 
    756   auto Dbi = File.getPDBDbiStream();
    757   if (!Dbi)
    758     return Dbi.takeError();
    759 
    760   ListScope D(P, "New FPO");
    761   for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
    762     DictScope DD(P, "");
    763     P.printNumber("Offset", Fpo.Offset);
    764     P.printNumber("Size", Fpo.Size);
    765     P.printNumber("Number of locals", Fpo.NumLocals);
    766     P.printNumber("Number of params", Fpo.NumParams);
    767     P.printNumber("Size of Prolog", Fpo.getPrologSize());
    768     P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
    769     P.printBoolean("Has SEH", Fpo.hasSEH());
    770     P.printBoolean("Use BP", Fpo.useBP());
    771     P.printNumber("Frame Pointer", Fpo.getFP());
    772   }
    773   return Error::success();
    774 }
    775 
    776 void LLVMOutputStyle::flush() { P.flush(); }
    777