xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "BytesOutputStyle.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "StreamUtil.h"
120b57cec5SDimitry Andric #include "llvm-pdbutil.h"
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Formatters.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MSFCommon.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
19*81ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
220b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
230b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
240b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
250b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
260b57cec5SDimitry Andric #include "llvm/Support/FormatAdapters.h"
270b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric using namespace llvm::codeview;
310b57cec5SDimitry Andric using namespace llvm::msf;
320b57cec5SDimitry Andric using namespace llvm::pdb;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace {
350b57cec5SDimitry Andric struct StreamSpec {
360b57cec5SDimitry Andric   uint32_t SI = 0;
370b57cec5SDimitry Andric   uint32_t Begin = 0;
380b57cec5SDimitry Andric   uint32_t Size = 0;
390b57cec5SDimitry Andric };
400b57cec5SDimitry Andric } // namespace
410b57cec5SDimitry Andric 
parseStreamSpec(StringRef Str)420b57cec5SDimitry Andric static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
430b57cec5SDimitry Andric   StreamSpec Result;
440b57cec5SDimitry Andric   if (Str.consumeInteger(0, Result.SI))
450b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::invalid_format,
460b57cec5SDimitry Andric                                 "Invalid Stream Specification");
470b57cec5SDimitry Andric   if (Str.consume_front(":")) {
480b57cec5SDimitry Andric     if (Str.consumeInteger(0, Result.Begin))
490b57cec5SDimitry Andric       return make_error<RawError>(raw_error_code::invalid_format,
500b57cec5SDimitry Andric                                   "Invalid Stream Specification");
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric   if (Str.consume_front("@")) {
530b57cec5SDimitry Andric     if (Str.consumeInteger(0, Result.Size))
540b57cec5SDimitry Andric       return make_error<RawError>(raw_error_code::invalid_format,
550b57cec5SDimitry Andric                                   "Invalid Stream Specification");
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   if (!Str.empty())
590b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::invalid_format,
600b57cec5SDimitry Andric                                 "Invalid Stream Specification");
610b57cec5SDimitry Andric   return Result;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
parseStreamSpecs(LinePrinter & P)640b57cec5SDimitry Andric static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
650b57cec5SDimitry Andric   SmallVector<StreamSpec, 2> Result;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   for (auto &Str : opts::bytes::DumpStreamData) {
680b57cec5SDimitry Andric     auto ESS = parseStreamSpec(Str);
690b57cec5SDimitry Andric     if (!ESS) {
700b57cec5SDimitry Andric       P.formatLine("Error parsing stream spec {0}: {1}", Str,
710b57cec5SDimitry Andric                    toString(ESS.takeError()));
720b57cec5SDimitry Andric       continue;
730b57cec5SDimitry Andric     }
740b57cec5SDimitry Andric     Result.push_back(*ESS);
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric   return Result;
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
printHeader(LinePrinter & P,const Twine & S)790b57cec5SDimitry Andric static void printHeader(LinePrinter &P, const Twine &S) {
800b57cec5SDimitry Andric   P.NewLine();
810b57cec5SDimitry Andric   P.formatLine("{0,=60}", S);
820b57cec5SDimitry Andric   P.formatLine("{0}", fmt_repeat('=', 60));
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
BytesOutputStyle(PDBFile & File)850b57cec5SDimitry Andric BytesOutputStyle::BytesOutputStyle(PDBFile &File)
86*81ad6265SDimitry Andric     : File(File), P(2, false, outs(), opts::Filters) {}
870b57cec5SDimitry Andric 
dump()880b57cec5SDimitry Andric Error BytesOutputStyle::dump() {
890b57cec5SDimitry Andric 
90*81ad6265SDimitry Andric   if (opts::bytes::DumpBlockRange) {
910b57cec5SDimitry Andric     auto &R = *opts::bytes::DumpBlockRange;
92*81ad6265SDimitry Andric     uint32_t Max = R.Max.value_or(R.Min);
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric     if (Max < R.Min)
950b57cec5SDimitry Andric       return make_error<StringError>(
960b57cec5SDimitry Andric           "Invalid block range specified.  Max < Min",
970b57cec5SDimitry Andric           inconvertibleErrorCode());
980b57cec5SDimitry Andric     if (Max >= File.getBlockCount())
990b57cec5SDimitry Andric       return make_error<StringError>(
1000b57cec5SDimitry Andric           "Invalid block range specified.  Requested block out of bounds",
1010b57cec5SDimitry Andric           inconvertibleErrorCode());
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric     dumpBlockRanges(R.Min, Max);
1040b57cec5SDimitry Andric     P.NewLine();
1050b57cec5SDimitry Andric   }
1060b57cec5SDimitry Andric 
107*81ad6265SDimitry Andric   if (opts::bytes::DumpByteRange) {
1080b57cec5SDimitry Andric     auto &R = *opts::bytes::DumpByteRange;
109*81ad6265SDimitry Andric     uint32_t Max = R.Max.value_or(File.getFileSize());
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric     if (Max < R.Min)
1120b57cec5SDimitry Andric       return make_error<StringError>("Invalid byte range specified.  Max < Min",
1130b57cec5SDimitry Andric                                      inconvertibleErrorCode());
1140b57cec5SDimitry Andric     if (Max >= File.getFileSize())
1150b57cec5SDimitry Andric       return make_error<StringError>(
1160b57cec5SDimitry Andric           "Invalid byte range specified.  Requested byte larger than file size",
1170b57cec5SDimitry Andric           inconvertibleErrorCode());
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     dumpByteRanges(R.Min, Max);
1200b57cec5SDimitry Andric     P.NewLine();
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   if (opts::bytes::Fpm) {
1240b57cec5SDimitry Andric     dumpFpm();
1250b57cec5SDimitry Andric     P.NewLine();
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   if (!opts::bytes::DumpStreamData.empty()) {
1290b57cec5SDimitry Andric     dumpStreamBytes();
1300b57cec5SDimitry Andric     P.NewLine();
1310b57cec5SDimitry Andric   }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (opts::bytes::NameMap) {
1340b57cec5SDimitry Andric     dumpNameMap();
1350b57cec5SDimitry Andric     P.NewLine();
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   if (opts::bytes::SectionContributions) {
1390b57cec5SDimitry Andric     dumpSectionContributions();
1400b57cec5SDimitry Andric     P.NewLine();
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   if (opts::bytes::SectionMap) {
1440b57cec5SDimitry Andric     dumpSectionMap();
1450b57cec5SDimitry Andric     P.NewLine();
1460b57cec5SDimitry Andric   }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   if (opts::bytes::ModuleInfos) {
1490b57cec5SDimitry Andric     dumpModuleInfos();
1500b57cec5SDimitry Andric     P.NewLine();
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   if (opts::bytes::FileInfo) {
1540b57cec5SDimitry Andric     dumpFileInfo();
1550b57cec5SDimitry Andric     P.NewLine();
1560b57cec5SDimitry Andric   }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   if (opts::bytes::TypeServerMap) {
1590b57cec5SDimitry Andric     dumpTypeServerMap();
1600b57cec5SDimitry Andric     P.NewLine();
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   if (opts::bytes::ECData) {
1640b57cec5SDimitry Andric     dumpECData();
1650b57cec5SDimitry Andric     P.NewLine();
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   if (!opts::bytes::TypeIndex.empty()) {
1690b57cec5SDimitry Andric     dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
1700b57cec5SDimitry Andric     P.NewLine();
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   if (!opts::bytes::IdIndex.empty()) {
1740b57cec5SDimitry Andric     dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
1750b57cec5SDimitry Andric     P.NewLine();
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   if (opts::bytes::ModuleSyms) {
1790b57cec5SDimitry Andric     dumpModuleSyms();
1800b57cec5SDimitry Andric     P.NewLine();
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   if (opts::bytes::ModuleC11) {
1840b57cec5SDimitry Andric     dumpModuleC11();
1850b57cec5SDimitry Andric     P.NewLine();
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   if (opts::bytes::ModuleC13) {
1890b57cec5SDimitry Andric     dumpModuleC13();
1900b57cec5SDimitry Andric     P.NewLine();
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   return Error::success();
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
dumpNameMap()1960b57cec5SDimitry Andric void BytesOutputStyle::dumpNameMap() {
1970b57cec5SDimitry Andric   printHeader(P, "Named Stream Map");
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   AutoIndent Indent(P);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   auto &InfoS = Err(File.getPDBInfoStream());
2020b57cec5SDimitry Andric   BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
2030b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamPDB);
2040b57cec5SDimitry Andric   P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
dumpBlockRanges(uint32_t Min,uint32_t Max)2070b57cec5SDimitry Andric void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
2080b57cec5SDimitry Andric   printHeader(P, "MSF Blocks");
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   AutoIndent Indent(P);
2110b57cec5SDimitry Andric   for (uint32_t I = Min; I <= Max; ++I) {
2120b57cec5SDimitry Andric     uint64_t Base = I;
2130b57cec5SDimitry Andric     Base *= File.getBlockSize();
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     auto ExpectedData = File.getBlockData(I, File.getBlockSize());
2160b57cec5SDimitry Andric     if (!ExpectedData) {
2170b57cec5SDimitry Andric       P.formatLine("Could not get block {0}.  Reason = {1}", I,
2180b57cec5SDimitry Andric                    toString(ExpectedData.takeError()));
2190b57cec5SDimitry Andric       continue;
2200b57cec5SDimitry Andric     }
2210b57cec5SDimitry Andric     std::string Label = formatv("Block {0}", I).str();
2220b57cec5SDimitry Andric     P.formatBinary(Label, *ExpectedData, Base, 0);
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
dumpSectionContributions()2260b57cec5SDimitry Andric void BytesOutputStyle::dumpSectionContributions() {
2270b57cec5SDimitry Andric   printHeader(P, "Section Contributions");
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   AutoIndent Indent(P);
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2320b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getSectionContributionData();
2330b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2340b57cec5SDimitry Andric   P.formatMsfStreamData("Section Contributions", File, Layout, NS);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
dumpSectionMap()2370b57cec5SDimitry Andric void BytesOutputStyle::dumpSectionMap() {
2380b57cec5SDimitry Andric   printHeader(P, "Section Map");
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   AutoIndent Indent(P);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2430b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
2440b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2450b57cec5SDimitry Andric   P.formatMsfStreamData("Section Map", File, Layout, NS);
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
dumpModuleInfos()2480b57cec5SDimitry Andric void BytesOutputStyle::dumpModuleInfos() {
2490b57cec5SDimitry Andric   printHeader(P, "Module Infos");
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   AutoIndent Indent(P);
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2540b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getModiSubstreamData();
2550b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2560b57cec5SDimitry Andric   P.formatMsfStreamData("Module Infos", File, Layout, NS);
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
dumpFileInfo()2590b57cec5SDimitry Andric void BytesOutputStyle::dumpFileInfo() {
2600b57cec5SDimitry Andric   printHeader(P, "File Info");
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   AutoIndent Indent(P);
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2650b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
2660b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2670b57cec5SDimitry Andric   P.formatMsfStreamData("File Info", File, Layout, NS);
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric 
dumpTypeServerMap()2700b57cec5SDimitry Andric void BytesOutputStyle::dumpTypeServerMap() {
2710b57cec5SDimitry Andric   printHeader(P, "Type Server Map");
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   AutoIndent Indent(P);
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2760b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
2770b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2780b57cec5SDimitry Andric   P.formatMsfStreamData("Type Server Map", File, Layout, NS);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric 
dumpECData()2810b57cec5SDimitry Andric void BytesOutputStyle::dumpECData() {
2820b57cec5SDimitry Andric   printHeader(P, "Edit and Continue Data");
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   AutoIndent Indent(P);
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   auto &DbiS = Err(File.getPDBDbiStream());
2870b57cec5SDimitry Andric   BinarySubstreamRef NS = DbiS.getECSubstreamData();
2880b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamDBI);
2890b57cec5SDimitry Andric   P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric 
dumpTypeIndex(uint32_t StreamIdx,ArrayRef<uint32_t> Indices)2920b57cec5SDimitry Andric void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
2930b57cec5SDimitry Andric                                      ArrayRef<uint32_t> Indices) {
2940b57cec5SDimitry Andric   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
2950b57cec5SDimitry Andric   assert(!Indices.empty());
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   bool IsTpi = (StreamIdx == StreamTPI);
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
3000b57cec5SDimitry Andric   printHeader(P, Label);
3010b57cec5SDimitry Andric   auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   AutoIndent Indent(P);
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   auto Substream = Stream.getTypeRecordsSubstream();
3060b57cec5SDimitry Andric   auto &Types = Err(initializeTypes(StreamIdx));
3070b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(StreamIdx);
3080b57cec5SDimitry Andric   for (const auto &Id : Indices) {
3090b57cec5SDimitry Andric     TypeIndex TI(Id);
3100b57cec5SDimitry Andric     if (TI.toArrayIndex() >= Types.capacity()) {
3110b57cec5SDimitry Andric       P.formatLine("Error: TypeIndex {0} does not exist", TI);
3120b57cec5SDimitry Andric       continue;
3130b57cec5SDimitry Andric     }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric     auto Type = Types.getType(TI);
3160b57cec5SDimitry Andric     uint32_t Offset = Types.getOffsetOfType(TI);
3170b57cec5SDimitry Andric     auto OneType = Substream.slice(Offset, Type.length());
3180b57cec5SDimitry Andric     P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
3190b57cec5SDimitry Andric   }
3200b57cec5SDimitry Andric }
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric template <typename CallbackT>
iterateOneModule(PDBFile & File,LinePrinter & P,const DbiModuleList & Modules,uint32_t I,uint32_t Digits,uint32_t IndentLevel,CallbackT Callback)3230b57cec5SDimitry Andric static void iterateOneModule(PDBFile &File, LinePrinter &P,
3240b57cec5SDimitry Andric                              const DbiModuleList &Modules, uint32_t I,
3250b57cec5SDimitry Andric                              uint32_t Digits, uint32_t IndentLevel,
3260b57cec5SDimitry Andric                              CallbackT Callback) {
3270b57cec5SDimitry Andric   if (I >= Modules.getModuleCount()) {
3280b57cec5SDimitry Andric     P.formatLine("Mod {0:4} | Invalid module index ",
3290b57cec5SDimitry Andric                  fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
3300b57cec5SDimitry Andric     return;
3310b57cec5SDimitry Andric   }
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   auto Modi = Modules.getModuleDescriptor(I);
3340b57cec5SDimitry Andric   P.formatLine("Mod {0:4} | `{1}`: ",
3350b57cec5SDimitry Andric                fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
3360b57cec5SDimitry Andric                Modi.getModuleName());
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   uint16_t ModiStream = Modi.getModuleStreamIndex();
3390b57cec5SDimitry Andric   AutoIndent Indent2(P, IndentLevel);
3400b57cec5SDimitry Andric   if (ModiStream == kInvalidStreamIndex)
3410b57cec5SDimitry Andric     return;
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   auto ModStreamData = File.createIndexedStream(ModiStream);
3440b57cec5SDimitry Andric   ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
3450b57cec5SDimitry Andric   if (auto EC = ModStream.reload()) {
3460b57cec5SDimitry Andric     P.formatLine("Could not parse debug information.");
3470b57cec5SDimitry Andric     return;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric   auto Layout = File.getStreamLayout(ModiStream);
3500b57cec5SDimitry Andric   Callback(I, ModStream, Layout);
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric template <typename CallbackT>
iterateModules(PDBFile & File,LinePrinter & P,uint32_t IndentLevel,CallbackT Callback)3540b57cec5SDimitry Andric static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
3550b57cec5SDimitry Andric                            CallbackT Callback) {
3560b57cec5SDimitry Andric   AutoIndent Indent(P);
3570b57cec5SDimitry Andric   if (!File.hasPDBDbiStream()) {
3580b57cec5SDimitry Andric     P.formatLine("DBI Stream not present");
3590b57cec5SDimitry Andric     return;
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric   ExitOnError Err("Unexpected error processing modules");
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   auto &Stream = Err(File.getPDBDbiStream());
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   const DbiModuleList &Modules = Stream.modules();
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
3690b57cec5SDimitry Andric     iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
3700b57cec5SDimitry Andric                      Callback);
3710b57cec5SDimitry Andric   } else {
3720b57cec5SDimitry Andric     uint32_t Count = Modules.getModuleCount();
3730b57cec5SDimitry Andric     uint32_t Digits = NumDigits(Count);
3740b57cec5SDimitry Andric     for (uint32_t I = 0; I < Count; ++I) {
3750b57cec5SDimitry Andric       iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
3760b57cec5SDimitry Andric     }
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
dumpModuleSyms()3800b57cec5SDimitry Andric void BytesOutputStyle::dumpModuleSyms() {
3810b57cec5SDimitry Andric   printHeader(P, "Module Symbols");
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   AutoIndent Indent(P);
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   iterateModules(File, P, 2,
3860b57cec5SDimitry Andric                  [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
3870b57cec5SDimitry Andric                         const MSFStreamLayout &Layout) {
3880b57cec5SDimitry Andric                    auto Symbols = Stream.getSymbolsSubstream();
3890b57cec5SDimitry Andric                    P.formatMsfStreamData("Symbols", File, Layout, Symbols);
3900b57cec5SDimitry Andric                  });
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
dumpModuleC11()3930b57cec5SDimitry Andric void BytesOutputStyle::dumpModuleC11() {
3940b57cec5SDimitry Andric   printHeader(P, "C11 Debug Chunks");
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   AutoIndent Indent(P);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   iterateModules(File, P, 2,
3990b57cec5SDimitry Andric                  [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
4000b57cec5SDimitry Andric                         const MSFStreamLayout &Layout) {
4010b57cec5SDimitry Andric                    auto Chunks = Stream.getC11LinesSubstream();
4020b57cec5SDimitry Andric                    P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
4030b57cec5SDimitry Andric                                          Chunks);
4040b57cec5SDimitry Andric                  });
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
dumpModuleC13()4070b57cec5SDimitry Andric void BytesOutputStyle::dumpModuleC13() {
4080b57cec5SDimitry Andric   printHeader(P, "Debug Chunks");
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   AutoIndent Indent(P);
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   iterateModules(
4130b57cec5SDimitry Andric       File, P, 2,
4140b57cec5SDimitry Andric       [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
4150b57cec5SDimitry Andric              const MSFStreamLayout &Layout) {
4160b57cec5SDimitry Andric         auto Chunks = Stream.getC13LinesSubstream();
4170b57cec5SDimitry Andric         if (opts::bytes::SplitChunks) {
4180b57cec5SDimitry Andric           for (const auto &SS : Stream.subsections()) {
4190b57cec5SDimitry Andric             BinarySubstreamRef ThisChunk;
4200b57cec5SDimitry Andric             std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
4210b57cec5SDimitry Andric             P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
4220b57cec5SDimitry Andric                                   ThisChunk);
4230b57cec5SDimitry Andric           }
4240b57cec5SDimitry Andric         } else {
4250b57cec5SDimitry Andric           P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
4260b57cec5SDimitry Andric         }
4270b57cec5SDimitry Andric       });
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric 
dumpByteRanges(uint32_t Min,uint32_t Max)4300b57cec5SDimitry Andric void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
4310b57cec5SDimitry Andric   printHeader(P, "MSF Bytes");
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric   AutoIndent Indent(P);
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   BinaryStreamReader Reader(File.getMsfBuffer());
4360b57cec5SDimitry Andric   ArrayRef<uint8_t> Data;
4370b57cec5SDimitry Andric   consumeError(Reader.skip(Min));
4380b57cec5SDimitry Andric   uint32_t Size = Max - Min + 1;
4390b57cec5SDimitry Andric   auto EC = Reader.readBytes(Data, Size);
4400b57cec5SDimitry Andric   assert(!EC);
4410b57cec5SDimitry Andric   consumeError(std::move(EC));
4420b57cec5SDimitry Andric   P.formatBinary("Bytes", Data, Min);
4430b57cec5SDimitry Andric }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric Expected<codeview::LazyRandomTypeCollection &>
initializeTypes(uint32_t StreamIdx)4460b57cec5SDimitry Andric BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
4470b57cec5SDimitry Andric   auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
4480b57cec5SDimitry Andric   if (TypeCollection)
4490b57cec5SDimitry Andric     return *TypeCollection;
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
4520b57cec5SDimitry Andric                                       : File.getPDBIpiStream();
4530b57cec5SDimitry Andric   if (!Tpi)
4540b57cec5SDimitry Andric     return Tpi.takeError();
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   auto &Types = Tpi->typeArray();
4570b57cec5SDimitry Andric   uint32_t Count = Tpi->getNumTypeRecords();
4580b57cec5SDimitry Andric   auto Offsets = Tpi->getTypeIndexOffsets();
4590b57cec5SDimitry Andric   TypeCollection =
4608bcb0991SDimitry Andric       std::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   return *TypeCollection;
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric 
dumpFpm()4650b57cec5SDimitry Andric void BytesOutputStyle::dumpFpm() {
4660b57cec5SDimitry Andric   printHeader(P, "Free Page Map");
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric   msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();
4690b57cec5SDimitry Andric   P.formatMsfStreamBlocks(File, FpmLayout);
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric 
dumpStreamBytes()4720b57cec5SDimitry Andric void BytesOutputStyle::dumpStreamBytes() {
4730b57cec5SDimitry Andric   if (StreamPurposes.empty())
4740b57cec5SDimitry Andric     discoverStreamPurposes(File, StreamPurposes);
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   printHeader(P, "Stream Data");
4770b57cec5SDimitry Andric   ExitOnError Err("Unexpected error reading stream data");
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   auto Specs = parseStreamSpecs(P);
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric   for (const auto &Spec : Specs) {
4820b57cec5SDimitry Andric     AutoIndent Indent(P);
4830b57cec5SDimitry Andric     if (Spec.SI >= StreamPurposes.size()) {
4840b57cec5SDimitry Andric       P.formatLine("Stream {0}: Not present", Spec.SI);
4850b57cec5SDimitry Andric       continue;
4860b57cec5SDimitry Andric     }
4870b57cec5SDimitry Andric     P.formatMsfStreamData("Data", File, Spec.SI,
4880b57cec5SDimitry Andric                           StreamPurposes[Spec.SI].getShortName(), Spec.Begin,
4890b57cec5SDimitry Andric                           Spec.Size);
4900b57cec5SDimitry Andric   }
4910b57cec5SDimitry Andric }
492