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