blob: 8a4d21b27ba6bbad6e513b8b5ba4254602ee8e2d [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());
642 auto &Globals = cantFail(getPdb().getPDBGlobalsStream());
643
644 for (uint32_t PubSymOff : Globals.getGlobalsTable()) {
645 CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
646 HandleOneSymbol(Sym);
647 }
648 } else {
649 for (const auto &Sec : File.symbol_groups()) {
650 for (const auto &SS : Sec.getDebugSubsections()) {
651 if (SS.kind() != DebugSubsectionKind::Symbols)
652 continue;
653
654 DebugSymbolsSubsectionRef Symbols;
655 BinaryStreamReader Reader(SS.getRecordData());
656 cantFail(Symbols.initialize(Reader));
657 for (const auto &S : Symbols)
658 HandleOneSymbol(S);
659 }
660 }
Zachary Turner99c69822017-08-31 20:43:22 +0000661 }
662
663 LongestNamespace += StringRef(" namespace ''").size();
Zachary Turner4c806612017-08-31 20:50:25 +0000664 size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
665 size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
Zachary Turner99c69822017-08-31 20:43:22 +0000666
667 // Compute the max number of digits for count and size fields, including comma
668 // separators.
669 StringRef CountHeader("Count");
670 StringRef SizeHeader("Size");
Zachary Turner4c806612017-08-31 20:50:25 +0000671 size_t CD = NumDigits(UdtStats.Totals.Count);
Zachary Turner99c69822017-08-31 20:43:22 +0000672 CD += (CD - 1) / 3;
673 CD = std::max(CD, CountHeader.size());
674
Zachary Turner4c806612017-08-31 20:50:25 +0000675 size_t SD = NumDigits(UdtStats.Totals.Size);
Zachary Turner99c69822017-08-31 20:43:22 +0000676 SD += (SD - 1) / 3;
677 SD = std::max(SD, SizeHeader.size());
678
679 uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
680
681 P.formatLine("{0} | {1} {2}",
682 fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
683 fmt_align(CountHeader, AlignStyle::Right, CD),
684 fmt_align(SizeHeader, AlignStyle::Right, SD));
685
686 P.formatLine("{0}", fmt_repeat('-', TableWidth));
687 for (const auto &Stat : UdtTargetStats.Individual) {
688 StringRef Label = getUdtStatLabel(Stat.first);
689 P.formatLine("{0} | {1:N} {2:N}",
690 fmt_align(Label, AlignStyle::Right, FieldWidth),
691 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
692 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
693 }
694 P.formatLine("{0}", fmt_repeat('-', TableWidth));
695 P.formatLine("{0} | {1:N} {2:N}",
696 fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
697 fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
698 fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
699 P.formatLine("{0}", fmt_repeat('-', TableWidth));
700 for (const auto &Stat : NamespacedStats) {
701 std::string Label = formatv("namespace '{0}'", Stat.getKey());
702 P.formatLine("{0} | {1:N} {2:N}",
703 fmt_align(Label, AlignStyle::Right, FieldWidth),
704 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
705 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
706 }
707 return Error::success();
708}
709
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000710static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
711 const LineColumnEntry &E) {
Zachary Turner4e950642017-06-15 23:56:19 +0000712 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
713 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
714
715 // Let's try to keep it under 100 characters
716 constexpr uint32_t kMaxRowLength = 100;
717 // At least 3 spaces between columns.
718 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
719 uint32_t ItemsLeft = E.LineNumbers.size();
720 auto LineIter = E.LineNumbers.begin();
721 while (ItemsLeft != 0) {
722 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
723 for (uint32_t I = 0; I < RowColumns; ++I) {
724 LineInfo Line(LineIter->Flags);
725 std::string LineStr;
726 if (Line.isAlwaysStepInto())
727 LineStr = "ASI";
728 else if (Line.isNeverStepInto())
729 LineStr = "NSI";
Zachary Turner0e327d02017-06-15 23:12:41 +0000730 else
Zachary Turner4e950642017-06-15 23:56:19 +0000731 LineStr = utostr(Line.getStartLine());
732 char Statement = Line.isStatement() ? ' ' : '!';
733 P.format("{0} {1:X-} {2} ",
734 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
735 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
736 Statement);
737 ++LineIter;
738 --ItemsLeft;
Zachary Turner63055452017-06-15 22:24:24 +0000739 }
Zachary Turner4e950642017-06-15 23:56:19 +0000740 P.NewLine();
Zachary Turner63055452017-06-15 22:24:24 +0000741 }
Zachary Turner4e950642017-06-15 23:56:19 +0000742}
743
Zachary Turner7df69952017-06-22 20:57:39 +0000744Error DumpOutputStyle::dumpLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000745 printHeader(P, "Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000746
Zachary Turnerf2872b92017-06-15 23:59:56 +0000747 uint32_t LastModi = UINT32_MAX;
748 uint32_t LastNameIndex = UINT32_MAX;
749 iterateModuleSubsections<DebugLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000750 File, PrintScope{P, 4},
Zachary Turnerf2872b92017-06-15 23:59:56 +0000751 [this, &LastModi, &LastNameIndex](uint32_t Modi,
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000752 const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000753 DebugLinesSubsectionRef &Lines) {
754 uint16_t Segment = Lines.header()->RelocSegment;
755 uint32_t Begin = Lines.header()->RelocOffset;
756 uint32_t End = Begin + Lines.header()->CodeSize;
757 for (const auto &Block : Lines) {
758 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
759 LastModi = Modi;
760 LastNameIndex = Block.NameIndex;
761 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
Zachary Turner4e950642017-06-15 23:56:19 +0000762 }
763
Zachary Turnerf2872b92017-06-15 23:59:56 +0000764 AutoIndent Indent(P, 2);
765 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
766 uint32_t Count = Block.LineNumbers.size();
767 if (Lines.hasColumnInfo())
768 P.format("line/column/addr entries = {0}", Count);
769 else
770 P.format("line/addr entries = {0}", Count);
Zachary Turner4e950642017-06-15 23:56:19 +0000771
Zachary Turnerf2872b92017-06-15 23:59:56 +0000772 P.NewLine();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000773 typesetLinesAndColumns(P, Begin, Block);
Zachary Turner4e950642017-06-15 23:56:19 +0000774 }
775 });
776
777 return Error::success();
778}
779
Zachary Turner7df69952017-06-22 20:57:39 +0000780Error DumpOutputStyle::dumpInlineeLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000781 printHeader(P, "Inlinee Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000782
Zachary Turnerf2872b92017-06-15 23:59:56 +0000783 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000784 File, PrintScope{P, 2},
785 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000786 DebugInlineeLinesSubsectionRef &Lines) {
787 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
788 for (const auto &Entry : Lines) {
789 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
790 fmtle(Entry.Header->SourceLineNum));
791 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
Zachary Turner4e950642017-06-15 23:56:19 +0000792 }
Zachary Turnerf2872b92017-06-15 23:59:56 +0000793 P.NewLine();
Zachary Turner4e950642017-06-15 23:56:19 +0000794 });
795
Zachary Turner63055452017-06-15 22:24:24 +0000796 return Error::success();
797}
Zachary Turner0e327d02017-06-15 23:12:41 +0000798
Zachary Turner7df69952017-06-22 20:57:39 +0000799Error DumpOutputStyle::dumpXmi() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000800 printHeader(P, "Cross Module Imports");
801 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000802 File, PrintScope{P, 2},
803 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000804 DebugCrossModuleImportsSubsectionRef &Imports) {
805 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
806
807 for (const auto &Xmi : Imports) {
808 auto ExpectedModule =
809 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
810 StringRef Module;
811 SmallString<32> ModuleStorage;
812 if (!ExpectedModule) {
813 Module = "(unknown module)";
814 consumeError(ExpectedModule.takeError());
815 } else
816 Module = *ExpectedModule;
817 if (Module.size() > 32) {
818 ModuleStorage = "...";
819 ModuleStorage += Module.take_back(32 - 3);
820 Module = ModuleStorage;
821 }
822 std::vector<std::string> TIs;
823 for (const auto I : Xmi.Imports)
824 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
825 std::string Result =
826 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
827 P.formatLine("{0,+32} | {1}", Module, Result);
828 }
829 });
830
831 return Error::success();
832}
833
Zachary Turner7df69952017-06-22 20:57:39 +0000834Error DumpOutputStyle::dumpXme() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000835 printHeader(P, "Cross Module Exports");
836
837 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000838 File, PrintScope{P, 2},
839 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000840 DebugCrossModuleExportsSubsectionRef &Exports) {
841 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
842 for (const auto &Export : Exports) {
843 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
844 TypeIndex(Export.Global));
845 }
846 });
847
848 return Error::success();
849}
850
Zachary Turner7df69952017-06-22 20:57:39 +0000851Error DumpOutputStyle::dumpStringTable() {
Zachary Turner63055452017-06-15 22:24:24 +0000852 printHeader(P, "String Table");
853
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000854 if (File.isObj()) {
855 P.formatLine("Dumping string table is not supported for object files");
856 return Error::success();
857 }
858
Zachary Turner63055452017-06-15 22:24:24 +0000859 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000860 auto IS = getPdb().getStringTable();
Zachary Turner63055452017-06-15 22:24:24 +0000861 if (!IS) {
862 P.formatLine("Not present in file");
863 consumeError(IS.takeError());
864 return Error::success();
865 }
866
867 if (IS->name_ids().empty()) {
868 P.formatLine("Empty");
869 return Error::success();
870 }
871
872 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
873 uint32_t Digits = NumDigits(*MaxID);
874
875 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
876 "String");
877
878 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
879 std::sort(SortedIDs.begin(), SortedIDs.end());
880 for (uint32_t I : SortedIDs) {
881 auto ES = IS->getStringForID(I);
882 llvm::SmallString<32> Str;
883 if (!ES) {
884 consumeError(ES.takeError());
885 Str = "Error reading string";
886 } else if (!ES->empty()) {
887 Str.append("'");
888 Str.append(*ES);
889 Str.append("'");
890 }
891
892 if (!Str.empty())
893 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
894 }
895 return Error::success();
896}
897
Zachary Turner02a26772017-06-30 18:15:47 +0000898static void buildDepSet(LazyRandomTypeCollection &Types,
899 ArrayRef<TypeIndex> Indices,
900 std::map<TypeIndex, CVType> &DepSet) {
901 SmallVector<TypeIndex, 4> DepList;
902 for (const auto &I : Indices) {
903 TypeIndex TI(I);
904 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
905 continue;
906
907 CVType Type = Types.getType(TI);
908 DepSet[TI] = Type;
909 codeview::discoverTypeIndices(Type, DepList);
910 buildDepSet(Types, DepList, DepSet);
911 }
912}
913
914static void dumpFullTypeStream(LinePrinter &Printer,
915 LazyRandomTypeCollection &Types,
916 TpiStream &Stream, bool Bytes, bool Extras) {
917 Printer.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
918 uint32_t Width =
919 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
920
921 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000922 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000923
924 if (auto EC = codeview::visitTypeStream(Types, V)) {
925 Printer.formatLine("An error occurred dumping type records: {0}",
926 toString(std::move(EC)));
927 }
928}
929
930static void dumpPartialTypeStream(LinePrinter &Printer,
931 LazyRandomTypeCollection &Types,
932 TpiStream &Stream, ArrayRef<TypeIndex> TiList,
933 bool Bytes, bool Extras, bool Deps) {
934 uint32_t Width =
935 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
936
937 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000938 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000939
940 if (opts::dump::DumpTypeDependents) {
941 // If we need to dump all dependents, then iterate each index and find
942 // all dependents, adding them to a map ordered by TypeIndex.
943 std::map<TypeIndex, CVType> DepSet;
944 buildDepSet(Types, TiList, DepSet);
945
946 Printer.formatLine(
947 "Showing {0:N} records and their dependents ({1:N} records total)",
948 TiList.size(), DepSet.size());
949
950 for (auto &Dep : DepSet) {
951 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
952 Printer.formatLine("An error occurred dumping type record {0}: {1}",
953 Dep.first, toString(std::move(EC)));
954 }
955 } else {
956 Printer.formatLine("Showing {0:N} records.", TiList.size());
957
958 for (const auto &I : TiList) {
959 TypeIndex TI(I);
960 CVType Type = Types.getType(TI);
961 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
962 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
963 toString(std::move(EC)));
964 }
965 }
966}
967
Zachary Turner7df69952017-06-22 20:57:39 +0000968Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Zachary Turner63055452017-06-15 22:24:24 +0000969 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
970
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000971 if (StreamIdx == StreamTPI) {
972 printHeader(P, "Types (TPI Stream)");
973 } else if (StreamIdx == StreamIPI) {
974 printHeader(P, "Types (IPI Stream)");
975 }
976
977 AutoIndent Indent(P);
978 if (File.isObj()) {
979 P.formatLine("Dumping types is not supported for object files");
980 return Error::success();
981 }
982
Zachary Turner63055452017-06-15 22:24:24 +0000983 bool Present = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000984 bool DumpTypes = false;
Zachary Turner63055452017-06-15 22:24:24 +0000985 bool DumpBytes = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +0000986 bool DumpExtras = false;
Zachary Turner59224cb2017-06-16 23:42:15 +0000987 std::vector<uint32_t> Indices;
Zachary Turner63055452017-06-15 22:24:24 +0000988 if (StreamIdx == StreamTPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000989 Present = getPdb().hasPDBTpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000990 DumpTypes = opts::dump::DumpTypes;
991 DumpBytes = opts::dump::DumpTypeData;
992 DumpExtras = opts::dump::DumpTypeExtras;
993 Indices.assign(opts::dump::DumpTypeIndex.begin(),
994 opts::dump::DumpTypeIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +0000995 } else if (StreamIdx == StreamIPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000996 Present = getPdb().hasPDBIpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +0000997 DumpTypes = opts::dump::DumpIds;
998 DumpBytes = opts::dump::DumpIdData;
999 DumpExtras = opts::dump::DumpIdExtras;
1000 Indices.assign(opts::dump::DumpIdIndex.begin(),
1001 opts::dump::DumpIdIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +00001002 }
1003
Zachary Turner63055452017-06-15 22:24:24 +00001004 if (!Present) {
1005 P.formatLine("Stream not present");
1006 return Error::success();
1007 }
1008
Reid Klecknerdd853e52017-07-27 23:13:18 +00001009 ExitOnError Err("Unexpected error processing types: ");
Zachary Turner63055452017-06-15 22:24:24 +00001010
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001011 auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
1012 : getPdb().getPDBIpiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001013
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001014 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
Zachary Turner63055452017-06-15 22:24:24 +00001015
Zachary Turner02a26772017-06-30 18:15:47 +00001016 if (DumpTypes || !Indices.empty()) {
1017 if (Indices.empty())
1018 dumpFullTypeStream(P, Types, Stream, DumpBytes, DumpExtras);
1019 else {
1020 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
1021 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
1022 opts::dump::DumpTypeDependents);
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001023 }
1024 }
1025
1026 if (DumpExtras) {
1027 P.NewLine();
1028 auto IndexOffsets = Stream.getTypeIndexOffsets();
1029 P.formatLine("Type Index Offsets:");
1030 for (const auto &IO : IndexOffsets) {
1031 AutoIndent Indent2(P);
1032 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
1033 }
1034
1035 P.NewLine();
1036 P.formatLine("Hash Adjusters:");
1037 auto &Adjusters = Stream.getHashAdjusters();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001038 auto &Strings = Err(getPdb().getStringTable());
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001039 for (const auto &A : Adjusters) {
1040 AutoIndent Indent2(P);
1041 auto ExpectedStr = Strings.getStringForID(A.first);
1042 TypeIndex TI(A.second);
1043 if (ExpectedStr)
1044 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
1045 else {
1046 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
1047 consumeError(ExpectedStr.takeError());
1048 }
1049 }
Zachary Turner63055452017-06-15 22:24:24 +00001050 }
1051 return Error::success();
1052}
1053
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001054Error DumpOutputStyle::dumpModuleSymsForObj() {
Zachary Turner63055452017-06-15 22:24:24 +00001055 printHeader(P, "Symbols");
1056
1057 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001058
1059 ExitOnError Err("Unexpected error processing symbols: ");
1060
1061 auto &Types = File.types();
1062
1063 SymbolVisitorCallbackPipeline Pipeline;
1064 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
1065 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
1066
1067 Pipeline.addCallbackToPipeline(Deserializer);
1068 Pipeline.addCallbackToPipeline(Dumper);
1069 CVSymbolVisitor Visitor(Pipeline);
1070
1071 std::unique_ptr<llvm::Error> SymbolError;
1072
1073 iterateModuleSubsections<DebugSymbolsSubsectionRef>(
1074 File, PrintScope{P, 2},
1075 [&](uint32_t Modi, const SymbolGroup &Strings,
1076 DebugSymbolsSubsectionRef &Symbols) {
1077 for (auto Symbol : Symbols) {
1078 if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
1079 SymbolError = llvm::make_unique<Error>(std::move(EC));
1080 return;
1081 }
1082 }
1083 });
1084
1085 if (SymbolError)
1086 return std::move(*SymbolError);
1087
1088 return Error::success();
1089}
1090
1091Error DumpOutputStyle::dumpModuleSymsForPdb() {
1092 printHeader(P, "Symbols");
1093
1094 AutoIndent Indent(P);
1095 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001096 P.formatLine("DBI Stream not present");
1097 return Error::success();
1098 }
1099
Reid Klecknerdd853e52017-07-27 23:13:18 +00001100 ExitOnError Err("Unexpected error processing symbols: ");
Zachary Turner63055452017-06-15 22:24:24 +00001101
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001102 auto &Ids = File.ids();
1103 auto &Types = File.types();
Zachary Turner63055452017-06-15 22:24:24 +00001104
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001105 iterateSymbolGroups(
1106 File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
1107 auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
Zachary Turner58699362017-08-03 23:11:52 +00001108 if (!ExpectedModS) {
1109 P.formatLine("Error loading module stream {0}. {1}", I,
1110 toString(ExpectedModS.takeError()));
1111 return;
1112 }
Zachary Turner63055452017-06-15 22:24:24 +00001113
Zachary Turner58699362017-08-03 23:11:52 +00001114 ModuleDebugStreamRef &ModS = *ExpectedModS;
Zachary Turner63055452017-06-15 22:24:24 +00001115
Zachary Turner58699362017-08-03 23:11:52 +00001116 SymbolVisitorCallbackPipeline Pipeline;
1117 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turner59e3ae82017-08-08 18:34:44 +00001118 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids,
1119 Types);
Zachary Turner63055452017-06-15 22:24:24 +00001120
Zachary Turner58699362017-08-03 23:11:52 +00001121 Pipeline.addCallbackToPipeline(Deserializer);
1122 Pipeline.addCallbackToPipeline(Dumper);
1123 CVSymbolVisitor Visitor(Pipeline);
1124 auto SS = ModS.getSymbolsSubstream();
1125 if (auto EC =
1126 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
1127 P.formatLine("Error while processing symbol records. {0}",
1128 toString(std::move(EC)));
1129 return;
1130 }
1131 });
Zachary Turner63055452017-06-15 22:24:24 +00001132 return Error::success();
1133}
1134
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001135Error DumpOutputStyle::dumpGlobals() {
1136 printHeader(P, "Global Symbols");
1137 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001138
1139 if (File.isObj()) {
1140 P.formatLine("Dumping Globals is not supported for object files");
1141 return Error::success();
1142 }
1143
1144 if (!getPdb().hasPDBGlobalsStream()) {
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001145 P.formatLine("Globals stream not present");
1146 return Error::success();
1147 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001148 ExitOnError Err("Error dumping globals stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001149 auto &Globals = Err(getPdb().getPDBGlobalsStream());
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001150
1151 const GSIHashTable &Table = Globals.getGlobalsTable();
1152 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1153 return Error::success();
1154}
1155
Zachary Turner7df69952017-06-22 20:57:39 +00001156Error DumpOutputStyle::dumpPublics() {
Zachary Turner63055452017-06-15 22:24:24 +00001157 printHeader(P, "Public Symbols");
Zachary Turner63055452017-06-15 22:24:24 +00001158 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001159
1160 if (File.isObj()) {
1161 P.formatLine("Dumping Globals is not supported for object files");
1162 return Error::success();
1163 }
1164
1165 if (!getPdb().hasPDBPublicsStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001166 P.formatLine("Publics stream not present");
1167 return Error::success();
1168 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001169 ExitOnError Err("Error dumping publics stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001170 auto &Publics = Err(getPdb().getPDBPublicsStream());
Zachary Turner63055452017-06-15 22:24:24 +00001171
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001172 const GSIHashTable &PublicsTable = Publics.getPublicsTable();
Zachary Turner5448dab2017-08-09 04:23:59 +00001173 if (opts::dump::DumpPublicExtras) {
1174 P.printLine("Publics Header");
1175 AutoIndent Indent(P);
1176 P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
1177 formatSegmentOffset(Publics.getThunkTableSection(),
1178 Publics.getThunkTableOffset()));
1179 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001180 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
Zachary Turneraf8c75a2017-06-30 21:35:00 +00001181
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001182 // Skip the rest if we aren't dumping extras.
Reid Kleckner686f1212017-07-21 18:28:55 +00001183 if (!opts::dump::DumpPublicExtras)
1184 return Error::success();
1185
Reid Kleckner686f1212017-07-21 18:28:55 +00001186 P.formatLine("Address Map");
1187 {
1188 // These are offsets into the publics stream sorted by secidx:secrel.
1189 AutoIndent Indent2(P);
1190 for (uint32_t Addr : Publics.getAddressMap())
1191 P.formatLine("off = {0}", Addr);
1192 }
1193
1194 // The thunk map is optional debug info used for ILT thunks.
1195 if (!Publics.getThunkMap().empty()) {
1196 P.formatLine("Thunk Map");
1197 AutoIndent Indent2(P);
1198 for (uint32_t Addr : Publics.getThunkMap())
1199 P.formatLine("{0:x8}", Addr);
1200 }
1201
1202 // The section offsets table appears to be empty when incremental linking
1203 // isn't in use.
1204 if (!Publics.getSectionOffsets().empty()) {
1205 P.formatLine("Section Offsets");
1206 AutoIndent Indent2(P);
1207 for (const SectionOffset &SO : Publics.getSectionOffsets())
1208 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
1209 }
1210
Zachary Turner63055452017-06-15 22:24:24 +00001211 return Error::success();
1212}
1213
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001214Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
1215 bool HashExtras) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001216 auto ExpectedSyms = getPdb().getPDBSymbolStream();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001217 if (!ExpectedSyms)
1218 return ExpectedSyms.takeError();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001219 auto &Types = File.types();
1220 auto &Ids = File.ids();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001221
Zachary Turner5448dab2017-08-09 04:23:59 +00001222 if (HashExtras) {
1223 P.printLine("GSI Header");
1224 AutoIndent Indent(P);
1225 P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
1226 Table.getVerSignature(), Table.getVerHeader(),
1227 Table.getHashRecordSize(), Table.getNumBuckets());
1228 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001229
Zachary Turner5448dab2017-08-09 04:23:59 +00001230 {
1231 P.printLine("Records");
1232 SymbolVisitorCallbackPipeline Pipeline;
1233 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001234 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
Zachary Turner5448dab2017-08-09 04:23:59 +00001235
1236 Pipeline.addCallbackToPipeline(Deserializer);
1237 Pipeline.addCallbackToPipeline(Dumper);
1238 CVSymbolVisitor Visitor(Pipeline);
1239
1240 BinaryStreamRef SymStream =
1241 ExpectedSyms->getSymbolArray().getUnderlyingStream();
1242 for (uint32_t PubSymOff : Table) {
1243 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
1244 if (!Sym)
1245 return Sym.takeError();
1246 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
1247 return E;
1248 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001249 }
1250
1251 // Return early if we aren't dumping public hash table and address map info.
1252 if (!HashExtras)
1253 return Error::success();
1254
Zachary Turner5448dab2017-08-09 04:23:59 +00001255 P.formatLine("Hash Entries");
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001256 {
1257 AutoIndent Indent2(P);
1258 for (const PSHashRecord &HR : Table.HashRecords)
1259 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
1260 uint32_t(HR.CRef));
1261 }
1262
1263 // FIXME: Dump the bitmap.
1264
1265 P.formatLine("Hash Buckets");
1266 {
1267 AutoIndent Indent2(P);
1268 for (uint32_t Hash : Table.HashBuckets)
1269 P.formatLine("{0:x8}", Hash);
1270 }
1271
1272 return Error::success();
1273}
1274
Zachary Turner63055452017-06-15 22:24:24 +00001275static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1276 OMFSegDescFlags Flags) {
1277 std::vector<std::string> Opts;
1278 if (Flags == OMFSegDescFlags::None)
1279 return "none";
1280
1281 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
1282 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
1283 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
1284 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
1285 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
1286 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
1287 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
Zachary Turner47d9a562017-06-16 00:04:24 +00001288 return typesetItemList(Opts, IndentLevel, 4, " | ");
Zachary Turner63055452017-06-15 22:24:24 +00001289}
1290
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001291Error DumpOutputStyle::dumpSectionHeaders() {
1292 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1293 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1294 return Error::success();
1295}
1296
Zachary Turner92e584c2017-08-04 21:10:04 +00001297static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
1298 ArrayRef<llvm::object::coff_section>>>
1299loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
1300 if (!File.hasPDBDbiStream())
1301 return make_error<StringError>(
1302 "Section headers require a DBI Stream, which could not be loaded",
1303 inconvertibleErrorCode());
1304
1305 auto &Dbi = cantFail(File.getPDBDbiStream());
1306 uint32_t SI = Dbi.getDebugStreamIndex(Type);
1307
1308 if (SI == kInvalidStreamIndex)
1309 return make_error<StringError>(
1310 "PDB does not contain the requested image section header type",
1311 inconvertibleErrorCode());
1312
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001313 auto Stream = File.createIndexedStream(SI);
Zachary Turner92e584c2017-08-04 21:10:04 +00001314 if (!Stream)
1315 return make_error<StringError>("Could not load the required stream data",
1316 inconvertibleErrorCode());
1317
1318 ArrayRef<object::coff_section> Headers;
1319 if (Stream->getLength() % sizeof(object::coff_section) != 0)
1320 return make_error<StringError>(
1321 "Section header array size is not a multiple of section header size",
1322 inconvertibleErrorCode());
1323
1324 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
1325 BinaryStreamReader Reader(*Stream);
1326 cantFail(Reader.readArray(Headers, NumHeaders));
1327 return std::make_pair(std::move(Stream), Headers);
1328}
1329
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001330void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1331 printHeader(P, Label);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001332
1333 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001334 if (File.isObj()) {
1335 P.formatLine("Dumping Section Headers is not supported for object files");
1336 return;
1337 }
1338
1339 ExitOnError Err("Error dumping section headers: ");
Zachary Turner92e584c2017-08-04 21:10:04 +00001340 std::unique_ptr<MappedBlockStream> Stream;
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001341 ArrayRef<object::coff_section> Headers;
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001342 auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
Zachary Turner92e584c2017-08-04 21:10:04 +00001343 if (!ExpectedHeaders) {
1344 P.printLine(toString(ExpectedHeaders.takeError()));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001345 return;
1346 }
Zachary Turner92e584c2017-08-04 21:10:04 +00001347 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001348
1349 uint32_t I = 1;
1350 for (const auto &Header : Headers) {
1351 P.NewLine();
1352 P.formatLine("SECTION HEADER #{0}", I);
1353 P.formatLine("{0,8} name", Header.Name);
1354 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1355 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1356 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1357 P.formatLine("{0,8:X-} file pointer to raw data",
1358 uint32_t(Header.PointerToRawData));
1359 P.formatLine("{0,8:X-} file pointer to relocation table",
1360 uint32_t(Header.PointerToRelocations));
1361 P.formatLine("{0,8:X-} file pointer to line numbers",
1362 uint32_t(Header.PointerToLinenumbers));
1363 P.formatLine("{0,8:X-} number of relocations",
1364 uint32_t(Header.NumberOfRelocations));
1365 P.formatLine("{0,8:X-} number of line numbers",
1366 uint32_t(Header.NumberOfLinenumbers));
1367 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1368 AutoIndent IndentMore(P, 9);
1369 P.formatLine("{0}", formatSectionCharacteristics(
1370 P.getIndentLevel(), Header.Characteristics, 1, ""));
1371 ++I;
1372 }
1373 return;
1374}
1375
Zachary Turner92e584c2017-08-04 21:10:04 +00001376std::vector<std::string> getSectionNames(PDBFile &File) {
1377 auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
1378 if (!ExpectedHeaders)
1379 return {};
1380
1381 std::unique_ptr<MappedBlockStream> Stream;
1382 ArrayRef<object::coff_section> Headers;
1383 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1384 std::vector<std::string> Names;
1385 for (const auto &H : Headers)
1386 Names.push_back(H.Name);
1387 return Names;
1388}
1389
Zachary Turner7df69952017-06-22 20:57:39 +00001390Error DumpOutputStyle::dumpSectionContribs() {
Zachary Turner63055452017-06-15 22:24:24 +00001391 printHeader(P, "Section Contributions");
Zachary Turner63055452017-06-15 22:24:24 +00001392
1393 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001394 if (File.isObj()) {
1395 P.formatLine(
1396 "Dumping section contributions is not supported for object files");
1397 return Error::success();
1398 }
1399
1400 ExitOnError Err("Error dumping section contributions: ");
1401 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001402 P.formatLine(
1403 "Section contribs require a DBI Stream, which could not be loaded");
1404 return Error::success();
1405 }
1406
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001407 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001408
1409 class Visitor : public ISectionContribVisitor {
1410 public:
Zachary Turner92e584c2017-08-04 21:10:04 +00001411 Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
1412 auto Max = std::max_element(
1413 Names.begin(), Names.end(),
1414 [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
1415 MaxNameLen = (Max == Names.end() ? 0 : Max->size());
1416 }
Zachary Turner63055452017-06-15 22:24:24 +00001417 void visit(const SectionContrib &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001418 assert(SC.ISect > 0);
Zachary Turner489a7a02017-08-07 20:24:01 +00001419 std::string NameInsert;
1420 if (SC.ISect < Names.size()) {
1421 StringRef SectionName = Names[SC.ISect - 1];
1422 NameInsert = formatv("[{0}]", SectionName).str();
1423 } else
1424 NameInsert = "[???]";
Zachary Turner92e584c2017-08-04 21:10:04 +00001425 P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1426 "crc = {4}",
1427 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
1428 fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
1429 fmt_align(NameInsert, AlignStyle::Left, MaxNameLen + 2));
1430 AutoIndent Indent(P, MaxNameLen + 2);
Zachary Turner63055452017-06-15 22:24:24 +00001431 P.formatLine(" {0}",
1432 formatSectionCharacteristics(P.getIndentLevel() + 6,
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001433 SC.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001434 }
1435 void visit(const SectionContrib2 &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001436 P.formatLine(
1437 "SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1438 "crc = {4}, coff section = {5}",
1439 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), fmtle(SC.Base.Size),
1440 fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1441 fmtle(SC.ISectCoff));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001442 P.formatLine(" {0}", formatSectionCharacteristics(
1443 P.getIndentLevel() + 6,
1444 SC.Base.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001445 }
1446
1447 private:
1448 LinePrinter &P;
Zachary Turner92e584c2017-08-04 21:10:04 +00001449 uint32_t MaxNameLen;
1450 ArrayRef<std::string> Names;
Zachary Turner63055452017-06-15 22:24:24 +00001451 };
1452
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001453 std::vector<std::string> Names = getSectionNames(getPdb());
Zachary Turner92e584c2017-08-04 21:10:04 +00001454 Visitor V(P, makeArrayRef(Names));
Zachary Turner63055452017-06-15 22:24:24 +00001455 Dbi.visitSectionContributions(V);
1456 return Error::success();
1457}
1458
Zachary Turner7df69952017-06-22 20:57:39 +00001459Error DumpOutputStyle::dumpSectionMap() {
Zachary Turner63055452017-06-15 22:24:24 +00001460 printHeader(P, "Section Map");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001461 AutoIndent Indent(P);
1462
1463 if (File.isObj()) {
1464 P.formatLine("Dumping section map is not supported for object files");
1465 return Error::success();
1466 }
1467
Reid Klecknerdd853e52017-07-27 23:13:18 +00001468 ExitOnError Err("Error dumping section map: ");
Zachary Turner63055452017-06-15 22:24:24 +00001469
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001470 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001471 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1472 "not be loaded");
1473 return Error::success();
1474 }
1475
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001476 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001477
1478 uint32_t I = 0;
1479 for (auto &M : Dbi.getSectionMap()) {
1480 P.formatLine(
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001481 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
Zachary Turner63055452017-06-15 22:24:24 +00001482 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1483 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1484 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1485 P.formatLine(" flags = {0}",
1486 formatSegMapDescriptorFlag(
1487 P.getIndentLevel() + 13,
1488 static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1489 ++I;
1490 }
1491 return Error::success();
1492}