blob: 3d2490509c03ef64872758112318e688dcdde061 [file] [log] [blame]
Zachary Turnerea40f402018-03-29 16:28:20 +00001//===- ExplainOutputStyle.cpp --------------------------------- *- C++ --*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Zachary Turnerea40f402018-03-29 16:28:20 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "ExplainOutputStyle.h"
10
11#include "FormatUtil.h"
Zachary Turner15b2bdf2018-04-04 17:29:09 +000012#include "InputFile.h"
Zachary Turnerea40f402018-03-29 16:28:20 +000013#include "StreamUtil.h"
14#include "llvm-pdbutil.h"
15
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +000016#include "llvm/DebugInfo/CodeView/Formatters.h"
Zachary Turnerea40f402018-03-29 16:28:20 +000017#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +000018#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
19#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
Zachary Turnerea40f402018-03-29 16:28:20 +000020#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +000021#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
Zachary Turner15b2bdf2018-04-04 17:29:09 +000022#include "llvm/Support/BinaryByteStream.h"
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +000023#include "llvm/Support/BinaryStreamArray.h"
24#include "llvm/Support/Error.h"
Zachary Turnerea40f402018-03-29 16:28:20 +000025
26using namespace llvm;
27using namespace llvm::codeview;
28using namespace llvm::msf;
29using namespace llvm::pdb;
30
Zachary Turner15b2bdf2018-04-04 17:29:09 +000031ExplainOutputStyle::ExplainOutputStyle(InputFile &File, uint64_t FileOffset)
32 : File(File), FileOffset(FileOffset), P(2, false, outs()) {}
Zachary Turnerea40f402018-03-29 16:28:20 +000033
34Error ExplainOutputStyle::dump() {
35 P.formatLine("Explaining file offset {0} of file '{1}'.", FileOffset,
36 File.getFilePath());
37
Zachary Turner15b2bdf2018-04-04 17:29:09 +000038 if (File.isPdb())
39 return explainPdbFile();
40
41 return explainBinaryFile();
42}
43
44Error ExplainOutputStyle::explainPdbFile() {
45 bool IsAllocated = explainPdbBlockStatus();
Zachary Turnerea40f402018-03-29 16:28:20 +000046 if (!IsAllocated)
47 return Error::success();
48
49 AutoIndent Indent(P);
Zachary Turner15b2bdf2018-04-04 17:29:09 +000050 if (isPdbSuperBlock())
51 explainPdbSuperBlockOffset();
52 else if (isPdbFpmBlock())
53 explainPdbFpmBlockOffset();
54 else if (isPdbBlockMapBlock())
55 explainPdbBlockMapOffset();
56 else if (isPdbStreamDirectoryBlock())
57 explainPdbStreamDirectoryOffset();
58 else if (auto Index = getPdbBlockStreamIndex())
59 explainPdbStreamOffset(*Index);
Zachary Turnerea40f402018-03-29 16:28:20 +000060 else
Zachary Turner15b2bdf2018-04-04 17:29:09 +000061 explainPdbUnknownBlock();
Zachary Turnerea40f402018-03-29 16:28:20 +000062 return Error::success();
63}
64
Zachary Turner15b2bdf2018-04-04 17:29:09 +000065Error ExplainOutputStyle::explainBinaryFile() {
66 std::unique_ptr<BinaryByteStream> Stream =
Jonas Devlieghere0eaee542019-08-15 15:54:37 +000067 std::make_unique<BinaryByteStream>(File.unknown().getBuffer(),
Zachary Turner15b2bdf2018-04-04 17:29:09 +000068 llvm::support::little);
69 switch (opts::explain::InputType) {
70 case opts::explain::InputFileType::DBIStream: {
71 DbiStream Dbi(std::move(Stream));
72 if (auto EC = Dbi.reload(nullptr))
73 return EC;
74 explainStreamOffset(Dbi, FileOffset);
75 break;
76 }
77 case opts::explain::InputFileType::PDBStream: {
78 InfoStream Info(std::move(Stream));
79 if (auto EC = Info.reload())
80 return EC;
81 explainStreamOffset(Info, FileOffset);
82 break;
83 }
84 default:
85 llvm_unreachable("Invalid input file type!");
86 }
87 return Error::success();
Zachary Turnerea40f402018-03-29 16:28:20 +000088}
89
Zachary Turner15b2bdf2018-04-04 17:29:09 +000090uint32_t ExplainOutputStyle::pdbBlockIndex() const {
91 return FileOffset / File.pdb().getBlockSize();
Zachary Turnerea40f402018-03-29 16:28:20 +000092}
93
Zachary Turner15b2bdf2018-04-04 17:29:09 +000094uint32_t ExplainOutputStyle::pdbBlockOffset() const {
95 uint64_t BlockStart = pdbBlockIndex() * File.pdb().getBlockSize();
96 assert(FileOffset >= BlockStart);
97 return FileOffset - BlockStart;
Zachary Turnerea40f402018-03-29 16:28:20 +000098}
99
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000100bool ExplainOutputStyle::isPdbSuperBlock() const {
101 return pdbBlockIndex() == 0;
102}
103
104bool ExplainOutputStyle::isPdbFpm1() const {
105 return ((pdbBlockIndex() - 1) % File.pdb().getBlockSize() == 0);
106}
107bool ExplainOutputStyle::isPdbFpm2() const {
108 return ((pdbBlockIndex() - 2) % File.pdb().getBlockSize() == 0);
109}
110
111bool ExplainOutputStyle::isPdbFpmBlock() const {
112 return isPdbFpm1() || isPdbFpm2();
113}
114
115bool ExplainOutputStyle::isPdbBlockMapBlock() const {
116 return pdbBlockIndex() == File.pdb().getBlockMapIndex();
117}
118
119bool ExplainOutputStyle::isPdbStreamDirectoryBlock() const {
120 const auto &Layout = File.pdb().getMsfLayout();
121 return llvm::is_contained(Layout.DirectoryBlocks, pdbBlockIndex());
122}
123
124Optional<uint32_t> ExplainOutputStyle::getPdbBlockStreamIndex() const {
125 const auto &Layout = File.pdb().getMsfLayout();
Zachary Turnerea40f402018-03-29 16:28:20 +0000126 for (const auto &Entry : enumerate(Layout.StreamMap)) {
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000127 if (!llvm::is_contained(Entry.value(), pdbBlockIndex()))
Zachary Turnerea40f402018-03-29 16:28:20 +0000128 continue;
129 return Entry.index();
130 }
131 return None;
132}
133
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000134bool ExplainOutputStyle::explainPdbBlockStatus() {
135 if (FileOffset >= File.pdb().getFileSize()) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000136 P.formatLine("Address {0} is not in the file (file size = {1}).",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000137 FileOffset, File.pdb().getFileSize());
Zachary Turnerea40f402018-03-29 16:28:20 +0000138 return false;
139 }
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000140 P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, pdbBlockOffset(),
141 pdbBlockIndex());
Zachary Turnerea40f402018-03-29 16:28:20 +0000142
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000143 bool IsFree = File.pdb().getMsfLayout().FreePageMap[pdbBlockIndex()];
144 P.formatLine("Address is in block {0} ({1}allocated).", pdbBlockIndex(),
Zachary Turnerea40f402018-03-29 16:28:20 +0000145 IsFree ? "un" : "");
146 return !IsFree;
147}
148
Zachary Turner1b204162018-03-29 17:11:14 +0000149#define endof(Class, Field) (offsetof(Class, Field) + sizeof(Class::Field))
150
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000151void ExplainOutputStyle::explainPdbSuperBlockOffset() {
Zachary Turner1b204162018-03-29 17:11:14 +0000152 P.formatLine("This corresponds to offset {0} of the MSF super block, ",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000153 pdbBlockOffset());
154 if (pdbBlockOffset() < endof(SuperBlock, MagicBytes))
Zachary Turnerea40f402018-03-29 16:28:20 +0000155 P.printLine("which is part of the MSF file magic.");
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000156 else if (pdbBlockOffset() < endof(SuperBlock, BlockSize)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000157 P.printLine("which contains the block size of the file.");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000158 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000159 uint32_t(File.pdb().getMsfLayout().SB->BlockSize));
160 } else if (pdbBlockOffset() < endof(SuperBlock, FreeBlockMapBlock)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000161 P.printLine("which contains the index of the FPM block (e.g. 1 or 2).");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000162 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000163 uint32_t(File.pdb().getMsfLayout().SB->FreeBlockMapBlock));
164 } else if (pdbBlockOffset() < endof(SuperBlock, NumBlocks)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000165 P.printLine("which contains the number of blocks in the file.");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000166 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000167 uint32_t(File.pdb().getMsfLayout().SB->NumBlocks));
168 } else if (pdbBlockOffset() < endof(SuperBlock, NumDirectoryBytes)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000169 P.printLine("which contains the number of bytes in the stream directory.");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000170 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000171 uint32_t(File.pdb().getMsfLayout().SB->NumDirectoryBytes));
172 } else if (pdbBlockOffset() < endof(SuperBlock, Unknown1)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000173 P.printLine("whose purpose is unknown.");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000174 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000175 uint32_t(File.pdb().getMsfLayout().SB->Unknown1));
176 } else if (pdbBlockOffset() < endof(SuperBlock, BlockMapAddr)) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000177 P.printLine("which contains the file offset of the block map.");
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000178 P.formatLine("The current value is {0}.",
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000179 uint32_t(File.pdb().getMsfLayout().SB->BlockMapAddr));
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000180 } else {
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000181 assert(pdbBlockOffset() > sizeof(SuperBlock));
Zachary Turnerea40f402018-03-29 16:28:20 +0000182 P.printLine(
183 "which is outside the range of valid data for the super block.");
184 }
185}
186
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000187static std::string toBinaryString(uint8_t Byte) {
188 char Result[9] = {0};
189 for (int I = 0; I < 8; ++I) {
190 char C = (Byte & 1) ? '1' : '0';
191 Result[I] = C;
192 Byte >>= 1;
193 }
194 return std::string(Result);
195}
196
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000197void ExplainOutputStyle::explainPdbFpmBlockOffset() {
198 const MSFLayout &Layout = File.pdb().getMsfLayout();
Zachary Turnerea40f402018-03-29 16:28:20 +0000199 uint32_t MainFpm = Layout.mainFpmBlock();
200 uint32_t AltFpm = Layout.alternateFpmBlock();
201
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000202 assert(isPdbFpmBlock());
203 uint32_t Fpm = isPdbFpm1() ? 1 : 2;
204 uint32_t FpmChunk = pdbBlockIndex() / File.pdb().getBlockSize();
Zachary Turnerea40f402018-03-29 16:28:20 +0000205 assert((Fpm == MainFpm) || (Fpm == AltFpm));
206 (void)AltFpm;
207 bool IsMain = (Fpm == MainFpm);
208 P.formatLine("Address is in FPM{0} ({1} FPM)", Fpm, IsMain ? "Main" : "Alt");
209 uint32_t DescribedBlockStart =
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000210 8 * (FpmChunk * File.pdb().getBlockSize() + pdbBlockOffset());
211 if (DescribedBlockStart > File.pdb().getBlockCount()) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000212 P.printLine("Address is in extraneous FPM space.");
213 return;
214 }
215
216 P.formatLine("Address describes the allocation status of blocks [{0},{1})",
217 DescribedBlockStart, DescribedBlockStart + 8);
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000218 ArrayRef<uint8_t> Bytes;
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000219 cantFail(File.pdb().getMsfBuffer().readBytes(FileOffset, 1, Bytes));
Zachary Turnerf4b6dcf2018-03-29 17:45:34 +0000220 P.formatLine("Status = {0} (Note: 0 = allocated, 1 = free)",
221 toBinaryString(Bytes[0]));
Zachary Turnerea40f402018-03-29 16:28:20 +0000222}
223
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000224void ExplainOutputStyle::explainPdbBlockMapOffset() {
225 uint64_t BlockMapOffset = File.pdb().getBlockMapOffset();
Zachary Turnerea40f402018-03-29 16:28:20 +0000226 uint32_t OffsetInBlock = FileOffset - BlockMapOffset;
227 P.formatLine("Address is at offset {0} of the directory block list",
228 OffsetInBlock);
229}
230
231static uint32_t getOffsetInStream(ArrayRef<support::ulittle32_t> StreamBlocks,
232 uint64_t FileOffset, uint32_t BlockSize) {
233 uint32_t BlockIndex = FileOffset / BlockSize;
234 uint32_t OffsetInBlock = FileOffset - BlockIndex * BlockSize;
235
236 auto Iter = llvm::find(StreamBlocks, BlockIndex);
237 assert(Iter != StreamBlocks.end());
238 uint32_t StreamBlockIndex = std::distance(StreamBlocks.begin(), Iter);
239 return StreamBlockIndex * BlockSize + OffsetInBlock;
240}
241
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000242void ExplainOutputStyle::explainPdbStreamOffset(uint32_t Stream) {
Zachary Turnerea40f402018-03-29 16:28:20 +0000243 SmallVector<StreamInfo, 12> Streams;
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000244 discoverStreamPurposes(File.pdb(), Streams);
Zachary Turnerea40f402018-03-29 16:28:20 +0000245
246 assert(Stream <= Streams.size());
247 const StreamInfo &S = Streams[Stream];
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000248 const auto &Layout = File.pdb().getStreamLayout(Stream);
Zachary Turnerea40f402018-03-29 16:28:20 +0000249 uint32_t StreamOff =
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000250 getOffsetInStream(Layout.Blocks, FileOffset, File.pdb().getBlockSize());
Zachary Turnerea40f402018-03-29 16:28:20 +0000251 P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.",
252 StreamOff, Layout.Length, Stream, S.getLongName(),
253 (StreamOff > Layout.Length) ? " in unused space" : "");
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000254 switch (S.getPurpose()) {
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000255 case StreamPurpose::DBI: {
256 DbiStream &Dbi = cantFail(File.pdb().getPDBDbiStream());
257 explainStreamOffset(Dbi, StreamOff);
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000258 break;
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000259 }
260 case StreamPurpose::PDB: {
261 InfoStream &Info = cantFail(File.pdb().getPDBInfoStream());
262 explainStreamOffset(Info, StreamOff);
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000263 break;
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000264 }
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000265 case StreamPurpose::IPI:
266 case StreamPurpose::TPI:
267 case StreamPurpose::ModuleStream:
268 case StreamPurpose::NamedStream:
269 default:
270 break;
271 }
Zachary Turnerea40f402018-03-29 16:28:20 +0000272}
273
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000274void ExplainOutputStyle::explainPdbStreamDirectoryOffset() {
275 auto DirectoryBlocks = File.pdb().getDirectoryBlockArray();
276 const auto &Layout = File.pdb().getMsfLayout();
Zachary Turnerea40f402018-03-29 16:28:20 +0000277 uint32_t StreamOff =
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000278 getOffsetInStream(DirectoryBlocks, FileOffset, File.pdb().getBlockSize());
Zachary Turnerea40f402018-03-29 16:28:20 +0000279 P.formatLine("Address is at offset {0}/{1} of Stream Directory{2}.",
280 StreamOff, uint32_t(Layout.SB->NumDirectoryBytes),
281 uint32_t(StreamOff > Layout.SB->NumDirectoryBytes)
282 ? " in unused space"
283 : "");
284}
285
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000286void ExplainOutputStyle::explainPdbUnknownBlock() {
Zachary Turnerea40f402018-03-29 16:28:20 +0000287 P.formatLine("Address has unknown purpose.");
288}
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000289
290template <typename T>
291static void printStructField(LinePrinter &P, StringRef Label, T Value) {
292 P.formatLine("which contains {0}.", Label);
293 P.formatLine("The current value is {0}.", Value);
294}
295
296static void explainDbiHeaderOffset(LinePrinter &P, DbiStream &Dbi,
297 uint32_t Offset) {
298 const DbiStreamHeader *Header = Dbi.getHeader();
299 assert(Header != nullptr);
300
301 if (Offset < endof(DbiStreamHeader, VersionSignature))
302 printStructField(P, "the DBI Stream Version Signature",
303 int32_t(Header->VersionSignature));
304 else if (Offset < endof(DbiStreamHeader, VersionHeader))
305 printStructField(P, "the DBI Stream Version Header",
306 uint32_t(Header->VersionHeader));
307 else if (Offset < endof(DbiStreamHeader, Age))
308 printStructField(P, "the age of the DBI Stream", uint32_t(Header->Age));
309 else if (Offset < endof(DbiStreamHeader, GlobalSymbolStreamIndex))
310 printStructField(P, "the index of the Global Symbol Stream",
311 uint16_t(Header->GlobalSymbolStreamIndex));
312 else if (Offset < endof(DbiStreamHeader, BuildNumber))
313 printStructField(P, "the build number", uint16_t(Header->BuildNumber));
314 else if (Offset < endof(DbiStreamHeader, PublicSymbolStreamIndex))
315 printStructField(P, "the index of the Public Symbol Stream",
316 uint16_t(Header->PublicSymbolStreamIndex));
317 else if (Offset < endof(DbiStreamHeader, PdbDllVersion))
318 printStructField(P, "the version of mspdb.dll",
319 uint16_t(Header->PdbDllVersion));
320 else if (Offset < endof(DbiStreamHeader, SymRecordStreamIndex))
321 printStructField(P, "the index of the Symbol Record Stream",
322 uint16_t(Header->SymRecordStreamIndex));
323 else if (Offset < endof(DbiStreamHeader, PdbDllRbld))
324 printStructField(P, "the rbld of mspdb.dll", uint16_t(Header->PdbDllRbld));
325 else if (Offset < endof(DbiStreamHeader, ModiSubstreamSize))
326 printStructField(P, "the size of the Module Info Substream",
327 int32_t(Header->ModiSubstreamSize));
328 else if (Offset < endof(DbiStreamHeader, SecContrSubstreamSize))
329 printStructField(P, "the size of the Section Contribution Substream",
330 int32_t(Header->SecContrSubstreamSize));
331 else if (Offset < endof(DbiStreamHeader, SectionMapSize))
332 printStructField(P, "the size of the Section Map Substream",
333 int32_t(Header->SectionMapSize));
334 else if (Offset < endof(DbiStreamHeader, FileInfoSize))
335 printStructField(P, "the size of the File Info Substream",
336 int32_t(Header->FileInfoSize));
337 else if (Offset < endof(DbiStreamHeader, TypeServerSize))
338 printStructField(P, "the size of the Type Server Map",
339 int32_t(Header->TypeServerSize));
340 else if (Offset < endof(DbiStreamHeader, MFCTypeServerIndex))
341 printStructField(P, "the index of the MFC Type Server stream",
342 uint32_t(Header->MFCTypeServerIndex));
343 else if (Offset < endof(DbiStreamHeader, OptionalDbgHdrSize))
344 printStructField(P, "the size of the Optional Debug Stream array",
345 int32_t(Header->OptionalDbgHdrSize));
346 else if (Offset < endof(DbiStreamHeader, ECSubstreamSize))
347 printStructField(P, "the size of the Edit & Continue Substream",
348 int32_t(Header->ECSubstreamSize));
349 else if (Offset < endof(DbiStreamHeader, Flags))
350 printStructField(P, "the DBI Stream flags", uint16_t(Header->Flags));
351 else if (Offset < endof(DbiStreamHeader, MachineType))
352 printStructField(P, "the machine type", uint16_t(Header->MachineType));
353 else if (Offset < endof(DbiStreamHeader, Reserved))
354 printStructField(P, "reserved data", uint32_t(Header->Reserved));
355}
356
357static void explainDbiModiSubstreamOffset(LinePrinter &P, DbiStream &Dbi,
358 uint32_t Offset) {
359 VarStreamArray<DbiModuleDescriptor> ModuleDescriptors;
360 BinaryStreamRef ModiSubstreamData = Dbi.getModiSubstreamData().StreamData;
361 BinaryStreamReader Reader(ModiSubstreamData);
362
363 cantFail(Reader.readArray(ModuleDescriptors, ModiSubstreamData.getLength()));
364 auto Prev = ModuleDescriptors.begin();
365 assert(Prev.offset() == 0);
366 auto Current = Prev;
367 uint32_t Index = 0;
368 while (true) {
369 Prev = Current;
370 ++Current;
371 if (Current == ModuleDescriptors.end() || Offset < Current.offset())
372 break;
373 ++Index;
374 }
375
376 DbiModuleDescriptor &Descriptor = *Prev;
377 P.formatLine("which contains the descriptor for module {0} ({1}).", Index,
378 Descriptor.getModuleName());
379}
380
381template <typename T>
382static void dontExplain(LinePrinter &Printer, T &Stream, uint32_t Offset) {}
383
384template <typename T, typename SubstreamRangeT>
385static void explainSubstreamOffset(LinePrinter &P, uint32_t OffsetInStream,
386 T &Stream,
387 const SubstreamRangeT &Substreams) {
388 uint32_t SubOffset = OffsetInStream;
389 for (const auto &Entry : Substreams) {
Zachary Turnerce5b8342018-03-30 17:28:35 +0000390 if (Entry.Size <= 0)
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000391 continue;
Zachary Turnerce5b8342018-03-30 17:28:35 +0000392 uint32_t S = static_cast<uint32_t>(Entry.Size);
393 if (SubOffset < S) {
394 P.formatLine("address is at offset {0}/{1} of the {2}.", SubOffset, S,
395 Entry.Label);
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000396 Entry.Explain(P, Stream, SubOffset);
397 return;
398 }
Zachary Turnerce5b8342018-03-30 17:28:35 +0000399 SubOffset -= S;
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000400 }
401}
402
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000403void ExplainOutputStyle::explainStreamOffset(DbiStream &Dbi,
404 uint32_t OffsetInStream) {
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000405 P.printLine("Within the DBI stream:");
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000406 AutoIndent Indent(P);
407 const DbiStreamHeader *Header = Dbi.getHeader();
408 assert(Header != nullptr);
409
410 struct SubstreamInfo {
Zachary Turnerce5b8342018-03-30 17:28:35 +0000411 int32_t Size;
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000412 StringRef Label;
413 void (*Explain)(LinePrinter &, DbiStream &, uint32_t);
414 } Substreams[] = {
415 {sizeof(DbiStreamHeader), "DBI Stream Header", explainDbiHeaderOffset},
Zachary Turnerce5b8342018-03-30 17:28:35 +0000416 {int32_t(Header->ModiSubstreamSize), "Module Info Substream",
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000417 explainDbiModiSubstreamOffset},
Zachary Turnerce5b8342018-03-30 17:28:35 +0000418 {int32_t(Header->SecContrSubstreamSize), "Section Contribution Substream",
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000419 dontExplain<DbiStream>},
Zachary Turnerce5b8342018-03-30 17:28:35 +0000420 {int32_t(Header->SectionMapSize), "Section Map", dontExplain<DbiStream>},
421 {int32_t(Header->FileInfoSize), "File Info Substream",
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000422 dontExplain<DbiStream>},
Zachary Turnerce5b8342018-03-30 17:28:35 +0000423 {int32_t(Header->TypeServerSize), "Type Server Map Substream",
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000424 dontExplain<DbiStream>},
Zachary Turnerce5b8342018-03-30 17:28:35 +0000425 {int32_t(Header->ECSubstreamSize), "Edit & Continue Substream",
426 dontExplain<DbiStream>},
427 {int32_t(Header->OptionalDbgHdrSize), "Optional Debug Stream Array",
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000428 dontExplain<DbiStream>},
429 };
430
431 explainSubstreamOffset(P, OffsetInStream, Dbi, Substreams);
432}
433
434static void explainPdbStreamHeaderOffset(LinePrinter &P, InfoStream &Info,
435 uint32_t Offset) {
436 const InfoStreamHeader *Header = Info.getHeader();
437 assert(Header != nullptr);
438
439 if (Offset < endof(InfoStreamHeader, Version))
440 printStructField(P, "the PDB Stream Version Signature",
441 uint32_t(Header->Version));
442 else if (Offset < endof(InfoStreamHeader, Signature))
443 printStructField(P, "the signature of the PDB Stream",
444 uint32_t(Header->Signature));
445 else if (Offset < endof(InfoStreamHeader, Age))
446 printStructField(P, "the age of the PDB", uint32_t(Header->Age));
447 else if (Offset < endof(InfoStreamHeader, Guid))
448 printStructField(P, "the guid of the PDB", fmt_guid(Header->Guid.Guid));
449}
450
Zachary Turner15b2bdf2018-04-04 17:29:09 +0000451void ExplainOutputStyle::explainStreamOffset(InfoStream &Info,
452 uint32_t OffsetInStream) {
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000453 P.printLine("Within the PDB stream:");
Zachary Turnerd5cf5cf2018-03-30 17:16:50 +0000454 AutoIndent Indent(P);
455
456 struct SubstreamInfo {
457 uint32_t Size;
458 StringRef Label;
459 void (*Explain)(LinePrinter &, InfoStream &, uint32_t);
460 } Substreams[] = {{sizeof(InfoStreamHeader), "PDB Stream Header",
461 explainPdbStreamHeaderOffset},
462 {Info.getNamedStreamMapByteSize(), "Named Stream Map",
463 dontExplain<InfoStream>},
464 {Info.getStreamSize(), "PDB Feature Signatures",
465 dontExplain<InfoStream>}};
466
467 explainSubstreamOffset(P, OffsetInStream, Info, Substreams);
468}