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