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