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