1//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- 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// Dumps debug information present in PDB files.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm-pdbutil.h"
14
15#include "BytesOutputStyle.h"
16#include "DumpOutputStyle.h"
17#include "ExplainOutputStyle.h"
18#include "OutputStyle.h"
19#include "PrettyClassDefinitionDumper.h"
20#include "PrettyCompilandDumper.h"
21#include "PrettyEnumDumper.h"
22#include "PrettyExternalSymbolDumper.h"
23#include "PrettyFunctionDumper.h"
24#include "PrettyTypeDumper.h"
25#include "PrettyTypedefDumper.h"
26#include "PrettyVariableDumper.h"
27#include "YAMLOutputStyle.h"
28
29#include "llvm/ADT/ArrayRef.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/BinaryFormat/Magic.h"
33#include "llvm/Config/config.h"
34#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
35#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
36#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
37#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
38#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
39#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
40#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
41#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
42#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
43#include "llvm/DebugInfo/MSF/MSFBuilder.h"
44#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
45#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
46#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
47#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
48#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
49#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
50#include "llvm/DebugInfo/PDB/IPDBSession.h"
51#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
52#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
53#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
54#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
55#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
56#include "llvm/DebugInfo/PDB/Native/InputFile.h"
57#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
58#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
59#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
60#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
61#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
62#include "llvm/DebugInfo/PDB/Native/RawError.h"
63#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
64#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
65#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
66#include "llvm/DebugInfo/PDB/PDB.h"
67#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
68#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
69#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
70#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
71#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
72#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
73#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
74#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
75#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
76#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
77#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
78#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
79#include "llvm/Support/BinaryByteStream.h"
80#include "llvm/Support/COM.h"
81#include "llvm/Support/CommandLine.h"
82#include "llvm/Support/ConvertUTF.h"
83#include "llvm/Support/FileOutputBuffer.h"
84#include "llvm/Support/FileSystem.h"
85#include "llvm/Support/Format.h"
86#include "llvm/Support/InitLLVM.h"
87#include "llvm/Support/LineIterator.h"
88#include "llvm/Support/MemoryBuffer.h"
89#include "llvm/Support/Path.h"
90#include "llvm/Support/PrettyStackTrace.h"
91#include "llvm/Support/Process.h"
92#include "llvm/Support/Regex.h"
93#include "llvm/Support/ScopedPrinter.h"
94#include "llvm/Support/Signals.h"
95#include "llvm/Support/raw_ostream.h"
96
97using namespace llvm;
98using namespace llvm::codeview;
99using namespace llvm::msf;
100using namespace llvm::pdb;
101
102namespace opts {
103
104cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
105cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
106
107cl::SubCommand DiaDumpSubcommand("diadump",
108 "Dump debug information using a DIA-like API");
109
110cl::SubCommand
111 PrettySubcommand("pretty",
112 "Dump semantic information about types and symbols");
113
114cl::SubCommand
115 YamlToPdbSubcommand("yaml2pdb",
116 "Generate a PDB file from a YAML description");
117cl::SubCommand
118 PdbToYamlSubcommand("pdb2yaml",
119 "Generate a detailed YAML description of a PDB File");
120
121cl::SubCommand MergeSubcommand("merge",
122 "Merge multiple PDBs into a single PDB");
123
124cl::SubCommand ExplainSubcommand("explain",
125 "Explain the meaning of a file offset");
126
127cl::SubCommand ExportSubcommand("export",
128 "Write binary data from a stream to a file");
129
130static cl::OptionCategory TypeCategory("Symbol Type Options");
131static cl::OptionCategory FilterCategory("Filtering and Sorting Options");
132static cl::OptionCategory OtherOptions("Other Options");
133
134cl::ValuesClass ChunkValues = cl::values(
135 clEnumValN(ModuleSubsection::CrossScopeExports, "cme",
136 "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
137 clEnumValN(ModuleSubsection::CrossScopeImports, "cmi",
138 "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
139 clEnumValN(ModuleSubsection::FileChecksums, "fc",
140 "File checksums (DEBUG_S_CHECKSUMS subsection)"),
141 clEnumValN(ModuleSubsection::InlineeLines, "ilines",
142 "Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
143 clEnumValN(ModuleSubsection::Lines, "lines",
144 "Lines (DEBUG_S_LINES subsection)"),
145 clEnumValN(ModuleSubsection::StringTable, "strings",
146 "String Table (DEBUG_S_STRINGTABLE subsection) (not "
147 "typically present in PDB file)"),
148 clEnumValN(ModuleSubsection::FrameData, "frames",
149 "Frame Data (DEBUG_S_FRAMEDATA subsection)"),
150 clEnumValN(ModuleSubsection::Symbols, "symbols",
151 "Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
152 "present in PDB file)"),
153 clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
154 "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
155 clEnumValN(ModuleSubsection::Unknown, "unknown",
156 "Any subsection not covered by another option"),
157 clEnumValN(ModuleSubsection::All, "all", "All known subsections"));
158
159namespace diadump {
160static cl::list<std::string> InputFilenames(cl::Positional,
161 cl::desc("<input PDB files>"),
162 cl::OneOrMore,
163 cl::sub(DiaDumpSubcommand));
164
165cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
166 cl::sub(DiaDumpSubcommand));
167
168static cl::opt<bool>
169 ShowClassHierarchy("hierarchy", cl::desc("Show lexical and class parents"),
170 cl::sub(DiaDumpSubcommand));
171static cl::opt<bool> NoSymIndexIds(
172 "no-ids",
173 cl::desc("Don't show any SymIndexId fields (overrides -hierarchy)"),
174 cl::sub(DiaDumpSubcommand));
175
176static cl::opt<bool>
177 Recurse("recurse",
178 cl::desc("When dumping a SymIndexId, dump the full details of the "
179 "corresponding record"),
180 cl::sub(DiaDumpSubcommand));
181
182static cl::opt<bool> Enums("enums", cl::desc("Dump enum types"),
183 cl::sub(DiaDumpSubcommand));
184static cl::opt<bool> Pointers("pointers", cl::desc("Dump enum types"),
185 cl::sub(DiaDumpSubcommand));
186static cl::opt<bool> UDTs("udts", cl::desc("Dump udt types"),
187 cl::sub(DiaDumpSubcommand));
188static cl::opt<bool> Compilands("compilands",
189 cl::desc("Dump compiland information"),
190 cl::sub(DiaDumpSubcommand));
191static cl::opt<bool> Funcsigs("funcsigs",
192 cl::desc("Dump function signature information"),
193 cl::sub(DiaDumpSubcommand));
194static cl::opt<bool> Arrays("arrays", cl::desc("Dump array types"),
195 cl::sub(DiaDumpSubcommand));
196static cl::opt<bool> VTShapes("vtshapes", cl::desc("Dump virtual table shapes"),
197 cl::sub(DiaDumpSubcommand));
198static cl::opt<bool> Typedefs("typedefs", cl::desc("Dump typedefs"),
199 cl::sub(DiaDumpSubcommand));
200} // namespace diadump
201
202FilterOptions Filters;
203
204namespace pretty {
205static cl::list<std::string> InputFilenames(cl::Positional,
206 cl::desc("<input PDB files>"),
207 cl::OneOrMore,
208 cl::sub(PrettySubcommand));
209
210cl::opt<bool> InjectedSources("injected-sources",
211 cl::desc("Display injected sources"),
212 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
213cl::opt<bool> ShowInjectedSourceContent(
214 "injected-source-content",
215 cl::desc("When displaying an injected source, display the file content"),
216 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
217
218cl::list<std::string> WithName(
219 "with-name",
220 cl::desc("Display any symbol or type with the specified exact name"),
221 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
222
223cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
224 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
225cl::opt<bool> Symbols("module-syms",
226 cl::desc("Display symbols for each compiland"),
227 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
228cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
229 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
230cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
231 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
232static cl::list<SymLevel> SymTypes(
233 "sym-types", cl::desc("Type of symbols to dump (default all)"),
234 cl::cat(TypeCategory), cl::sub(PrettySubcommand),
235 cl::values(
236 clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"),
237 clEnumValN(SymLevel::Data, "data", "Display data symbols"),
238 clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"),
239 clEnumValN(SymLevel::All, "all", "Display all symbols (default)")));
240
241cl::opt<bool>
242 Types("types",
243 cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
244 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
245cl::opt<bool> Classes("classes", cl::desc("Display class types"),
246 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
247cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
248 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
249cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
250 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
251cl::opt<bool> Funcsigs("funcsigs", cl::desc("Display function signatures"),
252 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
253cl::opt<bool> Pointers("pointers", cl::desc("Display pointer types"),
254 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
255cl::opt<bool> Arrays("arrays", cl::desc("Display arrays"),
256 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
257cl::opt<bool> VTShapes("vtshapes", cl::desc("Display vftable shapes"),
258 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
259
260cl::opt<SymbolSortMode> SymbolOrder(
261 "symbol-order", cl::desc("symbol sort order"),
262 cl::init(Val: SymbolSortMode::None),
263 cl::values(clEnumValN(SymbolSortMode::None, "none",
264 "Undefined / no particular sort order"),
265 clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"),
266 clEnumValN(SymbolSortMode::Size, "size",
267 "Sort symbols by size")),
268 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
269
270cl::opt<ClassSortMode> ClassOrder(
271 "class-order", cl::desc("Class sort order"), cl::init(Val: ClassSortMode::None),
272 cl::values(
273 clEnumValN(ClassSortMode::None, "none",
274 "Undefined / no particular sort order"),
275 clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
276 clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
277 clEnumValN(ClassSortMode::Padding, "padding",
278 "Sort classes by amount of padding"),
279 clEnumValN(ClassSortMode::PaddingPct, "padding-pct",
280 "Sort classes by percentage of space consumed by padding"),
281 clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm",
282 "Sort classes by amount of immediate padding"),
283 clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm",
284 "Sort classes by percentage of space consumed by immediate "
285 "padding")),
286 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
287
288cl::opt<ClassDefinitionFormat> ClassFormat(
289 "class-definitions", cl::desc("Class definition format"),
290 cl::init(Val: ClassDefinitionFormat::All),
291 cl::values(
292 clEnumValN(ClassDefinitionFormat::All, "all",
293 "Display all class members including data, constants, "
294 "typedefs, functions, etc"),
295 clEnumValN(ClassDefinitionFormat::Layout, "layout",
296 "Only display members that contribute to class size."),
297 clEnumValN(ClassDefinitionFormat::None, "none",
298 "Don't display class definitions")),
299 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
300cl::opt<uint32_t> ClassRecursionDepth(
301 "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"),
302 cl::init(Val: 0), cl::cat(TypeCategory), cl::sub(PrettySubcommand));
303
304cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
305 cl::sub(PrettySubcommand));
306cl::opt<bool>
307 All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
308 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
309
310cl::opt<uint64_t> LoadAddress(
311 "load-address",
312 cl::desc("Assume the module is loaded at the specified address"),
313 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
314cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
315 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
316cl::opt<cl::boolOrDefault>
317 ColorOutput("color-output",
318 cl::desc("Override use of color (default = isatty)"),
319 cl::cat(OtherOptions), cl::sub(PrettySubcommand));
320cl::list<std::string>
321 ExcludeTypes("exclude-types",
322 cl::desc("Exclude types by regular expression"),
323 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
324cl::list<std::string>
325 ExcludeSymbols("exclude-symbols",
326 cl::desc("Exclude symbols by regular expression"),
327 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
328cl::list<std::string>
329 ExcludeCompilands("exclude-compilands",
330 cl::desc("Exclude compilands by regular expression"),
331 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
332
333cl::list<std::string> IncludeTypes(
334 "include-types",
335 cl::desc("Include only types which match a regular expression"),
336 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
337cl::list<std::string> IncludeSymbols(
338 "include-symbols",
339 cl::desc("Include only symbols which match a regular expression"),
340 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
341cl::list<std::string> IncludeCompilands(
342 "include-compilands",
343 cl::desc("Include only compilands those which match a regular expression"),
344 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
345cl::opt<uint32_t> SizeThreshold(
346 "min-type-size", cl::desc("Displays only those types which are greater "
347 "than or equal to the specified size."),
348 cl::init(Val: 0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
349cl::opt<uint32_t> PaddingThreshold(
350 "min-class-padding", cl::desc("Displays only those classes which have at "
351 "least the specified amount of padding."),
352 cl::init(Val: 0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
353cl::opt<uint32_t> ImmediatePaddingThreshold(
354 "min-class-padding-imm",
355 cl::desc("Displays only those classes which have at least the specified "
356 "amount of immediate padding, ignoring padding internal to bases "
357 "and aggregates."),
358 cl::init(Val: 0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
359
360cl::opt<bool> ExcludeCompilerGenerated(
361 "no-compiler-generated",
362 cl::desc("Don't show compiler generated types and symbols"),
363 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
364cl::opt<bool>
365 ExcludeSystemLibraries("no-system-libs",
366 cl::desc("Don't show symbols from system libraries"),
367 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
368
369cl::opt<bool> NoEnumDefs("no-enum-definitions",
370 cl::desc("Don't display full enum definitions"),
371 cl::cat(FilterCategory), cl::sub(PrettySubcommand));
372}
373
374static cl::OptionCategory FileOptions("Module & File Options");
375
376namespace bytes {
377static cl::OptionCategory MsfBytes("MSF File Options");
378static cl::OptionCategory DbiBytes("Dbi Stream Options");
379static cl::OptionCategory PdbBytes("PDB Stream Options");
380static cl::OptionCategory Types("Type Options");
381static cl::OptionCategory ModuleCategory("Module Options");
382
383std::optional<NumberRange> DumpBlockRange;
384std::optional<NumberRange> DumpByteRange;
385
386cl::opt<std::string> DumpBlockRangeOpt(
387 "block-range", cl::value_desc("start[-end]"),
388 cl::desc("Dump binary data from specified range of blocks."),
389 cl::sub(BytesSubcommand), cl::cat(MsfBytes));
390
391cl::opt<std::string>
392 DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
393 cl::desc("Dump binary data from specified range of bytes"),
394 cl::sub(BytesSubcommand), cl::cat(MsfBytes));
395
396cl::list<std::string>
397 DumpStreamData("stream-data", cl::CommaSeparated,
398 cl::desc("Dump binary data from specified streams. Format "
399 "is SN[:Start][@Size]"),
400 cl::sub(BytesSubcommand), cl::cat(MsfBytes));
401
402cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"),
403 cl::sub(BytesSubcommand), cl::cat(PdbBytes));
404cl::opt<bool> Fpm("fpm", cl::desc("Dump free page map"),
405 cl::sub(BytesSubcommand), cl::cat(MsfBytes));
406
407cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"),
408 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
409cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"),
410 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
411cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"),
412 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
413cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"),
414 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
415cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"),
416 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
417cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
418 cl::sub(BytesSubcommand), cl::cat(DbiBytes));
419
420cl::list<uint32_t> TypeIndex(
421 "type", cl::desc("Dump the type record with the given type index"),
422 cl::CommaSeparated, cl::sub(BytesSubcommand), cl::cat(TypeCategory));
423cl::list<uint32_t>
424 IdIndex("id", cl::desc("Dump the id record with the given type index"),
425 cl::CommaSeparated, cl::sub(BytesSubcommand),
426 cl::cat(TypeCategory));
427
428cl::opt<uint32_t> ModuleIndex(
429 "mod",
430 cl::desc(
431 "Limit options in the Modules category to the specified module index"),
432 cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
433cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"),
434 cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
435cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden,
436 cl::desc("Dump C11 CodeView debug chunks"),
437 cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
438cl::opt<bool> ModuleC13("chunks",
439 cl::desc("Dump C13 CodeView debug chunk subsection"),
440 cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
441cl::opt<bool> SplitChunks(
442 "split-chunks",
443 cl::desc(
444 "When dumping debug chunks, show a different section for each chunk"),
445 cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
446static cl::list<std::string> InputFilenames(cl::Positional,
447 cl::desc("<input PDB files>"),
448 cl::OneOrMore,
449 cl::sub(BytesSubcommand));
450
451} // namespace bytes
452
453namespace dump {
454
455static cl::OptionCategory MsfOptions("MSF Container Options");
456static cl::OptionCategory TypeOptions("Type Record Options");
457static cl::OptionCategory SymbolOptions("Symbol Options");
458static cl::OptionCategory MiscOptions("Miscellaneous Options");
459
460// MSF OPTIONS
461cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
462 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
463cl::opt<bool> DumpStreams("streams",
464 cl::desc("dump summary of the PDB streams"),
465 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
466cl::opt<bool> DumpStreamBlocks(
467 "stream-blocks",
468 cl::desc("Add block information to the output of -streams"),
469 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
470cl::opt<bool> DumpSymbolStats(
471 "sym-stats",
472 cl::desc("Dump a detailed breakdown of symbol usage/size for each module"),
473 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
474cl::opt<bool> DumpTypeStats(
475 "type-stats",
476 cl::desc("Dump a detailed breakdown of type usage/size"),
477 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
478cl::opt<bool> DumpIDStats(
479 "id-stats",
480 cl::desc("Dump a detailed breakdown of IPI types usage/size"),
481 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
482cl::opt<bool> DumpUdtStats(
483 "udt-stats",
484 cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"),
485 cl::cat(MsfOptions), cl::sub(DumpSubcommand));
486
487// TYPE OPTIONS
488cl::opt<bool> DumpTypes("types",
489 cl::desc("dump CodeView type records from TPI stream"),
490 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
491cl::opt<bool> DumpTypeData(
492 "type-data",
493 cl::desc("dump CodeView type record raw bytes from TPI stream"),
494 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
495cl::opt<bool>
496 DumpTypeRefStats("type-ref-stats",
497 cl::desc("dump statistics on the number and size of types "
498 "transitively referenced by symbol records"),
499 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
500
501cl::opt<bool> DumpTypeExtras("type-extras",
502 cl::desc("dump type hashes and index offsets"),
503 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
504
505cl::opt<bool> DontResolveForwardRefs(
506 "dont-resolve-forward-refs",
507 cl::desc("When dumping type records for classes, unions, enums, and "
508 "structs, don't try to resolve forward references"),
509 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
510
511cl::list<uint32_t> DumpTypeIndex(
512 "type-index", cl::CommaSeparated,
513 cl::desc("only dump types with the specified hexadecimal type index"),
514 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
515
516cl::opt<bool> DumpIds("ids",
517 cl::desc("dump CodeView type records from IPI stream"),
518 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
519cl::opt<bool>
520 DumpIdData("id-data",
521 cl::desc("dump CodeView type record raw bytes from IPI stream"),
522 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
523
524cl::opt<bool> DumpIdExtras("id-extras",
525 cl::desc("dump id hashes and index offsets"),
526 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
527cl::list<uint32_t> DumpIdIndex(
528 "id-index", cl::CommaSeparated,
529 cl::desc("only dump ids with the specified hexadecimal type index"),
530 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
531
532cl::opt<bool> DumpTypeDependents(
533 "dependents",
534 cl::desc("In conjunection with -type-index and -id-index, dumps the entire "
535 "dependency graph for the specified index instead of "
536 "just the single record with the specified index"),
537 cl::cat(TypeOptions), cl::sub(DumpSubcommand));
538
539// SYMBOL OPTIONS
540cl::opt<bool> DumpGlobals("globals", cl::desc("dump Globals symbol records"),
541 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
542cl::opt<bool> DumpGlobalExtras("global-extras", cl::desc("dump Globals hashes"),
543 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
544cl::list<std::string> DumpGlobalNames(
545 "global-name",
546 cl::desc(
547 "With -globals, only dump globals whose name matches the given value"),
548 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
549cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
550 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
551cl::opt<bool> DumpPublicExtras("public-extras",
552 cl::desc("dump Publics hashes and address maps"),
553 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
554cl::opt<bool>
555 DumpGSIRecords("gsi-records",
556 cl::desc("dump public / global common record stream"),
557 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
558cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
559 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
560
561cl::opt<bool>
562 DumpSymRecordBytes("sym-data",
563 cl::desc("dump CodeView symbol record raw bytes"),
564 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
565
566cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"),
567 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
568
569cl::opt<uint32_t> DumpSymbolOffset(
570 "symbol-offset", cl::Optional,
571 cl::desc("only dump symbol record with the specified symbol offset"),
572 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
573cl::opt<bool> DumpParents("show-parents",
574 cl::desc("dump the symbols record's all parents."),
575 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
576cl::opt<uint32_t>
577 DumpParentDepth("parent-recurse-depth", cl::Optional, cl::init(Val: -1U),
578 cl::desc("only recurse to a depth of N when displaying "
579 "parents of a symbol record."),
580 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
581cl::opt<bool> DumpChildren("show-children",
582 cl::desc("dump the symbols record's all children."),
583 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
584cl::opt<uint32_t>
585 DumpChildrenDepth("children-recurse-depth", cl::Optional, cl::init(Val: -1U),
586 cl::desc("only recurse to a depth of N when displaying "
587 "children of a symbol record."),
588 cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
589
590// MODULE & FILE OPTIONS
591cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
592 cl::cat(FileOptions), cl::sub(DumpSubcommand));
593cl::opt<bool> DumpModuleFiles(
594 "files",
595 cl::desc("Dump the source files that contribute to each module's."),
596 cl::cat(FileOptions), cl::sub(DumpSubcommand));
597cl::opt<bool> DumpLines(
598 "l",
599 cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
600 cl::cat(FileOptions), cl::sub(DumpSubcommand));
601cl::opt<bool> DumpInlineeLines(
602 "il",
603 cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
604 cl::cat(FileOptions), cl::sub(DumpSubcommand));
605cl::opt<bool> DumpXmi(
606 "xmi",
607 cl::desc(
608 "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
609 cl::cat(FileOptions), cl::sub(DumpSubcommand));
610cl::opt<bool> DumpXme(
611 "xme",
612 cl::desc(
613 "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
614 cl::cat(FileOptions), cl::sub(DumpSubcommand));
615cl::opt<uint32_t> DumpModi("modi", cl::Optional,
616 cl::desc("For all options that iterate over "
617 "modules, limit to the specified module"),
618 cl::cat(FileOptions), cl::sub(DumpSubcommand));
619cl::opt<bool> JustMyCode("jmc", cl::Optional,
620 cl::desc("For all options that iterate over modules, "
621 "ignore modules from system libraries"),
622 cl::cat(FileOptions), cl::sub(DumpSubcommand));
623
624// MISCELLANEOUS OPTIONS
625cl::opt<bool> DumpNamedStreams("named-streams",
626 cl::desc("dump PDB named stream table"),
627 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
628
629cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
630 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
631cl::opt<bool> DumpStringTableDetails("string-table-details",
632 cl::desc("dump PDB String Table Details"),
633 cl::cat(MiscOptions),
634 cl::sub(DumpSubcommand));
635
636cl::opt<bool> DumpSectionContribs("section-contribs",
637 cl::desc("dump section contributions"),
638 cl::cat(MiscOptions),
639 cl::sub(DumpSubcommand));
640cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
641 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
642cl::opt<bool> DumpSectionHeaders("section-headers",
643 cl::desc("Dump image section headers"),
644 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
645
646cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
647 cl::cat(MiscOptions), cl::sub(DumpSubcommand));
648
649static cl::list<std::string> InputFilenames(cl::Positional,
650 cl::desc("<input PDB files>"),
651 cl::OneOrMore,
652 cl::sub(DumpSubcommand));
653}
654
655namespace yaml2pdb {
656cl::opt<std::string>
657 YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
658 cl::sub(YamlToPdbSubcommand));
659
660cl::opt<std::string> InputFilename(cl::Positional,
661 cl::desc("<input YAML file>"), cl::Required,
662 cl::sub(YamlToPdbSubcommand));
663}
664
665namespace pdb2yaml {
666cl::opt<bool> All("all",
667 cl::desc("Dump everything we know how to dump."),
668 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
669cl::opt<bool> NoFileHeaders("no-file-headers",
670 cl::desc("Do not dump MSF file headers"),
671 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
672cl::opt<bool> Minimal("minimal",
673 cl::desc("Don't write fields with default values"),
674 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
675
676cl::opt<bool> StreamMetadata(
677 "stream-metadata",
678 cl::desc("Dump the number of streams and each stream's size"),
679 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
680cl::opt<bool> StreamDirectory(
681 "stream-directory",
682 cl::desc("Dump each stream's block map (implies -stream-metadata)"),
683 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
684cl::opt<bool> PdbStream("pdb-stream",
685 cl::desc("Dump the PDB Stream (Stream 1)"),
686 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
687
688cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
689 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
690
691cl::opt<bool> DbiStream("dbi-stream",
692 cl::desc("Dump the DBI Stream Headers (Stream 2)"),
693 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
694
695cl::opt<bool> TpiStream("tpi-stream",
696 cl::desc("Dump the TPI Stream (Stream 3)"),
697 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
698
699cl::opt<bool> IpiStream("ipi-stream",
700 cl::desc("Dump the IPI Stream (Stream 5)"),
701 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
702
703cl::opt<bool> PublicsStream("publics-stream",
704 cl::desc("Dump the Publics Stream"),
705 cl::sub(PdbToYamlSubcommand), cl::init(Val: false));
706
707// MODULE & FILE OPTIONS
708cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
709 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
710cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
711 cl::cat(FileOptions),
712 cl::sub(PdbToYamlSubcommand));
713cl::list<ModuleSubsection> DumpModuleSubsections(
714 "subsections", cl::CommaSeparated,
715 cl::desc("dump subsections from each module's debug stream"), ChunkValues,
716 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
717cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
718 cl::cat(FileOptions),
719 cl::sub(PdbToYamlSubcommand));
720cl::opt<bool> DumpSectionHeaders("section-headers",
721 cl::desc("Dump section headers."),
722 cl::cat(FileOptions),
723 cl::sub(PdbToYamlSubcommand));
724
725cl::list<std::string> InputFilename(cl::Positional,
726 cl::desc("<input PDB file>"), cl::Required,
727 cl::sub(PdbToYamlSubcommand));
728} // namespace pdb2yaml
729
730namespace merge {
731static cl::list<std::string> InputFilenames(cl::Positional,
732 cl::desc("<input PDB files>"),
733 cl::OneOrMore,
734 cl::sub(MergeSubcommand));
735cl::opt<std::string>
736 PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
737 cl::sub(MergeSubcommand));
738}
739
740namespace explain {
741cl::list<std::string> InputFilename(cl::Positional,
742 cl::desc("<input PDB file>"), cl::Required,
743 cl::sub(ExplainSubcommand));
744
745cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"),
746 cl::sub(ExplainSubcommand), cl::OneOrMore);
747
748cl::opt<InputFileType> InputType(
749 "input-type", cl::desc("Specify how to interpret the input file"),
750 cl::init(Val: InputFileType::PDBFile), cl::Optional, cl::sub(ExplainSubcommand),
751 cl::values(clEnumValN(InputFileType::PDBFile, "pdb-file",
752 "Treat input as a PDB file (default)"),
753 clEnumValN(InputFileType::PDBStream, "pdb-stream",
754 "Treat input as raw contents of PDB stream"),
755 clEnumValN(InputFileType::DBIStream, "dbi-stream",
756 "Treat input as raw contents of DBI stream"),
757 clEnumValN(InputFileType::Names, "names-stream",
758 "Treat input as raw contents of /names named stream"),
759 clEnumValN(InputFileType::ModuleStream, "mod-stream",
760 "Treat input as raw contents of a module stream")));
761} // namespace explain
762
763namespace exportstream {
764static cl::list<std::string> InputFilename(cl::Positional,
765 cl::desc("<input PDB file>"),
766 cl::Required,
767 cl::sub(ExportSubcommand));
768cl::opt<std::string> OutputFile("out",
769 cl::desc("The file to write the stream to"),
770 cl::Required, cl::sub(ExportSubcommand));
771cl::opt<std::string>
772 Stream("stream", cl::Required,
773 cl::desc("The index or name of the stream whose contents to export"),
774 cl::sub(ExportSubcommand));
775cl::opt<bool> ForceName("name",
776 cl::desc("Force the interpretation of -stream as a "
777 "string, even if it is a valid integer"),
778 cl::sub(ExportSubcommand), cl::Optional,
779 cl::init(Val: false));
780} // namespace exportstream
781}
782
783static ExitOnError ExitOnErr;
784
785static void yamlToPdb(StringRef Path) {
786 BumpPtrAllocator Allocator;
787 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
788 MemoryBuffer::getFileOrSTDIN(Filename: Path, /*IsText=*/false,
789 /*RequiresNullTerminator=*/false);
790
791 if (ErrorOrBuffer.getError()) {
792 ExitOnErr(createFileError(F: Path, E: errorCodeToError(EC: ErrorOrBuffer.getError())));
793 }
794
795 std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
796
797 llvm::yaml::Input In(Buffer->getBuffer());
798 pdb::yaml::PdbObject YamlObj(Allocator);
799 In >> YamlObj;
800
801 PDBFileBuilder Builder(Allocator);
802
803 uint32_t BlockSize = 4096;
804 if (YamlObj.Headers)
805 BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
806 ExitOnErr(Builder.initialize(BlockSize));
807 // Add each of the reserved streams. We ignore stream metadata in the
808 // yaml, because we will reconstruct our own view of the streams. For
809 // example, the YAML may say that there were 20 streams in the original
810 // PDB, but maybe we only dump a subset of those 20 streams, so we will
811 // have fewer, and the ones we do have may end up with different indices
812 // than the ones in the original PDB. So we just start with a clean slate.
813 for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
814 ExitOnErr(Builder.getMsfBuilder().addStream(Size: 0));
815
816 StringsAndChecksums Strings;
817 Strings.setStrings(std::make_shared<DebugStringTableSubsection>());
818
819 if (YamlObj.StringTable) {
820 for (auto S : *YamlObj.StringTable)
821 Strings.strings()->insert(S);
822 }
823
824 pdb::yaml::PdbInfoStream DefaultInfoStream;
825 pdb::yaml::PdbDbiStream DefaultDbiStream;
826 pdb::yaml::PdbTpiStream DefaultTpiStream;
827 pdb::yaml::PdbTpiStream DefaultIpiStream;
828
829 const auto &Info = YamlObj.PdbStream.value_or(u&: DefaultInfoStream);
830
831 auto &InfoBuilder = Builder.getInfoBuilder();
832 InfoBuilder.setAge(Info.Age);
833 InfoBuilder.setGuid(Info.Guid);
834 InfoBuilder.setSignature(Info.Signature);
835 InfoBuilder.setVersion(Info.Version);
836 for (auto F : Info.Features)
837 InfoBuilder.addFeature(Sig: F);
838
839 const auto &Dbi = YamlObj.DbiStream.value_or(u&: DefaultDbiStream);
840 auto &DbiBuilder = Builder.getDbiBuilder();
841 DbiBuilder.setAge(Dbi.Age);
842 DbiBuilder.setBuildNumber(Dbi.BuildNumber);
843 DbiBuilder.setFlags(Dbi.Flags);
844 DbiBuilder.setMachineType(Dbi.MachineType);
845 DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
846 DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
847 DbiBuilder.setVersionHeader(Dbi.VerHeader);
848 for (const auto &MI : Dbi.ModInfos) {
849 auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(ModuleName: MI.Mod));
850 ModiBuilder.setObjFileName(MI.Obj);
851
852 for (auto S : MI.SourceFiles)
853 ExitOnErr(DbiBuilder.addModuleSourceFile(Module&: ModiBuilder, File: S));
854 if (MI.Modi) {
855 const auto &ModiStream = *MI.Modi;
856 for (const auto &Symbol : ModiStream.Symbols) {
857 ModiBuilder.addSymbol(
858 Symbol: Symbol.toCodeViewSymbol(Allocator, Container: CodeViewContainer::Pdb));
859 }
860 }
861
862 // Each module has its own checksum subsection, so scan for it every time.
863 Strings.setChecksums(nullptr);
864 CodeViewYAML::initializeStringsAndChecksums(Sections: MI.Subsections, SC&: Strings);
865
866 auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList(
867 Allocator, Subsections: MI.Subsections, SC: Strings));
868 for (auto &SS : CodeViewSubsections) {
869 ModiBuilder.addDebugSubsection(Subsection: SS);
870 }
871 }
872
873 std::vector<object::coff_section> Sections;
874 if (!Dbi.SectionHeaders.empty()) {
875 for (const auto &Hdr : Dbi.SectionHeaders)
876 Sections.emplace_back(args: Hdr.toCoffSection());
877
878 DbiBuilder.createSectionMap(SecHdrs: Sections);
879 ExitOnErr(DbiBuilder.addDbgStream(
880 Type: pdb::DbgHeaderType::SectionHdr,
881 // FIXME: Downcasting to an ArrayRef<uint8_t> should use a helper
882 // function in LLVM
883 Data: ArrayRef<uint8_t>{(const uint8_t *)Sections.data(),
884 Sections.size() * sizeof(object::coff_section)}));
885 }
886
887 auto &TpiBuilder = Builder.getTpiBuilder();
888 const auto &Tpi = YamlObj.TpiStream.value_or(u&: DefaultTpiStream);
889 TpiBuilder.setVersionHeader(Tpi.Version);
890 AppendingTypeTableBuilder TS(Allocator);
891 for (const auto &R : Tpi.Records) {
892 CVType Type = R.toCodeViewRecord(Serializer&: TS);
893 uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
894 TpiBuilder.addTypeRecord(Type: Type.RecordData, Hash);
895 }
896
897 const auto &Ipi = YamlObj.IpiStream.value_or(u&: DefaultIpiStream);
898 auto &IpiBuilder = Builder.getIpiBuilder();
899 IpiBuilder.setVersionHeader(Ipi.Version);
900 for (const auto &R : Ipi.Records) {
901 CVType Type = R.toCodeViewRecord(Serializer&: TS);
902 uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
903 IpiBuilder.addTypeRecord(Type: Type.RecordData, Hash);
904 }
905
906 if (YamlObj.PublicsStream) {
907 auto &GsiBuilder = Builder.getGsiBuilder();
908 std::vector<BulkPublic> BulkPublics;
909 for (const auto &P : YamlObj.PublicsStream->PubSyms) {
910 CVSymbol CV = P.toCodeViewSymbol(Allocator, Container: CodeViewContainer::Pdb);
911 auto PS = cantFail(ValOrErr: SymbolDeserializer::deserializeAs<PublicSym32>(Symbol: CV));
912
913 BulkPublic BP;
914 BP.Name = PS.Name.data();
915 BP.NameLen = PS.Name.size();
916 BP.setFlags(PS.Flags);
917 BP.Offset = PS.Offset;
918 BP.Segment = PS.Segment;
919 BulkPublics.emplace_back(args&: BP);
920 }
921 GsiBuilder.addPublicSymbols(PublicsIn: std::move(BulkPublics));
922 }
923
924 Builder.getStringTableBuilder().setStrings(*Strings.strings());
925
926 codeview::GUID IgnoredOutGuid;
927 ExitOnErr(Builder.commit(Filename: opts::yaml2pdb::YamlPdbOutputFile, Guid: &IgnoredOutGuid));
928}
929
930static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) {
931 ExitOnErr(loadDataForPDB(Type: PDB_ReaderType::Native, Path, Session));
932
933 NativeSession *NS = static_cast<NativeSession *>(Session.get());
934 return NS->getPDBFile();
935}
936
937static void pdb2Yaml(StringRef Path) {
938 std::unique_ptr<IPDBSession> Session;
939 auto &File = loadPDB(Path, Session);
940
941 auto O = std::make_unique<YAMLOutputStyle>(args&: File);
942
943 ExitOnErr(O->dump());
944}
945
946static void dumpRaw(StringRef Path) {
947 InputFile IF = ExitOnErr(InputFile::open(Path));
948
949 auto O = std::make_unique<DumpOutputStyle>(args&: IF);
950 ExitOnErr(O->dump());
951}
952
953static void dumpBytes(StringRef Path) {
954 std::unique_ptr<IPDBSession> Session;
955 auto &File = loadPDB(Path, Session);
956
957 auto O = std::make_unique<BytesOutputStyle>(args&: File);
958
959 ExitOnErr(O->dump());
960}
961
962bool opts::pretty::shouldDumpSymLevel(SymLevel Search) {
963 if (SymTypes.empty())
964 return true;
965 if (llvm::is_contained(Range&: SymTypes, Element: Search))
966 return true;
967 if (llvm::is_contained(Range&: SymTypes, Element: SymLevel::All))
968 return true;
969 return false;
970}
971
972uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) {
973 auto SymbolType = Symbol.getType();
974 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
975
976 return RawType.getLength();
977}
978
979bool opts::pretty::compareFunctionSymbols(
980 const std::unique_ptr<PDBSymbolFunc> &F1,
981 const std::unique_ptr<PDBSymbolFunc> &F2) {
982 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
983
984 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
985 return F1->getName() < F2->getName();
986
987 // Note that we intentionally sort in descending order on length, since
988 // long functions are more interesting than short functions.
989 return F1->getLength() > F2->getLength();
990}
991
992bool opts::pretty::compareDataSymbols(
993 const std::unique_ptr<PDBSymbolData> &F1,
994 const std::unique_ptr<PDBSymbolData> &F2) {
995 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
996
997 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
998 return F1->getName() < F2->getName();
999
1000 // Note that we intentionally sort in descending order on length, since
1001 // large types are more interesting than short ones.
1002 return getTypeLength(Symbol: *F1) > getTypeLength(Symbol: *F2);
1003}
1004
1005static std::string stringOr(std::string Str, std::string IfEmpty) {
1006 return (Str.empty()) ? IfEmpty : Str;
1007}
1008
1009static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
1010 auto Sources = Session.getInjectedSources();
1011 if (!Sources || !Sources->getChildCount()) {
1012 Printer.printLine(T: "There are no injected sources.");
1013 return;
1014 }
1015
1016 while (auto IS = Sources->getNext()) {
1017 Printer.NewLine();
1018 std::string File = stringOr(Str: IS->getFileName(), IfEmpty: "<null>");
1019 uint64_t Size = IS->getCodeByteSize();
1020 std::string Obj = stringOr(Str: IS->getObjectFileName(), IfEmpty: "<null>");
1021 std::string VFName = stringOr(Str: IS->getVirtualFileName(), IfEmpty: "<null>");
1022 uint32_t CRC = IS->getCrc32();
1023
1024 WithColor(Printer, PDB_ColorItem::Path).get() << File;
1025 Printer << " (";
1026 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Size;
1027 Printer << " bytes): ";
1028 WithColor(Printer, PDB_ColorItem::Keyword).get() << "obj";
1029 Printer << "=";
1030 WithColor(Printer, PDB_ColorItem::Path).get() << Obj;
1031 Printer << ", ";
1032 WithColor(Printer, PDB_ColorItem::Keyword).get() << "vname";
1033 Printer << "=";
1034 WithColor(Printer, PDB_ColorItem::Path).get() << VFName;
1035 Printer << ", ";
1036 WithColor(Printer, PDB_ColorItem::Keyword).get() << "crc";
1037 Printer << "=";
1038 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << CRC;
1039 Printer << ", ";
1040 WithColor(Printer, PDB_ColorItem::Keyword).get() << "compression";
1041 Printer << "=";
1042 dumpPDBSourceCompression(
1043 OS&: WithColor(Printer, PDB_ColorItem::LiteralValue).get(),
1044 Compression: IS->getCompression());
1045
1046 if (!opts::pretty::ShowInjectedSourceContent)
1047 continue;
1048
1049 // Set the indent level to 0 when printing file content.
1050 int Indent = Printer.getIndentLevel();
1051 Printer.Unindent(Amount: Indent);
1052
1053 if (IS->getCompression() == PDB_SourceCompression::None)
1054 Printer.printLine(T: IS->getCode());
1055 else
1056 Printer.formatBinary(Label: "Compressed data",
1057 Data: arrayRefFromStringRef(Input: IS->getCode()),
1058 /*StartOffset=*/0);
1059
1060 // Re-indent back to the original level.
1061 Printer.Indent(Amount: Indent);
1062 }
1063}
1064
1065template <typename OuterT, typename ChildT>
1066void diaDumpChildren(PDBSymbol &Outer, PdbSymbolIdField Ids,
1067 PdbSymbolIdField Recurse) {
1068 OuterT *ConcreteOuter = dyn_cast<OuterT>(&Outer);
1069 if (!ConcreteOuter)
1070 return;
1071
1072 auto Children = ConcreteOuter->template findAllChildren<ChildT>();
1073 while (auto Child = Children->getNext()) {
1074 outs() << " {";
1075 Child->defaultDump(outs(), 4, Ids, Recurse);
1076 outs() << "\n }\n";
1077 }
1078}
1079
1080static void dumpDia(StringRef Path) {
1081 std::unique_ptr<IPDBSession> Session;
1082
1083 const auto ReaderType =
1084 opts::diadump::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
1085 ExitOnErr(loadDataForPDB(Type: ReaderType, Path, Session));
1086
1087 auto GlobalScope = Session->getGlobalScope();
1088
1089 std::vector<PDB_SymType> SymTypes;
1090
1091 if (opts::diadump::Compilands)
1092 SymTypes.push_back(x: PDB_SymType::Compiland);
1093 if (opts::diadump::Enums)
1094 SymTypes.push_back(x: PDB_SymType::Enum);
1095 if (opts::diadump::Pointers)
1096 SymTypes.push_back(x: PDB_SymType::PointerType);
1097 if (opts::diadump::UDTs)
1098 SymTypes.push_back(x: PDB_SymType::UDT);
1099 if (opts::diadump::Funcsigs)
1100 SymTypes.push_back(x: PDB_SymType::FunctionSig);
1101 if (opts::diadump::Arrays)
1102 SymTypes.push_back(x: PDB_SymType::ArrayType);
1103 if (opts::diadump::VTShapes)
1104 SymTypes.push_back(x: PDB_SymType::VTableShape);
1105 if (opts::diadump::Typedefs)
1106 SymTypes.push_back(x: PDB_SymType::Typedef);
1107 PdbSymbolIdField Ids = opts::diadump::NoSymIndexIds ? PdbSymbolIdField::None
1108 : PdbSymbolIdField::All;
1109
1110 PdbSymbolIdField Recurse = PdbSymbolIdField::None;
1111 if (opts::diadump::Recurse)
1112 Recurse = PdbSymbolIdField::All;
1113 if (!opts::diadump::ShowClassHierarchy)
1114 Ids &= ~(PdbSymbolIdField::ClassParent | PdbSymbolIdField::LexicalParent);
1115
1116 for (PDB_SymType ST : SymTypes) {
1117 auto Children = GlobalScope->findAllChildren(Type: ST);
1118 while (auto Child = Children->getNext()) {
1119 outs() << "{";
1120 Child->defaultDump(OS&: outs(), Indent: 2, ShowFlags: Ids, RecurseFlags: Recurse);
1121
1122 diaDumpChildren<PDBSymbolTypeEnum, PDBSymbolData>(Outer&: *Child, Ids, Recurse);
1123 outs() << "\n}\n";
1124 }
1125 }
1126}
1127
1128static void dumpPretty(StringRef Path) {
1129 std::unique_ptr<IPDBSession> Session;
1130
1131 const auto ReaderType =
1132 opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
1133 ExitOnErr(loadDataForPDB(Type: ReaderType, Path, Session));
1134
1135 if (opts::pretty::LoadAddress)
1136 Session->setLoadAddress(opts::pretty::LoadAddress);
1137
1138 auto &Stream = outs();
1139 const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET
1140 ? Stream.has_colors()
1141 : opts::pretty::ColorOutput == cl::BOU_TRUE;
1142 LinePrinter Printer(2, UseColor, Stream, opts::Filters);
1143
1144 auto GlobalScope(Session->getGlobalScope());
1145 if (!GlobalScope)
1146 return;
1147 std::string FileName(GlobalScope->getSymbolsFileName());
1148
1149 WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
1150 WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
1151 Printer.Indent();
1152 uint64_t FileSize = 0;
1153
1154 Printer.NewLine();
1155 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
1156 if (!sys::fs::file_size(Path: FileName, Result&: FileSize)) {
1157 Printer << ": " << FileSize << " bytes";
1158 } else {
1159 Printer << ": (Unable to obtain file size)";
1160 }
1161
1162 Printer.NewLine();
1163 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
1164 Printer << ": " << GlobalScope->getGuid();
1165
1166 Printer.NewLine();
1167 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
1168 Printer << ": " << GlobalScope->getAge();
1169
1170 Printer.NewLine();
1171 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
1172 Printer << ": ";
1173 if (GlobalScope->hasCTypes())
1174 outs() << "HasCTypes ";
1175 if (GlobalScope->hasPrivateSymbols())
1176 outs() << "HasPrivateSymbols ";
1177 Printer.Unindent();
1178
1179 if (!opts::pretty::WithName.empty()) {
1180 Printer.NewLine();
1181 WithColor(Printer, PDB_ColorItem::SectionHeader).get()
1182 << "---SYMBOLS & TYPES BY NAME---";
1183
1184 for (StringRef Name : opts::pretty::WithName) {
1185 auto Symbols = GlobalScope->findChildren(
1186 Type: PDB_SymType::None, Name, Flags: PDB_NameSearchFlags::NS_CaseSensitive);
1187 if (!Symbols || Symbols->getChildCount() == 0) {
1188 Printer.formatLine(Fmt: "[not found] - {0}", Items&: Name);
1189 continue;
1190 }
1191 Printer.formatLine(Fmt: "[{0} occurrences] - {1}", Items: Symbols->getChildCount(),
1192 Items&: Name);
1193
1194 AutoIndent Indent(Printer);
1195 Printer.NewLine();
1196
1197 while (auto Symbol = Symbols->getNext()) {
1198 switch (Symbol->getSymTag()) {
1199 case PDB_SymType::Typedef: {
1200 TypedefDumper TD(Printer);
1201 std::unique_ptr<PDBSymbolTypeTypedef> T =
1202 llvm::unique_dyn_cast<PDBSymbolTypeTypedef>(Val: std::move(Symbol));
1203 TD.start(Symbol: *T);
1204 break;
1205 }
1206 case PDB_SymType::Enum: {
1207 EnumDumper ED(Printer);
1208 std::unique_ptr<PDBSymbolTypeEnum> E =
1209 llvm::unique_dyn_cast<PDBSymbolTypeEnum>(Val: std::move(Symbol));
1210 ED.start(Symbol: *E);
1211 break;
1212 }
1213 case PDB_SymType::UDT: {
1214 ClassDefinitionDumper CD(Printer);
1215 std::unique_ptr<PDBSymbolTypeUDT> C =
1216 llvm::unique_dyn_cast<PDBSymbolTypeUDT>(Val: std::move(Symbol));
1217 CD.start(Class: *C);
1218 break;
1219 }
1220 case PDB_SymType::BaseClass:
1221 case PDB_SymType::Friend: {
1222 TypeDumper TD(Printer);
1223 Symbol->dump(Dumper&: TD);
1224 break;
1225 }
1226 case PDB_SymType::Function: {
1227 FunctionDumper FD(Printer);
1228 std::unique_ptr<PDBSymbolFunc> F =
1229 llvm::unique_dyn_cast<PDBSymbolFunc>(Val: std::move(Symbol));
1230 FD.start(Symbol: *F, Pointer: FunctionDumper::PointerType::None);
1231 break;
1232 }
1233 case PDB_SymType::Data: {
1234 VariableDumper VD(Printer);
1235 std::unique_ptr<PDBSymbolData> D =
1236 llvm::unique_dyn_cast<PDBSymbolData>(Val: std::move(Symbol));
1237 VD.start(Var: *D);
1238 break;
1239 }
1240 case PDB_SymType::PublicSymbol: {
1241 ExternalSymbolDumper ED(Printer);
1242 std::unique_ptr<PDBSymbolPublicSymbol> PS =
1243 llvm::unique_dyn_cast<PDBSymbolPublicSymbol>(Val: std::move(Symbol));
1244 ED.dump(Symbol: *PS);
1245 break;
1246 }
1247 default:
1248 llvm_unreachable("Unexpected symbol tag!");
1249 }
1250 }
1251 }
1252 llvm::outs().flush();
1253 }
1254
1255 if (opts::pretty::Compilands) {
1256 Printer.NewLine();
1257 WithColor(Printer, PDB_ColorItem::SectionHeader).get()
1258 << "---COMPILANDS---";
1259 auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
1260
1261 if (Compilands) {
1262 Printer.Indent();
1263 CompilandDumper Dumper(Printer);
1264 CompilandDumpFlags options = CompilandDumper::Flags::None;
1265 if (opts::pretty::Lines)
1266 options = options | CompilandDumper::Flags::Lines;
1267 while (auto Compiland = Compilands->getNext())
1268 Dumper.start(Symbol: *Compiland, flags: options);
1269 Printer.Unindent();
1270 }
1271 }
1272
1273 if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs ||
1274 opts::pretty::Funcsigs || opts::pretty::Pointers ||
1275 opts::pretty::Arrays || opts::pretty::VTShapes) {
1276 Printer.NewLine();
1277 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
1278 Printer.Indent();
1279 TypeDumper Dumper(Printer);
1280 Dumper.start(Exe: *GlobalScope);
1281 Printer.Unindent();
1282 }
1283
1284 if (opts::pretty::Symbols) {
1285 Printer.NewLine();
1286 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
1287 if (auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>()) {
1288 Printer.Indent();
1289 CompilandDumper Dumper(Printer);
1290 while (auto Compiland = Compilands->getNext())
1291 Dumper.start(Symbol: *Compiland, flags: true);
1292 Printer.Unindent();
1293 }
1294 }
1295
1296 if (opts::pretty::Globals) {
1297 Printer.NewLine();
1298 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
1299 Printer.Indent();
1300 if (shouldDumpSymLevel(Search: opts::pretty::SymLevel::Functions)) {
1301 if (auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>()) {
1302 FunctionDumper Dumper(Printer);
1303 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
1304 while (auto Function = Functions->getNext()) {
1305 Printer.NewLine();
1306 Dumper.start(Symbol: *Function, Pointer: FunctionDumper::PointerType::None);
1307 }
1308 } else {
1309 std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs;
1310 while (auto Func = Functions->getNext())
1311 Funcs.push_back(x: std::move(Func));
1312 llvm::sort(C&: Funcs, Comp: opts::pretty::compareFunctionSymbols);
1313 for (const auto &Func : Funcs) {
1314 Printer.NewLine();
1315 Dumper.start(Symbol: *Func, Pointer: FunctionDumper::PointerType::None);
1316 }
1317 }
1318 }
1319 }
1320 if (shouldDumpSymLevel(Search: opts::pretty::SymLevel::Data)) {
1321 if (auto Vars = GlobalScope->findAllChildren<PDBSymbolData>()) {
1322 VariableDumper Dumper(Printer);
1323 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
1324 while (auto Var = Vars->getNext())
1325 Dumper.start(Var: *Var);
1326 } else {
1327 std::vector<std::unique_ptr<PDBSymbolData>> Datas;
1328 while (auto Var = Vars->getNext())
1329 Datas.push_back(x: std::move(Var));
1330 llvm::sort(C&: Datas, Comp: opts::pretty::compareDataSymbols);
1331 for (const auto &Var : Datas)
1332 Dumper.start(Var: *Var);
1333 }
1334 }
1335 }
1336 if (shouldDumpSymLevel(Search: opts::pretty::SymLevel::Thunks)) {
1337 if (auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>()) {
1338 CompilandDumper Dumper(Printer);
1339 while (auto Thunk = Thunks->getNext())
1340 Dumper.dump(Symbol: *Thunk);
1341 }
1342 }
1343 Printer.Unindent();
1344 }
1345 if (opts::pretty::Externals) {
1346 Printer.NewLine();
1347 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
1348 Printer.Indent();
1349 ExternalSymbolDumper Dumper(Printer);
1350 Dumper.start(Symbol: *GlobalScope);
1351 }
1352 if (opts::pretty::Lines) {
1353 Printer.NewLine();
1354 }
1355 if (opts::pretty::InjectedSources) {
1356 Printer.NewLine();
1357 WithColor(Printer, PDB_ColorItem::SectionHeader).get()
1358 << "---INJECTED SOURCES---";
1359 AutoIndent Indent1(Printer);
1360 dumpInjectedSources(Printer, Session&: *Session);
1361 }
1362
1363 Printer.NewLine();
1364 outs().flush();
1365}
1366
1367static void mergePdbs() {
1368 BumpPtrAllocator Allocator;
1369 MergingTypeTableBuilder MergedTpi(Allocator);
1370 MergingTypeTableBuilder MergedIpi(Allocator);
1371
1372 // Create a Tpi and Ipi type table with all types from all input files.
1373 for (const auto &Path : opts::merge::InputFilenames) {
1374 std::unique_ptr<IPDBSession> Session;
1375 auto &File = loadPDB(Path, Session);
1376 SmallVector<TypeIndex, 128> TypeMap;
1377 SmallVector<TypeIndex, 128> IdMap;
1378 if (File.hasPDBTpiStream()) {
1379 auto &Tpi = ExitOnErr(File.getPDBTpiStream());
1380 ExitOnErr(
1381 codeview::mergeTypeRecords(Dest&: MergedTpi, SourceToDest&: TypeMap, Types: Tpi.typeArray()));
1382 }
1383 if (File.hasPDBIpiStream()) {
1384 auto &Ipi = ExitOnErr(File.getPDBIpiStream());
1385 ExitOnErr(codeview::mergeIdRecords(Dest&: MergedIpi, Types: TypeMap, SourceToDest&: IdMap,
1386 Ids: Ipi.typeArray()));
1387 }
1388 }
1389
1390 // Then write the PDB.
1391 PDBFileBuilder Builder(Allocator);
1392 ExitOnErr(Builder.initialize(BlockSize: 4096));
1393 // Add each of the reserved streams. We might not put any data in them,
1394 // but at least they have to be present.
1395 for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
1396 ExitOnErr(Builder.getMsfBuilder().addStream(Size: 0));
1397
1398 auto &DestTpi = Builder.getTpiBuilder();
1399 auto &DestIpi = Builder.getIpiBuilder();
1400 MergedTpi.ForEachRecord(Func: [&DestTpi](TypeIndex TI, const CVType &Type) {
1401 uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
1402 DestTpi.addTypeRecord(Type: Type.RecordData, Hash);
1403 });
1404 MergedIpi.ForEachRecord(Func: [&DestIpi](TypeIndex TI, const CVType &Type) {
1405 uint32_t Hash = ExitOnErr(llvm::pdb::hashTypeRecord(Type));
1406 DestIpi.addTypeRecord(Type: Type.RecordData, Hash);
1407 });
1408 Builder.getInfoBuilder().addFeature(Sig: PdbRaw_FeatureSig::VC140);
1409
1410 SmallString<64> OutFile(opts::merge::PdbOutputFile);
1411 if (OutFile.empty()) {
1412 OutFile = opts::merge::InputFilenames[0];
1413 llvm::sys::path::replace_extension(path&: OutFile, extension: "merged.pdb");
1414 }
1415
1416 codeview::GUID IgnoredOutGuid;
1417 ExitOnErr(Builder.commit(Filename: OutFile, Guid: &IgnoredOutGuid));
1418}
1419
1420static void explain() {
1421 InputFile IF =
1422 ExitOnErr(InputFile::open(Path: opts::explain::InputFilename.front(), AllowUnknownFile: true));
1423
1424 for (uint64_t Off : opts::explain::Offsets) {
1425 auto O = std::make_unique<ExplainOutputStyle>(args&: IF, args&: Off);
1426
1427 ExitOnErr(O->dump());
1428 }
1429}
1430
1431static void exportStream() {
1432 std::unique_ptr<IPDBSession> Session;
1433 PDBFile &File = loadPDB(Path: opts::exportstream::InputFilename.front(), Session);
1434
1435 std::unique_ptr<MappedBlockStream> SourceStream;
1436 uint32_t Index = 0;
1437 bool Success = false;
1438 std::string OutFileName = opts::exportstream::OutputFile;
1439
1440 if (!opts::exportstream::ForceName) {
1441 // First try to parse it as an integer, if it fails fall back to treating it
1442 // as a named stream.
1443 if (to_integer(S: opts::exportstream::Stream, Num&: Index)) {
1444 if (Index >= File.getNumStreams()) {
1445 errs() << "Error: " << Index << " is not a valid stream index.\n";
1446 exit(status: 1);
1447 }
1448 Success = true;
1449 outs() << "Dumping contents of stream index " << Index << " to file "
1450 << OutFileName << ".\n";
1451 }
1452 }
1453
1454 if (!Success) {
1455 InfoStream &IS = cantFail(ValOrErr: File.getPDBInfoStream());
1456 Index = ExitOnErr(IS.getNamedStreamIndex(Name: opts::exportstream::Stream));
1457 outs() << "Dumping contents of stream '" << opts::exportstream::Stream
1458 << "' (index " << Index << ") to file " << OutFileName << ".\n";
1459 }
1460
1461 SourceStream = File.createIndexedStream(SN: Index);
1462 auto OutFile = ExitOnErr(
1463 FileOutputBuffer::create(FilePath: OutFileName, Size: SourceStream->getLength()));
1464 FileBufferByteStream DestStream(std::move(OutFile), llvm::endianness::little);
1465 BinaryStreamWriter Writer(DestStream);
1466 ExitOnErr(Writer.writeStreamRef(Ref: *SourceStream));
1467 ExitOnErr(DestStream.commit());
1468}
1469
1470static bool parseRange(StringRef Str,
1471 std::optional<opts::bytes::NumberRange> &Parsed) {
1472 if (Str.empty())
1473 return true;
1474
1475 llvm::Regex R("^([^-]+)(-([^-]+))?$");
1476 llvm::SmallVector<llvm::StringRef, 2> Matches;
1477 if (!R.match(String: Str, Matches: &Matches))
1478 return false;
1479
1480 Parsed.emplace();
1481 if (!to_integer(S: Matches[1], Num&: Parsed->Min))
1482 return false;
1483
1484 if (!Matches[3].empty()) {
1485 Parsed->Max.emplace();
1486 if (!to_integer(S: Matches[3], Num&: *Parsed->Max))
1487 return false;
1488 }
1489 return true;
1490}
1491
1492static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) {
1493 // If this list contains "All" plus some other stuff, remove the other stuff
1494 // and just keep "All" in the list.
1495 if (!llvm::is_contained(Range&: Chunks, Element: opts::ModuleSubsection::All))
1496 return;
1497 Chunks.reset();
1498 Chunks.push_back(value: opts::ModuleSubsection::All);
1499}
1500
1501int main(int Argc, const char **Argv) {
1502 InitLLVM X(Argc, Argv);
1503 ExitOnErr.setBanner("llvm-pdbutil: ");
1504
1505 cl::HideUnrelatedOptions(
1506 Categories: {&opts::TypeCategory, &opts::FilterCategory, &opts::OtherOptions});
1507 cl::ParseCommandLineOptions(argc: Argc, argv: Argv, Overview: "LLVM PDB Dumper\n");
1508
1509 if (opts::BytesSubcommand) {
1510 if (!parseRange(Str: opts::bytes::DumpBlockRangeOpt,
1511 Parsed&: opts::bytes::DumpBlockRange)) {
1512 errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
1513 << "' invalid format.\n";
1514 errs().flush();
1515 exit(status: 1);
1516 }
1517 if (!parseRange(Str: opts::bytes::DumpByteRangeOpt,
1518 Parsed&: opts::bytes::DumpByteRange)) {
1519 errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
1520 << "' invalid format.\n";
1521 errs().flush();
1522 exit(status: 1);
1523 }
1524 }
1525
1526 if (opts::DumpSubcommand) {
1527 if (opts::dump::RawAll) {
1528 opts::dump::DumpGlobals = true;
1529 opts::dump::DumpFpo = true;
1530 opts::dump::DumpInlineeLines = true;
1531 opts::dump::DumpIds = true;
1532 opts::dump::DumpIdExtras = true;
1533 opts::dump::DumpLines = true;
1534 opts::dump::DumpModules = true;
1535 opts::dump::DumpModuleFiles = true;
1536 opts::dump::DumpPublics = true;
1537 opts::dump::DumpSectionContribs = true;
1538 opts::dump::DumpSectionHeaders = true;
1539 opts::dump::DumpSectionMap = true;
1540 opts::dump::DumpStreams = true;
1541 opts::dump::DumpStreamBlocks = true;
1542 opts::dump::DumpStringTable = true;
1543 opts::dump::DumpStringTableDetails = true;
1544 opts::dump::DumpSummary = true;
1545 opts::dump::DumpSymbols = true;
1546 opts::dump::DumpSymbolStats = true;
1547 opts::dump::DumpTypes = true;
1548 opts::dump::DumpTypeExtras = true;
1549 opts::dump::DumpUdtStats = true;
1550 opts::dump::DumpXme = true;
1551 opts::dump::DumpXmi = true;
1552 }
1553 }
1554 if (opts::PdbToYamlSubcommand) {
1555 if (opts::pdb2yaml::All) {
1556 opts::pdb2yaml::StreamMetadata = true;
1557 opts::pdb2yaml::StreamDirectory = true;
1558 opts::pdb2yaml::PdbStream = true;
1559 opts::pdb2yaml::StringTable = true;
1560 opts::pdb2yaml::DbiStream = true;
1561 opts::pdb2yaml::TpiStream = true;
1562 opts::pdb2yaml::IpiStream = true;
1563 opts::pdb2yaml::PublicsStream = true;
1564 opts::pdb2yaml::DumpModules = true;
1565 opts::pdb2yaml::DumpModuleFiles = true;
1566 opts::pdb2yaml::DumpModuleSyms = true;
1567 opts::pdb2yaml::DumpSectionHeaders = true;
1568 opts::pdb2yaml::DumpModuleSubsections.push_back(
1569 value: opts::ModuleSubsection::All);
1570 }
1571 simplifyChunkList(Chunks&: opts::pdb2yaml::DumpModuleSubsections);
1572
1573 if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
1574 opts::pdb2yaml::DumpModules = true;
1575
1576 if (opts::pdb2yaml::DumpModules)
1577 opts::pdb2yaml::DbiStream = true;
1578
1579 if (opts::pdb2yaml::DumpSectionHeaders)
1580 opts::pdb2yaml::DbiStream = true;
1581 }
1582
1583 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
1584
1585 // Initialize the filters for LinePrinter.
1586 auto propagate = [&](auto &Target, auto &Reference) {
1587 llvm::append_range(Target, Reference);
1588 };
1589
1590 propagate(opts::Filters.ExcludeTypes, opts::pretty::ExcludeTypes);
1591 propagate(opts::Filters.ExcludeTypes, opts::pretty::ExcludeTypes);
1592 propagate(opts::Filters.ExcludeSymbols, opts::pretty::ExcludeSymbols);
1593 propagate(opts::Filters.ExcludeCompilands, opts::pretty::ExcludeCompilands);
1594 propagate(opts::Filters.IncludeTypes, opts::pretty::IncludeTypes);
1595 propagate(opts::Filters.IncludeSymbols, opts::pretty::IncludeSymbols);
1596 propagate(opts::Filters.IncludeCompilands, opts::pretty::IncludeCompilands);
1597 opts::Filters.PaddingThreshold = opts::pretty::PaddingThreshold;
1598 opts::Filters.SizeThreshold = opts::pretty::SizeThreshold;
1599 opts::Filters.JustMyCode = opts::dump::JustMyCode;
1600 if (opts::dump::DumpModi.getNumOccurrences() > 0) {
1601 if (opts::dump::DumpModi.getNumOccurrences() != 1) {
1602 errs() << "argument '-modi' specified more than once.\n";
1603 errs().flush();
1604 exit(status: 1);
1605 }
1606 opts::Filters.DumpModi = opts::dump::DumpModi;
1607 }
1608 if (opts::dump::DumpSymbolOffset) {
1609 if (opts::dump::DumpModi.getNumOccurrences() != 1) {
1610 errs()
1611 << "need to specify argument '-modi' when using '-symbol-offset'.\n";
1612 errs().flush();
1613 exit(status: 1);
1614 }
1615 opts::Filters.SymbolOffset = opts::dump::DumpSymbolOffset;
1616 if (opts::dump::DumpParents)
1617 opts::Filters.ParentRecurseDepth = opts::dump::DumpParentDepth;
1618 if (opts::dump::DumpChildren)
1619 opts::Filters.ChildrenRecurseDepth = opts::dump::DumpChildrenDepth;
1620 }
1621
1622 if (opts::PdbToYamlSubcommand) {
1623 pdb2Yaml(Path: opts::pdb2yaml::InputFilename.front());
1624 } else if (opts::YamlToPdbSubcommand) {
1625 if (opts::yaml2pdb::YamlPdbOutputFile.empty()) {
1626 SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue());
1627 sys::path::replace_extension(path&: OutputFilename, extension: ".pdb");
1628 opts::yaml2pdb::YamlPdbOutputFile = std::string(OutputFilename);
1629 }
1630 yamlToPdb(Path: opts::yaml2pdb::InputFilename);
1631 } else if (opts::DiaDumpSubcommand) {
1632 llvm::for_each(Range&: opts::diadump::InputFilenames, F: dumpDia);
1633 } else if (opts::PrettySubcommand) {
1634 if (opts::pretty::Lines)
1635 opts::pretty::Compilands = true;
1636
1637 if (opts::pretty::All) {
1638 opts::pretty::Compilands = true;
1639 opts::pretty::Symbols = true;
1640 opts::pretty::Globals = true;
1641 opts::pretty::Types = true;
1642 opts::pretty::Externals = true;
1643 opts::pretty::Lines = true;
1644 }
1645
1646 if (opts::pretty::Types) {
1647 opts::pretty::Classes = true;
1648 opts::pretty::Typedefs = true;
1649 opts::pretty::Enums = true;
1650 opts::pretty::Pointers = true;
1651 opts::pretty::Funcsigs = true;
1652 }
1653
1654 // When adding filters for excluded compilands and types, we need to
1655 // remember that these are regexes. So special characters such as * and \
1656 // need to be escaped in the regex. In the case of a literal \, this means
1657 // it needs to be escaped again in the C++. So matching a single \ in the
1658 // input requires 4 \es in the C++.
1659 if (opts::pretty::ExcludeCompilerGenerated) {
1660 opts::Filters.ExcludeTypes.push_back(x: "__vc_attributes");
1661 opts::Filters.ExcludeCompilands.push_back(x: "\\* Linker \\*");
1662 }
1663 if (opts::pretty::ExcludeSystemLibraries) {
1664 opts::Filters.ExcludeCompilands.push_back(
1665 x: "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld");
1666 opts::Filters.ExcludeCompilands.push_back(x: "f:\\\\dd\\\\vctools\\\\crt");
1667 opts::Filters.ExcludeCompilands.push_back(
1668 x: "d:\\\\th.obj.x86fre\\\\minkernel");
1669 }
1670 llvm::for_each(Range&: opts::pretty::InputFilenames, F: dumpPretty);
1671 } else if (opts::DumpSubcommand) {
1672 llvm::for_each(Range&: opts::dump::InputFilenames, F: dumpRaw);
1673 } else if (opts::BytesSubcommand) {
1674 llvm::for_each(Range&: opts::bytes::InputFilenames, F: dumpBytes);
1675 } else if (opts::MergeSubcommand) {
1676 if (opts::merge::InputFilenames.size() < 2) {
1677 errs() << "merge subcommand requires at least 2 input files.\n";
1678 exit(status: 1);
1679 }
1680 mergePdbs();
1681 } else if (opts::ExplainSubcommand) {
1682 explain();
1683 } else if (opts::ExportSubcommand) {
1684 exportStream();
1685 }
1686
1687 outs().flush();
1688 return 0;
1689}
1690