blob: 9ce6a51ca91cb16848bfc56b78f5a77097cbe16f [file] [log] [blame]
Zachary Turnerd3117392016-06-03 19:28:33 +00001//===- LLVMOutputStyle.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 "LLVMOutputStyle.h"
11
12#include "llvm-pdbdump.h"
13#include "llvm/DebugInfo/CodeView/EnumTables.h"
14#include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
15#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000016#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17#include "llvm/DebugInfo/MSF/StreamReader.h"
Zachary Turnerd3117392016-06-03 19:28:33 +000018#include "llvm/DebugInfo/PDB/PDBExtras.h"
19#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
20#include "llvm/DebugInfo/PDB/Raw/EnumTables.h"
21#include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
22#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
23#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
24#include "llvm/DebugInfo/PDB/Raw/ModStream.h"
25#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
26#include "llvm/DebugInfo/PDB/Raw/PublicsStream.h"
27#include "llvm/DebugInfo/PDB/Raw/RawError.h"
28#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
29#include "llvm/Object/COFF.h"
30
31#include <unordered_map>
32
33using namespace llvm;
34using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000035using namespace llvm::msf;
Zachary Turnerd3117392016-06-03 19:28:33 +000036using namespace llvm::pdb;
37
38static void printSectionOffset(llvm::raw_ostream &OS,
39 const SectionOffset &Off) {
40 OS << Off.Off << ", " << Off.Isect;
41}
42
43LLVMOutputStyle::LLVMOutputStyle(PDBFile &File)
44 : File(File), P(outs()), TD(&P, false) {}
45
Zachary Turnera30bd1a2016-06-30 17:42:48 +000046Error LLVMOutputStyle::dump() {
47 if (auto EC = dumpFileHeaders())
48 return EC;
49
50 if (auto EC = dumpStreamSummary())
51 return EC;
52
53 if (auto EC = dumpStreamBlocks())
54 return EC;
55
56 if (auto EC = dumpStreamData())
57 return EC;
58
59 if (auto EC = dumpInfoStream())
60 return EC;
61
62 if (auto EC = dumpNamedStream())
63 return EC;
64
65 if (auto EC = dumpTpiStream(StreamTPI))
66 return EC;
67
68 if (auto EC = dumpTpiStream(StreamIPI))
69 return EC;
70
71 if (auto EC = dumpDbiStream())
72 return EC;
73
74 if (auto EC = dumpSectionContribs())
75 return EC;
76
77 if (auto EC = dumpSectionMap())
78 return EC;
79
80 if (auto EC = dumpPublicsStream())
81 return EC;
82
83 if (auto EC = dumpSectionHeaders())
84 return EC;
85
86 if (auto EC = dumpFpoStream())
87 return EC;
88
89 flush();
90
91 return Error::success();
92}
93
Zachary Turnerd3117392016-06-03 19:28:33 +000094Error LLVMOutputStyle::dumpFileHeaders() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +000095 if (!opts::raw::DumpHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +000096 return Error::success();
97
98 DictScope D(P, "FileHeaders");
99 P.printNumber("BlockSize", File.getBlockSize());
Zachary Turnerb927e022016-07-15 22:17:19 +0000100 P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
Zachary Turnerd3117392016-06-03 19:28:33 +0000101 P.printNumber("NumBlocks", File.getBlockCount());
102 P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
103 P.printNumber("Unknown1", File.getUnknown1());
104 P.printNumber("BlockMapAddr", File.getBlockMapIndex());
105 P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
Zachary Turnerd3117392016-06-03 19:28:33 +0000106
107 // The directory is not contiguous. Instead, the block map contains a
108 // contiguous list of block numbers whose contents, when concatenated in
109 // order, make up the directory.
110 P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
111 P.printNumber("NumStreams", File.getNumStreams());
112 return Error::success();
113}
114
115Error LLVMOutputStyle::dumpStreamSummary() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000116 if (!opts::raw::DumpStreamSummary)
Zachary Turnerd3117392016-06-03 19:28:33 +0000117 return Error::success();
118
Reid Kleckner11582c52016-06-17 20:38:01 +0000119 // It's OK if we fail to load some of these streams, we still attempt to print
120 // what we can.
Zachary Turnera1657a92016-06-08 17:26:39 +0000121 auto Dbi = File.getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000122 auto Tpi = File.getPDBTpiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000123 auto Ipi = File.getPDBIpiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000124 auto Info = File.getPDBInfoStream();
Zachary Turnerd3117392016-06-03 19:28:33 +0000125
126 ListScope L(P, "Streams");
127 uint32_t StreamCount = File.getNumStreams();
128 std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
129 std::unordered_map<uint16_t, std::string> NamedStreams;
130
Reid Kleckner11582c52016-06-17 20:38:01 +0000131 if (Dbi) {
132 for (auto &ModI : Dbi->modules()) {
133 uint16_t SN = ModI.Info.getModuleStreamIndex();
134 ModStreams[SN] = &ModI;
135 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000136 }
Reid Kleckner11582c52016-06-17 20:38:01 +0000137 if (Info) {
138 for (auto &NSE : Info->named_streams()) {
139 NamedStreams[NSE.second] = NSE.first();
140 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000141 }
142
143 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
144 std::string Label("Stream ");
145 Label += to_string(StreamIdx);
146 std::string Value;
147 if (StreamIdx == OldMSFDirectory)
148 Value = "Old MSF Directory";
149 else if (StreamIdx == StreamPDB)
150 Value = "PDB Stream";
151 else if (StreamIdx == StreamDBI)
152 Value = "DBI Stream";
153 else if (StreamIdx == StreamTPI)
154 Value = "TPI Stream";
155 else if (StreamIdx == StreamIPI)
156 Value = "IPI Stream";
Reid Kleckner11582c52016-06-17 20:38:01 +0000157 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000158 Value = "Global Symbol Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000159 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000160 Value = "Public Symbol Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000161 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000162 Value = "Public Symbol Records";
Reid Kleckner11582c52016-06-17 20:38:01 +0000163 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000164 Value = "TPI Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000165 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000166 Value = "TPI Aux Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000167 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000168 Value = "IPI Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000169 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000170 Value = "IPI Aux Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000171 else if (Dbi &&
172 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
Zachary Turnerd3117392016-06-03 19:28:33 +0000173 Value = "Exception Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000174 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
Zachary Turnerd3117392016-06-03 19:28:33 +0000175 Value = "Fixup Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000176 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
Zachary Turnerd3117392016-06-03 19:28:33 +0000177 Value = "FPO Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000178 else if (Dbi &&
179 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
Zachary Turnerd3117392016-06-03 19:28:33 +0000180 Value = "New FPO Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000181 else if (Dbi &&
182 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
Zachary Turnerd3117392016-06-03 19:28:33 +0000183 Value = "Omap From Source Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000184 else if (Dbi &&
185 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
Zachary Turnerd3117392016-06-03 19:28:33 +0000186 Value = "Omap To Source Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000187 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
Zachary Turnerd3117392016-06-03 19:28:33 +0000188 Value = "Pdata";
Reid Kleckner11582c52016-06-17 20:38:01 +0000189 else if (Dbi &&
190 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
Zachary Turnerd3117392016-06-03 19:28:33 +0000191 Value = "Section Header Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000192 else if (Dbi &&
193 StreamIdx ==
194 Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
Zachary Turnerd3117392016-06-03 19:28:33 +0000195 Value = "Section Header Original Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000196 else if (Dbi &&
197 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
Zachary Turnerd3117392016-06-03 19:28:33 +0000198 Value = "Token Rid Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000199 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
Zachary Turnerd3117392016-06-03 19:28:33 +0000200 Value = "Xdata";
201 else {
202 auto ModIter = ModStreams.find(StreamIdx);
203 auto NSIter = NamedStreams.find(StreamIdx);
204 if (ModIter != ModStreams.end()) {
205 Value = "Module \"";
206 Value += ModIter->second->Info.getModuleName().str();
207 Value += "\"";
208 } else if (NSIter != NamedStreams.end()) {
209 Value = "Named Stream \"";
210 Value += NSIter->second;
211 Value += "\"";
212 } else {
213 Value = "???";
214 }
215 }
216 Value = "[" + Value + "]";
217 Value =
218 Value + " (" + to_string(File.getStreamByteSize(StreamIdx)) + " bytes)";
219
220 P.printString(Label, Value);
221 }
Reid Kleckner11582c52016-06-17 20:38:01 +0000222
223 // Consume errors from missing streams.
224 if (!Dbi)
225 consumeError(Dbi.takeError());
226 if (!Tpi)
227 consumeError(Tpi.takeError());
228 if (!Ipi)
229 consumeError(Ipi.takeError());
230 if (!Info)
231 consumeError(Info.takeError());
232
Zachary Turnerd3117392016-06-03 19:28:33 +0000233 P.flush();
234 return Error::success();
235}
236
237Error LLVMOutputStyle::dumpStreamBlocks() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000238 if (!opts::raw::DumpStreamBlocks)
Zachary Turnerd3117392016-06-03 19:28:33 +0000239 return Error::success();
240
241 ListScope L(P, "StreamBlocks");
242 uint32_t StreamCount = File.getNumStreams();
243 for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
244 std::string Name("Stream ");
245 Name += to_string(StreamIdx);
246 auto StreamBlocks = File.getStreamBlockList(StreamIdx);
247 P.printList(Name, StreamBlocks);
248 }
249 return Error::success();
250}
251
252Error LLVMOutputStyle::dumpStreamData() {
253 uint32_t StreamCount = File.getNumStreams();
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000254 StringRef DumpStreamStr = opts::raw::DumpStreamDataIdx;
Zachary Turnerd3117392016-06-03 19:28:33 +0000255 uint32_t DumpStreamNum;
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000256 if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum))
Zachary Turnerd3117392016-06-03 19:28:33 +0000257 return Error::success();
258
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000259 if (DumpStreamNum >= StreamCount)
260 return make_error<RawError>(raw_error_code::no_stream);
261
Zachary Turnerd66889c2016-07-28 19:12:28 +0000262 auto S = MappedBlockStream::createIndexedStream(
263 File.getMsfLayout(), File.getMsfBuffer(), DumpStreamNum);
264 StreamReader R(*S);
Zachary Turnerd3117392016-06-03 19:28:33 +0000265 while (R.bytesRemaining() > 0) {
266 ArrayRef<uint8_t> Data;
267 uint32_t BytesToReadInBlock = std::min(
268 R.bytesRemaining(), static_cast<uint32_t>(File.getBlockSize()));
269 if (auto EC = R.readBytes(Data, BytesToReadInBlock))
270 return EC;
271 P.printBinaryBlock(
272 "Data",
273 StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size()));
274 }
275 return Error::success();
276}
277
278Error LLVMOutputStyle::dumpInfoStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000279 if (!opts::raw::DumpHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +0000280 return Error::success();
Zachary Turnera1657a92016-06-08 17:26:39 +0000281 auto IS = File.getPDBInfoStream();
282 if (!IS)
283 return IS.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000284
285 DictScope D(P, "PDB Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000286 P.printNumber("Version", IS->getVersion());
287 P.printHex("Signature", IS->getSignature());
288 P.printNumber("Age", IS->getAge());
289 P.printObject("Guid", IS->getGuid());
Zachary Turnerd3117392016-06-03 19:28:33 +0000290 return Error::success();
291}
292
293Error LLVMOutputStyle::dumpNamedStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000294 if (opts::raw::DumpStreamDataName.empty())
Zachary Turnerd3117392016-06-03 19:28:33 +0000295 return Error::success();
296
Zachary Turnera1657a92016-06-08 17:26:39 +0000297 auto IS = File.getPDBInfoStream();
298 if (!IS)
299 return IS.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000300
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000301 uint32_t NameStreamIndex =
302 IS->getNamedStreamIndex(opts::raw::DumpStreamDataName);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000303 if (NameStreamIndex == 0 || NameStreamIndex >= File.getNumStreams())
304 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd3117392016-06-03 19:28:33 +0000305
306 if (NameStreamIndex != 0) {
307 std::string Name("Stream '");
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000308 Name += opts::raw::DumpStreamDataName;
Zachary Turnerd3117392016-06-03 19:28:33 +0000309 Name += "'";
310 DictScope D(P, Name);
311 P.printNumber("Index", NameStreamIndex);
312
Zachary Turnerd66889c2016-07-28 19:12:28 +0000313 auto NameStream = MappedBlockStream::createIndexedStream(
314 File.getMsfLayout(), File.getMsfBuffer(), NameStreamIndex);
315 StreamReader Reader(*NameStream);
Zachary Turnerd3117392016-06-03 19:28:33 +0000316
317 NameHashTable NameTable;
318 if (auto EC = NameTable.load(Reader))
319 return EC;
320
321 P.printHex("Signature", NameTable.getSignature());
322 P.printNumber("Version", NameTable.getHashVersion());
323 P.printNumber("Name Count", NameTable.getNameCount());
324 ListScope L(P, "Names");
325 for (uint32_t ID : NameTable.name_ids()) {
326 StringRef Str = NameTable.getStringForID(ID);
327 if (!Str.empty())
328 P.printString(to_string(ID), Str);
329 }
330 }
331 return Error::success();
332}
333
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000334static void printTypeIndexOffset(raw_ostream &OS,
335 const TypeIndexOffset &TIOff) {
336 OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
337}
338
339static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000340 if (!opts::raw::DumpTpiHash)
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000341 return;
342 DictScope DD(P, "Hash");
Rui Ueyamaf14a74c2016-06-07 23:53:43 +0000343 P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
Rui Ueyamad8339172016-06-07 23:44:27 +0000344 P.printNumber("Hash Key Size", Tpi.getHashKeySize());
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000345 P.printList("Values", Tpi.getHashValues());
346 P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
347 printTypeIndexOffset);
348 P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
349 printTypeIndexOffset);
350}
351
Zachary Turnerd3117392016-06-03 19:28:33 +0000352Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
353 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
354
355 bool DumpRecordBytes = false;
356 bool DumpRecords = false;
357 StringRef Label;
358 StringRef VerLabel;
359 if (StreamIdx == StreamTPI) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000360 DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
361 DumpRecords = opts::raw::DumpTpiRecords;
Zachary Turnerd3117392016-06-03 19:28:33 +0000362 Label = "Type Info Stream (TPI)";
363 VerLabel = "TPI Version";
364 } else if (StreamIdx == StreamIPI) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000365 DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
366 DumpRecords = opts::raw::DumpIpiRecords;
Zachary Turnerd3117392016-06-03 19:28:33 +0000367 Label = "Type Info Stream (IPI)";
368 VerLabel = "IPI Version";
369 }
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000370 if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
Zachary Turnerd3117392016-06-03 19:28:33 +0000371 return Error::success();
372
Zachary Turnera1657a92016-06-08 17:26:39 +0000373 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
374 : File.getPDBIpiStream();
375 if (!Tpi)
376 return Tpi.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000377
378 if (DumpRecords || DumpRecordBytes) {
379 DictScope D(P, Label);
380
Zachary Turnera1657a92016-06-08 17:26:39 +0000381 P.printNumber(VerLabel, Tpi->getTpiVersion());
382 P.printNumber("Record count", Tpi->NumTypeRecords());
Zachary Turnerd3117392016-06-03 19:28:33 +0000383
384 ListScope L(P, "Records");
385
386 bool HadError = false;
Zachary Turnera1657a92016-06-08 17:26:39 +0000387 for (auto &Type : Tpi->types(&HadError)) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000388 DictScope DD(P, "");
389
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000390 if (DumpRecords) {
391 if (auto EC = TD.dump(Type))
392 return EC;
393 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000394
395 if (DumpRecordBytes)
396 P.printBinaryBlock("Bytes", Type.Data);
397 }
Zachary Turnera1657a92016-06-08 17:26:39 +0000398 dumpTpiHash(P, *Tpi);
Zachary Turnerd3117392016-06-03 19:28:33 +0000399 if (HadError)
400 return make_error<RawError>(raw_error_code::corrupt_file,
401 "TPI stream contained corrupt record");
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000402 } else if (opts::raw::DumpModuleSyms) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000403 // Even if the user doesn't want to dump type records, we still need to
404 // iterate them in order to build the list of types so that we can print
405 // them when dumping module symbols. So when they want to dump symbols
406 // but not types, use a null output stream.
407 ScopedPrinter *OldP = TD.getPrinter();
408 TD.setPrinter(nullptr);
409
410 bool HadError = false;
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000411 for (auto &Type : Tpi->types(&HadError)) {
412 if (auto EC = TD.dump(Type))
413 return EC;
414 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000415
416 TD.setPrinter(OldP);
Zachary Turnera1657a92016-06-08 17:26:39 +0000417 dumpTpiHash(P, *Tpi);
Zachary Turnerd3117392016-06-03 19:28:33 +0000418 if (HadError)
419 return make_error<RawError>(raw_error_code::corrupt_file,
420 "TPI stream contained corrupt record");
421 }
422 P.flush();
423 return Error::success();
424}
425
426Error LLVMOutputStyle::dumpDbiStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000427 bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms ||
428 opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo;
429 if (!opts::raw::DumpHeaders && !DumpModules)
Zachary Turnerd3117392016-06-03 19:28:33 +0000430 return Error::success();
431
Zachary Turnera1657a92016-06-08 17:26:39 +0000432 auto DS = File.getPDBDbiStream();
433 if (!DS)
434 return DS.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000435
436 DictScope D(P, "DBI Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000437 P.printNumber("Dbi Version", DS->getDbiVersion());
438 P.printNumber("Age", DS->getAge());
439 P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
440 P.printBoolean("Has CTypes", DS->hasCTypes());
441 P.printBoolean("Is Stripped", DS->isStripped());
442 P.printObject("Machine Type", DS->getMachineType());
443 P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
444 P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
445 P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
Zachary Turnerd3117392016-06-03 19:28:33 +0000446
Zachary Turnera1657a92016-06-08 17:26:39 +0000447 uint16_t Major = DS->getBuildMajorVersion();
448 uint16_t Minor = DS->getBuildMinorVersion();
Zachary Turnerd3117392016-06-03 19:28:33 +0000449 P.printVersion("Toolchain Version", Major, Minor);
450
451 std::string DllName;
452 raw_string_ostream DllStream(DllName);
453 DllStream << "mspdb" << Major << Minor << ".dll version";
454 DllStream.flush();
Zachary Turnera1657a92016-06-08 17:26:39 +0000455 P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
Zachary Turnerd3117392016-06-03 19:28:33 +0000456
457 if (DumpModules) {
458 ListScope L(P, "Modules");
Zachary Turnera1657a92016-06-08 17:26:39 +0000459 for (auto &Modi : DS->modules()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000460 DictScope DD(P);
461 P.printString("Name", Modi.Info.getModuleName().str());
462 P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
463 P.printString("Object File Name", Modi.Info.getObjFileName().str());
464 P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
465 P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
466 P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
467 P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize());
468 P.printNumber("C13 Line Info Byte Size",
469 Modi.Info.getC13LineInfoByteSize());
470 P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize());
471 P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex());
472 P.printBoolean("Has EC Info", Modi.Info.hasECInfo());
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000473 if (opts::raw::DumpModuleFiles) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000474 std::string FileListName =
475 to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
476 ListScope LL(P, FileListName);
477 for (auto File : Modi.SourceFiles)
478 P.printString(File.str());
479 }
480 bool HasModuleDI =
481 (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
482 bool ShouldDumpSymbols =
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000483 (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
484 if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000485 auto ModStreamData = MappedBlockStream::createIndexedStream(
Zachary Turnerd66889c2016-07-28 19:12:28 +0000486 File.getMsfLayout(), File.getMsfBuffer(),
487 Modi.Info.getModuleStreamIndex());
488
489 ModStream ModS(Modi.Info, std::move(ModStreamData));
Zachary Turnerd3117392016-06-03 19:28:33 +0000490 if (auto EC = ModS.reload())
491 return EC;
492
493 if (ShouldDumpSymbols) {
494 ListScope SS(P, "Symbols");
495 codeview::CVSymbolDumper SD(P, TD, nullptr, false);
496 bool HadError = false;
497 for (const auto &S : ModS.symbols(&HadError)) {
498 DictScope DD(P, "");
499
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000500 if (opts::raw::DumpModuleSyms)
Zachary Turnerd3117392016-06-03 19:28:33 +0000501 SD.dump(S);
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000502 if (opts::raw::DumpSymRecordBytes)
Zachary Turnerd3117392016-06-03 19:28:33 +0000503 P.printBinaryBlock("Bytes", S.Data);
504 }
505 if (HadError)
506 return make_error<RawError>(
507 raw_error_code::corrupt_file,
508 "DBI stream contained corrupt symbol record");
509 }
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000510 if (opts::raw::DumpLineInfo) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000511 ListScope SS(P, "LineInfo");
512 bool HadError = false;
513 // Define a locally scoped visitor to print the different
514 // substream types types.
515 class RecordVisitor : public codeview::IModuleSubstreamVisitor {
516 public:
517 RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
518 Error visitUnknown(ModuleSubstreamKind Kind,
Zachary Turnerd66889c2016-07-28 19:12:28 +0000519 ReadableStreamRef Stream) override {
Zachary Turnerd3117392016-06-03 19:28:33 +0000520 DictScope DD(P, "Unknown");
521 ArrayRef<uint8_t> Data;
522 StreamReader R(Stream);
523 if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
524 return make_error<RawError>(
525 raw_error_code::corrupt_file,
526 "DBI stream contained corrupt line info record");
527 }
528 P.printBinaryBlock("Data", Data);
529 return Error::success();
530 }
531 Error
Zachary Turnerd66889c2016-07-28 19:12:28 +0000532 visitFileChecksums(ReadableStreamRef Data,
Zachary Turnerd3117392016-06-03 19:28:33 +0000533 const FileChecksumArray &Checksums) override {
534 DictScope DD(P, "FileChecksums");
535 for (const auto &C : Checksums) {
536 DictScope DDD(P, "Checksum");
537 if (auto Result = getFileNameForOffset(C.FileNameOffset))
538 P.printString("FileName", Result.get());
539 else
540 return Result.takeError();
541 P.flush();
542 P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames());
543 P.printBinaryBlock("Checksum", C.Checksum);
544 }
545 return Error::success();
546 }
547
Zachary Turnerd66889c2016-07-28 19:12:28 +0000548 Error visitLines(ReadableStreamRef Data,
549 const LineSubstreamHeader *Header,
Zachary Turnerd3117392016-06-03 19:28:33 +0000550 const LineInfoArray &Lines) override {
551 DictScope DD(P, "Lines");
552 for (const auto &L : Lines) {
553 if (auto Result = getFileNameForOffset2(L.NameIndex))
554 P.printString("FileName", Result.get());
555 else
556 return Result.takeError();
557 P.flush();
558 for (const auto &N : L.LineNumbers) {
559 DictScope DDD(P, "Line");
560 LineInfo LI(N.Flags);
561 P.printNumber("Offset", N.Offset);
562 if (LI.isAlwaysStepInto())
563 P.printString("StepInto", StringRef("Always"));
564 else if (LI.isNeverStepInto())
565 P.printString("StepInto", StringRef("Never"));
566 else
567 P.printNumber("LineNumberStart", LI.getStartLine());
568 P.printNumber("EndDelta", LI.getLineDelta());
569 P.printBoolean("IsStatement", LI.isStatement());
570 }
571 for (const auto &C : L.Columns) {
572 DictScope DDD(P, "Column");
573 P.printNumber("Start", C.StartColumn);
574 P.printNumber("End", C.EndColumn);
575 }
576 }
577 return Error::success();
578 }
579
580 private:
581 Expected<StringRef> getFileNameForOffset(uint32_t Offset) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000582 auto ST = F.getStringTable();
583 if (!ST)
584 return ST.takeError();
585
586 return ST->getStringForID(Offset);
Zachary Turnerd3117392016-06-03 19:28:33 +0000587 }
588 Expected<StringRef> getFileNameForOffset2(uint32_t Offset) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000589 auto DS = F.getPDBDbiStream();
590 if (!DS)
591 return DS.takeError();
592 return DS->getFileNameForIndex(Offset);
Zachary Turnerd3117392016-06-03 19:28:33 +0000593 }
594 ScopedPrinter &P;
595 PDBFile &F;
596 };
597
598 RecordVisitor V(P, File);
599 for (const auto &L : ModS.lines(&HadError)) {
600 if (auto EC = codeview::visitModuleSubstream(L, V))
601 return EC;
602 }
603 }
604 }
605 }
606 }
607 return Error::success();
608}
609
610Error LLVMOutputStyle::dumpSectionContribs() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000611 if (!opts::raw::DumpSectionContribs)
Zachary Turnerd3117392016-06-03 19:28:33 +0000612 return Error::success();
613
Zachary Turnera1657a92016-06-08 17:26:39 +0000614 auto Dbi = File.getPDBDbiStream();
615 if (!Dbi)
616 return Dbi.takeError();
617
Zachary Turnerd3117392016-06-03 19:28:33 +0000618 ListScope L(P, "Section Contributions");
619 class Visitor : public ISectionContribVisitor {
620 public:
621 Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
622 void visit(const SectionContrib &SC) override {
623 DictScope D(P, "Contribution");
624 P.printNumber("ISect", SC.ISect);
625 P.printNumber("Off", SC.Off);
626 P.printNumber("Size", SC.Size);
627 P.printFlags("Characteristics", SC.Characteristics,
628 codeview::getImageSectionCharacteristicNames(),
629 COFF::SectionCharacteristics(0x00F00000));
630 {
631 DictScope DD(P, "Module");
632 P.printNumber("Index", SC.Imod);
633 auto M = DS.modules();
634 if (M.size() > SC.Imod) {
635 P.printString("Name", M[SC.Imod].Info.getModuleName());
636 }
637 }
638 P.printNumber("Data CRC", SC.DataCrc);
639 P.printNumber("Reloc CRC", SC.RelocCrc);
640 P.flush();
641 }
642 void visit(const SectionContrib2 &SC) override {
643 visit(SC.Base);
644 P.printNumber("ISect Coff", SC.ISectCoff);
645 P.flush();
646 }
647
648 private:
649 ScopedPrinter &P;
650 DbiStream &DS;
651 };
Zachary Turnera1657a92016-06-08 17:26:39 +0000652 Visitor V(P, *Dbi);
653 Dbi->visitSectionContributions(V);
Zachary Turnerd3117392016-06-03 19:28:33 +0000654 return Error::success();
655}
656
657Error LLVMOutputStyle::dumpSectionMap() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000658 if (!opts::raw::DumpSectionMap)
Zachary Turnerd3117392016-06-03 19:28:33 +0000659 return Error::success();
660
Zachary Turnera1657a92016-06-08 17:26:39 +0000661 auto Dbi = File.getPDBDbiStream();
662 if (!Dbi)
663 return Dbi.takeError();
664
Zachary Turnerd3117392016-06-03 19:28:33 +0000665 ListScope L(P, "Section Map");
Zachary Turnera1657a92016-06-08 17:26:39 +0000666 for (auto &M : Dbi->getSectionMap()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000667 DictScope D(P, "Entry");
668 P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
669 P.printNumber("Flags", M.Flags);
670 P.printNumber("Ovl", M.Ovl);
671 P.printNumber("Group", M.Group);
672 P.printNumber("Frame", M.Frame);
673 P.printNumber("SecName", M.SecName);
674 P.printNumber("ClassName", M.ClassName);
675 P.printNumber("Offset", M.Offset);
676 P.printNumber("SecByteLength", M.SecByteLength);
677 P.flush();
678 }
679 return Error::success();
680}
681
682Error LLVMOutputStyle::dumpPublicsStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000683 if (!opts::raw::DumpPublics)
Zachary Turnerd3117392016-06-03 19:28:33 +0000684 return Error::success();
685
686 DictScope D(P, "Publics Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000687 auto Publics = File.getPDBPublicsStream();
688 if (!Publics)
689 return Publics.takeError();
690
691 auto Dbi = File.getPDBDbiStream();
692 if (!Dbi)
693 return Dbi.takeError();
694
695 P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
696 P.printNumber("SymHash", Publics->getSymHash());
697 P.printNumber("AddrMap", Publics->getAddrMap());
698 P.printNumber("Number of buckets", Publics->getNumBuckets());
699 P.printList("Hash Buckets", Publics->getHashBuckets());
700 P.printList("Address Map", Publics->getAddressMap());
701 P.printList("Thunk Map", Publics->getThunkMap());
702 P.printList("Section Offsets", Publics->getSectionOffsets(),
Zachary Turnerd3117392016-06-03 19:28:33 +0000703 printSectionOffset);
704 ListScope L(P, "Symbols");
705 codeview::CVSymbolDumper SD(P, TD, nullptr, false);
706 bool HadError = false;
Zachary Turnera1657a92016-06-08 17:26:39 +0000707 for (auto S : Publics->getSymbols(&HadError)) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000708 DictScope DD(P, "");
709
710 SD.dump(S);
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000711 if (opts::raw::DumpSymRecordBytes)
Zachary Turnerd3117392016-06-03 19:28:33 +0000712 P.printBinaryBlock("Bytes", S.Data);
713 }
714 if (HadError)
715 return make_error<RawError>(
716 raw_error_code::corrupt_file,
717 "Public symbol stream contained corrupt record");
718
719 return Error::success();
720}
721
722Error LLVMOutputStyle::dumpSectionHeaders() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000723 if (!opts::raw::DumpSectionHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +0000724 return Error::success();
725
Zachary Turnera1657a92016-06-08 17:26:39 +0000726 auto Dbi = File.getPDBDbiStream();
727 if (!Dbi)
728 return Dbi.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000729
730 ListScope D(P, "Section Headers");
Zachary Turnera1657a92016-06-08 17:26:39 +0000731 for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000732 DictScope DD(P, "");
733
734 // If a name is 8 characters long, there is no NUL character at end.
735 StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
736 P.printString("Name", Name);
737 P.printNumber("Virtual Size", Section.VirtualSize);
738 P.printNumber("Virtual Address", Section.VirtualAddress);
739 P.printNumber("Size of Raw Data", Section.SizeOfRawData);
740 P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
741 P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
742 P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
743 P.printNumber("Number of Relocations", Section.NumberOfRelocations);
744 P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
Rui Ueyama2c5384a2016-06-06 21:34:55 +0000745 P.printFlags("Characteristics", Section.Characteristics,
746 getImageSectionCharacteristicNames());
Zachary Turnerd3117392016-06-03 19:28:33 +0000747 }
748 return Error::success();
749}
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000750
751Error LLVMOutputStyle::dumpFpoStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000752 if (!opts::raw::DumpFpo)
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000753 return Error::success();
754
Zachary Turnera1657a92016-06-08 17:26:39 +0000755 auto Dbi = File.getPDBDbiStream();
756 if (!Dbi)
757 return Dbi.takeError();
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000758
759 ListScope D(P, "New FPO");
Zachary Turnera1657a92016-06-08 17:26:39 +0000760 for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000761 DictScope DD(P, "");
762 P.printNumber("Offset", Fpo.Offset);
763 P.printNumber("Size", Fpo.Size);
764 P.printNumber("Number of locals", Fpo.NumLocals);
765 P.printNumber("Number of params", Fpo.NumParams);
766 P.printNumber("Size of Prolog", Fpo.getPrologSize());
767 P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
768 P.printBoolean("Has SEH", Fpo.hasSEH());
769 P.printBoolean("Use BP", Fpo.useBP());
770 P.printNumber("Frame Pointer", Fpo.getFP());
771 }
772 return Error::success();
773}
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000774
Zachary Turner7120a472016-06-06 20:37:05 +0000775void LLVMOutputStyle::flush() { P.flush(); }