llvm.org GIT mirror llvm / 0895032
[llvm-pdbutil] Rename "raw" to "dump". Now you run llvm-pdbutil dump <options>. This is a followup after having renamed the tool, whereas before raw was obviously just the style of dumping, whereas now "dump" is the action to perform with the "util". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306055 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
13 changed file(s) with 1222 addition(s) and 1221 deletion(s). Raw diff Collapse all Expand all
0 ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml
11 ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml
22 ; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
3 ; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s
4 ; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s
3 ; RUN: llvm-pdbutil dump -types %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s
4 ; RUN: llvm-pdbutil dump -ids %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s
55
66 TPI-TYPES: Types (TPI Stream)
77 TPI-TYPES-NEXT: ============================================================
0 ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml
11 ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml
22 ; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
3 ; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=MERGED %s
4 ; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s
3 ; RUN: llvm-pdbutil dump -ids %t.3.pdb | FileCheck -check-prefix=MERGED %s
4 ; RUN: llvm-pdbutil dump -types %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s
55
66
77 MERGED: Types (IPI Stream)
0 +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml
11 ; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml
22 ; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
3 ; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=MERGED %s
3 ; RUN: llvm-pdbutil dump -types %t.3.pdb | FileCheck -check-prefix=MERGED %s
44
55
66 MERGED: Types (TPI Stream)
None ; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
1 ; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
2 ; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
3 ; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
4 ; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
0 ; RUN: llvm-pdbutil dump -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
1 ; RUN: llvm-pdbutil dump -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
2 ; RUN: not llvm-pdbutil dump -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
3 ; RUN: not llvm-pdbutil dump -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
4 ; RUN: not llvm-pdbutil dump -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
55
66 BLOCK0: MSF Blocks
77 BLOCK0-NEXT: ============================================================
None ; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
1 ; RUN: llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
2 ; RUN: llvm-pdbutil raw -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
0 ; RUN: llvm-pdbutil dump -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
1 ; RUN: llvm-pdbutil dump -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
2 ; RUN: llvm-pdbutil dump -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
33
44 STREAM: Stream Data
55 STREAM-NEXT: ============================================================
22 RUN: -stream-metadata %p/Inputs/empty.pdb > %t.1
33 RUN: llvm-pdbutil yaml2pdb -pdb=%t.2 %t.1
44
5 RUN: llvm-pdbutil raw -summary -string-table -types %p/Inputs/empty.pdb | FileCheck %s
6 RUN: llvm-pdbutil raw -summary -string-table -types %t.2 | FileCheck %s
5 RUN: llvm-pdbutil dump -summary -string-table -types %p/Inputs/empty.pdb | FileCheck %s
6 RUN: llvm-pdbutil dump -summary -string-table -types %t.2 | FileCheck %s
77
88
99 CHECK: Summary
99 add_llvm_tool(llvm-pdbutil
1010 Analyze.cpp
1111 Diff.cpp
12 DumpOutputStyle.cpp
1213 llvm-pdbutil.cpp
1314 FormatUtil.cpp
1415 LinePrinter.cpp
2526 PrettyTypeDumper.cpp
2627 PrettyTypedefDumper.cpp
2728 PrettyVariableDumper.cpp
28 RawOutputStyle.cpp
2929 StreamUtil.cpp
3030 YAMLOutputStyle.cpp
3131 )
0 //===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "DumpOutputStyle.h"
10
11 #include "FormatUtil.h"
12 #include "MinimalSymbolDumper.h"
13 #include "MinimalTypeDumper.h"
14 #include "StreamUtil.h"
15 #include "llvm-pdbutil.h"
16
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
19 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
20 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
21 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
22 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
25 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
28 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
30 #include "llvm/DebugInfo/CodeView/EnumTables.h"
31 #include "llvm/DebugInfo/CodeView/Formatters.h"
32 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
33 #include "llvm/DebugInfo/CodeView/Line.h"
34 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
35 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
36 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
37 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
38 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
39 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
40 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
41 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
42 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
43 #include "llvm/DebugInfo/PDB/Native/EnumTables.h"
44 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
45 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
46 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
47 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
48 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
49 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
50 #include "llvm/DebugInfo/PDB/Native/RawError.h"
51 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
52 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
53 #include "llvm/DebugInfo/PDB/PDBExtras.h"
54 #include "llvm/Object/COFF.h"
55 #include "llvm/Support/BinaryStreamReader.h"
56 #include "llvm/Support/FormatAdapters.h"
57 #include "llvm/Support/FormatVariadic.h"
58
59 #include
60
61 using namespace llvm;
62 using namespace llvm::codeview;
63 using namespace llvm::msf;
64 using namespace llvm::pdb;
65
66 DumpOutputStyle::DumpOutputStyle(PDBFile &File)
67 : File(File), P(2, false, outs()) {}
68
69 Error DumpOutputStyle::dump() {
70 if (opts::dump::DumpSummary) {
71 if (auto EC = dumpFileSummary())
72 return EC;
73 P.NewLine();
74 }
75
76 if (opts::dump::DumpStreams) {
77 if (auto EC = dumpStreamSummary())
78 return EC;
79 P.NewLine();
80 }
81
82 if (opts::dump::DumpBlockRange.hasValue()) {
83 if (auto EC = dumpBlockRanges())
84 return EC;
85 P.NewLine();
86 }
87
88 if (!opts::dump::DumpStreamData.empty()) {
89 if (auto EC = dumpStreamBytes())
90 return EC;
91 P.NewLine();
92 }
93
94 if (opts::dump::DumpStringTable) {
95 if (auto EC = dumpStringTable())
96 return EC;
97 P.NewLine();
98 }
99
100 if (opts::dump::DumpModules) {
101 if (auto EC = dumpModules())
102 return EC;
103 }
104
105 if (opts::dump::DumpModuleFiles) {
106 if (auto EC = dumpModuleFiles())
107 return EC;
108 }
109
110 if (opts::dump::DumpLines) {
111 if (auto EC = dumpLines())
112 return EC;
113 }
114
115 if (opts::dump::DumpInlineeLines) {
116 if (auto EC = dumpInlineeLines())
117 return EC;
118 }
119
120 if (opts::dump::DumpXmi) {
121 if (auto EC = dumpXmi())
122 return EC;
123 }
124
125 if (opts::dump::DumpXme) {
126 if (auto EC = dumpXme())
127 return EC;
128 }
129
130 if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) {
131 if (auto EC = dumpTpiStream(StreamTPI))
132 return EC;
133 }
134
135 if (opts::dump::DumpIds || opts::dump::DumpIdExtras) {
136 if (auto EC = dumpTpiStream(StreamIPI))
137 return EC;
138 }
139
140 if (opts::dump::DumpPublics) {
141 if (auto EC = dumpPublics())
142 return EC;
143 }
144
145 if (opts::dump::DumpSymbols) {
146 if (auto EC = dumpModuleSyms())
147 return EC;
148 }
149
150 if (opts::dump::DumpSectionContribs) {
151 if (auto EC = dumpSectionContribs())
152 return EC;
153 }
154
155 if (opts::dump::DumpSectionMap) {
156 if (auto EC = dumpSectionMap())
157 return EC;
158 }
159
160 return Error::success();
161 }
162
163 static void printHeader(LinePrinter &P, const Twine &S) {
164 P.NewLine();
165 P.formatLine("{0,=60}", S);
166 P.formatLine("{0}", fmt_repeat('=', 60));
167 }
168
169 Error DumpOutputStyle::dumpFileSummary() {
170 printHeader(P, "Summary");
171
172 ExitOnError Err("Invalid PDB Format");
173
174 AutoIndent Indent(P);
175 P.formatLine("Block Size: {0}", File.getBlockSize());
176 P.formatLine("Number of blocks: {0}", File.getBlockCount());
177 P.formatLine("Number of streams: {0}", File.getNumStreams());
178
179 auto &PS = Err(File.getPDBInfoStream());
180 P.formatLine("Signature: {0}", PS.getSignature());
181 P.formatLine("Age: {0}", PS.getAge());
182 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
183 P.formatLine("Features: {0:x+}", static_cast(PS.getFeatures()));
184 P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
185 P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
186 P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
187 P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
188 P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
189 if (File.hasPDBDbiStream()) {
190 auto &DBI = Err(File.getPDBDbiStream());
191 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
192 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
193 P.formatLine("Is stripped: {0}", DBI.isStripped());
194 }
195
196 return Error::success();
197 }
198
199 Error DumpOutputStyle::dumpStreamSummary() {
200 printHeader(P, "Streams");
201
202 if (StreamPurposes.empty())
203 discoverStreamPurposes(File, StreamPurposes);
204
205 AutoIndent Indent(P);
206 uint32_t StreamCount = File.getNumStreams();
207
208 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
209 P.formatLine(
210 "Stream {0}: [{1}] ({2} bytes)",
211 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
212 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
213 }
214
215 return Error::success();
216 }
217
218 Error DumpOutputStyle::dumpBlockRanges() {
219 printHeader(P, "MSF Blocks");
220
221 auto &R = *opts::dump::DumpBlockRange;
222 uint32_t Max = R.Max.getValueOr(R.Min);
223
224 AutoIndent Indent(P);
225 if (Max < R.Min)
226 return make_error(
227 "Invalid block range specified. Max < Min",
228 std::make_error_code(std::errc::bad_address));
229 if (Max >= File.getBlockCount())
230 return make_error(
231 "Invalid block range specified. Requested block out of bounds",
232 std::make_error_code(std::errc::bad_address));
233
234 for (uint32_t I = R.Min; I <= Max; ++I) {
235 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
236 if (!ExpectedData)
237 return ExpectedData.takeError();
238 std::string Label = formatv("Block {0}", I).str();
239 P.formatBinary(Label, *ExpectedData, 0);
240 }
241
242 return Error::success();
243 }
244
245 static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
246 uint32_t &Size) {
247 if (Str.consumeInteger(0, SI))
248 return make_error(raw_error_code::invalid_format,
249 "Invalid Stream Specification");
250 if (Str.consume_front(":")) {
251 if (Str.consumeInteger(0, Offset))
252 return make_error(raw_error_code::invalid_format,
253 "Invalid Stream Specification");
254 }
255 if (Str.consume_front("@")) {
256 if (Str.consumeInteger(0, Size))
257 return make_error(raw_error_code::invalid_format,
258 "Invalid Stream Specification");
259 }
260 if (!Str.empty())
261 return make_error(raw_error_code::invalid_format,
262 "Invalid Stream Specification");
263 return Error::success();
264 }
265
266 Error DumpOutputStyle::dumpStreamBytes() {
267 if (StreamPurposes.empty())
268 discoverStreamPurposes(File, StreamPurposes);
269
270 printHeader(P, "Stream Data");
271 ExitOnError Err("Unexpected error reading stream data");
272
273 for (auto &Str : opts::dump::DumpStreamData) {
274 uint32_t SI = 0;
275 uint32_t Begin = 0;
276 uint32_t Size = 0;
277 uint32_t End = 0;
278
279 if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
280 return EC;
281
282 AutoIndent Indent(P);
283 if (SI >= File.getNumStreams()) {
284 P.formatLine("Stream {0}: Not present", SI);
285 continue;
286 }
287
288 auto S = MappedBlockStream::createIndexedStream(
289 File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
290 if (!S) {
291 P.NewLine();
292 P.formatLine("Stream {0}: Not present", SI);
293 continue;
294 }
295
296 if (Size == 0)
297 End = S->getLength();
298 else
299 End = std::min(Begin + Size, S->getLength());
300
301 P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
302 StreamPurposes[SI]);
303 AutoIndent Indent2(P);
304
305 BinaryStreamReader R(*S);
306 ArrayRef StreamData;
307 Err(R.readBytes(StreamData, S->getLength()));
308 Size = End - Begin;
309 StreamData = StreamData.slice(Begin, Size);
310 P.formatBinary("Data", StreamData, Begin);
311 }
312 return Error::success();
313 }
314
315 static Expected getModuleDebugStream(PDBFile &File,
316 uint32_t Index) {
317 ExitOnError Err("Unexpected error");
318
319 auto &Dbi = Err(File.getPDBDbiStream());
320 const auto &Modules = Dbi.modules();
321 auto Modi = Modules.getModuleDescriptor(Index);
322
323 uint16_t ModiStream = Modi.getModuleStreamIndex();
324 if (ModiStream == kInvalidStreamIndex)
325 return make_error(raw_error_code::no_stream,
326 "Module stream not present");
327
328 auto ModStreamData = MappedBlockStream::createIndexedStream(
329 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
330 File.getAllocator());
331
332 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
333 if (auto EC = ModS.reload())
334 return make_error(raw_error_code::corrupt_file,
335 "Invalid module stream");
336
337 return std::move(ModS);
338 }
339
340 static std::string formatChecksumKind(FileChecksumKind Kind) {
341 switch (Kind) {
342 RETURN_CASE(FileChecksumKind, None, "None");
343 RETURN_CASE(FileChecksumKind, MD5, "MD5");
344 RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
345 RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
346 }
347 return formatUnknownEnum(Kind);
348 }
349
350 namespace {
351 class StringsAndChecksumsPrinter {
352 const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
353 ExitOnError Err("Unexpected error processing modules");
354 return Err(File.getStringTable()).getStringTable();
355 }
356
357 template
358 void formatInternal(LinePrinter &Printer, bool Append,
359 Args &&... args) const {
360 if (Append)
361 Printer.format(std::forward(args)...);
362 else
363 Printer.formatLine(std::forward(args)...);
364 }
365
366 public:
367 StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
368 : Records(extractStringTable(File)) {
369 auto MDS = getModuleDebugStream(File, Modi);
370 if (!MDS) {
371 consumeError(MDS.takeError());
372 return;
373 }
374
375 DebugStream = llvm::make_unique(std::move(*MDS));
376 Records.initialize(MDS->subsections());
377 if (Records.hasChecksums()) {
378 for (const auto &Entry : Records.checksums()) {
379 auto S = Records.strings().getString(Entry.FileNameOffset);
380 if (!S)
381 continue;
382 ChecksumsByFile[*S] = Entry;
383 }
384 }
385 }
386
387 Expected getNameFromStringTable(uint32_t Offset) const {
388 return Records.strings().getString(Offset);
389 }
390
391 void formatFromFileName(LinePrinter &Printer, StringRef File,
392 bool Append = false) const {
393 auto FC = ChecksumsByFile.find(File);
394 if (FC == ChecksumsByFile.end()) {
395 formatInternal(Printer, Append, "- (no checksum) {0}", File);
396 return;
397 }
398
399 formatInternal(Printer, Append, "- ({0}: {1}) {2}",
400 formatChecksumKind(FC->getValue().Kind),
401 toHex(FC->getValue().Checksum), File);
402 }
403
404 void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
405 bool Append = false) const {
406 if (!Records.hasChecksums()) {
407 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
408 return;
409 }
410
411 auto Iter = Records.checksums().getArray().at(Offset);
412 if (Iter == Records.checksums().getArray().end()) {
413 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
414 return;
415 }
416
417 uint32_t FO = Iter->FileNameOffset;
418 auto ExpectedFile = getNameFromStringTable(FO);
419 if (!ExpectedFile) {
420 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
421 consumeError(ExpectedFile.takeError());
422 return;
423 }
424 if (Iter->Kind == FileChecksumKind::None) {
425 formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
426 } else {
427 formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
428 formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
429 }
430 }
431
432 std::unique_ptr DebugStream;
433 StringsAndChecksumsRef Records;
434 StringMap ChecksumsByFile;
435 };
436 } // namespace
437
438 template
439 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
440 CallbackT Callback) {
441 AutoIndent Indent(P);
442 if (!File.hasPDBDbiStream()) {
443 P.formatLine("DBI Stream not present");
444 return;
445 }
446
447 ExitOnError Err("Unexpected error processing modules");
448
449 auto &Stream = Err(File.getPDBDbiStream());
450
451 const DbiModuleList &Modules = Stream.modules();
452 uint32_t Count = Modules.getModuleCount();
453 uint32_t Digits = NumDigits(Count);
454 for (uint32_t I = 0; I < Count; ++I) {
455 auto Modi = Modules.getModuleDescriptor(I);
456 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
457 Modi.getModuleName());
458
459 StringsAndChecksumsPrinter Strings(File, I);
460 AutoIndent Indent2(P, IndentLevel);
461 Callback(I, Strings);
462 }
463 }
464
465 template
466 static void iterateModuleSubsections(
467 PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
468 llvm::function_ref
469 SubsectionT &)>
470 Callback) {
471
472 iterateModules(
473 File, P, IndentLevel,
474 [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
475 auto MDS = getModuleDebugStream(File, Modi);
476 if (!MDS) {
477 consumeError(MDS.takeError());
478 return;
479 }
480
481 for (const auto &SS : MDS->subsections()) {
482 SubsectionT Subsection;
483
484 if (SS.kind() != Subsection.kind())
485 continue;
486
487 BinaryStreamReader Reader(SS.getRecordData());
488 if (auto EC = Subsection.initialize(Reader))
489 continue;
490 Callback(Modi, Strings, Subsection);
491 }
492 });
493 }
494
495 Error DumpOutputStyle::dumpModules() {
496 printHeader(P, "Modules");
497
498 AutoIndent Indent(P);
499 if (!File.hasPDBDbiStream()) {
500 P.formatLine("DBI Stream not present");
501 return Error::success();
502 }
503
504 ExitOnError Err("Unexpected error processing modules");
505
506 auto &Stream = Err(File.getPDBDbiStream());
507
508 const DbiModuleList &Modules = Stream.modules();
509 uint32_t Count = Modules.getModuleCount();
510 uint32_t Digits = NumDigits(Count);
511 for (uint32_t I = 0; I < Count; ++I) {
512 auto Modi = Modules.getModuleDescriptor(I);
513 P.formatLine("Mod {0:4} | Name: `{1}`: ",
514 fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
515 P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
516 P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
517 Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
518 Modi.hasECInfo());
519 }
520 return Error::success();
521 }
522
523 Error DumpOutputStyle::dumpModuleFiles() {
524 printHeader(P, "Files");
525
526 ExitOnError Err("Unexpected error processing modules");
527
528 iterateModules(
529 File, P, 11,
530 [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
531 auto &Stream = Err(File.getPDBDbiStream());
532
533 const DbiModuleList &Modules = Stream.modules();
534 for (const auto &F : Modules.source_files(Modi)) {
535 Strings.formatFromFileName(P, F);
536 }
537 });
538 return Error::success();
539 }
540
541 static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
542 uint32_t Start, const LineColumnEntry &E) {
543 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
544 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
545
546 // Let's try to keep it under 100 characters
547 constexpr uint32_t kMaxRowLength = 100;
548 // At least 3 spaces between columns.
549 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
550 uint32_t ItemsLeft = E.LineNumbers.size();
551 auto LineIter = E.LineNumbers.begin();
552 while (ItemsLeft != 0) {
553 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
554 for (uint32_t I = 0; I < RowColumns; ++I) {
555 LineInfo Line(LineIter->Flags);
556 std::string LineStr;
557 if (Line.isAlwaysStepInto())
558 LineStr = "ASI";
559 else if (Line.isNeverStepInto())
560 LineStr = "NSI";
561 else
562 LineStr = utostr(Line.getStartLine());
563 char Statement = Line.isStatement() ? ' ' : '!';
564 P.format("{0} {1:X-} {2} ",
565 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
566 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
567 Statement);
568 ++LineIter;
569 --ItemsLeft;
570 }
571 P.NewLine();
572 }
573 }
574
575 Error DumpOutputStyle::dumpLines() {
576 printHeader(P, "Lines");
577
578 uint32_t LastModi = UINT32_MAX;
579 uint32_t LastNameIndex = UINT32_MAX;
580 iterateModuleSubsections(
581 File, P, 4,
582 [this, &LastModi, &LastNameIndex](uint32_t Modi,
583 StringsAndChecksumsPrinter &Strings,
584 DebugLinesSubsectionRef &Lines) {
585 uint16_t Segment = Lines.header()->RelocSegment;
586 uint32_t Begin = Lines.header()->RelocOffset;
587 uint32_t End = Begin + Lines.header()->CodeSize;
588 for (const auto &Block : Lines) {
589 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
590 LastModi = Modi;
591 LastNameIndex = Block.NameIndex;
592 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
593 }
594
595 AutoIndent Indent(P, 2);
596 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
597 uint32_t Count = Block.LineNumbers.size();
598 if (Lines.hasColumnInfo())
599 P.format("line/column/addr entries = {0}", Count);
600 else
601 P.format("line/addr entries = {0}", Count);
602
603 P.NewLine();
604 typesetLinesAndColumns(File, P, Begin, Block);
605 }
606 });
607
608 return Error::success();
609 }
610
611 Error DumpOutputStyle::dumpInlineeLines() {
612 printHeader(P, "Inlinee Lines");
613
614 iterateModuleSubsections(
615 File, P, 2,
616 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
617 DebugInlineeLinesSubsectionRef &Lines) {
618 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
619 for (const auto &Entry : Lines) {
620 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
621 fmtle(Entry.Header->SourceLineNum));
622 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
623 }
624 P.NewLine();
625 });
626
627 return Error::success();
628 }
629
630 Error DumpOutputStyle::dumpXmi() {
631 printHeader(P, "Cross Module Imports");
632 iterateModuleSubsections(
633 File, P, 2,
634 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
635 DebugCrossModuleImportsSubsectionRef &Imports) {
636 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
637
638 for (const auto &Xmi : Imports) {
639 auto ExpectedModule =
640 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
641 StringRef Module;
642 SmallString<32> ModuleStorage;
643 if (!ExpectedModule) {
644 Module = "(unknown module)";
645 consumeError(ExpectedModule.takeError());
646 } else
647 Module = *ExpectedModule;
648 if (Module.size() > 32) {
649 ModuleStorage = "...";
650 ModuleStorage += Module.take_back(32 - 3);
651 Module = ModuleStorage;
652 }
653 std::vector TIs;
654 for (const auto I : Xmi.Imports)
655 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
656 std::string Result =
657 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
658 P.formatLine("{0,+32} | {1}", Module, Result);
659 }
660 });
661
662 return Error::success();
663 }
664
665 Error DumpOutputStyle::dumpXme() {
666 printHeader(P, "Cross Module Exports");
667
668 iterateModuleSubsections(
669 File, P, 2,
670 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
671 DebugCrossModuleExportsSubsectionRef &Exports) {
672 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
673 for (const auto &Export : Exports) {
674 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
675 TypeIndex(Export.Global));
676 }
677 });
678
679 return Error::success();
680 }
681
682 Error DumpOutputStyle::dumpStringTable() {
683 printHeader(P, "String Table");
684
685 AutoIndent Indent(P);
686 auto IS = File.getStringTable();
687 if (!IS) {
688 P.formatLine("Not present in file");
689 consumeError(IS.takeError());
690 return Error::success();
691 }
692
693 if (IS->name_ids().empty()) {
694 P.formatLine("Empty");
695 return Error::success();
696 }
697
698 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
699 uint32_t Digits = NumDigits(*MaxID);
700
701 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
702 "String");
703
704 std::vector SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
705 std::sort(SortedIDs.begin(), SortedIDs.end());
706 for (uint32_t I : SortedIDs) {
707 auto ES = IS->getStringForID(I);
708 llvm::SmallString<32> Str;
709 if (!ES) {
710 consumeError(ES.takeError());
711 Str = "Error reading string";
712 } else if (!ES->empty()) {
713 Str.append("'");
714 Str.append(*ES);
715 Str.append("'");
716 }
717
718 if (!Str.empty())
719 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
720 }
721 return Error::success();
722 }
723
724 Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
725 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
726
727 bool Present = false;
728 bool DumpTypes = false;
729 bool DumpBytes = false;
730 bool DumpExtras = false;
731 std::vector Indices;
732 if (StreamIdx == StreamTPI) {
733 printHeader(P, "Types (TPI Stream)");
734 Present = File.hasPDBTpiStream();
735 DumpTypes = opts::dump::DumpTypes;
736 DumpBytes = opts::dump::DumpTypeData;
737 DumpExtras = opts::dump::DumpTypeExtras;
738 Indices.assign(opts::dump::DumpTypeIndex.begin(),
739 opts::dump::DumpTypeIndex.end());
740 } else if (StreamIdx == StreamIPI) {
741 printHeader(P, "Types (IPI Stream)");
742 Present = File.hasPDBIpiStream();
743 DumpTypes = opts::dump::DumpIds;
744 DumpBytes = opts::dump::DumpIdData;
745 DumpExtras = opts::dump::DumpIdExtras;
746 Indices.assign(opts::dump::DumpIdIndex.begin(),
747 opts::dump::DumpIdIndex.end());
748 }
749
750 AutoIndent Indent(P);
751 if (!Present) {
752 P.formatLine("Stream not present");
753 return Error::success();
754 }
755
756 ExitOnError Err("Unexpected error processing types");
757
758 auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
759 : File.getPDBIpiStream());
760
761 auto &Types = Err(initializeTypes(StreamIdx));
762
763 if (DumpTypes) {
764 P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
765 uint32_t Width =
766 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
767
768 MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
769 Stream.getHashValues());
770
771 if (Indices.empty()) {
772 if (auto EC = codeview::visitTypeStream(Types, V)) {
773 P.formatLine("An error occurred dumping type records: {0}",
774 toString(std::move(EC)));
775 }
776 } else {
777 for (const auto &I : Indices) {
778 TypeIndex TI(I);
779 CVType Type = Types.getType(TI);
780 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
781 P.formatLine("An error occurred dumping type record {0}: {1}", TI,
782 toString(std::move(EC)));
783 }
784 }
785 }
786
787 if (DumpExtras) {
788 P.NewLine();
789 auto IndexOffsets = Stream.getTypeIndexOffsets();
790 P.formatLine("Type Index Offsets:");
791 for (const auto &IO : IndexOffsets) {
792 AutoIndent Indent2(P);
793 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
794 }
795
796 P.NewLine();
797 P.formatLine("Hash Adjusters:");
798 auto &Adjusters = Stream.getHashAdjusters();
799 auto &Strings = Err(File.getStringTable());
800 for (const auto &A : Adjusters) {
801 AutoIndent Indent2(P);
802 auto ExpectedStr = Strings.getStringForID(A.first);
803 TypeIndex TI(A.second);
804 if (ExpectedStr)
805 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
806 else {
807 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
808 consumeError(ExpectedStr.takeError());
809 }
810 }
811 }
812 return Error::success();
813 }
814
815 Expected
816 DumpOutputStyle::initializeTypes(uint32_t SN) {
817 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
818 auto Tpi =
819 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
820 if (!Tpi)
821 return Tpi.takeError();
822
823 if (!TypeCollection) {
824 auto &Types = Tpi->typeArray();
825 uint32_t Count = Tpi->getNumTypeRecords();
826 auto Offsets = Tpi->getTypeIndexOffsets();
827 TypeCollection =
828 llvm::make_unique(Types, Count, Offsets);
829 }
830
831 return *TypeCollection;
832 }
833
834 Error DumpOutputStyle::dumpModuleSyms() {
835 printHeader(P, "Symbols");
836
837 AutoIndent Indent(P);
838 if (!File.hasPDBDbiStream()) {
839 P.formatLine("DBI Stream not present");
840 return Error::success();
841 }
842
843 ExitOnError Err("Unexpected error processing symbols");
844
845 auto &Stream = Err(File.getPDBDbiStream());
846
847 auto &Types = Err(initializeTypes(StreamTPI));
848
849 const DbiModuleList &Modules = Stream.modules();
850 uint32_t Count = Modules.getModuleCount();
851 uint32_t Digits = NumDigits(Count);
852 for (uint32_t I = 0; I < Count; ++I) {
853 auto Modi = Modules.getModuleDescriptor(I);
854 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
855 Modi.getModuleName());
856 uint16_t ModiStream = Modi.getModuleStreamIndex();
857 if (ModiStream == kInvalidStreamIndex) {
858 P.formatLine(" ");
859 continue;
860 }
861 auto ModStreamData = MappedBlockStream::createIndexedStream(
862 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
863 File.getAllocator());
864
865 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
866 if (auto EC = ModS.reload()) {
867 P.formatLine("Error loading module stream {0}. {1}", I,
868 toString(std::move(EC)));
869 continue;
870 }
871
872 SymbolVisitorCallbackPipeline Pipeline;
873 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
874 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
875
876 Pipeline.addCallbackToPipeline(Deserializer);
877 Pipeline.addCallbackToPipeline(Dumper);
878 CVSymbolVisitor Visitor(Pipeline);
879 if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) {
880 P.formatLine("Error while processing symbol records. {0}",
881 toString(std::move(EC)));
882 continue;
883 }
884 }
885 return Error::success();
886 }
887
888 Error DumpOutputStyle::dumpPublics() {
889 printHeader(P, "Public Symbols");
890
891 AutoIndent Indent(P);
892 if (!File.hasPDBPublicsStream()) {
893 P.formatLine("Publics stream not present");
894 return Error::success();
895 }
896
897 ExitOnError Err("Error dumping publics stream");
898
899 auto &Types = Err(initializeTypes(StreamTPI));
900 auto &Publics = Err(File.getPDBPublicsStream());
901 SymbolVisitorCallbackPipeline Pipeline;
902 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
903 MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types);
904
905 Pipeline.addCallbackToPipeline(Deserializer);
906 Pipeline.addCallbackToPipeline(Dumper);
907 CVSymbolVisitor Visitor(Pipeline);
908 auto ExpectedSymbols = Publics.getSymbolArray();
909 if (!ExpectedSymbols) {
910 P.formatLine("Could not read public symbol record stream");
911 return Error::success();
912 }
913
914 if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols))
915 P.formatLine("Error while processing public symbol records. {0}",
916 toString(std::move(EC)));
917
918 return Error::success();
919 }
920
921 static std::string formatSectionCharacteristics(uint32_t IndentLevel,
922 uint32_t C) {
923 using SC = COFF::SectionCharacteristics;
924 std::vector Opts;
925 if (C == COFF::SC_Invalid)
926 return "invalid";
927 if (C == 0)
928 return "none";
929
930 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
931 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
932 PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
933 PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
934 "IMAGE_SCN_CNT_INITIALIZED_DATA");
935 PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
936 "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
937 PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
938 PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
939 PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
940 PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
941 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
942 PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
943 PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
944 PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
945 PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
946 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
947 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
948 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
949 "IMAGE_SCN_ALIGN_1BYTES");
950 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
951 "IMAGE_SCN_ALIGN_2BYTES");
952 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
953 "IMAGE_SCN_ALIGN_4BYTES");
954 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
955 "IMAGE_SCN_ALIGN_8BYTES");
956 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
957 "IMAGE_SCN_ALIGN_16BYTES");
958 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
959 "IMAGE_SCN_ALIGN_32BYTES");
960 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
961 "IMAGE_SCN_ALIGN_64BYTES");
962 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
963 "IMAGE_SCN_ALIGN_128BYTES");
964 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
965 "IMAGE_SCN_ALIGN_256BYTES");
966 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
967 "IMAGE_SCN_ALIGN_512BYTES");
968 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
969 "IMAGE_SCN_ALIGN_1024BYTES");
970 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
971 "IMAGE_SCN_ALIGN_2048BYTES");
972 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
973 "IMAGE_SCN_ALIGN_4096BYTES");
974 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
975 "IMAGE_SCN_ALIGN_8192BYTES");
976 PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
977 PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
978 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
979 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
980 PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
981 PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
982 PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
983 PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
984 return typesetItemList(Opts, IndentLevel, 3, " | ");
985 }
986
987 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
988 OMFSegDescFlags Flags) {
989 std::vector Opts;
990 if (Flags == OMFSegDescFlags::None)
991 return "none";
992
993 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
994 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
995 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
996 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
997 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
998 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
999 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
1000 return typesetItemList(Opts, IndentLevel, 4, " | ");
1001 }
1002
1003 Error DumpOutputStyle::dumpSectionContribs() {
1004 printHeader(P, "Section Contributions");
1005 ExitOnError Err("Error dumping publics stream");
1006
1007 AutoIndent Indent(P);
1008 if (!File.hasPDBDbiStream()) {
1009 P.formatLine(
1010 "Section contribs require a DBI Stream, which could not be loaded");
1011 return Error::success();
1012 }
1013
1014 auto &Dbi = Err(File.getPDBDbiStream());
1015
1016 class Visitor : public ISectionContribVisitor {
1017 public:
1018 Visitor(LinePrinter &P) : P(P) {}
1019 void visit(const SectionContrib &SC) override {
1020 P.formatLine(
1021 "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
1022 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
1023 fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
1024 P.formatLine(" {0}",
1025 formatSectionCharacteristics(P.getIndentLevel() + 6,
1026 SC.Characteristics));
1027 }
1028 void visit(const SectionContrib2 &SC) override {
1029 P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1030 "crc = {4}, coff section = {5}",
1031 formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
1032 fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
1033 fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1034 fmtle(SC.ISectCoff));
1035 P.formatLine(" {0}",
1036 formatSectionCharacteristics(P.getIndentLevel() + 6,
1037 SC.Base.Characteristics));
1038 }
1039
1040 private:
1041 LinePrinter &P;
1042 };
1043
1044 Visitor V(P);
1045 Dbi.visitSectionContributions(V);
1046 return Error::success();
1047 }
1048
1049 Error DumpOutputStyle::dumpSectionMap() {
1050 printHeader(P, "Section Map");
1051 ExitOnError Err("Error dumping section map");
1052
1053 AutoIndent Indent(P);
1054 if (!File.hasPDBDbiStream()) {
1055 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1056 "not be loaded");
1057 return Error::success();
1058 }
1059
1060 auto &Dbi = Err(File.getPDBDbiStream());
1061
1062 uint32_t I = 0;
1063 for (auto &M : Dbi.getSectionMap()) {
1064 P.formatLine(
1065 "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
1066 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1067 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1068 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1069 P.formatLine(" flags = {0}",
1070 formatSegMapDescriptorFlag(
1071 P.getIndentLevel() + 13,
1072 static_cast(uint16_t(M.Flags))));
1073 ++I;
1074 }
1075 return Error::success();
1076 }
0 //===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
10 #define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H
11
12 #include "LinePrinter.h"
13 #include "OutputStyle.h"
14
15 #include "llvm/ADT/Optional.h"
16 #include "llvm/ADT/SmallVector.h"
17
18 #include
19
20 namespace llvm {
21 class BitVector;
22
23 namespace codeview {
24 class LazyRandomTypeCollection;
25 }
26
27 namespace pdb {
28 class DumpOutputStyle : public OutputStyle {
29 public:
30 DumpOutputStyle(PDBFile &File);
31
32 Error dump() override;
33
34 private:
35 Expected initializeTypes(uint32_t SN);
36
37 Error dumpFileSummary();
38 Error dumpStreamSummary();
39 Error dumpBlockRanges();
40 Error dumpStreamBytes();
41 Error dumpStringTable();
42 Error dumpLines();
43 Error dumpInlineeLines();
44 Error dumpXmi();
45 Error dumpXme();
46 Error dumpTpiStream(uint32_t StreamIdx);
47 Error dumpModules();
48 Error dumpModuleFiles();
49 Error dumpModuleSyms();
50 Error dumpPublics();
51 Error dumpSectionContribs();
52 Error dumpSectionMap();
53
54 PDBFile &File;
55 LinePrinter P;
56 std::unique_ptr TpiTypes;
57 std::unique_ptr IpiTypes;
58 SmallVector StreamPurposes;
59 };
60 } // namespace pdb
61 } // namespace llvm
62
63 #endif
+0
-1077
tools/llvm-pdbutil/RawOutputStyle.cpp less more
None //===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "RawOutputStyle.h"
10
11 #include "FormatUtil.h"
12 #include "MinimalSymbolDumper.h"
13 #include "MinimalTypeDumper.h"
14 #include "StreamUtil.h"
15 #include "llvm-pdbutil.h"
16
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
19 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
20 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
21 #include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
22 #include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
23 #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
24 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
25 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
26 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
27 #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
28 #include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
29 #include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
30 #include "llvm/DebugInfo/CodeView/EnumTables.h"
31 #include "llvm/DebugInfo/CodeView/Formatters.h"
32 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
33 #include "llvm/DebugInfo/CodeView/Line.h"
34 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
35 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
36 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
37 #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
38 #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
39 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
40 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
41 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
42 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
43 #include "llvm/DebugInfo/PDB/Native/EnumTables.h"
44 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
45 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
46 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
47 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
48 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
49 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
50 #include "llvm/DebugInfo/PDB/Native/RawError.h"
51 #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
52 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
53 #include "llvm/DebugInfo/PDB/PDBExtras.h"
54 #include "llvm/Object/COFF.h"
55 #include "llvm/Support/BinaryStreamReader.h"
56 #include "llvm/Support/FormatAdapters.h"
57 #include "llvm/Support/FormatVariadic.h"
58
59 #include
60
61 using namespace llvm;
62 using namespace llvm::codeview;
63 using namespace llvm::msf;
64 using namespace llvm::pdb;
65
66 RawOutputStyle::RawOutputStyle(PDBFile &File)
67 : File(File), P(2, false, outs()) {}
68
69 Error RawOutputStyle::dump() {
70 if (opts::raw::DumpSummary) {
71 if (auto EC = dumpFileSummary())
72 return EC;
73 P.NewLine();
74 }
75
76 if (opts::raw::DumpStreams) {
77 if (auto EC = dumpStreamSummary())
78 return EC;
79 P.NewLine();
80 }
81
82 if (opts::raw::DumpBlockRange.hasValue()) {
83 if (auto EC = dumpBlockRanges())
84 return EC;
85 P.NewLine();
86 }
87
88 if (!opts::raw::DumpStreamData.empty()) {
89 if (auto EC = dumpStreamBytes())
90 return EC;
91 P.NewLine();
92 }
93
94 if (opts::raw::DumpStringTable) {
95 if (auto EC = dumpStringTable())
96 return EC;
97 P.NewLine();
98 }
99
100 if (opts::raw::DumpModules) {
101 if (auto EC = dumpModules())
102 return EC;
103 }
104
105 if (opts::raw::DumpModuleFiles) {
106 if (auto EC = dumpModuleFiles())
107 return EC;
108 }
109
110 if (opts::raw::DumpLines) {
111 if (auto EC = dumpLines())
112 return EC;
113 }
114
115 if (opts::raw::DumpInlineeLines) {
116 if (auto EC = dumpInlineeLines())
117 return EC;
118 }
119
120 if (opts::raw::DumpXmi) {
121 if (auto EC = dumpXmi())
122 return EC;
123 }
124
125 if (opts::raw::DumpXme) {
126 if (auto EC = dumpXme())
127 return EC;
128 }
129
130 if (opts::raw::DumpTypes || opts::raw::DumpTypeExtras) {
131 if (auto EC = dumpTpiStream(StreamTPI))
132 return EC;
133 }
134
135 if (opts::raw::DumpIds || opts::raw::DumpIdExtras) {
136 if (auto EC = dumpTpiStream(StreamIPI))
137 return EC;
138 }
139
140 if (opts::raw::DumpPublics) {
141 if (auto EC = dumpPublics())
142 return EC;
143 }
144
145 if (opts::raw::DumpSymbols) {
146 if (auto EC = dumpModuleSyms())
147 return EC;
148 }
149
150 if (opts::raw::DumpSectionContribs) {
151 if (auto EC = dumpSectionContribs())
152 return EC;
153 }
154
155 if (opts::raw::DumpSectionMap) {
156 if (auto EC = dumpSectionMap())
157 return EC;
158 }
159
160 return Error::success();
161 }
162
163 static void printHeader(LinePrinter &P, const Twine &S) {
164 P.NewLine();
165 P.formatLine("{0,=60}", S);
166 P.formatLine("{0}", fmt_repeat('=', 60));
167 }
168
169 Error RawOutputStyle::dumpFileSummary() {
170 printHeader(P, "Summary");
171
172 ExitOnError Err("Invalid PDB Format");
173
174 AutoIndent Indent(P);
175 P.formatLine("Block Size: {0}", File.getBlockSize());
176 P.formatLine("Number of blocks: {0}", File.getBlockCount());
177 P.formatLine("Number of streams: {0}", File.getNumStreams());
178
179 auto &PS = Err(File.getPDBInfoStream());
180 P.formatLine("Signature: {0}", PS.getSignature());
181 P.formatLine("Age: {0}", PS.getAge());
182 P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
183 P.formatLine("Features: {0:x+}", static_cast(PS.getFeatures()));
184 P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
185 P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
186 P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
187 P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
188 P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
189 if (File.hasPDBDbiStream()) {
190 auto &DBI = Err(File.getPDBDbiStream());
191 P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
192 P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
193 P.formatLine("Is stripped: {0}", DBI.isStripped());
194 }
195
196 return Error::success();
197 }
198
199 Error RawOutputStyle::dumpStreamSummary() {
200 printHeader(P, "Streams");
201
202 if (StreamPurposes.empty())
203 discoverStreamPurposes(File, StreamPurposes);
204
205 AutoIndent Indent(P);
206 uint32_t StreamCount = File.getNumStreams();
207
208 for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
209 P.formatLine(
210 "Stream {0}: [{1}] ({2} bytes)",
211 fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
212 StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
213 }
214
215 return Error::success();
216 }
217
218 Error RawOutputStyle::dumpBlockRanges() {
219 printHeader(P, "MSF Blocks");
220
221 auto &R = *opts::raw::DumpBlockRange;
222 uint32_t Max = R.Max.getValueOr(R.Min);
223
224 AutoIndent Indent(P);
225 if (Max < R.Min)
226 return make_error(
227 "Invalid block range specified. Max < Min",
228 std::make_error_code(std::errc::bad_address));
229 if (Max >= File.getBlockCount())
230 return make_error(
231 "Invalid block range specified. Requested block out of bounds",
232 std::make_error_code(std::errc::bad_address));
233
234 for (uint32_t I = R.Min; I <= Max; ++I) {
235 auto ExpectedData = File.getBlockData(I, File.getBlockSize());
236 if (!ExpectedData)
237 return ExpectedData.takeError();
238 std::string Label = formatv("Block {0}", I).str();
239 P.formatBinary(Label, *ExpectedData, 0);
240 }
241
242 return Error::success();
243 }
244
245 static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
246 uint32_t &Size) {
247 if (Str.consumeInteger(0, SI))
248 return make_error(raw_error_code::invalid_format,
249 "Invalid Stream Specification");
250 if (Str.consume_front(":")) {
251 if (Str.consumeInteger(0, Offset))
252 return make_error(raw_error_code::invalid_format,
253 "Invalid Stream Specification");
254 }
255 if (Str.consume_front("@")) {
256 if (Str.consumeInteger(0, Size))
257 return make_error(raw_error_code::invalid_format,
258 "Invalid Stream Specification");
259 }
260 if (!Str.empty())
261 return make_error(raw_error_code::invalid_format,
262 "Invalid Stream Specification");
263 return Error::success();
264 }
265
266 Error RawOutputStyle::dumpStreamBytes() {
267 if (StreamPurposes.empty())
268 discoverStreamPurposes(File, StreamPurposes);
269
270 printHeader(P, "Stream Data");
271 ExitOnError Err("Unexpected error reading stream data");
272
273 for (auto &Str : opts::raw::DumpStreamData) {
274 uint32_t SI = 0;
275 uint32_t Begin = 0;
276 uint32_t Size = 0;
277 uint32_t End = 0;
278
279 if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
280 return EC;
281
282 AutoIndent Indent(P);
283 if (SI >= File.getNumStreams()) {
284 P.formatLine("Stream {0}: Not present", SI);
285 continue;
286 }
287
288 auto S = MappedBlockStream::createIndexedStream(
289 File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
290 if (!S) {
291 P.NewLine();
292 P.formatLine("Stream {0}: Not present", SI);
293 continue;
294 }
295
296 if (Size == 0)
297 End = S->getLength();
298 else
299 End = std::min(Begin + Size, S->getLength());
300
301 P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
302 StreamPurposes[SI]);
303 AutoIndent Indent2(P);
304
305 BinaryStreamReader R(*S);
306 ArrayRef StreamData;
307 Err(R.readBytes(StreamData, S->getLength()));
308 Size = End - Begin;
309 StreamData = StreamData.slice(Begin, Size);
310 P.formatBinary("Data", StreamData, Begin);
311 }
312 return Error::success();
313 }
314
315 static Expected getModuleDebugStream(PDBFile &File,
316 uint32_t Index) {
317 ExitOnError Err("Unexpected error");
318
319 auto &Dbi = Err(File.getPDBDbiStream());
320 const auto &Modules = Dbi.modules();
321 auto Modi = Modules.getModuleDescriptor(Index);
322
323 uint16_t ModiStream = Modi.getModuleStreamIndex();
324 if (ModiStream == kInvalidStreamIndex)
325 return make_error(raw_error_code::no_stream,
326 "Module stream not present");
327
328 auto ModStreamData = MappedBlockStream::createIndexedStream(
329 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
330 File.getAllocator());
331
332 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
333 if (auto EC = ModS.reload())
334 return make_error(raw_error_code::corrupt_file,
335 "Invalid module stream");
336
337 return std::move(ModS);
338 }
339
340 static std::string formatChecksumKind(FileChecksumKind Kind) {
341 switch (Kind) {
342 RETURN_CASE(FileChecksumKind, None, "None");
343 RETURN_CASE(FileChecksumKind, MD5, "MD5");
344 RETURN_CASE(FileChecksumKind, SHA1, "SHA-1");
345 RETURN_CASE(FileChecksumKind, SHA256, "SHA-256");
346 }
347 return formatUnknownEnum(Kind);
348 }
349
350 namespace {
351 class StringsAndChecksumsPrinter {
352 const DebugStringTableSubsectionRef &extractStringTable(PDBFile &File) {
353 ExitOnError Err("Unexpected error processing modules");
354 return Err(File.getStringTable()).getStringTable();
355 }
356
357 template
358 void formatInternal(LinePrinter &Printer, bool Append,
359 Args &&... args) const {
360 if (Append)
361 Printer.format(std::forward(args)...);
362 else
363 Printer.formatLine(std::forward(args)...);
364 }
365
366 public:
367 StringsAndChecksumsPrinter(PDBFile &File, uint32_t Modi)
368 : Records(extractStringTable(File)) {
369 auto MDS = getModuleDebugStream(File, Modi);
370 if (!MDS) {
371 consumeError(MDS.takeError());
372 return;
373 }
374
375 DebugStream = llvm::make_unique(std::move(*MDS));
376 Records.initialize(MDS->subsections());
377 if (Records.hasChecksums()) {
378 for (const auto &Entry : Records.checksums()) {
379 auto S = Records.strings().getString(Entry.FileNameOffset);
380 if (!S)
381 continue;
382 ChecksumsByFile[*S] = Entry;
383 }
384 }
385 }
386
387 Expected getNameFromStringTable(uint32_t Offset) const {
388 return Records.strings().getString(Offset);
389 }
390
391 void formatFromFileName(LinePrinter &Printer, StringRef File,
392 bool Append = false) const {
393 auto FC = ChecksumsByFile.find(File);
394 if (FC == ChecksumsByFile.end()) {
395 formatInternal(Printer, Append, "- (no checksum) {0}", File);
396 return;
397 }
398
399 formatInternal(Printer, Append, "- ({0}: {1}) {2}",
400 formatChecksumKind(FC->getValue().Kind),
401 toHex(FC->getValue().Checksum), File);
402 }
403
404 void formatFromChecksumsOffset(LinePrinter &Printer, uint32_t Offset,
405 bool Append = false) const {
406 if (!Records.hasChecksums()) {
407 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
408 return;
409 }
410
411 auto Iter = Records.checksums().getArray().at(Offset);
412 if (Iter == Records.checksums().getArray().end()) {
413 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
414 return;
415 }
416
417 uint32_t FO = Iter->FileNameOffset;
418 auto ExpectedFile = getNameFromStringTable(FO);
419 if (!ExpectedFile) {
420 formatInternal(Printer, Append, "(unknown file name offset {0})", Offset);
421 consumeError(ExpectedFile.takeError());
422 return;
423 }
424 if (Iter->Kind == FileChecksumKind::None) {
425 formatInternal(Printer, Append, "{0} (no checksum)", *ExpectedFile);
426 } else {
427 formatInternal(Printer, Append, "{0} ({1}: {2})", *ExpectedFile,
428 formatChecksumKind(Iter->Kind), toHex(Iter->Checksum));
429 }
430 }
431
432 std::unique_ptr DebugStream;
433 StringsAndChecksumsRef Records;
434 StringMap ChecksumsByFile;
435 };
436 } // namespace
437
438 template
439 static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
440 CallbackT Callback) {
441 AutoIndent Indent(P);
442 if (!File.hasPDBDbiStream()) {
443 P.formatLine("DBI Stream not present");
444 return;
445 }
446
447 ExitOnError Err("Unexpected error processing modules");
448
449 auto &Stream = Err(File.getPDBDbiStream());
450
451 const DbiModuleList &Modules = Stream.modules();
452 uint32_t Count = Modules.getModuleCount();
453 uint32_t Digits = NumDigits(Count);
454 for (uint32_t I = 0; I < Count; ++I) {
455 auto Modi = Modules.getModuleDescriptor(I);
456 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
457 Modi.getModuleName());
458
459 StringsAndChecksumsPrinter Strings(File, I);
460 AutoIndent Indent2(P, IndentLevel);
461 Callback(I, Strings);
462 }
463 }
464
465 template
466 static void iterateModuleSubsections(
467 PDBFile &File, LinePrinter &P, uint32_t IndentLevel,
468 llvm::function_ref
469 SubsectionT &)>
470 Callback) {
471
472 iterateModules(
473 File, P, IndentLevel,
474 [&File, &Callback](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
475 auto MDS = getModuleDebugStream(File, Modi);
476 if (!MDS) {
477 consumeError(MDS.takeError());
478 return;
479 }
480
481 for (const auto &SS : MDS->subsections()) {
482 SubsectionT Subsection;
483
484 if (SS.kind() != Subsection.kind())
485 continue;
486
487 BinaryStreamReader Reader(SS.getRecordData());
488 if (auto EC = Subsection.initialize(Reader))
489 continue;
490 Callback(Modi, Strings, Subsection);
491 }
492 });
493 }
494
495 Error RawOutputStyle::dumpModules() {
496 printHeader(P, "Modules");
497
498 AutoIndent Indent(P);
499 if (!File.hasPDBDbiStream()) {
500 P.formatLine("DBI Stream not present");
501 return Error::success();
502 }
503
504 ExitOnError Err("Unexpected error processing modules");
505
506 auto &Stream = Err(File.getPDBDbiStream());
507
508 const DbiModuleList &Modules = Stream.modules();
509 uint32_t Count = Modules.getModuleCount();
510 uint32_t Digits = NumDigits(Count);
511 for (uint32_t I = 0; I < Count; ++I) {
512 auto Modi = Modules.getModuleDescriptor(I);
513 P.formatLine("Mod {0:4} | Name: `{1}`: ",
514 fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
515 P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
516 P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
517 Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
518 Modi.hasECInfo());
519 }
520 return Error::success();
521 }
522
523 Error RawOutputStyle::dumpModuleFiles() {
524 printHeader(P, "Files");
525
526 ExitOnError Err("Unexpected error processing modules");
527
528 iterateModules(
529 File, P, 11,
530 [this, &Err](uint32_t Modi, StringsAndChecksumsPrinter &Strings) {
531 auto &Stream = Err(File.getPDBDbiStream());
532
533 const DbiModuleList &Modules = Stream.modules();
534 for (const auto &F : Modules.source_files(Modi)) {
535 Strings.formatFromFileName(P, F);
536 }
537 });
538 return Error::success();
539 }
540
541 static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P,
542 uint32_t Start, const LineColumnEntry &E) {
543 const uint32_t kMaxCharsPerLineNumber = 4; // 4 digit line number
544 uint32_t MinColumnWidth = kMaxCharsPerLineNumber + 5;
545
546 // Let's try to keep it under 100 characters
547 constexpr uint32_t kMaxRowLength = 100;
548 // At least 3 spaces between columns.
549 uint32_t ColumnsPerRow = kMaxRowLength / (MinColumnWidth + 3);
550 uint32_t ItemsLeft = E.LineNumbers.size();
551 auto LineIter = E.LineNumbers.begin();
552 while (ItemsLeft != 0) {
553 uint32_t RowColumns = std::min(ItemsLeft, ColumnsPerRow);
554 for (uint32_t I = 0; I < RowColumns; ++I) {
555 LineInfo Line(LineIter->Flags);
556 std::string LineStr;
557 if (Line.isAlwaysStepInto())
558 LineStr = "ASI";
559 else if (Line.isNeverStepInto())
560 LineStr = "NSI";
561 else
562 LineStr = utostr(Line.getStartLine());
563 char Statement = Line.isStatement() ? ' ' : '!';
564 P.format("{0} {1:X-} {2} ",
565 fmt_align(LineStr, AlignStyle::Right, kMaxCharsPerLineNumber),
566 fmt_align(Start + LineIter->Offset, AlignStyle::Right, 8, '0'),
567 Statement);
568 ++LineIter;
569 --ItemsLeft;
570 }
571 P.NewLine();
572 }
573 }
574
575 Error RawOutputStyle::dumpLines() {
576 printHeader(P, "Lines");
577
578 uint32_t LastModi = UINT32_MAX;
579 uint32_t LastNameIndex = UINT32_MAX;
580 iterateModuleSubsections(
581 File, P, 4,
582 [this, &LastModi, &LastNameIndex](uint32_t Modi,
583 StringsAndChecksumsPrinter &Strings,
584 DebugLinesSubsectionRef &Lines) {
585 uint16_t Segment = Lines.header()->RelocSegment;
586 uint32_t Begin = Lines.header()->RelocOffset;
587 uint32_t End = Begin + Lines.header()->CodeSize;
588 for (const auto &Block : Lines) {
589 if (LastModi != Modi || LastNameIndex != Block.NameIndex) {
590 LastModi = Modi;
591 LastNameIndex = Block.NameIndex;
592 Strings.formatFromChecksumsOffset(P, Block.NameIndex);
593 }
594
595 AutoIndent Indent(P, 2);
596 P.formatLine("{0:X-4}:{1:X-8}-{2:X-8}, ", Segment, Begin, End);
597 uint32_t Count = Block.LineNumbers.size();
598 if (Lines.hasColumnInfo())
599 P.format("line/column/addr entries = {0}", Count);
600 else
601 P.format("line/addr entries = {0}", Count);
602
603 P.NewLine();
604 typesetLinesAndColumns(File, P, Begin, Block);
605 }
606 });
607
608 return Error::success();
609 }
610
611 Error RawOutputStyle::dumpInlineeLines() {
612 printHeader(P, "Inlinee Lines");
613
614 iterateModuleSubsections(
615 File, P, 2,
616 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
617 DebugInlineeLinesSubsectionRef &Lines) {
618 P.formatLine("{0,+8} | {1,+5} | {2}", "Inlinee", "Line", "Source File");
619 for (const auto &Entry : Lines) {
620 P.formatLine("{0,+8} | {1,+5} | ", Entry.Header->Inlinee,
621 fmtle(Entry.Header->SourceLineNum));
622 Strings.formatFromChecksumsOffset(P, Entry.Header->FileID, true);
623 }
624 P.NewLine();
625 });
626
627 return Error::success();
628 }
629
630 Error RawOutputStyle::dumpXmi() {
631 printHeader(P, "Cross Module Imports");
632 iterateModuleSubsections(
633 File, P, 2,
634 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
635 DebugCrossModuleImportsSubsectionRef &Imports) {
636 P.formatLine("{0,=32} | {1}", "Imported Module", "Type IDs");
637
638 for (const auto &Xmi : Imports) {
639 auto ExpectedModule =
640 Strings.getNameFromStringTable(Xmi.Header->ModuleNameOffset);
641 StringRef Module;
642 SmallString<32> ModuleStorage;
643 if (!ExpectedModule) {
644 Module = "(unknown module)";
645 consumeError(ExpectedModule.takeError());
646 } else
647 Module = *ExpectedModule;
648 if (Module.size() > 32) {
649 ModuleStorage = "...";
650 ModuleStorage += Module.take_back(32 - 3);
651 Module = ModuleStorage;
652 }
653 std::vector TIs;
654 for (const auto I : Xmi.Imports)
655 TIs.push_back(formatv("{0,+10:X+}", fmtle(I)));
656 std::string Result =
657 typesetItemList(TIs, P.getIndentLevel() + 35, 12, " ");
658 P.formatLine("{0,+32} | {1}", Module, Result);
659 }
660 });
661
662 return Error::success();
663 }
664
665 Error RawOutputStyle::dumpXme() {
666 printHeader(P, "Cross Module Exports");
667
668 iterateModuleSubsections(
669 File, P, 2,
670 [this](uint32_t Modi, StringsAndChecksumsPrinter &Strings,
671 DebugCrossModuleExportsSubsectionRef &Exports) {
672 P.formatLine("{0,-10} | {1}", "Local ID", "Global ID");
673 for (const auto &Export : Exports) {
674 P.formatLine("{0,+10:X+} | {1}", TypeIndex(Export.Local),
675 TypeIndex(Export.Global));
676 }
677 });
678
679 return Error::success();
680 }
681
682 Error RawOutputStyle::dumpStringTable() {
683 printHeader(P, "String Table");
684
685 AutoIndent Indent(P);
686 auto IS = File.getStringTable();
687 if (!IS) {
688 P.formatLine("Not present in file");
689 consumeError(IS.takeError());
690 return Error::success();
691 }
692
693 if (IS->name_ids().empty()) {
694 P.formatLine("Empty");
695 return Error::success();
696 }
697
698 auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
699 uint32_t Digits = NumDigits(*MaxID);
700
701 P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
702 "String");
703
704 std::vector SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
705 std::sort(SortedIDs.begin(), SortedIDs.end());
706 for (uint32_t I : SortedIDs) {
707 auto ES = IS->getStringForID(I);
708 llvm::SmallString<32> Str;
709 if (!ES) {
710 consumeError(ES.takeError());
711 Str = "Error reading string";
712 } else if (!ES->empty()) {
713 Str.append("'");
714 Str.append(*ES);
715 Str.append("'");
716 }
717
718 if (!Str.empty())
719 P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
720 }
721 return Error::success();
722 }
723
724 Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
725 assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
726
727 bool Present = false;
728 bool DumpTypes = false;
729 bool DumpBytes = false;
730 bool DumpExtras = false;
731 std::vector Indices;
732 if (StreamIdx == StreamTPI) {
733 printHeader(P, "Types (TPI Stream)");
734 Present = File.hasPDBTpiStream();
735 DumpTypes = opts::raw::DumpTypes;
736 DumpBytes = opts::raw::DumpTypeData;
737 DumpExtras = opts::raw::DumpTypeExtras;
738 Indices.assign(opts::raw::DumpTypeIndex.begin(),
739 opts::raw::DumpTypeIndex.end());
740 } else if (StreamIdx == StreamIPI) {
741 printHeader(P, "Types (IPI Stream)");
742 Present = File.hasPDBIpiStream();
743 DumpTypes = opts::raw::DumpIds;
744 DumpBytes = opts::raw::DumpIdData;
745 DumpExtras = opts::raw::DumpIdExtras;
746 Indices.assign(opts::raw::DumpIdIndex.begin(),
747 opts::raw::DumpIdIndex.end());
748 }
749
750 AutoIndent Indent(P);
751 if (!Present) {
752 P.formatLine("Stream not present");
753 return Error::success();
754 }
755
756 ExitOnError Err("Unexpected error processing types");
757
758 auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
759 : File.getPDBIpiStream());
760
761 auto &Types = Err(initializeTypes(StreamIdx));
762
763 if (DumpTypes) {
764 P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
765 uint32_t Width =
766 NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
767
768 MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types,
769 Stream.getHashValues());
770
771 if (Indices.empty()) {
772 if (auto EC = codeview::visitTypeStream(Types, V)) {
773 P.formatLine("An error occurred dumping type records: {0}",
774 toString(std::move(EC)));
775 }
776 } else {
777 for (const auto &I : Indices) {
778 TypeIndex TI(I);
779 CVType Type = Types.getType(TI);
780 if (auto EC = codeview::visitTypeRecord(Type, TI, V))
781 P.formatLine("An error occurred dumping type record {0}: {1}", TI,
782 toString(std::move(EC)));
783 }
784 }
785 }
786
787 if (DumpExtras) {
788 P.NewLine();
789 auto IndexOffsets = Stream.getTypeIndexOffsets();
790 P.formatLine("Type Index Offsets:");
791 for (const auto &IO : IndexOffsets) {
792 AutoIndent Indent2(P);
793 P.formatLine("TI: {0}, Offset: {1}", IO.Type, fmtle(IO.Offset));
794 }
795
796 P.NewLine();
797 P.formatLine("Hash Adjusters:");
798 auto &Adjusters = Stream.getHashAdjusters();
799 auto &Strings = Err(File.getStringTable());
800 for (const auto &A : Adjusters) {
801 AutoIndent Indent2(P);
802 auto ExpectedStr = Strings.getStringForID(A.first);
803 TypeIndex TI(A.second);
804 if (ExpectedStr)
805 P.formatLine("`{0}` -> {1}", *ExpectedStr, TI);
806 else {
807 P.formatLine("unknown str id ({0}) -> {1}", A.first, TI);
808 consumeError(ExpectedStr.takeError());
809 }
810 }
811 }
812 return Error::success();
813 }
814
815 Expected
816 RawOutputStyle::initializeTypes(uint32_t SN) {
817 auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
818 auto Tpi =
819 (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
820 if (!Tpi)
821 return Tpi.takeError();
822
823 if (!TypeCollection) {
824 auto &Types = Tpi->typeArray();
825 uint32_t Count = Tpi->getNumTypeRecords();
826 auto Offsets = Tpi->getTypeIndexOffsets();
827 TypeCollection =
828 llvm::make_unique(Types, Count, Offsets);
829 }
830
831 return *TypeCollection;
832 }
833
834 Error RawOutputStyle::dumpModuleSyms() {
835 printHeader(P, "Symbols");
836
837 AutoIndent Indent(P);
838 if (!File.hasPDBDbiStream()) {
839 P.formatLine("DBI Stream not present");
840 return Error::success();
841 }
842
843 ExitOnError Err("Unexpected error processing symbols");
844
845 auto &Stream = Err(File.getPDBDbiStream());
846
847 auto &Types = Err(initializeTypes(StreamTPI));
848
849 const DbiModuleList &Modules = Stream.modules();
850 uint32_t Count = Modules.getModuleCount();
851 uint32_t Digits = NumDigits(Count);
852 for (uint32_t I = 0; I < Count; ++I) {
853 auto Modi = Modules.getModuleDescriptor(I);
854 P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
855 Modi.getModuleName());
856 uint16_t ModiStream = Modi.getModuleStreamIndex();
857 if (ModiStream == kInvalidStreamIndex) {
858 P.formatLine(" ");
859 continue;
860 }
861 auto ModStreamData = MappedBlockStream::createIndexedStream(
862 File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
863 File.getAllocator());
864
865 ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
866 if (auto EC = ModS.reload()) {
867 P.formatLine("Error loading module stream {0}. {1}", I,
868 toString(std::move(EC)));
869 continue;
870 }
871
872 SymbolVisitorCallbackPipeline Pipeline;
873 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
874 MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
875
876 Pipeline.addCallbackToPipeline(Deserializer);
877 Pipeline.addCallbackToPipeline(Dumper);
878 CVSymbolVisitor Visitor(Pipeline);
879 if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) {
880 P.formatLine("Error while processing symbol records. {0}",
881 toString(std::move(EC)));
882 continue;
883 }
884 }
885 return Error::success();
886 }
887
888 Error RawOutputStyle::dumpPublics() {
889 printHeader(P, "Public Symbols");
890
891 AutoIndent Indent(P);
892 if (!File.hasPDBPublicsStream()) {
893 P.formatLine("Publics stream not present");
894 return Error::success();
895 }
896
897 ExitOnError Err("Error dumping publics stream");
898
899 auto &Types = Err(initializeTypes(StreamTPI));
900 auto &Publics = Err(File.getPDBPublicsStream());
901 SymbolVisitorCallbackPipeline Pipeline;
902 SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
903 MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
904
905 Pipeline.addCallbackToPipeline(Deserializer);
906 Pipeline.addCallbackToPipeline(Dumper);
907 CVSymbolVisitor Visitor(Pipeline);
908 auto ExpectedSymbols = Publics.getSymbolArray();
909 if (!ExpectedSymbols) {
910 P.formatLine("Could not read public symbol record stream");
911 return Error::success();
912 }
913
914 if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols))
915 P.formatLine("Error while processing public symbol records. {0}",
916 toString(std::move(EC)));
917
918 return Error::success();
919 }
920
921 static std::string formatSectionCharacteristics(uint32_t IndentLevel,
922 uint32_t C) {
923 using SC = COFF::SectionCharacteristics;
924 std::vector Opts;
925 if (C == COFF::SC_Invalid)
926 return "invalid";
927 if (C == 0)
928 return "none";
929
930 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
931 PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
932 PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
933 PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
934 "IMAGE_SCN_CNT_INITIALIZED_DATA");
935 PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
936 "IMAGE_SCN_CNT_UNINITIALIZED_DATA");
937 PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
938 PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
939 PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
940 PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
941 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
942 PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
943 PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
944 PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
945 PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
946 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
947 PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
948 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
949 "IMAGE_SCN_ALIGN_1BYTES");
950 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
951 "IMAGE_SCN_ALIGN_2BYTES");
952 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
953 "IMAGE_SCN_ALIGN_4BYTES");
954 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
955 "IMAGE_SCN_ALIGN_8BYTES");
956 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
957 "IMAGE_SCN_ALIGN_16BYTES");
958 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
959 "IMAGE_SCN_ALIGN_32BYTES");
960 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
961 "IMAGE_SCN_ALIGN_64BYTES");
962 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
963 "IMAGE_SCN_ALIGN_128BYTES");
964 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
965 "IMAGE_SCN_ALIGN_256BYTES");
966 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
967 "IMAGE_SCN_ALIGN_512BYTES");
968 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
969 "IMAGE_SCN_ALIGN_1024BYTES");
970 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
971 "IMAGE_SCN_ALIGN_2048BYTES");
972 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
973 "IMAGE_SCN_ALIGN_4096BYTES");
974 PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
975 "IMAGE_SCN_ALIGN_8192BYTES");
976 PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
977 PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
978 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
979 PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
980 PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
981 PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
982 PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
983 PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
984 return typesetItemList(Opts, IndentLevel, 3, " | ");
985 }
986
987 static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
988 OMFSegDescFlags Flags) {
989 std::vector Opts;
990 if (Flags == OMFSegDescFlags::None)
991 return "none";
992
993 PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
994 PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
995 PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
996 PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
997 PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
998 PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
999 PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
1000 return typesetItemList(Opts, IndentLevel, 4, " | ");
1001 }
1002
1003 Error RawOutputStyle::dumpSectionContribs() {
1004 printHeader(P, "Section Contributions");
1005 ExitOnError Err("Error dumping publics stream");
1006
1007 AutoIndent Indent(P);
1008 if (!File.hasPDBDbiStream()) {
1009 P.formatLine(
1010 "Section contribs require a DBI Stream, which could not be loaded");
1011 return Error::success();
1012 }
1013
1014 auto &Dbi = Err(File.getPDBDbiStream());
1015
1016 class Visitor : public ISectionContribVisitor {
1017 public:
1018 Visitor(LinePrinter &P) : P(P) {}
1019 void visit(const SectionContrib &SC) override {
1020 P.formatLine(
1021 "SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
1022 formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
1023 fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
1024 P.formatLine(" {0}",
1025 formatSectionCharacteristics(P.getIndentLevel() + 6,
1026 SC.Characteristics));
1027 }
1028 void visit(const SectionContrib2 &SC) override {
1029 P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
1030 "crc = {4}, coff section = {5}",
1031 formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
1032 fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
1033 fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
1034 fmtle(SC.ISectCoff));
1035 P.formatLine(" {0}",
1036 formatSectionCharacteristics(P.getIndentLevel() + 6,
1037 SC.Base.Characteristics));
1038 }
1039
1040 private:
1041 LinePrinter &P;
1042 };
1043
1044 Visitor V(P);
1045 Dbi.visitSectionContributions(V);
1046 return Error::success();
1047 }
1048
1049 Error RawOutputStyle::dumpSectionMap() {
1050 printHeader(P, "Section Map");
1051 ExitOnError Err("Error dumping section map");
1052
1053 AutoIndent Indent(P);
1054 if (!File.hasPDBDbiStream()) {
1055 P.formatLine("Dumping the section map requires a DBI Stream, which could "
1056 "not be loaded");
1057 return Error::success();
1058 }
1059
1060 auto &Dbi = Err(File.getPDBDbiStream());
1061
1062 uint32_t I = 0;
1063 for (auto &M : Dbi.getSectionMap()) {
1064 P.formatLine(
1065 "Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
1066 fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
1067 P.formatLine(" class = {0}, offset = {1}, size = {2}",
1068 fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
1069 P.formatLine(" flags = {0}",
1070 formatSegMapDescriptorFlag(
1071 P.getIndentLevel() + 13,
1072 static_cast(uint16_t(M.Flags))));
1073 ++I;
1074 }
1075 return Error::success();
1076 }
+0
-64
tools/llvm-pdbutil/RawOutputStyle.h less more
None //===- RawOutputStyle.h -------------------------------------- *- C++ --*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
10 #define LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
11
12 #include "LinePrinter.h"
13 #include "OutputStyle.h"
14
15 #include "llvm/ADT/Optional.h"
16 #include "llvm/ADT/SmallVector.h"
17
18 #include
19
20 namespace llvm {
21 class BitVector;
22
23 namespace codeview {
24 class LazyRandomTypeCollection;
25 }
26
27 namespace pdb {
28 class RawOutputStyle : public OutputStyle {
29 public:
30 RawOutputStyle(PDBFile &File);
31
32 Error dump() override;
33
34 private:
35 Expected initializeTypes(uint32_t SN);
36
37 Error dumpFileSummary();
38 Error dumpStreamSummary();
39 Error dumpBlockRanges();
40 Error dumpStreamBytes();
41 Error dumpStringTable();
42 Error dumpLines();
43 Error dumpInlineeLines();
44 Error dumpXmi();
45 Error dumpXme();
46 Error dumpTpiStream(uint32_t StreamIdx);
47 Error dumpModules();
48 Error dumpModuleFiles();
49 Error dumpModuleSyms();
50 Error dumpPublics();
51 Error dumpSectionContribs();
52 Error dumpSectionMap();
53
54 PDBFile &File;
55 LinePrinter P;
56 std::unique_ptr TpiTypes;
57 std::unique_ptr IpiTypes;
58 SmallVector StreamPurposes;
59 };
60 } // namespace pdb
61 } // namespace llvm
62
63 #endif
1414
1515 #include "Analyze.h"
1616 #include "Diff.h"
17 #include "DumpOutputStyle.h"
1718 #include "LinePrinter.h"
1819 #include "OutputStyle.h"
1920 #include "PrettyCompilandDumper.h"
2122 #include "PrettyFunctionDumper.h"
2223 #include "PrettyTypeDumper.h"
2324 #include "PrettyVariableDumper.h"
24 #include "RawOutputStyle.h"
2525 #include "YAMLOutputStyle.h"
2626
2727 #include "llvm/ADT/ArrayRef.h"
8585
8686 namespace opts {
8787
88 cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
88 cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
8989 cl::SubCommand
9090 PrettySubcommand("pretty",
9191 "Dump semantic information about types and symbols");
262262
263263 cl::OptionCategory FileOptions("Module & File Options");
264264
265 namespace raw {
265 namespace dump {
266266
267267 cl::OptionCategory MsfOptions("MSF Container Options");
268268 cl::OptionCategory TypeOptions("Type Record Options");
271271
272272 // MSF OPTIONS
273273 cl::opt DumpSummary("summary", cl::desc("dump file summary"),
274 cl::cat(MsfOptions), cl::sub(RawSubcommand));
274 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
275275 cl::opt DumpStreams("streams",
276276 cl::desc("dump summary of the PDB streams"),
277 cl::cat(MsfOptions), cl::sub(RawSubcommand));
277 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
278278 cl::opt
279279 DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
280280 cl::desc("Dump binary data from specified range."),
281 cl::cat(MsfOptions), cl::sub(RawSubcommand));
281 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
282282 llvm::Optional DumpBlockRange;
283283
284284 cl::list
285285 DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
286286 cl::desc("Dump binary data from specified streams. Format "
287287 "is SN[:Start][@Size]"),
288 cl::cat(MsfOptions), cl::sub(RawSubcommand));
288 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
289289
290290 // TYPE OPTIONS
291291 cl::opt DumpTypes("types",
292292 cl::desc("dump CodeView type records from TPI stream"),
293 cl::cat(TypeOptions), cl::sub(RawSubcommand));
293 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
294294 cl::opt DumpTypeData(
295295 "type-data",
296296 cl::desc("dump CodeView type record raw bytes from TPI stream"),
297 cl::cat(TypeOptions), cl::sub(RawSubcommand));
297 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
298298
299299 cl::opt DumpTypeExtras("type-extras",
300300 cl::desc("dump type hashes and index offsets"),
301 cl::cat(TypeOptions), cl::sub(RawSubcommand));
301 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
302302
303303 cl::list DumpTypeIndex(
304304 "type-index", cl::ZeroOrMore,
305305 cl::desc("only dump types with the specified hexadecimal type index"),
306 cl::cat(TypeOptions), cl::sub(RawSubcommand));
306 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
307307
308308 cl::opt DumpIds("ids",
309309 cl::desc("dump CodeView type records from IPI stream"),
310 cl::cat(TypeOptions), cl::sub(RawSubcommand));
310 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
311311 cl::opt
312312 DumpIdData("id-data",
313313 cl::desc("dump CodeView type record raw bytes from IPI stream"),
314 cl::cat(TypeOptions), cl::sub(RawSubcommand));
314 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
315315
316316 cl::opt DumpIdExtras("id-extras",
317317 cl::desc("dump id hashes and index offsets"),
318 cl::cat(TypeOptions), cl::sub(RawSubcommand));
318 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
319319 cl::list DumpIdIndex(
320320 "id-index", cl::ZeroOrMore,
321321 cl::desc("only dump ids with the specified hexadecimal type index"),
322 cl::cat(TypeOptions), cl::sub(RawSubcommand));
322 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
323323
324324 // SYMBOL OPTIONS
325325 cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"),
326 cl::cat(SymbolOptions), cl::sub(RawSubcommand));
326 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
327327 cl::opt DumpSymbols("symbols", cl::desc("dump module symbols"),
328 cl::cat(SymbolOptions), cl::sub(RawSubcommand));
328 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
329329
330330 cl::opt
331331 DumpSymRecordBytes("sym-data",
332332 cl::desc("dump CodeView symbol record raw bytes"),
333 cl::cat(SymbolOptions), cl::sub(RawSubcommand));
333 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
334334
335335 // MODULE & FILE OPTIONS
336336 cl::opt DumpModules("modules", cl::desc("dump compiland information"),
337 cl::cat(FileOptions), cl::sub(RawSubcommand));
337 cl::cat(FileOptions), cl::sub(DumpSubcommand));
338338 cl::opt DumpModuleFiles(
339339 "files",
340340 cl::desc("Dump the source files that contribute to each module's."),
341 cl::cat(FileOptions), cl::sub(RawSubcommand));
341 cl::cat(FileOptions), cl::sub(DumpSubcommand));
342342 cl::opt DumpLines(
343343 "l",
344344 cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
345 cl::cat(FileOptions), cl::sub(RawSubcommand));
345 cl::cat(FileOptions), cl::sub(DumpSubcommand));
346346 cl::opt DumpInlineeLines(
347347 "il",
348348 cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
349 cl::cat(FileOptions), cl::sub(RawSubcommand));
349 cl::cat(FileOptions), cl::sub(DumpSubcommand));
350350 cl::opt DumpXmi(
351351 "xmi",
352352 cl::desc(
353353 "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
354 cl::cat(FileOptions), cl::sub(RawSubcommand));
354 cl::cat(FileOptions), cl::sub(DumpSubcommand));
355355 cl::opt DumpXme(
356356 "xme",
357357 cl::desc(
358358 "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
359 cl::cat(FileOptions), cl::sub(RawSubcommand));
359 cl::cat(FileOptions), cl::sub(DumpSubcommand));
360360
361361 // MISCELLANEOUS OPTIONS
362362 cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"),
363 cl::cat(MiscOptions), cl::sub(RawSubcommand));
363 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
364364
365365 cl::opt DumpSectionContribs("section-contribs",
366366 cl::desc("dump section contributions"),
367 cl::cat(MiscOptions), cl::sub(RawSubcommand));
367 cl::cat(MiscOptions),
368 cl::sub(DumpSubcommand));
368369 cl::opt DumpSectionMap("section-map", cl::desc("dump section map"),
369 cl::cat(MiscOptions), cl::sub(RawSubcommand));
370 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
370371
371372 cl::opt RawAll("all", cl::desc("Implies most other options."),
372 cl::cat(MiscOptions), cl::sub(RawSubcommand));
373 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
373374
374375 cl::list InputFilenames(cl::Positional,
375376 cl::desc(""),
376 cl::OneOrMore, cl::sub(RawSubcommand));
377 cl::OneOrMore, cl::sub(DumpSubcommand));
377378 }
378379
379380 namespace yaml2pdb {
619620 std::unique_ptr Session;
620621 auto &File = loadPDB(Path, Session);
621622
622 auto O = llvm::make_unique<RawOutputStyle>(File);
623 auto O = llvm::make_unique<DumpOutputStyle>(File);
623624
624625 ExitOnErr(O->dump());
625626 }
895896 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
896897
897898 cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
898 if (!opts::raw::DumpBlockRangeOpt.empty()) {
899 if (!opts::dump::DumpBlockRangeOpt.empty()) {
899900 llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
900901 llvm::SmallVector Matches;
901 if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) {
902 errs() << "Argument '" << opts::raw::DumpBlockRangeOpt
902 if (!R.match(opts::dump::DumpBlockRangeOpt, &Matches)) {
903 errs() << "Argument '" << opts::dump::DumpBlockRangeOpt
903904 << "' invalid format.\n";
904905 errs().flush();
905906 exit(1);
906907 }
907 opts::raw::DumpBlockRange.emplace();
908 Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min);
908 opts::dump::DumpBlockRange.emplace();
909 Matches[1].getAsInteger(10, opts::dump::DumpBlockRange->Min);
909910 if (!Matches[3].empty()) {
910 opts::raw::DumpBlockRange->Max.emplace();
911 Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max);
912 }
913 }
914
915 if (opts::RawSubcommand) {
916 if (opts::raw::RawAll) {
917 opts::raw::DumpLines = true;
918 opts::raw::DumpInlineeLines = true;
919 opts::raw::DumpXme = true;
920 opts::raw::DumpXmi = true;
921 opts::raw::DumpIds = true;
922 opts::raw::DumpPublics = true;
923 opts::raw::DumpSectionContribs = true;
924 opts::raw::DumpSectionMap = true;
925 opts::raw::DumpStreams = true;
926 opts::raw::DumpStringTable = true;
927 opts::raw::DumpSummary = true;
928 opts::raw::DumpSymbols = true;
929 opts::raw::DumpIds = true;
930 opts::raw::DumpIdExtras = true;
931 opts::raw::DumpTypes = true;
932 opts::raw::DumpTypeExtras = true;
933 opts::raw::DumpModules = true;
934 opts::raw::DumpModuleFiles = true;
911 opts::dump::DumpBlockRange->Max.emplace();
912 Matches[3].getAsInteger(10, *opts::dump::DumpBlockRange->Max);
913 }
914 }
915
916 if (opts::DumpSubcommand) {
917 if (opts::dump::RawAll) {
918 opts::dump::DumpLines = true;
919 opts::dump::DumpInlineeLines = true;
920 opts::dump::DumpXme = true;
921 opts::dump::DumpXmi = true;
922 opts::dump::DumpIds = true;
923 opts::dump::DumpPublics = true;
924 opts::dump::DumpSectionContribs = true;
925 opts::dump::DumpSectionMap = true;
926 opts::dump::DumpStreams = true;
927 opts::dump::DumpStringTable = true;
928 opts::dump::DumpSummary = true;
929 opts::dump::DumpSymbols = true;
930 opts::dump::DumpIds = true;
931 opts::dump::DumpIdExtras = true;
932 opts::dump::DumpTypes = true;
933 opts::dump::DumpTypeExtras = true;
934 opts::dump::DumpModules = true;
935 opts::dump::DumpModuleFiles = true;
935936 }
936937 }
937938 if (opts::PdbToYamlSubcommand) {
10131014 }
10141015 std::for_each(opts::pretty::InputFilenames.begin(),
10151016 opts::pretty::InputFilenames.end(), dumpPretty);
1016 } else if (opts::RawSubcommand) {
1017 std::for_each(opts::raw::InputFilenames.begin(),
1018 opts::raw::InputFilenames.end(), dumpRaw);
1017 } else if (opts::DumpSubcommand) {
1018 std::for_each(opts::dump::InputFilenames.begin(),
1019 opts::dump::InputFilenames.end(), dumpRaw);
10191020 } else if (opts::DiffSubcommand) {
10201021 if (opts::diff::InputFilenames.size() != 2) {
10211022 errs() << "diff subcommand expects exactly 2 arguments.\n";
9191 extern llvm::cl::opt ClassRecursionDepth;
9292 }
9393
94 namespace raw {
94 namespace dump {
9595 struct BlockRange {
9696 uint32_t Min;
9797 llvm::Optional Max;