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