blob: 2b96c8f986aa0ef701735938eebeb79a5cc3a224 [file] [log] [blame]
Zachary Turner08bb54f2017-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 Turner554302a2017-06-23 23:08:57 +000012#include "FormatUtil.h"
Zachary Turner08bb54f2017-06-22 20:58:11 +000013#include "StreamUtil.h"
14#include "llvm-pdbutil.h"
15
Zachary Turner5d2c9172017-06-23 21:50:54 +000016#include "llvm/DebugInfo/CodeView/Formatters.h"
17#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
Zachary Turner34173de2017-08-02 22:25:52 +000018#include "llvm/DebugInfo/MSF/MSFCommon.h"
Zachary Turner08bb54f2017-06-22 20:58:11 +000019#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Zachary Turner777bbb52017-06-23 21:11:54 +000020#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
Zachary Turnera77c3fd2017-06-23 20:18:38 +000021#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
Zachary Turner554302a2017-06-23 23:08:57 +000022#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
Zachary Turner08bb54f2017-06-22 20:58:11 +000023#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
24#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turner5d2c9172017-06-23 21:50:54 +000025#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
Zachary Turner08bb54f2017-06-22 20:58:11 +000026#include "llvm/Support/BinaryStreamReader.h"
27#include "llvm/Support/FormatAdapters.h"
28#include "llvm/Support/FormatVariadic.h"
29
30using namespace llvm;
Zachary Turner5d2c9172017-06-23 21:50:54 +000031using namespace llvm::codeview;
Zachary Turner08bb54f2017-06-22 20:58:11 +000032using namespace llvm::msf;
33using namespace llvm::pdb;
34
35namespace {
36struct StreamSpec {
37 uint32_t SI = 0;
38 uint32_t Begin = 0;
39 uint32_t Size = 0;
40};
41} // namespace
42
43static 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
65static 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
80static 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
86BytesOutputStyle::BytesOutputStyle(PDBFile &File)
87 : File(File), P(2, false, outs()) {}
88
89Error 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
Zachary Turner87f3ec22017-06-23 19:54:44 +0000108 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
Zachary Turner34173de2017-08-02 22:25:52 +0000124 if (opts::bytes::Fpm) {
125 dumpFpm();
126 P.NewLine();
127 }
128
Zachary Turner08bb54f2017-06-22 20:58:11 +0000129 if (!opts::bytes::DumpStreamData.empty()) {
130 dumpStreamBytes();
131 P.NewLine();
132 }
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000133
134 if (opts::bytes::NameMap) {
135 dumpNameMap();
136 P.NewLine();
137 }
Zachary Turner777bbb52017-06-23 21:11:54 +0000138
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
Zachary Turner5d2c9172017-06-23 21:50:54 +0000169 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
Zachary Turner554302a2017-06-23 23:08:57 +0000179 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
Zachary Turner08bb54f2017-06-22 20:58:11 +0000194 return Error::success();
195}
196
Zachary Turnera77c3fd2017-06-23 20:18:38 +0000197void 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
Zachary Turner08bb54f2017-06-22 20:58:11 +0000208void 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
Zachary Turner777bbb52017-06-23 21:11:54 +0000227void 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
238void 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
249void 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
260void 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
271void 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
282void 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
Zachary Turner5d2c9172017-06-23 21:50:54 +0000293void 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
Zachary Turner554302a2017-06-23 23:08:57 +0000323template <typename CallbackT>
324static void iterateOneModule(PDBFile &File, LinePrinter &P,
325 const DbiModuleList &Modules, uint32_t I,
326 uint32_t Digits, uint32_t IndentLevel,
327 CallbackT Callback) {
Zachary Turner72267192017-06-26 17:22:36 +0000328 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
Zachary Turner554302a2017-06-23 23:08:57 +0000334 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();
Zachary Turner554302a2017-06-23 23:08:57 +0000340 AutoIndent Indent2(P, IndentLevel);
Zachary Turner72267192017-06-26 17:22:36 +0000341 if (ModiStream == kInvalidStreamIndex)
342 return;
343
Zachary Turner554302a2017-06-23 23:08:57 +0000344 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
356template <typename CallbackT>
357static 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
383void 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
396void 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
410void BytesOutputStyle::dumpModuleC13() {
411 printHeader(P, "Debug Chunks");
412
413 AutoIndent Indent(P);
414
Zachary Turner72267192017-06-26 17:22:36 +0000415 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 });
Zachary Turner554302a2017-06-23 23:08:57 +0000431}
432
Zachary Turner87f3ec22017-06-23 19:54:44 +0000433void 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
Zachary Turner5d2c9172017-06-23 21:50:54 +0000448Expected<codeview::LazyRandomTypeCollection &>
449BytesOutputStyle::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
Zachary Turner34173de2017-08-02 22:25:52 +0000468void BytesOutputStyle::dumpFpm() {
469 printHeader(P, "Free Page Map");
470
471 msf::MSFStreamLayout FpmLayout = File.getFpmStreamLayout();
472 P.formatMsfStreamBlocks(File, FpmLayout);
473}
474
Zachary Turner08bb54f2017-06-22 20:58:11 +0000475void 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) {
Zachary Turner08bb54f2017-06-22 20:58:11 +0000485 AutoIndent Indent(P);
Zachary Turner35abb612017-06-23 18:52:13 +0000486 if (Spec.SI >= StreamPurposes.size()) {
Zachary Turner08bb54f2017-06-22 20:58:11 +0000487 P.formatLine("Stream {0}: Not present", Spec.SI);
488 continue;
489 }
Zachary Turnerb6d8c582017-08-21 14:53:25 +0000490 P.formatMsfStreamData("Data", File, Spec.SI,
491 StreamPurposes[Spec.SI].getShortName(), Spec.Begin,
492 Spec.Size);
Zachary Turner08bb54f2017-06-22 20:58:11 +0000493 }
494}