Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp
35259 views
1
//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "DumpOutputStyle.h"
10
11
#include "MinimalSymbolDumper.h"
12
#include "MinimalTypeDumper.h"
13
#include "StreamUtil.h"
14
#include "TypeReferenceTracker.h"
15
#include "llvm-pdbutil.h"
16
17
#include "llvm/ADT/STLExtras.h"
18
#include "llvm/ADT/StringExtras.h"
19
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
20
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
21
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
22
#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
23
#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
24
#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
25
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
26
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
27
#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
28
#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
29
#include "llvm/DebugInfo/CodeView/Formatters.h"
30
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
31
#include "llvm/DebugInfo/CodeView/Line.h"
32
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
33
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
34
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
35
#include "llvm/DebugInfo/CodeView/TypeHashing.h"
36
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
37
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
38
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
39
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
40
#include "llvm/DebugInfo/PDB/Native/FormatUtil.h"
41
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
42
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
43
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
44
#include "llvm/DebugInfo/PDB/Native/InputFile.h"
45
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
46
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
47
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
48
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
49
#include "llvm/DebugInfo/PDB/Native/RawError.h"
50
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
51
#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
52
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
53
#include "llvm/Object/COFF.h"
54
#include "llvm/Support/BinaryStreamReader.h"
55
#include "llvm/Support/FormatAdapters.h"
56
#include "llvm/Support/FormatVariadic.h"
57
58
#include <cctype>
59
60
using namespace llvm;
61
using namespace llvm::codeview;
62
using namespace llvm::msf;
63
using namespace llvm::pdb;
64
65
DumpOutputStyle::DumpOutputStyle(InputFile &File)
66
: File(File), P(2, false, outs(), opts::Filters) {
67
if (opts::dump::DumpTypeRefStats)
68
RefTracker.reset(new TypeReferenceTracker(File));
69
}
70
71
DumpOutputStyle::~DumpOutputStyle() {}
72
73
PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
74
object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
75
76
void DumpOutputStyle::printStreamNotValidForObj() {
77
AutoIndent Indent(P, 4);
78
P.formatLine("Dumping this stream is not valid for object files");
79
}
80
81
void DumpOutputStyle::printStreamNotPresent(StringRef StreamName) {
82
AutoIndent Indent(P, 4);
83
P.formatLine("{0} stream not present", StreamName);
84
}
85
86
Error DumpOutputStyle::dump() {
87
// Walk symbols & globals if we are supposed to mark types referenced.
88
if (opts::dump::DumpTypeRefStats)
89
RefTracker->mark();
90
91
if (opts::dump::DumpSummary) {
92
if (auto EC = dumpFileSummary())
93
return EC;
94
P.NewLine();
95
}
96
97
if (opts::dump::DumpStreams) {
98
if (auto EC = dumpStreamSummary())
99
return EC;
100
P.NewLine();
101
}
102
103
if (opts::dump::DumpSymbolStats) {
104
ExitOnError Err("Unexpected error processing module stats: ");
105
Err(dumpSymbolStats());
106
P.NewLine();
107
}
108
109
if (opts::dump::DumpUdtStats) {
110
if (auto EC = dumpUdtStats())
111
return EC;
112
P.NewLine();
113
}
114
115
if (opts::dump::DumpTypeStats || opts::dump::DumpIDStats) {
116
if (auto EC = dumpTypeStats())
117
return EC;
118
P.NewLine();
119
}
120
121
if (opts::dump::DumpNamedStreams) {
122
if (auto EC = dumpNamedStreams())
123
return EC;
124
P.NewLine();
125
}
126
127
if (opts::dump::DumpStringTable || opts::dump::DumpStringTableDetails) {
128
if (auto EC = dumpStringTable())
129
return EC;
130
P.NewLine();
131
}
132
133
if (opts::dump::DumpModules) {
134
ExitOnError Err("Unexpected error processing modules: ");
135
Err(dumpModules());
136
}
137
138
if (opts::dump::DumpModuleFiles) {
139
ExitOnError Err("Unexpected error processing files: ");
140
Err(dumpModuleFiles());
141
}
142
143
if (opts::dump::DumpLines) {
144
ExitOnError Err("Unexpected error processing lines: ");
145
Err(dumpLines());
146
}
147
148
if (opts::dump::DumpInlineeLines) {
149
ExitOnError Err("Unexpected error processing inlinee lines: ");
150
Err(dumpInlineeLines());
151
}
152
153
if (opts::dump::DumpXmi) {
154
ExitOnError Err("Unexpected error processing cross module imports: ");
155
Err(dumpXmi());
156
}
157
158
if (opts::dump::DumpXme) {
159
ExitOnError Err("Unexpected error processing cross module exports: ");
160
Err(dumpXme());
161
}
162
163
if (opts::dump::DumpFpo) {
164
if (auto EC = dumpFpo())
165
return EC;
166
}
167
168
if (File.isObj()) {
169
if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
170
opts::dump::DumpTypeExtras)
171
if (auto EC = dumpTypesFromObjectFile())
172
return EC;
173
} else {
174
if (opts::dump::DumpTypes || !opts::dump::DumpTypeIndex.empty() ||
175
opts::dump::DumpTypeExtras) {
176
if (auto EC = dumpTpiStream(StreamTPI))
177
return EC;
178
}
179
180
if (opts::dump::DumpIds || !opts::dump::DumpIdIndex.empty() ||
181
opts::dump::DumpIdExtras) {
182
if (auto EC = dumpTpiStream(StreamIPI))
183
return EC;
184
}
185
}
186
187
if (opts::dump::DumpGSIRecords) {
188
if (auto EC = dumpGSIRecords())
189
return EC;
190
}
191
192
if (opts::dump::DumpGlobals) {
193
if (auto EC = dumpGlobals())
194
return EC;
195
}
196
197
if (opts::dump::DumpPublics) {
198
if (auto EC = dumpPublics())
199
return EC;
200
}
201
202
if (opts::dump::DumpSymbols) {
203
ExitOnError Err("Unexpected error processing symbols: ");
204
Err(File.isPdb() ? dumpModuleSymsForPdb() : dumpModuleSymsForObj());
205
}
206
207
if (opts::dump::DumpTypeRefStats) {
208
if (auto EC = dumpTypeRefStats())
209
return EC;
210
}
211
212
if (opts::dump::DumpSectionHeaders) {
213
if (auto EC = dumpSectionHeaders())
214
return EC;
215
}
216
217
if (opts::dump::DumpSectionContribs) {
218
if (auto EC = dumpSectionContribs())
219
return EC;
220
}
221
222
if (opts::dump::DumpSectionMap) {
223
if (auto EC = dumpSectionMap())
224
return EC;
225
}
226
227
P.NewLine();
228
229
return Error::success();
230
}
231
232
static void printHeader(LinePrinter &P, const Twine &S) {
233
P.NewLine();
234
P.formatLine("{0,=60}", S);
235
P.formatLine("{0}", fmt_repeat('=', 60));
236
}
237
238
Error DumpOutputStyle::dumpFileSummary() {
239
printHeader(P, "Summary");
240
241
if (File.isObj()) {
242
printStreamNotValidForObj();
243
return Error::success();
244
}
245
246
AutoIndent Indent(P);
247
ExitOnError Err("Invalid PDB Format: ");
248
249
P.formatLine("Block Size: {0}", getPdb().getBlockSize());
250
P.formatLine("Number of blocks: {0}", getPdb().getBlockCount());
251
P.formatLine("Number of streams: {0}", getPdb().getNumStreams());
252
253
auto &PS = Err(getPdb().getPDBInfoStream());
254
P.formatLine("Signature: {0}", PS.getSignature());
255
P.formatLine("Age: {0}", PS.getAge());
256
P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
257
P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
258
P.formatLine("Has Debug Info: {0}", getPdb().hasPDBDbiStream());
259
P.formatLine("Has Types: {0}", getPdb().hasPDBTpiStream());
260
P.formatLine("Has IDs: {0}", getPdb().hasPDBIpiStream());
261
P.formatLine("Has Globals: {0}", getPdb().hasPDBGlobalsStream());
262
P.formatLine("Has Publics: {0}", getPdb().hasPDBPublicsStream());
263
if (getPdb().hasPDBDbiStream()) {
264
DbiStream &DBI = Err(getPdb().getPDBDbiStream());
265
P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
266
P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
267
P.formatLine("Is stripped: {0}", DBI.isStripped());
268
}
269
270
return Error::success();
271
}
272
273
static StatCollection getSymbolStats(const SymbolGroup &SG,
274
StatCollection &CumulativeStats) {
275
StatCollection Stats;
276
if (SG.getFile().isPdb() && SG.hasDebugStream()) {
277
// For PDB files, all symbols are packed into one stream.
278
for (const auto &S : SG.getPdbModuleStream().symbols(nullptr)) {
279
Stats.update(S.kind(), S.length());
280
CumulativeStats.update(S.kind(), S.length());
281
}
282
return Stats;
283
}
284
285
for (const auto &SS : SG.getDebugSubsections()) {
286
// For object files, all symbols are spread across multiple Symbol
287
// subsections of a given .debug$S section.
288
if (SS.kind() != DebugSubsectionKind::Symbols)
289
continue;
290
DebugSymbolsSubsectionRef Symbols;
291
BinaryStreamReader Reader(SS.getRecordData());
292
cantFail(Symbols.initialize(Reader));
293
for (const auto &S : Symbols) {
294
Stats.update(S.kind(), S.length());
295
CumulativeStats.update(S.kind(), S.length());
296
}
297
}
298
return Stats;
299
}
300
301
static StatCollection getChunkStats(const SymbolGroup &SG,
302
StatCollection &CumulativeStats) {
303
StatCollection Stats;
304
for (const auto &Chunk : SG.getDebugSubsections()) {
305
Stats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
306
CumulativeStats.update(uint32_t(Chunk.kind()), Chunk.getRecordLength());
307
}
308
return Stats;
309
}
310
311
static inline std::string formatModuleDetailKind(DebugSubsectionKind K) {
312
return formatChunkKind(K, false);
313
}
314
315
static inline std::string formatModuleDetailKind(SymbolKind K) {
316
return formatSymbolKind(K);
317
}
318
319
// Get the stats sorted by size, descending.
320
std::vector<StatCollection::KindAndStat>
321
StatCollection::getStatsSortedBySize() const {
322
std::vector<KindAndStat> SortedStats(Individual.begin(), Individual.end());
323
llvm::stable_sort(SortedStats,
324
[](const KindAndStat &LHS, const KindAndStat &RHS) {
325
return LHS.second.Size > RHS.second.Size;
326
});
327
return SortedStats;
328
}
329
330
template <typename Kind>
331
static void printModuleDetailStats(LinePrinter &P, StringRef Label,
332
const StatCollection &Stats) {
333
P.NewLine();
334
P.formatLine(" {0}", Label);
335
AutoIndent Indent(P);
336
P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", "Total",
337
Stats.Totals.Count, Stats.Totals.Size);
338
P.formatLine("{0}", fmt_repeat('-', 74));
339
340
for (const auto &K : Stats.getStatsSortedBySize()) {
341
std::string KindName = formatModuleDetailKind(Kind(K.first));
342
P.formatLine("{0,40}: {1,7} entries ({2,12:N} bytes)", KindName,
343
K.second.Count, K.second.Size);
344
}
345
}
346
347
Error DumpOutputStyle::dumpStreamSummary() {
348
printHeader(P, "Streams");
349
350
if (File.isObj()) {
351
printStreamNotValidForObj();
352
return Error::success();
353
}
354
355
AutoIndent Indent(P);
356
357
if (StreamPurposes.empty())
358
discoverStreamPurposes(getPdb(), StreamPurposes);
359
360
uint32_t StreamCount = getPdb().getNumStreams();
361
uint32_t MaxStreamSize = getPdb().getMaxStreamSize();
362
363
for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
364
P.formatLine(
365
"Stream {0} ({1} bytes): [{2}]",
366
fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
367
fmt_align(getPdb().getStreamByteSize(StreamIdx), AlignStyle::Right,
368
NumDigits(MaxStreamSize)),
369
StreamPurposes[StreamIdx].getLongName());
370
371
if (opts::dump::DumpStreamBlocks) {
372
auto Blocks = getPdb().getStreamBlockList(StreamIdx);
373
std::vector<uint32_t> BV(Blocks.begin(), Blocks.end());
374
P.formatLine(" {0} Blocks: [{1}]",
375
fmt_repeat(' ', NumDigits(StreamCount)),
376
make_range(BV.begin(), BV.end()));
377
}
378
}
379
380
return Error::success();
381
}
382
383
static Expected<std::pair<std::unique_ptr<MappedBlockStream>,
384
ArrayRef<llvm::object::coff_section>>>
385
loadSectionHeaders(PDBFile &File, DbgHeaderType Type) {
386
if (!File.hasPDBDbiStream())
387
return make_error<StringError>(
388
"Section headers require a DBI Stream, which could not be loaded",
389
inconvertibleErrorCode());
390
391
DbiStream &Dbi = cantFail(File.getPDBDbiStream());
392
uint32_t SI = Dbi.getDebugStreamIndex(Type);
393
394
if (SI == kInvalidStreamIndex)
395
return make_error<StringError>(
396
"PDB does not contain the requested image section header type",
397
inconvertibleErrorCode());
398
399
auto Stream = File.createIndexedStream(SI);
400
if (!Stream)
401
return make_error<StringError>("Could not load the required stream data",
402
inconvertibleErrorCode());
403
404
ArrayRef<object::coff_section> Headers;
405
if (Stream->getLength() % sizeof(object::coff_section) != 0)
406
return make_error<StringError>(
407
"Section header array size is not a multiple of section header size",
408
inconvertibleErrorCode());
409
410
uint32_t NumHeaders = Stream->getLength() / sizeof(object::coff_section);
411
BinaryStreamReader Reader(*Stream);
412
cantFail(Reader.readArray(Headers, NumHeaders));
413
return std::make_pair(std::move(Stream), Headers);
414
}
415
416
static Expected<std::vector<std::string>> getSectionNames(PDBFile &File) {
417
auto ExpectedHeaders = loadSectionHeaders(File, DbgHeaderType::SectionHdr);
418
if (!ExpectedHeaders)
419
return ExpectedHeaders.takeError();
420
421
std::unique_ptr<MappedBlockStream> Stream;
422
ArrayRef<object::coff_section> Headers;
423
std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
424
std::vector<std::string> Names;
425
for (const auto &H : Headers)
426
Names.push_back(H.Name);
427
return Names;
428
}
429
430
static void dumpSectionContrib(LinePrinter &P, const SectionContrib &SC,
431
ArrayRef<std::string> SectionNames,
432
uint32_t FieldWidth) {
433
std::string NameInsert;
434
if (SC.ISect > 0 && SC.ISect <= SectionNames.size()) {
435
StringRef SectionName = SectionNames[SC.ISect - 1];
436
NameInsert = formatv("[{0}]", SectionName).str();
437
} else
438
NameInsert = "[???]";
439
P.formatLine("SC{5} | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
440
"crc = {4}",
441
formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size),
442
fmtle(SC.Imod), fmtle(SC.DataCrc), fmtle(SC.RelocCrc),
443
fmt_align(NameInsert, AlignStyle::Left, FieldWidth + 2));
444
AutoIndent Indent(P, FieldWidth + 2);
445
P.formatLine(" {0}",
446
formatSectionCharacteristics(P.getIndentLevel() + 6,
447
SC.Characteristics, 3, " | "));
448
}
449
450
static void dumpSectionContrib(LinePrinter &P, const SectionContrib2 &SC,
451
ArrayRef<std::string> SectionNames,
452
uint32_t FieldWidth) {
453
P.formatLine("SC2[{6}] | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
454
"crc = {4}, coff section = {5}",
455
formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
456
fmtle(SC.Base.Size), fmtle(SC.Base.Imod), fmtle(SC.Base.DataCrc),
457
fmtle(SC.Base.RelocCrc), fmtle(SC.ISectCoff));
458
P.formatLine(" {0}",
459
formatSectionCharacteristics(P.getIndentLevel() + 6,
460
SC.Base.Characteristics, 3, " | "));
461
}
462
463
Error DumpOutputStyle::dumpModules() {
464
printHeader(P, "Modules");
465
466
if (File.isObj()) {
467
printStreamNotValidForObj();
468
return Error::success();
469
}
470
471
if (!getPdb().hasPDBDbiStream()) {
472
printStreamNotPresent("DBI");
473
return Error::success();
474
}
475
476
AutoIndent Indent(P);
477
478
Expected<DbiStream &> StreamOrErr = getPdb().getPDBDbiStream();
479
if (!StreamOrErr)
480
return StreamOrErr.takeError();
481
DbiStream &Stream = *StreamOrErr;
482
483
const DbiModuleList &Modules = Stream.modules();
484
return iterateSymbolGroups(
485
File, PrintScope{P, 11},
486
[&](uint32_t Modi, const SymbolGroup &Strings) -> Error {
487
auto Desc = Modules.getModuleDescriptor(Modi);
488
if (opts::dump::DumpSectionContribs) {
489
auto SectionsOrErr = getSectionNames(getPdb());
490
if (!SectionsOrErr)
491
return SectionsOrErr.takeError();
492
ArrayRef<std::string> Sections = *SectionsOrErr;
493
dumpSectionContrib(P, Desc.getSectionContrib(), Sections, 0);
494
}
495
P.formatLine("Obj: `{0}`: ", Desc.getObjFileName());
496
P.formatLine("debug stream: {0}, # files: {1}, has ec info: {2}",
497
Desc.getModuleStreamIndex(), Desc.getNumberOfFiles(),
498
Desc.hasECInfo());
499
500
auto PdbPathOrErr = Stream.getECName(Desc.getPdbFilePathNameIndex());
501
if (!PdbPathOrErr)
502
return PdbPathOrErr.takeError();
503
StringRef PdbFilePath = *PdbPathOrErr;
504
505
auto SrcPathOrErr = Stream.getECName(Desc.getSourceFileNameIndex());
506
if (!SrcPathOrErr)
507
return SrcPathOrErr.takeError();
508
StringRef SrcFilePath = *SrcPathOrErr;
509
510
P.formatLine("pdb file ni: {0} `{1}`, src file ni: {2} `{3}`",
511
Desc.getPdbFilePathNameIndex(), PdbFilePath,
512
Desc.getSourceFileNameIndex(), SrcFilePath);
513
return Error::success();
514
});
515
}
516
517
Error DumpOutputStyle::dumpModuleFiles() {
518
printHeader(P, "Files");
519
520
if (File.isObj()) {
521
printStreamNotValidForObj();
522
return Error::success();
523
}
524
525
if (!getPdb().hasPDBDbiStream()) {
526
printStreamNotPresent("DBI");
527
return Error::success();
528
}
529
530
return iterateSymbolGroups(
531
File, PrintScope{P, 11},
532
[this](uint32_t Modi, const SymbolGroup &Strings) -> Error {
533
Expected<DbiStream &> StreamOrErr = getPdb().getPDBDbiStream();
534
if (!StreamOrErr)
535
return StreamOrErr.takeError();
536
DbiStream &Stream = *StreamOrErr;
537
538
const DbiModuleList &Modules = Stream.modules();
539
for (const auto &F : Modules.source_files(Modi)) {
540
Strings.formatFromFileName(P, F);
541
}
542
return Error::success();
543
});
544
}
545
546
Error DumpOutputStyle::dumpSymbolStats() {
547
printHeader(P, "Module Stats");
548
549
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
550
printStreamNotPresent("DBI");
551
return Error::success();
552
}
553
554
StatCollection SymStats;
555
StatCollection ChunkStats;
556
PrintScope Scope(P, 2);
557
558
if (Error Err = iterateSymbolGroups(
559
File, Scope, [&](uint32_t Modi, const SymbolGroup &SG) -> Error {
560
StatCollection SS = getSymbolStats(SG, SymStats);
561
StatCollection CS = getChunkStats(SG, ChunkStats);
562
563
if (!SG.getFile().isPdb())
564
return Error::success();
565
566
AutoIndent Indent(P);
567
auto Modules = cantFail(File.pdb().getPDBDbiStream()).modules();
568
uint32_t ModCount = Modules.getModuleCount();
569
DbiModuleDescriptor Desc = Modules.getModuleDescriptor(Modi);
570
uint32_t StreamIdx = Desc.getModuleStreamIndex();
571
572
if (StreamIdx == kInvalidStreamIndex) {
573
P.formatLine(
574
"Mod {0} (debug info not present): [{1}]",
575
fmt_align(Modi, AlignStyle::Right, NumDigits(ModCount)),
576
Desc.getModuleName());
577
return Error::success();
578
}
579
P.formatLine("Stream {0}, {1} bytes", StreamIdx,
580
getPdb().getStreamByteSize(StreamIdx));
581
582
printModuleDetailStats<SymbolKind>(P, "Symbols", SS);
583
printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", CS);
584
585
return Error::success();
586
}))
587
return Err;
588
589
if (SymStats.Totals.Count > 0) {
590
P.printLine(" Summary |");
591
AutoIndent Indent(P, 4);
592
printModuleDetailStats<SymbolKind>(P, "Symbols", SymStats);
593
printModuleDetailStats<DebugSubsectionKind>(P, "Chunks", ChunkStats);
594
}
595
596
return Error::success();
597
}
598
599
Error DumpOutputStyle::dumpTypeStats() {
600
printHeader(P, "Type Record Stats");
601
602
// Iterate the types, categorize by kind, accumulate size stats.
603
StatCollection TypeStats;
604
LazyRandomTypeCollection &Types =
605
opts::dump::DumpTypeStats ? File.types() : File.ids();
606
for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
607
TI = Types.getNext(*TI)) {
608
CVType Type = Types.getType(*TI);
609
TypeStats.update(uint32_t(Type.kind()), Type.length());
610
}
611
612
P.NewLine();
613
P.formatLine(" Types");
614
AutoIndent Indent(P);
615
P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)", "Total",
616
TypeStats.Totals.Count, TypeStats.Totals.Size,
617
(double)TypeStats.Totals.Size / TypeStats.Totals.Count);
618
P.formatLine("{0}", fmt_repeat('-', 74));
619
620
for (const auto &K : TypeStats.getStatsSortedBySize()) {
621
P.formatLine("{0,16}: {1,7} entries ({2,12:N} bytes, {3,7} avg)",
622
formatTypeLeafKind(TypeLeafKind(K.first)), K.second.Count,
623
K.second.Size, (double)K.second.Size / K.second.Count);
624
}
625
return Error::success();
626
}
627
628
static bool isValidNamespaceIdentifier(StringRef S) {
629
if (S.empty())
630
return false;
631
632
if (std::isdigit(S[0]))
633
return false;
634
635
return llvm::all_of(S, [](char C) { return std::isalnum(C); });
636
}
637
638
namespace {
639
constexpr uint32_t kNoneUdtKind = 0;
640
constexpr uint32_t kSimpleUdtKind = 1;
641
constexpr uint32_t kUnknownUdtKind = 2;
642
} // namespace
643
644
static std::string getUdtStatLabel(uint32_t Kind) {
645
if (Kind == kNoneUdtKind)
646
return "<none type>";
647
648
if (Kind == kSimpleUdtKind)
649
return "<simple type>";
650
651
if (Kind == kUnknownUdtKind)
652
return "<unknown type>";
653
654
return formatTypeLeafKind(static_cast<TypeLeafKind>(Kind));
655
}
656
657
static uint32_t getLongestTypeLeafName(const StatCollection &Stats) {
658
size_t L = 0;
659
for (const auto &Stat : Stats.Individual) {
660
std::string Label = getUdtStatLabel(Stat.first);
661
L = std::max(L, Label.size());
662
}
663
return static_cast<uint32_t>(L);
664
}
665
666
Error DumpOutputStyle::dumpUdtStats() {
667
printHeader(P, "S_UDT Record Stats");
668
669
if (File.isPdb() && !getPdb().hasPDBGlobalsStream()) {
670
printStreamNotPresent("Globals");
671
return Error::success();
672
}
673
674
StatCollection UdtStats;
675
StatCollection UdtTargetStats;
676
AutoIndent Indent(P, 4);
677
678
auto &TpiTypes = File.types();
679
680
StringMap<StatCollection::Stat> NamespacedStats;
681
682
size_t LongestNamespace = 0;
683
auto HandleOneSymbol = [&](const CVSymbol &Sym) {
684
if (Sym.kind() != SymbolKind::S_UDT)
685
return;
686
UdtStats.update(SymbolKind::S_UDT, Sym.length());
687
688
UDTSym UDT = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(Sym));
689
690
uint32_t Kind = 0;
691
uint32_t RecordSize = 0;
692
693
if (UDT.Type.isNoneType())
694
Kind = kNoneUdtKind;
695
else if (UDT.Type.isSimple())
696
Kind = kSimpleUdtKind;
697
else if (std::optional<CVType> T = TpiTypes.tryGetType(UDT.Type)) {
698
Kind = T->kind();
699
RecordSize = T->length();
700
} else
701
Kind = kUnknownUdtKind;
702
703
UdtTargetStats.update(Kind, RecordSize);
704
705
size_t Pos = UDT.Name.find("::");
706
if (Pos == StringRef::npos)
707
return;
708
709
StringRef Scope = UDT.Name.take_front(Pos);
710
if (Scope.empty() || !isValidNamespaceIdentifier(Scope))
711
return;
712
713
LongestNamespace = std::max(LongestNamespace, Scope.size());
714
NamespacedStats[Scope].update(RecordSize);
715
};
716
717
P.NewLine();
718
719
if (File.isPdb()) {
720
auto &SymbolRecords = cantFail(getPdb().getPDBSymbolStream());
721
auto ExpGlobals = getPdb().getPDBGlobalsStream();
722
if (!ExpGlobals)
723
return ExpGlobals.takeError();
724
725
for (uint32_t PubSymOff : ExpGlobals->getGlobalsTable()) {
726
CVSymbol Sym = SymbolRecords.readRecord(PubSymOff);
727
HandleOneSymbol(Sym);
728
}
729
} else {
730
for (const auto &Sec : File.symbol_groups()) {
731
for (const auto &SS : Sec.getDebugSubsections()) {
732
if (SS.kind() != DebugSubsectionKind::Symbols)
733
continue;
734
735
DebugSymbolsSubsectionRef Symbols;
736
BinaryStreamReader Reader(SS.getRecordData());
737
cantFail(Symbols.initialize(Reader));
738
for (const auto &S : Symbols)
739
HandleOneSymbol(S);
740
}
741
}
742
}
743
744
LongestNamespace += StringRef(" namespace ''").size();
745
size_t LongestTypeLeafKind = getLongestTypeLeafName(UdtTargetStats);
746
size_t FieldWidth = std::max(LongestNamespace, LongestTypeLeafKind);
747
748
// Compute the max number of digits for count and size fields, including comma
749
// separators.
750
StringRef CountHeader("Count");
751
StringRef SizeHeader("Size");
752
size_t CD = NumDigits(UdtStats.Totals.Count);
753
CD += (CD - 1) / 3;
754
CD = std::max(CD, CountHeader.size());
755
756
size_t SD = NumDigits(UdtStats.Totals.Size);
757
SD += (SD - 1) / 3;
758
SD = std::max(SD, SizeHeader.size());
759
760
uint32_t TableWidth = FieldWidth + 3 + CD + 2 + SD + 1;
761
762
P.formatLine("{0} | {1} {2}",
763
fmt_align("Record Kind", AlignStyle::Right, FieldWidth),
764
fmt_align(CountHeader, AlignStyle::Right, CD),
765
fmt_align(SizeHeader, AlignStyle::Right, SD));
766
767
P.formatLine("{0}", fmt_repeat('-', TableWidth));
768
for (const auto &Stat : UdtTargetStats.getStatsSortedBySize()) {
769
std::string Label = getUdtStatLabel(Stat.first);
770
P.formatLine("{0} | {1:N} {2:N}",
771
fmt_align(Label, AlignStyle::Right, FieldWidth),
772
fmt_align(Stat.second.Count, AlignStyle::Right, CD),
773
fmt_align(Stat.second.Size, AlignStyle::Right, SD));
774
}
775
P.formatLine("{0}", fmt_repeat('-', TableWidth));
776
P.formatLine("{0} | {1:N} {2:N}",
777
fmt_align("Total (S_UDT)", AlignStyle::Right, FieldWidth),
778
fmt_align(UdtStats.Totals.Count, AlignStyle::Right, CD),
779
fmt_align(UdtStats.Totals.Size, AlignStyle::Right, SD));
780
P.formatLine("{0}", fmt_repeat('-', TableWidth));
781
struct StrAndStat {
782
StringRef Key;
783
StatCollection::Stat Stat;
784
};
785
786
// Print namespace stats in descending order of size.
787
std::vector<StrAndStat> NamespacedStatsSorted;
788
for (const auto &Stat : NamespacedStats)
789
NamespacedStatsSorted.push_back({Stat.getKey(), Stat.second});
790
llvm::stable_sort(NamespacedStatsSorted,
791
[](const StrAndStat &L, const StrAndStat &R) {
792
return L.Stat.Size > R.Stat.Size;
793
});
794
for (const auto &Stat : NamespacedStatsSorted) {
795
std::string Label = std::string(formatv("namespace '{0}'", Stat.Key));
796
P.formatLine("{0} | {1:N} {2:N}",
797
fmt_align(Label, AlignStyle::Right, FieldWidth),
798
fmt_align(Stat.Stat.Count, AlignStyle::Right, CD),
799
fmt_align(Stat.Stat.Size, AlignStyle::Right, SD));
800
}
801
return Error::success();
802
}
803
804
static void typesetLinesAndColumns(LinePrinter &P, uint32_t Start,
805
const LineColumnEntry &E) {
806
const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
807
uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
808
809
// Let's try to keep it under 100 characters
810
constexpr uint32_t kMaxRowLength = 100;
811
// At least 3 spaces between columns.
812
uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
813
uint32_t ItemsLeft = E.LineNumbers.size();
814
auto LineIter = E.LineNumbers.begin();
815
while (ItemsLeft != 0) {
816
uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
817
for (uint32_t I = 0; I < RowColumns; ++I) {
818
LineInfo Line(LineIter->Flags);
819
std::string LineStr;
820
if (Line.isAlwaysStepInto())
821
LineStr = "ASI";
822
else if (Line.isNeverStepInto())
823
LineStr = "NSI";
824
else
825
LineStr = utostr(Line.getStartLine());
826
char Statement = Line.isStatement() ? ' ' : '!';
827
P.format("{0} {1:X-} {2} ",
828
fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
829
fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
830
Statement);
831
++LineIter;
832
--ItemsLeft;
833
}
834
P.NewLine();
835
}
836
}
837
838
Error DumpOutputStyle::dumpLines() {
839
printHeader(P, "Lines");
840
841
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
842
printStreamNotPresent("DBI");
843
return Error::success();
844
}
845
846
uint32_t LastModi = UINT32_MAX;
847
uint32_t LastNameIndex = UINT32_MAX;
848
return iterateModuleSubsections<DebugLinesSubsectionRef>(
849
File, PrintScope{P, 4},
850
[this, &LastModi,
851
&LastNameIndex](uint32_t Modi, const SymbolGroup &Strings,
852
DebugLinesSubsectionRef &Lines) -> Error {
853
uint16_t Segment = Lines.header()->RelocSegment;
854
uint32_t Begin = Lines.header()->RelocOffset;
855
uint32_t End = Begin + Lines.header()->CodeSize;
856
for (const auto &Block : Lines) {
857
if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
858
LastModi = Modi;
859
LastNameIndex = Block.NameIndex;
860
Strings.formatFromChecksumsOffset(P, Block.NameIndex);
861
}
862
863
AutoIndent Indent(P, 2);
864
P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
865
uint32_t Count = Block.LineNumbers.size();
866
if (Lines.hasColumnInfo())
867
P.format("line/column/addr entries = {0}", Count);
868
else
869
P.format("line/addr entries = {0}", Count);
870
871
P.NewLine();
872
typesetLinesAndColumns(P, Begin, Block);
873
}
874
return Error::success();
875
});
876
}
877
878
Error DumpOutputStyle::dumpInlineeLines() {
879
printHeader(P, "Inlinee Lines");
880
881
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
882
printStreamNotPresent("DBI");
883
return Error::success();
884
}
885
886
return iterateModuleSubsections<DebugInlineeLinesSubsectionRef>(
887
File, PrintScope{P, 2},
888
[this](uint32_t Modi, const SymbolGroup &Strings,
889
DebugInlineeLinesSubsectionRef &Lines) -> Error {
890
P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
891
for (const auto &Entry : Lines) {
892
P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
893
fmtle(Entry.Header->SourceLineNum));
894
Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
895
for (const auto &ExtraFileID : Entry.ExtraFiles) {
896
P.formatLine(" ");
897
Strings.formatFromChecksumsOffset(P, ExtraFileID, true);
898
}
899
}
900
P.NewLine();
901
return Error::success();
902
});
903
}
904
905
Error DumpOutputStyle::dumpXmi() {
906
printHeader(P, "Cross Module Imports");
907
908
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
909
printStreamNotPresent("DBI");
910
return Error::success();
911
}
912
913
return iterateModuleSubsections<DebugCrossModuleImportsSubsectionRef>(
914
File, PrintScope{P, 2},
915
[this](uint32_t Modi, const SymbolGroup &Strings,
916
DebugCrossModuleImportsSubsectionRef &Imports) -> Error {
917
P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
918
919
for (const auto &Xmi : Imports) {
920
auto ExpectedModule =
921
Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
922
StringRef Module;
923
SmallString<32> ModuleStorage;
924
if (!ExpectedModule) {
925
Module = "(unknown module)";
926
consumeError(ExpectedModule.takeError());
927
} else
928
Module = *ExpectedModule;
929
if (Module.size() > 32) {
930
ModuleStorage = "...";
931
ModuleStorage += Module.take_back(32 - 3);
932
Module = ModuleStorage;
933
}
934
std::vector<std::string> TIs;
935
for (const auto I : Xmi.Imports)
936
TIs.push_back(std::string(formatv("{0,+10:X+}", fmtle(I))));
937
std::string Result =
938
typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
939
P.formatLine("{0,+32} | {1}", Module, Result);
940
}
941
return Error::success();
942
});
943
}
944
945
Error DumpOutputStyle::dumpXme() {
946
printHeader(P, "Cross Module Exports");
947
948
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
949
printStreamNotPresent("DBI");
950
return Error::success();
951
}
952
953
return iterateModuleSubsections<DebugCrossModuleExportsSubsectionRef>(
954
File, PrintScope{P, 2},
955
[this](uint32_t Modi, const SymbolGroup &Strings,
956
DebugCrossModuleExportsSubsectionRef &Exports) -> Error {
957
P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
958
for (const auto &Export : Exports) {
959
P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
960
TypeIndex(Export.Global));
961
}
962
return Error::success();
963
});
964
}
965
966
std::string formatFrameType(object::frame_type FT) {
967
switch (FT) {
968
case object::frame_type::Fpo:
969
return "FPO";
970
case object::frame_type::NonFpo:
971
return "Non-FPO";
972
case object::frame_type::Trap:
973
return "Trap";
974
case object::frame_type::Tss:
975
return "TSS";
976
}
977
return "<unknown>";
978
}
979
980
Error DumpOutputStyle::dumpOldFpo(PDBFile &File) {
981
printHeader(P, "Old FPO Data");
982
983
ExitOnError Err("Error dumping old fpo data:");
984
DbiStream &Dbi = Err(File.getPDBDbiStream());
985
986
if (!Dbi.hasOldFpoRecords()) {
987
printStreamNotPresent("FPO");
988
return Error::success();
989
}
990
991
const FixedStreamArray<object::FpoData>& Records = Dbi.getOldFpoRecords();
992
993
P.printLine(" RVA | Code | Locals | Params | Prolog | Saved Regs | Use "
994
"BP | Has SEH | Frame Type");
995
996
for (const object::FpoData &FD : Records) {
997
P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,6} | {5,10} | {6,6} | "
998
"{7,7} | {8,9}",
999
uint32_t(FD.Offset), uint32_t(FD.Size), uint32_t(FD.NumLocals),
1000
uint32_t(FD.NumParams), FD.getPrologSize(),
1001
FD.getNumSavedRegs(), FD.useBP(), FD.hasSEH(),
1002
formatFrameType(FD.getFP()));
1003
}
1004
return Error::success();
1005
}
1006
1007
Error DumpOutputStyle::dumpNewFpo(PDBFile &File) {
1008
printHeader(P, "New FPO Data");
1009
1010
ExitOnError Err("Error dumping new fpo data:");
1011
DbiStream &Dbi = Err(File.getPDBDbiStream());
1012
1013
if (!Dbi.hasNewFpoRecords()) {
1014
printStreamNotPresent("New FPO");
1015
return Error::success();
1016
}
1017
1018
const DebugFrameDataSubsectionRef& FDS = Dbi.getNewFpoRecords();
1019
1020
P.printLine(" RVA | Code | Locals | Params | Stack | Prolog | Saved Regs "
1021
"| Has SEH | Has C++EH | Start | Program");
1022
for (const FrameData &FD : FDS) {
1023
bool IsFuncStart = FD.Flags & FrameData::IsFunctionStart;
1024
bool HasEH = FD.Flags & FrameData::HasEH;
1025
bool HasSEH = FD.Flags & FrameData::HasSEH;
1026
1027
auto &StringTable = Err(File.getStringTable());
1028
1029
auto Program = Err(StringTable.getStringForID(FD.FrameFunc));
1030
P.formatLine("{0:X-8} | {1,4} | {2,6} | {3,6} | {4,5} | {5,6} | {6,10} | "
1031
"{7,7} | {8,9} | {9,5} | {10}",
1032
uint32_t(FD.RvaStart), uint32_t(FD.CodeSize),
1033
uint32_t(FD.LocalSize), uint32_t(FD.ParamsSize),
1034
uint32_t(FD.MaxStackSize), uint16_t(FD.PrologSize),
1035
uint16_t(FD.SavedRegsSize), HasSEH, HasEH, IsFuncStart,
1036
Program);
1037
}
1038
return Error::success();
1039
}
1040
1041
Error DumpOutputStyle::dumpFpo() {
1042
if (!File.isPdb()) {
1043
printStreamNotValidForObj();
1044
return Error::success();
1045
}
1046
1047
PDBFile &File = getPdb();
1048
if (!File.hasPDBDbiStream()) {
1049
printStreamNotPresent("DBI");
1050
return Error::success();
1051
}
1052
1053
if (auto EC = dumpOldFpo(File))
1054
return EC;
1055
if (auto EC = dumpNewFpo(File))
1056
return EC;
1057
return Error::success();
1058
}
1059
1060
Error DumpOutputStyle::dumpStringTableFromPdb() {
1061
AutoIndent Indent(P);
1062
auto IS = getPdb().getStringTable();
1063
if (!IS) {
1064
P.formatLine("Not present in file");
1065
consumeError(IS.takeError());
1066
return Error::success();
1067
}
1068
1069
if (opts::dump::DumpStringTable) {
1070
if (IS->name_ids().empty())
1071
P.formatLine("Empty");
1072
else {
1073
auto MaxID = llvm::max_element(IS->name_ids());
1074
uint32_t Digits = NumDigits(*MaxID);
1075
1076
P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
1077
"String");
1078
1079
std::vector<uint32_t> SortedIDs(IS->name_ids().begin(),
1080
IS->name_ids().end());
1081
llvm::sort(SortedIDs);
1082
for (uint32_t I : SortedIDs) {
1083
auto ES = IS->getStringForID(I);
1084
llvm::SmallString<32> Str;
1085
if (!ES) {
1086
consumeError(ES.takeError());
1087
Str = "Error reading string";
1088
} else if (!ES->empty()) {
1089
Str.append("'");
1090
Str.append(*ES);
1091
Str.append("'");
1092
}
1093
1094
if (!Str.empty())
1095
P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits),
1096
Str);
1097
}
1098
}
1099
}
1100
1101
if (opts::dump::DumpStringTableDetails) {
1102
P.NewLine();
1103
{
1104
P.printLine("String Table Header:");
1105
AutoIndent Indent(P);
1106
P.formatLine("Signature: {0}", IS->getSignature());
1107
P.formatLine("Hash Version: {0}", IS->getHashVersion());
1108
P.formatLine("Name Buffer Size: {0}", IS->getByteSize());
1109
P.NewLine();
1110
}
1111
1112
BinaryStreamRef NameBuffer = IS->getStringTable().getBuffer();
1113
ArrayRef<uint8_t> Contents;
1114
cantFail(NameBuffer.readBytes(0, NameBuffer.getLength(), Contents));
1115
P.formatBinary("Name Buffer", Contents, 0);
1116
P.NewLine();
1117
{
1118
P.printLine("Hash Table:");
1119
AutoIndent Indent(P);
1120
P.formatLine("Bucket Count: {0}", IS->name_ids().size());
1121
for (const auto &Entry : enumerate(IS->name_ids()))
1122
P.formatLine("Bucket[{0}] : {1}", Entry.index(),
1123
uint32_t(Entry.value()));
1124
P.formatLine("Name Count: {0}", IS->getNameCount());
1125
}
1126
}
1127
return Error::success();
1128
}
1129
1130
Error DumpOutputStyle::dumpStringTableFromObj() {
1131
return iterateModuleSubsections<DebugStringTableSubsectionRef>(
1132
File, PrintScope{P, 4},
1133
[&](uint32_t Modi, const SymbolGroup &Strings,
1134
DebugStringTableSubsectionRef &Strings2) -> Error {
1135
BinaryStreamRef StringTableBuffer = Strings2.getBuffer();
1136
BinaryStreamReader Reader(StringTableBuffer);
1137
while (Reader.bytesRemaining() > 0) {
1138
StringRef Str;
1139
uint32_t Offset = Reader.getOffset();
1140
cantFail(Reader.readCString(Str));
1141
if (Str.empty())
1142
continue;
1143
1144
P.formatLine("{0} | {1}", fmt_align(Offset, AlignStyle::Right, 4),
1145
Str);
1146
}
1147
return Error::success();
1148
});
1149
}
1150
1151
Error DumpOutputStyle::dumpNamedStreams() {
1152
printHeader(P, "Named Streams");
1153
1154
if (File.isObj()) {
1155
printStreamNotValidForObj();
1156
return Error::success();
1157
}
1158
1159
AutoIndent Indent(P);
1160
ExitOnError Err("Invalid PDB File: ");
1161
1162
auto &IS = Err(File.pdb().getPDBInfoStream());
1163
const NamedStreamMap &NS = IS.getNamedStreams();
1164
for (const auto &Entry : NS.entries()) {
1165
P.printLine(Entry.getKey());
1166
AutoIndent Indent2(P, 2);
1167
P.formatLine("Index: {0}", Entry.getValue());
1168
P.formatLine("Size in bytes: {0}",
1169
File.pdb().getStreamByteSize(Entry.getValue()));
1170
}
1171
1172
return Error::success();
1173
}
1174
1175
Error DumpOutputStyle::dumpStringTable() {
1176
printHeader(P, "String Table");
1177
1178
if (File.isPdb())
1179
return dumpStringTableFromPdb();
1180
1181
return dumpStringTableFromObj();
1182
}
1183
1184
static void buildDepSet(LazyRandomTypeCollection &Types,
1185
ArrayRef<TypeIndex> Indices,
1186
std::map<TypeIndex, CVType> &DepSet) {
1187
SmallVector<TypeIndex, 4> DepList;
1188
for (const auto &I : Indices) {
1189
TypeIndex TI(I);
1190
if (DepSet.find(TI) != DepSet.end() || TI.isSimple() || TI.isNoneType())
1191
continue;
1192
1193
CVType Type = Types.getType(TI);
1194
DepSet[TI] = Type;
1195
codeview::discoverTypeIndices(Type, DepList);
1196
buildDepSet(Types, DepList, DepSet);
1197
}
1198
}
1199
1200
static void
1201
dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
1202
TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
1203
uint32_t NumHashBuckets,
1204
FixedStreamArray<support::ulittle32_t> HashValues,
1205
TpiStream *Stream, bool Bytes, bool Extras) {
1206
1207
Printer.formatLine("Showing {0:N} records", NumTypeRecords);
1208
uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
1209
1210
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
1211
NumHashBuckets, HashValues, Stream);
1212
1213
if (auto EC = codeview::visitTypeStream(Types, V)) {
1214
Printer.formatLine("An error occurred dumping type records: {0}",
1215
toString(std::move(EC)));
1216
}
1217
}
1218
1219
static void dumpPartialTypeStream(LinePrinter &Printer,
1220
LazyRandomTypeCollection &Types,
1221
TypeReferenceTracker *RefTracker,
1222
TpiStream &Stream, ArrayRef<TypeIndex> TiList,
1223
bool Bytes, bool Extras, bool Deps) {
1224
uint32_t Width =
1225
NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
1226
1227
MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
1228
Stream.getNumHashBuckets(), Stream.getHashValues(),
1229
&Stream);
1230
1231
if (opts::dump::DumpTypeDependents) {
1232
// If we need to dump all dependents, then iterate each index and find
1233
// all dependents, adding them to a map ordered by TypeIndex.
1234
std::map<TypeIndex, CVType> DepSet;
1235
buildDepSet(Types, TiList, DepSet);
1236
1237
Printer.formatLine(
1238
"Showing {0:N} records and their dependents ({1:N} records total)",
1239
TiList.size(), DepSet.size());
1240
1241
for (auto &Dep : DepSet) {
1242
if (auto EC = codeview::visitTypeRecord(Dep.second, Dep.first, V))
1243
Printer.formatLine("An error occurred dumping type record {0}: {1}",
1244
Dep.first, toString(std::move(EC)));
1245
}
1246
} else {
1247
Printer.formatLine("Showing {0:N} records.", TiList.size());
1248
1249
for (const auto &I : TiList) {
1250
TypeIndex TI(I);
1251
if (TI.isSimple()) {
1252
Printer.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Width),
1253
Types.getTypeName(TI));
1254
} else if (std::optional<CVType> Type = Types.tryGetType(TI)) {
1255
if (auto EC = codeview::visitTypeRecord(*Type, TI, V))
1256
Printer.formatLine("An error occurred dumping type record {0}: {1}",
1257
TI, toString(std::move(EC)));
1258
} else {
1259
Printer.formatLine("Type {0} doesn't exist in TPI stream", TI);
1260
}
1261
}
1262
}
1263
}
1264
1265
Error DumpOutputStyle::dumpTypesFromObjectFile() {
1266
LazyRandomTypeCollection Types(100);
1267
1268
for (const auto &S : getObj().sections()) {
1269
Expected<StringRef> NameOrErr = S.getName();
1270
if (!NameOrErr)
1271
return NameOrErr.takeError();
1272
StringRef SectionName = *NameOrErr;
1273
1274
// .debug$T is a standard CodeView type section, while .debug$P is the same
1275
// format but used for MSVC precompiled header object files.
1276
if (SectionName == ".debug$T")
1277
printHeader(P, "Types (.debug$T)");
1278
else if (SectionName == ".debug$P")
1279
printHeader(P, "Precompiled Types (.debug$P)");
1280
else
1281
continue;
1282
1283
Expected<StringRef> ContentsOrErr = S.getContents();
1284
if (!ContentsOrErr)
1285
return ContentsOrErr.takeError();
1286
1287
uint32_t Magic;
1288
BinaryStreamReader Reader(*ContentsOrErr, llvm::endianness::little);
1289
if (auto EC = Reader.readInteger(Magic))
1290
return EC;
1291
if (Magic != COFF::DEBUG_SECTION_MAGIC)
1292
return make_error<StringError>("Invalid CodeView debug section.",
1293
inconvertibleErrorCode());
1294
1295
Types.reset(Reader, 100);
1296
1297
if (opts::dump::DumpTypes) {
1298
dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
1299
opts::dump::DumpTypeData, false);
1300
} else if (opts::dump::DumpTypeExtras) {
1301
auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
1302
auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
1303
assert(LocalHashes.size() == GlobalHashes.size());
1304
1305
P.formatLine("Local / Global hashes:");
1306
TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
1307
for (auto H : zip(LocalHashes, GlobalHashes)) {
1308
AutoIndent Indent2(P);
1309
LocallyHashedType &L = std::get<0>(H);
1310
GloballyHashedType &G = std::get<1>(H);
1311
1312
P.formatLine("TI: {0}, LocalHash: {1:X}, GlobalHash: {2}", TI, L, G);
1313
1314
++TI;
1315
}
1316
P.NewLine();
1317
}
1318
}
1319
1320
return Error::success();
1321
}
1322
1323
Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
1324
assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
1325
1326
if (StreamIdx == StreamTPI) {
1327
printHeader(P, "Types (TPI Stream)");
1328
} else if (StreamIdx == StreamIPI) {
1329
printHeader(P, "Types (IPI Stream)");
1330
}
1331
1332
assert(!File.isObj());
1333
1334
bool Present = false;
1335
bool DumpTypes = false;
1336
bool DumpBytes = false;
1337
bool DumpExtras = false;
1338
std::vector<uint32_t> Indices;
1339
if (StreamIdx == StreamTPI) {
1340
Present = getPdb().hasPDBTpiStream();
1341
DumpTypes = opts::dump::DumpTypes;
1342
DumpBytes = opts::dump::DumpTypeData;
1343
DumpExtras = opts::dump::DumpTypeExtras;
1344
Indices.assign(opts::dump::DumpTypeIndex.begin(),
1345
opts::dump::DumpTypeIndex.end());
1346
} else if (StreamIdx == StreamIPI) {
1347
Present = getPdb().hasPDBIpiStream();
1348
DumpTypes = opts::dump::DumpIds;
1349
DumpBytes = opts::dump::DumpIdData;
1350
DumpExtras = opts::dump::DumpIdExtras;
1351
Indices.assign(opts::dump::DumpIdIndex.begin(),
1352
opts::dump::DumpIdIndex.end());
1353
}
1354
1355
if (!Present) {
1356
printStreamNotPresent(StreamIdx == StreamTPI ? "TPI" : "IPI");
1357
return Error::success();
1358
}
1359
1360
AutoIndent Indent(P);
1361
ExitOnError Err("Unexpected error processing types: ");
1362
1363
auto &Stream = Err((StreamIdx == StreamTPI) ? getPdb().getPDBTpiStream()
1364
: getPdb().getPDBIpiStream());
1365
1366
auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
1367
1368
// Only emit notes about referenced/unreferenced for types.
1369
TypeReferenceTracker *MaybeTracker =
1370
(StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
1371
1372
// Enable resolving forward decls.
1373
Stream.buildHashMap();
1374
1375
if (DumpTypes || !Indices.empty()) {
1376
if (Indices.empty())
1377
dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
1378
Stream.getNumHashBuckets(), Stream.getHashValues(),
1379
&Stream, DumpBytes, DumpExtras);
1380
else {
1381
std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
1382
dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
1383
DumpExtras, opts::dump::DumpTypeDependents);
1384
}
1385
}
1386
1387
if (DumpExtras) {
1388
P.NewLine();
1389
1390
P.formatLine("Header Version: {0}",
1391
static_cast<uint32_t>(Stream.getTpiVersion()));
1392
P.formatLine("Hash Stream Index: {0}", Stream.getTypeHashStreamIndex());
1393
P.formatLine("Aux Hash Stream Index: {0}",
1394
Stream.getTypeHashStreamAuxIndex());
1395
P.formatLine("Hash Key Size: {0}", Stream.getHashKeySize());
1396
P.formatLine("Num Hash Buckets: {0}", Stream.getNumHashBuckets());
1397
1398
auto IndexOffsets = Stream.getTypeIndexOffsets();
1399
P.formatLine("Type Index Offsets:");
1400
for (const auto &IO : IndexOffsets) {
1401
AutoIndent Indent2(P);
1402
P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
1403
}
1404
1405
if (getPdb().hasPDBStringTable()) {
1406
P.NewLine();
1407
P.formatLine("Hash Adjusters:");
1408
auto &Adjusters = Stream.getHashAdjusters();
1409
auto &Strings = Err(getPdb().getStringTable());
1410
for (const auto &A : Adjusters) {
1411
AutoIndent Indent2(P);
1412
auto ExpectedStr = Strings.getStringForID(A.first);
1413
TypeIndex TI(A.second);
1414
if (ExpectedStr)
1415
P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
1416
else {
1417
P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
1418
consumeError(ExpectedStr.takeError());
1419
}
1420
}
1421
}
1422
}
1423
return Error::success();
1424
}
1425
1426
Error DumpOutputStyle::dumpModuleSymsForObj() {
1427
printHeader(P, "Symbols");
1428
1429
AutoIndent Indent(P);
1430
1431
auto &Types = File.types();
1432
1433
SymbolVisitorCallbackPipeline Pipeline;
1434
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::ObjectFile);
1435
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types, Types);
1436
1437
Pipeline.addCallbackToPipeline(Deserializer);
1438
Pipeline.addCallbackToPipeline(Dumper);
1439
CVSymbolVisitor Visitor(Pipeline);
1440
1441
return iterateModuleSubsections<DebugSymbolsSubsectionRef>(
1442
File, PrintScope{P, 2},
1443
[&](uint32_t Modi, const SymbolGroup &Strings,
1444
DebugSymbolsSubsectionRef &Symbols) -> Error {
1445
Dumper.setSymbolGroup(&Strings);
1446
for (auto Symbol : Symbols) {
1447
if (auto EC = Visitor.visitSymbolRecord(Symbol)) {
1448
return EC;
1449
}
1450
}
1451
return Error::success();
1452
});
1453
}
1454
1455
Error DumpOutputStyle::dumpModuleSymsForPdb() {
1456
printHeader(P, "Symbols");
1457
1458
if (File.isPdb() && !getPdb().hasPDBDbiStream()) {
1459
printStreamNotPresent("DBI");
1460
return Error::success();
1461
}
1462
1463
AutoIndent Indent(P);
1464
1465
auto &Ids = File.ids();
1466
auto &Types = File.types();
1467
1468
return iterateSymbolGroups(
1469
File, PrintScope{P, 2},
1470
[&](uint32_t I, const SymbolGroup &Strings) -> Error {
1471
auto ExpectedModS = getModuleDebugStream(File.pdb(), I);
1472
if (!ExpectedModS) {
1473
P.formatLine("Error loading module stream {0}. {1}", I,
1474
toString(ExpectedModS.takeError()));
1475
return Error::success();
1476
}
1477
1478
ModuleDebugStreamRef &ModS = *ExpectedModS;
1479
1480
SymbolVisitorCallbackPipeline Pipeline;
1481
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1482
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Strings,
1483
Ids, Types);
1484
1485
Pipeline.addCallbackToPipeline(Deserializer);
1486
Pipeline.addCallbackToPipeline(Dumper);
1487
CVSymbolVisitor Visitor(Pipeline);
1488
auto SS = ModS.getSymbolsSubstream();
1489
if (opts::Filters.SymbolOffset) {
1490
CVSymbolVisitor::FilterOptions Filter;
1491
Filter.SymbolOffset = opts::Filters.SymbolOffset;
1492
Filter.ParentRecursiveDepth = opts::Filters.ParentRecurseDepth;
1493
Filter.ChildRecursiveDepth = opts::Filters.ChildrenRecurseDepth;
1494
if (auto EC = Visitor.visitSymbolStreamFiltered(ModS.getSymbolArray(),
1495
Filter)) {
1496
P.formatLine("Error while processing symbol records. {0}",
1497
toStringWithoutConsuming(EC));
1498
return EC;
1499
}
1500
} else if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray(),
1501
SS.Offset)) {
1502
P.formatLine("Error while processing symbol records. {0}",
1503
toStringWithoutConsuming(EC));
1504
return EC;
1505
}
1506
return Error::success();
1507
});
1508
}
1509
1510
Error DumpOutputStyle::dumpTypeRefStats() {
1511
printHeader(P, "Type Reference Statistics");
1512
AutoIndent Indent(P);
1513
1514
// Sum the byte size of all type records, and the size and count of all
1515
// referenced records.
1516
size_t TotalRecs = File.types().size();
1517
size_t RefRecs = 0;
1518
size_t TotalBytes = 0;
1519
size_t RefBytes = 0;
1520
auto &Types = File.types();
1521
for (std::optional<TypeIndex> TI = Types.getFirst(); TI;
1522
TI = Types.getNext(*TI)) {
1523
CVType Type = File.types().getType(*TI);
1524
TotalBytes += Type.length();
1525
if (RefTracker->isTypeReferenced(*TI)) {
1526
++RefRecs;
1527
RefBytes += Type.length();
1528
}
1529
}
1530
1531
P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
1532
(double)RefRecs / TotalRecs);
1533
P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
1534
(double)RefBytes / TotalBytes);
1535
1536
return Error::success();
1537
}
1538
1539
Error DumpOutputStyle::dumpGSIRecords() {
1540
printHeader(P, "GSI Records");
1541
1542
if (File.isObj()) {
1543
printStreamNotValidForObj();
1544
return Error::success();
1545
}
1546
1547
if (!getPdb().hasPDBSymbolStream()) {
1548
printStreamNotPresent("GSI Common Symbol");
1549
return Error::success();
1550
}
1551
1552
AutoIndent Indent(P);
1553
1554
auto &Records = cantFail(getPdb().getPDBSymbolStream());
1555
auto &Types = File.types();
1556
auto &Ids = File.ids();
1557
1558
P.printLine("Records");
1559
SymbolVisitorCallbackPipeline Pipeline;
1560
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1561
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
1562
1563
Pipeline.addCallbackToPipeline(Deserializer);
1564
Pipeline.addCallbackToPipeline(Dumper);
1565
CVSymbolVisitor Visitor(Pipeline);
1566
1567
BinaryStreamRef SymStream = Records.getSymbolArray().getUnderlyingStream();
1568
if (auto E = Visitor.visitSymbolStream(Records.getSymbolArray(), 0))
1569
return E;
1570
return Error::success();
1571
}
1572
1573
Error DumpOutputStyle::dumpGlobals() {
1574
printHeader(P, "Global Symbols");
1575
1576
if (File.isObj()) {
1577
printStreamNotValidForObj();
1578
return Error::success();
1579
}
1580
1581
if (!getPdb().hasPDBGlobalsStream()) {
1582
printStreamNotPresent("Globals");
1583
return Error::success();
1584
}
1585
1586
AutoIndent Indent(P);
1587
ExitOnError Err("Error dumping globals stream: ");
1588
auto &Globals = Err(getPdb().getPDBGlobalsStream());
1589
1590
if (opts::dump::DumpGlobalNames.empty()) {
1591
const GSIHashTable &Table = Globals.getGlobalsTable();
1592
Err(dumpSymbolsFromGSI(Table, opts::dump::DumpGlobalExtras));
1593
} else {
1594
SymbolStream &SymRecords = cantFail(getPdb().getPDBSymbolStream());
1595
auto &Types = File.types();
1596
auto &Ids = File.ids();
1597
1598
SymbolVisitorCallbackPipeline Pipeline;
1599
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1600
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
1601
1602
Pipeline.addCallbackToPipeline(Deserializer);
1603
Pipeline.addCallbackToPipeline(Dumper);
1604
CVSymbolVisitor Visitor(Pipeline);
1605
1606
using ResultEntryType = std::pair<uint32_t, CVSymbol>;
1607
for (StringRef Name : opts::dump::DumpGlobalNames) {
1608
AutoIndent Indent(P);
1609
P.formatLine("Global Name `{0}`", Name);
1610
std::vector<ResultEntryType> Results =
1611
Globals.findRecordsByName(Name, SymRecords);
1612
if (Results.empty()) {
1613
AutoIndent Indent(P);
1614
P.printLine("(no matching records found)");
1615
continue;
1616
}
1617
1618
for (ResultEntryType Result : Results) {
1619
if (auto E = Visitor.visitSymbolRecord(Result.second, Result.first))
1620
return E;
1621
}
1622
}
1623
}
1624
return Error::success();
1625
}
1626
1627
Error DumpOutputStyle::dumpPublics() {
1628
printHeader(P, "Public Symbols");
1629
1630
if (File.isObj()) {
1631
printStreamNotValidForObj();
1632
return Error::success();
1633
}
1634
1635
if (!getPdb().hasPDBPublicsStream()) {
1636
printStreamNotPresent("Publics");
1637
return Error::success();
1638
}
1639
1640
AutoIndent Indent(P);
1641
ExitOnError Err("Error dumping publics stream: ");
1642
auto &Publics = Err(getPdb().getPDBPublicsStream());
1643
1644
const GSIHashTable &PublicsTable = Publics.getPublicsTable();
1645
if (opts::dump::DumpPublicExtras) {
1646
P.printLine("Publics Header");
1647
AutoIndent Indent(P);
1648
P.formatLine("sym hash = {0}, thunk table addr = {1}", Publics.getSymHash(),
1649
formatSegmentOffset(Publics.getThunkTableSection(),
1650
Publics.getThunkTableOffset()));
1651
}
1652
Err(dumpSymbolsFromGSI(PublicsTable, opts::dump::DumpPublicExtras));
1653
1654
// Skip the rest if we aren't dumping extras.
1655
if (!opts::dump::DumpPublicExtras)
1656
return Error::success();
1657
1658
P.formatLine("Address Map");
1659
{
1660
// These are offsets into the publics stream sorted by secidx:secrel.
1661
AutoIndent Indent2(P);
1662
for (uint32_t Addr : Publics.getAddressMap())
1663
P.formatLine("off = {0}", Addr);
1664
}
1665
1666
// The thunk map is optional debug info used for ILT thunks.
1667
if (!Publics.getThunkMap().empty()) {
1668
P.formatLine("Thunk Map");
1669
AutoIndent Indent2(P);
1670
for (uint32_t Addr : Publics.getThunkMap())
1671
P.formatLine("{0:x8}", Addr);
1672
}
1673
1674
// The section offsets table appears to be empty when incremental linking
1675
// isn't in use.
1676
if (!Publics.getSectionOffsets().empty()) {
1677
P.formatLine("Section Offsets");
1678
AutoIndent Indent2(P);
1679
for (const SectionOffset &SO : Publics.getSectionOffsets())
1680
P.formatLine("{0:x4}:{1:x8}", uint16_t(SO.Isect), uint32_t(SO.Off));
1681
}
1682
1683
return Error::success();
1684
}
1685
1686
Error DumpOutputStyle::dumpSymbolsFromGSI(const GSIHashTable &Table,
1687
bool HashExtras) {
1688
auto ExpectedSyms = getPdb().getPDBSymbolStream();
1689
if (!ExpectedSyms)
1690
return ExpectedSyms.takeError();
1691
auto &Types = File.types();
1692
auto &Ids = File.ids();
1693
1694
if (HashExtras) {
1695
P.printLine("GSI Header");
1696
AutoIndent Indent(P);
1697
P.formatLine("sig = {0:X}, hdr = {1:X}, hr size = {2}, num buckets = {3}",
1698
Table.getVerSignature(), Table.getVerHeader(),
1699
Table.getHashRecordSize(), Table.getNumBuckets());
1700
}
1701
1702
{
1703
P.printLine("Records");
1704
SymbolVisitorCallbackPipeline Pipeline;
1705
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
1706
MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Ids, Types);
1707
1708
Pipeline.addCallbackToPipeline(Deserializer);
1709
Pipeline.addCallbackToPipeline(Dumper);
1710
CVSymbolVisitor Visitor(Pipeline);
1711
1712
1713
BinaryStreamRef SymStream =
1714
ExpectedSyms->getSymbolArray().getUnderlyingStream();
1715
for (uint32_t PubSymOff : Table) {
1716
Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, PubSymOff);
1717
if (!Sym)
1718
return Sym.takeError();
1719
if (auto E = Visitor.visitSymbolRecord(*Sym, PubSymOff))
1720
return E;
1721
}
1722
}
1723
1724
// Return early if we aren't dumping public hash table and address map info.
1725
if (HashExtras) {
1726
P.formatLine("Hash Entries");
1727
{
1728
AutoIndent Indent2(P);
1729
for (const PSHashRecord &HR : Table.HashRecords)
1730
P.formatLine("off = {0}, refcnt = {1}", uint32_t(HR.Off),
1731
uint32_t(HR.CRef));
1732
}
1733
1734
P.formatLine("Hash Buckets");
1735
{
1736
AutoIndent Indent2(P);
1737
for (uint32_t Hash : Table.HashBuckets)
1738
P.formatLine("{0:x8}", Hash);
1739
}
1740
}
1741
1742
return Error::success();
1743
}
1744
1745
static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
1746
OMFSegDescFlags Flags) {
1747
std::vector<std::string> Opts;
1748
if (Flags == OMFSegDescFlags::None)
1749
return "none";
1750
1751
PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
1752
PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
1753
PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
1754
PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
1755
PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
1756
PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
1757
PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
1758
return typesetItemList(Opts, IndentLevel, 4, " | ");
1759
}
1760
1761
Error DumpOutputStyle::dumpSectionHeaders() {
1762
dumpSectionHeaders("Section Headers", DbgHeaderType::SectionHdr);
1763
dumpSectionHeaders("Original Section Headers", DbgHeaderType::SectionHdrOrig);
1764
return Error::success();
1765
}
1766
1767
void DumpOutputStyle::dumpSectionHeaders(StringRef Label, DbgHeaderType Type) {
1768
printHeader(P, Label);
1769
1770
if (File.isObj()) {
1771
printStreamNotValidForObj();
1772
return;
1773
}
1774
1775
if (!getPdb().hasPDBDbiStream()) {
1776
printStreamNotPresent("DBI");
1777
return;
1778
}
1779
1780
AutoIndent Indent(P);
1781
ExitOnError Err("Error dumping section headers: ");
1782
std::unique_ptr<MappedBlockStream> Stream;
1783
ArrayRef<object::coff_section> Headers;
1784
auto ExpectedHeaders = loadSectionHeaders(getPdb(), Type);
1785
if (!ExpectedHeaders) {
1786
P.printLine(toString(ExpectedHeaders.takeError()));
1787
return;
1788
}
1789
std::tie(Stream, Headers) = std::move(*ExpectedHeaders);
1790
1791
uint32_t I = 1;
1792
for (const auto &Header : Headers) {
1793
P.NewLine();
1794
P.formatLine("SECTION HEADER #{0}", I);
1795
P.formatLine("{0,8} name", Header.Name);
1796
P.formatLine("{0,8:X-} virtual size", uint32_t(Header.VirtualSize));
1797
P.formatLine("{0,8:X-} virtual address", uint32_t(Header.VirtualAddress));
1798
P.formatLine("{0,8:X-} size of raw data", uint32_t(Header.SizeOfRawData));
1799
P.formatLine("{0,8:X-} file pointer to raw data",
1800
uint32_t(Header.PointerToRawData));
1801
P.formatLine("{0,8:X-} file pointer to relocation table",
1802
uint32_t(Header.PointerToRelocations));
1803
P.formatLine("{0,8:X-} file pointer to line numbers",
1804
uint32_t(Header.PointerToLinenumbers));
1805
P.formatLine("{0,8:X-} number of relocations",
1806
uint32_t(Header.NumberOfRelocations));
1807
P.formatLine("{0,8:X-} number of line numbers",
1808
uint32_t(Header.NumberOfLinenumbers));
1809
P.formatLine("{0,8:X-} flags", uint32_t(Header.Characteristics));
1810
AutoIndent IndentMore(P, 9);
1811
P.formatLine("{0}", formatSectionCharacteristics(
1812
P.getIndentLevel(), Header.Characteristics, 1, ""));
1813
++I;
1814
}
1815
}
1816
1817
Error DumpOutputStyle::dumpSectionContribs() {
1818
printHeader(P, "Section Contributions");
1819
1820
if (File.isObj()) {
1821
printStreamNotValidForObj();
1822
return Error::success();
1823
}
1824
1825
if (!getPdb().hasPDBDbiStream()) {
1826
printStreamNotPresent("DBI");
1827
return Error::success();
1828
}
1829
1830
AutoIndent Indent(P);
1831
ExitOnError Err("Error dumping section contributions: ");
1832
1833
DbiStream &Dbi = Err(getPdb().getPDBDbiStream());
1834
1835
class Visitor : public ISectionContribVisitor {
1836
public:
1837
Visitor(LinePrinter &P, ArrayRef<std::string> Names) : P(P), Names(Names) {
1838
auto Max = llvm::max_element(Names, [](StringRef S1, StringRef S2) {
1839
return S1.size() < S2.size();
1840
});
1841
MaxNameLen = (Max == Names.end() ? 0 : Max->size());
1842
}
1843
void visit(const SectionContrib &SC) override {
1844
dumpSectionContrib(P, SC, Names, MaxNameLen);
1845
}
1846
void visit(const SectionContrib2 &SC) override {
1847
dumpSectionContrib(P, SC, Names, MaxNameLen);
1848
}
1849
1850
private:
1851
LinePrinter &P;
1852
uint32_t MaxNameLen;
1853
ArrayRef<std::string> Names;
1854
};
1855
1856
auto NamesOrErr = getSectionNames(getPdb());
1857
if (!NamesOrErr)
1858
return NamesOrErr.takeError();
1859
ArrayRef<std::string> Names = *NamesOrErr;
1860
Visitor V(P, Names);
1861
Dbi.visitSectionContributions(V);
1862
return Error::success();
1863
}
1864
1865
Error DumpOutputStyle::dumpSectionMap() {
1866
printHeader(P, "Section Map");
1867
1868
if (File.isObj()) {
1869
printStreamNotValidForObj();
1870
return Error::success();
1871
}
1872
1873
if (!getPdb().hasPDBDbiStream()) {
1874
printStreamNotPresent("DBI");
1875
return Error::success();
1876
}
1877
1878
AutoIndent Indent(P);
1879
ExitOnError Err("Error dumping section map: ");
1880
1881
DbiStream &Dbi = Err(getPdb().getPDBDbiStream());
1882
1883
uint32_t I = 0;
1884
for (auto &M : Dbi.getSectionMap()) {
1885
P.formatLine(
1886
"Section {0:4} | ovl = {1}, group = {2}, frame = {3}, name = {4}", I,
1887
fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1888
P.formatLine(" class = {0}, offset = {1}, size = {2}",
1889
fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1890
P.formatLine(" flags = {0}",
1891
formatSegMapDescriptorFlag(
1892
P.getIndentLevel() + 13,
1893
static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
1894
++I;
1895
}
1896
return Error::success();
1897
}
1898
1899