]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r305575, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-pdbutil / RawOutputStyle.cpp
1 //===- RawOutputStyle.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 "RawOutputStyle.h"
11
12 #include "CompactTypeDumpVisitor.h"
13 #include "FormatUtil.h"
14 #include "MinimalSymbolDumper.h"
15 #include "MinimalTypeDumper.h"
16 #include "StreamUtil.h"
17 #include "llvm-pdbutil.h"
18
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
21 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
22 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
25 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
28 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
30 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
31 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
32 #include "llvm/DebugInfo/CodeView/EnumTables.h"
33 #include "llvm/DebugInfo/CodeView/Formatters.h"
34 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
35 #include "llvm/DebugInfo/CodeView/Line.h"
36 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
37 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
38 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
39 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
40 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
41 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
42 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
43 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
44 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
45 #include "llvm/DebugInfo/PDB/Native/EnumTables.h"
46 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
47 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
48 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
49 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
50 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
51 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
52 #include "llvm/DebugInfo/PDB/Native/RawError.h"
53 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
54 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
55 #include "llvm/DebugInfo/PDB/PDBExtras.h"
56 #include "llvm/Object/COFF.h"
57 #include "llvm/Support/BinaryStreamReader.h"
58 #include "llvm/Support/FormatAdapters.h"
59 #include "llvm/Support/FormatVariadic.h"
60
61 #include <unordered_map>
62
63 using namespace llvm;
64 using namespace llvm::codeview;
65 using namespace llvm::msf;
66 using namespace llvm::pdb;
67
68 RawOutputStyle::RawOutputStyle(PDBFile &File)
69     : File(File), P(2, false, outs()) {}
70
71 Error RawOutputStyle::dump() {
72   if (opts::raw::DumpSummary) {
73     if (auto EC = dumpFileSummary())
74       return EC;
75     P.NewLine();
76   }
77
78   if (opts::raw::DumpStreams) {
79     if (auto EC = dumpStreamSummary())
80       return EC;
81     P.NewLine();
82   }
83
84   if (opts::raw::DumpBlockRange.hasValue()) {
85     if (auto EC = dumpBlockRanges())
86       return EC;
87     P.NewLine();
88   }
89
90   if (!opts::raw::DumpStreamData.empty()) {
91     if (auto EC = dumpStreamBytes())
92       return EC;
93     P.NewLine();
94   }
95
96   if (opts::raw::DumpStringTable) {
97     if (auto EC = dumpStringTable())
98       return EC;
99     P.NewLine();
100   }
101
102   if (opts::raw::DumpModules) {
103     if (auto EC = dumpModules())
104       return EC;
105   }
106
107   if (opts::raw::DumpModuleFiles) {
108     if (auto EC = dumpModuleFiles())
109       return EC;
110   }
111
112   if (opts::raw::DumpLines) {
113     if (auto EC = dumpLines())
114       return EC;
115   }
116
117   if (opts::raw::DumpInlineeLines) {
118     if (auto EC = dumpInlineeLines())
119       return EC;
120   }
121
122   if (opts::raw::DumpXmi) {
123     if (auto EC = dumpXmi())
124       return EC;
125   }
126
127   if (opts::raw::DumpXme) {
128     if (auto EC = dumpXme())
129       return EC;
130   }
131
132   if (opts::raw::DumpTypes || opts::raw::DumpTypeExtras) {
133     if (auto EC = dumpTpiStream(StreamTPI))
134       return EC;
135   }
136
137   if (opts::raw::DumpIds || opts::raw::DumpIdExtras) {
138     if (auto EC = dumpTpiStream(StreamIPI))
139       return EC;
140   }
141
142   if (opts::raw::DumpPublics) {
143     if (auto EC = dumpPublics())
144       return EC;
145   }
146
147   if (opts::raw::DumpSymbols) {
148     if (auto EC = dumpModuleSyms())
149       return EC;
150   }
151
152   if (opts::raw::DumpSectionContribs) {
153     if (auto EC = dumpSectionContribs())
154       return EC;
155   }
156
157   if (opts::raw::DumpSectionMap) {
158     if (auto EC = dumpSectionMap())
159       return EC;
160   }
161
162   return Error::success();
163 }
164
165 static void printHeader(LinePrinter &P, const Twine &S) {
166   P.NewLine();
167   P.formatLine("{0,=60}", S);
168   P.formatLine("{0}", fmt_repeat('=', 60));
169 }
170
171 Error RawOutputStyle::dumpFileSummary() {
172   printHeader(P, "Summary");
173
174   ExitOnError Err("Invalid PDB Format");
175
176   AutoIndent Indent(P);
177   P.formatLine("Block Size: {0}", File.getBlockSize());
178   P.formatLine("Number of blocks: {0}", File.getBlockCount());
179   P.formatLine("Number of streams: {0}", File.getNumStreams());
180
181   auto &PS = Err(File.getPDBInfoStream());
182   P.formatLine("Signature: {0}", PS.getSignature());
183   P.formatLine("Age: {0}", PS.getAge());
184   P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
185   P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
186   P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
187   P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
188   P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
189   P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
190   P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
191   if (File.hasPDBDbiStream()) {
192     auto &DBI = Err(File.getPDBDbiStream());
193     P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
194     P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
195     P.formatLine("Is stripped: {0}", DBI.isStripped());
196   }
197
198   return Error::success();
199 }
200
201 Error RawOutputStyle::dumpStreamSummary() {
202   printHeader(P, "Streams");
203
204   if (StreamPurposes.empty())
205     discoverStreamPurposes(File, StreamPurposes);
206
207   AutoIndent Indent(P);
208   uint32_t StreamCount = File.getNumStreams();
209
210   for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
211     P.formatLine(
212         "Stream {0}: [{1}] ({2} bytes)",
213         fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
214         StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
215   }
216
217   return Error::success();
218 }
219
220 Error RawOutputStyle::dumpBlockRanges() {
221   printHeader(P, "MSF Blocks");
222
223   auto &R = *opts::raw::DumpBlockRange;
224   uint32_t Max = R.Max.getValueOr(R.Min);
225
226   AutoIndent Indent(P);
227   if (Max < R.Min)
228     return make_error<StringError>(
229         "Invalid block range specified.  Max < Min",
230         std::make_error_code(std::errc::bad_address));
231   if (Max >= File.getBlockCount())
232     return make_error<StringError>(
233         "Invalid block range specified.  Requested block out of bounds",
234         std::make_error_code(std::errc::bad_address));
235
236   for (uint32_t I = R.Min; I <= Max; ++I) {
237     auto ExpectedData = File.getBlockData(I, File.getBlockSize());
238     if (!ExpectedData)
239       return ExpectedData.takeError();
240     std::string Label = formatv("Block {0}", I).str();
241     P.formatBinary(Label, *ExpectedData, 0);
242   }
243
244   return Error::success();
245 }
246
247 static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
248                              uint32_t &Size) {
249   if (Str.consumeInteger(0, SI))
250     return make_error<RawError>(raw_error_code::invalid_format,
251                                 "Invalid Stream Specification");
252   if (Str.consume_front(":")) {
253     if (Str.consumeInteger(0, Offset))
254       return make_error<RawError>(raw_error_code::invalid_format,
255                                   "Invalid Stream Specification");
256   }
257   if (Str.consume_front("@")) {
258     if (Str.consumeInteger(0, Size))
259       return make_error<RawError>(raw_error_code::invalid_format,
260                                   "Invalid Stream Specification");
261   }
262   if (!Str.empty())
263     return make_error<RawError>(raw_error_code::invalid_format,
264                                 "Invalid Stream Specification");
265   return Error::success();
266 }
267
268 Error RawOutputStyle::dumpStreamBytes() {
269   if (StreamPurposes.empty())
270     discoverStreamPurposes(File, StreamPurposes);
271
272   printHeader(P, "Stream Data");
273   ExitOnError Err("Unexpected error reading stream data");
274
275   for (auto &Str : opts::raw::DumpStreamData) {
276     uint32_t SI = 0;
277     uint32_t Begin = 0;
278     uint32_t Size = 0;
279     uint32_t End = 0;
280
281     if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
282       return EC;
283
284     AutoIndent Indent(P);
285     if (SI >= File.getNumStreams()) {
286       P.formatLine("Stream {0}: Not present", SI);
287       continue;
288     }
289
290     auto S = MappedBlockStream::createIndexedStream(
291         File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
292     if (!S) {
293       P.NewLine();
294       P.formatLine("Stream {0}: Not present", SI);
295       continue;
296     }
297
298     if (Size == 0)
299       End = S->getLength();
300     else
301       End = std::min(Begin + Size, S->getLength());
302
303     P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
304                  StreamPurposes[SI]);
305     AutoIndent Indent2(P);
306
307     BinaryStreamReader R(*S);
308     ArrayRef<uint8_t> StreamData;
309     Err(R.readBytes(StreamData, S->getLength()));
310     Size = End - Begin;
311     StreamData = StreamData.slice(Begin, Size);
312     P.formatBinary("Data", StreamData, Begin);
313   }
314   return Error::success();
315 }
316
317 static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
318                                                            uint32_t Index) {
319   ExitOnError Err("Unexpected error");
320
321   auto &Dbi = Err(File.getPDBDbiStream());
322   const auto &Modules = Dbi.modules();
323   auto Modi = Modules.getModuleDescriptor(Index);
324
325   uint16_t ModiStream = Modi.getModuleStreamIndex();
326   if (ModiStream == kInvalidStreamIndex)
327     return make_error<RawError>(raw_error_code::no_stream,
328                                 "Module stream not present");
329
330   auto ModStreamData = MappedBlockStream::createIndexedStream(
331       File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
332       File.getAllocator());
333
334   ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
335   if (auto EC = ModS.reload())
336     return make_error<RawError>(raw_error_code::corrupt_file,
337                                 "Invalid module stream");
338
339   return std::move(ModS);
340 }
341
342 static std::string formatChecksumKind(FileChecksumKind Kind) {
343   switch (Kind) {
344     RETURN_CASE(FileChecksumKind, None, "None");
345     RETURN_CASE(FileChecksumKind, MD5, "MD5");
346     RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
347     RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
348   }
349   return formatUnknownEnum(Kind);
350 }
351
352 namespace {
353 class StringsAndChecksumsPrinter {
354   const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
355     ExitOnError Err("Unexpected error processing modules");
356     return Err(File.getStringTable()).getStringTable();
357   }
358
359   template <typename... Args>
360   void formatInternal(LinePrinter &Printer, bool Append,
361                       Args &&... args) const {
362     if (Append)
363       Printer.format(std::forward<Args>(args)...);
364     else
365       Printer.formatLine(std::forward<Args>(args)...);
366   }
367
368 public:
369   StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
370       : Records(extractStringTable(File)) {
371     auto MDS = getModuleDebugStream(File, Modi);
372     if (!MDS) {
373       consumeError(MDS.takeError());
374       return;
375     }
376
377     DebugStream = llvm::make_unique<ModuleDebugStreamRef>(std::move(*MDS));
378     Records.initialize(MDS->subsections());
379     if (Records.hasChecksums()) {
380       for (const auto &Entry : Records.checksums()) {
381         auto S = Records.strings().getString(Entry.FileNameOffset);
382         if (!S)
383           continue;
384         ChecksumsByFile[*S] = Entry;
385       }
386     }
387   }
388
389   Expected<StringRef> getNameFromStringTable(uint32_t Offset) const {
390     return Records.strings().getString(Offset);
391   }
392
393   void formatFromFileName(LinePrinter &Printer, StringRef File,
394                           bool Append = false) const {
395     auto FC = ChecksumsByFile.find(File);
396     if (FC == ChecksumsByFile.end()) {
397       formatInternal(Printer, Append, "- (no checksum) {0}", File);
398       return;
399     }
400
401     formatInternal(Printer, Append, "- ({0}: {1}) {2}",
402                    formatChecksumKind(FC->getValue().Kind),
403                    toHex(FC->getValue().Checksum), File);
404   }
405
406   void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
407                                  bool Append = false) const {
408     if (!Records.hasChecksums()) {
409       formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
410       return;
411     }
412
413     auto Iter = Records.checksums().getArray().at(Offset);
414     if (Iter == Records.checksums().getArray().end()) {
415       formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
416       return;
417     }
418
419     uint32_t FO = Iter->FileNameOffset;
420     auto ExpectedFile = getNameFromStringTable(FO);
421     if (!ExpectedFile) {
422       formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
423       consumeError(ExpectedFile.takeError());
424       return;
425     }
426     if (Iter->Kind == FileChecksumKind::None) {
427       formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
428     } else {
429       formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
430                      formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
431     }
432   }
433
434   std::unique_ptr<ModuleDebugStreamRef> DebugStream;
435   StringsAndChecksumsRef Records;
436   StringMap<FileChecksumEntry> ChecksumsByFile;
437 };
438 } // namespace
439
440 template <typename CallbackT>
441 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
442                            CallbackT Callback) {
443   AutoIndent Indent(P);
444   if (!File.hasPDBDbiStream()) {
445     P.formatLine("DBI Stream not present");
446     return;
447   }
448
449   ExitOnError Err("Unexpected error processing modules");
450
451   auto &Stream = Err(File.getPDBDbiStream());
452
453   const DbiModuleList &Modules = Stream.modules();
454   uint32_t Count = Modules.getModuleCount();
455   uint32_t Digits = NumDigits(Count);
456   for (uint32_t I = 0; I < Count; ++I) {
457     auto Modi = Modules.getModuleDescriptor(I);
458     P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
459                  Modi.getModuleName());
460
461     StringsAndChecksumsPrinter Strings(File, I);
462     AutoIndent Indent2(P, IndentLevel);
463     Callback(I, Strings);
464   }
465 }
466
467 template <typename SubsectionT>
468 static void iterateModuleSubsections(
469     PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
470     llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &,
471                             SubsectionT &)>
472         Callback) {
473
474   iterateModules(
475       File, P, IndentLevel,
476       [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
477         auto MDS = getModuleDebugStream(File, Modi);
478         if (!MDS) {
479           consumeError(MDS.takeError());
480           return;
481         }
482
483         for (const auto &SS : MDS->subsections()) {
484           SubsectionT Subsection;
485
486           if (SS.kind() != Subsection.kind())
487             continue;
488
489           BinaryStreamReader Reader(SS.getRecordData());
490           if (auto EC = Subsection.initialize(Reader))
491             continue;
492           Callback(Modi, Strings, Subsection);
493         }
494       });
495 }
496
497 Error RawOutputStyle::dumpModules() {
498   printHeader(P, "Modules");
499
500   AutoIndent Indent(P);
501   if (!File.hasPDBDbiStream()) {
502     P.formatLine("DBI Stream not present");
503     return Error::success();
504   }
505
506   ExitOnError Err("Unexpected error processing modules");
507
508   auto &Stream = Err(File.getPDBDbiStream());
509
510   const DbiModuleList &Modules = Stream.modules();
511   uint32_t Count = Modules.getModuleCount();
512   uint32_t Digits = NumDigits(Count);
513   for (uint32_t I = 0; I < Count; ++I) {
514     auto Modi = Modules.getModuleDescriptor(I);
515     P.formatLine("Mod {0:4} | Name: `{1}`: ",
516                  fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
517     P.formatLine("           Obj: `{0}`: ", Modi.getObjFileName());
518     P.formatLine("           debug stream: {0}, # files: {1}, has ec info: {2}",
519                  Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
520                  Modi.hasECInfo());
521   }
522   return Error::success();
523 }
524
525 Error RawOutputStyle::dumpModuleFiles() {
526   printHeader(P, "Files");
527
528   ExitOnError Err("Unexpected error processing modules");
529
530   iterateModules(
531       File, P, 11,
532       [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
533         auto &Stream = Err(File.getPDBDbiStream());
534
535         const DbiModuleList &Modules = Stream.modules();
536         for (const auto &F : Modules.source_files(Modi)) {
537           Strings.formatFromFileName(P, F);
538         }
539       });
540   return Error::success();
541 }
542
543 static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
544                                    uint32_t Start, const LineColumnEntry &E) {
545   const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
546   uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
547
548   // Let's try to keep it under 100 characters
549   constexpr uint32_t kMaxRowLength = 100;
550   // At least 3 spaces between columns.
551   uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
552   uint32_t ItemsLeft = E.LineNumbers.size();
553   auto LineIter = E.LineNumbers.begin();
554   while (ItemsLeft != 0) {
555     uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
556     for (uint32_t I = 0; I < RowColumns; ++I) {
557       LineInfo Line(LineIter->Flags);
558       std::string LineStr;
559       if (Line.isAlwaysStepInto())
560         LineStr = "ASI";
561       else if (Line.isNeverStepInto())
562         LineStr = "NSI";
563       else
564         LineStr = utostr(Line.getStartLine());
565       char Statement = Line.isStatement() ? ' ' : '!';
566       P.format("{0} {1:X-} {2} ",
567                fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
568                fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
569                Statement);
570       ++LineIter;
571       --ItemsLeft;
572     }
573     P.NewLine();
574   }
575 }
576
577 Error RawOutputStyle::dumpLines() {
578   printHeader(P, "Lines");
579
580   uint32_t LastModi = UINT32_MAX;
581   uint32_t LastNameIndex = UINT32_MAX;
582   iterateModuleSubsections<DebugLinesSubsectionRef>(
583       File, P, 4,
584       [this, &LastModi, &LastNameIndex](uint32_t Modi,
585                                         StringsAndChecksumsPrinter &Strings,
586                                         DebugLinesSubsectionRef &Lines) {
587         uint16_t Segment = Lines.header()->RelocSegment;
588         uint32_t Begin = Lines.header()->RelocOffset;
589         uint32_t End = Begin + Lines.header()->CodeSize;
590         for (const auto &Block : Lines) {
591           if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
592             LastModi = Modi;
593             LastNameIndex = Block.NameIndex;
594             Strings.formatFromChecksumsOffset(P, Block.NameIndex);
595           }
596
597           AutoIndent Indent(P, 2);
598           P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
599           uint32_t Count = Block.LineNumbers.size();
600           if (Lines.hasColumnInfo())
601             P.format("line/column/addr entries = {0}", Count);
602           else
603             P.format("line/addr entries = {0}", Count);
604
605           P.NewLine();
606           typesetLinesAndColumns(File, P, Begin, Block);
607         }
608       });
609
610   return Error::success();
611 }
612
613 Error RawOutputStyle::dumpInlineeLines() {
614   printHeader(P, "Inlinee Lines");
615
616   iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
617       File, P, 2,
618       [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
619              DebugInlineeLinesSubsectionRef &Lines) {
620         P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
621         for (const auto &Entry : Lines) {
622           P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
623                        fmtle(Entry.Header->SourceLineNum));
624           Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
625         }
626         P.NewLine();
627       });
628
629   return Error::success();
630 }
631
632 Error RawOutputStyle::dumpXmi() {
633   printHeader(P, "Cross Module Imports");
634   iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
635       File, P, 2,
636       [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
637              DebugCrossModuleImportsSubsectionRef &Imports) {
638         P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
639
640         for (const auto &Xmi : Imports) {
641           auto ExpectedModule =
642               Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
643           StringRef Module;
644           SmallString<32> ModuleStorage;
645           if (!ExpectedModule) {
646             Module = "(unknown module)";
647             consumeError(ExpectedModule.takeError());
648           } else
649             Module = *ExpectedModule;
650           if (Module.size() > 32) {
651             ModuleStorage = "...";
652             ModuleStorage += Module.take_back(32 - 3);
653             Module = ModuleStorage;
654           }
655           std::vector<std::string> TIs;
656           for (const auto I : Xmi.Imports)
657             TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
658           std::string Result =
659               typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
660           P.formatLine("{0,+32} | {1}", Module, Result);
661         }
662       });
663
664   return Error::success();
665 }
666
667 Error RawOutputStyle::dumpXme() {
668   printHeader(P, "Cross Module Exports");
669
670   iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
671       File, P, 2,
672       [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
673              DebugCrossModuleExportsSubsectionRef &Exports) {
674         P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
675         for (const auto &Export : Exports) {
676           P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
677                        TypeIndex(Export.Global));
678         }
679       });
680
681   return Error::success();
682 }
683
684 Error RawOutputStyle::dumpStringTable() {
685   printHeader(P, "String Table");
686
687   AutoIndent Indent(P);
688   auto IS = File.getStringTable();
689   if (!IS) {
690     P.formatLine("Not present in file");
691     consumeError(IS.takeError());
692     return Error::success();
693   }
694
695   if (IS->name_ids().empty()) {
696     P.formatLine("Empty");
697     return Error::success();
698   }
699
700   auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
701   uint32_t Digits = NumDigits(*MaxID);
702
703   P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
704                "String");
705
706   std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
707   std::sort(SortedIDs.begin(), SortedIDs.end());
708   for (uint32_t I : SortedIDs) {
709     auto ES = IS->getStringForID(I);
710     llvm::SmallString<32> Str;
711     if (!ES) {
712       consumeError(ES.takeError());
713       Str = "Error reading string";
714     } else if (!ES->empty()) {
715       Str.append("'");
716       Str.append(*ES);
717       Str.append("'");
718     }
719
720     if (!Str.empty())
721       P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
722   }
723   return Error::success();
724 }
725
726 Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
727   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
728
729   bool Present = false;
730   bool DumpTypes = false;
731   bool DumpBytes = false;
732   bool DumpExtras = false;
733   if (StreamIdx == StreamTPI) {
734     printHeader(P, "Types (TPI Stream)");
735     Present = File.hasPDBTpiStream();
736     DumpTypes = opts::raw::DumpTypes;
737     DumpBytes = opts::raw::DumpTypeData;
738     DumpExtras = opts::raw::DumpTypeExtras;
739   } else if (StreamIdx == StreamIPI) {
740     printHeader(P, "Types (IPI Stream)");
741     Present = File.hasPDBIpiStream();
742     DumpTypes = opts::raw::DumpIds;
743     DumpBytes = opts::raw::DumpIdData;
744     DumpExtras = opts::raw::DumpIdExtras;
745   }
746
747   AutoIndent Indent(P);
748   if (!Present) {
749     P.formatLine("Stream not present");
750     return Error::success();
751   }
752
753   ExitOnError Err("Unexpected error processing types");
754
755   auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
756                                               : File.getPDBIpiStream());
757
758   auto &Types = Err(initializeTypeDatabase(StreamIdx));
759
760   if (DumpTypes) {
761     P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
762     uint32_t Width =
763         NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
764
765     MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
766                              Stream.getHashValues());
767
768     Optional<TypeIndex> I = Types.getFirst();
769     if (auto EC = codeview::visitTypeStream(Types, V)) {
770       P.formatLine("An error occurred dumping type records: {0}",
771                    toString(std::move(EC)));
772     }
773   }
774
775   if (DumpExtras) {
776     P.NewLine();
777     auto IndexOffsets = Stream.getTypeIndexOffsets();
778     P.formatLine("Type Index Offsets:");
779     for (const auto &IO : IndexOffsets) {
780       AutoIndent Indent2(P);
781       P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
782     }
783
784     P.NewLine();
785     P.formatLine("Hash Adjusters:");
786     auto &Adjusters = Stream.getHashAdjusters();
787     auto &Strings = Err(File.getStringTable());
788     for (const auto &A : Adjusters) {
789       AutoIndent Indent2(P);
790       auto ExpectedStr = Strings.getStringForID(A.first);
791       TypeIndex TI(A.second);
792       if (ExpectedStr)
793         P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
794       else {
795         P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
796         consumeError(ExpectedStr.takeError());
797       }
798     }
799   }
800   return Error::success();
801 }
802
803 Expected<codeview::LazyRandomTypeCollection &>
804 RawOutputStyle::initializeTypeDatabase(uint32_t SN) {
805   auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
806   auto Tpi =
807       (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
808   if (!Tpi)
809     return Tpi.takeError();
810
811   if (!TypeCollection) {
812     auto &Types = Tpi->typeArray();
813     uint32_t Count = Tpi->getNumTypeRecords();
814     auto Offsets = Tpi->getTypeIndexOffsets();
815     TypeCollection =
816         llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
817   }
818
819   return *TypeCollection;
820 }
821
822 Error RawOutputStyle::dumpModuleSyms() {
823   printHeader(P, "Symbols");
824
825   AutoIndent Indent(P);
826   if (!File.hasPDBDbiStream()) {
827     P.formatLine("DBI Stream not present");
828     return Error::success();
829   }
830
831   ExitOnError Err("Unexpected error processing symbols");
832
833   auto &Stream = Err(File.getPDBDbiStream());
834
835   auto &Types = Err(initializeTypeDatabase(StreamTPI));
836
837   const DbiModuleList &Modules = Stream.modules();
838   uint32_t Count = Modules.getModuleCount();
839   uint32_t Digits = NumDigits(Count);
840   for (uint32_t I = 0; I < Count; ++I) {
841     auto Modi = Modules.getModuleDescriptor(I);
842     P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
843                  Modi.getModuleName());
844     uint16_t ModiStream = Modi.getModuleStreamIndex();
845     if (ModiStream == kInvalidStreamIndex) {
846       P.formatLine("           <symbols not present>");
847       continue;
848     }
849     auto ModStreamData = MappedBlockStream::createIndexedStream(
850         File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
851         File.getAllocator());
852
853     ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
854     if (auto EC = ModS.reload()) {
855       P.formatLine("Error loading module stream {0}.  {1}", I,
856                    toString(std::move(EC)));
857       continue;
858     }
859
860     SymbolVisitorCallbackPipeline Pipeline;
861     SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
862     MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
863
864     Pipeline.addCallbackToPipeline(Deserializer);
865     Pipeline.addCallbackToPipeline(Dumper);
866     CVSymbolVisitor Visitor(Pipeline);
867     if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) {
868       P.formatLine("Error while processing symbol records.  {0}",
869                    toString(std::move(EC)));
870       continue;
871     }
872   }
873   return Error::success();
874 }
875
876 Error RawOutputStyle::dumpPublics() {
877   printHeader(P, "Public Symbols");
878
879   AutoIndent Indent(P);
880   if (!File.hasPDBPublicsStream()) {
881     P.formatLine("Publics stream not present");
882     return Error::success();
883   }
884
885   ExitOnError Err("Error dumping publics stream");
886
887   auto &Types = Err(initializeTypeDatabase(StreamTPI));
888   auto &Publics = Err(File.getPDBPublicsStream());
889   SymbolVisitorCallbackPipeline Pipeline;
890   SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
891   MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
892
893   Pipeline.addCallbackToPipeline(Deserializer);
894   Pipeline.addCallbackToPipeline(Dumper);
895   CVSymbolVisitor Visitor(Pipeline);
896   auto ExpectedSymbols = Publics.getSymbolArray();
897   if (!ExpectedSymbols) {
898     P.formatLine("Could not read public symbol record stream");
899     return Error::success();
900   }
901
902   if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols))
903     P.formatLine("Error while processing public symbol records.  {0}",
904                  toString(std::move(EC)));
905
906   return Error::success();
907 }
908
909 static std::string formatSectionCharacteristics(uint32_t IndentLevel,
910                                                 uint32_t C) {
911   using SC = COFF::SectionCharacteristics;
912   std::vector<std::string> Opts;
913   if (C == COFF::SC_Invalid)
914     return "invalid";
915   if (C == 0)
916     return "none";
917
918   PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
919   PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
920   PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
921   PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
922             "IMAGE_SCN_CNT_INITIALIZED_DATA");
923   PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
924             "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
925   PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
926   PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
927   PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
928   PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
929   PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
930   PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
931   PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
932   PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
933   PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
934   PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
935   PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
936   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
937                    "IMAGE_SCN_ALIGN_1BYTES");
938   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
939                    "IMAGE_SCN_ALIGN_2BYTES");
940   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
941                    "IMAGE_SCN_ALIGN_4BYTES");
942   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
943                    "IMAGE_SCN_ALIGN_8BYTES");
944   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
945                    "IMAGE_SCN_ALIGN_16BYTES");
946   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
947                    "IMAGE_SCN_ALIGN_32BYTES");
948   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
949                    "IMAGE_SCN_ALIGN_64BYTES");
950   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
951                    "IMAGE_SCN_ALIGN_128BYTES");
952   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
953                    "IMAGE_SCN_ALIGN_256BYTES");
954   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
955                    "IMAGE_SCN_ALIGN_512BYTES");
956   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
957                    "IMAGE_SCN_ALIGN_1024BYTES");
958   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
959                    "IMAGE_SCN_ALIGN_2048BYTES");
960   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
961                    "IMAGE_SCN_ALIGN_4096BYTES");
962   PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
963                    "IMAGE_SCN_ALIGN_8192BYTES");
964   PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
965   PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
966   PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
967   PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
968   PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
969   PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
970   PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
971   PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
972   return typesetItemList(Opts, IndentLevel, 3, " | ");
973 }
974
975 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
976                                               OMFSegDescFlags Flags) {
977   std::vector<std::string> Opts;
978   if (Flags == OMFSegDescFlags::None)
979     return "none";
980
981   PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
982   PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
983   PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
984   PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
985   PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
986   PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
987   PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
988   return typesetItemList(Opts, IndentLevel, 4, " | ");
989 }
990
991 Error RawOutputStyle::dumpSectionContribs() {
992   printHeader(P, "Section Contributions");
993   ExitOnError Err("Error dumping publics stream");
994
995   AutoIndent Indent(P);
996   if (!File.hasPDBDbiStream()) {
997     P.formatLine(
998         "Section contribs require a DBI Stream, which could not be loaded");
999     return Error::success();
1000   }
1001
1002   auto &Dbi = Err(File.getPDBDbiStream());
1003
1004   class Visitor : public ISectionContribVisitor {
1005   public:
1006     Visitor(LinePrinter &P) : P(P) {}
1007     void visit(const SectionContrib &SC) override {
1008       P.formatLine(
1009           "SC  | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
1010           formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
1011           fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
1012       P.formatLine("      {0}",
1013                    formatSectionCharacteristics(P.getIndentLevel() + 6,
1014                                                 SC.Characteristics));
1015     }
1016     void visit(const SectionContrib2 &SC) override {
1017       P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1018                    "crc = {4}, coff section = {5}",
1019                    formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
1020                    fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
1021                    fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1022                    fmtle(SC.ISectCoff));
1023       P.formatLine("      {0}",
1024                    formatSectionCharacteristics(P.getIndentLevel() + 6,
1025                                                 SC.Base.Characteristics));
1026     }
1027
1028   private:
1029     LinePrinter &P;
1030   };
1031
1032   Visitor V(P);
1033   Dbi.visitSectionContributions(V);
1034   return Error::success();
1035 }
1036
1037 Error RawOutputStyle::dumpSectionMap() {
1038   printHeader(P, "Section Map");
1039   ExitOnError Err("Error dumping section map");
1040
1041   AutoIndent Indent(P);
1042   if (!File.hasPDBDbiStream()) {
1043     P.formatLine("Dumping the section map requires a DBI Stream, which could "
1044                  "not be loaded");
1045     return Error::success();
1046   }
1047
1048   auto &Dbi = Err(File.getPDBDbiStream());
1049
1050   uint32_t I = 0;
1051   for (auto &M : Dbi.getSectionMap()) {
1052     P.formatLine(
1053         "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
1054         fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1055     P.formatLine("               class = {0}, offset = {1}, size = {2}",
1056                  fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1057     P.formatLine("               flags = {0}",
1058                  formatSegMapDescriptorFlag(
1059                      P.getIndentLevel() + 13,
1060                      static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1061     ++I;
1062   }
1063   return Error::success();
1064 }