llvm-pdbutil.cpp revision 321238
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::opt<bool> PrintValueColumns( 288 "values", cl::init(true), 289 cl::desc("Print one column for each PDB with the field value"), 290 cl::Optional, cl::sub(DiffSubcommand)); 291cl::opt<bool> 292 PrintResultColumn("result", cl::init(false), 293 cl::desc("Print a column with the result status"), 294 cl::Optional, cl::sub(DiffSubcommand)); 295 296cl::opt<std::string> LeftRoot( 297 "left-bin-root", cl::Optional, 298 cl::desc("Treats the specified path as the root of the tree containing " 299 "binaries referenced by the left PDB. The root is stripped from " 300 "embedded paths when doing equality comparisons."), 301 cl::sub(DiffSubcommand)); 302cl::opt<std::string> RightRoot( 303 "right-bin-root", cl::Optional, 304 cl::desc("Treats the specified path as the root of the tree containing " 305 "binaries referenced by the right PDB. The root is stripped from " 306 "embedded paths when doing equality comparisons"), 307 cl::sub(DiffSubcommand)); 308 309cl::opt<std::string> Left(cl::Positional, cl::desc("<left>"), 310 cl::sub(DiffSubcommand)); 311cl::opt<std::string> Right(cl::Positional, cl::desc("<right>"), 312 cl::sub(DiffSubcommand)); 313} 314 315cl::OptionCategory FileOptions("Module & File Options"); 316 317namespace bytes { 318cl::OptionCategory MsfBytes("MSF File Options"); 319cl::OptionCategory DbiBytes("Dbi Stream Options"); 320cl::OptionCategory PdbBytes("PDB Stream Options"); 321cl::OptionCategory Types("Type Options"); 322cl::OptionCategory ModuleCategory("Module Options"); 323 324llvm::Optional<NumberRange> DumpBlockRange; 325llvm::Optional<NumberRange> DumpByteRange; 326 327cl::opt<std::string> DumpBlockRangeOpt( 328 "block-range", cl::value_desc("start[-end]"), 329 cl::desc("Dump binary data from specified range of blocks."), 330 cl::sub(BytesSubcommand), cl::cat(MsfBytes)); 331 332cl::opt<std::string> 333 DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"), 334 cl::desc("Dump binary data from specified range of bytes"), 335 cl::sub(BytesSubcommand), cl::cat(MsfBytes)); 336 337cl::list<std::string> 338 DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, 339 cl::desc("Dump binary data from specified streams. Format " 340 "is SN[:Start][@Size]"), 341 cl::sub(BytesSubcommand), cl::cat(MsfBytes)); 342 343cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"), 344 cl::sub(BytesSubcommand), cl::cat(PdbBytes)); 345 346cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"), 347 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 348cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"), 349 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 350cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"), 351 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 352cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"), 353 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 354cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"), 355 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 356cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"), 357 cl::sub(BytesSubcommand), cl::cat(DbiBytes)); 358 359cl::list<uint32_t> 360 TypeIndex("type", 361 cl::desc("Dump the type record with the given type index"), 362 cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), 363 cl::cat(TypeCategory)); 364cl::list<uint32_t> 365 IdIndex("id", cl::desc("Dump the id record with the given type index"), 366 cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), 367 cl::cat(TypeCategory)); 368 369cl::opt<uint32_t> ModuleIndex( 370 "mod", 371 cl::desc( 372 "Limit options in the Modules category to the specified module index"), 373 cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); 374cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"), 375 cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); 376cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden, 377 cl::desc("Dump C11 CodeView debug chunks"), 378 cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); 379cl::opt<bool> ModuleC13("chunks", 380 cl::desc("Dump C13 CodeView debug chunk subsection"), 381 cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); 382cl::opt<bool> SplitChunks( 383 "split-chunks", 384 cl::desc( 385 "When dumping debug chunks, show a different section for each chunk"), 386 cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); 387cl::list<std::string> InputFilenames(cl::Positional, 388 cl::desc("<input PDB files>"), 389 cl::OneOrMore, cl::sub(BytesSubcommand)); 390 391} // namespace bytes 392 393namespace dump { 394 395cl::OptionCategory MsfOptions("MSF Container Options"); 396cl::OptionCategory TypeOptions("Type Record Options"); 397cl::OptionCategory SymbolOptions("Symbol Options"); 398cl::OptionCategory MiscOptions("Miscellaneous Options"); 399 400// MSF OPTIONS 401cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"), 402 cl::cat(MsfOptions), cl::sub(DumpSubcommand)); 403cl::opt<bool> DumpStreams("streams", 404 cl::desc("dump summary of the PDB streams"), 405 cl::cat(MsfOptions), cl::sub(DumpSubcommand)); 406cl::opt<bool> DumpStreamBlocks( 407 "stream-blocks", 408 cl::desc("Add block information to the output of -streams"), 409 cl::cat(MsfOptions), cl::sub(DumpSubcommand)); 410 411// TYPE OPTIONS 412cl::opt<bool> DumpTypes("types", 413 cl::desc("dump CodeView type records from TPI stream"), 414 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 415cl::opt<bool> DumpTypeData( 416 "type-data", 417 cl::desc("dump CodeView type record raw bytes from TPI stream"), 418 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 419 420cl::opt<bool> DumpTypeExtras("type-extras", 421 cl::desc("dump type hashes and index offsets"), 422 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 423 424cl::list<uint32_t> DumpTypeIndex( 425 "type-index", cl::ZeroOrMore, cl::CommaSeparated, 426 cl::desc("only dump types with the specified hexadecimal type index"), 427 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 428 429cl::opt<bool> DumpIds("ids", 430 cl::desc("dump CodeView type records from IPI stream"), 431 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 432cl::opt<bool> 433 DumpIdData("id-data", 434 cl::desc("dump CodeView type record raw bytes from IPI stream"), 435 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 436 437cl::opt<bool> DumpIdExtras("id-extras", 438 cl::desc("dump id hashes and index offsets"), 439 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 440cl::list<uint32_t> DumpIdIndex( 441 "id-index", cl::ZeroOrMore, cl::CommaSeparated, 442 cl::desc("only dump ids with the specified hexadecimal type index"), 443 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 444 445cl::opt<bool> DumpTypeDependents( 446 "dependents", 447 cl::desc("In conjunection with -type-index and -id-index, dumps the entire " 448 "dependency graph for the specified index instead of " 449 "just the single record with the specified index"), 450 cl::cat(TypeOptions), cl::sub(DumpSubcommand)); 451 452// SYMBOL OPTIONS 453cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"), 454 cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); 455cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"), 456 cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); 457 458cl::opt<bool> 459 DumpSymRecordBytes("sym-data", 460 cl::desc("dump CodeView symbol record raw bytes"), 461 cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); 462 463// MODULE & FILE OPTIONS 464cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), 465 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 466cl::opt<bool> DumpModuleFiles( 467 "files", 468 cl::desc("Dump the source files that contribute to each module's."), 469 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 470cl::opt<bool> DumpLines( 471 "l", 472 cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"), 473 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 474cl::opt<bool> DumpInlineeLines( 475 "il", 476 cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"), 477 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 478cl::opt<bool> DumpXmi( 479 "xmi", 480 cl::desc( 481 "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), 482 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 483cl::opt<bool> DumpXme( 484 "xme", 485 cl::desc( 486 "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), 487 cl::cat(FileOptions), cl::sub(DumpSubcommand)); 488 489// MISCELLANEOUS OPTIONS 490cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"), 491 cl::cat(MiscOptions), cl::sub(DumpSubcommand)); 492 493cl::opt<bool> DumpSectionContribs("section-contribs", 494 cl::desc("dump section contributions"), 495 cl::cat(MiscOptions), 496 cl::sub(DumpSubcommand)); 497cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"), 498 cl::cat(MiscOptions), cl::sub(DumpSubcommand)); 499 500cl::opt<bool> RawAll("all", cl::desc("Implies most other options."), 501 cl::cat(MiscOptions), cl::sub(DumpSubcommand)); 502 503cl::list<std::string> InputFilenames(cl::Positional, 504 cl::desc("<input PDB files>"), 505 cl::OneOrMore, cl::sub(DumpSubcommand)); 506} 507 508namespace yaml2pdb { 509cl::opt<std::string> 510 YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), 511 cl::sub(YamlToPdbSubcommand)); 512 513cl::opt<std::string> InputFilename(cl::Positional, 514 cl::desc("<input YAML file>"), cl::Required, 515 cl::sub(YamlToPdbSubcommand)); 516} 517 518namespace pdb2yaml { 519cl::opt<bool> All("all", 520 cl::desc("Dump everything we know how to dump."), 521 cl::sub(PdbToYamlSubcommand), cl::init(false)); 522cl::opt<bool> NoFileHeaders("no-file-headers", 523 cl::desc("Do not dump MSF file headers"), 524 cl::sub(PdbToYamlSubcommand), cl::init(false)); 525cl::opt<bool> Minimal("minimal", 526 cl::desc("Don't write fields with default values"), 527 cl::sub(PdbToYamlSubcommand), cl::init(false)); 528 529cl::opt<bool> StreamMetadata( 530 "stream-metadata", 531 cl::desc("Dump the number of streams and each stream's size"), 532 cl::sub(PdbToYamlSubcommand), cl::init(false)); 533cl::opt<bool> StreamDirectory( 534 "stream-directory", 535 cl::desc("Dump each stream's block map (implies -stream-metadata)"), 536 cl::sub(PdbToYamlSubcommand), cl::init(false)); 537cl::opt<bool> PdbStream("pdb-stream", 538 cl::desc("Dump the PDB Stream (Stream 1)"), 539 cl::sub(PdbToYamlSubcommand), cl::init(false)); 540 541cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"), 542 cl::sub(PdbToYamlSubcommand), cl::init(false)); 543 544cl::opt<bool> DbiStream("dbi-stream", 545 cl::desc("Dump the DBI Stream Headers (Stream 2)"), 546 cl::sub(PdbToYamlSubcommand), cl::init(false)); 547 548cl::opt<bool> TpiStream("tpi-stream", 549 cl::desc("Dump the TPI Stream (Stream 3)"), 550 cl::sub(PdbToYamlSubcommand), cl::init(false)); 551 552cl::opt<bool> IpiStream("ipi-stream", 553 cl::desc("Dump the IPI Stream (Stream 5)"), 554 cl::sub(PdbToYamlSubcommand), cl::init(false)); 555 556// MODULE & FILE OPTIONS 557cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"), 558 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); 559cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"), 560 cl::cat(FileOptions), 561 cl::sub(PdbToYamlSubcommand)); 562cl::list<ModuleSubsection> DumpModuleSubsections( 563 "subsections", cl::ZeroOrMore, cl::CommaSeparated, 564 cl::desc("dump subsections from each module's debug stream"), ChunkValues, 565 cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); 566cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"), 567 cl::cat(FileOptions), 568 cl::sub(PdbToYamlSubcommand)); 569 570cl::list<std::string> InputFilename(cl::Positional, 571 cl::desc("<input PDB file>"), cl::Required, 572 cl::sub(PdbToYamlSubcommand)); 573} // namespace pdb2yaml 574 575namespace analyze { 576cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"), 577 cl::sub(AnalyzeSubcommand), cl::init(false)); 578cl::list<std::string> InputFilename(cl::Positional, 579 cl::desc("<input PDB file>"), cl::Required, 580 cl::sub(AnalyzeSubcommand)); 581} 582 583namespace merge { 584cl::list<std::string> InputFilenames(cl::Positional, 585 cl::desc("<input PDB files>"), 586 cl::OneOrMore, cl::sub(MergeSubcommand)); 587cl::opt<std::string> 588 PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), 589 cl::sub(MergeSubcommand)); 590} 591} 592 593static ExitOnError ExitOnErr; 594 595static void yamlToPdb(StringRef Path) { 596 BumpPtrAllocator Allocator; 597 ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer = 598 MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, 599 /*RequiresNullTerminator=*/false); 600 601 if (ErrorOrBuffer.getError()) { 602 ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path)); 603 } 604 605 std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get(); 606 607 llvm::yaml::Input In(Buffer->getBuffer()); 608 pdb::yaml::PdbObject YamlObj(Allocator); 609 In >> YamlObj; 610 611 PDBFileBuilder Builder(Allocator); 612 613 uint32_t BlockSize = 4096; 614 if (YamlObj.Headers.hasValue()) 615 BlockSize = YamlObj.Headers->SuperBlock.BlockSize; 616 ExitOnErr(Builder.initialize(BlockSize)); 617 // Add each of the reserved streams. We ignore stream metadata in the 618 // yaml, because we will reconstruct our own view of the streams. For 619 // example, the YAML may say that there were 20 streams in the original 620 // PDB, but maybe we only dump a subset of those 20 streams, so we will 621 // have fewer, and the ones we do have may end up with different indices 622 // than the ones in the original PDB. So we just start with a clean slate. 623 for (uint32_t I = 0; I < kSpecialStreamCount; ++I) 624 ExitOnErr(Builder.getMsfBuilder().addStream(0)); 625 626 StringsAndChecksums Strings; 627 Strings.setStrings(std::make_shared<DebugStringTableSubsection>()); 628 629 if (YamlObj.StringTable.hasValue()) { 630 for (auto S : *YamlObj.StringTable) 631 Strings.strings()->insert(S); 632 } 633 634 pdb::yaml::PdbInfoStream DefaultInfoStream; 635 pdb::yaml::PdbDbiStream DefaultDbiStream; 636 pdb::yaml::PdbTpiStream DefaultTpiStream; 637 pdb::yaml::PdbTpiStream DefaultIpiStream; 638 639 const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); 640 641 auto &InfoBuilder = Builder.getInfoBuilder(); 642 InfoBuilder.setAge(Info.Age); 643 InfoBuilder.setGuid(Info.Guid); 644 InfoBuilder.setSignature(Info.Signature); 645 InfoBuilder.setVersion(Info.Version); 646 for (auto F : Info.Features) 647 InfoBuilder.addFeature(F); 648 649 const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); 650 auto &DbiBuilder = Builder.getDbiBuilder(); 651 DbiBuilder.setAge(Dbi.Age); 652 DbiBuilder.setBuildNumber(Dbi.BuildNumber); 653 DbiBuilder.setFlags(Dbi.Flags); 654 DbiBuilder.setMachineType(Dbi.MachineType); 655 DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); 656 DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); 657 DbiBuilder.setVersionHeader(Dbi.VerHeader); 658 for (const auto &MI : Dbi.ModInfos) { 659 auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); 660 ModiBuilder.setObjFileName(MI.Obj); 661 662 for (auto S : MI.SourceFiles) 663 ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); 664 if (MI.Modi.hasValue()) { 665 const auto &ModiStream = *MI.Modi; 666 for (auto Symbol : ModiStream.Symbols) { 667 ModiBuilder.addSymbol( 668 Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); 669 } 670 } 671 672 // Each module has its own checksum subsection, so scan for it every time. 673 Strings.setChecksums(nullptr); 674 CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings); 675 676 auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList( 677 Allocator, MI.Subsections, Strings)); 678 for (auto &SS : CodeViewSubsections) { 679 ModiBuilder.addDebugSubsection(SS); 680 } 681 } 682 683 auto &TpiBuilder = Builder.getTpiBuilder(); 684 const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); 685 TpiBuilder.setVersionHeader(Tpi.Version); 686 for (const auto &R : Tpi.Records) { 687 CVType Type = R.toCodeViewRecord(Allocator); 688 TpiBuilder.addTypeRecord(Type.RecordData, None); 689 } 690 691 const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); 692 auto &IpiBuilder = Builder.getIpiBuilder(); 693 IpiBuilder.setVersionHeader(Ipi.Version); 694 for (const auto &R : Ipi.Records) { 695 CVType Type = R.toCodeViewRecord(Allocator); 696 IpiBuilder.addTypeRecord(Type.RecordData, None); 697 } 698 699 Builder.getStringTableBuilder().setStrings(*Strings.strings()); 700 701 ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); 702} 703 704static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) { 705 ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session)); 706 707 NativeSession *NS = static_cast<NativeSession *>(Session.get()); 708 return NS->getPDBFile(); 709} 710 711static void pdb2Yaml(StringRef Path) { 712 std::unique_ptr<IPDBSession> Session; 713 auto &File = loadPDB(Path, Session); 714 715 auto O = llvm::make_unique<YAMLOutputStyle>(File); 716 O = llvm::make_unique<YAMLOutputStyle>(File); 717 718 ExitOnErr(O->dump()); 719} 720 721static void dumpRaw(StringRef Path) { 722 std::unique_ptr<IPDBSession> Session; 723 auto &File = loadPDB(Path, Session); 724 725 auto O = llvm::make_unique<DumpOutputStyle>(File); 726 727 ExitOnErr(O->dump()); 728} 729 730static void dumpBytes(StringRef Path) { 731 std::unique_ptr<IPDBSession> Session; 732 auto &File = loadPDB(Path, Session); 733 734 auto O = llvm::make_unique<BytesOutputStyle>(File); 735 736 ExitOnErr(O->dump()); 737} 738 739static void dumpAnalysis(StringRef Path) { 740 std::unique_ptr<IPDBSession> Session; 741 auto &File = loadPDB(Path, Session); 742 auto O = llvm::make_unique<AnalysisStyle>(File); 743 744 ExitOnErr(O->dump()); 745} 746 747static void diff(StringRef Path1, StringRef Path2) { 748 std::unique_ptr<IPDBSession> Session1; 749 std::unique_ptr<IPDBSession> Session2; 750 751 auto &File1 = loadPDB(Path1, Session1); 752 auto &File2 = loadPDB(Path2, Session2); 753 754 auto O = llvm::make_unique<DiffStyle>(File1, File2); 755 756 ExitOnErr(O->dump()); 757} 758 759bool opts::pretty::shouldDumpSymLevel(SymLevel Search) { 760 if (SymTypes.empty()) 761 return true; 762 if (llvm::find(SymTypes, Search) != SymTypes.end()) 763 return true; 764 if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end()) 765 return true; 766 return false; 767} 768 769uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) { 770 auto SymbolType = Symbol.getType(); 771 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); 772 773 return RawType.getLength(); 774} 775 776bool opts::pretty::compareFunctionSymbols( 777 const std::unique_ptr<PDBSymbolFunc> &F1, 778 const std::unique_ptr<PDBSymbolFunc> &F2) { 779 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); 780 781 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) 782 return F1->getName() < F2->getName(); 783 784 // Note that we intentionally sort in descending order on length, since 785 // long functions are more interesting than short functions. 786 return F1->getLength() > F2->getLength(); 787} 788 789bool opts::pretty::compareDataSymbols( 790 const std::unique_ptr<PDBSymbolData> &F1, 791 const std::unique_ptr<PDBSymbolData> &F2) { 792 assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); 793 794 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) 795 return F1->getName() < F2->getName(); 796 797 // Note that we intentionally sort in descending order on length, since 798 // large types are more interesting than short ones. 799 return getTypeLength(*F1) > getTypeLength(*F2); 800} 801 802static void dumpPretty(StringRef Path) { 803 std::unique_ptr<IPDBSession> Session; 804 805 const auto ReaderType = 806 opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; 807 ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); 808 809 if (opts::pretty::LoadAddress) 810 Session->setLoadAddress(opts::pretty::LoadAddress); 811 812 auto &Stream = outs(); 813 const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET 814 ? Stream.has_colors() 815 : opts::pretty::ColorOutput == cl::BOU_TRUE; 816 LinePrinter Printer(2, UseColor, Stream); 817 818 auto GlobalScope(Session->getGlobalScope()); 819 std::string FileName(GlobalScope->getSymbolsFileName()); 820 821 WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; 822 WithColor(Printer, PDB_ColorItem::Path).get() << FileName; 823 Printer.Indent(); 824 uint64_t FileSize = 0; 825 826 Printer.NewLine(); 827 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; 828 if (!sys::fs::file_size(FileName, FileSize)) { 829 Printer << ": " << FileSize << " bytes"; 830 } else { 831 Printer << ": (Unable to obtain file size)"; 832 } 833 834 Printer.NewLine(); 835 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; 836 Printer << ": " << GlobalScope->getGuid(); 837 838 Printer.NewLine(); 839 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; 840 Printer << ": " << GlobalScope->getAge(); 841 842 Printer.NewLine(); 843 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; 844 Printer << ": "; 845 if (GlobalScope->hasCTypes()) 846 outs() << "HasCTypes "; 847 if (GlobalScope->hasPrivateSymbols()) 848 outs() << "HasPrivateSymbols "; 849 Printer.Unindent(); 850 851 if (opts::pretty::Compilands) { 852 Printer.NewLine(); 853 WithColor(Printer, PDB_ColorItem::SectionHeader).get() 854 << "---COMPILANDS---"; 855 Printer.Indent(); 856 auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); 857 CompilandDumper Dumper(Printer); 858 CompilandDumpFlags options = CompilandDumper::Flags::None; 859 if (opts::pretty::Lines) 860 options = options | CompilandDumper::Flags::Lines; 861 while (auto Compiland = Compilands->getNext()) 862 Dumper.start(*Compiland, options); 863 Printer.Unindent(); 864 } 865 866 if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) { 867 Printer.NewLine(); 868 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; 869 Printer.Indent(); 870 TypeDumper Dumper(Printer); 871 Dumper.start(*GlobalScope); 872 Printer.Unindent(); 873 } 874 875 if (opts::pretty::Symbols) { 876 Printer.NewLine(); 877 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; 878 Printer.Indent(); 879 auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); 880 CompilandDumper Dumper(Printer); 881 while (auto Compiland = Compilands->getNext()) 882 Dumper.start(*Compiland, true); 883 Printer.Unindent(); 884 } 885 886 if (opts::pretty::Globals) { 887 Printer.NewLine(); 888 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; 889 Printer.Indent(); 890 if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { 891 FunctionDumper Dumper(Printer); 892 auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>(); 893 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { 894 while (auto Function = Functions->getNext()) { 895 Printer.NewLine(); 896 Dumper.start(*Function, FunctionDumper::PointerType::None); 897 } 898 } else { 899 std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs; 900 while (auto Func = Functions->getNext()) 901 Funcs.push_back(std::move(Func)); 902 std::sort(Funcs.begin(), Funcs.end(), 903 opts::pretty::compareFunctionSymbols); 904 for (const auto &Func : Funcs) { 905 Printer.NewLine(); 906 Dumper.start(*Func, FunctionDumper::PointerType::None); 907 } 908 } 909 } 910 if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { 911 auto Vars = GlobalScope->findAllChildren<PDBSymbolData>(); 912 VariableDumper Dumper(Printer); 913 if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { 914 while (auto Var = Vars->getNext()) 915 Dumper.start(*Var); 916 } else { 917 std::vector<std::unique_ptr<PDBSymbolData>> Datas; 918 while (auto Var = Vars->getNext()) 919 Datas.push_back(std::move(Var)); 920 std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols); 921 for (const auto &Var : Datas) 922 Dumper.start(*Var); 923 } 924 } 925 if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { 926 auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>(); 927 CompilandDumper Dumper(Printer); 928 while (auto Thunk = Thunks->getNext()) 929 Dumper.dump(*Thunk); 930 } 931 Printer.Unindent(); 932 } 933 if (opts::pretty::Externals) { 934 Printer.NewLine(); 935 WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; 936 Printer.Indent(); 937 ExternalSymbolDumper Dumper(Printer); 938 Dumper.start(*GlobalScope); 939 } 940 if (opts::pretty::Lines) { 941 Printer.NewLine(); 942 } 943 outs().flush(); 944} 945 946static void mergePdbs() { 947 BumpPtrAllocator Allocator; 948 TypeTableBuilder MergedTpi(Allocator); 949 TypeTableBuilder MergedIpi(Allocator); 950 951 // Create a Tpi and Ipi type table with all types from all input files. 952 for (const auto &Path : opts::merge::InputFilenames) { 953 std::unique_ptr<IPDBSession> Session; 954 auto &File = loadPDB(Path, Session); 955 SmallVector<TypeIndex, 128> TypeMap; 956 SmallVector<TypeIndex, 128> IdMap; 957 if (File.hasPDBTpiStream()) { 958 auto &Tpi = ExitOnErr(File.getPDBTpiStream()); 959 ExitOnErr( 960 codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray())); 961 } 962 if (File.hasPDBIpiStream()) { 963 auto &Ipi = ExitOnErr(File.getPDBIpiStream()); 964 ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, 965 Ipi.typeArray())); 966 } 967 } 968 969 // Then write the PDB. 970 PDBFileBuilder Builder(Allocator); 971 ExitOnErr(Builder.initialize(4096)); 972 // Add each of the reserved streams. We might not put any data in them, 973 // but at least they have to be present. 974 for (uint32_t I = 0; I < kSpecialStreamCount; ++I) 975 ExitOnErr(Builder.getMsfBuilder().addStream(0)); 976 977 auto &DestTpi = Builder.getTpiBuilder(); 978 auto &DestIpi = Builder.getIpiBuilder(); 979 MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef<uint8_t> Data) { 980 DestTpi.addTypeRecord(Data, None); 981 }); 982 MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef<uint8_t> Data) { 983 DestIpi.addTypeRecord(Data, None); 984 }); 985 Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140); 986 987 SmallString<64> OutFile(opts::merge::PdbOutputFile); 988 if (OutFile.empty()) { 989 OutFile = opts::merge::InputFilenames[0]; 990 llvm::sys::path::replace_extension(OutFile, "merged.pdb"); 991 } 992 ExitOnErr(Builder.commit(OutFile)); 993} 994 995static bool parseRange(StringRef Str, 996 Optional<opts::bytes::NumberRange> &Parsed) { 997 if (Str.empty()) 998 return true; 999 1000 llvm::Regex R("^([^-]+)(-([^-]+))?$"); 1001 llvm::SmallVector<llvm::StringRef, 2> Matches; 1002 if (!R.match(Str, &Matches)) 1003 return false; 1004 1005 Parsed.emplace(); 1006 if (!to_integer(Matches[1], Parsed->Min)) 1007 return false; 1008 1009 if (!Matches[3].empty()) { 1010 Parsed->Max.emplace(); 1011 if (!to_integer(Matches[3], *Parsed->Max)) 1012 return false; 1013 } 1014 return true; 1015} 1016 1017static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) { 1018 // If this list contains "All" plus some other stuff, remove the other stuff 1019 // and just keep "All" in the list. 1020 if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All)) 1021 return; 1022 Chunks.reset(); 1023 Chunks.push_back(opts::ModuleSubsection::All); 1024} 1025 1026int main(int argc_, const char *argv_[]) { 1027 // Print a stack trace if we signal out. 1028 sys::PrintStackTraceOnErrorSignal(argv_[0]); 1029 PrettyStackTraceProgram X(argc_, argv_); 1030 1031 ExitOnErr.setBanner("llvm-pdbutil: "); 1032 1033 SmallVector<const char *, 256> argv; 1034 SpecificBumpPtrAllocator<char> ArgAllocator; 1035 ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( 1036 argv, makeArrayRef(argv_, argc_), ArgAllocator))); 1037 1038 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 1039 1040 cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); 1041 1042 if (opts::BytesSubcommand) { 1043 if (!parseRange(opts::bytes::DumpBlockRangeOpt, 1044 opts::bytes::DumpBlockRange)) { 1045 errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt 1046 << "' invalid format.\n"; 1047 errs().flush(); 1048 exit(1); 1049 } 1050 if (!parseRange(opts::bytes::DumpByteRangeOpt, 1051 opts::bytes::DumpByteRange)) { 1052 errs() << "Argument '" << opts::bytes::DumpByteRangeOpt 1053 << "' invalid format.\n"; 1054 errs().flush(); 1055 exit(1); 1056 } 1057 } 1058 1059 if (opts::DumpSubcommand) { 1060 if (opts::dump::RawAll) { 1061 opts::dump::DumpLines = true; 1062 opts::dump::DumpInlineeLines = true; 1063 opts::dump::DumpXme = true; 1064 opts::dump::DumpXmi = true; 1065 opts::dump::DumpIds = true; 1066 opts::dump::DumpPublics = true; 1067 opts::dump::DumpSectionContribs = true; 1068 opts::dump::DumpSectionMap = true; 1069 opts::dump::DumpStreams = true; 1070 opts::dump::DumpStreamBlocks = true; 1071 opts::dump::DumpStringTable = true; 1072 opts::dump::DumpSummary = true; 1073 opts::dump::DumpSymbols = true; 1074 opts::dump::DumpIds = true; 1075 opts::dump::DumpIdExtras = true; 1076 opts::dump::DumpTypes = true; 1077 opts::dump::DumpTypeExtras = true; 1078 opts::dump::DumpModules = true; 1079 opts::dump::DumpModuleFiles = true; 1080 } 1081 } 1082 if (opts::PdbToYamlSubcommand) { 1083 if (opts::pdb2yaml::All) { 1084 opts::pdb2yaml::StreamMetadata = true; 1085 opts::pdb2yaml::StreamDirectory = true; 1086 opts::pdb2yaml::PdbStream = true; 1087 opts::pdb2yaml::StringTable = true; 1088 opts::pdb2yaml::DbiStream = true; 1089 opts::pdb2yaml::TpiStream = true; 1090 opts::pdb2yaml::IpiStream = true; 1091 opts::pdb2yaml::DumpModules = true; 1092 opts::pdb2yaml::DumpModuleFiles = true; 1093 opts::pdb2yaml::DumpModuleSyms = true; 1094 opts::pdb2yaml::DumpModuleSubsections.push_back( 1095 opts::ModuleSubsection::All); 1096 } 1097 simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections); 1098 1099 if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles) 1100 opts::pdb2yaml::DumpModules = true; 1101 1102 if (opts::pdb2yaml::DumpModules) 1103 opts::pdb2yaml::DbiStream = true; 1104 } 1105 if (opts::DiffSubcommand) { 1106 if (!opts::diff::PrintResultColumn && !opts::diff::PrintValueColumns) { 1107 llvm::errs() << "WARNING: No diff columns specified\n"; 1108 } 1109 } 1110 1111 llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); 1112 1113 if (opts::PdbToYamlSubcommand) { 1114 pdb2Yaml(opts::pdb2yaml::InputFilename.front()); 1115 } else if (opts::YamlToPdbSubcommand) { 1116 if (opts::yaml2pdb::YamlPdbOutputFile.empty()) { 1117 SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue()); 1118 sys::path::replace_extension(OutputFilename, ".pdb"); 1119 opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str(); 1120 } 1121 yamlToPdb(opts::yaml2pdb::InputFilename); 1122 } else if (opts::AnalyzeSubcommand) { 1123 dumpAnalysis(opts::analyze::InputFilename.front()); 1124 } else if (opts::PrettySubcommand) { 1125 if (opts::pretty::Lines) 1126 opts::pretty::Compilands = true; 1127 1128 if (opts::pretty::All) { 1129 opts::pretty::Compilands = true; 1130 opts::pretty::Symbols = true; 1131 opts::pretty::Globals = true; 1132 opts::pretty::Types = true; 1133 opts::pretty::Externals = true; 1134 opts::pretty::Lines = true; 1135 } 1136 1137 if (opts::pretty::Types) { 1138 opts::pretty::Classes = true; 1139 opts::pretty::Typedefs = true; 1140 opts::pretty::Enums = true; 1141 } 1142 1143 // When adding filters for excluded compilands and types, we need to 1144 // remember that these are regexes. So special characters such as * and \ 1145 // need to be escaped in the regex. In the case of a literal \, this means 1146 // it needs to be escaped again in the C++. So matching a single \ in the 1147 // input requires 4 \es in the C++. 1148 if (opts::pretty::ExcludeCompilerGenerated) { 1149 opts::pretty::ExcludeTypes.push_back("__vc_attributes"); 1150 opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); 1151 } 1152 if (opts::pretty::ExcludeSystemLibraries) { 1153 opts::pretty::ExcludeCompilands.push_back( 1154 "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); 1155 opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); 1156 opts::pretty::ExcludeCompilands.push_back( 1157 "d:\\\\th.obj.x86fre\\\\minkernel"); 1158 } 1159 std::for_each(opts::pretty::InputFilenames.begin(), 1160 opts::pretty::InputFilenames.end(), dumpPretty); 1161 } else if (opts::DumpSubcommand) { 1162 std::for_each(opts::dump::InputFilenames.begin(), 1163 opts::dump::InputFilenames.end(), dumpRaw); 1164 } else if (opts::BytesSubcommand) { 1165 std::for_each(opts::bytes::InputFilenames.begin(), 1166 opts::bytes::InputFilenames.end(), dumpBytes); 1167 } else if (opts::DiffSubcommand) { 1168 diff(opts::diff::Left, opts::diff::Right); 1169 } else if (opts::MergeSubcommand) { 1170 if (opts::merge::InputFilenames.size() < 2) { 1171 errs() << "merge subcommand requires at least 2 input files.\n"; 1172 exit(1); 1173 } 1174 mergePdbs(); 1175 } 1176 1177 outs().flush(); 1178 return 0; 1179} 1180