blob: 5b02d68bc7a7cce75955d8b9f1e648e9a7e692f2 [file] [log] [blame]
Zachary Turner7df69952017-06-22 20:57:39 +00001//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
Zachary Turner63055452017-06-15 22:24:24 +00002//
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
Zachary Turner7df69952017-06-22 20:57:39 +000010#include "DumpOutputStyle.h"
Zachary Turner63055452017-06-15 22:24:24 +000011
Zachary Turner63055452017-06-15 22:24:24 +000012#include "FormatUtil.h"
Zachary Turnerabb17cc2017-09-01 20:06:56 +000013#include "InputFile.h"
Zachary Turner63055452017-06-15 22:24:24 +000014#include "MinimalSymbolDumper.h"
15#include "MinimalTypeDumper.h"
16#include "StreamUtil.h"
17#include "llvm-pdbutil.h"
18
Zachary Turnerf2872b92017-06-15 23:59:56 +000019#include "llvm/ADT/STLExtras.h"
Zachary Turner63055452017-06-15 22:24:24 +000020#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
21#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
22#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
23#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
24#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
25#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
26#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
27#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
28#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
29#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
30#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
31#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
32#include "llvm/DebugInfo/CodeView/EnumTables.h"
33#include "llvm/DebugInfo/CodeView/Formatters.h"
34#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
35#include "llvm/DebugInfo/CodeView/Line.h"
36#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
37#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
38#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
39#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
40#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
Zachary Turner02a26772017-06-30 18:15:47 +000041#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
Zachary Turner63055452017-06-15 22:24:24 +000042#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
43#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
44#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
45#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
46#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
47#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
48#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
49#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
50#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
51#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
52#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
Reid Kleckner14d90fd2017-07-26 00:40:36 +000053#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
Zachary Turner63055452017-06-15 22:24:24 +000054#include "llvm/DebugInfo/PDB/Native/RawError.h"
55#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
56#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
57#include "llvm/DebugInfo/PDB/PDBExtras.h"
58#include "llvm/Object/COFF.h"
59#include "llvm/Support/BinaryStreamReader.h"
60#include "llvm/Support/FormatAdapters.h"
61#include "llvm/Support/FormatVariadic.h"
62
Zachary Turner99c69822017-08-31 20:43:22 +000063#include <cctype>
Zachary Turner63055452017-06-15 22:24:24 +000064#include <unordered_map>
65
66using namespace llvm;
67using namespace llvm::codeview;
68using namespace llvm::msf;
69using namespace llvm::pdb;
70
Zachary Turnerabb17cc2017-09-01 20:06:56 +000071DumpOutputStyle::DumpOutputStyle(InputFile &File)
Zachary Turner63055452017-06-15 22:24:24 +000072 : File(File), P(2, false, outs()) {}
73
Zachary Turnerabb17cc2017-09-01 20:06:56 +000074PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
75object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
76
Zachary Turner7df69952017-06-22 20:57:39 +000077Error DumpOutputStyle::dump() {
78 if (opts::dump::DumpSummary) {
Zachary Turner63055452017-06-15 22:24:24 +000079 if (auto EC = dumpFileSummary())
80 return EC;
81 P.NewLine();
82 }
83
Zachary Turner7df69952017-06-22 20:57:39 +000084 if (opts::dump::DumpStreams) {
Zachary Turner63055452017-06-15 22:24:24 +000085 if (auto EC = dumpStreamSummary())
86 return EC;
87 P.NewLine();
88 }
89
Zachary Turnerabb17cc2017-09-01 20:06:56 +000090 if (opts::dump::DumpSymbolStats) {
Zachary Turner99c69822017-08-31 20:43:22 +000091 if (auto EC = dumpSymbolStats())
92 return EC;
93 P.NewLine();
94 }
95
Zachary Turnerabb17cc2017-09-01 20:06:56 +000096 if (opts::dump::DumpUdtStats) {
Zachary Turner99c69822017-08-31 20:43:22 +000097 if (auto EC = dumpUdtStats())
Zachary Turnerd1de2f42017-08-21 14:53:25 +000098 return EC;
99 P.NewLine();
100 }
101
Zachary Turner7df69952017-06-22 20:57:39 +0000102 if (opts::dump::DumpStringTable) {
Zachary Turner63055452017-06-15 22:24:24 +0000103 if (auto EC = dumpStringTable())
104 return EC;
105 P.NewLine();
106 }
107
Zachary Turner7df69952017-06-22 20:57:39 +0000108 if (opts::dump::DumpModules) {
Zachary Turner63055452017-06-15 22:24:24 +0000109 if (auto EC = dumpModules())
110 return EC;
111 }
112
Zachary Turner7df69952017-06-22 20:57:39 +0000113 if (opts::dump::DumpModuleFiles) {
Zachary Turner0e327d02017-06-15 23:12:41 +0000114 if (auto EC = dumpModuleFiles())
115 return EC;
116 }
117
Zachary Turner7df69952017-06-22 20:57:39 +0000118 if (opts::dump::DumpLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000119 if (auto EC = dumpLines())
120 return EC;
121 }
122
Zachary Turner7df69952017-06-22 20:57:39 +0000123 if (opts::dump::DumpInlineeLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000124 if (auto EC = dumpInlineeLines())
125 return EC;
126 }
127
Zachary Turner7df69952017-06-22 20:57:39 +0000128 if (opts::dump::DumpXmi) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000129 if (auto EC = dumpXmi())
130 return EC;
131 }
132
Zachary Turner7df69952017-06-22 20:57:39 +0000133 if (opts::dump::DumpXme) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000134 if (auto EC = dumpXme())
135 return EC;
136 }
137
Zachary Turner02a26772017-06-30 18:15:47 +0000138 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
139 opts::dump::DumpTypeExtras) {
Zachary Turner63055452017-06-15 22:24:24 +0000140 if (auto EC = dumpTpiStream(StreamTPI))
141 return EC;
142 }
143
Zachary Turner02a26772017-06-30 18:15:47 +0000144 if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
145 opts::dump::DumpIdExtras) {
Zachary Turner63055452017-06-15 22:24:24 +0000146 if (auto EC = dumpTpiStream(StreamIPI))
147 return EC;
148 }
149
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000150 if (opts::dump::DumpGlobals) {
151 if (auto EC = dumpGlobals())
152 return EC;
153 }
154
Zachary Turner7df69952017-06-22 20:57:39 +0000155 if (opts::dump::DumpPublics) {
Zachary Turner63055452017-06-15 22:24:24 +0000156 if (auto EC = dumpPublics())
157 return EC;
158 }
159
Zachary Turner7df69952017-06-22 20:57:39 +0000160 if (opts::dump::DumpSymbols) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000161 auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj();
162 if (EC)
Zachary Turner63055452017-06-15 22:24:24 +0000163 return EC;
164 }
165
Zachary Turnerfb1cd502017-08-04 20:02:38 +0000166 if (opts::dump::DumpSectionHeaders) {
167 if (auto EC = dumpSectionHeaders())
168 return EC;
169 }
170
Zachary Turner7df69952017-06-22 20:57:39 +0000171 if (opts::dump::DumpSectionContribs) {
Zachary Turner63055452017-06-15 22:24:24 +0000172 if (auto EC = dumpSectionContribs())
173 return EC;
174 }
175
Zachary Turner7df69952017-06-22 20:57:39 +0000176 if (opts::dump::DumpSectionMap) {
Zachary Turner63055452017-06-15 22:24:24 +0000177 if (auto EC = dumpSectionMap())
178 return EC;
179 }
180
181 return Error::success();
182}
183
184static void printHeader(LinePrinter &P, const Twine &S) {
185 P.NewLine();
186 P.formatLine("{0,=60}", S);
187 P.formatLine("{0}", fmt_repeat('=', 60));
188}
189
Zachary Turner7df69952017-06-22 20:57:39 +0000190Error DumpOutputStyle::dumpFileSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000191 printHeader(P, "Summary");
192
Reid Klecknerdd853e52017-07-27 23:13:18 +0000193 ExitOnError Err("Invalid PDB Format: ");
Zachary Turner63055452017-06-15 22:24:24 +0000194
195 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000196 if (File.isObj()) {
197 P.formatLine("Dumping File summary is not valid for object files");
198 return Error::success();
199 }
Zachary Turner63055452017-06-15 22:24:24 +0000200
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000201 P.formatLine("Block Size: {0}", getPdb().getBlockSize());
202 P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
203 P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
204
205 auto &PS = Err(getPdb().getPDBInfoStream());
Zachary Turner63055452017-06-15 22:24:24 +0000206 P.formatLine("Signature: {0}", PS.getSignature());
207 P.formatLine("Age: {0}", PS.getAge());
208 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
209 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000210 P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
211 P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
212 P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
213 P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
214 P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
215 if (getPdb().hasPDBDbiStream()) {
216 auto &DBI = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +0000217 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
218 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
219 P.formatLine("Is stripped: {0}", DBI.isStripped());
220 }
221
222 return Error::success();
223}
224
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000225static StatCollection getSymbolStats(const SymbolGroup &SG,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000226 StatCollection &CumulativeStats) {
227 StatCollection Stats;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000228 if (SG.getFile().isPdb()) {
229 // For PDB files, all symbols are packed into one stream.
230 for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
231 Stats.update(S.kind(), S.length());
232 CumulativeStats.update(S.kind(), S.length());
233 }
234 return Stats;
235 }
236
237 for (const auto &SS : SG.getDebugSubsections()) {
238 // For object files, all symbols are spread across multiple Symbol
239 // subsections of a given .debug$S section.
240 if (SS.kind() != DebugSubsectionKind::Symbols)
241 continue;
242 DebugSymbolsSubsectionRef Symbols;
243 BinaryStreamReader Reader(SS.getRecordData());
244 cantFail(Symbols.initialize(Reader));
245 for (const auto &S : Symbols) {
246 Stats.update(S.kind(), S.length());
247 CumulativeStats.update(S.kind(), S.length());
248 }
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000249 }
250 return Stats;
251}
252
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000253static StatCollection getChunkStats(const SymbolGroup &SG,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000254 StatCollection &CumulativeStats) {
255 StatCollection Stats;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000256 for (const auto &Chunk : SG.getDebugSubsections()) {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000257 Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
258 CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
259 }
260 return Stats;
261}
262
263static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
264 return formatChunkKind(K, false);
265}
266
267static inline std::string formatModuleDetailKind(SymbolKind K) {
268 return formatSymbolKind(K);
269}
270
271template <typename Kind>
272static void printModuleDetailStats(LinePrinter &P, StringRef Label,
273 const StatCollection &Stats) {
274 P.NewLine();
275 P.formatLine(" {0}", Label);
276 AutoIndent Indent(P);
277 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total",
278 Stats.Totals.Count, Stats.Totals.Size);
279 P.formatLine("{0}", fmt_repeat('-', 74));
280 for (const auto &K : Stats.Individual) {
281 std::string KindName = formatModuleDetailKind(Kind(K.first));
282 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName,
283 K.second.Count, K.second.Size);
284 }
285}
286
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000287static bool isMyCode(const SymbolGroup &Group) {
288 if (Group.getFile().isObj())
289 return true;
290
291 StringRef Name = Group.name();
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000292 if (Name.startswith("Import:"))
293 return false;
294 if (Name.endswith_lower(".dll"))
295 return false;
296 if (Name.equals_lower("* linker *"))
297 return false;
298 if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools"))
299 return false;
300 if (Name.startswith_lower("f:\\dd\\vctools\\crt"))
301 return false;
302 return true;
303}
304
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000305static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) {
306 if (opts::dump::JustMyCode && !isMyCode(Group))
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000307 return false;
308
309 // If the arg was not specified on the command line, always dump all modules.
310 if (opts::dump::DumpModi.getNumOccurrences() == 0)
311 return true;
312
313 // Otherwise, only dump if this is the same module specified.
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000314 return (opts::dump::DumpModi == Idx);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000315}
316
Zachary Turner7df69952017-06-22 20:57:39 +0000317Error DumpOutputStyle::dumpStreamSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000318 printHeader(P, "Streams");
319
Zachary Turner63055452017-06-15 22:24:24 +0000320 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000321 if (File.isObj()) {
322 P.formatLine("Dumping streams is not valid for object files");
323 return Error::success();
324 }
325
326 if (StreamPurposes.empty())
327 discoverStreamPurposes(getPdb(), StreamPurposes);
328
329 uint32_t StreamCount = getPdb().getNumStreams();
330 uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
Zachary Turner63055452017-06-15 22:24:24 +0000331
332 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
333 P.formatLine(
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000334 "Stream {0} ({1} bytes): [{2}]",
Zachary Turner63055452017-06-15 22:24:24 +0000335 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000336 fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000337 NumDigits(MaxStreamSize)),
338 StreamPurposes[StreamIdx].getLongName());
339
Zachary Turner5f098522017-06-23 20:28:14 +0000340 if (opts::dump::DumpStreamBlocks) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000341 auto Blocks = getPdb().getStreamBlockList(StreamIdx);
Zachary Turner5f098522017-06-23 20:28:14 +0000342 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
343 P.formatLine(" {0} Blocks: [{1}]",
344 fmt_repeat(' ', NumDigits(StreamCount)),
345 make_range(BV.begin(), BV.end()));
346 }
Zachary Turner63055452017-06-15 22:24:24 +0000347 }
348
349 return Error::success();
350}
351
Zachary Turner0e327d02017-06-15 23:12:41 +0000352static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
353 uint32_t Index) {
Reid Klecknerdd853e52017-07-27 23:13:18 +0000354 ExitOnError Err("Unexpected error: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000355
356 auto &Dbi = Err(File.getPDBDbiStream());
357 const auto &Modules = Dbi.modules();
358 auto Modi = Modules.getModuleDescriptor(Index);
359
360 uint16_t ModiStream = Modi.getModuleStreamIndex();
361 if (ModiStream == kInvalidStreamIndex)
362 return make_error<RawError>(raw_error_code::no_stream,
363 "Module stream not present");
364
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000365 auto ModStreamData = File.createIndexedStream(ModiStream);
Zachary Turner0e327d02017-06-15 23:12:41 +0000366
367 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
368 if (auto EC = ModS.reload())
369 return make_error<RawError>(raw_error_code::corrupt_file,
370 "Invalid module stream");
371
372 return std::move(ModS);
373}
374
Zachary Turnerf2872b92017-06-15 23:59:56 +0000375template <typename CallbackT>
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000376static void
377iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope,
378 const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) {
379 if (HeaderScope) {
380 HeaderScope->P.formatLine(
381 "Mod {0:4} | `{1}`: ",
382 fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name());
383 }
Zachary Turner58699362017-08-03 23:11:52 +0000384
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000385 AutoIndent Indent(HeaderScope);
386 Callback(Modi, SG);
Zachary Turner58699362017-08-03 23:11:52 +0000387}
388
389template <typename CallbackT>
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000390static void iterateSymbolGroups(InputFile &Input,
391 const Optional<PrintScope> &HeaderScope,
392 CallbackT Callback) {
393 AutoIndent Indent(HeaderScope);
Zachary Turnerf2872b92017-06-15 23:59:56 +0000394
Reid Klecknerdd853e52017-07-27 23:13:18 +0000395 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turnerf2872b92017-06-15 23:59:56 +0000396
Zachary Turner58699362017-08-03 23:11:52 +0000397 if (opts::dump::DumpModi.getNumOccurrences() > 0) {
398 assert(opts::dump::DumpModi.getNumOccurrences() == 1);
399 uint32_t Modi = opts::dump::DumpModi;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000400 SymbolGroup SG(&Input, Modi);
401 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG,
402 Modi, Callback);
Zachary Turner58699362017-08-03 23:11:52 +0000403 return;
404 }
405
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000406 uint32_t I = 0;
407
408 for (const auto &SG : Input.symbol_groups()) {
409 if (shouldDumpSymbolGroup(I, SG))
410 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I,
411 Callback);
412
413 ++I;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000414 }
415}
416
417template <typename SubsectionT>
418static void iterateModuleSubsections(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000419 InputFile &File, const Optional<PrintScope> &HeaderScope,
420 llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)>
Zachary Turnerf2872b92017-06-15 23:59:56 +0000421 Callback) {
422
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000423 iterateSymbolGroups(File, HeaderScope,
424 [&](uint32_t Modi, const SymbolGroup &SG) {
425 for (const auto &SS : SG.getDebugSubsections()) {
426 SubsectionT Subsection;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000427
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000428 if (SS.kind() != Subsection.kind())
429 continue;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000430
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000431 BinaryStreamReader Reader(SS.getRecordData());
432 if (auto EC = Subsection.initialize(Reader))
433 continue;
434 Callback(Modi, SG, Subsection);
435 }
436 });
Zachary Turnerf2872b92017-06-15 23:59:56 +0000437}
438
Zachary Turner7df69952017-06-22 20:57:39 +0000439Error DumpOutputStyle::dumpModules() {
Zachary Turner63055452017-06-15 22:24:24 +0000440 printHeader(P, "Modules");
Zachary Turner63055452017-06-15 22:24:24 +0000441 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000442
443 if (File.isObj()) {
444 P.formatLine("Dumping modules is not supported for object files");
445 return Error::success();
446 }
447
448 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +0000449 P.formatLine("DBI Stream not present");
450 return Error::success();
451 }
452
Reid Klecknerdd853e52017-07-27 23:13:18 +0000453 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner63055452017-06-15 22:24:24 +0000454
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000455 auto &Stream = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +0000456
457 const DbiModuleList &Modules = Stream.modules();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000458 iterateSymbolGroups(
459 File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000460 auto Desc = Modules.getModuleDescriptor(Modi);
461 P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
462 P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
463 Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
464 Desc.hasECInfo());
465 StringRef PdbFilePath =
466 Err(Stream.getECName(Desc.getPdbFilePathNameIndex()));
467 StringRef SrcFilePath =
468 Err(Stream.getECName(Desc.getSourceFileNameIndex()));
469 P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
470 Desc.getPdbFilePathNameIndex(), PdbFilePath,
471 Desc.getSourceFileNameIndex(), SrcFilePath);
472 });
Zachary Turner0e327d02017-06-15 23:12:41 +0000473 return Error::success();
474}
475
Zachary Turner7df69952017-06-22 20:57:39 +0000476Error DumpOutputStyle::dumpModuleFiles() {
Zachary Turner0e327d02017-06-15 23:12:41 +0000477 printHeader(P, "Files");
478
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000479 if (File.isObj()) {
480 P.formatLine("Dumping files is not valid for object files");
481 return Error::success();
482 }
483
Reid Klecknerdd853e52017-07-27 23:13:18 +0000484 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000485
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000486 iterateSymbolGroups(File, PrintScope{P, 11},
487 [this, &Err](uint32_t Modi, const SymbolGroup &Strings) {
488 auto &Stream = Err(getPdb().getPDBDbiStream());
Zachary Turner0e327d02017-06-15 23:12:41 +0000489
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000490 const DbiModuleList &Modules = Stream.modules();
491 for (const auto &F : Modules.source_files(Modi)) {
492 Strings.formatFromFileName(P, F);
493 }
494 });
Zachary Turner4e950642017-06-15 23:56:19 +0000495 return Error::success();
496}
497
Zachary Turner99c69822017-08-31 20:43:22 +0000498Error DumpOutputStyle::dumpSymbolStats() {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000499 printHeader(P, "Module Stats");
500
501 ExitOnError Err("Unexpected error processing modules: ");
502
503 StatCollection SymStats;
504 StatCollection ChunkStats;
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000505
Zachary Turner41f07062017-09-01 20:17:20 +0000506 Optional<PrintScope> Scope;
507 if (File.isPdb())
508 Scope.emplace(P, 2);
509
510 iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000511 StatCollection SS = getSymbolStats(SG, SymStats);
512 StatCollection CS = getChunkStats(SG, ChunkStats);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000513
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000514 if (SG.getFile().isPdb()) {
Zachary Turner41f07062017-09-01 20:17:20 +0000515 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000516 auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
517 uint32_t ModCount = Modules.getModuleCount();
518 DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
519 uint32_t StreamIdx = Desc.getModuleStreamIndex();
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000520
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000521 if (StreamIdx == kInvalidStreamIndex) {
522 P.formatLine("Mod {0} (debug info not present): [{1}]",
523 fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
524 Desc.getModuleName());
525 return;
526 }
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000527 P.formatLine("Stream {0}, {1} bytes", StreamIdx,
528 getPdb().getStreamByteSize(StreamIdx));
529
530 printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
531 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000532 }
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000533 });
534
535 P.printLine(" Summary |");
536 AutoIndent Indent(P, 4);
537 if (SymStats.Totals.Count > 0) {
538 printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
539 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
540 }
541
542 return Error::success();
543}
544
Zachary Turner99c69822017-08-31 20:43:22 +0000545static bool isValidNamespaceIdentifier(StringRef S) {
546 if (S.empty())
547 return false;
548
549 if (std::isdigit(S[0]))
550 return false;
551
552 return llvm::all_of(S, [](char C) { return std::isalnum(C); });
553}
554
555namespace {
556constexpr uint32_t kNoneUdtKind = 0;
557constexpr uint32_t kSimpleUdtKind = 1;
558constexpr uint32_t kUnknownUdtKind = 2;
559const StringRef NoneLabel("<none type>");
560const StringRef SimpleLabel("<simple type>");
561const StringRef UnknownLabel("<unknown type>");
562
563} // namespace
564
565static StringRef getUdtStatLabel(uint32_t Kind) {
566 if (Kind == kNoneUdtKind)
567 return NoneLabel;
568
569 if (Kind == kSimpleUdtKind)
570 return SimpleLabel;
571
572 if (Kind == kUnknownUdtKind)
573 return UnknownLabel;
574
575 return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
576}
577
578static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
579 size_t L = 0;
580 for (const auto &Stat : Stats.Individual) {
581 StringRef Label = getUdtStatLabel(Stat.first);
582 L = std::max(L, Label.size());
583 }
584 return static_cast<uint32_t>(L);
585}
586
587Error DumpOutputStyle::dumpUdtStats() {
588 printHeader(P, "S_UDT Record Stats");
589
590 StatCollection UdtStats;
591 StatCollection UdtTargetStats;
Zachary Turner99c69822017-08-31 20:43:22 +0000592 AutoIndent Indent(P, 4);
593
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000594 auto &TpiTypes = File.types();
Zachary Turner99c69822017-08-31 20:43:22 +0000595
596 StringMap<StatCollection::Stat> NamespacedStats;
597
Zachary Turner99c69822017-08-31 20:43:22 +0000598 size_t LongestNamespace = 0;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000599 auto HandleOneSymbol = [&](const CVSymbol &Sym) {
Zachary Turner99c69822017-08-31 20:43:22 +0000600 if (Sym.kind() != SymbolKind::S_UDT)
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000601 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000602 UdtStats.update(SymbolKind::S_UDT, Sym.length());
603
604 UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
605
606 uint32_t Kind = 0;
607 uint32_t RecordSize = 0;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000608
609 if (UDT.Type.isNoneType())
610 Kind = kNoneUdtKind;
611 else if (UDT.Type.isSimple())
612 Kind = kSimpleUdtKind;
613 else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
614 Kind = T->kind();
615 RecordSize = T->length();
616 } else
617 Kind = kUnknownUdtKind;
Zachary Turner99c69822017-08-31 20:43:22 +0000618
619 UdtTargetStats.update(Kind, RecordSize);
620
621 size_t Pos = UDT.Name.find("::");
622 if (Pos == StringRef::npos)
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000623 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000624
625 StringRef Scope = UDT.Name.take_front(Pos);
626 if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000627 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000628
629 LongestNamespace = std::max(LongestNamespace, Scope.size());
630 NamespacedStats[Scope].update(RecordSize);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000631 };
632
633 P.NewLine();
634
635 if (File.isPdb()) {
636 if (!getPdb().hasPDBGlobalsStream()) {
637 P.printLine("- Error: globals stream not present");
638 return Error::success();
639 }
640
641 auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
Reid Kleckner145090f2017-10-27 00:45:51 +0000642 auto ExpGlobals = getPdb().getPDBGlobalsStream();
643 if (!ExpGlobals)
644 return ExpGlobals.takeError();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000645
Reid Kleckner145090f2017-10-27 00:45:51 +0000646 for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000647 CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
648 HandleOneSymbol(Sym);
649 }
650 } else {
651 for (const auto &Sec : File.symbol_groups()) {
652 for (const auto &SS : Sec.getDebugSubsections()) {
653 if (SS.kind() != DebugSubsectionKind::Symbols)
654 continue;
655
656 DebugSymbolsSubsectionRef Symbols;
657 BinaryStreamReader Reader(SS.getRecordData());
658 cantFail(Symbols.initialize(Reader));
659 for (const auto &S : Symbols)
660 HandleOneSymbol(S);
661 }
662 }
Zachary Turner99c69822017-08-31 20:43:22 +0000663 }
664
665 LongestNamespace += StringRef(" namespace ''").size();
Zachary Turner4c806612017-08-31 20:50:25 +0000666 size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
667 size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
Zachary Turner99c69822017-08-31 20:43:22 +0000668
669 // Compute the max number of digits for count and size fields, including comma
670 // separators.
671 StringRef CountHeader("Count");
672 StringRef SizeHeader("Size");
Zachary Turner4c806612017-08-31 20:50:25 +0000673 size_t CD = NumDigits(UdtStats.Totals.Count);
Zachary Turner99c69822017-08-31 20:43:22 +0000674 CD += (CD - 1) / 3;
675 CD = std::max(CD, CountHeader.size());
676
Zachary Turner4c806612017-08-31 20:50:25 +0000677 size_t SD = NumDigits(UdtStats.Totals.Size);
Zachary Turner99c69822017-08-31 20:43:22 +0000678 SD += (SD - 1) / 3;
679 SD = std::max(SD, SizeHeader.size());
680
681 uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
682
683 P.formatLine("{0} | {1} {2}",
684 fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
685 fmt_align(CountHeader, AlignStyle::Right, CD),
686 fmt_align(SizeHeader, AlignStyle::Right, SD));
687
688 P.formatLine("{0}", fmt_repeat('-', TableWidth));
689 for (const auto &Stat : UdtTargetStats.Individual) {
690 StringRef Label = getUdtStatLabel(Stat.first);
691 P.formatLine("{0} | {1:N} {2:N}",
692 fmt_align(Label, AlignStyle::Right, FieldWidth),
693 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
694 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
695 }
696 P.formatLine("{0}", fmt_repeat('-', TableWidth));
697 P.formatLine("{0} | {1:N} {2:N}",
698 fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
699 fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
700 fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
701 P.formatLine("{0}", fmt_repeat('-', TableWidth));
702 for (const auto &Stat : NamespacedStats) {
703 std::string Label = formatv("namespace '{0}'", Stat.getKey());
704 P.formatLine("{0} | {1:N} {2:N}",
705 fmt_align(Label, AlignStyle::Right, FieldWidth),
706 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
707 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
708 }
709 return Error::success();
710}
711
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000712static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
713 const LineColumnEntry &E) {
Zachary Turner4e950642017-06-15 23:56:19 +0000714 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
715 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
716
717 // Let's try to keep it under 100 characters
718 constexpr uint32_t kMaxRowLength = 100;
719 // At least 3 spaces between columns.
720 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
721 uint32_t ItemsLeft = E.LineNumbers.size();
722 auto LineIter = E.LineNumbers.begin();
723 while (ItemsLeft != 0) {
724 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
725 for (uint32_t I = 0; I < RowColumns; ++I) {
726 LineInfo Line(LineIter->Flags);
727 std::string LineStr;
728 if (Line.isAlwaysStepInto())
729 LineStr = "ASI";
730 else if (Line.isNeverStepInto())
731 LineStr = "NSI";
Zachary Turner0e327d02017-06-15 23:12:41 +0000732 else
Zachary Turner4e950642017-06-15 23:56:19 +0000733 LineStr = utostr(Line.getStartLine());
734 char Statement = Line.isStatement() ? ' ' : '!';
735 P.format("{0} {1:X-} {2} ",
736 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
737 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
738 Statement);
739 ++LineIter;
740 --ItemsLeft;
Zachary Turner63055452017-06-15 22:24:24 +0000741 }
Zachary Turner4e950642017-06-15 23:56:19 +0000742 P.NewLine();
Zachary Turner63055452017-06-15 22:24:24 +0000743 }
Zachary Turner4e950642017-06-15 23:56:19 +0000744}
745
Zachary Turner7df69952017-06-22 20:57:39 +0000746Error DumpOutputStyle::dumpLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000747 printHeader(P, "Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000748
Zachary Turnerf2872b92017-06-15 23:59:56 +0000749 uint32_t LastModi = UINT32_MAX;
750 uint32_t LastNameIndex = UINT32_MAX;
751 iterateModuleSubsections<DebugLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000752 File, PrintScope{P, 4},
Zachary Turnerf2872b92017-06-15 23:59:56 +0000753 [this, &LastModi, &LastNameIndex](uint32_t Modi,
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000754 const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000755 DebugLinesSubsectionRef &Lines) {
756 uint16_t Segment = Lines.header()->RelocSegment;
757 uint32_t Begin = Lines.header()->RelocOffset;
758 uint32_t End = Begin + Lines.header()->CodeSize;
759 for (const auto &Block : Lines) {
760 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
761 LastModi = Modi;
762 LastNameIndex = Block.NameIndex;
763 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
Zachary Turner4e950642017-06-15 23:56:19 +0000764 }
765
Zachary Turnerf2872b92017-06-15 23:59:56 +0000766 AutoIndent Indent(P, 2);
767 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
768 uint32_t Count = Block.LineNumbers.size();
769 if (Lines.hasColumnInfo())
770 P.format("line/column/addr entries = {0}", Count);
771 else
772 P.format("line/addr entries = {0}", Count);
Zachary Turner4e950642017-06-15 23:56:19 +0000773
Zachary Turnerf2872b92017-06-15 23:59:56 +0000774 P.NewLine();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000775 typesetLinesAndColumns(P, Begin, Block);
Zachary Turner4e950642017-06-15 23:56:19 +0000776 }
777 });
778
779 return Error::success();
780}
781
Zachary Turner7df69952017-06-22 20:57:39 +0000782Error DumpOutputStyle::dumpInlineeLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000783 printHeader(P, "Inlinee Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000784
Zachary Turnerf2872b92017-06-15 23:59:56 +0000785 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000786 File, PrintScope{P, 2},
787 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000788 DebugInlineeLinesSubsectionRef &Lines) {
789 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
790 for (const auto &Entry : Lines) {
791 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
792 fmtle(Entry.Header->SourceLineNum));
793 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
Zachary Turner4e950642017-06-15 23:56:19 +0000794 }
Zachary Turnerf2872b92017-06-15 23:59:56 +0000795 P.NewLine();
Zachary Turner4e950642017-06-15 23:56:19 +0000796 });
797
Zachary Turner63055452017-06-15 22:24:24 +0000798 return Error::success();
799}
Zachary Turner0e327d02017-06-15 23:12:41 +0000800
Zachary Turner7df69952017-06-22 20:57:39 +0000801Error DumpOutputStyle::dumpXmi() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000802 printHeader(P, "Cross Module Imports");
803 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000804 File, PrintScope{P, 2},
805 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000806 DebugCrossModuleImportsSubsectionRef &Imports) {
807 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
808
809 for (const auto &Xmi : Imports) {
810 auto ExpectedModule =
811 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
812 StringRef Module;
813 SmallString<32> ModuleStorage;
814 if (!ExpectedModule) {
815 Module = "(unknown module)";
816 consumeError(ExpectedModule.takeError());
817 } else
818 Module = *ExpectedModule;
819 if (Module.size() > 32) {
820 ModuleStorage = "...";
821 ModuleStorage += Module.take_back(32 - 3);
822 Module = ModuleStorage;
823 }
824 std::vector<std::string> TIs;
825 for (const auto I : Xmi.Imports)
826 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
827 std::string Result =
828 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
829 P.formatLine("{0,+32} | {1}", Module, Result);
830 }
831 });
832
833 return Error::success();
834}
835
Zachary Turner7df69952017-06-22 20:57:39 +0000836Error DumpOutputStyle::dumpXme() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000837 printHeader(P, "Cross Module Exports");
838
839 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000840 File, PrintScope{P, 2},
841 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000842 DebugCrossModuleExportsSubsectionRef &Exports) {
843 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
844 for (const auto &Export : Exports) {
845 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
846 TypeIndex(Export.Global));
847 }
848 });
849
850 return Error::success();
851}
852
Zachary Turner7df69952017-06-22 20:57:39 +0000853Error DumpOutputStyle::dumpStringTable() {
Zachary Turner63055452017-06-15 22:24:24 +0000854 printHeader(P, "String Table");
855
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000856 if (File.isObj()) {
857 P.formatLine("Dumping string table is not supported for object files");
858 return Error::success();
859 }
860
Zachary Turner63055452017-06-15 22:24:24 +0000861 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000862 auto IS = getPdb().getStringTable();
Zachary Turner63055452017-06-15 22:24:24 +0000863 if (!IS) {
864 P.formatLine("Not present in file");
865 consumeError(IS.takeError());
866 return Error::success();
867 }
868
869 if (IS->name_ids().empty()) {
870 P.formatLine("Empty");
871 return Error::success();
872 }
873
874 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
875 uint32_t Digits = NumDigits(*MaxID);
876
877 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
878 "String");
879
880 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
881 std::sort(SortedIDs.begin(), SortedIDs.end());
882 for (uint32_t I : SortedIDs) {
883 auto ES = IS->getStringForID(I);
884 llvm::SmallString<32> Str;
885 if (!ES) {
886 consumeError(ES.takeError());
887 Str = "Error reading string";
888 } else if (!ES->empty()) {
889 Str.append("'");
890 Str.append(*ES);
891 Str.append("'");
892 }
893
894 if (!Str.empty())
895 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
896 }
897 return Error::success();
898}
899
Zachary Turner02a26772017-06-30 18:15:47 +0000900static void buildDepSet(LazyRandomTypeCollection &Types,
901 ArrayRef<TypeIndex> Indices,
902 std::map<TypeIndex, CVType> &DepSet) {
903 SmallVector<TypeIndex, 4> DepList;
904 for (const auto &I : Indices) {
905 TypeIndex TI(I);
906 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
907 continue;
908
909 CVType Type = Types.getType(TI);
910 DepSet[TI] = Type;
911 codeview::discoverTypeIndices(Type, DepList);
912 buildDepSet(Types, DepList, DepSet);
913 }
914}
915
916static void dumpFullTypeStream(LinePrinter &Printer,
917 LazyRandomTypeCollection &Types,
918 TpiStream &Stream, bool Bytes, bool Extras) {
919 Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
920 uint32_t Width =
921 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
922
923 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000924 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000925
926 if (auto EC = codeview::visitTypeStream(Types, V)) {
927 Printer.formatLine("An error occurred dumping type records: {0}",
928 toString(std::move(EC)));
929 }
930}
931
932static void dumpPartialTypeStream(LinePrinter &Printer,
933 LazyRandomTypeCollection &Types,
934 TpiStream &Stream, ArrayRef<TypeIndex> TiList,
935 bool Bytes, bool Extras, bool Deps) {
936 uint32_t Width =
937 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
938
939 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000940 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000941
942 if (opts::dump::DumpTypeDependents) {
943 // If we need to dump all dependents, then iterate each index and find
944 // all dependents, adding them to a map ordered by TypeIndex.
945 std::map<TypeIndex, CVType> DepSet;
946 buildDepSet(Types, TiList, DepSet);
947
948 Printer.formatLine(
949 "Showing {0:N} records and their dependents ({1:N} records total)",
950 TiList.size(), DepSet.size());
951
952 for (auto &Dep : DepSet) {
953 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
954 Printer.formatLine("An error occurred dumping type record {0}: {1}",
955 Dep.first, toString(std::move(EC)));
956 }
957 } else {
958 Printer.formatLine("Showing {0:N} records.", TiList.size());
959
960 for (const auto &I : TiList) {
961 TypeIndex TI(I);
962 CVType Type = Types.getType(TI);
963 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
964 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
965 toString(std::move(EC)));
966 }
967 }
968}
969
Zachary Turner7df69952017-06-22 20:57:39 +0000970Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Zachary Turner63055452017-06-15 22:24:24 +0000971 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
972
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000973 if (StreamIdx == StreamTPI) {
974 printHeader(P, "Types (TPI Stream)");
975 } else if (StreamIdx == StreamIPI) {
976 printHeader(P, "Types (IPI Stream)");
977 }
978
979 AutoIndent Indent(P);
980 if (File.isObj()) {
981 P.formatLine("Dumping types is not supported for object files");
982 return Error::success();
983 }
984
Zachary Turner63055452017-06-15 22:24:24 +0000985 bool Present = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000986 bool DumpTypes = false;
Zachary Turner63055452017-06-15 22:24:24 +0000987 bool DumpBytes = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000988 bool DumpExtras = false;
Zachary Turner59224cb2017-06-16 23:42:15 +0000989 std::vector<uint32_t> Indices;
Zachary Turner63055452017-06-15 22:24:24 +0000990 if (StreamIdx == StreamTPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000991 Present = getPdb().hasPDBTpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000992 DumpTypes = opts::dump::DumpTypes;
993 DumpBytes = opts::dump::DumpTypeData;
994 DumpExtras = opts::dump::DumpTypeExtras;
995 Indices.assign(opts::dump::DumpTypeIndex.begin(),
996 opts::dump::DumpTypeIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +0000997 } else if (StreamIdx == StreamIPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000998 Present = getPdb().hasPDBIpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000999 DumpTypes = opts::dump::DumpIds;
1000 DumpBytes = opts::dump::DumpIdData;
1001 DumpExtras = opts::dump::DumpIdExtras;
1002 Indices.assign(opts::dump::DumpIdIndex.begin(),
1003 opts::dump::DumpIdIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +00001004 }
1005
Zachary Turner63055452017-06-15 22:24:24 +00001006 if (!Present) {
1007 P.formatLine("Stream not present");
1008 return Error::success();
1009 }
1010
Reid Klecknerdd853e52017-07-27 23:13:18 +00001011 ExitOnError Err("Unexpected error processing types: ");
Zachary Turner63055452017-06-15 22:24:24 +00001012
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001013 auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
1014 : getPdb().getPDBIpiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001015
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001016 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
Zachary Turner63055452017-06-15 22:24:24 +00001017
Zachary Turner02a26772017-06-30 18:15:47 +00001018 if (DumpTypes || !Indices.empty()) {
1019 if (Indices.empty())
1020 dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
1021 else {
1022 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
1023 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
1024 opts::dump::DumpTypeDependents);
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001025 }
1026 }
1027
1028 if (DumpExtras) {
1029 P.NewLine();
1030 auto IndexOffsets = Stream.getTypeIndexOffsets();
1031 P.formatLine("Type Index Offsets:");
1032 for (const auto &IO : IndexOffsets) {
1033 AutoIndent Indent2(P);
1034 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
1035 }
1036
1037 P.NewLine();
1038 P.formatLine("Hash Adjusters:");
1039 auto &Adjusters = Stream.getHashAdjusters();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001040 auto &Strings = Err(getPdb().getStringTable());
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001041 for (const auto &A : Adjusters) {
1042 AutoIndent Indent2(P);
1043 auto ExpectedStr = Strings.getStringForID(A.first);
1044 TypeIndex TI(A.second);
1045 if (ExpectedStr)
1046 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
1047 else {
1048 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
1049 consumeError(ExpectedStr.takeError());
1050 }
1051 }
Zachary Turner63055452017-06-15 22:24:24 +00001052 }
1053 return Error::success();
1054}
1055
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001056Error DumpOutputStyle::dumpModuleSymsForObj() {
Zachary Turner63055452017-06-15 22:24:24 +00001057 printHeader(P, "Symbols");
1058
1059 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001060
1061 ExitOnError Err("Unexpected error processing symbols: ");
1062
1063 auto &Types = File.types();
1064
1065 SymbolVisitorCallbackPipeline Pipeline;
1066 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
1067 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
1068
1069 Pipeline.addCallbackToPipeline(Deserializer);
1070 Pipeline.addCallbackToPipeline(Dumper);
1071 CVSymbolVisitor Visitor(Pipeline);
1072
1073 std::unique_ptr<llvm::Error> SymbolError;
1074
1075 iterateModuleSubsections<DebugSymbolsSubsectionRef>(
1076 File, PrintScope{P, 2},
1077 [&](uint32_t Modi, const SymbolGroup &Strings,
1078 DebugSymbolsSubsectionRef &Symbols) {
1079 for (auto Symbol : Symbols) {
1080 if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
1081 SymbolError = llvm::make_unique<Error>(std::move(EC));
1082 return;
1083 }
1084 }
1085 });
1086
1087 if (SymbolError)
1088 return std::move(*SymbolError);
1089
1090 return Error::success();
1091}
1092
1093Error DumpOutputStyle::dumpModuleSymsForPdb() {
1094 printHeader(P, "Symbols");
1095
1096 AutoIndent Indent(P);
1097 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001098 P.formatLine("DBI Stream not present");
1099 return Error::success();
1100 }
1101
Reid Klecknerdd853e52017-07-27 23:13:18 +00001102 ExitOnError Err("Unexpected error processing symbols: ");
Zachary Turner63055452017-06-15 22:24:24 +00001103
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001104 auto &Ids = File.ids();
1105 auto &Types = File.types();
Zachary Turner63055452017-06-15 22:24:24 +00001106
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001107 iterateSymbolGroups(
1108 File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
1109 auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
Zachary Turner58699362017-08-03 23:11:52 +00001110 if (!ExpectedModS) {
1111 P.formatLine("Error loading module stream {0}. {1}", I,
1112 toString(ExpectedModS.takeError()));
1113 return;
1114 }
Zachary Turner63055452017-06-15 22:24:24 +00001115
Zachary Turner58699362017-08-03 23:11:52 +00001116 ModuleDebugStreamRef &ModS = *ExpectedModS;
Zachary Turner63055452017-06-15 22:24:24 +00001117
Zachary Turner58699362017-08-03 23:11:52 +00001118 SymbolVisitorCallbackPipeline Pipeline;
1119 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turner59e3ae82017-08-08 18:34:44 +00001120 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids,
1121 Types);
Zachary Turner63055452017-06-15 22:24:24 +00001122
Zachary Turner58699362017-08-03 23:11:52 +00001123 Pipeline.addCallbackToPipeline(Deserializer);
1124 Pipeline.addCallbackToPipeline(Dumper);
1125 CVSymbolVisitor Visitor(Pipeline);
1126 auto SS = ModS.getSymbolsSubstream();
1127 if (auto EC =
1128 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
1129 P.formatLine("Error while processing symbol records. {0}",
1130 toString(std::move(EC)));
1131 return;
1132 }
1133 });
Zachary Turner63055452017-06-15 22:24:24 +00001134 return Error::success();
1135}
1136
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001137Error DumpOutputStyle::dumpGlobals() {
1138 printHeader(P, "Global Symbols");
1139 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001140
1141 if (File.isObj()) {
1142 P.formatLine("Dumping Globals is not supported for object files");
1143 return Error::success();
1144 }
1145
1146 if (!getPdb().hasPDBGlobalsStream()) {
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001147 P.formatLine("Globals stream not present");
1148 return Error::success();
1149 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001150 ExitOnError Err("Error dumping globals stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001151 auto &Globals = Err(getPdb().getPDBGlobalsStream());
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001152
1153 const GSIHashTable &Table = Globals.getGlobalsTable();
1154 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1155 return Error::success();
1156}
1157
Zachary Turner7df69952017-06-22 20:57:39 +00001158Error DumpOutputStyle::dumpPublics() {
Zachary Turner63055452017-06-15 22:24:24 +00001159 printHeader(P, "Public Symbols");
Zachary Turner63055452017-06-15 22:24:24 +00001160 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001161
1162 if (File.isObj()) {
1163 P.formatLine("Dumping Globals is not supported for object files");
1164 return Error::success();
1165 }
1166
1167 if (!getPdb().hasPDBPublicsStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001168 P.formatLine("Publics stream not present");
1169 return Error::success();
1170 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001171 ExitOnError Err("Error dumping publics stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001172 auto &Publics = Err(getPdb().getPDBPublicsStream());
Zachary Turner63055452017-06-15 22:24:24 +00001173
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001174 const GSIHashTable &PublicsTable = Publics.getPublicsTable();
Zachary Turner5448dab2017-08-09 04:23:59 +00001175 if (opts::dump::DumpPublicExtras) {
1176 P.printLine("Publics Header");
1177 AutoIndent Indent(P);
1178 P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
1179 formatSegmentOffset(Publics.getThunkTableSection(),
1180 Publics.getThunkTableOffset()));
1181 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001182 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
Zachary Turneraf8c75a2017-06-30 21:35:00 +00001183
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001184 // Skip the rest if we aren't dumping extras.
Reid Kleckner686f1212017-07-21 18:28:55 +00001185 if (!opts::dump::DumpPublicExtras)
1186 return Error::success();
1187
Reid Kleckner686f1212017-07-21 18:28:55 +00001188 P.formatLine("Address Map");
1189 {
1190 // These are offsets into the publics stream sorted by secidx:secrel.
1191 AutoIndent Indent2(P);
1192 for (uint32_t Addr : Publics.getAddressMap())
1193 P.formatLine("off = {0}", Addr);
1194 }
1195
1196 // The thunk map is optional debug info used for ILT thunks.
1197 if (!Publics.getThunkMap().empty()) {
1198 P.formatLine("Thunk Map");
1199 AutoIndent Indent2(P);
1200 for (uint32_t Addr : Publics.getThunkMap())
1201 P.formatLine("{0:x8}", Addr);
1202 }
1203
1204 // The section offsets table appears to be empty when incremental linking
1205 // isn't in use.
1206 if (!Publics.getSectionOffsets().empty()) {
1207 P.formatLine("Section Offsets");
1208 AutoIndent Indent2(P);
1209 for (const SectionOffset &SO : Publics.getSectionOffsets())
1210 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
1211 }
1212
Zachary Turner63055452017-06-15 22:24:24 +00001213 return Error::success();
1214}
1215
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001216Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
1217 bool HashExtras) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001218 auto ExpectedSyms = getPdb().getPDBSymbolStream();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001219 if (!ExpectedSyms)
1220 return ExpectedSyms.takeError();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001221 auto &Types = File.types();
1222 auto &Ids = File.ids();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001223
Zachary Turner5448dab2017-08-09 04:23:59 +00001224 if (HashExtras) {
1225 P.printLine("GSI Header");
1226 AutoIndent Indent(P);
1227 P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
1228 Table.getVerSignature(), Table.getVerHeader(),
1229 Table.getHashRecordSize(), Table.getNumBuckets());
1230 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001231
Zachary Turner5448dab2017-08-09 04:23:59 +00001232 {
1233 P.printLine("Records");
1234 SymbolVisitorCallbackPipeline Pipeline;
1235 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001236 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
Zachary Turner5448dab2017-08-09 04:23:59 +00001237
1238 Pipeline.addCallbackToPipeline(Deserializer);
1239 Pipeline.addCallbackToPipeline(Dumper);
1240 CVSymbolVisitor Visitor(Pipeline);
1241
1242 BinaryStreamRef SymStream =
1243 ExpectedSyms->getSymbolArray().getUnderlyingStream();
1244 for (uint32_t PubSymOff : Table) {
1245 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
1246 if (!Sym)
1247 return Sym.takeError();
1248 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
1249 return E;
1250 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001251 }
1252
1253 // Return early if we aren't dumping public hash table and address map info.
1254 if (!HashExtras)
1255 return Error::success();
1256
Zachary Turner5448dab2017-08-09 04:23:59 +00001257 P.formatLine("Hash Entries");
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001258 {
1259 AutoIndent Indent2(P);
1260 for (const PSHashRecord &HR : Table.HashRecords)
1261 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
1262 uint32_t(HR.CRef));
1263 }
1264
1265 // FIXME: Dump the bitmap.
1266
1267 P.formatLine("Hash Buckets");
1268 {
1269 AutoIndent Indent2(P);
1270 for (uint32_t Hash : Table.HashBuckets)
1271 P.formatLine("{0:x8}", Hash);
1272 }
1273
1274 return Error::success();
1275}
1276
Zachary Turner63055452017-06-15 22:24:24 +00001277static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1278 OMFSegDescFlags Flags) {
1279 std::vector<std::string> Opts;
1280 if (Flags == OMFSegDescFlags::None)
1281 return "none";
1282
1283 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
1284 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
1285 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
1286 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
1287 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
1288 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
1289 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
Zachary Turner47d9a562017-06-16 00:04:24 +00001290 return typesetItemList(Opts, IndentLevel, 4, " | ");
Zachary Turner63055452017-06-15 22:24:24 +00001291}
1292
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001293Error DumpOutputStyle::dumpSectionHeaders() {
1294 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1295 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1296 return Error::success();
1297}
1298
Zachary Turner92e584c2017-08-04 21:10:04 +00001299static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
1300 ArrayRef<llvm::object::coff_section>>>
1301loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
1302 if (!File.hasPDBDbiStream())
1303 return make_error<StringError>(
1304 "Section headers require a DBI Stream, which could not be loaded",
1305 inconvertibleErrorCode());
1306
1307 auto &Dbi = cantFail(File.getPDBDbiStream());
1308 uint32_t SI = Dbi.getDebugStreamIndex(Type);
1309
1310 if (SI == kInvalidStreamIndex)
1311 return make_error<StringError>(
1312 "PDB does not contain the requested image section header type",
1313 inconvertibleErrorCode());
1314
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001315 auto Stream = File.createIndexedStream(SI);
Zachary Turner92e584c2017-08-04 21:10:04 +00001316 if (!Stream)
1317 return make_error<StringError>("Could not load the required stream data",
1318 inconvertibleErrorCode());
1319
1320 ArrayRef<object::coff_section> Headers;
1321 if (Stream->getLength() % sizeof(object::coff_section) != 0)
1322 return make_error<StringError>(
1323 "Section header array size is not a multiple of section header size",
1324 inconvertibleErrorCode());
1325
1326 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
1327 BinaryStreamReader Reader(*Stream);
1328 cantFail(Reader.readArray(Headers, NumHeaders));
1329 return std::make_pair(std::move(Stream), Headers);
1330}
1331
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001332void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1333 printHeader(P, Label);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001334
1335 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001336 if (File.isObj()) {
1337 P.formatLine("Dumping Section Headers is not supported for object files");
1338 return;
1339 }
1340
1341 ExitOnError Err("Error dumping section headers: ");
Zachary Turner92e584c2017-08-04 21:10:04 +00001342 std::unique_ptr<MappedBlockStream> Stream;
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001343 ArrayRef<object::coff_section> Headers;
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001344 auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
Zachary Turner92e584c2017-08-04 21:10:04 +00001345 if (!ExpectedHeaders) {
1346 P.printLine(toString(ExpectedHeaders.takeError()));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001347 return;
1348 }
Zachary Turner92e584c2017-08-04 21:10:04 +00001349 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001350
1351 uint32_t I = 1;
1352 for (const auto &Header : Headers) {
1353 P.NewLine();
1354 P.formatLine("SECTION HEADER #{0}", I);
1355 P.formatLine("{0,8} name", Header.Name);
1356 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1357 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1358 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1359 P.formatLine("{0,8:X-} file pointer to raw data",
1360 uint32_t(Header.PointerToRawData));
1361 P.formatLine("{0,8:X-} file pointer to relocation table",
1362 uint32_t(Header.PointerToRelocations));
1363 P.formatLine("{0,8:X-} file pointer to line numbers",
1364 uint32_t(Header.PointerToLinenumbers));
1365 P.formatLine("{0,8:X-} number of relocations",
1366 uint32_t(Header.NumberOfRelocations));
1367 P.formatLine("{0,8:X-} number of line numbers",
1368 uint32_t(Header.NumberOfLinenumbers));
1369 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1370 AutoIndent IndentMore(P, 9);
1371 P.formatLine("{0}", formatSectionCharacteristics(
1372 P.getIndentLevel(), Header.Characteristics, 1, ""));
1373 ++I;
1374 }
1375 return;
1376}
1377
Zachary Turner92e584c2017-08-04 21:10:04 +00001378std::vector<std::string> getSectionNames(PDBFile &File) {
1379 auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
1380 if (!ExpectedHeaders)
1381 return {};
1382
1383 std::unique_ptr<MappedBlockStream> Stream;
1384 ArrayRef<object::coff_section> Headers;
1385 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1386 std::vector<std::string> Names;
1387 for (const auto &H : Headers)
1388 Names.push_back(H.Name);
1389 return Names;
1390}
1391
Zachary Turner7df69952017-06-22 20:57:39 +00001392Error DumpOutputStyle::dumpSectionContribs() {
Zachary Turner63055452017-06-15 22:24:24 +00001393 printHeader(P, "Section Contributions");
Zachary Turner63055452017-06-15 22:24:24 +00001394
1395 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001396 if (File.isObj()) {
1397 P.formatLine(
1398 "Dumping section contributions is not supported for object files");
1399 return Error::success();
1400 }
1401
1402 ExitOnError Err("Error dumping section contributions: ");
1403 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001404 P.formatLine(
1405 "Section contribs require a DBI Stream, which could not be loaded");
1406 return Error::success();
1407 }
1408
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001409 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001410
1411 class Visitor : public ISectionContribVisitor {
1412 public:
Zachary Turner92e584c2017-08-04 21:10:04 +00001413 Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
1414 auto Max = std::max_element(
1415 Names.begin(), Names.end(),
1416 [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
1417 MaxNameLen = (Max == Names.end() ? 0 : Max->size());
1418 }
Zachary Turner63055452017-06-15 22:24:24 +00001419 void visit(const SectionContrib &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001420 assert(SC.ISect > 0);
Zachary Turner489a7a02017-08-07 20:24:01 +00001421 std::string NameInsert;
1422 if (SC.ISect < Names.size()) {
1423 StringRef SectionName = Names[SC.ISect - 1];
1424 NameInsert = formatv("[{0}]", SectionName).str();
1425 } else
1426 NameInsert = "[???]";
Zachary Turner92e584c2017-08-04 21:10:04 +00001427 P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1428 "crc = {4}",
1429 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
1430 fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
1431 fmt_align(NameInsert, AlignStyle::Left, MaxNameLen + 2));
1432 AutoIndent Indent(P, MaxNameLen + 2);
Zachary Turner63055452017-06-15 22:24:24 +00001433 P.formatLine(" {0}",
1434 formatSectionCharacteristics(P.getIndentLevel() + 6,
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001435 SC.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001436 }
1437 void visit(const SectionContrib2 &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001438 P.formatLine(
1439 "SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1440 "crc = {4}, coff section = {5}",
1441 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), fmtle(SC.Base.Size),
1442 fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1443 fmtle(SC.ISectCoff));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001444 P.formatLine(" {0}", formatSectionCharacteristics(
1445 P.getIndentLevel() + 6,
1446 SC.Base.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001447 }
1448
1449 private:
1450 LinePrinter &P;
Zachary Turner92e584c2017-08-04 21:10:04 +00001451 uint32_t MaxNameLen;
1452 ArrayRef<std::string> Names;
Zachary Turner63055452017-06-15 22:24:24 +00001453 };
1454
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001455 std::vector<std::string> Names = getSectionNames(getPdb());
Zachary Turner92e584c2017-08-04 21:10:04 +00001456 Visitor V(P, makeArrayRef(Names));
Zachary Turner63055452017-06-15 22:24:24 +00001457 Dbi.visitSectionContributions(V);
1458 return Error::success();
1459}
1460
Zachary Turner7df69952017-06-22 20:57:39 +00001461Error DumpOutputStyle::dumpSectionMap() {
Zachary Turner63055452017-06-15 22:24:24 +00001462 printHeader(P, "Section Map");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001463 AutoIndent Indent(P);
1464
1465 if (File.isObj()) {
1466 P.formatLine("Dumping section map is not supported for object files");
1467 return Error::success();
1468 }
1469
Reid Klecknerdd853e52017-07-27 23:13:18 +00001470 ExitOnError Err("Error dumping section map: ");
Zachary Turner63055452017-06-15 22:24:24 +00001471
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001472 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001473 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1474 "not be loaded");
1475 return Error::success();
1476 }
1477
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001478 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001479
1480 uint32_t I = 0;
1481 for (auto &M : Dbi.getSectionMap()) {
1482 P.formatLine(
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001483 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
Zachary Turner63055452017-06-15 22:24:24 +00001484 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1485 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1486 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1487 P.formatLine(" flags = {0}",
1488 formatSegMapDescriptorFlag(
1489 P.getIndentLevel() + 13,
1490 static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1491 ++I;
1492 }
1493 return Error::success();
1494}