blob: 6797adfc8f89a0fd3d2c5d95eaac98aa5151bdbb [file] [log] [blame]
Zachary Turner7df69952017-06-22 20:57:39 +00001//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
Zachary Turner63055452017-06-15 22:24:24 +00002//
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
Zachary Turner7df69952017-06-22 20:57:39 +000010#include "DumpOutputStyle.h"
Zachary Turner63055452017-06-15 22:24:24 +000011
Zachary Turner63055452017-06-15 22:24:24 +000012#include "FormatUtil.h"
13#include "MinimalSymbolDumper.h"
14#include "MinimalTypeDumper.h"
15#include "StreamUtil.h"
16#include "llvm-pdbutil.h"
17
Zachary Turnerf2872b92017-06-15 23:59:56 +000018#include "llvm/ADT/STLExtras.h"
Zachary Turner63055452017-06-15 22:24:24 +000019#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
20#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
21#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
22#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
23#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
24#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
25#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
26#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
27#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
28#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
29#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
30#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
31#include "llvm/DebugInfo/CodeView/EnumTables.h"
32#include "llvm/DebugInfo/CodeView/Formatters.h"
33#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
34#include "llvm/DebugInfo/CodeView/Line.h"
35#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
36#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
37#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
38#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
39#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
Zachary Turner02a26772017-06-30 18:15:47 +000040#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
Zachary Turner63055452017-06-15 22:24:24 +000041#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"
Reid Kleckner14d90fd2017-07-26 00:40:36 +000052#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
Zachary Turner63055452017-06-15 22:24:24 +000053#include "llvm/DebugInfo/PDB/Native/RawError.h"
54#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
55#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
56#include "llvm/DebugInfo/PDB/PDBExtras.h"
57#include "llvm/Object/COFF.h"
58#include "llvm/Support/BinaryStreamReader.h"
59#include "llvm/Support/FormatAdapters.h"
60#include "llvm/Support/FormatVariadic.h"
61
62#include <unordered_map>
63
64using namespace llvm;
65using namespace llvm::codeview;
66using namespace llvm::msf;
67using namespace llvm::pdb;
68
Zachary Turner7df69952017-06-22 20:57:39 +000069DumpOutputStyle::DumpOutputStyle(PDBFile &File)
Zachary Turner63055452017-06-15 22:24:24 +000070 : File(File), P(2, false, outs()) {}
71
Zachary Turner7df69952017-06-22 20:57:39 +000072Error DumpOutputStyle::dump() {
73 if (opts::dump::DumpSummary) {
Zachary Turner63055452017-06-15 22:24:24 +000074 if (auto EC = dumpFileSummary())
75 return EC;
76 P.NewLine();
77 }
78
Zachary Turner7df69952017-06-22 20:57:39 +000079 if (opts::dump::DumpStreams) {
Zachary Turner63055452017-06-15 22:24:24 +000080 if (auto EC = dumpStreamSummary())
81 return EC;
82 P.NewLine();
83 }
84
Zachary Turner7df69952017-06-22 20:57:39 +000085 if (opts::dump::DumpStringTable) {
Zachary Turner63055452017-06-15 22:24:24 +000086 if (auto EC = dumpStringTable())
87 return EC;
88 P.NewLine();
89 }
90
Zachary Turner7df69952017-06-22 20:57:39 +000091 if (opts::dump::DumpModules) {
Zachary Turner63055452017-06-15 22:24:24 +000092 if (auto EC = dumpModules())
93 return EC;
94 }
95
Zachary Turner7df69952017-06-22 20:57:39 +000096 if (opts::dump::DumpModuleFiles) {
Zachary Turner0e327d02017-06-15 23:12:41 +000097 if (auto EC = dumpModuleFiles())
98 return EC;
99 }
100
Zachary Turner7df69952017-06-22 20:57:39 +0000101 if (opts::dump::DumpLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000102 if (auto EC = dumpLines())
103 return EC;
104 }
105
Zachary Turner7df69952017-06-22 20:57:39 +0000106 if (opts::dump::DumpInlineeLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000107 if (auto EC = dumpInlineeLines())
108 return EC;
109 }
110
Zachary Turner7df69952017-06-22 20:57:39 +0000111 if (opts::dump::DumpXmi) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000112 if (auto EC = dumpXmi())
113 return EC;
114 }
115
Zachary Turner7df69952017-06-22 20:57:39 +0000116 if (opts::dump::DumpXme) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000117 if (auto EC = dumpXme())
118 return EC;
119 }
120
Zachary Turner02a26772017-06-30 18:15:47 +0000121 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
122 opts::dump::DumpTypeExtras) {
Zachary Turner63055452017-06-15 22:24:24 +0000123 if (auto EC = dumpTpiStream(StreamTPI))
124 return EC;
125 }
126
Zachary Turner02a26772017-06-30 18:15:47 +0000127 if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
128 opts::dump::DumpIdExtras) {
Zachary Turner63055452017-06-15 22:24:24 +0000129 if (auto EC = dumpTpiStream(StreamIPI))
130 return EC;
131 }
132
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000133 if (opts::dump::DumpGlobals) {
134 if (auto EC = dumpGlobals())
135 return EC;
136 }
137
Zachary Turner7df69952017-06-22 20:57:39 +0000138 if (opts::dump::DumpPublics) {
Zachary Turner63055452017-06-15 22:24:24 +0000139 if (auto EC = dumpPublics())
140 return EC;
141 }
142
Zachary Turner7df69952017-06-22 20:57:39 +0000143 if (opts::dump::DumpSymbols) {
Zachary Turner63055452017-06-15 22:24:24 +0000144 if (auto EC = dumpModuleSyms())
145 return EC;
146 }
147
Zachary Turnerfb1cd502017-08-04 20:02:38 +0000148 if (opts::dump::DumpSectionHeaders) {
149 if (auto EC = dumpSectionHeaders())
150 return EC;
151 }
152
Zachary Turner7df69952017-06-22 20:57:39 +0000153 if (opts::dump::DumpSectionContribs) {
Zachary Turner63055452017-06-15 22:24:24 +0000154 if (auto EC = dumpSectionContribs())
155 return EC;
156 }
157
Zachary Turner7df69952017-06-22 20:57:39 +0000158 if (opts::dump::DumpSectionMap) {
Zachary Turner63055452017-06-15 22:24:24 +0000159 if (auto EC = dumpSectionMap())
160 return EC;
161 }
162
163 return Error::success();
164}
165
166static void printHeader(LinePrinter &P, const Twine &S) {
167 P.NewLine();
168 P.formatLine("{0,=60}", S);
169 P.formatLine("{0}", fmt_repeat('=', 60));
170}
171
Zachary Turner7df69952017-06-22 20:57:39 +0000172Error DumpOutputStyle::dumpFileSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000173 printHeader(P, "Summary");
174
Reid Klecknerdd853e52017-07-27 23:13:18 +0000175 ExitOnError Err("Invalid PDB Format: ");
Zachary Turner63055452017-06-15 22:24:24 +0000176
177 AutoIndent Indent(P);
178 P.formatLine("Block Size: {0}", File.getBlockSize());
179 P.formatLine("Number of blocks: {0}", File.getBlockCount());
180 P.formatLine("Number of streams: {0}", File.getNumStreams());
181
182 auto &PS = Err(File.getPDBInfoStream());
183 P.formatLine("Signature: {0}", PS.getSignature());
184 P.formatLine("Age: {0}", PS.getAge());
185 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
186 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
187 P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
188 P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
189 P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
190 P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
191 P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
192 if (File.hasPDBDbiStream()) {
193 auto &DBI = Err(File.getPDBDbiStream());
194 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
195 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
196 P.formatLine("Is stripped: {0}", DBI.isStripped());
197 }
198
199 return Error::success();
200}
201
Zachary Turner7df69952017-06-22 20:57:39 +0000202Error DumpOutputStyle::dumpStreamSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000203 printHeader(P, "Streams");
204
205 if (StreamPurposes.empty())
206 discoverStreamPurposes(File, StreamPurposes);
207
208 AutoIndent Indent(P);
209 uint32_t StreamCount = File.getNumStreams();
210
211 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
212 P.formatLine(
213 "Stream {0}: [{1}] ({2} bytes)",
214 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
215 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
Zachary Turner5f098522017-06-23 20:28:14 +0000216 if (opts::dump::DumpStreamBlocks) {
217 auto Blocks = File.getStreamBlockList(StreamIdx);
218 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
219 P.formatLine(" {0} Blocks: [{1}]",
220 fmt_repeat(' ', NumDigits(StreamCount)),
221 make_range(BV.begin(), BV.end()));
222 }
Zachary Turner63055452017-06-15 22:24:24 +0000223 }
224
225 return Error::success();
226}
227
Zachary Turner0e327d02017-06-15 23:12:41 +0000228static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
229 uint32_t Index) {
Reid Klecknerdd853e52017-07-27 23:13:18 +0000230 ExitOnError Err("Unexpected error: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000231
232 auto &Dbi = Err(File.getPDBDbiStream());
233 const auto &Modules = Dbi.modules();
234 auto Modi = Modules.getModuleDescriptor(Index);
235
236 uint16_t ModiStream = Modi.getModuleStreamIndex();
237 if (ModiStream == kInvalidStreamIndex)
238 return make_error<RawError>(raw_error_code::no_stream,
239 "Module stream not present");
240
241 auto ModStreamData = MappedBlockStream::createIndexedStream(
242 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
243 File.getAllocator());
244
245 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
246 if (auto EC = ModS.reload())
247 return make_error<RawError>(raw_error_code::corrupt_file,
248 "Invalid module stream");
249
250 return std::move(ModS);
251}
252
Zachary Turner0e327d02017-06-15 23:12:41 +0000253static std::string formatChecksumKind(FileChecksumKind Kind) {
254 switch (Kind) {
255 RETURN_CASE(FileChecksumKind, None, "None");
256 RETURN_CASE(FileChecksumKind, MD5, "MD5");
257 RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
258 RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
259 }
260 return formatUnknownEnum(Kind);
261}
262
Zachary Turner4e950642017-06-15 23:56:19 +0000263namespace {
264class StringsAndChecksumsPrinter {
265 const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
Reid Klecknerdd853e52017-07-27 23:13:18 +0000266 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner4e950642017-06-15 23:56:19 +0000267 return Err(File.getStringTable()).getStringTable();
268 }
269
270 template <typename... Args>
271 void formatInternal(LinePrinter &Printer, bool Append,
272 Args &&... args) const {
273 if (Append)
274 Printer.format(std::forward<Args>(args)...);
275 else
276 Printer.formatLine(std::forward<Args>(args)...);
277 }
278
279public:
280 StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
281 : Records(extractStringTable(File)) {
282 auto MDS = getModuleDebugStream(File, Modi);
283 if (!MDS) {
284 consumeError(MDS.takeError());
285 return;
286 }
287
288 DebugStream = llvm::make_unique<ModuleDebugStreamRef>(std::move(*MDS));
289 Records.initialize(MDS->subsections());
290 if (Records.hasChecksums()) {
291 for (const auto &Entry : Records.checksums()) {
292 auto S = Records.strings().getString(Entry.FileNameOffset);
293 if (!S)
294 continue;
295 ChecksumsByFile[*S] = Entry;
296 }
297 }
298 }
299
300 Expected<StringRef> getNameFromStringTable(uint32_t Offset) const {
301 return Records.strings().getString(Offset);
302 }
303
304 void formatFromFileName(LinePrinter &Printer, StringRef File,
305 bool Append = false) const {
306 auto FC = ChecksumsByFile.find(File);
307 if (FC == ChecksumsByFile.end()) {
308 formatInternal(Printer, Append, "- (no checksum) {0}", File);
309 return;
310 }
311
312 formatInternal(Printer, Append, "- ({0}: {1}) {2}",
313 formatChecksumKind(FC->getValue().Kind),
314 toHex(FC->getValue().Checksum), File);
315 }
316
317 void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
318 bool Append = false) const {
319 if (!Records.hasChecksums()) {
320 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
321 return;
322 }
323
324 auto Iter = Records.checksums().getArray().at(Offset);
325 if (Iter == Records.checksums().getArray().end()) {
326 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
327 return;
328 }
329
330 uint32_t FO = Iter->FileNameOffset;
331 auto ExpectedFile = getNameFromStringTable(FO);
332 if (!ExpectedFile) {
333 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
334 consumeError(ExpectedFile.takeError());
335 return;
336 }
337 if (Iter->Kind == FileChecksumKind::None) {
338 formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
339 } else {
340 formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
341 formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
342 }
343 }
344
345 std::unique_ptr<ModuleDebugStreamRef> DebugStream;
346 StringsAndChecksumsRef Records;
347 StringMap<FileChecksumEntry> ChecksumsByFile;
348};
349} // namespace
350
Zachary Turnerf2872b92017-06-15 23:59:56 +0000351template <typename CallbackT>
Zachary Turner58699362017-08-03 23:11:52 +0000352static void iterateOneModule(PDBFile &File, LinePrinter &P,
353 const DbiModuleDescriptor &Descriptor,
354 uint32_t Modi, uint32_t IndentLevel,
355 uint32_t Digits, CallbackT Callback) {
356 P.formatLine(
357 "Mod {0:4} | `{1}`: ", fmt_align(Modi, AlignStyle::Right, Digits),
358 Descriptor.getModuleName());
359
360 StringsAndChecksumsPrinter Strings(File, Modi);
361 AutoIndent Indent2(P, IndentLevel);
362 Callback(Modi, Strings);
363}
364
365template <typename CallbackT>
Zachary Turnerf2872b92017-06-15 23:59:56 +0000366static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
367 CallbackT Callback) {
368 AutoIndent Indent(P);
369 if (!File.hasPDBDbiStream()) {
370 P.formatLine("DBI Stream not present");
371 return;
372 }
373
Reid Klecknerdd853e52017-07-27 23:13:18 +0000374 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turnerf2872b92017-06-15 23:59:56 +0000375
376 auto &Stream = Err(File.getPDBDbiStream());
377
378 const DbiModuleList &Modules = Stream.modules();
Zachary Turner58699362017-08-03 23:11:52 +0000379
380 if (opts::dump::DumpModi.getNumOccurrences() > 0) {
381 assert(opts::dump::DumpModi.getNumOccurrences() == 1);
382 uint32_t Modi = opts::dump::DumpModi;
383 auto Descriptor = Modules.getModuleDescriptor(Modi);
384 iterateOneModule(File, P, Descriptor, Modi, IndentLevel, NumDigits(Modi),
385 Callback);
386 return;
387 }
388
Zachary Turnerf2872b92017-06-15 23:59:56 +0000389 uint32_t Count = Modules.getModuleCount();
390 uint32_t Digits = NumDigits(Count);
391 for (uint32_t I = 0; I < Count; ++I) {
Zachary Turner58699362017-08-03 23:11:52 +0000392 auto Descriptor = Modules.getModuleDescriptor(I);
393 iterateOneModule(File, P, Descriptor, I, IndentLevel, Digits, Callback);
Zachary Turnerf2872b92017-06-15 23:59:56 +0000394 }
395}
396
397template <typename SubsectionT>
398static void iterateModuleSubsections(
399 PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
400 llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &,
401 SubsectionT &)>
402 Callback) {
403
404 iterateModules(
405 File, P, IndentLevel,
406 [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
407 auto MDS = getModuleDebugStream(File, Modi);
408 if (!MDS) {
409 consumeError(MDS.takeError());
410 return;
411 }
412
413 for (const auto &SS : MDS->subsections()) {
414 SubsectionT Subsection;
415
416 if (SS.kind() != Subsection.kind())
417 continue;
418
419 BinaryStreamReader Reader(SS.getRecordData());
420 if (auto EC = Subsection.initialize(Reader))
421 continue;
422 Callback(Modi, Strings, Subsection);
423 }
424 });
425}
426
Zachary Turner7df69952017-06-22 20:57:39 +0000427Error DumpOutputStyle::dumpModules() {
Zachary Turner63055452017-06-15 22:24:24 +0000428 printHeader(P, "Modules");
429
430 AutoIndent Indent(P);
431 if (!File.hasPDBDbiStream()) {
432 P.formatLine("DBI Stream not present");
433 return Error::success();
434 }
435
Reid Klecknerdd853e52017-07-27 23:13:18 +0000436 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner63055452017-06-15 22:24:24 +0000437
438 auto &Stream = Err(File.getPDBDbiStream());
439
440 const DbiModuleList &Modules = Stream.modules();
441 uint32_t Count = Modules.getModuleCount();
442 uint32_t Digits = NumDigits(Count);
443 for (uint32_t I = 0; I < Count; ++I) {
444 auto Modi = Modules.getModuleDescriptor(I);
445 P.formatLine("Mod {0:4} | Name: `{1}`: ",
446 fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
447 P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
448 P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
449 Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
450 Modi.hasECInfo());
Zachary Turner6c4bfba2017-07-07 05:04:36 +0000451 StringRef PdbFilePath =
452 Err(Stream.getECName(Modi.getPdbFilePathNameIndex()));
453 StringRef SrcFilePath =
454 Err(Stream.getECName(Modi.getSourceFileNameIndex()));
455 P.formatLine(" pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
456 Modi.getPdbFilePathNameIndex(), PdbFilePath,
457 Modi.getSourceFileNameIndex(), SrcFilePath);
Zachary Turner0e327d02017-06-15 23:12:41 +0000458 }
459 return Error::success();
460}
461
Zachary Turner7df69952017-06-22 20:57:39 +0000462Error DumpOutputStyle::dumpModuleFiles() {
Zachary Turner0e327d02017-06-15 23:12:41 +0000463 printHeader(P, "Files");
464
Reid Klecknerdd853e52017-07-27 23:13:18 +0000465 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000466
Zachary Turnerf2872b92017-06-15 23:59:56 +0000467 iterateModules(
468 File, P, 11,
469 [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
470 auto &Stream = Err(File.getPDBDbiStream());
Zachary Turner0e327d02017-06-15 23:12:41 +0000471
Zachary Turnerf2872b92017-06-15 23:59:56 +0000472 const DbiModuleList &Modules = Stream.modules();
473 for (const auto &F : Modules.source_files(Modi)) {
474 Strings.formatFromFileName(P, F);
475 }
476 });
Zachary Turner4e950642017-06-15 23:56:19 +0000477 return Error::success();
478}
479
480static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
481 uint32_t Start, const LineColumnEntry &E) {
482 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
483 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
484
485 // Let's try to keep it under 100 characters
486 constexpr uint32_t kMaxRowLength = 100;
487 // At least 3 spaces between columns.
488 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
489 uint32_t ItemsLeft = E.LineNumbers.size();
490 auto LineIter = E.LineNumbers.begin();
491 while (ItemsLeft != 0) {
492 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
493 for (uint32_t I = 0; I < RowColumns; ++I) {
494 LineInfo Line(LineIter->Flags);
495 std::string LineStr;
496 if (Line.isAlwaysStepInto())
497 LineStr = "ASI";
498 else if (Line.isNeverStepInto())
499 LineStr = "NSI";
Zachary Turner0e327d02017-06-15 23:12:41 +0000500 else
Zachary Turner4e950642017-06-15 23:56:19 +0000501 LineStr = utostr(Line.getStartLine());
502 char Statement = Line.isStatement() ? ' ' : '!';
503 P.format("{0} {1:X-} {2} ",
504 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
505 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
506 Statement);
507 ++LineIter;
508 --ItemsLeft;
Zachary Turner63055452017-06-15 22:24:24 +0000509 }
Zachary Turner4e950642017-06-15 23:56:19 +0000510 P.NewLine();
Zachary Turner63055452017-06-15 22:24:24 +0000511 }
Zachary Turner4e950642017-06-15 23:56:19 +0000512}
513
Zachary Turner7df69952017-06-22 20:57:39 +0000514Error DumpOutputStyle::dumpLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000515 printHeader(P, "Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000516
Zachary Turnerf2872b92017-06-15 23:59:56 +0000517 uint32_t LastModi = UINT32_MAX;
518 uint32_t LastNameIndex = UINT32_MAX;
519 iterateModuleSubsections<DebugLinesSubsectionRef>(
520 File, P, 4,
521 [this, &LastModi, &LastNameIndex](uint32_t Modi,
522 StringsAndChecksumsPrinter &Strings,
523 DebugLinesSubsectionRef &Lines) {
524 uint16_t Segment = Lines.header()->RelocSegment;
525 uint32_t Begin = Lines.header()->RelocOffset;
526 uint32_t End = Begin + Lines.header()->CodeSize;
527 for (const auto &Block : Lines) {
528 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
529 LastModi = Modi;
530 LastNameIndex = Block.NameIndex;
531 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
Zachary Turner4e950642017-06-15 23:56:19 +0000532 }
533
Zachary Turnerf2872b92017-06-15 23:59:56 +0000534 AutoIndent Indent(P, 2);
535 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
536 uint32_t Count = Block.LineNumbers.size();
537 if (Lines.hasColumnInfo())
538 P.format("line/column/addr entries = {0}", Count);
539 else
540 P.format("line/addr entries = {0}", Count);
Zachary Turner4e950642017-06-15 23:56:19 +0000541
Zachary Turnerf2872b92017-06-15 23:59:56 +0000542 P.NewLine();
543 typesetLinesAndColumns(File, P, Begin, Block);
Zachary Turner4e950642017-06-15 23:56:19 +0000544 }
545 });
546
547 return Error::success();
548}
549
Zachary Turner7df69952017-06-22 20:57:39 +0000550Error DumpOutputStyle::dumpInlineeLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000551 printHeader(P, "Inlinee Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000552
Zachary Turnerf2872b92017-06-15 23:59:56 +0000553 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
554 File, P, 2,
555 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
556 DebugInlineeLinesSubsectionRef &Lines) {
557 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
558 for (const auto &Entry : Lines) {
559 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
560 fmtle(Entry.Header->SourceLineNum));
561 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
Zachary Turner4e950642017-06-15 23:56:19 +0000562 }
Zachary Turnerf2872b92017-06-15 23:59:56 +0000563 P.NewLine();
Zachary Turner4e950642017-06-15 23:56:19 +0000564 });
565
Zachary Turner63055452017-06-15 22:24:24 +0000566 return Error::success();
567}
Zachary Turner0e327d02017-06-15 23:12:41 +0000568
Zachary Turner7df69952017-06-22 20:57:39 +0000569Error DumpOutputStyle::dumpXmi() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000570 printHeader(P, "Cross Module Imports");
571 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
572 File, P, 2,
573 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
574 DebugCrossModuleImportsSubsectionRef &Imports) {
575 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
576
577 for (const auto &Xmi : Imports) {
578 auto ExpectedModule =
579 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
580 StringRef Module;
581 SmallString<32> ModuleStorage;
582 if (!ExpectedModule) {
583 Module = "(unknown module)";
584 consumeError(ExpectedModule.takeError());
585 } else
586 Module = *ExpectedModule;
587 if (Module.size() > 32) {
588 ModuleStorage = "...";
589 ModuleStorage += Module.take_back(32 - 3);
590 Module = ModuleStorage;
591 }
592 std::vector<std::string> TIs;
593 for (const auto I : Xmi.Imports)
594 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
595 std::string Result =
596 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
597 P.formatLine("{0,+32} | {1}", Module, Result);
598 }
599 });
600
601 return Error::success();
602}
603
Zachary Turner7df69952017-06-22 20:57:39 +0000604Error DumpOutputStyle::dumpXme() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000605 printHeader(P, "Cross Module Exports");
606
607 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
608 File, P, 2,
609 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
610 DebugCrossModuleExportsSubsectionRef &Exports) {
611 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
612 for (const auto &Export : Exports) {
613 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
614 TypeIndex(Export.Global));
615 }
616 });
617
618 return Error::success();
619}
620
Zachary Turner7df69952017-06-22 20:57:39 +0000621Error DumpOutputStyle::dumpStringTable() {
Zachary Turner63055452017-06-15 22:24:24 +0000622 printHeader(P, "String Table");
623
624 AutoIndent Indent(P);
625 auto IS = File.getStringTable();
626 if (!IS) {
627 P.formatLine("Not present in file");
628 consumeError(IS.takeError());
629 return Error::success();
630 }
631
632 if (IS->name_ids().empty()) {
633 P.formatLine("Empty");
634 return Error::success();
635 }
636
637 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
638 uint32_t Digits = NumDigits(*MaxID);
639
640 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
641 "String");
642
643 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
644 std::sort(SortedIDs.begin(), SortedIDs.end());
645 for (uint32_t I : SortedIDs) {
646 auto ES = IS->getStringForID(I);
647 llvm::SmallString<32> Str;
648 if (!ES) {
649 consumeError(ES.takeError());
650 Str = "Error reading string";
651 } else if (!ES->empty()) {
652 Str.append("'");
653 Str.append(*ES);
654 Str.append("'");
655 }
656
657 if (!Str.empty())
658 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
659 }
660 return Error::success();
661}
662
Zachary Turner02a26772017-06-30 18:15:47 +0000663static void buildDepSet(LazyRandomTypeCollection &Types,
664 ArrayRef<TypeIndex> Indices,
665 std::map<TypeIndex, CVType> &DepSet) {
666 SmallVector<TypeIndex, 4> DepList;
667 for (const auto &I : Indices) {
668 TypeIndex TI(I);
669 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
670 continue;
671
672 CVType Type = Types.getType(TI);
673 DepSet[TI] = Type;
674 codeview::discoverTypeIndices(Type, DepList);
675 buildDepSet(Types, DepList, DepSet);
676 }
677}
678
679static void dumpFullTypeStream(LinePrinter &Printer,
680 LazyRandomTypeCollection &Types,
681 TpiStream &Stream, bool Bytes, bool Extras) {
682 Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
683 uint32_t Width =
684 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
685
686 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000687 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000688
689 if (auto EC = codeview::visitTypeStream(Types, V)) {
690 Printer.formatLine("An error occurred dumping type records: {0}",
691 toString(std::move(EC)));
692 }
693}
694
695static void dumpPartialTypeStream(LinePrinter &Printer,
696 LazyRandomTypeCollection &Types,
697 TpiStream &Stream, ArrayRef<TypeIndex> TiList,
698 bool Bytes, bool Extras, bool Deps) {
699 uint32_t Width =
700 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
701
702 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000703 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000704
705 if (opts::dump::DumpTypeDependents) {
706 // If we need to dump all dependents, then iterate each index and find
707 // all dependents, adding them to a map ordered by TypeIndex.
708 std::map<TypeIndex, CVType> DepSet;
709 buildDepSet(Types, TiList, DepSet);
710
711 Printer.formatLine(
712 "Showing {0:N} records and their dependents ({1:N} records total)",
713 TiList.size(), DepSet.size());
714
715 for (auto &Dep : DepSet) {
716 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
717 Printer.formatLine("An error occurred dumping type record {0}: {1}",
718 Dep.first, toString(std::move(EC)));
719 }
720 } else {
721 Printer.formatLine("Showing {0:N} records.", TiList.size());
722
723 for (const auto &I : TiList) {
724 TypeIndex TI(I);
725 CVType Type = Types.getType(TI);
726 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
727 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
728 toString(std::move(EC)));
729 }
730 }
731}
732
Zachary Turner7df69952017-06-22 20:57:39 +0000733Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Zachary Turner63055452017-06-15 22:24:24 +0000734 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
735
736 bool Present = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000737 bool DumpTypes = false;
Zachary Turner63055452017-06-15 22:24:24 +0000738 bool DumpBytes = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000739 bool DumpExtras = false;
Zachary Turner59224cb2017-06-16 23:42:15 +0000740 std::vector<uint32_t> Indices;
Zachary Turner63055452017-06-15 22:24:24 +0000741 if (StreamIdx == StreamTPI) {
742 printHeader(P, "Types (TPI Stream)");
743 Present = File.hasPDBTpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000744 DumpTypes = opts::dump::DumpTypes;
745 DumpBytes = opts::dump::DumpTypeData;
746 DumpExtras = opts::dump::DumpTypeExtras;
747 Indices.assign(opts::dump::DumpTypeIndex.begin(),
748 opts::dump::DumpTypeIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +0000749 } else if (StreamIdx == StreamIPI) {
750 printHeader(P, "Types (IPI Stream)");
751 Present = File.hasPDBIpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000752 DumpTypes = opts::dump::DumpIds;
753 DumpBytes = opts::dump::DumpIdData;
754 DumpExtras = opts::dump::DumpIdExtras;
755 Indices.assign(opts::dump::DumpIdIndex.begin(),
756 opts::dump::DumpIdIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +0000757 }
758
759 AutoIndent Indent(P);
760 if (!Present) {
761 P.formatLine("Stream not present");
762 return Error::success();
763 }
764
Reid Klecknerdd853e52017-07-27 23:13:18 +0000765 ExitOnError Err("Unexpected error processing types: ");
Zachary Turner63055452017-06-15 22:24:24 +0000766
767 auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
768 : File.getPDBIpiStream());
769
Zachary Turner59224cb2017-06-16 23:42:15 +0000770 auto &Types = Err(initializeTypes(StreamIdx));
Zachary Turner63055452017-06-15 22:24:24 +0000771
Zachary Turner02a26772017-06-30 18:15:47 +0000772 if (DumpTypes || !Indices.empty()) {
773 if (Indices.empty())
774 dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
775 else {
776 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
777 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
778 opts::dump::DumpTypeDependents);
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000779 }
780 }
781
782 if (DumpExtras) {
783 P.NewLine();
784 auto IndexOffsets = Stream.getTypeIndexOffsets();
785 P.formatLine("Type Index Offsets:");
786 for (const auto &IO : IndexOffsets) {
787 AutoIndent Indent2(P);
788 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
789 }
790
791 P.NewLine();
792 P.formatLine("Hash Adjusters:");
793 auto &Adjusters = Stream.getHashAdjusters();
794 auto &Strings = Err(File.getStringTable());
795 for (const auto &A : Adjusters) {
796 AutoIndent Indent2(P);
797 auto ExpectedStr = Strings.getStringForID(A.first);
798 TypeIndex TI(A.second);
799 if (ExpectedStr)
800 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
801 else {
802 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
803 consumeError(ExpectedStr.takeError());
804 }
805 }
Zachary Turner63055452017-06-15 22:24:24 +0000806 }
807 return Error::success();
808}
809
810Expected<codeview::LazyRandomTypeCollection &>
Zachary Turner7df69952017-06-22 20:57:39 +0000811DumpOutputStyle::initializeTypes(uint32_t SN) {
Zachary Turner63055452017-06-15 22:24:24 +0000812 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
813 auto Tpi =
814 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
815 if (!Tpi)
816 return Tpi.takeError();
817
818 if (!TypeCollection) {
819 auto &Types = Tpi->typeArray();
820 uint32_t Count = Tpi->getNumTypeRecords();
821 auto Offsets = Tpi->getTypeIndexOffsets();
822 TypeCollection =
823 llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
824 }
825
826 return *TypeCollection;
827}
828
Zachary Turner7df69952017-06-22 20:57:39 +0000829Error DumpOutputStyle::dumpModuleSyms() {
Zachary Turner63055452017-06-15 22:24:24 +0000830 printHeader(P, "Symbols");
831
832 AutoIndent Indent(P);
833 if (!File.hasPDBDbiStream()) {
834 P.formatLine("DBI Stream not present");
835 return Error::success();
836 }
837
Reid Klecknerdd853e52017-07-27 23:13:18 +0000838 ExitOnError Err("Unexpected error processing symbols: ");
Zachary Turner63055452017-06-15 22:24:24 +0000839
Zachary Turner59224cb2017-06-16 23:42:15 +0000840 auto &Types = Err(initializeTypes(StreamTPI));
Zachary Turner63055452017-06-15 22:24:24 +0000841
Zachary Turner58699362017-08-03 23:11:52 +0000842 iterateModules(
843 File, P, 2, [&](uint32_t I, StringsAndChecksumsPrinter &Strings) {
844 auto ExpectedModS = getModuleDebugStream(File, I);
845 if (!ExpectedModS) {
846 P.formatLine("Error loading module stream {0}. {1}", I,
847 toString(ExpectedModS.takeError()));
848 return;
849 }
Zachary Turner63055452017-06-15 22:24:24 +0000850
Zachary Turner58699362017-08-03 23:11:52 +0000851 ModuleDebugStreamRef &ModS = *ExpectedModS;
Zachary Turner63055452017-06-15 22:24:24 +0000852
Zachary Turner58699362017-08-03 23:11:52 +0000853 SymbolVisitorCallbackPipeline Pipeline;
854 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
855 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
Zachary Turner63055452017-06-15 22:24:24 +0000856
Zachary Turner58699362017-08-03 23:11:52 +0000857 Pipeline.addCallbackToPipeline(Deserializer);
858 Pipeline.addCallbackToPipeline(Dumper);
859 CVSymbolVisitor Visitor(Pipeline);
860 auto SS = ModS.getSymbolsSubstream();
861 if (auto EC =
862 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
863 P.formatLine("Error while processing symbol records. {0}",
864 toString(std::move(EC)));
865 return;
866 }
867 });
Zachary Turner63055452017-06-15 22:24:24 +0000868 return Error::success();
869}
870
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000871Error DumpOutputStyle::dumpGlobals() {
872 printHeader(P, "Global Symbols");
873 AutoIndent Indent(P);
874 if (!File.hasPDBGlobalsStream()) {
875 P.formatLine("Globals stream not present");
876 return Error::success();
877 }
Reid Klecknerdd853e52017-07-27 23:13:18 +0000878 ExitOnError Err("Error dumping globals stream: ");
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000879 auto &Globals = Err(File.getPDBGlobalsStream());
880
881 const GSIHashTable &Table = Globals.getGlobalsTable();
882 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
883 return Error::success();
884}
885
Zachary Turner7df69952017-06-22 20:57:39 +0000886Error DumpOutputStyle::dumpPublics() {
Zachary Turner63055452017-06-15 22:24:24 +0000887 printHeader(P, "Public Symbols");
Zachary Turner63055452017-06-15 22:24:24 +0000888 AutoIndent Indent(P);
889 if (!File.hasPDBPublicsStream()) {
890 P.formatLine("Publics stream not present");
891 return Error::success();
892 }
Reid Klecknerdd853e52017-07-27 23:13:18 +0000893 ExitOnError Err("Error dumping publics stream: ");
Zachary Turner63055452017-06-15 22:24:24 +0000894 auto &Publics = Err(File.getPDBPublicsStream());
Zachary Turner63055452017-06-15 22:24:24 +0000895
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000896 const GSIHashTable &PublicsTable = Publics.getPublicsTable();
897 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
Zachary Turneraf8c75a2017-06-30 21:35:00 +0000898
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000899 // Skip the rest if we aren't dumping extras.
Reid Kleckner686f1212017-07-21 18:28:55 +0000900 if (!opts::dump::DumpPublicExtras)
901 return Error::success();
902
Reid Kleckner686f1212017-07-21 18:28:55 +0000903 P.formatLine("Address Map");
904 {
905 // These are offsets into the publics stream sorted by secidx:secrel.
906 AutoIndent Indent2(P);
907 for (uint32_t Addr : Publics.getAddressMap())
908 P.formatLine("off = {0}", Addr);
909 }
910
911 // The thunk map is optional debug info used for ILT thunks.
912 if (!Publics.getThunkMap().empty()) {
913 P.formatLine("Thunk Map");
914 AutoIndent Indent2(P);
915 for (uint32_t Addr : Publics.getThunkMap())
916 P.formatLine("{0:x8}", Addr);
917 }
918
919 // The section offsets table appears to be empty when incremental linking
920 // isn't in use.
921 if (!Publics.getSectionOffsets().empty()) {
922 P.formatLine("Section Offsets");
923 AutoIndent Indent2(P);
924 for (const SectionOffset &SO : Publics.getSectionOffsets())
925 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
926 }
927
Zachary Turner63055452017-06-15 22:24:24 +0000928 return Error::success();
929}
930
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000931Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
932 bool HashExtras) {
933 auto ExpectedSyms = File.getPDBSymbolStream();
934 if (!ExpectedSyms)
935 return ExpectedSyms.takeError();
936 auto ExpectedTypes = initializeTypes(StreamTPI);
937 if (!ExpectedTypes)
938 return ExpectedTypes.takeError();
939 SymbolVisitorCallbackPipeline Pipeline;
940 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
941 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, *ExpectedTypes);
942
943 Pipeline.addCallbackToPipeline(Deserializer);
944 Pipeline.addCallbackToPipeline(Dumper);
945 CVSymbolVisitor Visitor(Pipeline);
946
947 BinaryStreamRef SymStream =
948 ExpectedSyms->getSymbolArray().getUnderlyingStream();
949 for (uint32_t PubSymOff : Table) {
950 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
951 if (!Sym)
952 return Sym.takeError();
953 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
954 return E;
955 }
956
957 // Return early if we aren't dumping public hash table and address map info.
958 if (!HashExtras)
959 return Error::success();
960
961 P.formatLine("Hash Records");
962 {
963 AutoIndent Indent2(P);
964 for (const PSHashRecord &HR : Table.HashRecords)
965 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
966 uint32_t(HR.CRef));
967 }
968
969 // FIXME: Dump the bitmap.
970
971 P.formatLine("Hash Buckets");
972 {
973 AutoIndent Indent2(P);
974 for (uint32_t Hash : Table.HashBuckets)
975 P.formatLine("{0:x8}", Hash);
976 }
977
978 return Error::success();
979}
980
Zachary Turner63055452017-06-15 22:24:24 +0000981static std::string formatSectionCharacteristics(uint32_t IndentLevel,
Zachary Turnerfb1cd502017-08-04 20:02:38 +0000982 uint32_t C,
983 uint32_t FlagsPerLine,
984 StringRef Separator) {
Zachary Turner63055452017-06-15 22:24:24 +0000985 using SC = COFF::SectionCharacteristics;
986 std::vector<std::string> Opts;
987 if (C == COFF::SC_Invalid)
988 return "invalid";
989 if (C == 0)
990 return "none";
991
992 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
993 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
994 PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
995 PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
996 "IMAGE_SCN_CNT_INITIALIZED_DATA");
997 PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
998 "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
999 PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
1000 PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
1001 PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
1002 PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
1003 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
1004 PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
1005 PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
1006 PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
1007 PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
1008 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
1009 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
1010 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
1011 "IMAGE_SCN_ALIGN_1BYTES");
1012 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
1013 "IMAGE_SCN_ALIGN_2BYTES");
1014 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
1015 "IMAGE_SCN_ALIGN_4BYTES");
1016 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
1017 "IMAGE_SCN_ALIGN_8BYTES");
1018 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
1019 "IMAGE_SCN_ALIGN_16BYTES");
1020 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
1021 "IMAGE_SCN_ALIGN_32BYTES");
1022 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
1023 "IMAGE_SCN_ALIGN_64BYTES");
1024 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
1025 "IMAGE_SCN_ALIGN_128BYTES");
1026 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
1027 "IMAGE_SCN_ALIGN_256BYTES");
1028 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
1029 "IMAGE_SCN_ALIGN_512BYTES");
1030 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
1031 "IMAGE_SCN_ALIGN_1024BYTES");
1032 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
1033 "IMAGE_SCN_ALIGN_2048BYTES");
1034 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
1035 "IMAGE_SCN_ALIGN_4096BYTES");
1036 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
1037 "IMAGE_SCN_ALIGN_8192BYTES");
1038 PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
1039 PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
1040 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
1041 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
1042 PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
1043 PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
1044 PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
1045 PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001046 return typesetItemList(Opts, IndentLevel, FlagsPerLine, Separator);
Zachary Turner63055452017-06-15 22:24:24 +00001047}
1048
1049static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1050 OMFSegDescFlags Flags) {
1051 std::vector<std::string> Opts;
1052 if (Flags == OMFSegDescFlags::None)
1053 return "none";
1054
1055 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
1056 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
1057 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
1058 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
1059 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
1060 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
1061 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
Zachary Turner47d9a562017-06-16 00:04:24 +00001062 return typesetItemList(Opts, IndentLevel, 4, " | ");
Zachary Turner63055452017-06-15 22:24:24 +00001063}
1064
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001065Error DumpOutputStyle::dumpSectionHeaders() {
1066 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1067 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1068 return Error::success();
1069}
1070
1071void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1072 printHeader(P, Label);
1073 ExitOnError Err("Error dumping publics stream: ");
1074
1075 AutoIndent Indent(P);
1076 if (!File.hasPDBDbiStream()) {
1077 P.formatLine(
1078 "Section headers require a DBI Stream, which could not be loaded");
1079 return;
1080 }
1081
1082 auto &Dbi = Err(File.getPDBDbiStream());
1083 uint32_t SI = Dbi.getDebugStreamIndex(Type);
1084
1085 if (SI == kInvalidStreamIndex) {
1086 P.formatLine(
1087 "PDB does not contain the requested image section header type");
1088 return;
1089 }
1090
1091 auto Stream = MappedBlockStream::createIndexedStream(
1092 File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
1093 if (!Stream) {
1094 P.formatLine("Could not load the required stream data");
1095 return;
1096 }
1097 ArrayRef<object::coff_section> Headers;
1098 if (Stream->getLength() % sizeof(object::coff_section) != 0) {
1099 P.formatLine(
1100 "Section header array size is not a multiple of section header size");
1101 return;
1102 }
1103 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
1104 BinaryStreamReader Reader(*Stream);
1105 cantFail(Reader.readArray(Headers, NumHeaders));
1106 if (Headers.empty()) {
1107 P.formatLine("No section headers");
1108 return;
1109 }
1110
1111 uint32_t I = 1;
1112 for (const auto &Header : Headers) {
1113 P.NewLine();
1114 P.formatLine("SECTION HEADER #{0}", I);
1115 P.formatLine("{0,8} name", Header.Name);
1116 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1117 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1118 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1119 P.formatLine("{0,8:X-} file pointer to raw data",
1120 uint32_t(Header.PointerToRawData));
1121 P.formatLine("{0,8:X-} file pointer to relocation table",
1122 uint32_t(Header.PointerToRelocations));
1123 P.formatLine("{0,8:X-} file pointer to line numbers",
1124 uint32_t(Header.PointerToLinenumbers));
1125 P.formatLine("{0,8:X-} number of relocations",
1126 uint32_t(Header.NumberOfRelocations));
1127 P.formatLine("{0,8:X-} number of line numbers",
1128 uint32_t(Header.NumberOfLinenumbers));
1129 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1130 AutoIndent IndentMore(P, 9);
1131 P.formatLine("{0}", formatSectionCharacteristics(
1132 P.getIndentLevel(), Header.Characteristics, 1, ""));
1133 ++I;
1134 }
1135 return;
1136}
1137
Zachary Turner7df69952017-06-22 20:57:39 +00001138Error DumpOutputStyle::dumpSectionContribs() {
Zachary Turner63055452017-06-15 22:24:24 +00001139 printHeader(P, "Section Contributions");
Reid Klecknerdd853e52017-07-27 23:13:18 +00001140 ExitOnError Err("Error dumping publics stream: ");
Zachary Turner63055452017-06-15 22:24:24 +00001141
1142 AutoIndent Indent(P);
1143 if (!File.hasPDBDbiStream()) {
1144 P.formatLine(
1145 "Section contribs require a DBI Stream, which could not be loaded");
1146 return Error::success();
1147 }
1148
1149 auto &Dbi = Err(File.getPDBDbiStream());
1150
1151 class Visitor : public ISectionContribVisitor {
1152 public:
1153 Visitor(LinePrinter &P) : P(P) {}
1154 void visit(const SectionContrib &SC) override {
1155 P.formatLine(
1156 "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
1157 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
1158 fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
1159 P.formatLine(" {0}",
1160 formatSectionCharacteristics(P.getIndentLevel() + 6,
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001161 SC.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001162 }
1163 void visit(const SectionContrib2 &SC) override {
1164 P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1165 "crc = {4}, coff section = {5}",
1166 formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
1167 fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
1168 fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1169 fmtle(SC.ISectCoff));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001170 P.formatLine(" {0}", formatSectionCharacteristics(
1171 P.getIndentLevel() + 6,
1172 SC.Base.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001173 }
1174
1175 private:
1176 LinePrinter &P;
1177 };
1178
1179 Visitor V(P);
1180 Dbi.visitSectionContributions(V);
1181 return Error::success();
1182}
1183
Zachary Turner7df69952017-06-22 20:57:39 +00001184Error DumpOutputStyle::dumpSectionMap() {
Zachary Turner63055452017-06-15 22:24:24 +00001185 printHeader(P, "Section Map");
Reid Klecknerdd853e52017-07-27 23:13:18 +00001186 ExitOnError Err("Error dumping section map: ");
Zachary Turner63055452017-06-15 22:24:24 +00001187
1188 AutoIndent Indent(P);
1189 if (!File.hasPDBDbiStream()) {
1190 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1191 "not be loaded");
1192 return Error::success();
1193 }
1194
1195 auto &Dbi = Err(File.getPDBDbiStream());
1196
1197 uint32_t I = 0;
1198 for (auto &M : Dbi.getSectionMap()) {
1199 P.formatLine(
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001200 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
Zachary Turner63055452017-06-15 22:24:24 +00001201 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1202 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1203 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1204 P.formatLine(" flags = {0}",
1205 formatSegMapDescriptorFlag(
1206 P.getIndentLevel() + 13,
1207 static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1208 ++I;
1209 }
1210 return Error::success();
1211}