blob: 69438b3fbf9805af77db5e43f17c61e68494bf0f [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
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +000038namespace {
39struct PageStats {
40 explicit PageStats(const BitVector &FreePages)
41 : Upm(FreePages), ActualUsedPages(FreePages.size()),
42 MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) {
43 const_cast<BitVector &>(Upm).flip();
44 // To calculate orphaned pages, we start with the set of pages that the
45 // MSF thinks are used. Each time we find one that actually *is* used,
46 // we unset it. Whichever bits remain set at the end are orphaned.
47 OrphanedPages = Upm;
48 }
49
50 // The inverse of the MSF File's copy of the Fpm. The basis for which we
51 // determine the allocation status of each page.
52 const BitVector Upm;
53
54 // Pages which are marked as used in the FPM and are used at least once.
55 BitVector ActualUsedPages;
56
57 // Pages which are marked as used in the FPM but are used more than once.
58 BitVector MultiUsePages;
59
60 // Pages which are marked as used in the FPM but are not used at all.
61 BitVector OrphanedPages;
62
63 // Pages which are marked free in the FPM but are used.
64 BitVector UseAfterFreePages;
65};
66}
67
68static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) {
69 if (Stats.Upm.test(UsedIndex)) {
70 if (Stats.ActualUsedPages.test(UsedIndex))
71 Stats.MultiUsePages.set(UsedIndex);
72 Stats.ActualUsedPages.set(UsedIndex);
73 Stats.OrphanedPages.reset(UsedIndex);
74 } else {
75 // The MSF doesn't think this page is used, but it is.
76 Stats.UseAfterFreePages.set(UsedIndex);
77 }
78}
79
Zachary Turnerd3117392016-06-03 19:28:33 +000080static void printSectionOffset(llvm::raw_ostream &OS,
81 const SectionOffset &Off) {
82 OS << Off.Off << ", " << Off.Isect;
83}
84
85LLVMOutputStyle::LLVMOutputStyle(PDBFile &File)
Zachary Turner5e3e4bb2016-08-05 21:45:34 +000086 : File(File), P(outs()), Dumper(&P, false) {}
Zachary Turnerd3117392016-06-03 19:28:33 +000087
Zachary Turnera30bd1a2016-06-30 17:42:48 +000088Error LLVMOutputStyle::dump() {
89 if (auto EC = dumpFileHeaders())
90 return EC;
91
92 if (auto EC = dumpStreamSummary())
93 return EC;
94
Rui Ueyama7a5cdc62016-07-29 21:38:00 +000095 if (auto EC = dumpFreePageMap())
96 return EC;
97
Zachary Turnera30bd1a2016-06-30 17:42:48 +000098 if (auto EC = dumpStreamBlocks())
99 return EC;
100
Zachary Turner72c5b642016-09-09 18:17:52 +0000101 if (auto EC = dumpBlockRanges())
102 return EC;
103
104 if (auto EC = dumpStreamBytes())
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000105 return EC;
106
107 if (auto EC = dumpInfoStream())
108 return EC;
109
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000110 if (auto EC = dumpTpiStream(StreamTPI))
111 return EC;
112
113 if (auto EC = dumpTpiStream(StreamIPI))
114 return EC;
115
116 if (auto EC = dumpDbiStream())
117 return EC;
118
119 if (auto EC = dumpSectionContribs())
120 return EC;
121
122 if (auto EC = dumpSectionMap())
123 return EC;
124
125 if (auto EC = dumpPublicsStream())
126 return EC;
127
128 if (auto EC = dumpSectionHeaders())
129 return EC;
130
131 if (auto EC = dumpFpoStream())
132 return EC;
133
134 flush();
135
136 return Error::success();
137}
138
Zachary Turnerd3117392016-06-03 19:28:33 +0000139Error LLVMOutputStyle::dumpFileHeaders() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000140 if (!opts::raw::DumpHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +0000141 return Error::success();
142
143 DictScope D(P, "FileHeaders");
144 P.printNumber("BlockSize", File.getBlockSize());
Zachary Turnerb927e022016-07-15 22:17:19 +0000145 P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
Zachary Turnerd3117392016-06-03 19:28:33 +0000146 P.printNumber("NumBlocks", File.getBlockCount());
147 P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
148 P.printNumber("Unknown1", File.getUnknown1());
149 P.printNumber("BlockMapAddr", File.getBlockMapIndex());
150 P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
Zachary Turnerd3117392016-06-03 19:28:33 +0000151
152 // The directory is not contiguous. Instead, the block map contains a
153 // contiguous list of block numbers whose contents, when concatenated in
154 // order, make up the directory.
155 P.printList("DirectoryBlocks", File.getDirectoryBlockArray());
156 P.printNumber("NumStreams", File.getNumStreams());
157 return Error::success();
158}
159
Zachary Turner36efbfa2016-09-09 19:00:49 +0000160void LLVMOutputStyle::discoverStreamPurposes() {
161 if (!StreamPurposes.empty())
162 return;
Zachary Turnerd3117392016-06-03 19:28:33 +0000163
Reid Kleckner11582c52016-06-17 20:38:01 +0000164 // It's OK if we fail to load some of these streams, we still attempt to print
165 // what we can.
Zachary Turnera1657a92016-06-08 17:26:39 +0000166 auto Dbi = File.getPDBDbiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000167 auto Tpi = File.getPDBTpiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000168 auto Ipi = File.getPDBIpiStream();
Zachary Turnera1657a92016-06-08 17:26:39 +0000169 auto Info = File.getPDBInfoStream();
Zachary Turnerd3117392016-06-03 19:28:33 +0000170
Zachary Turnerd3117392016-06-03 19:28:33 +0000171 uint32_t StreamCount = File.getNumStreams();
172 std::unordered_map<uint16_t, const ModuleInfoEx *> ModStreams;
173 std::unordered_map<uint16_t, std::string> NamedStreams;
174
Reid Kleckner11582c52016-06-17 20:38:01 +0000175 if (Dbi) {
176 for (auto &ModI : Dbi->modules()) {
177 uint16_t SN = ModI.Info.getModuleStreamIndex();
178 ModStreams[SN] = &ModI;
179 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000180 }
Reid Kleckner11582c52016-06-17 20:38:01 +0000181 if (Info) {
182 for (auto &NSE : Info->named_streams()) {
183 NamedStreams[NSE.second] = NSE.first();
184 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000185 }
186
Zachary Turner36efbfa2016-09-09 19:00:49 +0000187 StreamPurposes.resize(StreamCount);
Zachary Turnerd3117392016-06-03 19:28:33 +0000188 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000189 std::string Value;
190 if (StreamIdx == OldMSFDirectory)
191 Value = "Old MSF Directory";
192 else if (StreamIdx == StreamPDB)
193 Value = "PDB Stream";
194 else if (StreamIdx == StreamDBI)
195 Value = "DBI Stream";
196 else if (StreamIdx == StreamTPI)
197 Value = "TPI Stream";
198 else if (StreamIdx == StreamIPI)
199 Value = "IPI Stream";
Reid Kleckner11582c52016-06-17 20:38:01 +0000200 else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000201 Value = "Global Symbol Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000202 else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000203 Value = "Public Symbol Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000204 else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000205 Value = "Public Symbol Records";
Reid Kleckner11582c52016-06-17 20:38:01 +0000206 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000207 Value = "TPI Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000208 else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000209 Value = "TPI Aux Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000210 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000211 Value = "IPI Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000212 else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex())
Zachary Turnerd3117392016-06-03 19:28:33 +0000213 Value = "IPI Aux Hash";
Reid Kleckner11582c52016-06-17 20:38:01 +0000214 else if (Dbi &&
215 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception))
Zachary Turnerd3117392016-06-03 19:28:33 +0000216 Value = "Exception Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000217 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup))
Zachary Turnerd3117392016-06-03 19:28:33 +0000218 Value = "Fixup Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000219 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO))
Zachary Turnerd3117392016-06-03 19:28:33 +0000220 Value = "FPO Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000221 else if (Dbi &&
222 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO))
Zachary Turnerd3117392016-06-03 19:28:33 +0000223 Value = "New FPO Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000224 else if (Dbi &&
225 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc))
Zachary Turnerd3117392016-06-03 19:28:33 +0000226 Value = "Omap From Source Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000227 else if (Dbi &&
228 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc))
Zachary Turnerd3117392016-06-03 19:28:33 +0000229 Value = "Omap To Source Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000230 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata))
Zachary Turnerd3117392016-06-03 19:28:33 +0000231 Value = "Pdata";
Reid Kleckner11582c52016-06-17 20:38:01 +0000232 else if (Dbi &&
233 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr))
Zachary Turnerd3117392016-06-03 19:28:33 +0000234 Value = "Section Header Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000235 else if (Dbi &&
236 StreamIdx ==
237 Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig))
Zachary Turnerd3117392016-06-03 19:28:33 +0000238 Value = "Section Header Original Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000239 else if (Dbi &&
240 StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap))
Zachary Turnerd3117392016-06-03 19:28:33 +0000241 Value = "Token Rid Data";
Reid Kleckner11582c52016-06-17 20:38:01 +0000242 else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata))
Zachary Turnerd3117392016-06-03 19:28:33 +0000243 Value = "Xdata";
244 else {
245 auto ModIter = ModStreams.find(StreamIdx);
246 auto NSIter = NamedStreams.find(StreamIdx);
247 if (ModIter != ModStreams.end()) {
248 Value = "Module \"";
249 Value += ModIter->second->Info.getModuleName().str();
250 Value += "\"";
251 } else if (NSIter != NamedStreams.end()) {
252 Value = "Named Stream \"";
253 Value += NSIter->second;
254 Value += "\"";
255 } else {
256 Value = "???";
257 }
258 }
Zachary Turner36efbfa2016-09-09 19:00:49 +0000259 StreamPurposes[StreamIdx] = Value;
Zachary Turnerd3117392016-06-03 19:28:33 +0000260 }
Reid Kleckner11582c52016-06-17 20:38:01 +0000261
262 // Consume errors from missing streams.
263 if (!Dbi)
264 consumeError(Dbi.takeError());
265 if (!Tpi)
266 consumeError(Tpi.takeError());
267 if (!Ipi)
268 consumeError(Ipi.takeError());
269 if (!Info)
270 consumeError(Info.takeError());
Zachary Turner36efbfa2016-09-09 19:00:49 +0000271}
272
273Error LLVMOutputStyle::dumpStreamSummary() {
274 if (!opts::raw::DumpStreamSummary)
275 return Error::success();
276
277 discoverStreamPurposes();
278
279 uint32_t StreamCount = File.getNumStreams();
280
281 ListScope L(P, "Streams");
282 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
283 std::string Label("Stream ");
284 Label += to_string(StreamIdx);
285
286 std::string Value = "[" + StreamPurposes[StreamIdx] + "] (";
287 Value += to_string(File.getStreamByteSize(StreamIdx));
288 Value += " bytes)";
289
290 P.printString(Label, Value);
291 }
Reid Kleckner11582c52016-06-17 20:38:01 +0000292
Zachary Turnerd3117392016-06-03 19:28:33 +0000293 P.flush();
294 return Error::success();
295}
296
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000297Error LLVMOutputStyle::dumpFreePageMap() {
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000298 if (!opts::raw::DumpPageStats)
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000299 return Error::success();
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000300
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000301 // Start with used pages instead of free pages because
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000302 // the number of free pages is far larger than used pages.
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000303 BitVector FPM = File.getMsfLayout().FreePageMap;
304
305 PageStats PS(FPM);
306
307 recordKnownUsedPage(PS, 0); // MSF Super Block
308
Zachary Turner8cf51c32016-08-03 16:53:21 +0000309 uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout());
310 uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout());
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000311 for (uint32_t I = 0; I < NumSections; ++I) {
312 uint32_t Fpm0 = 1 + BlocksPerSection * I;
313 // 2 Fpm blocks spaced at `getBlockSize()` block intervals
314 recordKnownUsedPage(PS, Fpm0);
315 recordKnownUsedPage(PS, Fpm0 + 1);
316 }
317
318 recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table
319
Rui Ueyama22e67382016-08-02 23:22:46 +0000320 for (auto DB : File.getDirectoryBlockArray())
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000321 recordKnownUsedPage(PS, DB);
Rui Ueyama22e67382016-08-02 23:22:46 +0000322
323 // Record pages used by streams. Note that pages for stream 0
324 // are considered being unused because that's what MSVC tools do.
325 // Stream 0 doesn't contain actual data, so it makes some sense,
326 // though it's a bit confusing to us.
327 for (auto &SE : File.getStreamMap().drop_front(1))
328 for (auto &S : SE)
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000329 recordKnownUsedPage(PS, S);
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000330
331 dumpBitVector("Msf Free Pages", FPM);
332 dumpBitVector("Orphaned Pages", PS.OrphanedPages);
333 dumpBitVector("Multiply Used Pages", PS.MultiUsePages);
334 dumpBitVector("Use After Free Pages", PS.UseAfterFreePages);
Rui Ueyama7a5cdc62016-07-29 21:38:00 +0000335 return Error::success();
336}
337
Zachary Turnerd3c7b8e2016-08-01 21:19:45 +0000338void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) {
339 std::vector<uint32_t> Vec;
340 for (uint32_t I = 0, E = V.size(); I != E; ++I)
341 if (V[I])
342 Vec.push_back(I);
343 P.printList(Name, Vec);
344}
345
Zachary Turnerd3117392016-06-03 19:28:33 +0000346Error LLVMOutputStyle::dumpStreamBlocks() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000347 if (!opts::raw::DumpStreamBlocks)
Zachary Turnerd3117392016-06-03 19:28:33 +0000348 return Error::success();
349
350 ListScope L(P, "StreamBlocks");
351 uint32_t StreamCount = File.getNumStreams();
352 for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
353 std::string Name("Stream ");
354 Name += to_string(StreamIdx);
355 auto StreamBlocks = File.getStreamBlockList(StreamIdx);
356 P.printList(Name, StreamBlocks);
357 }
358 return Error::success();
359}
360
Zachary Turner72c5b642016-09-09 18:17:52 +0000361Error LLVMOutputStyle::dumpBlockRanges() {
362 if (!opts::raw::DumpBlockRange.hasValue())
363 return Error::success();
364 auto &R = *opts::raw::DumpBlockRange;
365 uint32_t Max = R.Max.getValueOr(R.Min);
366
367 if (Max < R.Min)
368 return make_error<StringError>(
369 "Invalid block range specified. Max < Min",
370 std::make_error_code(std::errc::bad_address));
371 if (Max >= File.getBlockCount())
372 return make_error<StringError>(
373 "Invalid block range specified. Requested block out of bounds",
374 std::make_error_code(std::errc::bad_address));
375
376 DictScope D(P, "Block Data");
377 for (uint32_t I = R.Min; I <= Max; ++I) {
378 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
379 if (!ExpectedData)
380 return ExpectedData.takeError();
381 std::string Label;
382 llvm::raw_string_ostream S(Label);
383 S << "Block " << I;
384 S.flush();
385 P.printBinaryBlock(Label, *ExpectedData);
386 }
387
388 return Error::success();
389}
390
391Error LLVMOutputStyle::dumpStreamBytes() {
392 if (opts::raw::DumpStreamData.empty())
Zachary Turnerd3117392016-06-03 19:28:33 +0000393 return Error::success();
394
Zachary Turner36efbfa2016-09-09 19:00:49 +0000395 discoverStreamPurposes();
396
Zachary Turner72c5b642016-09-09 18:17:52 +0000397 DictScope D(P, "Stream Data");
398 for (uint32_t SI : opts::raw::DumpStreamData) {
399 if (SI >= File.getNumStreams())
400 return make_error<RawError>(raw_error_code::no_stream);
Zachary Turnerd2b2bfe2016-06-08 00:25:08 +0000401
Zachary Turner72c5b642016-09-09 18:17:52 +0000402 auto S = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
403 File.getMsfBuffer(), SI);
404 if (!S)
405 continue;
Zachary Turner36efbfa2016-09-09 19:00:49 +0000406 DictScope DD(P, "Stream");
407
408 P.printNumber("Index", SI);
409 P.printString("Type", StreamPurposes[SI]);
410 P.printNumber("Size", S->getLength());
411 auto Blocks = File.getMsfLayout().StreamMap[SI];
412 P.printList("Blocks", Blocks);
413
Zachary Turner72c5b642016-09-09 18:17:52 +0000414 StreamReader R(*S);
415 ArrayRef<uint8_t> StreamData;
416 if (auto EC = R.readBytes(StreamData, S->getLength()))
Zachary Turnerd3117392016-06-03 19:28:33 +0000417 return EC;
Zachary Turner36efbfa2016-09-09 19:00:49 +0000418 P.printBinaryBlock("Data", StreamData);
Zachary Turnerd3117392016-06-03 19:28:33 +0000419 }
420 return Error::success();
421}
422
423Error LLVMOutputStyle::dumpInfoStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000424 if (!opts::raw::DumpHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +0000425 return Error::success();
Zachary Turnera1657a92016-06-08 17:26:39 +0000426 auto IS = File.getPDBInfoStream();
427 if (!IS)
428 return IS.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000429
430 DictScope D(P, "PDB Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000431 P.printNumber("Version", IS->getVersion());
432 P.printHex("Signature", IS->getSignature());
433 P.printNumber("Age", IS->getAge());
434 P.printObject("Guid", IS->getGuid());
Zachary Turnerd3117392016-06-03 19:28:33 +0000435 return Error::success();
436}
437
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000438static void printTypeIndexOffset(raw_ostream &OS,
439 const TypeIndexOffset &TIOff) {
440 OS << "{" << TIOff.Type.getIndex() << ", " << TIOff.Offset << "}";
441}
442
443static void dumpTpiHash(ScopedPrinter &P, TpiStream &Tpi) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000444 if (!opts::raw::DumpTpiHash)
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000445 return;
446 DictScope DD(P, "Hash");
Rui Ueyamaf14a74c2016-06-07 23:53:43 +0000447 P.printNumber("Number of Hash Buckets", Tpi.NumHashBuckets());
Rui Ueyamad8339172016-06-07 23:44:27 +0000448 P.printNumber("Hash Key Size", Tpi.getHashKeySize());
Rui Ueyamafd97bf12016-06-03 20:48:51 +0000449 P.printList("Values", Tpi.getHashValues());
450 P.printList("Type Index Offsets", Tpi.getTypeIndexOffsets(),
451 printTypeIndexOffset);
452 P.printList("Hash Adjustments", Tpi.getHashAdjustments(),
453 printTypeIndexOffset);
454}
455
Zachary Turnerd3117392016-06-03 19:28:33 +0000456Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
457 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
458
459 bool DumpRecordBytes = false;
460 bool DumpRecords = false;
461 StringRef Label;
462 StringRef VerLabel;
463 if (StreamIdx == StreamTPI) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000464 DumpRecordBytes = opts::raw::DumpTpiRecordBytes;
465 DumpRecords = opts::raw::DumpTpiRecords;
Zachary Turnerd3117392016-06-03 19:28:33 +0000466 Label = "Type Info Stream (TPI)";
467 VerLabel = "TPI Version";
468 } else if (StreamIdx == StreamIPI) {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000469 DumpRecordBytes = opts::raw::DumpIpiRecordBytes;
470 DumpRecords = opts::raw::DumpIpiRecords;
Zachary Turnerd3117392016-06-03 19:28:33 +0000471 Label = "Type Info Stream (IPI)";
472 VerLabel = "IPI Version";
473 }
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000474 if (!DumpRecordBytes && !DumpRecords && !opts::raw::DumpModuleSyms)
Zachary Turnerd3117392016-06-03 19:28:33 +0000475 return Error::success();
476
Zachary Turnera1657a92016-06-08 17:26:39 +0000477 auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
478 : File.getPDBIpiStream();
479 if (!Tpi)
480 return Tpi.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000481
482 if (DumpRecords || DumpRecordBytes) {
483 DictScope D(P, Label);
484
Zachary Turnera1657a92016-06-08 17:26:39 +0000485 P.printNumber(VerLabel, Tpi->getTpiVersion());
486 P.printNumber("Record count", Tpi->NumTypeRecords());
Zachary Turnerd3117392016-06-03 19:28:33 +0000487
488 ListScope L(P, "Records");
489
490 bool HadError = false;
Zachary Turnera1657a92016-06-08 17:26:39 +0000491 for (auto &Type : Tpi->types(&HadError)) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000492 DictScope DD(P, "");
493
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000494 if (DumpRecords) {
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000495 if (auto EC = Dumper.dump(Type))
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000496 return EC;
497 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000498
499 if (DumpRecordBytes)
Zachary Turnerc67b00c2016-09-14 23:00:16 +0000500 P.printBinaryBlock("Bytes", Type.content());
Zachary Turnerd3117392016-06-03 19:28:33 +0000501 }
Zachary Turnera1657a92016-06-08 17:26:39 +0000502 dumpTpiHash(P, *Tpi);
Zachary Turnerd3117392016-06-03 19:28:33 +0000503 if (HadError)
504 return make_error<RawError>(raw_error_code::corrupt_file,
505 "TPI stream contained corrupt record");
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000506 } else if (opts::raw::DumpModuleSyms) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000507 // Even if the user doesn't want to dump type records, we still need to
508 // iterate them in order to build the list of types so that we can print
509 // them when dumping module symbols. So when they want to dump symbols
510 // but not types, use a null output stream.
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000511 ScopedPrinter *OldP = Dumper.getPrinter();
512 Dumper.setPrinter(nullptr);
Zachary Turnerd3117392016-06-03 19:28:33 +0000513
514 bool HadError = false;
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000515 for (auto &Type : Tpi->types(&HadError)) {
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000516 if (auto EC = Dumper.dump(Type))
Zachary Turner01ee3dae2016-06-16 18:22:27 +0000517 return EC;
518 }
Zachary Turnerd3117392016-06-03 19:28:33 +0000519
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000520 Dumper.setPrinter(OldP);
Zachary Turnera1657a92016-06-08 17:26:39 +0000521 dumpTpiHash(P, *Tpi);
Zachary Turnerd3117392016-06-03 19:28:33 +0000522 if (HadError)
523 return make_error<RawError>(raw_error_code::corrupt_file,
524 "TPI stream contained corrupt record");
525 }
526 P.flush();
527 return Error::success();
528}
529
530Error LLVMOutputStyle::dumpDbiStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000531 bool DumpModules = opts::raw::DumpModules || opts::raw::DumpModuleSyms ||
532 opts::raw::DumpModuleFiles || opts::raw::DumpLineInfo;
533 if (!opts::raw::DumpHeaders && !DumpModules)
Zachary Turnerd3117392016-06-03 19:28:33 +0000534 return Error::success();
535
Zachary Turnera1657a92016-06-08 17:26:39 +0000536 auto DS = File.getPDBDbiStream();
537 if (!DS)
538 return DS.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000539
540 DictScope D(P, "DBI Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000541 P.printNumber("Dbi Version", DS->getDbiVersion());
542 P.printNumber("Age", DS->getAge());
543 P.printBoolean("Incremental Linking", DS->isIncrementallyLinked());
544 P.printBoolean("Has CTypes", DS->hasCTypes());
545 P.printBoolean("Is Stripped", DS->isStripped());
546 P.printObject("Machine Type", DS->getMachineType());
547 P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex());
548 P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex());
549 P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex());
Zachary Turnerd3117392016-06-03 19:28:33 +0000550
Zachary Turnera1657a92016-06-08 17:26:39 +0000551 uint16_t Major = DS->getBuildMajorVersion();
552 uint16_t Minor = DS->getBuildMinorVersion();
Zachary Turnerd3117392016-06-03 19:28:33 +0000553 P.printVersion("Toolchain Version", Major, Minor);
554
555 std::string DllName;
556 raw_string_ostream DllStream(DllName);
557 DllStream << "mspdb" << Major << Minor << ".dll version";
558 DllStream.flush();
Zachary Turnera1657a92016-06-08 17:26:39 +0000559 P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion());
Zachary Turnerd3117392016-06-03 19:28:33 +0000560
561 if (DumpModules) {
562 ListScope L(P, "Modules");
Zachary Turnera1657a92016-06-08 17:26:39 +0000563 for (auto &Modi : DS->modules()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000564 DictScope DD(P);
565 P.printString("Name", Modi.Info.getModuleName().str());
566 P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex());
567 P.printString("Object File Name", Modi.Info.getObjFileName().str());
568 P.printNumber("Num Files", Modi.Info.getNumberOfFiles());
569 P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex());
570 P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex());
571 P.printNumber("Line Info Byte Size", Modi.Info.getLineInfoByteSize());
572 P.printNumber("C13 Line Info Byte Size",
573 Modi.Info.getC13LineInfoByteSize());
574 P.printNumber("Symbol Byte Size", Modi.Info.getSymbolDebugInfoByteSize());
575 P.printNumber("Type Server Index", Modi.Info.getTypeServerIndex());
576 P.printBoolean("Has EC Info", Modi.Info.hasECInfo());
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000577 if (opts::raw::DumpModuleFiles) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000578 std::string FileListName =
579 to_string(Modi.SourceFiles.size()) + " Contributing Source Files";
580 ListScope LL(P, FileListName);
581 for (auto File : Modi.SourceFiles)
582 P.printString(File.str());
583 }
584 bool HasModuleDI =
585 (Modi.Info.getModuleStreamIndex() < File.getNumStreams());
586 bool ShouldDumpSymbols =
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000587 (opts::raw::DumpModuleSyms || opts::raw::DumpSymRecordBytes);
588 if (HasModuleDI && (ShouldDumpSymbols || opts::raw::DumpLineInfo)) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000589 auto ModStreamData = MappedBlockStream::createIndexedStream(
Zachary Turnerd66889c2016-07-28 19:12:28 +0000590 File.getMsfLayout(), File.getMsfBuffer(),
591 Modi.Info.getModuleStreamIndex());
592
593 ModStream ModS(Modi.Info, std::move(ModStreamData));
Zachary Turnerd3117392016-06-03 19:28:33 +0000594 if (auto EC = ModS.reload())
595 return EC;
596
597 if (ShouldDumpSymbols) {
598 ListScope SS(P, "Symbols");
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000599 codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
Zachary Turnerd3117392016-06-03 19:28:33 +0000600 bool HadError = false;
601 for (const auto &S : ModS.symbols(&HadError)) {
602 DictScope DD(P, "");
603
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000604 if (opts::raw::DumpModuleSyms)
Zachary Turnerd3117392016-06-03 19:28:33 +0000605 SD.dump(S);
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000606 if (opts::raw::DumpSymRecordBytes)
Zachary Turnerc67b00c2016-09-14 23:00:16 +0000607 P.printBinaryBlock("Bytes", S.content());
Zachary Turnerd3117392016-06-03 19:28:33 +0000608 }
609 if (HadError)
610 return make_error<RawError>(
611 raw_error_code::corrupt_file,
612 "DBI stream contained corrupt symbol record");
613 }
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000614 if (opts::raw::DumpLineInfo) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000615 ListScope SS(P, "LineInfo");
616 bool HadError = false;
617 // Define a locally scoped visitor to print the different
618 // substream types types.
619 class RecordVisitor : public codeview::IModuleSubstreamVisitor {
620 public:
621 RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {}
622 Error visitUnknown(ModuleSubstreamKind Kind,
Zachary Turnerd66889c2016-07-28 19:12:28 +0000623 ReadableStreamRef Stream) override {
Zachary Turnerd3117392016-06-03 19:28:33 +0000624 DictScope DD(P, "Unknown");
625 ArrayRef<uint8_t> Data;
626 StreamReader R(Stream);
627 if (auto EC = R.readBytes(Data, R.bytesRemaining())) {
628 return make_error<RawError>(
629 raw_error_code::corrupt_file,
630 "DBI stream contained corrupt line info record");
631 }
632 P.printBinaryBlock("Data", Data);
633 return Error::success();
634 }
635 Error
Zachary Turnerd66889c2016-07-28 19:12:28 +0000636 visitFileChecksums(ReadableStreamRef Data,
Zachary Turnerd3117392016-06-03 19:28:33 +0000637 const FileChecksumArray &Checksums) override {
638 DictScope DD(P, "FileChecksums");
639 for (const auto &C : Checksums) {
640 DictScope DDD(P, "Checksum");
641 if (auto Result = getFileNameForOffset(C.FileNameOffset))
642 P.printString("FileName", Result.get());
643 else
644 return Result.takeError();
645 P.flush();
646 P.printEnum("Kind", uint8_t(C.Kind), getFileChecksumNames());
647 P.printBinaryBlock("Checksum", C.Checksum);
648 }
649 return Error::success();
650 }
651
Zachary Turnerd66889c2016-07-28 19:12:28 +0000652 Error visitLines(ReadableStreamRef Data,
653 const LineSubstreamHeader *Header,
Zachary Turnerd3117392016-06-03 19:28:33 +0000654 const LineInfoArray &Lines) override {
655 DictScope DD(P, "Lines");
656 for (const auto &L : Lines) {
657 if (auto Result = getFileNameForOffset2(L.NameIndex))
658 P.printString("FileName", Result.get());
659 else
660 return Result.takeError();
661 P.flush();
662 for (const auto &N : L.LineNumbers) {
663 DictScope DDD(P, "Line");
664 LineInfo LI(N.Flags);
665 P.printNumber("Offset", N.Offset);
666 if (LI.isAlwaysStepInto())
667 P.printString("StepInto", StringRef("Always"));
668 else if (LI.isNeverStepInto())
669 P.printString("StepInto", StringRef("Never"));
670 else
671 P.printNumber("LineNumberStart", LI.getStartLine());
672 P.printNumber("EndDelta", LI.getLineDelta());
673 P.printBoolean("IsStatement", LI.isStatement());
674 }
675 for (const auto &C : L.Columns) {
676 DictScope DDD(P, "Column");
677 P.printNumber("Start", C.StartColumn);
678 P.printNumber("End", C.EndColumn);
679 }
680 }
681 return Error::success();
682 }
683
684 private:
685 Expected<StringRef> getFileNameForOffset(uint32_t Offset) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000686 auto ST = F.getStringTable();
687 if (!ST)
688 return ST.takeError();
689
690 return ST->getStringForID(Offset);
Zachary Turnerd3117392016-06-03 19:28:33 +0000691 }
692 Expected<StringRef> getFileNameForOffset2(uint32_t Offset) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000693 auto DS = F.getPDBDbiStream();
694 if (!DS)
695 return DS.takeError();
696 return DS->getFileNameForIndex(Offset);
Zachary Turnerd3117392016-06-03 19:28:33 +0000697 }
698 ScopedPrinter &P;
699 PDBFile &F;
700 };
701
702 RecordVisitor V(P, File);
703 for (const auto &L : ModS.lines(&HadError)) {
704 if (auto EC = codeview::visitModuleSubstream(L, V))
705 return EC;
706 }
707 }
708 }
709 }
710 }
711 return Error::success();
712}
713
714Error LLVMOutputStyle::dumpSectionContribs() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000715 if (!opts::raw::DumpSectionContribs)
Zachary Turnerd3117392016-06-03 19:28:33 +0000716 return Error::success();
717
Zachary Turnera1657a92016-06-08 17:26:39 +0000718 auto Dbi = File.getPDBDbiStream();
719 if (!Dbi)
720 return Dbi.takeError();
721
Zachary Turnerd3117392016-06-03 19:28:33 +0000722 ListScope L(P, "Section Contributions");
723 class Visitor : public ISectionContribVisitor {
724 public:
725 Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {}
726 void visit(const SectionContrib &SC) override {
727 DictScope D(P, "Contribution");
728 P.printNumber("ISect", SC.ISect);
729 P.printNumber("Off", SC.Off);
730 P.printNumber("Size", SC.Size);
731 P.printFlags("Characteristics", SC.Characteristics,
732 codeview::getImageSectionCharacteristicNames(),
733 COFF::SectionCharacteristics(0x00F00000));
734 {
735 DictScope DD(P, "Module");
736 P.printNumber("Index", SC.Imod);
737 auto M = DS.modules();
738 if (M.size() > SC.Imod) {
739 P.printString("Name", M[SC.Imod].Info.getModuleName());
740 }
741 }
742 P.printNumber("Data CRC", SC.DataCrc);
743 P.printNumber("Reloc CRC", SC.RelocCrc);
744 P.flush();
745 }
746 void visit(const SectionContrib2 &SC) override {
747 visit(SC.Base);
748 P.printNumber("ISect Coff", SC.ISectCoff);
749 P.flush();
750 }
751
752 private:
753 ScopedPrinter &P;
754 DbiStream &DS;
755 };
Zachary Turnera1657a92016-06-08 17:26:39 +0000756 Visitor V(P, *Dbi);
757 Dbi->visitSectionContributions(V);
Zachary Turnerd3117392016-06-03 19:28:33 +0000758 return Error::success();
759}
760
761Error LLVMOutputStyle::dumpSectionMap() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000762 if (!opts::raw::DumpSectionMap)
Zachary Turnerd3117392016-06-03 19:28:33 +0000763 return Error::success();
764
Zachary Turnera1657a92016-06-08 17:26:39 +0000765 auto Dbi = File.getPDBDbiStream();
766 if (!Dbi)
767 return Dbi.takeError();
768
Zachary Turnerd3117392016-06-03 19:28:33 +0000769 ListScope L(P, "Section Map");
Zachary Turnera1657a92016-06-08 17:26:39 +0000770 for (auto &M : Dbi->getSectionMap()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000771 DictScope D(P, "Entry");
772 P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames());
773 P.printNumber("Flags", M.Flags);
774 P.printNumber("Ovl", M.Ovl);
775 P.printNumber("Group", M.Group);
776 P.printNumber("Frame", M.Frame);
777 P.printNumber("SecName", M.SecName);
778 P.printNumber("ClassName", M.ClassName);
779 P.printNumber("Offset", M.Offset);
780 P.printNumber("SecByteLength", M.SecByteLength);
781 P.flush();
782 }
783 return Error::success();
784}
785
786Error LLVMOutputStyle::dumpPublicsStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000787 if (!opts::raw::DumpPublics)
Zachary Turnerd3117392016-06-03 19:28:33 +0000788 return Error::success();
789
790 DictScope D(P, "Publics Stream");
Zachary Turnera1657a92016-06-08 17:26:39 +0000791 auto Publics = File.getPDBPublicsStream();
792 if (!Publics)
793 return Publics.takeError();
794
795 auto Dbi = File.getPDBDbiStream();
796 if (!Dbi)
797 return Dbi.takeError();
798
799 P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex());
800 P.printNumber("SymHash", Publics->getSymHash());
801 P.printNumber("AddrMap", Publics->getAddrMap());
802 P.printNumber("Number of buckets", Publics->getNumBuckets());
803 P.printList("Hash Buckets", Publics->getHashBuckets());
804 P.printList("Address Map", Publics->getAddressMap());
805 P.printList("Thunk Map", Publics->getThunkMap());
806 P.printList("Section Offsets", Publics->getSectionOffsets(),
Zachary Turnerd3117392016-06-03 19:28:33 +0000807 printSectionOffset);
808 ListScope L(P, "Symbols");
Zachary Turner5e3e4bb2016-08-05 21:45:34 +0000809 codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
Zachary Turnerd3117392016-06-03 19:28:33 +0000810 bool HadError = false;
Zachary Turnera1657a92016-06-08 17:26:39 +0000811 for (auto S : Publics->getSymbols(&HadError)) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000812 DictScope DD(P, "");
813
814 SD.dump(S);
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000815 if (opts::raw::DumpSymRecordBytes)
Zachary Turnerc67b00c2016-09-14 23:00:16 +0000816 P.printBinaryBlock("Bytes", S.content());
Zachary Turnerd3117392016-06-03 19:28:33 +0000817 }
818 if (HadError)
819 return make_error<RawError>(
820 raw_error_code::corrupt_file,
821 "Public symbol stream contained corrupt record");
822
823 return Error::success();
824}
825
826Error LLVMOutputStyle::dumpSectionHeaders() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000827 if (!opts::raw::DumpSectionHeaders)
Zachary Turnerd3117392016-06-03 19:28:33 +0000828 return Error::success();
829
Zachary Turnera1657a92016-06-08 17:26:39 +0000830 auto Dbi = File.getPDBDbiStream();
831 if (!Dbi)
832 return Dbi.takeError();
Zachary Turnerd3117392016-06-03 19:28:33 +0000833
834 ListScope D(P, "Section Headers");
Zachary Turnera1657a92016-06-08 17:26:39 +0000835 for (const object::coff_section &Section : Dbi->getSectionHeaders()) {
Zachary Turnerd3117392016-06-03 19:28:33 +0000836 DictScope DD(P, "");
837
838 // If a name is 8 characters long, there is no NUL character at end.
839 StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name)));
840 P.printString("Name", Name);
841 P.printNumber("Virtual Size", Section.VirtualSize);
842 P.printNumber("Virtual Address", Section.VirtualAddress);
843 P.printNumber("Size of Raw Data", Section.SizeOfRawData);
844 P.printNumber("File Pointer to Raw Data", Section.PointerToRawData);
845 P.printNumber("File Pointer to Relocations", Section.PointerToRelocations);
846 P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers);
847 P.printNumber("Number of Relocations", Section.NumberOfRelocations);
848 P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers);
Rui Ueyama2c5384a2016-06-06 21:34:55 +0000849 P.printFlags("Characteristics", Section.Characteristics,
850 getImageSectionCharacteristicNames());
Zachary Turnerd3117392016-06-03 19:28:33 +0000851 }
852 return Error::success();
853}
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000854
855Error LLVMOutputStyle::dumpFpoStream() {
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000856 if (!opts::raw::DumpFpo)
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000857 return Error::success();
858
Zachary Turnera1657a92016-06-08 17:26:39 +0000859 auto Dbi = File.getPDBDbiStream();
860 if (!Dbi)
861 return Dbi.takeError();
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000862
863 ListScope D(P, "New FPO");
Zachary Turnera1657a92016-06-08 17:26:39 +0000864 for (const object::FpoData &Fpo : Dbi->getFpoRecords()) {
Rui Ueyamaef2b4882016-06-06 18:39:21 +0000865 DictScope DD(P, "");
866 P.printNumber("Offset", Fpo.Offset);
867 P.printNumber("Size", Fpo.Size);
868 P.printNumber("Number of locals", Fpo.NumLocals);
869 P.printNumber("Number of params", Fpo.NumParams);
870 P.printNumber("Size of Prolog", Fpo.getPrologSize());
871 P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs());
872 P.printBoolean("Has SEH", Fpo.hasSEH());
873 P.printBoolean("Use BP", Fpo.useBP());
874 P.printNumber("Frame Pointer", Fpo.getFP());
875 }
876 return Error::success();
877}
Zachary Turnera30bd1a2016-06-30 17:42:48 +0000878
Zachary Turner7120a472016-06-06 20:37:05 +0000879void LLVMOutputStyle::flush() { P.flush(); }