blob: 710e0348481fb1452bdcd279ac420d45adbd4548 [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 Turner376d4372017-12-05 23:58:18 +000041#include "llvm/DebugInfo/CodeView/TypeHashing.h"
Zachary Turner02a26772017-06-30 18:15:47 +000042#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
Zachary Turner63055452017-06-15 22:24:24 +000043#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
44#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
45#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
46#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
47#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
48#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
49#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
50#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
51#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
52#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
53#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
54#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turner376d4372017-12-05 23:58:18 +000055#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
Zachary Turner63055452017-06-15 22:24:24 +000056#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
57#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
58#include "llvm/DebugInfo/PDB/PDBExtras.h"
59#include "llvm/Object/COFF.h"
60#include "llvm/Support/BinaryStreamReader.h"
61#include "llvm/Support/FormatAdapters.h"
62#include "llvm/Support/FormatVariadic.h"
63
Zachary Turner99c69822017-08-31 20:43:22 +000064#include <cctype>
Zachary Turner63055452017-06-15 22:24:24 +000065#include <unordered_map>
66
67using namespace llvm;
68using namespace llvm::codeview;
69using namespace llvm::msf;
70using namespace llvm::pdb;
71
Zachary Turnerabb17cc2017-09-01 20:06:56 +000072DumpOutputStyle::DumpOutputStyle(InputFile &File)
Zachary Turner63055452017-06-15 22:24:24 +000073 : File(File), P(2, false, outs()) {}
74
Zachary Turnerabb17cc2017-09-01 20:06:56 +000075PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
76object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
77
Zachary Turner7df69952017-06-22 20:57:39 +000078Error DumpOutputStyle::dump() {
79 if (opts::dump::DumpSummary) {
Zachary Turner63055452017-06-15 22:24:24 +000080 if (auto EC = dumpFileSummary())
81 return EC;
82 P.NewLine();
83 }
84
Zachary Turner7df69952017-06-22 20:57:39 +000085 if (opts::dump::DumpStreams) {
Zachary Turner63055452017-06-15 22:24:24 +000086 if (auto EC = dumpStreamSummary())
87 return EC;
88 P.NewLine();
89 }
90
Zachary Turnerabb17cc2017-09-01 20:06:56 +000091 if (opts::dump::DumpSymbolStats) {
Zachary Turner99c69822017-08-31 20:43:22 +000092 if (auto EC = dumpSymbolStats())
93 return EC;
94 P.NewLine();
95 }
96
Zachary Turnerabb17cc2017-09-01 20:06:56 +000097 if (opts::dump::DumpUdtStats) {
Zachary Turner99c69822017-08-31 20:43:22 +000098 if (auto EC = dumpUdtStats())
Zachary Turnerd1de2f42017-08-21 14:53:25 +000099 return EC;
100 P.NewLine();
101 }
102
Zachary Turner7df69952017-06-22 20:57:39 +0000103 if (opts::dump::DumpStringTable) {
Zachary Turner63055452017-06-15 22:24:24 +0000104 if (auto EC = dumpStringTable())
105 return EC;
106 P.NewLine();
107 }
108
Zachary Turner7df69952017-06-22 20:57:39 +0000109 if (opts::dump::DumpModules) {
Zachary Turner63055452017-06-15 22:24:24 +0000110 if (auto EC = dumpModules())
111 return EC;
112 }
113
Zachary Turner7df69952017-06-22 20:57:39 +0000114 if (opts::dump::DumpModuleFiles) {
Zachary Turner0e327d02017-06-15 23:12:41 +0000115 if (auto EC = dumpModuleFiles())
116 return EC;
117 }
118
Zachary Turner7df69952017-06-22 20:57:39 +0000119 if (opts::dump::DumpLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000120 if (auto EC = dumpLines())
121 return EC;
122 }
123
Zachary Turner7df69952017-06-22 20:57:39 +0000124 if (opts::dump::DumpInlineeLines) {
Zachary Turner4e950642017-06-15 23:56:19 +0000125 if (auto EC = dumpInlineeLines())
126 return EC;
127 }
128
Zachary Turner7df69952017-06-22 20:57:39 +0000129 if (opts::dump::DumpXmi) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000130 if (auto EC = dumpXmi())
131 return EC;
132 }
133
Zachary Turner7df69952017-06-22 20:57:39 +0000134 if (opts::dump::DumpXme) {
Zachary Turner47d9a562017-06-16 00:04:24 +0000135 if (auto EC = dumpXme())
136 return EC;
137 }
138
Zachary Turner376d4372017-12-05 23:58:18 +0000139 if (File.isObj()) {
140 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
141 opts::dump::DumpTypeExtras)
142 if (auto EC = dumpTypesFromObjectFile())
143 return EC;
144 } else {
145 if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
146 opts::dump::DumpTypeExtras) {
147 if (auto EC = dumpTpiStream(StreamTPI))
148 return EC;
149 }
Zachary Turner63055452017-06-15 22:24:24 +0000150
Zachary Turner376d4372017-12-05 23:58:18 +0000151 if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
152 opts::dump::DumpIdExtras) {
153 if (auto EC = dumpTpiStream(StreamIPI))
154 return EC;
155 }
Zachary Turner63055452017-06-15 22:24:24 +0000156 }
157
Reid Kleckner14d90fd2017-07-26 00:40:36 +0000158 if (opts::dump::DumpGlobals) {
159 if (auto EC = dumpGlobals())
160 return EC;
161 }
162
Zachary Turner7df69952017-06-22 20:57:39 +0000163 if (opts::dump::DumpPublics) {
Zachary Turner63055452017-06-15 22:24:24 +0000164 if (auto EC = dumpPublics())
165 return EC;
166 }
167
Zachary Turner7df69952017-06-22 20:57:39 +0000168 if (opts::dump::DumpSymbols) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000169 auto EC = File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj();
170 if (EC)
Zachary Turner63055452017-06-15 22:24:24 +0000171 return EC;
172 }
173
Zachary Turnerfb1cd502017-08-04 20:02:38 +0000174 if (opts::dump::DumpSectionHeaders) {
175 if (auto EC = dumpSectionHeaders())
176 return EC;
177 }
178
Zachary Turner7df69952017-06-22 20:57:39 +0000179 if (opts::dump::DumpSectionContribs) {
Zachary Turner63055452017-06-15 22:24:24 +0000180 if (auto EC = dumpSectionContribs())
181 return EC;
182 }
183
Zachary Turner7df69952017-06-22 20:57:39 +0000184 if (opts::dump::DumpSectionMap) {
Zachary Turner63055452017-06-15 22:24:24 +0000185 if (auto EC = dumpSectionMap())
186 return EC;
187 }
188
189 return Error::success();
190}
191
192static void printHeader(LinePrinter &P, const Twine &S) {
193 P.NewLine();
194 P.formatLine("{0,=60}", S);
195 P.formatLine("{0}", fmt_repeat('=', 60));
196}
197
Zachary Turner7df69952017-06-22 20:57:39 +0000198Error DumpOutputStyle::dumpFileSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000199 printHeader(P, "Summary");
200
Reid Klecknerdd853e52017-07-27 23:13:18 +0000201 ExitOnError Err("Invalid PDB Format: ");
Zachary Turner63055452017-06-15 22:24:24 +0000202
203 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000204 if (File.isObj()) {
205 P.formatLine("Dumping File summary is not valid for object files");
206 return Error::success();
207 }
Zachary Turner63055452017-06-15 22:24:24 +0000208
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000209 P.formatLine("Block Size: {0}", getPdb().getBlockSize());
210 P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
211 P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
212
213 auto &PS = Err(getPdb().getPDBInfoStream());
Zachary Turner63055452017-06-15 22:24:24 +0000214 P.formatLine("Signature: {0}", PS.getSignature());
215 P.formatLine("Age: {0}", PS.getAge());
216 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
217 P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000218 P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
219 P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
220 P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
221 P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
222 P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
223 if (getPdb().hasPDBDbiStream()) {
224 auto &DBI = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +0000225 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
226 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
227 P.formatLine("Is stripped: {0}", DBI.isStripped());
228 }
229
230 return Error::success();
231}
232
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000233static StatCollection getSymbolStats(const SymbolGroup &SG,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000234 StatCollection &CumulativeStats) {
235 StatCollection Stats;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000236 if (SG.getFile().isPdb()) {
237 // For PDB files, all symbols are packed into one stream.
238 for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
239 Stats.update(S.kind(), S.length());
240 CumulativeStats.update(S.kind(), S.length());
241 }
242 return Stats;
243 }
244
245 for (const auto &SS : SG.getDebugSubsections()) {
246 // For object files, all symbols are spread across multiple Symbol
247 // subsections of a given .debug$S section.
248 if (SS.kind() != DebugSubsectionKind::Symbols)
249 continue;
250 DebugSymbolsSubsectionRef Symbols;
251 BinaryStreamReader Reader(SS.getRecordData());
252 cantFail(Symbols.initialize(Reader));
253 for (const auto &S : Symbols) {
254 Stats.update(S.kind(), S.length());
255 CumulativeStats.update(S.kind(), S.length());
256 }
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000257 }
258 return Stats;
259}
260
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000261static StatCollection getChunkStats(const SymbolGroup &SG,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000262 StatCollection &CumulativeStats) {
263 StatCollection Stats;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000264 for (const auto &Chunk : SG.getDebugSubsections()) {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000265 Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
266 CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
267 }
268 return Stats;
269}
270
271static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
272 return formatChunkKind(K, false);
273}
274
275static inline std::string formatModuleDetailKind(SymbolKind K) {
276 return formatSymbolKind(K);
277}
278
279template <typename Kind>
280static void printModuleDetailStats(LinePrinter &P, StringRef Label,
281 const StatCollection &Stats) {
282 P.NewLine();
283 P.formatLine(" {0}", Label);
284 AutoIndent Indent(P);
285 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", "Total",
286 Stats.Totals.Count, Stats.Totals.Size);
287 P.formatLine("{0}", fmt_repeat('-', 74));
288 for (const auto &K : Stats.Individual) {
289 std::string KindName = formatModuleDetailKind(Kind(K.first));
290 P.formatLine("{0,40}: {1,7} entries ({2,8} bytes)", KindName,
291 K.second.Count, K.second.Size);
292 }
293}
294
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000295static bool isMyCode(const SymbolGroup &Group) {
296 if (Group.getFile().isObj())
297 return true;
298
299 StringRef Name = Group.name();
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000300 if (Name.startswith("Import:"))
301 return false;
302 if (Name.endswith_lower(".dll"))
303 return false;
304 if (Name.equals_lower("* linker *"))
305 return false;
306 if (Name.startswith_lower("f:\\binaries\\Intermediate\\vctools"))
307 return false;
308 if (Name.startswith_lower("f:\\dd\\vctools\\crt"))
309 return false;
310 return true;
311}
312
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000313static bool shouldDumpSymbolGroup(uint32_t Idx, const SymbolGroup &Group) {
314 if (opts::dump::JustMyCode && !isMyCode(Group))
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000315 return false;
316
317 // If the arg was not specified on the command line, always dump all modules.
318 if (opts::dump::DumpModi.getNumOccurrences() == 0)
319 return true;
320
321 // Otherwise, only dump if this is the same module specified.
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000322 return (opts::dump::DumpModi == Idx);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000323}
324
Zachary Turner7df69952017-06-22 20:57:39 +0000325Error DumpOutputStyle::dumpStreamSummary() {
Zachary Turner63055452017-06-15 22:24:24 +0000326 printHeader(P, "Streams");
327
Zachary Turner63055452017-06-15 22:24:24 +0000328 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000329 if (File.isObj()) {
330 P.formatLine("Dumping streams is not valid for object files");
331 return Error::success();
332 }
333
334 if (StreamPurposes.empty())
335 discoverStreamPurposes(getPdb(), StreamPurposes);
336
337 uint32_t StreamCount = getPdb().getNumStreams();
338 uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
Zachary Turner63055452017-06-15 22:24:24 +0000339
340 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
341 P.formatLine(
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000342 "Stream {0} ({1} bytes): [{2}]",
Zachary Turner63055452017-06-15 22:24:24 +0000343 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000344 fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000345 NumDigits(MaxStreamSize)),
346 StreamPurposes[StreamIdx].getLongName());
347
Zachary Turner5f098522017-06-23 20:28:14 +0000348 if (opts::dump::DumpStreamBlocks) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000349 auto Blocks = getPdb().getStreamBlockList(StreamIdx);
Zachary Turner5f098522017-06-23 20:28:14 +0000350 std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
351 P.formatLine(" {0} Blocks: [{1}]",
352 fmt_repeat(' ', NumDigits(StreamCount)),
353 make_range(BV.begin(), BV.end()));
354 }
Zachary Turner63055452017-06-15 22:24:24 +0000355 }
356
357 return Error::success();
358}
359
Zachary Turner0e327d02017-06-15 23:12:41 +0000360static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
361 uint32_t Index) {
Reid Klecknerdd853e52017-07-27 23:13:18 +0000362 ExitOnError Err("Unexpected error: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000363
364 auto &Dbi = Err(File.getPDBDbiStream());
365 const auto &Modules = Dbi.modules();
366 auto Modi = Modules.getModuleDescriptor(Index);
367
368 uint16_t ModiStream = Modi.getModuleStreamIndex();
369 if (ModiStream == kInvalidStreamIndex)
370 return make_error<RawError>(raw_error_code::no_stream,
371 "Module stream not present");
372
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000373 auto ModStreamData = File.createIndexedStream(ModiStream);
Zachary Turner0e327d02017-06-15 23:12:41 +0000374
375 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
376 if (auto EC = ModS.reload())
377 return make_error<RawError>(raw_error_code::corrupt_file,
378 "Invalid module stream");
379
380 return std::move(ModS);
381}
382
Zachary Turnerf2872b92017-06-15 23:59:56 +0000383template <typename CallbackT>
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000384static void
385iterateOneModule(InputFile &File, const Optional<PrintScope> &HeaderScope,
386 const SymbolGroup &SG, uint32_t Modi, CallbackT Callback) {
387 if (HeaderScope) {
388 HeaderScope->P.formatLine(
389 "Mod {0:4} | `{1}`: ",
390 fmt_align(Modi, AlignStyle::Right, HeaderScope->LabelWidth), SG.name());
391 }
Zachary Turner58699362017-08-03 23:11:52 +0000392
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000393 AutoIndent Indent(HeaderScope);
394 Callback(Modi, SG);
Zachary Turner58699362017-08-03 23:11:52 +0000395}
396
397template <typename CallbackT>
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000398static void iterateSymbolGroups(InputFile &Input,
399 const Optional<PrintScope> &HeaderScope,
400 CallbackT Callback) {
401 AutoIndent Indent(HeaderScope);
Zachary Turnerf2872b92017-06-15 23:59:56 +0000402
Reid Klecknerdd853e52017-07-27 23:13:18 +0000403 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turnerf2872b92017-06-15 23:59:56 +0000404
Zachary Turner58699362017-08-03 23:11:52 +0000405 if (opts::dump::DumpModi.getNumOccurrences() > 0) {
406 assert(opts::dump::DumpModi.getNumOccurrences() == 1);
407 uint32_t Modi = opts::dump::DumpModi;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000408 SymbolGroup SG(&Input, Modi);
409 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(Modi)), SG,
410 Modi, Callback);
Zachary Turner58699362017-08-03 23:11:52 +0000411 return;
412 }
413
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000414 uint32_t I = 0;
415
416 for (const auto &SG : Input.symbol_groups()) {
417 if (shouldDumpSymbolGroup(I, SG))
418 iterateOneModule(Input, withLabelWidth(HeaderScope, NumDigits(I)), SG, I,
419 Callback);
420
421 ++I;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000422 }
423}
424
425template <typename SubsectionT>
426static void iterateModuleSubsections(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000427 InputFile &File, const Optional<PrintScope> &HeaderScope,
428 llvm::function_ref<void(uint32_t, const SymbolGroup &, SubsectionT &)>
Zachary Turnerf2872b92017-06-15 23:59:56 +0000429 Callback) {
430
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000431 iterateSymbolGroups(File, HeaderScope,
432 [&](uint32_t Modi, const SymbolGroup &SG) {
433 for (const auto &SS : SG.getDebugSubsections()) {
434 SubsectionT Subsection;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000435
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000436 if (SS.kind() != Subsection.kind())
437 continue;
Zachary Turnerf2872b92017-06-15 23:59:56 +0000438
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000439 BinaryStreamReader Reader(SS.getRecordData());
440 if (auto EC = Subsection.initialize(Reader))
441 continue;
442 Callback(Modi, SG, Subsection);
443 }
444 });
Zachary Turnerf2872b92017-06-15 23:59:56 +0000445}
446
Zachary Turner7df69952017-06-22 20:57:39 +0000447Error DumpOutputStyle::dumpModules() {
Zachary Turner63055452017-06-15 22:24:24 +0000448 printHeader(P, "Modules");
Zachary Turner63055452017-06-15 22:24:24 +0000449 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000450
451 if (File.isObj()) {
452 P.formatLine("Dumping modules is not supported for object files");
453 return Error::success();
454 }
455
456 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +0000457 P.formatLine("DBI Stream not present");
458 return Error::success();
459 }
460
Reid Klecknerdd853e52017-07-27 23:13:18 +0000461 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner63055452017-06-15 22:24:24 +0000462
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000463 auto &Stream = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +0000464
465 const DbiModuleList &Modules = Stream.modules();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000466 iterateSymbolGroups(
467 File, PrintScope{P, 11}, [&](uint32_t Modi, const SymbolGroup &Strings) {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000468 auto Desc = Modules.getModuleDescriptor(Modi);
469 P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
470 P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
471 Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
472 Desc.hasECInfo());
473 StringRef PdbFilePath =
474 Err(Stream.getECName(Desc.getPdbFilePathNameIndex()));
475 StringRef SrcFilePath =
476 Err(Stream.getECName(Desc.getSourceFileNameIndex()));
477 P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
478 Desc.getPdbFilePathNameIndex(), PdbFilePath,
479 Desc.getSourceFileNameIndex(), SrcFilePath);
480 });
Zachary Turner0e327d02017-06-15 23:12:41 +0000481 return Error::success();
482}
483
Zachary Turner7df69952017-06-22 20:57:39 +0000484Error DumpOutputStyle::dumpModuleFiles() {
Zachary Turner0e327d02017-06-15 23:12:41 +0000485 printHeader(P, "Files");
486
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000487 if (File.isObj()) {
488 P.formatLine("Dumping files is not valid for object files");
489 return Error::success();
490 }
491
Reid Klecknerdd853e52017-07-27 23:13:18 +0000492 ExitOnError Err("Unexpected error processing modules: ");
Zachary Turner0e327d02017-06-15 23:12:41 +0000493
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000494 iterateSymbolGroups(File, PrintScope{P, 11},
495 [this, &Err](uint32_t Modi, const SymbolGroup &Strings) {
496 auto &Stream = Err(getPdb().getPDBDbiStream());
Zachary Turner0e327d02017-06-15 23:12:41 +0000497
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000498 const DbiModuleList &Modules = Stream.modules();
499 for (const auto &F : Modules.source_files(Modi)) {
500 Strings.formatFromFileName(P, F);
501 }
502 });
Zachary Turner4e950642017-06-15 23:56:19 +0000503 return Error::success();
504}
505
Zachary Turner99c69822017-08-31 20:43:22 +0000506Error DumpOutputStyle::dumpSymbolStats() {
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000507 printHeader(P, "Module Stats");
508
509 ExitOnError Err("Unexpected error processing modules: ");
510
511 StatCollection SymStats;
512 StatCollection ChunkStats;
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000513
Zachary Turner41f07062017-09-01 20:17:20 +0000514 Optional<PrintScope> Scope;
515 if (File.isPdb())
516 Scope.emplace(P, 2);
517
518 iterateSymbolGroups(File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000519 StatCollection SS = getSymbolStats(SG, SymStats);
520 StatCollection CS = getChunkStats(SG, ChunkStats);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000521
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000522 if (SG.getFile().isPdb()) {
Zachary Turner41f07062017-09-01 20:17:20 +0000523 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000524 auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
525 uint32_t ModCount = Modules.getModuleCount();
526 DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
527 uint32_t StreamIdx = Desc.getModuleStreamIndex();
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000528
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000529 if (StreamIdx == kInvalidStreamIndex) {
530 P.formatLine("Mod {0} (debug info not present): [{1}]",
531 fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
532 Desc.getModuleName());
533 return;
534 }
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000535 P.formatLine("Stream {0}, {1} bytes", StreamIdx,
536 getPdb().getStreamByteSize(StreamIdx));
537
538 printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
539 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000540 }
Zachary Turnerd1de2f42017-08-21 14:53:25 +0000541 });
542
543 P.printLine(" Summary |");
544 AutoIndent Indent(P, 4);
545 if (SymStats.Totals.Count > 0) {
546 printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
547 printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
548 }
549
550 return Error::success();
551}
552
Zachary Turner99c69822017-08-31 20:43:22 +0000553static bool isValidNamespaceIdentifier(StringRef S) {
554 if (S.empty())
555 return false;
556
557 if (std::isdigit(S[0]))
558 return false;
559
560 return llvm::all_of(S, [](char C) { return std::isalnum(C); });
561}
562
563namespace {
564constexpr uint32_t kNoneUdtKind = 0;
565constexpr uint32_t kSimpleUdtKind = 1;
566constexpr uint32_t kUnknownUdtKind = 2;
567const StringRef NoneLabel("<none type>");
568const StringRef SimpleLabel("<simple type>");
569const StringRef UnknownLabel("<unknown type>");
570
571} // namespace
572
573static StringRef getUdtStatLabel(uint32_t Kind) {
574 if (Kind == kNoneUdtKind)
575 return NoneLabel;
576
577 if (Kind == kSimpleUdtKind)
578 return SimpleLabel;
579
580 if (Kind == kUnknownUdtKind)
581 return UnknownLabel;
582
583 return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
584}
585
586static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
587 size_t L = 0;
588 for (const auto &Stat : Stats.Individual) {
589 StringRef Label = getUdtStatLabel(Stat.first);
590 L = std::max(L, Label.size());
591 }
592 return static_cast<uint32_t>(L);
593}
594
595Error DumpOutputStyle::dumpUdtStats() {
596 printHeader(P, "S_UDT Record Stats");
597
598 StatCollection UdtStats;
599 StatCollection UdtTargetStats;
Zachary Turner99c69822017-08-31 20:43:22 +0000600 AutoIndent Indent(P, 4);
601
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000602 auto &TpiTypes = File.types();
Zachary Turner99c69822017-08-31 20:43:22 +0000603
604 StringMap<StatCollection::Stat> NamespacedStats;
605
Zachary Turner99c69822017-08-31 20:43:22 +0000606 size_t LongestNamespace = 0;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000607 auto HandleOneSymbol = [&](const CVSymbol &Sym) {
Zachary Turner99c69822017-08-31 20:43:22 +0000608 if (Sym.kind() != SymbolKind::S_UDT)
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000609 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000610 UdtStats.update(SymbolKind::S_UDT, Sym.length());
611
612 UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
613
614 uint32_t Kind = 0;
615 uint32_t RecordSize = 0;
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000616
617 if (UDT.Type.isNoneType())
618 Kind = kNoneUdtKind;
619 else if (UDT.Type.isSimple())
620 Kind = kSimpleUdtKind;
621 else if (Optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
622 Kind = T->kind();
623 RecordSize = T->length();
624 } else
625 Kind = kUnknownUdtKind;
Zachary Turner99c69822017-08-31 20:43:22 +0000626
627 UdtTargetStats.update(Kind, RecordSize);
628
629 size_t Pos = UDT.Name.find("::");
630 if (Pos == StringRef::npos)
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000631 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000632
633 StringRef Scope = UDT.Name.take_front(Pos);
634 if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000635 return;
Zachary Turner99c69822017-08-31 20:43:22 +0000636
637 LongestNamespace = std::max(LongestNamespace, Scope.size());
638 NamespacedStats[Scope].update(RecordSize);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000639 };
640
641 P.NewLine();
642
643 if (File.isPdb()) {
644 if (!getPdb().hasPDBGlobalsStream()) {
645 P.printLine("- Error: globals stream not present");
646 return Error::success();
647 }
648
649 auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
Reid Kleckner145090f2017-10-27 00:45:51 +0000650 auto ExpGlobals = getPdb().getPDBGlobalsStream();
651 if (!ExpGlobals)
652 return ExpGlobals.takeError();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000653
Reid Kleckner145090f2017-10-27 00:45:51 +0000654 for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000655 CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
656 HandleOneSymbol(Sym);
657 }
658 } else {
659 for (const auto &Sec : File.symbol_groups()) {
660 for (const auto &SS : Sec.getDebugSubsections()) {
661 if (SS.kind() != DebugSubsectionKind::Symbols)
662 continue;
663
664 DebugSymbolsSubsectionRef Symbols;
665 BinaryStreamReader Reader(SS.getRecordData());
666 cantFail(Symbols.initialize(Reader));
667 for (const auto &S : Symbols)
668 HandleOneSymbol(S);
669 }
670 }
Zachary Turner99c69822017-08-31 20:43:22 +0000671 }
672
673 LongestNamespace += StringRef(" namespace ''").size();
Zachary Turner4c806612017-08-31 20:50:25 +0000674 size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
675 size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
Zachary Turner99c69822017-08-31 20:43:22 +0000676
677 // Compute the max number of digits for count and size fields, including comma
678 // separators.
679 StringRef CountHeader("Count");
680 StringRef SizeHeader("Size");
Zachary Turner4c806612017-08-31 20:50:25 +0000681 size_t CD = NumDigits(UdtStats.Totals.Count);
Zachary Turner99c69822017-08-31 20:43:22 +0000682 CD += (CD - 1) / 3;
683 CD = std::max(CD, CountHeader.size());
684
Zachary Turner4c806612017-08-31 20:50:25 +0000685 size_t SD = NumDigits(UdtStats.Totals.Size);
Zachary Turner99c69822017-08-31 20:43:22 +0000686 SD += (SD - 1) / 3;
687 SD = std::max(SD, SizeHeader.size());
688
689 uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
690
691 P.formatLine("{0} | {1} {2}",
692 fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
693 fmt_align(CountHeader, AlignStyle::Right, CD),
694 fmt_align(SizeHeader, AlignStyle::Right, SD));
695
696 P.formatLine("{0}", fmt_repeat('-', TableWidth));
697 for (const auto &Stat : UdtTargetStats.Individual) {
698 StringRef Label = getUdtStatLabel(Stat.first);
699 P.formatLine("{0} | {1:N} {2:N}",
700 fmt_align(Label, AlignStyle::Right, FieldWidth),
701 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
702 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
703 }
704 P.formatLine("{0}", fmt_repeat('-', TableWidth));
705 P.formatLine("{0} | {1:N} {2:N}",
706 fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
707 fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
708 fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
709 P.formatLine("{0}", fmt_repeat('-', TableWidth));
710 for (const auto &Stat : NamespacedStats) {
711 std::string Label = formatv("namespace '{0}'", Stat.getKey());
712 P.formatLine("{0} | {1:N} {2:N}",
713 fmt_align(Label, AlignStyle::Right, FieldWidth),
714 fmt_align(Stat.second.Count, AlignStyle::Right, CD),
715 fmt_align(Stat.second.Size, AlignStyle::Right, SD));
716 }
717 return Error::success();
718}
719
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000720static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
721 const LineColumnEntry &E) {
Zachary Turner4e950642017-06-15 23:56:19 +0000722 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
723 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
724
725 // Let's try to keep it under 100 characters
726 constexpr uint32_t kMaxRowLength = 100;
727 // At least 3 spaces between columns.
728 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
729 uint32_t ItemsLeft = E.LineNumbers.size();
730 auto LineIter = E.LineNumbers.begin();
731 while (ItemsLeft != 0) {
732 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
733 for (uint32_t I = 0; I < RowColumns; ++I) {
734 LineInfo Line(LineIter->Flags);
735 std::string LineStr;
736 if (Line.isAlwaysStepInto())
737 LineStr = "ASI";
738 else if (Line.isNeverStepInto())
739 LineStr = "NSI";
Zachary Turner0e327d02017-06-15 23:12:41 +0000740 else
Zachary Turner4e950642017-06-15 23:56:19 +0000741 LineStr = utostr(Line.getStartLine());
742 char Statement = Line.isStatement() ? ' ' : '!';
743 P.format("{0} {1:X-} {2} ",
744 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
745 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
746 Statement);
747 ++LineIter;
748 --ItemsLeft;
Zachary Turner63055452017-06-15 22:24:24 +0000749 }
Zachary Turner4e950642017-06-15 23:56:19 +0000750 P.NewLine();
Zachary Turner63055452017-06-15 22:24:24 +0000751 }
Zachary Turner4e950642017-06-15 23:56:19 +0000752}
753
Zachary Turner7df69952017-06-22 20:57:39 +0000754Error DumpOutputStyle::dumpLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000755 printHeader(P, "Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000756
Zachary Turnerf2872b92017-06-15 23:59:56 +0000757 uint32_t LastModi = UINT32_MAX;
758 uint32_t LastNameIndex = UINT32_MAX;
759 iterateModuleSubsections<DebugLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000760 File, PrintScope{P, 4},
Zachary Turnerf2872b92017-06-15 23:59:56 +0000761 [this, &LastModi, &LastNameIndex](uint32_t Modi,
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000762 const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000763 DebugLinesSubsectionRef &Lines) {
764 uint16_t Segment = Lines.header()->RelocSegment;
765 uint32_t Begin = Lines.header()->RelocOffset;
766 uint32_t End = Begin + Lines.header()->CodeSize;
767 for (const auto &Block : Lines) {
768 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
769 LastModi = Modi;
770 LastNameIndex = Block.NameIndex;
771 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
Zachary Turner4e950642017-06-15 23:56:19 +0000772 }
773
Zachary Turnerf2872b92017-06-15 23:59:56 +0000774 AutoIndent Indent(P, 2);
775 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
776 uint32_t Count = Block.LineNumbers.size();
777 if (Lines.hasColumnInfo())
778 P.format("line/column/addr entries = {0}", Count);
779 else
780 P.format("line/addr entries = {0}", Count);
Zachary Turner4e950642017-06-15 23:56:19 +0000781
Zachary Turnerf2872b92017-06-15 23:59:56 +0000782 P.NewLine();
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000783 typesetLinesAndColumns(P, Begin, Block);
Zachary Turner4e950642017-06-15 23:56:19 +0000784 }
785 });
786
787 return Error::success();
788}
789
Zachary Turner7df69952017-06-22 20:57:39 +0000790Error DumpOutputStyle::dumpInlineeLines() {
Zachary Turner4e950642017-06-15 23:56:19 +0000791 printHeader(P, "Inlinee Lines");
Zachary Turner4e950642017-06-15 23:56:19 +0000792
Zachary Turnerf2872b92017-06-15 23:59:56 +0000793 iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000794 File, PrintScope{P, 2},
795 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turnerf2872b92017-06-15 23:59:56 +0000796 DebugInlineeLinesSubsectionRef &Lines) {
797 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
798 for (const auto &Entry : Lines) {
799 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
800 fmtle(Entry.Header->SourceLineNum));
801 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
Zachary Turner4e950642017-06-15 23:56:19 +0000802 }
Zachary Turnerf2872b92017-06-15 23:59:56 +0000803 P.NewLine();
Zachary Turner4e950642017-06-15 23:56:19 +0000804 });
805
Zachary Turner63055452017-06-15 22:24:24 +0000806 return Error::success();
807}
Zachary Turner0e327d02017-06-15 23:12:41 +0000808
Zachary Turner7df69952017-06-22 20:57:39 +0000809Error DumpOutputStyle::dumpXmi() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000810 printHeader(P, "Cross Module Imports");
811 iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000812 File, PrintScope{P, 2},
813 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000814 DebugCrossModuleImportsSubsectionRef &Imports) {
815 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
816
817 for (const auto &Xmi : Imports) {
818 auto ExpectedModule =
819 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
820 StringRef Module;
821 SmallString<32> ModuleStorage;
822 if (!ExpectedModule) {
823 Module = "(unknown module)";
824 consumeError(ExpectedModule.takeError());
825 } else
826 Module = *ExpectedModule;
827 if (Module.size() > 32) {
828 ModuleStorage = "...";
829 ModuleStorage += Module.take_back(32 - 3);
830 Module = ModuleStorage;
831 }
832 std::vector<std::string> TIs;
833 for (const auto I : Xmi.Imports)
834 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
835 std::string Result =
836 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
837 P.formatLine("{0,+32} | {1}", Module, Result);
838 }
839 });
840
841 return Error::success();
842}
843
Zachary Turner7df69952017-06-22 20:57:39 +0000844Error DumpOutputStyle::dumpXme() {
Zachary Turner47d9a562017-06-16 00:04:24 +0000845 printHeader(P, "Cross Module Exports");
846
847 iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000848 File, PrintScope{P, 2},
849 [this](uint32_t Modi, const SymbolGroup &Strings,
Zachary Turner47d9a562017-06-16 00:04:24 +0000850 DebugCrossModuleExportsSubsectionRef &Exports) {
851 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
852 for (const auto &Export : Exports) {
853 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
854 TypeIndex(Export.Global));
855 }
856 });
857
858 return Error::success();
859}
860
Zachary Turner7df69952017-06-22 20:57:39 +0000861Error DumpOutputStyle::dumpStringTable() {
Zachary Turner63055452017-06-15 22:24:24 +0000862 printHeader(P, "String Table");
863
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000864 if (File.isObj()) {
865 P.formatLine("Dumping string table is not supported for object files");
866 return Error::success();
867 }
868
Zachary Turner63055452017-06-15 22:24:24 +0000869 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +0000870 auto IS = getPdb().getStringTable();
Zachary Turner63055452017-06-15 22:24:24 +0000871 if (!IS) {
872 P.formatLine("Not present in file");
873 consumeError(IS.takeError());
874 return Error::success();
875 }
876
877 if (IS->name_ids().empty()) {
878 P.formatLine("Empty");
879 return Error::success();
880 }
881
882 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
883 uint32_t Digits = NumDigits(*MaxID);
884
885 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
886 "String");
887
888 std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
889 std::sort(SortedIDs.begin(), SortedIDs.end());
890 for (uint32_t I : SortedIDs) {
891 auto ES = IS->getStringForID(I);
892 llvm::SmallString<32> Str;
893 if (!ES) {
894 consumeError(ES.takeError());
895 Str = "Error reading string";
896 } else if (!ES->empty()) {
897 Str.append("'");
898 Str.append(*ES);
899 Str.append("'");
900 }
901
902 if (!Str.empty())
903 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
904 }
905 return Error::success();
906}
907
Zachary Turner02a26772017-06-30 18:15:47 +0000908static void buildDepSet(LazyRandomTypeCollection &Types,
909 ArrayRef<TypeIndex> Indices,
910 std::map<TypeIndex, CVType> &DepSet) {
911 SmallVector<TypeIndex, 4> DepList;
912 for (const auto &I : Indices) {
913 TypeIndex TI(I);
914 if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
915 continue;
916
917 CVType Type = Types.getType(TI);
918 DepSet[TI] = Type;
919 codeview::discoverTypeIndices(Type, DepList);
920 buildDepSet(Types, DepList, DepSet);
921 }
922}
923
Zachary Turner376d4372017-12-05 23:58:18 +0000924static void
925dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
Zachary Turner2ed069e2017-12-06 00:26:43 +0000926 uint32_t NumTypeRecords, uint32_t NumHashBuckets,
Zachary Turner376d4372017-12-05 23:58:18 +0000927 FixedStreamArray<support::ulittle32_t> HashValues,
928 bool Bytes, bool Extras) {
929
Zachary Turner2ed069e2017-12-06 00:26:43 +0000930 Printer.formatLine("Showing {0:N} records", NumTypeRecords);
931 uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
Zachary Turner02a26772017-06-30 18:15:47 +0000932
933 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Zachary Turner376d4372017-12-05 23:58:18 +0000934 NumHashBuckets, HashValues);
Zachary Turner02a26772017-06-30 18:15:47 +0000935
936 if (auto EC = codeview::visitTypeStream(Types, V)) {
937 Printer.formatLine("An error occurred dumping type records: {0}",
938 toString(std::move(EC)));
939 }
940}
941
942static void dumpPartialTypeStream(LinePrinter &Printer,
943 LazyRandomTypeCollection &Types,
944 TpiStream &Stream, ArrayRef<TypeIndex> TiList,
945 bool Bytes, bool Extras, bool Deps) {
946 uint32_t Width =
947 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
948
949 MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
Reid Klecknerc50349d2017-07-18 00:33:45 +0000950 Stream.getNumHashBuckets(), Stream.getHashValues());
Zachary Turner02a26772017-06-30 18:15:47 +0000951
952 if (opts::dump::DumpTypeDependents) {
953 // If we need to dump all dependents, then iterate each index and find
954 // all dependents, adding them to a map ordered by TypeIndex.
955 std::map<TypeIndex, CVType> DepSet;
956 buildDepSet(Types, TiList, DepSet);
957
958 Printer.formatLine(
959 "Showing {0:N} records and their dependents ({1:N} records total)",
960 TiList.size(), DepSet.size());
961
962 for (auto &Dep : DepSet) {
963 if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
964 Printer.formatLine("An error occurred dumping type record {0}: {1}",
965 Dep.first, toString(std::move(EC)));
966 }
967 } else {
968 Printer.formatLine("Showing {0:N} records.", TiList.size());
969
970 for (const auto &I : TiList) {
971 TypeIndex TI(I);
972 CVType Type = Types.getType(TI);
973 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
974 Printer.formatLine("An error occurred dumping type record {0}: {1}", TI,
975 toString(std::move(EC)));
976 }
977 }
978}
979
Zachary Turner376d4372017-12-05 23:58:18 +0000980Error DumpOutputStyle::dumpTypesFromObjectFile() {
981 LazyRandomTypeCollection Types(100);
982
983 for (const auto &S : getObj().sections()) {
984 StringRef SectionName;
985 if (auto EC = S.getName(SectionName))
986 return errorCodeToError(EC);
987
988 if (SectionName != ".debug$T")
989 continue;
990 StringRef Contents;
991 if (auto EC = S.getContents(Contents))
992 return errorCodeToError(EC);
993
994 uint32_t Magic;
995 BinaryStreamReader Reader(Contents, llvm::support::little);
996 if (auto EC = Reader.readInteger(Magic))
997 return EC;
998 if (Magic != COFF::DEBUG_SECTION_MAGIC)
999 return make_error<StringError>("Invalid CodeView debug section.",
1000 inconvertibleErrorCode());
1001
1002 Types.reset(Reader, 100);
1003
1004 if (opts::dump::DumpTypes) {
Zachary Turner2ed069e2017-12-06 00:26:43 +00001005 dumpFullTypeStream(P, Types, 0, 0, {}, opts::dump::DumpTypeData, false);
Zachary Turner376d4372017-12-05 23:58:18 +00001006 } else if (opts::dump::DumpTypeExtras) {
1007 auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
1008 auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
1009 assert(LocalHashes.size() == GlobalHashes.size());
1010
1011 P.formatLine("Local / Global hashes:");
1012 TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
1013 for (const auto &H : zip(LocalHashes, GlobalHashes)) {
1014 AutoIndent Indent2(P);
1015 LocallyHashedType &L = std::get<0>(H);
1016 GloballyHashedType &G = std::get<1>(H);
1017
1018 P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
1019
1020 ++TI;
1021 }
1022 P.NewLine();
1023 }
1024 }
1025
1026 return Error::success();
1027}
1028
Zachary Turner7df69952017-06-22 20:57:39 +00001029Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
Zachary Turner63055452017-06-15 22:24:24 +00001030 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
1031
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001032 if (StreamIdx == StreamTPI) {
1033 printHeader(P, "Types (TPI Stream)");
1034 } else if (StreamIdx == StreamIPI) {
1035 printHeader(P, "Types (IPI Stream)");
1036 }
1037
1038 AutoIndent Indent(P);
Zachary Turner376d4372017-12-05 23:58:18 +00001039 assert(!File.isObj());
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001040
Zachary Turner63055452017-06-15 22:24:24 +00001041 bool Present = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001042 bool DumpTypes = false;
Zachary Turner63055452017-06-15 22:24:24 +00001043 bool DumpBytes = false;
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001044 bool DumpExtras = false;
Zachary Turner59224cb2017-06-16 23:42:15 +00001045 std::vector<uint32_t> Indices;
Zachary Turner63055452017-06-15 22:24:24 +00001046 if (StreamIdx == StreamTPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001047 Present = getPdb().hasPDBTpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +00001048 DumpTypes = opts::dump::DumpTypes;
1049 DumpBytes = opts::dump::DumpTypeData;
1050 DumpExtras = opts::dump::DumpTypeExtras;
1051 Indices.assign(opts::dump::DumpTypeIndex.begin(),
1052 opts::dump::DumpTypeIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +00001053 } else if (StreamIdx == StreamIPI) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001054 Present = getPdb().hasPDBIpiStream();
Zachary Turner7df69952017-06-22 20:57:39 +00001055 DumpTypes = opts::dump::DumpIds;
1056 DumpBytes = opts::dump::DumpIdData;
1057 DumpExtras = opts::dump::DumpIdExtras;
1058 Indices.assign(opts::dump::DumpIdIndex.begin(),
1059 opts::dump::DumpIdIndex.end());
Zachary Turner63055452017-06-15 22:24:24 +00001060 }
1061
Zachary Turner63055452017-06-15 22:24:24 +00001062 if (!Present) {
1063 P.formatLine("Stream not present");
1064 return Error::success();
1065 }
1066
Reid Klecknerdd853e52017-07-27 23:13:18 +00001067 ExitOnError Err("Unexpected error processing types: ");
Zachary Turner63055452017-06-15 22:24:24 +00001068
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001069 auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
1070 : getPdb().getPDBIpiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001071
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001072 auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
Zachary Turner63055452017-06-15 22:24:24 +00001073
Zachary Turner02a26772017-06-30 18:15:47 +00001074 if (DumpTypes || !Indices.empty()) {
1075 if (Indices.empty())
Zachary Turner2ed069e2017-12-06 00:26:43 +00001076 dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
1077 Stream.getNumHashBuckets(), Stream.getHashValues(),
1078 DumpBytes, DumpExtras);
Zachary Turner02a26772017-06-30 18:15:47 +00001079 else {
1080 std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
1081 dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
1082 opts::dump::DumpTypeDependents);
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001083 }
1084 }
1085
1086 if (DumpExtras) {
1087 P.NewLine();
1088 auto IndexOffsets = Stream.getTypeIndexOffsets();
1089 P.formatLine("Type Index Offsets:");
1090 for (const auto &IO : IndexOffsets) {
1091 AutoIndent Indent2(P);
1092 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
1093 }
1094
1095 P.NewLine();
1096 P.formatLine("Hash Adjusters:");
1097 auto &Adjusters = Stream.getHashAdjusters();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001098 auto &Strings = Err(getPdb().getStringTable());
Zachary Turnerf8a2e042017-06-15 23:04:42 +00001099 for (const auto &A : Adjusters) {
1100 AutoIndent Indent2(P);
1101 auto ExpectedStr = Strings.getStringForID(A.first);
1102 TypeIndex TI(A.second);
1103 if (ExpectedStr)
1104 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
1105 else {
1106 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
1107 consumeError(ExpectedStr.takeError());
1108 }
1109 }
Zachary Turner63055452017-06-15 22:24:24 +00001110 }
1111 return Error::success();
1112}
1113
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001114Error DumpOutputStyle::dumpModuleSymsForObj() {
Zachary Turner63055452017-06-15 22:24:24 +00001115 printHeader(P, "Symbols");
1116
1117 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001118
1119 ExitOnError Err("Unexpected error processing symbols: ");
1120
1121 auto &Types = File.types();
1122
1123 SymbolVisitorCallbackPipeline Pipeline;
1124 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
1125 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
1126
1127 Pipeline.addCallbackToPipeline(Deserializer);
1128 Pipeline.addCallbackToPipeline(Dumper);
1129 CVSymbolVisitor Visitor(Pipeline);
1130
1131 std::unique_ptr<llvm::Error> SymbolError;
1132
1133 iterateModuleSubsections<DebugSymbolsSubsectionRef>(
1134 File, PrintScope{P, 2},
1135 [&](uint32_t Modi, const SymbolGroup &Strings,
1136 DebugSymbolsSubsectionRef &Symbols) {
1137 for (auto Symbol : Symbols) {
1138 if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
1139 SymbolError = llvm::make_unique<Error>(std::move(EC));
1140 return;
1141 }
1142 }
1143 });
1144
1145 if (SymbolError)
1146 return std::move(*SymbolError);
1147
1148 return Error::success();
1149}
1150
1151Error DumpOutputStyle::dumpModuleSymsForPdb() {
1152 printHeader(P, "Symbols");
1153
1154 AutoIndent Indent(P);
1155 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001156 P.formatLine("DBI Stream not present");
1157 return Error::success();
1158 }
1159
Reid Klecknerdd853e52017-07-27 23:13:18 +00001160 ExitOnError Err("Unexpected error processing symbols: ");
Zachary Turner63055452017-06-15 22:24:24 +00001161
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001162 auto &Ids = File.ids();
1163 auto &Types = File.types();
Zachary Turner63055452017-06-15 22:24:24 +00001164
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001165 iterateSymbolGroups(
1166 File, PrintScope{P, 2}, [&](uint32_t I, const SymbolGroup &Strings) {
1167 auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
Zachary Turner58699362017-08-03 23:11:52 +00001168 if (!ExpectedModS) {
1169 P.formatLine("Error loading module stream {0}. {1}", I,
1170 toString(ExpectedModS.takeError()));
1171 return;
1172 }
Zachary Turner63055452017-06-15 22:24:24 +00001173
Zachary Turner58699362017-08-03 23:11:52 +00001174 ModuleDebugStreamRef &ModS = *ExpectedModS;
Zachary Turner63055452017-06-15 22:24:24 +00001175
Zachary Turner58699362017-08-03 23:11:52 +00001176 SymbolVisitorCallbackPipeline Pipeline;
1177 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turner59e3ae82017-08-08 18:34:44 +00001178 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids,
1179 Types);
Zachary Turner63055452017-06-15 22:24:24 +00001180
Zachary Turner58699362017-08-03 23:11:52 +00001181 Pipeline.addCallbackToPipeline(Deserializer);
1182 Pipeline.addCallbackToPipeline(Dumper);
1183 CVSymbolVisitor Visitor(Pipeline);
1184 auto SS = ModS.getSymbolsSubstream();
1185 if (auto EC =
1186 Visitor.visitSymbolStream(ModS.getSymbolArray(), SS.Offset)) {
1187 P.formatLine("Error while processing symbol records. {0}",
1188 toString(std::move(EC)));
1189 return;
1190 }
1191 });
Zachary Turner63055452017-06-15 22:24:24 +00001192 return Error::success();
1193}
1194
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001195Error DumpOutputStyle::dumpGlobals() {
1196 printHeader(P, "Global Symbols");
1197 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001198
1199 if (File.isObj()) {
1200 P.formatLine("Dumping Globals is not supported for object files");
1201 return Error::success();
1202 }
1203
1204 if (!getPdb().hasPDBGlobalsStream()) {
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001205 P.formatLine("Globals stream not present");
1206 return Error::success();
1207 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001208 ExitOnError Err("Error dumping globals stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001209 auto &Globals = Err(getPdb().getPDBGlobalsStream());
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001210
1211 const GSIHashTable &Table = Globals.getGlobalsTable();
1212 Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1213 return Error::success();
1214}
1215
Zachary Turner7df69952017-06-22 20:57:39 +00001216Error DumpOutputStyle::dumpPublics() {
Zachary Turner63055452017-06-15 22:24:24 +00001217 printHeader(P, "Public Symbols");
Zachary Turner63055452017-06-15 22:24:24 +00001218 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001219
1220 if (File.isObj()) {
1221 P.formatLine("Dumping Globals is not supported for object files");
1222 return Error::success();
1223 }
1224
1225 if (!getPdb().hasPDBPublicsStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001226 P.formatLine("Publics stream not present");
1227 return Error::success();
1228 }
Reid Klecknerdd853e52017-07-27 23:13:18 +00001229 ExitOnError Err("Error dumping publics stream: ");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001230 auto &Publics = Err(getPdb().getPDBPublicsStream());
Zachary Turner63055452017-06-15 22:24:24 +00001231
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001232 const GSIHashTable &PublicsTable = Publics.getPublicsTable();
Zachary Turner5448dab2017-08-09 04:23:59 +00001233 if (opts::dump::DumpPublicExtras) {
1234 P.printLine("Publics Header");
1235 AutoIndent Indent(P);
1236 P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
1237 formatSegmentOffset(Publics.getThunkTableSection(),
1238 Publics.getThunkTableOffset()));
1239 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001240 Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
Zachary Turneraf8c75a2017-06-30 21:35:00 +00001241
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001242 // Skip the rest if we aren't dumping extras.
Reid Kleckner686f1212017-07-21 18:28:55 +00001243 if (!opts::dump::DumpPublicExtras)
1244 return Error::success();
1245
Reid Kleckner686f1212017-07-21 18:28:55 +00001246 P.formatLine("Address Map");
1247 {
1248 // These are offsets into the publics stream sorted by secidx:secrel.
1249 AutoIndent Indent2(P);
1250 for (uint32_t Addr : Publics.getAddressMap())
1251 P.formatLine("off = {0}", Addr);
1252 }
1253
1254 // The thunk map is optional debug info used for ILT thunks.
1255 if (!Publics.getThunkMap().empty()) {
1256 P.formatLine("Thunk Map");
1257 AutoIndent Indent2(P);
1258 for (uint32_t Addr : Publics.getThunkMap())
1259 P.formatLine("{0:x8}", Addr);
1260 }
1261
1262 // The section offsets table appears to be empty when incremental linking
1263 // isn't in use.
1264 if (!Publics.getSectionOffsets().empty()) {
1265 P.formatLine("Section Offsets");
1266 AutoIndent Indent2(P);
1267 for (const SectionOffset &SO : Publics.getSectionOffsets())
1268 P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
1269 }
1270
Zachary Turner63055452017-06-15 22:24:24 +00001271 return Error::success();
1272}
1273
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001274Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
1275 bool HashExtras) {
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001276 auto ExpectedSyms = getPdb().getPDBSymbolStream();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001277 if (!ExpectedSyms)
1278 return ExpectedSyms.takeError();
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001279 auto &Types = File.types();
1280 auto &Ids = File.ids();
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001281
Zachary Turner5448dab2017-08-09 04:23:59 +00001282 if (HashExtras) {
1283 P.printLine("GSI Header");
1284 AutoIndent Indent(P);
1285 P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
1286 Table.getVerSignature(), Table.getVerHeader(),
1287 Table.getHashRecordSize(), Table.getNumBuckets());
1288 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001289
Zachary Turner5448dab2017-08-09 04:23:59 +00001290 {
1291 P.printLine("Records");
1292 SymbolVisitorCallbackPipeline Pipeline;
1293 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001294 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
Zachary Turner5448dab2017-08-09 04:23:59 +00001295
1296 Pipeline.addCallbackToPipeline(Deserializer);
1297 Pipeline.addCallbackToPipeline(Dumper);
1298 CVSymbolVisitor Visitor(Pipeline);
1299
1300 BinaryStreamRef SymStream =
1301 ExpectedSyms->getSymbolArray().getUnderlyingStream();
1302 for (uint32_t PubSymOff : Table) {
1303 Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
1304 if (!Sym)
1305 return Sym.takeError();
1306 if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
1307 return E;
1308 }
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001309 }
1310
1311 // Return early if we aren't dumping public hash table and address map info.
1312 if (!HashExtras)
1313 return Error::success();
1314
Zachary Turner5448dab2017-08-09 04:23:59 +00001315 P.formatLine("Hash Entries");
Reid Kleckner14d90fd2017-07-26 00:40:36 +00001316 {
1317 AutoIndent Indent2(P);
1318 for (const PSHashRecord &HR : Table.HashRecords)
1319 P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
1320 uint32_t(HR.CRef));
1321 }
1322
1323 // FIXME: Dump the bitmap.
1324
1325 P.formatLine("Hash Buckets");
1326 {
1327 AutoIndent Indent2(P);
1328 for (uint32_t Hash : Table.HashBuckets)
1329 P.formatLine("{0:x8}", Hash);
1330 }
1331
1332 return Error::success();
1333}
1334
Zachary Turner63055452017-06-15 22:24:24 +00001335static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1336 OMFSegDescFlags Flags) {
1337 std::vector<std::string> Opts;
1338 if (Flags == OMFSegDescFlags::None)
1339 return "none";
1340
1341 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
1342 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
1343 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
1344 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
1345 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
1346 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
1347 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
Zachary Turner47d9a562017-06-16 00:04:24 +00001348 return typesetItemList(Opts, IndentLevel, 4, " | ");
Zachary Turner63055452017-06-15 22:24:24 +00001349}
1350
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001351Error DumpOutputStyle::dumpSectionHeaders() {
1352 dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1353 dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1354 return Error::success();
1355}
1356
Zachary Turner92e584c2017-08-04 21:10:04 +00001357static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
1358 ArrayRef<llvm::object::coff_section>>>
1359loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
1360 if (!File.hasPDBDbiStream())
1361 return make_error<StringError>(
1362 "Section headers require a DBI Stream, which could not be loaded",
1363 inconvertibleErrorCode());
1364
1365 auto &Dbi = cantFail(File.getPDBDbiStream());
1366 uint32_t SI = Dbi.getDebugStreamIndex(Type);
1367
1368 if (SI == kInvalidStreamIndex)
1369 return make_error<StringError>(
1370 "PDB does not contain the requested image section header type",
1371 inconvertibleErrorCode());
1372
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001373 auto Stream = File.createIndexedStream(SI);
Zachary Turner92e584c2017-08-04 21:10:04 +00001374 if (!Stream)
1375 return make_error<StringError>("Could not load the required stream data",
1376 inconvertibleErrorCode());
1377
1378 ArrayRef<object::coff_section> Headers;
1379 if (Stream->getLength() % sizeof(object::coff_section) != 0)
1380 return make_error<StringError>(
1381 "Section header array size is not a multiple of section header size",
1382 inconvertibleErrorCode());
1383
1384 uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
1385 BinaryStreamReader Reader(*Stream);
1386 cantFail(Reader.readArray(Headers, NumHeaders));
1387 return std::make_pair(std::move(Stream), Headers);
1388}
1389
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001390void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1391 printHeader(P, Label);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001392
1393 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001394 if (File.isObj()) {
1395 P.formatLine("Dumping Section Headers is not supported for object files");
1396 return;
1397 }
1398
1399 ExitOnError Err("Error dumping section headers: ");
Zachary Turner92e584c2017-08-04 21:10:04 +00001400 std::unique_ptr<MappedBlockStream> Stream;
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001401 ArrayRef<object::coff_section> Headers;
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001402 auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
Zachary Turner92e584c2017-08-04 21:10:04 +00001403 if (!ExpectedHeaders) {
1404 P.printLine(toString(ExpectedHeaders.takeError()));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001405 return;
1406 }
Zachary Turner92e584c2017-08-04 21:10:04 +00001407 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001408
1409 uint32_t I = 1;
1410 for (const auto &Header : Headers) {
1411 P.NewLine();
1412 P.formatLine("SECTION HEADER #{0}", I);
1413 P.formatLine("{0,8} name", Header.Name);
1414 P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1415 P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1416 P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1417 P.formatLine("{0,8:X-} file pointer to raw data",
1418 uint32_t(Header.PointerToRawData));
1419 P.formatLine("{0,8:X-} file pointer to relocation table",
1420 uint32_t(Header.PointerToRelocations));
1421 P.formatLine("{0,8:X-} file pointer to line numbers",
1422 uint32_t(Header.PointerToLinenumbers));
1423 P.formatLine("{0,8:X-} number of relocations",
1424 uint32_t(Header.NumberOfRelocations));
1425 P.formatLine("{0,8:X-} number of line numbers",
1426 uint32_t(Header.NumberOfLinenumbers));
1427 P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1428 AutoIndent IndentMore(P, 9);
1429 P.formatLine("{0}", formatSectionCharacteristics(
1430 P.getIndentLevel(), Header.Characteristics, 1, ""));
1431 ++I;
1432 }
1433 return;
1434}
1435
Zachary Turner92e584c2017-08-04 21:10:04 +00001436std::vector<std::string> getSectionNames(PDBFile &File) {
1437 auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
1438 if (!ExpectedHeaders)
1439 return {};
1440
1441 std::unique_ptr<MappedBlockStream> Stream;
1442 ArrayRef<object::coff_section> Headers;
1443 std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1444 std::vector<std::string> Names;
1445 for (const auto &H : Headers)
1446 Names.push_back(H.Name);
1447 return Names;
1448}
1449
Zachary Turner7df69952017-06-22 20:57:39 +00001450Error DumpOutputStyle::dumpSectionContribs() {
Zachary Turner63055452017-06-15 22:24:24 +00001451 printHeader(P, "Section Contributions");
Zachary Turner63055452017-06-15 22:24:24 +00001452
1453 AutoIndent Indent(P);
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001454 if (File.isObj()) {
1455 P.formatLine(
1456 "Dumping section contributions is not supported for object files");
1457 return Error::success();
1458 }
1459
1460 ExitOnError Err("Error dumping section contributions: ");
1461 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001462 P.formatLine(
1463 "Section contribs require a DBI Stream, which could not be loaded");
1464 return Error::success();
1465 }
1466
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001467 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001468
1469 class Visitor : public ISectionContribVisitor {
1470 public:
Zachary Turner92e584c2017-08-04 21:10:04 +00001471 Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
1472 auto Max = std::max_element(
1473 Names.begin(), Names.end(),
1474 [](StringRef S1, StringRef S2) { return S1.size() < S2.size(); });
1475 MaxNameLen = (Max == Names.end() ? 0 : Max->size());
1476 }
Zachary Turner63055452017-06-15 22:24:24 +00001477 void visit(const SectionContrib &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001478 assert(SC.ISect > 0);
Zachary Turner489a7a02017-08-07 20:24:01 +00001479 std::string NameInsert;
1480 if (SC.ISect < Names.size()) {
1481 StringRef SectionName = Names[SC.ISect - 1];
1482 NameInsert = formatv("[{0}]", SectionName).str();
1483 } else
1484 NameInsert = "[???]";
Zachary Turner92e584c2017-08-04 21:10:04 +00001485 P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1486 "crc = {4}",
1487 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
1488 fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
1489 fmt_align(NameInsert, AlignStyle::Left, MaxNameLen + 2));
1490 AutoIndent Indent(P, MaxNameLen + 2);
Zachary Turner63055452017-06-15 22:24:24 +00001491 P.formatLine(" {0}",
1492 formatSectionCharacteristics(P.getIndentLevel() + 6,
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001493 SC.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001494 }
1495 void visit(const SectionContrib2 &SC) override {
Zachary Turner92e584c2017-08-04 21:10:04 +00001496 P.formatLine(
1497 "SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1498 "crc = {4}, coff section = {5}",
1499 formatSegmentOffset(SC.Base.ISect, SC.Base.Off), fmtle(SC.Base.Size),
1500 fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1501 fmtle(SC.ISectCoff));
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001502 P.formatLine(" {0}", formatSectionCharacteristics(
1503 P.getIndentLevel() + 6,
1504 SC.Base.Characteristics, 3, " | "));
Zachary Turner63055452017-06-15 22:24:24 +00001505 }
1506
1507 private:
1508 LinePrinter &P;
Zachary Turner92e584c2017-08-04 21:10:04 +00001509 uint32_t MaxNameLen;
1510 ArrayRef<std::string> Names;
Zachary Turner63055452017-06-15 22:24:24 +00001511 };
1512
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001513 std::vector<std::string> Names = getSectionNames(getPdb());
Zachary Turner92e584c2017-08-04 21:10:04 +00001514 Visitor V(P, makeArrayRef(Names));
Zachary Turner63055452017-06-15 22:24:24 +00001515 Dbi.visitSectionContributions(V);
1516 return Error::success();
1517}
1518
Zachary Turner7df69952017-06-22 20:57:39 +00001519Error DumpOutputStyle::dumpSectionMap() {
Zachary Turner63055452017-06-15 22:24:24 +00001520 printHeader(P, "Section Map");
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001521 AutoIndent Indent(P);
1522
1523 if (File.isObj()) {
1524 P.formatLine("Dumping section map is not supported for object files");
1525 return Error::success();
1526 }
1527
Reid Klecknerdd853e52017-07-27 23:13:18 +00001528 ExitOnError Err("Error dumping section map: ");
Zachary Turner63055452017-06-15 22:24:24 +00001529
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001530 if (!getPdb().hasPDBDbiStream()) {
Zachary Turner63055452017-06-15 22:24:24 +00001531 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1532 "not be loaded");
1533 return Error::success();
1534 }
1535
Zachary Turnerabb17cc2017-09-01 20:06:56 +00001536 auto &Dbi = Err(getPdb().getPDBDbiStream());
Zachary Turner63055452017-06-15 22:24:24 +00001537
1538 uint32_t I = 0;
1539 for (auto &M : Dbi.getSectionMap()) {
1540 P.formatLine(
Zachary Turnerfb1cd502017-08-04 20:02:38 +00001541 "Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
Zachary Turner63055452017-06-15 22:24:24 +00001542 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1543 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1544 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1545 P.formatLine(" flags = {0}",
1546 formatSegMapDescriptorFlag(
1547 P.getIndentLevel() + 13,
1548 static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1549 ++I;
1550 }
1551 return Error::success();
1552}