blob: 9e5a28c2b98baa3467a2dd210d329907d4c48649 [file] [log] [blame]
Zachary Turner99402032017-06-22 20:58:11 +00001//===- 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
Zachary Turnerfa332822017-06-23 23:08:57 +000012#include "FormatUtil.h"
Zachary Turner99402032017-06-22 20:58:11 +000013#include "StreamUtil.h"
14#include "llvm-pdbutil.h"
15
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000016#include "llvm/DebugInfo/CodeView/Formatters.h"
17#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
Zachary Turner99402032017-06-22 20:58:11 +000018#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Zachary Turnerdd739682017-06-23 21:11:54 +000019#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
Zachary Turner6c3e41b2017-06-23 20:18:38 +000020#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
Zachary Turnerfa332822017-06-23 23:08:57 +000021#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
Zachary Turner99402032017-06-22 20:58:11 +000022#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
23#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000024#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
Zachary Turner99402032017-06-22 20:58:11 +000025#include "llvm/Support/BinaryStreamReader.h"
26#include "llvm/Support/FormatAdapters.h"
27#include "llvm/Support/FormatVariadic.h"
28
29using namespace llvm;
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000030using namespace llvm::codeview;
Zachary Turner99402032017-06-22 20:58:11 +000031using namespace llvm::msf;
32using namespace llvm::pdb;
33
34namespace {
35struct StreamSpec {
36 uint32_t SI = 0;
37 uint32_t Begin = 0;
38 uint32_t Size = 0;
39};
40} // namespace
41
42static 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
64static 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
79static 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
85BytesOutputStyle::BytesOutputStyle(PDBFile &File)
86 : File(File), P(2, false, outs()) {}
87
88Error 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
Zachary Turner6b124f22017-06-23 19:54:44 +0000107 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
Zachary Turner99402032017-06-22 20:58:11 +0000123 if (!opts::bytes::DumpStreamData.empty()) {
124 dumpStreamBytes();
125 P.NewLine();
126 }
Zachary Turner6c3e41b2017-06-23 20:18:38 +0000127
128 if (opts::bytes::NameMap) {
129 dumpNameMap();
130 P.NewLine();
131 }
Zachary Turnerdd739682017-06-23 21:11:54 +0000132
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
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000163 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
Zachary Turnerfa332822017-06-23 23:08:57 +0000173 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
Zachary Turner99402032017-06-22 20:58:11 +0000188 return Error::success();
189}
190
Zachary Turner6c3e41b2017-06-23 20:18:38 +0000191void 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
Zachary Turner99402032017-06-22 20:58:11 +0000202void 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
Zachary Turnerdd739682017-06-23 21:11:54 +0000221void 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
232void 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
243void 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
254void 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
265void 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
276void 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
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000287void 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
Zachary Turnerfa332822017-06-23 23:08:57 +0000317template <typename CallbackT>
318static void iterateOneModule(PDBFile &File, LinePrinter &P,
319 const DbiModuleList &Modules, uint32_t I,
320 uint32_t Digits, uint32_t IndentLevel,
321 CallbackT Callback) {
Zachary Turnere79b07e2017-06-26 17:22:36 +0000322 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
Zachary Turnerfa332822017-06-23 23:08:57 +0000328 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();
Zachary Turnerfa332822017-06-23 23:08:57 +0000334 AutoIndent Indent2(P, IndentLevel);
Zachary Turnere79b07e2017-06-26 17:22:36 +0000335 if (ModiStream == kInvalidStreamIndex)
336 return;
337
Zachary Turnerfa332822017-06-23 23:08:57 +0000338 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
350template <typename CallbackT>
351static 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
377void 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
390void 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
Zachary Turnere79b07e2017-06-26 17:22:36 +0000404static 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
Zachary Turnerfa332822017-06-23 23:08:57 +0000425void BytesOutputStyle::dumpModuleC13() {
426 printHeader(P, "Debug Chunks");
427
428 AutoIndent Indent(P);
429
Zachary Turnere79b07e2017-06-26 17:22:36 +0000430 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 });
Zachary Turnerfa332822017-06-23 23:08:57 +0000446}
447
Zachary Turner6b124f22017-06-23 19:54:44 +0000448void 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
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000463Expected<codeview::LazyRandomTypeCollection &>
464BytesOutputStyle::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
Zachary Turner99402032017-06-22 20:58:11 +0000483void 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) {
Zachary Turner99402032017-06-22 20:58:11 +0000493 AutoIndent Indent(P);
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000494 if (Spec.SI >= StreamPurposes.size()) {
Zachary Turner99402032017-06-22 20:58:11 +0000495 P.formatLine("Stream {0}: Not present", Spec.SI);
496 continue;
497 }
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000498 P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
499 Spec.Begin, Spec.Size);
Zachary Turner99402032017-06-22 20:58:11 +0000500 }
501}