]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp
Upgrade to OpenSSH 7.4p1.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-pdbdump / LLVMOutputStyle.cpp
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/CVTypeDumper.h"
14 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
15 #include "llvm/DebugInfo/CodeView/EnumTables.h"
16 #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
17 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
18 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
19 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
20 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
21 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
22 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
23 #include "llvm/DebugInfo/MSF/StreamReader.h"
24 #include "llvm/DebugInfo/PDB/PDBExtras.h"
25 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
26 #include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
27 #include "llvm/DebugInfo/PDB/Raw/GlobalsStream.h"
28 #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
29 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
30 #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
31 #include "llvm/DebugInfo/PDB/Raw/ModStream.h"
32 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
33 #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
34 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
35 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
36 #include "llvm/Object/COFF.h"
37
38 #include <unordered_map>
39
40 using namespace llvm;
41 using namespace llvm::codeview;
42 using namespace llvm::msf;
43 using namespace llvm::pdb;
44
45 namespace {
46 struct PageStats {
47   explicit PageStats(const BitVector &FreePages)
48       : Upm(FreePages), ActualUsedPages(FreePages.size()),
49         MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) {
50     const_cast<BitVector &>(Upm).flip();
51     // To calculate orphaned pages, we start with the set of pages that the
52     // MSF thinks are used.  Each time we find one that actually *is* used,
53     // we unset it.  Whichever bits remain set at the end are orphaned.
54     OrphanedPages = Upm;
55   }
56
57   // The inverse of the MSF File's copy of the Fpm.  The basis for which we
58   // determine the allocation status of each page.
59   const BitVector Upm;
60
61   // Pages which are marked as used in the FPM and are used at least once.
62   BitVector ActualUsedPages;
63
64   // Pages which are marked as used in the FPM but are used more than once.
65   BitVector MultiUsePages;
66
67   // Pages which are marked as used in the FPM but are not used at all.
68   BitVector OrphanedPages;
69
70   // Pages which are marked free in the FPM but are used.
71   BitVector UseAfterFreePages;
72 };
73 }
74
75 static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) {
76   if (Stats.Upm.test(UsedIndex)) {
77     if (Stats.ActualUsedPages.test(UsedIndex))
78       Stats.MultiUsePages.set(UsedIndex);
79     Stats.ActualUsedPages.set(UsedIndex);
80     Stats.OrphanedPages.reset(UsedIndex);
81   } else {
82     // The MSF doesn't think this page is used, but it is.
83     Stats.UseAfterFreePages.set(UsedIndex);
84   }
85 }
86
87 static void printSectionOffset(llvm::raw_ostream &OS,
88                                const SectionOffset &Off) {
89   OS << Off.Off << ", " << Off.Isect;
90 }
91
92 LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {}
93
94 Error LLVMOutputStyle::dump() {
95   if (auto EC = dumpFileHeaders())
96     return EC;
97
98   if (auto EC = dumpStreamSummary())
99     return EC;
100
101   if (auto EC = dumpFreePageMap())
102     return EC;
103
104   if (auto EC = dumpStreamBlocks())
105     return EC;
106
107   if (auto EC = dumpBlockRanges())
108     return EC;
109
110   if (auto EC = dumpStreamBytes())
111     return EC;
112
113   if (auto EC = dumpInfoStream())
114     return EC;
115
116   if (auto EC = dumpTpiStream(StreamTPI))
117     return EC;
118
119   if (auto EC = dumpTpiStream(StreamIPI))
120     return EC;
121
122   if (auto EC = dumpDbiStream())
123     return EC;
124
125   if (auto EC = dumpSectionContribs())
126     return EC;
127
128   if (auto EC = dumpSectionMap())
129     return EC;
130
131   if (auto EC = dumpGlobalsStream())
132     return EC;
133
134   if (auto EC = dumpPublicsStream())
135     return EC;
136
137   if (auto EC = dumpSectionHeaders())
138     return EC;
139
140   if (auto EC = dumpFpoStream())
141     return EC;
142
143   flush();
144
145   return Error::success();
146 }
147
148 Error LLVMOutputStyle::dumpFileHeaders() {
149   if (!opts::raw::DumpHeaders)
150     return Error::success();
151
152   DictScope D(P, "FileHeaders");
153   P.printNumber("BlockSize", File.getBlockSize());
154   P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
155   P.printNumber("NumBlocks", File.getBlockCount());
156   P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
157   P.printNumber("Unknown1", File.getUnknown1());
158   P.printNumber("BlockMapAddr", File.getBlockMapIndex());
159   P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
160
161   // The directory is not contiguous.  Instead, the block map contains a
162   // contiguous list of block numbers whose contents, when concatenated in
163   // order, make up the directory.
164   P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
165   P.printNumber("NumStreams", File.getNumStreams());
166   return Error::success();
167 }
168
169 void LLVMOutputStyle::discoverStreamPurposes() {
170   if (!StreamPurposes.empty())
171     return;
172
173   // It's OK if we fail to load some of these streams, we still attempt to print
174   // what we can.
175   auto Dbi = File.getPDBDbiStream();
176   auto Tpi = File.getPDBTpiStream();
177   auto Ipi = File.getPDBIpiStream();
178   auto Info = File.getPDBInfoStream();
179
180   uint32_t StreamCount = File.getNumStreams();
181   std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
182   std::unordered_map<uint16_t, std::string> NamedStreams;
183
184   if (Dbi) {
185     for (auto &ModI : Dbi->modules()) {
186       uint16_t SN = ModI.Info.getModuleStreamIndex();
187       ModStreams[SN] = &ModI;
188     }
189   }
190   if (Info) {
191     for (auto &NSE : Info->named_streams()) {
192       NamedStreams[NSE.second] = NSE.first();
193     }
194   }
195
196   StreamPurposes.resize(StreamCount);
197   for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
198     std::string Value;
199     if (StreamIdx == OldMSFDirectory)
200       Value = "Old MSF Directory";
201     else if (StreamIdx == StreamPDB)
202       Value = "PDB Stream";
203     else if (StreamIdx == StreamDBI)
204       Value = "DBI Stream";
205     else if (StreamIdx == StreamTPI)
206       Value = "TPI Stream";
207     else if (StreamIdx == StreamIPI)
208       Value = "IPI Stream";
209     else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
210       Value = "Global Symbol Hash";
211     else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
212       Value = "Public Symbol Hash";
213     else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
214       Value = "Public Symbol Records";
215     else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
216       Value = "TPI Hash";
217     else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
218       Value = "TPI Aux Hash";
219     else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
220       Value = "IPI Hash";
221     else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
222       Value = "IPI Aux Hash";
223     else if (Dbi &&
224              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
225       Value = "Exception Data";
226     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
227       Value = "Fixup Data";
228     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
229       Value = "FPO Data";
230     else if (Dbi &&
231              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
232       Value = "New FPO Data";
233     else if (Dbi &&
234              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
235       Value = "Omap From Source Data";
236     else if (Dbi &&
237              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
238       Value = "Omap To Source Data";
239     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
240       Value = "Pdata";
241     else if (Dbi &&
242              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
243       Value = "Section Header Data";
244     else if (Dbi &&
245              StreamIdx ==
246                  Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
247       Value = "Section Header Original Data";
248     else if (Dbi &&
249              StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
250       Value = "Token Rid Data";
251     else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
252       Value = "Xdata";
253     else {
254       auto ModIter = ModStreams.find(StreamIdx);
255       auto NSIter = NamedStreams.find(StreamIdx);
256       if (ModIter != ModStreams.end()) {
257         Value = "Module \"";
258         Value += ModIter->second->Info.getModuleName().str();
259         Value += "\"";
260       } else if (NSIter != NamedStreams.end()) {
261         Value = "Named Stream \"";
262         Value += NSIter->second;
263         Value += "\"";
264       } else {
265         Value = "???";
266       }
267     }
268     StreamPurposes[StreamIdx] = Value;
269   }
270
271   // Consume errors from missing streams.
272   if (!Dbi)
273     consumeError(Dbi.takeError());
274   if (!Tpi)
275     consumeError(Tpi.takeError());
276   if (!Ipi)
277     consumeError(Ipi.takeError());
278   if (!Info)
279     consumeError(Info.takeError());
280 }
281
282 Error LLVMOutputStyle::dumpStreamSummary() {
283   if (!opts::raw::DumpStreamSummary)
284     return Error::success();
285
286   discoverStreamPurposes();
287
288   uint32_t StreamCount = File.getNumStreams();
289
290   ListScope L(P, "Streams");
291   for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
292     std::string Label("Stream ");
293     Label += to_string(StreamIdx);
294
295     std::string Value = "[" + StreamPurposes[StreamIdx] + "] (";
296     Value += to_string(File.getStreamByteSize(StreamIdx));
297     Value += " bytes)";
298
299     P.printString(Label, Value);
300   }
301
302   P.flush();
303   return Error::success();
304 }
305
306 Error LLVMOutputStyle::dumpFreePageMap() {
307   if (!opts::raw::DumpPageStats)
308     return Error::success();
309
310   // Start with used pages instead of free pages because
311   // the number of free pages is far larger than used pages.
312   BitVector FPM = File.getMsfLayout().FreePageMap;
313
314   PageStats PS(FPM);
315
316   recordKnownUsedPage(PS, 0); // MSF Super Block
317
318   uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout());
319   uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout());
320   for (uint32_t I = 0; I < NumSections; ++I) {
321     uint32_t Fpm0 = 1 + BlocksPerSection * I;
322     // 2 Fpm blocks spaced at `getBlockSize()` block intervals
323     recordKnownUsedPage(PS, Fpm0);
324     recordKnownUsedPage(PS, Fpm0 + 1);
325   }
326
327   recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table
328
329   for (auto DB : File.getDirectoryBlockArray())
330     recordKnownUsedPage(PS, DB);
331
332   // Record pages used by streams. Note that pages for stream 0
333   // are considered being unused because that's what MSVC tools do.
334   // Stream 0 doesn't contain actual data, so it makes some sense,
335   // though it's a bit confusing to us.
336   for (auto &SE : File.getStreamMap().drop_front(1))
337     for (auto &S : SE)
338       recordKnownUsedPage(PS, S);
339
340   dumpBitVector("Msf Free Pages", FPM);
341   dumpBitVector("Orphaned Pages", PS.OrphanedPages);
342   dumpBitVector("Multiply Used Pages", PS.MultiUsePages);
343   dumpBitVector("Use After Free Pages", PS.UseAfterFreePages);
344   return Error::success();
345 }
346
347 void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) {
348   std::vector<uint32_t> Vec;
349   for (uint32_t I = 0, E = V.size(); I != E; ++I)
350     if (V[I])
351       Vec.push_back(I);
352   P.printList(Name, Vec);
353 }
354
355 Error LLVMOutputStyle::dumpGlobalsStream() {
356   if (!opts::raw::DumpGlobals)
357     return Error::success();
358   if (!File.hasPDBGlobalsStream()) {
359     P.printString("Globals Stream not present");
360     return Error::success();
361   }
362
363   auto Globals = File.getPDBGlobalsStream();
364   if (!Globals)
365     return Globals.takeError();
366   DictScope D(P, "Globals Stream");
367
368   auto Dbi = File.getPDBDbiStream();
369   if (!Dbi)
370     return Dbi.takeError();
371
372   P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex());
373   P.printNumber("Number of buckets", Globals->getNumBuckets());
374   P.printList("Hash Buckets", Globals->getHashBuckets());
375
376   return Error::success();
377 }
378
379 Error LLVMOutputStyle::dumpStreamBlocks() {
380   if (!opts::raw::DumpStreamBlocks)
381     return Error::success();
382
383   ListScope L(P, "StreamBlocks");
384   uint32_t StreamCount = File.getNumStreams();
385   for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
386     std::string Name("Stream ");
387     Name += to_string(StreamIdx);
388     auto StreamBlocks = File.getStreamBlockList(StreamIdx);
389     P.printList(Name, StreamBlocks);
390   }
391   return Error::success();
392 }
393
394 Error LLVMOutputStyle::dumpBlockRanges() {
395   if (!opts::raw::DumpBlockRange.hasValue())
396     return Error::success();
397   auto &R = *opts::raw::DumpBlockRange;
398   uint32_t Max = R.Max.getValueOr(R.Min);
399
400   if (Max < R.Min)
401     return make_error<StringError>(
402         "Invalid block range specified.  Max < Min",
403         std::make_error_code(std::errc::bad_address));
404   if (Max >= File.getBlockCount())
405     return make_error<StringError>(
406         "Invalid block range specified.  Requested block out of bounds",
407         std::make_error_code(std::errc::bad_address));
408
409   DictScope D(P, "Block Data");
410   for (uint32_t I = R.Min; I <= Max; ++I) {
411     auto ExpectedData = File.getBlockData(I, File.getBlockSize());
412     if (!ExpectedData)
413       return ExpectedData.takeError();
414     std::string Label;
415     llvm::raw_string_ostream S(Label);
416     S << "Block " << I;
417     S.flush();
418     P.printBinaryBlock(Label, *ExpectedData);
419   }
420
421   return Error::success();
422 }
423
424 Error LLVMOutputStyle::dumpStreamBytes() {
425   if (opts::raw::DumpStreamData.empty())
426     return Error::success();
427
428   discoverStreamPurposes();
429
430   DictScope D(P, "Stream Data");
431   for (uint32_t SI : opts::raw::DumpStreamData) {
432     if (SI >= File.getNumStreams())
433       return make_error<RawError>(raw_error_code::no_stream);
434
435     auto S = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
436                                                     File.getMsfBuffer(), SI);
437     if (!S)
438       continue;
439     DictScope DD(P, "Stream");
440
441     P.printNumber("Index", SI);
442     P.printString("Type", StreamPurposes[SI]);
443     P.printNumber("Size", S->getLength());
444     auto Blocks = File.getMsfLayout().StreamMap[SI];
445     P.printList("Blocks", Blocks);
446
447     StreamReader R(*S);
448     ArrayRef<uint8_t> StreamData;
449     if (auto EC = R.readBytes(StreamData, S->getLength()))
450       return EC;
451     P.printBinaryBlock("Data", StreamData);
452   }
453   return Error::success();
454 }
455
456 Error LLVMOutputStyle::dumpInfoStream() {
457   if (!opts::raw::DumpHeaders)
458     return Error::success();
459   if (!File.hasPDBInfoStream()) {
460     P.printString("PDB Stream not present");
461     return Error::success();
462   }
463   auto IS = File.getPDBInfoStream();
464   if (!IS)
465     return IS.takeError();
466
467   DictScope D(P, "PDB Stream");
468   P.printNumber("Version", IS->getVersion());
469   P.printHex("Signature", IS->getSignature());
470   P.printNumber("Age", IS->getAge());
471   P.printObject("Guid", IS->getGuid());
472   return Error::success();
473 }
474
475 static void printTypeIndexOffset(raw_ostream &OS,
476                                  const TypeIndexOffset &TIOff) {
477   OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
478 }
479
480 static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
481   if (!opts::raw::DumpTpiHash)
482     return;
483   DictScope DD(P, "Hash");
484   P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
485   P.printNumber("Hash Key Size", Tpi.getHashKeySize());
486   P.printList("Values", Tpi.getHashValues());
487   P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
488               printTypeIndexOffset);
489   P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
490               printTypeIndexOffset);
491 }
492
493 Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
494   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
495
496   bool DumpRecordBytes = false;
497   bool DumpRecords = false;
498   StringRef Label;
499   StringRef VerLabel;
500   if (StreamIdx == StreamTPI) {
501     if (!File.hasPDBTpiStream()) {
502       P.printString("Type Info Stream (TPI) not present");
503       return Error::success();
504     }
505     DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
506     DumpRecords = opts::raw::DumpTpiRecords;
507     Label = "Type Info Stream (TPI)";
508     VerLabel = "TPI Version";
509   } else if (StreamIdx == StreamIPI) {
510     if (!File.hasPDBIpiStream()) {
511       P.printString("Type Info Stream (IPI) not present");
512       return Error::success();
513     }
514     DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
515     DumpRecords = opts::raw::DumpIpiRecords;
516     Label = "Type Info Stream (IPI)";
517     VerLabel = "IPI Version";
518   }
519   if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
520     return Error::success();
521
522   auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
523                                       : File.getPDBIpiStream();
524   if (!Tpi)
525     return Tpi.takeError();
526
527   CVTypeDumper Dumper(TypeDB);
528   if (DumpRecords || DumpRecordBytes) {
529     DictScope D(P, Label);
530
531     P.printNumber(VerLabel, Tpi->getTpiVersion());
532     P.printNumber("Record count", Tpi->NumTypeRecords());
533
534     ListScope L(P, "Records");
535
536     bool HadError = false;
537     for (auto &Type : Tpi->types(&HadError)) {
538       DictScope DD(P, "");
539
540       if (DumpRecords) {
541         TypeDumpVisitor TDV(TypeDB, &P, false);
542         if (auto EC = Dumper.dump(Type, TDV))
543           return EC;
544       }
545
546       if (DumpRecordBytes)
547         P.printBinaryBlock("Bytes", Type.content());
548     }
549     dumpTpiHash(P, *Tpi);
550     if (HadError)
551       return make_error<RawError>(raw_error_code::corrupt_file,
552                                   "TPI stream contained corrupt record");
553   } else if (opts::raw::DumpModuleSyms) {
554     // Even if the user doesn't want to dump type records, we still need to
555     // iterate them in order to build the type database. So when they want to
556     // dump symbols but not types, don't stick a dumper on the end, just build
557     // the type database.
558     TypeDatabaseVisitor DBV(TypeDB);
559     TypeDeserializer Deserializer;
560     TypeVisitorCallbackPipeline Pipeline;
561     Pipeline.addCallbackToPipeline(Deserializer);
562     Pipeline.addCallbackToPipeline(DBV);
563
564     CVTypeVisitor Visitor(Pipeline);
565
566     bool HadError = false;
567     for (auto Type : Tpi->types(&HadError)) {
568       if (auto EC = Visitor.visitTypeRecord(Type))
569         return EC;
570     }
571
572     dumpTpiHash(P, *Tpi);
573     if (HadError)
574       return make_error<RawError>(raw_error_code::corrupt_file,
575                                   "TPI stream contained corrupt record");
576   }
577   P.flush();
578   return Error::success();
579 }
580
581 Error LLVMOutputStyle::dumpDbiStream() {
582   bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms ||
583                      opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo;
584   if (!opts::raw::DumpHeaders && !DumpModules)
585     return Error::success();
586   if (!File.hasPDBDbiStream()) {
587     P.printString("DBI Stream not present");
588     return Error::success();
589   }
590
591   auto DS = File.getPDBDbiStream();
592   if (!DS)
593     return DS.takeError();
594
595   DictScope D(P, "DBI Stream");
596   P.printNumber("Dbi Version", DS->getDbiVersion());
597   P.printNumber("Age", DS->getAge());
598   P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
599   P.printBoolean("Has CTypes", DS->hasCTypes());
600   P.printBoolean("Is Stripped", DS->isStripped());
601   P.printObject("Machine Type", DS->getMachineType());
602   P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
603   P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
604   P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
605
606   uint16_t Major = DS->getBuildMajorVersion();
607   uint16_t Minor = DS->getBuildMinorVersion();
608   P.printVersion("Toolchain Version", Major, Minor);
609
610   std::string DllName;
611   raw_string_ostream DllStream(DllName);
612   DllStream << "mspdb" << Major << Minor << ".dll version";
613   DllStream.flush();
614   P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
615
616   if (DumpModules) {
617     ListScope L(P, "Modules");
618     for (auto &Modi : DS->modules()) {
619       DictScope DD(P);
620       P.printString("Name", Modi.Info.getModuleName().str());
621       P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
622       P.printString("Object File Name", Modi.Info.getObjFileName().str());
623       P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
624       P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
625       P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
626       P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize());
627       P.printNumber("C13 Line Info Byte Size",
628                     Modi.Info.getC13LineInfoByteSize());
629       P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize());
630       P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex());
631       P.printBoolean("Has EC Info", Modi.Info.hasECInfo());
632       if (opts::raw::DumpModuleFiles) {
633         std::string FileListName =
634             to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
635         ListScope LL(P, FileListName);
636         for (auto File : Modi.SourceFiles)
637           P.printString(File.str());
638       }
639       bool HasModuleDI =
640           (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
641       bool ShouldDumpSymbols =
642           (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
643       if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) {
644         auto ModStreamData = MappedBlockStream::createIndexedStream(
645             File.getMsfLayout(), File.getMsfBuffer(),
646             Modi.Info.getModuleStreamIndex());
647
648         ModStream ModS(Modi.Info, std::move(ModStreamData));
649         if (auto EC = ModS.reload())
650           return EC;
651
652         if (ShouldDumpSymbols) {
653           ListScope SS(P, "Symbols");
654           codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
655           bool HadError = false;
656           for (auto S : ModS.symbols(&HadError)) {
657             DictScope LL(P, "");
658             if (opts::raw::DumpModuleSyms) {
659               if (auto EC = SD.dump(S)) {
660                 llvm::consumeError(std::move(EC));
661                 HadError = true;
662                 break;
663               }
664             }
665             if (opts::raw::DumpSymRecordBytes)
666               P.printBinaryBlock("Bytes", S.content());
667           }
668           if (HadError)
669             return make_error<RawError>(
670                 raw_error_code::corrupt_file,
671                 "DBI stream contained corrupt symbol record");
672         }
673         if (opts::raw::DumpLineInfo) {
674           ListScope SS(P, "LineInfo");
675           bool HadError = false;
676           // Define a locally scoped visitor to print the different
677           // substream types types.
678           class RecordVisitor : public codeview::IModuleSubstreamVisitor {
679           public:
680             RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
681             Error visitUnknown(ModuleSubstreamKind Kind,
682                                ReadableStreamRef Stream) override {
683               DictScope DD(P, "Unknown");
684               ArrayRef<uint8_t> Data;
685               StreamReader R(Stream);
686               if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
687                 return make_error<RawError>(
688                     raw_error_code::corrupt_file,
689                     "DBI stream contained corrupt line info record");
690               }
691               P.printBinaryBlock("Data", Data);
692               return Error::success();
693             }
694             Error
695             visitFileChecksums(ReadableStreamRef Data,
696                                const FileChecksumArray &Checksums) override {
697               DictScope DD(P, "FileChecksums");
698               for (const auto &C : Checksums) {
699                 DictScope DDD(P, "Checksum");
700                 if (auto Result = getFileNameForOffset(C.FileNameOffset))
701                   P.printString("FileName", Result.get());
702                 else
703                   return Result.takeError();
704                 P.flush();
705                 P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames());
706                 P.printBinaryBlock("Checksum", C.Checksum);
707               }
708               return Error::success();
709             }
710
711             Error visitLines(ReadableStreamRef Data,
712                              const LineSubstreamHeader *Header,
713                              const LineInfoArray &Lines) override {
714               DictScope DD(P, "Lines");
715               for (const auto &L : Lines) {
716                 if (auto Result = getFileNameForOffset2(L.NameIndex))
717                   P.printString("FileName", Result.get());
718                 else
719                   return Result.takeError();
720                 P.flush();
721                 for (const auto &N : L.LineNumbers) {
722                   DictScope DDD(P, "Line");
723                   LineInfo LI(N.Flags);
724                   P.printNumber("Offset", N.Offset);
725                   if (LI.isAlwaysStepInto())
726                     P.printString("StepInto", StringRef("Always"));
727                   else if (LI.isNeverStepInto())
728                     P.printString("StepInto", StringRef("Never"));
729                   else
730                     P.printNumber("LineNumberStart", LI.getStartLine());
731                   P.printNumber("EndDelta", LI.getLineDelta());
732                   P.printBoolean("IsStatement", LI.isStatement());
733                 }
734                 for (const auto &C : L.Columns) {
735                   DictScope DDD(P, "Column");
736                   P.printNumber("Start", C.StartColumn);
737                   P.printNumber("End", C.EndColumn);
738                 }
739               }
740               return Error::success();
741             }
742
743           private:
744             Expected<StringRef> getFileNameForOffset(uint32_t Offset) {
745               auto ST = F.getStringTable();
746               if (!ST)
747                 return ST.takeError();
748
749               return ST->getStringForID(Offset);
750             }
751             Expected<StringRef> getFileNameForOffset2(uint32_t Offset) {
752               auto DS = F.getPDBDbiStream();
753               if (!DS)
754                 return DS.takeError();
755               return DS->getFileNameForIndex(Offset);
756             }
757             ScopedPrinter &P;
758             PDBFile &F;
759           };
760
761           RecordVisitor V(P, File);
762           for (const auto &L : ModS.lines(&HadError)) {
763             if (auto EC = codeview::visitModuleSubstream(L, V))
764               return EC;
765           }
766         }
767       }
768     }
769   }
770   return Error::success();
771 }
772
773 Error LLVMOutputStyle::dumpSectionContribs() {
774   if (!opts::raw::DumpSectionContribs)
775     return Error::success();
776   if (!File.hasPDBDbiStream()) {
777     P.printString("DBI Stream not present");
778     return Error::success();
779   }
780
781   auto Dbi = File.getPDBDbiStream();
782   if (!Dbi)
783     return Dbi.takeError();
784
785   ListScope L(P, "Section Contributions");
786   class Visitor : public ISectionContribVisitor {
787   public:
788     Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
789     void visit(const SectionContrib &SC) override {
790       DictScope D(P, "Contribution");
791       P.printNumber("ISect", SC.ISect);
792       P.printNumber("Off", SC.Off);
793       P.printNumber("Size", SC.Size);
794       P.printFlags("Characteristics", SC.Characteristics,
795                    codeview::getImageSectionCharacteristicNames(),
796                    COFF::SectionCharacteristics(0x00F00000));
797       {
798         DictScope DD(P, "Module");
799         P.printNumber("Index", SC.Imod);
800         auto M = DS.modules();
801         if (M.size() > SC.Imod) {
802           P.printString("Name", M[SC.Imod].Info.getModuleName());
803         }
804       }
805       P.printNumber("Data CRC", SC.DataCrc);
806       P.printNumber("Reloc CRC", SC.RelocCrc);
807       P.flush();
808     }
809     void visit(const SectionContrib2 &SC) override {
810       visit(SC.Base);
811       P.printNumber("ISect Coff", SC.ISectCoff);
812       P.flush();
813     }
814
815   private:
816     ScopedPrinter &P;
817     DbiStream &DS;
818   };
819   Visitor V(P, *Dbi);
820   Dbi->visitSectionContributions(V);
821   return Error::success();
822 }
823
824 Error LLVMOutputStyle::dumpSectionMap() {
825   if (!opts::raw::DumpSectionMap)
826     return Error::success();
827   if (!File.hasPDBDbiStream()) {
828     P.printString("DBI Stream not present");
829     return Error::success();
830   }
831
832   auto Dbi = File.getPDBDbiStream();
833   if (!Dbi)
834     return Dbi.takeError();
835
836   ListScope L(P, "Section Map");
837   for (auto &M : Dbi->getSectionMap()) {
838     DictScope D(P, "Entry");
839     P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
840     P.printNumber("Ovl", M.Ovl);
841     P.printNumber("Group", M.Group);
842     P.printNumber("Frame", M.Frame);
843     P.printNumber("SecName", M.SecName);
844     P.printNumber("ClassName", M.ClassName);
845     P.printNumber("Offset", M.Offset);
846     P.printNumber("SecByteLength", M.SecByteLength);
847     P.flush();
848   }
849   return Error::success();
850 }
851
852 Error LLVMOutputStyle::dumpPublicsStream() {
853   if (!opts::raw::DumpPublics)
854     return Error::success();
855   if (!File.hasPDBPublicsStream()) {
856     P.printString("Publics Stream not present");
857     return Error::success();
858   }
859
860   auto Publics = File.getPDBPublicsStream();
861   if (!Publics)
862     return Publics.takeError();
863   DictScope D(P, "Publics Stream");
864
865   auto Dbi = File.getPDBDbiStream();
866   if (!Dbi)
867     return Dbi.takeError();
868
869   P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
870   P.printNumber("SymHash", Publics->getSymHash());
871   P.printNumber("AddrMap", Publics->getAddrMap());
872   P.printNumber("Number of buckets", Publics->getNumBuckets());
873   P.printList("Hash Buckets", Publics->getHashBuckets());
874   P.printList("Address Map", Publics->getAddressMap());
875   P.printList("Thunk Map", Publics->getThunkMap());
876   P.printList("Section Offsets", Publics->getSectionOffsets(),
877               printSectionOffset);
878   ListScope L(P, "Symbols");
879   codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
880   bool HadError = false;
881   for (auto S : Publics->getSymbols(&HadError)) {
882     DictScope DD(P, "");
883
884     if (auto EC = SD.dump(S)) {
885       HadError = true;
886       break;
887     }
888     if (opts::raw::DumpSymRecordBytes)
889       P.printBinaryBlock("Bytes", S.content());
890   }
891   if (HadError)
892     return make_error<RawError>(
893         raw_error_code::corrupt_file,
894         "Public symbol stream contained corrupt record");
895
896   return Error::success();
897 }
898
899 Error LLVMOutputStyle::dumpSectionHeaders() {
900   if (!opts::raw::DumpSectionHeaders)
901     return Error::success();
902   if (!File.hasPDBDbiStream()) {
903     P.printString("DBI Stream not present");
904     return Error::success();
905   }
906
907   auto Dbi = File.getPDBDbiStream();
908   if (!Dbi)
909     return Dbi.takeError();
910
911   ListScope D(P, "Section Headers");
912   for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
913     DictScope DD(P, "");
914
915     // If a name is 8 characters long, there is no NUL character at end.
916     StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
917     P.printString("Name", Name);
918     P.printNumber("Virtual Size", Section.VirtualSize);
919     P.printNumber("Virtual Address", Section.VirtualAddress);
920     P.printNumber("Size of Raw Data", Section.SizeOfRawData);
921     P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
922     P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
923     P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
924     P.printNumber("Number of Relocations", Section.NumberOfRelocations);
925     P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
926     P.printFlags("Characteristics", Section.Characteristics,
927                  getImageSectionCharacteristicNames());
928   }
929   return Error::success();
930 }
931
932 Error LLVMOutputStyle::dumpFpoStream() {
933   if (!opts::raw::DumpFpo)
934     return Error::success();
935   if (!File.hasPDBDbiStream()) {
936     P.printString("DBI Stream not present");
937     return Error::success();
938   }
939
940   auto Dbi = File.getPDBDbiStream();
941   if (!Dbi)
942     return Dbi.takeError();
943
944   ListScope D(P, "New FPO");
945   for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
946     DictScope DD(P, "");
947     P.printNumber("Offset", Fpo.Offset);
948     P.printNumber("Size", Fpo.Size);
949     P.printNumber("Number of locals", Fpo.NumLocals);
950     P.printNumber("Number of params", Fpo.NumParams);
951     P.printNumber("Size of Prolog", Fpo.getPrologSize());
952     P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
953     P.printBoolean("Has SEH", Fpo.hasSEH());
954     P.printBoolean("Use BP", Fpo.useBP());
955     P.printNumber("Frame Pointer", Fpo.getFP());
956   }
957   return Error::success();
958 }
959
960 void LLVMOutputStyle::flush() { P.flush(); }