llvm-pdbutil.cpp revision 320041
171579Sdeischen//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===// 271579Sdeischen// 371579Sdeischen// The LLVM Compiler Infrastructure 471579Sdeischen// 571579Sdeischen// This file is distributed under the University of Illinois Open Source 671579Sdeischen// License. See LICENSE.TXT for details. 771579Sdeischen// 871579Sdeischen//===----------------------------------------------------------------------===// 971579Sdeischen// 1071579Sdeischen// Dumps debug information present in PDB files. 1171579Sdeischen// 1271579Sdeischen//===----------------------------------------------------------------------===// 1371579Sdeischen 1471579Sdeischen#include "llvm-pdbutil.h" 1571579Sdeischen 1671579Sdeischen#include "Analyze.h" 1771579Sdeischen#include "Diff.h" 1871579Sdeischen#include "LinePrinter.h" 1971579Sdeischen#include "OutputStyle.h" 2071579Sdeischen#include "PrettyCompilandDumper.h" 2171579Sdeischen#include "PrettyExternalSymbolDumper.h" 2271579Sdeischen#include "PrettyFunctionDumper.h" 2371579Sdeischen#include "PrettyTypeDumper.h" 2471579Sdeischen#include "PrettyVariableDumper.h" 2571579Sdeischen#include "RawOutputStyle.h" 2671579Sdeischen#include "YAMLOutputStyle.h" 2790039Sobrien 2890039Sobrien#include "llvm/ADT/ArrayRef.h" 2990039Sobrien#include "llvm/ADT/BitVector.h" 3075368Sdeischen#include "llvm/ADT/DenseMap.h" 3171579Sdeischen#include "llvm/ADT/STLExtras.h" 32205997Sdelphij#include "llvm/ADT/StringExtras.h" 33205997Sdelphij#include "llvm/Config/config.h" 3475368Sdeischen#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 35218824Snwhitehorn#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" 36209876Snwhitehorn#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 3775368Sdeischen#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 3871579Sdeischen#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h" 3971579Sdeischen#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" 4071579Sdeischen#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" 4171579Sdeischen#include "llvm/DebugInfo/MSF/MSFBuilder.h" 4271579Sdeischen#include "llvm/DebugInfo/PDB/GenericError.h" 4371579Sdeischen#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" 4471579Sdeischen#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" 45#include "llvm/DebugInfo/PDB/IPDBSession.h" 46#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" 47#include "llvm/DebugInfo/PDB/Native/DbiStream.h" 48#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" 49#include "llvm/DebugInfo/PDB/Native/InfoStream.h" 50#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 51#include "llvm/DebugInfo/PDB/Native/NativeSession.h" 52#include "llvm/DebugInfo/PDB/Native/PDBFile.h" 53#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" 54#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" 55#include "llvm/DebugInfo/PDB/Native/RawConstants.h" 56#include "llvm/DebugInfo/PDB/Native/RawError.h" 57#include "llvm/DebugInfo/PDB/Native/TpiStream.h" 58#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 59#include "llvm/DebugInfo/PDB/PDB.h" 60#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" 61#include "llvm/DebugInfo/PDB/PDBSymbolData.h" 62#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 63#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" 64#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" 65#include "llvm/Support/BinaryByteStream.h" 66#include "llvm/Support/COM.h" 67#include "llvm/Support/CommandLine.h" 68#include "llvm/Support/ConvertUTF.h" 69#include "llvm/Support/FileOutputBuffer.h" 70#include "llvm/Support/FileSystem.h" 71#include "llvm/Support/Format.h" 72#include "llvm/Support/ManagedStatic.h" 73#include "llvm/Support/MemoryBuffer.h" 74#include "llvm/Support/Path.h" 75#include "llvm/Support/PrettyStackTrace.h" 76#include "llvm/Support/Process.h" 77#include "llvm/Support/Regex.h" 78#include "llvm/Support/ScopedPrinter.h" 79#include "llvm/Support/Signals.h" 80#include "llvm/Support/raw_ostream.h" 81 82using namespace llvm; 83using namespace llvm::codeview; 84using namespace llvm::msf; 85using namespace llvm::pdb; 86 87namespace opts { 88 89cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); 90cl::SubCommand 91 PrettySubcommand("pretty", 92 "Dump semantic information about types and symbols"); 93 94cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files"); 95 96cl::SubCommand 97 YamlToPdbSubcommand("yaml2pdb", 98 "Generate a PDB file from a YAML description"); 99cl::SubCommand 100 PdbToYamlSubcommand("pdb2yaml", 101 "Generate a detailed YAML description of a PDB File"); 102 103cl::SubCommand 104 AnalyzeSubcommand("analyze", 105 "Analyze various aspects of a PDB's structure"); 106 107cl::SubCommand MergeSubcommand("merge", 108 "Merge multiple PDBs into a single PDB"); 109 110cl::OptionCategory TypeCategory("Symbol Type Options"); 111cl::OptionCategory FilterCategory("Filtering and Sorting Options"); 112cl::OptionCategory OtherOptions("Other Options"); 113 114namespace pretty { 115cl::list<std::string> InputFilenames(cl::Positional, 116 cl::desc("<input PDB files>"), 117 cl::OneOrMore, cl::sub(PrettySubcommand)); 118 119cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"), 120 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 121cl::opt<bool> Symbols("module-syms", 122 cl::desc("Display symbols for each compiland"), 123 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 124cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"), 125 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 126cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"), 127 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 128cl::list<SymLevel> SymTypes( 129 "sym-types", cl::desc("Type of symbols to dump (default all)"), 130 cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore, 131 cl::values( 132 clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"), 133 clEnumValN(SymLevel::Data, "data", "Display data symbols"), 134 clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"), 135 clEnumValN(SymLevel::All, "all", "Display all symbols (default)"))); 136 137cl::opt<bool> 138 Types("types", 139 cl::desc("Display all types (implies -classes, -enums, -typedefs)"), 140 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 141cl::opt<bool> Classes("classes", cl::desc("Display class types"), 142 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 143cl::opt<bool> Enums("enums", cl::desc("Display enum types"), 144 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 145cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"), 146 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 147cl::opt<SymbolSortMode> SymbolOrder( 148 "symbol-order", cl::desc("symbol sort order"), 149 cl::init(SymbolSortMode::None), 150 cl::values(clEnumValN(SymbolSortMode::None, "none", 151 "Undefined / no particular sort order"), 152 clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"), 153 clEnumValN(SymbolSortMode::Size, "size", 154 "Sort symbols by size")), 155 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 156 157cl::opt<ClassSortMode> ClassOrder( 158 "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), 159 cl::values( 160 clEnumValN(ClassSortMode::None, "none", 161 "Undefined / no particular sort order"), 162 clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"), 163 clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"), 164 clEnumValN(ClassSortMode::Padding, "padding", 165 "Sort classes by amount of padding"), 166 clEnumValN(ClassSortMode::PaddingPct, "padding-pct", 167 "Sort classes by percentage of space consumed by padding"), 168 clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm", 169 "Sort classes by amount of immediate padding"), 170 clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm", 171 "Sort classes by percentage of space consumed by immediate " 172 "padding")), 173 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 174 175cl::opt<ClassDefinitionFormat> ClassFormat( 176 "class-definitions", cl::desc("Class definition format"), 177 cl::init(ClassDefinitionFormat::All), 178 cl::values( 179 clEnumValN(ClassDefinitionFormat::All, "all", 180 "Display all class members including data, constants, " 181 "typedefs, functions, etc"), 182 clEnumValN(ClassDefinitionFormat::Layout, "layout", 183 "Only display members that contribute to class size."), 184 clEnumValN(ClassDefinitionFormat::None, "none", 185 "Don't display class definitions")), 186 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 187cl::opt<uint32_t> ClassRecursionDepth( 188 "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"), 189 cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 190 191cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), 192 cl::sub(PrettySubcommand)); 193cl::opt<bool> 194 All("all", cl::desc("Implies all other options in 'Symbol Types' category"), 195 cl::cat(TypeCategory), cl::sub(PrettySubcommand)); 196 197cl::opt<uint64_t> LoadAddress( 198 "load-address", 199 cl::desc("Assume the module is loaded at the specified address"), 200 cl::cat(OtherOptions), cl::sub(PrettySubcommand)); 201cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"), 202 cl::cat(OtherOptions), cl::sub(PrettySubcommand)); 203cl::opt<cl::boolOrDefault> 204 ColorOutput("color-output", 205 cl::desc("Override use of color (default = isatty)"), 206 cl::cat(OtherOptions), cl::sub(PrettySubcommand)); 207cl::list<std::string> ExcludeTypes( 208 "exclude-types", cl::desc("Exclude types by regular expression"), 209 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 210cl::list<std::string> ExcludeSymbols( 211 "exclude-symbols", cl::desc("Exclude symbols by regular expression"), 212 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 213cl::list<std::string> ExcludeCompilands( 214 "exclude-compilands", cl::desc("Exclude compilands by regular expression"), 215 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 216 217cl::list<std::string> IncludeTypes( 218 "include-types", 219 cl::desc("Include only types which match a regular expression"), 220 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 221cl::list<std::string> IncludeSymbols( 222 "include-symbols", 223 cl::desc("Include only symbols which match a regular expression"), 224 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 225cl::list<std::string> IncludeCompilands( 226 "include-compilands", 227 cl::desc("Include only compilands those which match a regular expression"), 228 cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 229cl::opt<uint32_t> SizeThreshold( 230 "min-type-size", cl::desc("Displays only those types which are greater " 231 "than or equal to the specified size."), 232 cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 233cl::opt<uint32_t> PaddingThreshold( 234 "min-class-padding", cl::desc("Displays only those classes which have at " 235 "least the specified amount of padding."), 236 cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 237cl::opt<uint32_t> ImmediatePaddingThreshold( 238 "min-class-padding-imm", 239 cl::desc("Displays only those classes which have at least the specified " 240 "amount of immediate padding, ignoring padding internal to bases " 241 "and aggregates."), 242 cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 243 244cl::opt<bool> ExcludeCompilerGenerated( 245 "no-compiler-generated", 246 cl::desc("Don't show compiler generated types and symbols"), 247 cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 248cl::opt<bool> 249 ExcludeSystemLibraries("no-system-libs", 250 cl::desc("Don't show symbols from system libraries"), 251 cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 252 253cl::opt<bool> NoEnumDefs("no-enum-definitions", 254 cl::desc("Don't display full enum definitions"), 255 cl::cat(FilterCategory), cl::sub(PrettySubcommand)); 256} 257 258namespace diff { 259cl::opt<bool> Pedantic("pedantic", 260 cl::desc("Finds all differences (even structural ones " 261 "that produce otherwise identical PDBs)"), 262 cl::sub(DiffSubcommand)); 263 264cl::list<std::string> InputFilenames(cl::Positional, 265 cl::desc("<first> <second>"), 266 cl::OneOrMore, cl::sub(DiffSubcommand)); 267} 268 269cl::OptionCategory FileOptions("Module & File Options"); 270 271namespace raw { 272 273cl::OptionCategory MsfOptions("MSF Container Options"); 274cl::OptionCategory TypeOptions("Type Record Options"); 275cl::OptionCategory SymbolOptions("Symbol Options"); 276cl::OptionCategory MiscOptions("Miscellaneous Options"); 277 278// MSF OPTIONS 279cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"), 280 cl::cat(MsfOptions), cl::sub(RawSubcommand)); 281cl::opt<bool> DumpStreams("streams", 282 cl::desc("dump summary of the PDB streams"), 283 cl::cat(MsfOptions), cl::sub(RawSubcommand)); 284cl::opt<std::string> 285 DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), 286 cl::desc("Dump binary data from specified range."), 287 cl::cat(MsfOptions), cl::sub(RawSubcommand)); 288llvm::Optional<BlockRange> DumpBlockRange; 289 290cl::list<std::string> 291 DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, 292 cl::desc("Dump binary data from specified streams. Format " 293 "is SN[:Start][@Size]"), 294 cl::cat(MsfOptions), cl::sub(RawSubcommand)); 295 296// TYPE OPTIONS 297cl::opt<bool> DumpTypes("types", 298 cl::desc("dump CodeView type records from TPI stream"), 299 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 300cl::opt<bool> DumpTypeData( 301 "type-data", 302 cl::desc("dump CodeView type record raw bytes from TPI stream"), 303 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 304 305cl::opt<bool> DumpTypeExtras("type-extras", 306 cl::desc("dump type hashes and index offsets"), 307 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 308 309cl::opt<bool> DumpIds("ids", 310 cl::desc("dump CodeView type records from IPI stream"), 311 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 312cl::opt<bool> 313 DumpIdData("id-data", 314 cl::desc("dump CodeView type record raw bytes from IPI stream"), 315 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 316 317cl::opt<bool> DumpIdExtras("id-extras", 318 cl::desc("dump id hashes and index offsets"), 319 cl::cat(TypeOptions), cl::sub(RawSubcommand)); 320 321// SYMBOL OPTIONS 322cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"), 323 cl::cat(SymbolOptions), cl::sub(RawSubcommand)); 324cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"), 325 cl::cat(SymbolOptions), cl::sub(RawSubcommand)); 326 327cl::opt<bool> 328 DumpSymRecordBytes("sym-data", 329 cl::desc("dump CodeView symbol record raw bytes"), 330 cl::cat(SymbolOptions), cl::sub(RawSubcommand)); 331 332// MODULE & FILE OPTIONS 333cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), 334 cl::cat(FileOptions), cl::sub(RawSubcommand)); 335cl::opt<bool> DumpModuleFiles( 336 "files", 337 cl::desc("Dump the source files that contribute to each module's."), 338 cl::cat(FileOptions), cl::sub(RawSubcommand)); 339cl::opt<bool> DumpLines( 340 "l", 341 cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"), 342 cl::cat(FileOptions), cl::sub(RawSubcommand)); 343cl::opt<bool> DumpInlineeLines( 344 "il", 345 cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"), 346 cl::cat(FileOptions), cl::sub(RawSubcommand)); 347cl::opt<bool> DumpXmi( 348 "xmi", 349 cl::desc( 350 "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), 351 cl::cat(FileOptions), cl::sub(RawSubcommand)); 352cl::opt<bool> DumpXme( 353 "xme", 354 cl::desc( 355 "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), 356 cl::cat(FileOptions), cl::sub(RawSubcommand)); 357 358// MISCELLANEOUS OPTIONS 359cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"), 360 cl::cat(MiscOptions), cl::sub(RawSubcommand)); 361 362cl::opt<bool> DumpSectionContribs("section-contribs", 363 cl::desc("dump section contributions"), 364 cl::cat(MiscOptions), cl::sub(RawSubcommand)); 365cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"), 366 cl::cat(MiscOptions), cl::sub(RawSubcommand)); 367 368cl::opt<bool> RawAll("all", cl::desc("Implies most other options."), 369 cl::cat(MiscOptions), cl::sub(RawSubcommand)); 370 371cl::list<std::string> InputFilenames(cl::Positional, 372 cl::desc("<input PDB files>"), 373 cl::OneOrMore, cl::sub(RawSubcommand)); 374} 375 376namespace yaml2pdb { 377cl::opt<std::string> 378 YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), 379 cl::sub(YamlToPdbSubcommand)); 380 381cl::opt<std::string> InputFilename(cl::Positional, 382 cl::desc("<input YAML file>"), cl::Required, 383 cl::sub(YamlToPdbSubcommand)); 384} 385 386namespace pdb2yaml { 387cl::opt<bool> All("all", 388 cl::desc("Dump everything we know how to dump."), 389 cl::sub(PdbToYamlSubcommand), cl::init(false)); 390cl::opt<bool> NoFileHeaders("no-file-headers", 391 cl::desc("Do not dump MSF file headers"), 392 cl::sub(PdbToYamlSubcommand), cl::init(false)); 393cl::opt<bool> Minimal("minimal", 394 cl::desc("Don't write fields with default values"), 395 cl::sub(PdbToYamlSubcommand), cl::init(false)); 396 397cl::opt<bool> StreamMetadata( 398 "stream-metadata", 399 cl::desc("Dump the number of streams and each stream's size"), 400 cl::sub(PdbToYamlSubcommand), cl::init(false)); 401cl::opt<bool> StreamDirectory( 402 "stream-directory", 403 cl::desc("Dump each stream's block map (implies -stream-metadata)"), 404 cl::sub(PdbToYamlSubcommand), cl::init(false)); 405cl::opt<bool> PdbStream("pdb-stream", 406 cl::desc("Dump the PDB Stream (Stream 1)"), 407 cl::sub(PdbToYamlSubcommand), cl::init(false)); 408 409cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"), 410 cl::sub(PdbToYamlSubcommand), cl::init(false)); 411 412cl::opt<bool> DbiStream("dbi-stream", 413 cl::desc("Dump the DBI Stream Headers (Stream 2)"), 414 cl::sub(PdbToYamlSubcommand), cl::init(false)); 415 416cl::opt<bool> TpiStream("tpi-stream", 417 cl::desc("Dump the TPI Stream (Stream 3)"), 418 cl::sub(PdbToYamlSubcommand), cl::init(false)); 419 420cl::opt<bool> IpiStream("ipi-stream", 421 cl::desc("Dump the IPI Stream (Stream 5)"), 422 cl::sub(PdbToYamlSubcommand), cl::init(false)); 423 424// MODULE & FILE OPTIONS 425cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), 426 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); 427cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"), 428 cl::cat(FileOptions), 429 cl::sub(PdbToYamlSubcommand)); 430cl::list<ModuleSubsection> DumpModuleSubsections( 431 "subsections", cl::ZeroOrMore, cl::CommaSeparated, 432 cl::desc("dump subsections from each module's debug stream"), 433 cl::values( 434 clEnumValN( 435 ModuleSubsection::CrossScopeExports, "cme", 436 "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), 437 clEnumValN( 438 ModuleSubsection::CrossScopeImports, "cmi", 439 "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), 440 clEnumValN(ModuleSubsection::FileChecksums, "fc", 441 "File checksums (DEBUG_S_CHECKSUMS subsection)"), 442 clEnumValN(ModuleSubsection::InlineeLines, "ilines", 443 "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), 444 clEnumValN(ModuleSubsection::Lines, "lines", 445 "Lines (DEBUG_S_LINES subsection)"), 446 clEnumValN(ModuleSubsection::StringTable, "strings", 447 "String Table (DEBUG_S_STRINGTABLE subsection) (not " 448 "typically present in PDB file)"), 449 clEnumValN(ModuleSubsection::FrameData, "frames", 450 "Frame Data (DEBUG_S_FRAMEDATA subsection)"), 451 clEnumValN(ModuleSubsection::Symbols, "symbols", 452 "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " 453 "present in PDB file)"), 454 clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas", 455 "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"), 456 clEnumValN(ModuleSubsection::Unknown, "unknown", 457 "Any subsection not covered by another option"), 458 clEnumValN(ModuleSubsection::All, "all", "All known subsections")), 459 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); 460cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"), 461 cl::cat(FileOptions), 462 cl::sub(PdbToYamlSubcommand)); 463 464cl::list<std::string> InputFilename(cl::Positional, 465 cl::desc("<input PDB file>"), cl::Required, 466 cl::sub(PdbToYamlSubcommand)); 467} // namespace pdb2yaml 468 469namespace analyze { 470cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"), 471 cl::sub(AnalyzeSubcommand), cl::init(false)); 472cl::list<std::string> InputFilename(cl::Positional, 473 cl::desc("<input PDB file>"), cl::Required, 474 cl::sub(AnalyzeSubcommand)); 475} 476 477namespace merge { 478cl::list<std::string> InputFilenames(cl::Positional, 479 cl::desc("<input PDB files>"), 480 cl::OneOrMore, cl::sub(MergeSubcommand)); 481cl::opt<std::string> 482 PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), 483 cl::sub(MergeSubcommand)); 484} 485} 486 487static ExitOnError ExitOnErr; 488 489static void yamlToPdb(StringRef Path) { 490 BumpPtrAllocator Allocator; 491 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = 492 MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, 493 /*RequiresNullTerminator=*/false); 494 495 if (ErrorOrBuffer.getError()) { 496 ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path)); 497 } 498 499 std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get(); 500 501 llvm::yaml::Input In(Buffer->getBuffer()); 502 pdb::yaml::PdbObject YamlObj(Allocator); 503 In >> YamlObj; 504 505 PDBFileBuilder Builder(Allocator); 506 507 uint32_t BlockSize = 4096; 508 if (YamlObj.Headers.hasValue()) 509 BlockSize = YamlObj.Headers->SuperBlock.BlockSize; 510 ExitOnErr(Builder.initialize(BlockSize)); 511 // Add each of the reserved streams. We ignore stream metadata in the 512 // yaml, because we will reconstruct our own view of the streams. For 513 // example, the YAML may say that there were 20 streams in the original 514 // PDB, but maybe we only dump a subset of those 20 streams, so we will 515 // have fewer, and the ones we do have may end up with different indices 516 // than the ones in the original PDB. So we just start with a clean slate. 517 for (uint32_t I = 0; I < kSpecialStreamCount; ++I) 518 ExitOnErr(Builder.getMsfBuilder().addStream(0)); 519 520 StringsAndChecksums Strings; 521 Strings.setStrings(std::make_shared<DebugStringTableSubsection>()); 522 523 if (YamlObj.StringTable.hasValue()) { 524 for (auto S : *YamlObj.StringTable) 525 Strings.strings()->insert(S); 526 } 527 528 pdb::yaml::PdbInfoStream DefaultInfoStream; 529 pdb::yaml::PdbDbiStream DefaultDbiStream; 530 pdb::yaml::PdbTpiStream DefaultTpiStream; 531 pdb::yaml::PdbTpiStream DefaultIpiStream; 532 533 const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); 534 535 auto &InfoBuilder = Builder.getInfoBuilder(); 536 InfoBuilder.setAge(Info.Age); 537 InfoBuilder.setGuid(Info.Guid); 538 InfoBuilder.setSignature(Info.Signature); 539 InfoBuilder.setVersion(Info.Version); 540 for (auto F : Info.Features) 541 InfoBuilder.addFeature(F); 542 543 const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); 544 auto &DbiBuilder = Builder.getDbiBuilder(); 545 DbiBuilder.setAge(Dbi.Age); 546 DbiBuilder.setBuildNumber(Dbi.BuildNumber); 547 DbiBuilder.setFlags(Dbi.Flags); 548 DbiBuilder.setMachineType(Dbi.MachineType); 549 DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); 550 DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); 551 DbiBuilder.setVersionHeader(Dbi.VerHeader); 552 for (const auto &MI : Dbi.ModInfos) { 553 auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); 554 ModiBuilder.setObjFileName(MI.Obj); 555 556 for (auto S : MI.SourceFiles) 557 ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); 558 if (MI.Modi.hasValue()) { 559 const auto &ModiStream = *MI.Modi; 560 for (auto Symbol : ModiStream.Symbols) { 561 ModiBuilder.addSymbol( 562 Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); 563 } 564 } 565 566 // Each module has its own checksum subsection, so scan for it every time. 567 Strings.setChecksums(nullptr); 568 CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings); 569 570 auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList( 571 Allocator, MI.Subsections, Strings)); 572 for (auto &SS : CodeViewSubsections) { 573 ModiBuilder.addDebugSubsection(SS); 574 } 575 } 576 577 auto &TpiBuilder = Builder.getTpiBuilder(); 578 const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); 579 TpiBuilder.setVersionHeader(Tpi.Version); 580 for (const auto &R : Tpi.Records) { 581 CVType Type = R.toCodeViewRecord(Allocator); 582 TpiBuilder.addTypeRecord(Type.RecordData, None); 583 } 584 585 const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); 586 auto &IpiBuilder = Builder.getIpiBuilder(); 587 IpiBuilder.setVersionHeader(Ipi.Version); 588 for (const auto &R : Ipi.Records) { 589 CVType Type = R.toCodeViewRecord(Allocator); 590 IpiBuilder.addTypeRecord(Type.RecordData, None); 591 } 592 593 Builder.getStringTableBuilder().setStrings(*Strings.strings()); 594 595 ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); 596} 597 598static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) { 599 ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session)); 600 601 NativeSession *NS = static_cast<NativeSession *>(Session.get()); 602 return NS->getPDBFile(); 603} 604 605static void pdb2Yaml(StringRef Path) { 606 std::unique_ptr<IPDBSession> Session; 607 auto &File = loadPDB(Path, Session); 608 609 auto O = llvm::make_unique<YAMLOutputStyle>(File); 610 O = llvm::make_unique<YAMLOutputStyle>(File); 611 612 ExitOnErr(O->dump()); 613} 614 615static void dumpRaw(StringRef Path) { 616 std::unique_ptr<IPDBSession> Session; 617 auto &File = loadPDB(Path, Session); 618 619 auto O = llvm::make_unique<RawOutputStyle>(File); 620 621 ExitOnErr(O->dump()); 622} 623 624static void dumpAnalysis(StringRef Path) { 625 std::unique_ptr<IPDBSession> Session; 626 auto &File = loadPDB(Path, Session); 627 auto O = llvm::make_unique<AnalysisStyle>(File); 628 629 ExitOnErr(O->dump()); 630} 631 632static void diff(StringRef Path1, StringRef Path2) { 633 std::unique_ptr<IPDBSession> Session1; 634 std::unique_ptr<IPDBSession> Session2; 635 636 auto &File1 = loadPDB(Path1, Session1); 637 auto &File2 = loadPDB(Path2, Session2); 638 639 auto O = llvm::make_unique<DiffStyle>(File1, File2); 640 641 ExitOnErr(O->dump()); 642} 643 644bool opts::pretty::shouldDumpSymLevel(SymLevel Search) { 645 if (SymTypes.empty()) 646 return true; 647 if (llvm::find(SymTypes, Search) != SymTypes.end()) 648 return true; 649 if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end()) 650 return true; 651 return false; 652} 653 654uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) { 655 auto SymbolType = Symbol.getType(); 656 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); 657 658 return RawType.getLength(); 659} 660 661bool opts::pretty::compareFunctionSymbols( 662 const std::unique_ptr<PDBSymbolFunc> &F1, 663 const std::unique_ptr<PDBSymbolFunc> &F2) { 664 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); 665 666 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) 667 return F1->getName() < F2->getName(); 668 669 // Note that we intentionally sort in descending order on length, since 670 // long functions are more interesting than short functions. 671 return F1->getLength() > F2->getLength(); 672} 673 674bool opts::pretty::compareDataSymbols( 675 const std::unique_ptr<PDBSymbolData> &F1, 676 const std::unique_ptr<PDBSymbolData> &F2) { 677 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); 678 679 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) 680 return F1->getName() < F2->getName(); 681 682 // Note that we intentionally sort in descending order on length, since 683 // large types are more interesting than short ones. 684 return getTypeLength(*F1) > getTypeLength(*F2); 685} 686 687static void dumpPretty(StringRef Path) { 688 std::unique_ptr<IPDBSession> Session; 689 690 const auto ReaderType = 691 opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; 692 ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); 693 694 if (opts::pretty::LoadAddress) 695 Session->setLoadAddress(opts::pretty::LoadAddress); 696 697 auto &Stream = outs(); 698 const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET 699 ? Stream.has_colors() 700 : opts::pretty::ColorOutput == cl::BOU_TRUE; 701 LinePrinter Printer(2, UseColor, Stream); 702 703 auto GlobalScope(Session->getGlobalScope()); 704 std::string FileName(GlobalScope->getSymbolsFileName()); 705 706 WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; 707 WithColor(Printer, PDB_ColorItem::Path).get() << FileName; 708 Printer.Indent(); 709 uint64_t FileSize = 0; 710 711 Printer.NewLine(); 712 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; 713 if (!sys::fs::file_size(FileName, FileSize)) { 714 Printer << ": " << FileSize << " bytes"; 715 } else { 716 Printer << ": (Unable to obtain file size)"; 717 } 718 719 Printer.NewLine(); 720 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; 721 Printer << ": " << GlobalScope->getGuid(); 722 723 Printer.NewLine(); 724 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; 725 Printer << ": " << GlobalScope->getAge(); 726 727 Printer.NewLine(); 728 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; 729 Printer << ": "; 730 if (GlobalScope->hasCTypes()) 731 outs() << "HasCTypes "; 732 if (GlobalScope->hasPrivateSymbols()) 733 outs() << "HasPrivateSymbols "; 734 Printer.Unindent(); 735 736 if (opts::pretty::Compilands) { 737 Printer.NewLine(); 738 WithColor(Printer, PDB_ColorItem::SectionHeader).get() 739 << "---COMPILANDS---"; 740 Printer.Indent(); 741 auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); 742 CompilandDumper Dumper(Printer); 743 CompilandDumpFlags options = CompilandDumper::Flags::None; 744 if (opts::pretty::Lines) 745 options = options | CompilandDumper::Flags::Lines; 746 while (auto Compiland = Compilands->getNext()) 747 Dumper.start(*Compiland, options); 748 Printer.Unindent(); 749 } 750 751 if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) { 752 Printer.NewLine(); 753 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; 754 Printer.Indent(); 755 TypeDumper Dumper(Printer); 756 Dumper.start(*GlobalScope); 757 Printer.Unindent(); 758 } 759 760 if (opts::pretty::Symbols) { 761 Printer.NewLine(); 762 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; 763 Printer.Indent(); 764 auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); 765 CompilandDumper Dumper(Printer); 766 while (auto Compiland = Compilands->getNext()) 767 Dumper.start(*Compiland, true); 768 Printer.Unindent(); 769 } 770 771 if (opts::pretty::Globals) { 772 Printer.NewLine(); 773 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; 774 Printer.Indent(); 775 if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { 776 FunctionDumper Dumper(Printer); 777 auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>(); 778 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { 779 while (auto Function = Functions->getNext()) { 780 Printer.NewLine(); 781 Dumper.start(*Function, FunctionDumper::PointerType::None); 782 } 783 } else { 784 std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs; 785 while (auto Func = Functions->getNext()) 786 Funcs.push_back(std::move(Func)); 787 std::sort(Funcs.begin(), Funcs.end(), 788 opts::pretty::compareFunctionSymbols); 789 for (const auto &Func : Funcs) { 790 Printer.NewLine(); 791 Dumper.start(*Func, FunctionDumper::PointerType::None); 792 } 793 } 794 } 795 if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { 796 auto Vars = GlobalScope->findAllChildren<PDBSymbolData>(); 797 VariableDumper Dumper(Printer); 798 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { 799 while (auto Var = Vars->getNext()) 800 Dumper.start(*Var); 801 } else { 802 std::vector<std::unique_ptr<PDBSymbolData>> Datas; 803 while (auto Var = Vars->getNext()) 804 Datas.push_back(std::move(Var)); 805 std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols); 806 for (const auto &Var : Datas) 807 Dumper.start(*Var); 808 } 809 } 810 if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { 811 auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>(); 812 CompilandDumper Dumper(Printer); 813 while (auto Thunk = Thunks->getNext()) 814 Dumper.dump(*Thunk); 815 } 816 Printer.Unindent(); 817 } 818 if (opts::pretty::Externals) { 819 Printer.NewLine(); 820 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; 821 Printer.Indent(); 822 ExternalSymbolDumper Dumper(Printer); 823 Dumper.start(*GlobalScope); 824 } 825 if (opts::pretty::Lines) { 826 Printer.NewLine(); 827 } 828 outs().flush(); 829} 830 831static void mergePdbs() { 832 BumpPtrAllocator Allocator; 833 TypeTableBuilder MergedTpi(Allocator); 834 TypeTableBuilder MergedIpi(Allocator); 835 836 // Create a Tpi and Ipi type table with all types from all input files. 837 for (const auto &Path : opts::merge::InputFilenames) { 838 std::unique_ptr<IPDBSession> Session; 839 auto &File = loadPDB(Path, Session); 840 SmallVector<TypeIndex, 128> TypeMap; 841 SmallVector<TypeIndex, 128> IdMap; 842 if (File.hasPDBTpiStream()) { 843 auto &Tpi = ExitOnErr(File.getPDBTpiStream()); 844 ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr, 845 Tpi.typeArray())); 846 } 847 if (File.hasPDBIpiStream()) { 848 auto &Ipi = ExitOnErr(File.getPDBIpiStream()); 849 ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, 850 Ipi.typeArray())); 851 } 852 } 853 854 // Then write the PDB. 855 PDBFileBuilder Builder(Allocator); 856 ExitOnErr(Builder.initialize(4096)); 857 // Add each of the reserved streams. We might not put any data in them, 858 // but at least they have to be present. 859 for (uint32_t I = 0; I < kSpecialStreamCount; ++I) 860 ExitOnErr(Builder.getMsfBuilder().addStream(0)); 861 862 auto &DestTpi = Builder.getTpiBuilder(); 863 auto &DestIpi = Builder.getIpiBuilder(); 864 MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef<uint8_t> Data) { 865 DestTpi.addTypeRecord(Data, None); 866 }); 867 MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef<uint8_t> Data) { 868 DestIpi.addTypeRecord(Data, None); 869 }); 870 Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140); 871 872 SmallString<64> OutFile(opts::merge::PdbOutputFile); 873 if (OutFile.empty()) { 874 OutFile = opts::merge::InputFilenames[0]; 875 llvm::sys::path::replace_extension(OutFile, "merged.pdb"); 876 } 877 ExitOnErr(Builder.commit(OutFile)); 878} 879 880int main(int argc_, const char *argv_[]) { 881 // Print a stack trace if we signal out. 882 sys::PrintStackTraceOnErrorSignal(argv_[0]); 883 PrettyStackTraceProgram X(argc_, argv_); 884 885 ExitOnErr.setBanner("llvm-pdbutil: "); 886 887 SmallVector<const char *, 256> argv; 888 SpecificBumpPtrAllocator<char> ArgAllocator; 889 ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( 890 argv, makeArrayRef(argv_, argc_), ArgAllocator))); 891 892 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 893 894 cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); 895 if (!opts::raw::DumpBlockRangeOpt.empty()) { 896 llvm::Regex R("^([0-9]+)(-([0-9]+))?$"); 897 llvm::SmallVector<llvm::StringRef, 2> Matches; 898 if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) { 899 errs() << "Argument '" << opts::raw::DumpBlockRangeOpt 900 << "' invalid format.\n"; 901 errs().flush(); 902 exit(1); 903 } 904 opts::raw::DumpBlockRange.emplace(); 905 Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min); 906 if (!Matches[3].empty()) { 907 opts::raw::DumpBlockRange->Max.emplace(); 908 Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max); 909 } 910 } 911 912 if (opts::RawSubcommand) { 913 if (opts::raw::RawAll) { 914 opts::raw::DumpLines = true; 915 opts::raw::DumpInlineeLines = true; 916 opts::raw::DumpXme = true; 917 opts::raw::DumpXmi = true; 918 opts::raw::DumpIds = true; 919 opts::raw::DumpPublics = true; 920 opts::raw::DumpSectionContribs = true; 921 opts::raw::DumpSectionMap = true; 922 opts::raw::DumpStreams = true; 923 opts::raw::DumpStringTable = true; 924 opts::raw::DumpSummary = true; 925 opts::raw::DumpSymbols = true; 926 opts::raw::DumpIds = true; 927 opts::raw::DumpIdExtras = true; 928 opts::raw::DumpTypes = true; 929 opts::raw::DumpTypeExtras = true; 930 opts::raw::DumpModules = true; 931 opts::raw::DumpModuleFiles = true; 932 } 933 } 934 if (opts::PdbToYamlSubcommand) { 935 if (opts::pdb2yaml::All) { 936 opts::pdb2yaml::StreamMetadata = true; 937 opts::pdb2yaml::StreamDirectory = true; 938 opts::pdb2yaml::PdbStream = true; 939 opts::pdb2yaml::StringTable = true; 940 opts::pdb2yaml::DbiStream = true; 941 opts::pdb2yaml::TpiStream = true; 942 opts::pdb2yaml::IpiStream = true; 943 opts::pdb2yaml::DumpModules = true; 944 opts::pdb2yaml::DumpModuleFiles = true; 945 opts::pdb2yaml::DumpModuleSyms = true; 946 opts::pdb2yaml::DumpModuleSubsections.push_back( 947 opts::ModuleSubsection::All); 948 if (llvm::is_contained(opts::pdb2yaml::DumpModuleSubsections, 949 opts::ModuleSubsection::All)) { 950 opts::pdb2yaml::DumpModuleSubsections.reset(); 951 opts::pdb2yaml::DumpModuleSubsections.push_back( 952 opts::ModuleSubsection::All); 953 } 954 } 955 956 if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles) 957 opts::pdb2yaml::DumpModules = true; 958 959 if (opts::pdb2yaml::DumpModules) 960 opts::pdb2yaml::DbiStream = true; 961 } 962 963 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); 964 965 if (opts::PdbToYamlSubcommand) { 966 pdb2Yaml(opts::pdb2yaml::InputFilename.front()); 967 } else if (opts::YamlToPdbSubcommand) { 968 if (opts::yaml2pdb::YamlPdbOutputFile.empty()) { 969 SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue()); 970 sys::path::replace_extension(OutputFilename, ".pdb"); 971 opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str(); 972 } 973 yamlToPdb(opts::yaml2pdb::InputFilename); 974 } else if (opts::AnalyzeSubcommand) { 975 dumpAnalysis(opts::analyze::InputFilename.front()); 976 } else if (opts::PrettySubcommand) { 977 if (opts::pretty::Lines) 978 opts::pretty::Compilands = true; 979 980 if (opts::pretty::All) { 981 opts::pretty::Compilands = true; 982 opts::pretty::Symbols = true; 983 opts::pretty::Globals = true; 984 opts::pretty::Types = true; 985 opts::pretty::Externals = true; 986 opts::pretty::Lines = true; 987 } 988 989 if (opts::pretty::Types) { 990 opts::pretty::Classes = true; 991 opts::pretty::Typedefs = true; 992 opts::pretty::Enums = true; 993 } 994 995 // When adding filters for excluded compilands and types, we need to 996 // remember that these are regexes. So special characters such as * and \ 997 // need to be escaped in the regex. In the case of a literal \, this means 998 // it needs to be escaped again in the C++. So matching a single \ in the 999 // input requires 4 \es in the C++. 1000 if (opts::pretty::ExcludeCompilerGenerated) { 1001 opts::pretty::ExcludeTypes.push_back("__vc_attributes"); 1002 opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); 1003 } 1004 if (opts::pretty::ExcludeSystemLibraries) { 1005 opts::pretty::ExcludeCompilands.push_back( 1006 "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); 1007 opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); 1008 opts::pretty::ExcludeCompilands.push_back( 1009 "d:\\\\th.obj.x86fre\\\\minkernel"); 1010 } 1011 std::for_each(opts::pretty::InputFilenames.begin(), 1012 opts::pretty::InputFilenames.end(), dumpPretty); 1013 } else if (opts::RawSubcommand) { 1014 std::for_each(opts::raw::InputFilenames.begin(), 1015 opts::raw::InputFilenames.end(), dumpRaw); 1016 } else if (opts::DiffSubcommand) { 1017 if (opts::diff::InputFilenames.size() != 2) { 1018 errs() << "diff subcommand expects exactly 2 arguments.\n"; 1019 exit(1); 1020 } 1021 diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]); 1022 } else if (opts::MergeSubcommand) { 1023 if (opts::merge::InputFilenames.size() < 2) { 1024 errs() << "merge subcommand requires at least 2 input files.\n"; 1025 exit(1); 1026 } 1027 mergePdbs(); 1028 } 1029 1030 outs().flush(); 1031 return 0; 1032} 1033