1 //===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "RawOutputStyle.h"
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"
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"
61 #include <unordered_map>
64 using namespace llvm::codeview;
65 using namespace llvm::msf;
66 using namespace llvm::pdb;
68 RawOutputStyle::RawOutputStyle(PDBFile &File)
69 : File(File), P(2, false, outs()) {}
71 Error RawOutputStyle::dump() {
72 if (opts::raw::DumpSummary) {
73 if (auto EC = dumpFileSummary())
78 if (opts::raw::DumpStreams) {
79 if (auto EC = dumpStreamSummary())
84 if (opts::raw::DumpBlockRange.hasValue()) {
85 if (auto EC = dumpBlockRanges())
90 if (!opts::raw::DumpStreamData.empty()) {
91 if (auto EC = dumpStreamBytes())
96 if (opts::raw::DumpStringTable) {
97 if (auto EC = dumpStringTable())
102 if (opts::raw::DumpModules) {
103 if (auto EC = dumpModules())
107 if (opts::raw::DumpModuleFiles) {
108 if (auto EC = dumpModuleFiles())
112 if (opts::raw::DumpLines) {
113 if (auto EC = dumpLines())
117 if (opts::raw::DumpInlineeLines) {
118 if (auto EC = dumpInlineeLines())
122 if (opts::raw::DumpXmi) {
123 if (auto EC = dumpXmi())
127 if (opts::raw::DumpXme) {
128 if (auto EC = dumpXme())
132 if (opts::raw::DumpTypes || opts::raw::DumpTypeExtras) {
133 if (auto EC = dumpTpiStream(StreamTPI))
137 if (opts::raw::DumpIds || opts::raw::DumpIdExtras) {
138 if (auto EC = dumpTpiStream(StreamIPI))
142 if (opts::raw::DumpPublics) {
143 if (auto EC = dumpPublics())
147 if (opts::raw::DumpSymbols) {
148 if (auto EC = dumpModuleSyms())
152 if (opts::raw::DumpSectionContribs) {
153 if (auto EC = dumpSectionContribs())
157 if (opts::raw::DumpSectionMap) {
158 if (auto EC = dumpSectionMap())
162 return Error::success();
165 static void printHeader(LinePrinter &P, const Twine &S) {
167 P.formatLine("{0,=60}", S);
168 P.formatLine("{0}", fmt_repeat('=', 60));
171 Error RawOutputStyle::dumpFileSummary() {
172 printHeader(P, "Summary");
174 ExitOnError Err("Invalid PDB Format");
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());
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());
198 return Error::success();
201 Error RawOutputStyle::dumpStreamSummary() {
202 printHeader(P, "Streams");
204 if (StreamPurposes.empty())
205 discoverStreamPurposes(File, StreamPurposes);
207 AutoIndent Indent(P);
208 uint32_t StreamCount = File.getNumStreams();
210 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
212 "Stream {0}: [{1}] ({2} bytes)",
213 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
214 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
217 return Error::success();
220 Error RawOutputStyle::dumpBlockRanges() {
221 printHeader(P, "MSF Blocks");
223 auto &R = *opts::raw::DumpBlockRange;
224 uint32_t Max = R.Max.getValueOr(R.Min);
226 AutoIndent Indent(P);
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));
236 for (uint32_t I = R.Min; I <= Max; ++I) {
237 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
239 return ExpectedData.takeError();
240 std::string Label = formatv("Block {0}", I).str();
241 P.formatBinary(Label, *ExpectedData, 0);
244 return Error::success();
247 static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
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");
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");
263 return make_error<RawError>(raw_error_code::invalid_format,
264 "Invalid Stream Specification");
265 return Error::success();
268 Error RawOutputStyle::dumpStreamBytes() {
269 if (StreamPurposes.empty())
270 discoverStreamPurposes(File, StreamPurposes);
272 printHeader(P, "Stream Data");
273 ExitOnError Err("Unexpected error reading stream data");
275 for (auto &Str : opts::raw::DumpStreamData) {
281 if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
284 AutoIndent Indent(P);
285 if (SI >= File.getNumStreams()) {
286 P.formatLine("Stream {0}: Not present", SI);
290 auto S = MappedBlockStream::createIndexedStream(
291 File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
294 P.formatLine("Stream {0}: Not present", SI);
299 End = S->getLength();
301 End = std::min(Begin + Size, S->getLength());
303 P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
305 AutoIndent Indent2(P);
307 BinaryStreamReader R(*S);
308 ArrayRef<uint8_t> StreamData;
309 Err(R.readBytes(StreamData, S->getLength()));
311 StreamData = StreamData.slice(Begin, Size);
312 P.formatBinary("Data", StreamData, Begin);
314 return Error::success();
317 static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
319 ExitOnError Err("Unexpected error");
321 auto &Dbi = Err(File.getPDBDbiStream());
322 const auto &Modules = Dbi.modules();
323 auto Modi = Modules.getModuleDescriptor(Index);
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");
330 auto ModStreamData = MappedBlockStream::createIndexedStream(
331 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
332 File.getAllocator());
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");
339 return std::move(ModS);
342 static std::string formatChecksumKind(FileChecksumKind 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");
349 return formatUnknownEnum(Kind);
353 class StringsAndChecksumsPrinter {
354 const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
355 ExitOnError Err("Unexpected error processing modules");
356 return Err(File.getStringTable()).getStringTable();
359 template <typename... Args>
360 void formatInternal(LinePrinter &Printer, bool Append,
361 Args &&... args) const {
363 Printer.format(std::forward<Args>(args)...);
365 Printer.formatLine(std::forward<Args>(args)...);
369 StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
370 : Records(extractStringTable(File)) {
371 auto MDS = getModuleDebugStream(File, Modi);
373 consumeError(MDS.takeError());
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);
384 ChecksumsByFile[*S] = Entry;
389 Expected<StringRef> getNameFromStringTable(uint32_t Offset) const {
390 return Records.strings().getString(Offset);
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);
401 formatInternal(Printer, Append, "- ({0}: {1}) {2}",
402 formatChecksumKind(FC->getValue().Kind),
403 toHex(FC->getValue().Checksum), File);
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);
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);
419 uint32_t FO = Iter->FileNameOffset;
420 auto ExpectedFile = getNameFromStringTable(FO);
422 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
423 consumeError(ExpectedFile.takeError());
426 if (Iter->Kind == FileChecksumKind::None) {
427 formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
429 formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
430 formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
434 std::unique_ptr<ModuleDebugStreamRef> DebugStream;
435 StringsAndChecksumsRef Records;
436 StringMap<FileChecksumEntry> ChecksumsByFile;
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");
449 ExitOnError Err("Unexpected error processing modules");
451 auto &Stream = Err(File.getPDBDbiStream());
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());
461 StringsAndChecksumsPrinter Strings(File, I);
462 AutoIndent Indent2(P, IndentLevel);
463 Callback(I, Strings);
467 template <typename SubsectionT>
468 static void iterateModuleSubsections(
469 PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
470 llvm::function_ref<void(uint32_t, StringsAndChecksumsPrinter &,
475 File, P, IndentLevel,
476 [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
477 auto MDS = getModuleDebugStream(File, Modi);
479 consumeError(MDS.takeError());
483 for (const auto &SS : MDS->subsections()) {
484 SubsectionT Subsection;
486 if (SS.kind() != Subsection.kind())
489 BinaryStreamReader Reader(SS.getRecordData());
490 if (auto EC = Subsection.initialize(Reader))
492 Callback(Modi, Strings, Subsection);
497 Error RawOutputStyle::dumpModules() {
498 printHeader(P, "Modules");
500 AutoIndent Indent(P);
501 if (!File.hasPDBDbiStream()) {
502 P.formatLine("DBI Stream not present");
503 return Error::success();
506 ExitOnError Err("Unexpected error processing modules");
508 auto &Stream = Err(File.getPDBDbiStream());
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(),
522 return Error::success();
525 Error RawOutputStyle::dumpModuleFiles() {
526 printHeader(P, "Files");
528 ExitOnError Err("Unexpected error processing modules");
532 [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
533 auto &Stream = Err(File.getPDBDbiStream());
535 const DbiModuleList &Modules = Stream.modules();
536 for (const auto &F : Modules.source_files(Modi)) {
537 Strings.formatFromFileName(P, F);
540 return Error::success();
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;
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);
559 if (Line.isAlwaysStepInto())
561 else if (Line.isNeverStepInto())
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'),
577 Error RawOutputStyle::dumpLines() {
578 printHeader(P, "Lines");
580 uint32_t LastModi = UINT32_MAX;
581 uint32_t LastNameIndex = UINT32_MAX;
582 iterateModuleSubsections<DebugLinesSubsectionRef>(
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) {
593 LastNameIndex = Block.NameIndex;
594 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
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);
603 P.format("line/addr entries = {0}", Count);
606 typesetLinesAndColumns(File, P, Begin, Block);
610 return Error::success();
613 Error RawOutputStyle::dumpInlineeLines() {
614 printHeader(P, "Inlinee Lines");
616 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
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);
629 return Error::success();
632 Error RawOutputStyle::dumpXmi() {
633 printHeader(P, "Cross Module Imports");
634 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
636 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
637 DebugCrossModuleImportsSubsectionRef &Imports) {
638 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
640 for (const auto &Xmi : Imports) {
641 auto ExpectedModule =
642 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
644 SmallString<32> ModuleStorage;
645 if (!ExpectedModule) {
646 Module = "(unknown module)";
647 consumeError(ExpectedModule.takeError());
649 Module = *ExpectedModule;
650 if (Module.size() > 32) {
651 ModuleStorage = "...";
652 ModuleStorage += Module.take_back(32 - 3);
653 Module = ModuleStorage;
655 std::vector<std::string> TIs;
656 for (const auto I : Xmi.Imports)
657 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
659 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
660 P.formatLine("{0,+32} | {1}", Module, Result);
664 return Error::success();
667 Error RawOutputStyle::dumpXme() {
668 printHeader(P, "Cross Module Exports");
670 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
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));
681 return Error::success();
684 Error RawOutputStyle::dumpStringTable() {
685 printHeader(P, "String Table");
687 AutoIndent Indent(P);
688 auto IS = File.getStringTable();
690 P.formatLine("Not present in file");
691 consumeError(IS.takeError());
692 return Error::success();
695 if (IS->name_ids().empty()) {
696 P.formatLine("Empty");
697 return Error::success();
700 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
701 uint32_t Digits = NumDigits(*MaxID);
703 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
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;
712 consumeError(ES.takeError());
713 Str = "Error reading string";
714 } else if (!ES->empty()) {
721 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
723 return Error::success();
726 Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
727 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
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;
747 AutoIndent Indent(P);
749 P.formatLine("Stream not present");
750 return Error::success();
753 ExitOnError Err("Unexpected error processing types");
755 auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
756 : File.getPDBIpiStream());
758 auto &Types = Err(initializeTypeDatabase(StreamIdx));
761 P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
763 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
765 MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
766 Stream.getHashValues());
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)));
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));
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);
793 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
795 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
796 consumeError(ExpectedStr.takeError());
800 return Error::success();
803 Expected<codeview::LazyRandomTypeCollection &>
804 RawOutputStyle::initializeTypeDatabase(uint32_t SN) {
805 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
807 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
809 return Tpi.takeError();
811 if (!TypeCollection) {
812 auto &Types = Tpi->typeArray();
813 uint32_t Count = Tpi->getNumTypeRecords();
814 auto Offsets = Tpi->getTypeIndexOffsets();
816 llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
819 return *TypeCollection;
822 Error RawOutputStyle::dumpModuleSyms() {
823 printHeader(P, "Symbols");
825 AutoIndent Indent(P);
826 if (!File.hasPDBDbiStream()) {
827 P.formatLine("DBI Stream not present");
828 return Error::success();
831 ExitOnError Err("Unexpected error processing symbols");
833 auto &Stream = Err(File.getPDBDbiStream());
835 auto &Types = Err(initializeTypeDatabase(StreamTPI));
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>");
849 auto ModStreamData = MappedBlockStream::createIndexedStream(
850 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
851 File.getAllocator());
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)));
860 SymbolVisitorCallbackPipeline Pipeline;
861 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
862 MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
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)));
873 return Error::success();
876 Error RawOutputStyle::dumpPublics() {
877 printHeader(P, "Public Symbols");
879 AutoIndent Indent(P);
880 if (!File.hasPDBPublicsStream()) {
881 P.formatLine("Publics stream not present");
882 return Error::success();
885 ExitOnError Err("Error dumping publics stream");
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);
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();
902 if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols))
903 P.formatLine("Error while processing public symbol records. {0}",
904 toString(std::move(EC)));
906 return Error::success();
909 static std::string formatSectionCharacteristics(uint32_t IndentLevel,
911 using SC = COFF::SectionCharacteristics;
912 std::vector<std::string> Opts;
913 if (C == COFF::SC_Invalid)
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, " | ");
975 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
976 OMFSegDescFlags Flags) {
977 std::vector<std::string> Opts;
978 if (Flags == OMFSegDescFlags::None)
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, " | ");
991 Error RawOutputStyle::dumpSectionContribs() {
992 printHeader(P, "Section Contributions");
993 ExitOnError Err("Error dumping publics stream");
995 AutoIndent Indent(P);
996 if (!File.hasPDBDbiStream()) {
998 "Section contribs require a DBI Stream, which could not be loaded");
999 return Error::success();
1002 auto &Dbi = Err(File.getPDBDbiStream());
1004 class Visitor : public ISectionContribVisitor {
1006 Visitor(LinePrinter &P) : P(P) {}
1007 void visit(const SectionContrib &SC) override {
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));
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));
1033 Dbi.visitSectionContributions(V);
1034 return Error::success();
1037 Error RawOutputStyle::dumpSectionMap() {
1038 printHeader(P, "Section Map");
1039 ExitOnError Err("Error dumping section map");
1041 AutoIndent Indent(P);
1042 if (!File.hasPDBDbiStream()) {
1043 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1045 return Error::success();
1048 auto &Dbi = Err(File.getPDBDbiStream());
1051 for (auto &M : Dbi.getSectionMap()) {
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))));
1063 return Error::success();