blob: 288bef721041462a2a5e50548ab0480ae6c2315a [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
12#include "StreamUtil.h"
13#include "llvm-pdbutil.h"
14
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000015#include "llvm/DebugInfo/CodeView/Formatters.h"
16#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
Zachary Turner99402032017-06-22 20:58:11 +000017#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
Zachary Turnerdd739682017-06-23 21:11:54 +000018#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
Zachary Turner6c3e41b2017-06-23 20:18:38 +000019#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
Zachary Turner99402032017-06-22 20:58:11 +000020#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
21#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000022#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
Zachary Turner99402032017-06-22 20:58:11 +000023#include "llvm/Support/BinaryStreamReader.h"
24#include "llvm/Support/FormatAdapters.h"
25#include "llvm/Support/FormatVariadic.h"
26
27using namespace llvm;
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +000028using namespace llvm::codeview;
Zachary Turner99402032017-06-22 20:58:11 +000029using namespace llvm::msf;
30using namespace llvm::pdb;
31
32namespace {
33struct StreamSpec {
34 uint32_t SI = 0;
35 uint32_t Begin = 0;
36 uint32_t Size = 0;
37};
38} // namespace
39
40static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
41 StreamSpec Result;
42 if (Str.consumeInteger(0, Result.SI))
43 return make_error<RawError>(raw_error_code::invalid_format,
44 "Invalid Stream Specification");
45 if (Str.consume_front(":")) {
46 if (Str.consumeInteger(0, Result.Begin))
47 return make_error<RawError>(raw_error_code::invalid_format,
48 "Invalid Stream Specification");
49 }
50 if (Str.consume_front("@")) {
51 if (Str.consumeInteger(0, Result.Size))
52 return make_error<RawError>(raw_error_code::invalid_format,
53 "Invalid Stream Specification");
54 }
55
56 if (!Str.empty())
57 return make_error<RawError>(raw_error_code::invalid_format,
58 "Invalid Stream Specification");
59 return Result;
60}
61
62static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
63 SmallVector<StreamSpec, 2> Result;
64
65 for (auto &Str : opts::bytes::DumpStreamData) {
66 auto ESS = parseStreamSpec(Str);
67 if (!ESS) {
68 P.formatLine("Error parsing stream spec {0}: {1}", Str,
69 toString(ESS.takeError()));
70 continue;
71 }
72 Result.push_back(*ESS);
73 }
74 return Result;
75}
76
77static void printHeader(LinePrinter &P, const Twine &S) {
78 P.NewLine();
79 P.formatLine("{0,=60}", S);
80 P.formatLine("{0}", fmt_repeat('=', 60));
81}
82
83BytesOutputStyle::BytesOutputStyle(PDBFile &File)
84 : File(File), P(2, false, outs()) {}
85
86Error BytesOutputStyle::dump() {
87
88 if (opts::bytes::DumpBlockRange.hasValue()) {
89 auto &R = *opts::bytes::DumpBlockRange;
90 uint32_t Max = R.Max.getValueOr(R.Min);
91
92 if (Max < R.Min)
93 return make_error<StringError>(
94 "Invalid block range specified. Max < Min",
95 inconvertibleErrorCode());
96 if (Max >= File.getBlockCount())
97 return make_error<StringError>(
98 "Invalid block range specified. Requested block out of bounds",
99 inconvertibleErrorCode());
100
101 dumpBlockRanges(R.Min, Max);
102 P.NewLine();
103 }
104
Zachary Turner6b124f22017-06-23 19:54:44 +0000105 if (opts::bytes::DumpByteRange.hasValue()) {
106 auto &R = *opts::bytes::DumpByteRange;
107 uint32_t Max = R.Max.getValueOr(File.getFileSize());
108
109 if (Max < R.Min)
110 return make_error<StringError>("Invalid byte range specified. Max < Min",
111 inconvertibleErrorCode());
112 if (Max >= File.getFileSize())
113 return make_error<StringError>(
114 "Invalid byte range specified. Requested byte larger than file size",
115 inconvertibleErrorCode());
116
117 dumpByteRanges(R.Min, Max);
118 P.NewLine();
119 }
120
Zachary Turner99402032017-06-22 20:58:11 +0000121 if (!opts::bytes::DumpStreamData.empty()) {
122 dumpStreamBytes();
123 P.NewLine();
124 }
Zachary Turner6c3e41b2017-06-23 20:18:38 +0000125
126 if (opts::bytes::NameMap) {
127 dumpNameMap();
128 P.NewLine();
129 }
Zachary Turnerdd739682017-06-23 21:11:54 +0000130
131 if (opts::bytes::SectionContributions) {
132 dumpSectionContributions();
133 P.NewLine();
134 }
135
136 if (opts::bytes::SectionMap) {
137 dumpSectionMap();
138 P.NewLine();
139 }
140
141 if (opts::bytes::ModuleInfos) {
142 dumpModuleInfos();
143 P.NewLine();
144 }
145
146 if (opts::bytes::FileInfo) {
147 dumpFileInfo();
148 P.NewLine();
149 }
150
151 if (opts::bytes::TypeServerMap) {
152 dumpTypeServerMap();
153 P.NewLine();
154 }
155
156 if (opts::bytes::ECData) {
157 dumpECData();
158 P.NewLine();
159 }
160
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000161 if (!opts::bytes::TypeIndex.empty()) {
162 dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex);
163 P.NewLine();
164 }
165
166 if (!opts::bytes::IdIndex.empty()) {
167 dumpTypeIndex(StreamIPI, opts::bytes::IdIndex);
168 P.NewLine();
169 }
170
Zachary Turner99402032017-06-22 20:58:11 +0000171 return Error::success();
172}
173
Zachary Turner6c3e41b2017-06-23 20:18:38 +0000174void BytesOutputStyle::dumpNameMap() {
175 printHeader(P, "Named Stream Map");
176
177 AutoIndent Indent(P);
178
179 auto &InfoS = Err(File.getPDBInfoStream());
180 BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer();
181 auto Layout = File.getStreamLayout(StreamPDB);
182 P.formatMsfStreamData("Named Stream Map", File, Layout, NS);
183}
184
Zachary Turner99402032017-06-22 20:58:11 +0000185void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
186 printHeader(P, "MSF Blocks");
187
188 AutoIndent Indent(P);
189 for (uint32_t I = Min; I <= Max; ++I) {
190 uint64_t Base = I;
191 Base *= File.getBlockSize();
192
193 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
194 if (!ExpectedData) {
195 P.formatLine("Could not get block {0}. Reason = {1}", I,
196 toString(ExpectedData.takeError()));
197 continue;
198 }
199 std::string Label = formatv("Block {0}", I).str();
200 P.formatBinary(Label, *ExpectedData, Base, 0);
201 }
202}
203
Zachary Turnerdd739682017-06-23 21:11:54 +0000204void BytesOutputStyle::dumpSectionContributions() {
205 printHeader(P, "Section Contributions");
206
207 AutoIndent Indent(P);
208
209 auto &DbiS = Err(File.getPDBDbiStream());
210 BinarySubstreamRef NS = DbiS.getSectionContributionData();
211 auto Layout = File.getStreamLayout(StreamDBI);
212 P.formatMsfStreamData("Section Contributions", File, Layout, NS);
213}
214
215void BytesOutputStyle::dumpSectionMap() {
216 printHeader(P, "Section Map");
217
218 AutoIndent Indent(P);
219
220 auto &DbiS = Err(File.getPDBDbiStream());
221 BinarySubstreamRef NS = DbiS.getSecMapSubstreamData();
222 auto Layout = File.getStreamLayout(StreamDBI);
223 P.formatMsfStreamData("Section Map", File, Layout, NS);
224}
225
226void BytesOutputStyle::dumpModuleInfos() {
227 printHeader(P, "Module Infos");
228
229 AutoIndent Indent(P);
230
231 auto &DbiS = Err(File.getPDBDbiStream());
232 BinarySubstreamRef NS = DbiS.getModiSubstreamData();
233 auto Layout = File.getStreamLayout(StreamDBI);
234 P.formatMsfStreamData("Module Infos", File, Layout, NS);
235}
236
237void BytesOutputStyle::dumpFileInfo() {
238 printHeader(P, "File Info");
239
240 AutoIndent Indent(P);
241
242 auto &DbiS = Err(File.getPDBDbiStream());
243 BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData();
244 auto Layout = File.getStreamLayout(StreamDBI);
245 P.formatMsfStreamData("File Info", File, Layout, NS);
246}
247
248void BytesOutputStyle::dumpTypeServerMap() {
249 printHeader(P, "Type Server Map");
250
251 AutoIndent Indent(P);
252
253 auto &DbiS = Err(File.getPDBDbiStream());
254 BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData();
255 auto Layout = File.getStreamLayout(StreamDBI);
256 P.formatMsfStreamData("Type Server Map", File, Layout, NS);
257}
258
259void BytesOutputStyle::dumpECData() {
260 printHeader(P, "Edit and Continue Data");
261
262 AutoIndent Indent(P);
263
264 auto &DbiS = Err(File.getPDBDbiStream());
265 BinarySubstreamRef NS = DbiS.getECSubstreamData();
266 auto Layout = File.getStreamLayout(StreamDBI);
267 P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS);
268}
269
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000270void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx,
271 ArrayRef<uint32_t> Indices) {
272 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
273 assert(!Indices.empty());
274
275 bool IsTpi = (StreamIdx == StreamTPI);
276
277 StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records";
278 printHeader(P, Label);
279 auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream());
280
281 AutoIndent Indent(P);
282
283 auto Substream = Stream.getTypeRecordsSubstream();
284 auto &Types = Err(initializeTypes(StreamIdx));
285 auto Layout = File.getStreamLayout(StreamIdx);
286 for (const auto &Id : Indices) {
287 TypeIndex TI(Id);
288 if (TI.toArrayIndex() >= Types.capacity()) {
289 P.formatLine("Error: TypeIndex {0} does not exist", TI);
290 continue;
291 }
292
293 auto Type = Types.getType(TI);
294 uint32_t Offset = Types.getOffsetOfType(TI);
295 auto OneType = Substream.slice(Offset, Type.length());
296 P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType);
297 }
298}
299
Zachary Turner6b124f22017-06-23 19:54:44 +0000300void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) {
301 printHeader(P, "MSF Bytes");
302
303 AutoIndent Indent(P);
304
305 BinaryStreamReader Reader(File.getMsfBuffer());
306 ArrayRef<uint8_t> Data;
307 consumeError(Reader.skip(Min));
308 uint32_t Size = Max - Min + 1;
309 auto EC = Reader.readBytes(Data, Size);
310 assert(!EC);
311 consumeError(std::move(EC));
312 P.formatBinary("Bytes", Data, Min);
313}
314
Zachary Turnerc2f5b4b2017-06-23 21:50:54 +0000315Expected<codeview::LazyRandomTypeCollection &>
316BytesOutputStyle::initializeTypes(uint32_t StreamIdx) {
317 auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes;
318 if (TypeCollection)
319 return *TypeCollection;
320
321 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
322 : File.getPDBIpiStream();
323 if (!Tpi)
324 return Tpi.takeError();
325
326 auto &Types = Tpi->typeArray();
327 uint32_t Count = Tpi->getNumTypeRecords();
328 auto Offsets = Tpi->getTypeIndexOffsets();
329 TypeCollection =
330 llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
331
332 return *TypeCollection;
333}
334
Zachary Turner99402032017-06-22 20:58:11 +0000335void BytesOutputStyle::dumpStreamBytes() {
336 if (StreamPurposes.empty())
337 discoverStreamPurposes(File, StreamPurposes);
338
339 printHeader(P, "Stream Data");
340 ExitOnError Err("Unexpected error reading stream data");
341
342 auto Specs = parseStreamSpecs(P);
343
344 for (const auto &Spec : Specs) {
Zachary Turner99402032017-06-22 20:58:11 +0000345 AutoIndent Indent(P);
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000346 if (Spec.SI >= StreamPurposes.size()) {
Zachary Turner99402032017-06-22 20:58:11 +0000347 P.formatLine("Stream {0}: Not present", Spec.SI);
348 continue;
349 }
Zachary Turner0b36c3e2017-06-23 18:52:13 +0000350 P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
351 Spec.Begin, Spec.Size);
Zachary Turner99402032017-06-22 20:58:11 +0000352 }
353}