• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- BytesOutputStyle.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 "BytesOutputStyle.h"
11 
12 #include "FormatUtil.h"
13 #include "StreamUtil.h"
14 #include "llvm-pdbutil.h"
15 
16 #include "llvm/DebugInfo/CodeView/Formatters.h"
17 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
18 #include "llvm/DebugInfo/MSF/MSFCommon.h"
19 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
20 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
21 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
22 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
23 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
24 #include "llvm/DebugInfo/PDB/Native/RawError.h"
25 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
26 #include "llvm/Support/BinaryStreamReader.h"
27 #include "llvm/Support/FormatAdapters.h"
28 #include "llvm/Support/FormatVariadic.h"
29 
30 using namespace llvm;
31 using namespace llvm::codeview;
32 using namespace llvm::msf;
33 using namespace llvm::pdb;
34 
35 namespace {
36 struct StreamSpec {
37   uint32_t SI = 0;
38   uint32_t Begin = 0;
39   uint32_t Size = 0;
40 };
41 } // namespace
42 
parseStreamSpec(StringRef Str)43 static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
44   StreamSpec Result;
45   if (Str.consumeInteger(0, Result.SI))
46     return make_error<RawError>(raw_error_code::invalid_format,
47                                 "Invalid Stream Specification");
48   if (Str.consume_front(":")) {
49     if (Str.consumeInteger(0, Result.Begin))
50       return make_error<RawError>(raw_error_code::invalid_format,
51                                   "Invalid Stream Specification");
52   }
53   if (Str.consume_front("@")) {
54     if (Str.consumeInteger(0, Result.Size))
55       return make_error<RawError>(raw_error_code::invalid_format,
56                                   "Invalid Stream Specification");
57   }
58 
59   if (!Str.empty())
60     return make_error<RawError>(raw_error_code::invalid_format,
61                                 "Invalid Stream Specification");
62   return Result;
63 }
64 
parseStreamSpecs(LinePrinter & P)65 static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
66   SmallVector<StreamSpec, 2> Result;
67 
68   for (auto &Str : opts::bytes::DumpStreamData) {
69     auto ESS = parseStreamSpec(Str);
70     if (!ESS) {
71       P.formatLine("Error parsing stream spec {0}: {1}", Str,
72                    toString(ESS.takeError()));
73       continue;
74     }
75     Result.push_back(*ESS);
76   }
77   return Result;
78 }
79 
printHeader(LinePrinter & P,const Twine & S)80 static void printHeader(LinePrinter &P, const Twine &S) {
81   P.NewLine();
82   P.formatLine("{0,=60}", S);
83   P.formatLine("{0}", fmt_repeat('=', 60));
84 }
85 
BytesOutputStyle(PDBFile & File)86 BytesOutputStyle::BytesOutputStyle(PDBFile &File)
87     : File(File), P(2, false, outs()) {}
88 
dump()89 Error BytesOutputStyle::dump() {
90 
91   if (opts::bytes::DumpBlockRange.hasValue()) {
92     auto &R = *opts::bytes::DumpBlockRange;
93     uint32_t Max = R.Max.getValueOr(R.Min);
94 
95     if (Max < R.Min)
96       return make_error<StringError>(
97           "Invalid block range specified.  Max < Min",
98           inconvertibleErrorCode());
99     if (Max >= File.getBlockCount())
100       return make_error<StringError>(
101           "Invalid block range specified.  Requested block out of bounds",
102           inconvertibleErrorCode());
103 
104     dumpBlockRanges(R.Min, Max);
105     P.NewLine();
106   }
107 
108   if (opts::bytes::DumpByteRange.hasValue()) {
109     auto &R = *opts::bytes::DumpByteRange;
110     uint32_t Max = R.Max.getValueOr(File.getFileSize());
111 
112     if (Max < R.Min)
113       return make_error<StringError>("Invalid byte range specified.  Max < Min",
114                                      inconvertibleErrorCode());
115     if (Max >= File.getFileSize())
116       return make_error<StringError>(
117           "Invalid byte range specified.  Requested byte larger than file size",
118           inconvertibleErrorCode());
119 
120     dumpByteRanges(R.Min, Max);
121     P.NewLine();
122   }
123 
124   if (opts::bytes::Fpm) {
125     dumpFpm();
126     P.NewLine();
127   }
128 
129   if (!opts::bytes::DumpStreamData.empty()) {
130     dumpStreamBytes();
131     P.NewLine();
132   }
133 
134   if (opts::bytes::NameMap) {
135     dumpNameMap();
136     P.NewLine();
137   }
138 
139   if (opts::bytes::SectionContributions) {
140     dumpSectionContributions();
141     P.NewLine();
142   }
143 
144   if (opts::bytes::SectionMap) {
145     dumpSectionMap();
146     P.NewLine();
147   }
148 
149   if (opts::bytes::ModuleInfos) {
150     dumpModuleInfos();
151     P.NewLine();
152   }
153 
154   if (opts::bytes::FileInfo) {
155     dumpFileInfo();
156     P.NewLine();
157   }
158 
159   if (opts::bytes::TypeServerMap) {
160     dumpTypeServerMap();
161     P.NewLine();
162   }
163 
164   if (opts::bytes::ECData) {
165     dumpECData();
166     P.NewLine();
167   }
168 
169   if (!opts::bytes::TypeIndex.empty()) {
170     dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
171     P.NewLine();
172   }
173 
174   if (!opts::bytes::IdIndex.empty()) {
175     dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
176     P.NewLine();
177   }
178 
179   if (opts::bytes::ModuleSyms) {
180     dumpModuleSyms();
181     P.NewLine();
182   }
183 
184   if (opts::bytes::ModuleC11) {
185     dumpModuleC11();
186     P.NewLine();
187   }
188 
189   if (opts::bytes::ModuleC13) {
190     dumpModuleC13();
191     P.NewLine();
192   }
193 
194   return Error::success();
195 }
196 
dumpNameMap()197 void BytesOutputStyle::dumpNameMap() {
198   printHeader(P, "Named Stream Map");
199 
200   AutoIndent Indent(P);
201 
202   auto &InfoS = Err(File.getPDBInfoStream());
203   BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
204   auto Layout = File.getStreamLayout(StreamPDB);
205   P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
206 }
207 
dumpBlockRanges(uint32_t Min,uint32_t Max)208 void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
209   printHeader(P, "MSF Blocks");
210 
211   AutoIndent Indent(P);
212   for (uint32_t I = Min; I <= Max; ++I) {
213     uint64_t Base = I;
214     Base *= File.getBlockSize();
215 
216     auto ExpectedData = File.getBlockData(I, File.getBlockSize());
217     if (!ExpectedData) {
218       P.formatLine("Could not get block {0}.  Reason = {1}", I,
219                    toString(ExpectedData.takeError()));
220       continue;
221     }
222     std::string Label = formatv("Block {0}", I).str();
223     P.formatBinary(Label, *ExpectedData, Base, 0);
224   }
225 }
226 
dumpSectionContributions()227 void BytesOutputStyle::dumpSectionContributions() {
228   printHeader(P, "Section Contributions");
229 
230   AutoIndent Indent(P);
231 
232   auto &DbiS = Err(File.getPDBDbiStream());
233   BinarySubstreamRef NS = DbiS.getSectionContributionData();
234   auto Layout = File.getStreamLayout(StreamDBI);
235   P.formatMsfStreamData("Section Contributions", File, Layout, NS);
236 }
237 
dumpSectionMap()238 void BytesOutputStyle::dumpSectionMap() {
239   printHeader(P, "Section Map");
240 
241   AutoIndent Indent(P);
242 
243   auto &DbiS = Err(File.getPDBDbiStream());
244   BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
245   auto Layout = File.getStreamLayout(StreamDBI);
246   P.formatMsfStreamData("Section Map", File, Layout, NS);
247 }
248 
dumpModuleInfos()249 void BytesOutputStyle::dumpModuleInfos() {
250   printHeader(P, "Module Infos");
251 
252   AutoIndent Indent(P);
253 
254   auto &DbiS = Err(File.getPDBDbiStream());
255   BinarySubstreamRef NS = DbiS.getModiSubstreamData();
256   auto Layout = File.getStreamLayout(StreamDBI);
257   P.formatMsfStreamData("Module Infos", File, Layout, NS);
258 }
259 
dumpFileInfo()260 void BytesOutputStyle::dumpFileInfo() {
261   printHeader(P, "File Info");
262 
263   AutoIndent Indent(P);
264 
265   auto &DbiS = Err(File.getPDBDbiStream());
266   BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
267   auto Layout = File.getStreamLayout(StreamDBI);
268   P.formatMsfStreamData("File Info", File, Layout, NS);
269 }
270 
dumpTypeServerMap()271 void BytesOutputStyle::dumpTypeServerMap() {
272   printHeader(P, "Type Server Map");
273 
274   AutoIndent Indent(P);
275 
276   auto &DbiS = Err(File.getPDBDbiStream());
277   BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
278   auto Layout = File.getStreamLayout(StreamDBI);
279   P.formatMsfStreamData("Type Server Map", File, Layout, NS);
280 }
281 
dumpECData()282 void BytesOutputStyle::dumpECData() {
283   printHeader(P, "Edit and Continue Data");
284 
285   AutoIndent Indent(P);
286 
287   auto &DbiS = Err(File.getPDBDbiStream());
288   BinarySubstreamRef NS = DbiS.getECSubstreamData();
289   auto Layout = File.getStreamLayout(StreamDBI);
290   P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
291 }
292 
dumpTypeIndex(uint32_t StreamIdx,ArrayRef<uint32_t> Indices)293 void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
294                                      ArrayRef<uint32_t> Indices) {
295   assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
296   assert(!Indices.empty());
297 
298   bool IsTpi = (StreamIdx == StreamTPI);
299 
300   StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
301   printHeader(P, Label);
302   auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
303 
304   AutoIndent Indent(P);
305 
306   auto Substream = Stream.getTypeRecordsSubstream();
307   auto &Types = Err(initializeTypes(StreamIdx));
308   auto Layout = File.getStreamLayout(StreamIdx);
309   for (const auto &Id : Indices) {
310     TypeIndex TI(Id);
311     if (TI.toArrayIndex() >= Types.capacity()) {
312       P.formatLine("Error: TypeIndex {0} does not exist", TI);
313       continue;
314     }
315 
316     auto Type = Types.getType(TI);
317     uint32_t Offset = Types.getOffsetOfType(TI);
318     auto OneType = Substream.slice(Offset, Type.length());
319     P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
320   }
321 }
322 
323 template <typename CallbackT>
iterateOneModule(PDBFile & File,LinePrinter & P,const DbiModuleList & Modules,uint32_t I,uint32_t Digits,uint32_t IndentLevel,CallbackT Callback)324 static void iterateOneModule(PDBFile &File, LinePrinter &P,
325                              const DbiModuleList &Modules, uint32_t I,
326                              uint32_t Digits, uint32_t IndentLevel,
327                              CallbackT Callback) {
328   if (I >= Modules.getModuleCount()) {
329     P.formatLine("Mod {0:4} | Invalid module index ",
330                  fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)));
331     return;
332   }
333 
334   auto Modi = Modules.getModuleDescriptor(I);
335   P.formatLine("Mod {0:4} | `{1}`: ",
336                fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)),
337                Modi.getModuleName());
338 
339   uint16_t ModiStream = Modi.getModuleStreamIndex();
340   AutoIndent Indent2(P, IndentLevel);
341   if (ModiStream == kInvalidStreamIndex)
342     return;
343 
344   auto ModStreamData = MappedBlockStream::createIndexedStream(
345       File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
346       File.getAllocator());
347   ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData));
348   if (auto EC = ModStream.reload()) {
349     P.formatLine("Could not parse debug information.");
350     return;
351   }
352   auto Layout = File.getStreamLayout(ModiStream);
353   Callback(I, ModStream, Layout);
354 }
355 
356 template <typename CallbackT>
iterateModules(PDBFile & File,LinePrinter & P,uint32_t IndentLevel,CallbackT Callback)357 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
358                            CallbackT Callback) {
359   AutoIndent Indent(P);
360   if (!File.hasPDBDbiStream()) {
361     P.formatLine("DBI Stream not present");
362     return;
363   }
364 
365   ExitOnError Err("Unexpected error processing modules");
366 
367   auto &Stream = Err(File.getPDBDbiStream());
368 
369   const DbiModuleList &Modules = Stream.modules();
370 
371   if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) {
372     iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel,
373                      Callback);
374   } else {
375     uint32_t Count = Modules.getModuleCount();
376     uint32_t Digits = NumDigits(Count);
377     for (uint32_t I = 0; I < Count; ++I) {
378       iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback);
379     }
380   }
381 }
382 
dumpModuleSyms()383 void BytesOutputStyle::dumpModuleSyms() {
384   printHeader(P, "Module Symbols");
385 
386   AutoIndent Indent(P);
387 
388   iterateModules(File, P, 2,
389                  [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
390                         const MSFStreamLayout &Layout) {
391                    auto Symbols = Stream.getSymbolsSubstream();
392                    P.formatMsfStreamData("Symbols", File, Layout, Symbols);
393                  });
394 }
395 
dumpModuleC11()396 void BytesOutputStyle::dumpModuleC11() {
397   printHeader(P, "C11 Debug Chunks");
398 
399   AutoIndent Indent(P);
400 
401   iterateModules(File, P, 2,
402                  [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
403                         const MSFStreamLayout &Layout) {
404                    auto Chunks = Stream.getC11LinesSubstream();
405                    P.formatMsfStreamData("C11 Debug Chunks", File, Layout,
406                                          Chunks);
407                  });
408 }
409 
dumpModuleC13()410 void BytesOutputStyle::dumpModuleC13() {
411   printHeader(P, "Debug Chunks");
412 
413   AutoIndent Indent(P);
414 
415   iterateModules(
416       File, P, 2,
417       [this](uint32_t Modi, const ModuleDebugStreamRef &Stream,
418              const MSFStreamLayout &Layout) {
419         auto Chunks = Stream.getC13LinesSubstream();
420         if (opts::bytes::SplitChunks) {
421           for (const auto &SS : Stream.subsections()) {
422             BinarySubstreamRef ThisChunk;
423             std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength());
424             P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout,
425                                   ThisChunk);
426           }
427         } else {
428           P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks);
429         }
430       });
431 }
432 
dumpByteRanges(uint32_t Min,uint32_t Max)433 void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
434   printHeader(P, "MSF Bytes");
435 
436   AutoIndent Indent(P);
437 
438   BinaryStreamReader Reader(File.getMsfBuffer());
439   ArrayRef<uint8_t> Data;
440   consumeError(Reader.skip(Min));
441   uint32_t Size = Max - Min + 1;
442   auto EC = Reader.readBytes(Data, Size);
443   assert(!EC);
444   consumeError(std::move(EC));
445   P.formatBinary("Bytes", Data, Min);
446 }
447 
448 Expected<codeview::LazyRandomTypeCollection &>
initializeTypes(uint32_t StreamIdx)449 BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
450   auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
451   if (TypeCollection)
452     return *TypeCollection;
453 
454   auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
455                                       : File.getPDBIpiStream();
456   if (!Tpi)
457     return Tpi.takeError();
458 
459   auto &Types = Tpi->typeArray();
460   uint32_t Count = Tpi->getNumTypeRecords();
461   auto Offsets = Tpi->getTypeIndexOffsets();
462   TypeCollection =
463       llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
464 
465   return *TypeCollection;
466 }
467 
dumpFpm()468 void BytesOutputStyle::dumpFpm() {
469   printHeader(P, "Free Page Map");
470 
471   msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();
472   P.formatMsfStreamBlocks(File, FpmLayout);
473 }
474 
dumpStreamBytes()475 void BytesOutputStyle::dumpStreamBytes() {
476   if (StreamPurposes.empty())
477     discoverStreamPurposes(File, StreamPurposes);
478 
479   printHeader(P, "Stream Data");
480   ExitOnError Err("Unexpected error reading stream data");
481 
482   auto Specs = parseStreamSpecs(P);
483 
484   for (const auto &Spec : Specs) {
485     AutoIndent Indent(P);
486     if (Spec.SI >= StreamPurposes.size()) {
487       P.formatLine("Stream {0}: Not present", Spec.SI);
488       continue;
489     }
490     P.formatMsfStreamData("Data", File, Spec.SI,
491                           StreamPurposes[Spec.SI].getShortName(), Spec.Begin,
492                           Spec.Size);
493   }
494 }
495