2015-01-27 21:46:21 +01:00
|
|
|
//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2017-03-14 00:28:25 +01:00
|
|
|
// Dumps debug information present in PDB files.
|
2015-01-27 21:46:21 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-02-22 23:03:38 +01:00
|
|
|
#include "llvm-pdbdump.h"
|
2017-02-01 19:30:22 +01:00
|
|
|
|
|
|
|
#include "Analyze.h"
|
2017-03-14 00:28:25 +01:00
|
|
|
#include "Diff.h"
|
2016-06-03 21:28:33 +02:00
|
|
|
#include "LLVMOutputStyle.h"
|
2015-02-27 10:15:59 +01:00
|
|
|
#include "LinePrinter.h"
|
2016-06-03 21:28:33 +02:00
|
|
|
#include "OutputStyle.h"
|
2017-01-11 01:35:43 +01:00
|
|
|
#include "PrettyCompilandDumper.h"
|
|
|
|
#include "PrettyExternalSymbolDumper.h"
|
|
|
|
#include "PrettyFunctionDumper.h"
|
|
|
|
#include "PrettyTypeDumper.h"
|
|
|
|
#include "PrettyVariableDumper.h"
|
2016-06-06 22:37:05 +02:00
|
|
|
#include "YAMLOutputStyle.h"
|
2015-02-22 23:03:38 +01:00
|
|
|
|
2015-01-27 21:46:21 +01:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2015-10-15 03:27:19 +02:00
|
|
|
#include "llvm/ADT/BitVector.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2017-05-02 01:27:42 +02:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2015-01-27 21:46:21 +01:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2015-02-10 23:47:14 +01:00
|
|
|
#include "llvm/Config/config.h"
|
2017-05-19 21:26:58 +02:00
|
|
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
2017-05-02 18:56:09 +02:00
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
2017-05-19 01:03:41 +02:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
2017-05-19 01:04:08 +02:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
2016-07-29 22:56:36 +02:00
|
|
|
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
2016-05-06 22:51:57 +02:00
|
|
|
#include "llvm/DebugInfo/PDB/GenericError.h"
|
2015-02-10 23:43:25 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
|
2015-02-13 10:09:03 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
2017-04-27 18:11:19 +02:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
2017-01-25 23:38:55 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
|
2017-05-02 20:00:13 +02:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
2017-01-25 23:38:55 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
|
2015-02-13 10:09:03 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/PDB.h"
|
2015-02-10 23:43:25 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
|
2015-02-27 10:15:18 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
2015-02-13 10:09:03 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
|
2015-02-27 10:15:18 +01:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
|
2017-03-02 21:52:51 +01:00
|
|
|
#include "llvm/Support/BinaryByteStream.h"
|
2016-06-02 07:07:49 +02:00
|
|
|
#include "llvm/Support/COM.h"
|
2015-01-27 21:46:21 +01:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2016-06-14 22:48:36 +02:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
2015-02-22 23:03:38 +01:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2015-01-27 21:46:21 +01:00
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2015-10-15 03:27:19 +02:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2017-05-17 22:46:48 +02:00
|
|
|
#include "llvm/Support/Path.h"
|
2015-01-27 21:46:21 +01:00
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
2015-02-13 10:09:03 +01:00
|
|
|
#include "llvm/Support/Process.h"
|
2016-09-09 20:17:52 +02:00
|
|
|
#include "llvm/Support/Regex.h"
|
2016-05-04 18:09:04 +02:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2016-04-22 14:04:42 +02:00
|
|
|
#include "llvm/Support/Signals.h"
|
2016-04-25 19:38:08 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-01-27 21:46:21 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
2016-06-03 05:25:59 +02:00
|
|
|
using namespace llvm::codeview;
|
2016-07-22 21:56:05 +02:00
|
|
|
using namespace llvm::msf;
|
2016-04-29 19:28:47 +02:00
|
|
|
using namespace llvm::pdb;
|
2015-01-27 21:46:21 +01:00
|
|
|
|
|
|
|
namespace opts {
|
2015-02-15 21:27:53 +01:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file");
|
|
|
|
cl::SubCommand
|
|
|
|
PrettySubcommand("pretty",
|
|
|
|
"Dump semantic information about types and symbols");
|
2017-03-14 00:28:25 +01:00
|
|
|
|
|
|
|
cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files");
|
|
|
|
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::SubCommand
|
|
|
|
YamlToPdbSubcommand("yaml2pdb",
|
|
|
|
"Generate a PDB file from a YAML description");
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::SubCommand
|
|
|
|
PdbToYamlSubcommand("pdb2yaml",
|
|
|
|
"Generate a detailed YAML description of a PDB File");
|
2015-01-27 21:46:21 +01:00
|
|
|
|
2017-02-01 19:30:22 +01:00
|
|
|
cl::SubCommand
|
|
|
|
AnalyzeSubcommand("analyze",
|
|
|
|
"Analyze various aspects of a PDB's structure");
|
|
|
|
|
2017-05-19 01:03:41 +02:00
|
|
|
cl::SubCommand MergeSubcommand("merge",
|
|
|
|
"Merge multiple PDBs into a single PDB");
|
|
|
|
|
2015-03-02 05:39:56 +01:00
|
|
|
cl::OptionCategory TypeCategory("Symbol Type Options");
|
[llvm-pdbdump] More advanced class definition dumping.
Previously the dumping of class definitions was very primitive,
and it made it hard to do more than the most trivial of output
formats when dumping. As such, we would only dump one line for
each field, and then dump non-layout items like nested types
and enums.
With this patch, we do a complete analysis of the object
hierarchy including aggregate types, bases, virtual bases,
vftable analysis, etc. The only immediately visible effects
of this are that a) we can now dump a line for the vfptr where
before we would treat that as padding, and b) we now don't
treat virtual bases that come at the end of a class as padding
since we have a more detailed analysis of the class's storage
usage.
In subsequent patches, we should be able to use this analysis
to display a complete graphical view of a class's layout including
recursing arbitrarily deep into an object's base class / aggregate
member hierarchy.
llvm-svn: 300133
2017-04-13 01:18:21 +02:00
|
|
|
cl::OptionCategory FilterCategory("Filtering and Sorting Options");
|
2015-05-01 22:24:26 +02:00
|
|
|
cl::OptionCategory OtherOptions("Other Options");
|
2016-06-30 19:42:48 +02:00
|
|
|
|
|
|
|
namespace pretty {
|
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
|
|
|
cl::OneOrMore, cl::sub(PrettySubcommand));
|
2015-03-02 05:39:56 +01:00
|
|
|
|
|
|
|
cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-05-14 03:13:40 +02:00
|
|
|
cl::opt<bool> Symbols("module-syms",
|
|
|
|
cl::desc("Display symbols for each compiland"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-03-02 05:39:56 +01:00
|
|
|
cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-05-01 22:24:26 +02:00
|
|
|
cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-05-14 03:13:40 +02:00
|
|
|
cl::list<SymLevel> SymTypes(
|
|
|
|
"sym-types", cl::desc("Type of symbols to dump (default all)"),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore,
|
|
|
|
cl::values(
|
|
|
|
clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"),
|
|
|
|
clEnumValN(SymLevel::Data, "data", "Display data symbols"),
|
|
|
|
clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"),
|
|
|
|
clEnumValN(SymLevel::All, "all", "Display all symbols (default)")));
|
|
|
|
|
2017-04-07 01:43:12 +02:00
|
|
|
cl::opt<bool>
|
|
|
|
Types("types",
|
|
|
|
cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<bool> Classes("classes", cl::desc("Display class types"),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-05-14 03:13:40 +02:00
|
|
|
cl::opt<SymbolSortMode> SymbolOrder(
|
|
|
|
"symbol-order", cl::desc("symbol sort order"),
|
|
|
|
cl::init(SymbolSortMode::None),
|
|
|
|
cl::values(clEnumValN(SymbolSortMode::None, "none",
|
|
|
|
"Undefined / no particular sort order"),
|
|
|
|
clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"),
|
|
|
|
clEnumValN(SymbolSortMode::Size, "size",
|
|
|
|
"Sort symbols by size")),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
|
|
|
|
2017-04-13 23:11:00 +02:00
|
|
|
cl::opt<ClassSortMode> ClassOrder(
|
|
|
|
"class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
|
2017-04-24 19:47:24 +02:00
|
|
|
cl::values(
|
|
|
|
clEnumValN(ClassSortMode::None, "none",
|
|
|
|
"Undefined / no particular sort order"),
|
|
|
|
clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"),
|
|
|
|
clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"),
|
|
|
|
clEnumValN(ClassSortMode::Padding, "padding",
|
|
|
|
"Sort classes by amount of padding"),
|
|
|
|
clEnumValN(ClassSortMode::PaddingPct, "padding-pct",
|
2017-04-25 22:22:29 +02:00
|
|
|
"Sort classes by percentage of space consumed by padding"),
|
|
|
|
clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm",
|
|
|
|
"Sort classes by amount of immediate padding"),
|
|
|
|
clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm",
|
|
|
|
"Sort classes by percentage of space consumed by immediate "
|
|
|
|
"padding")),
|
2017-04-13 23:11:00 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
|
|
|
|
[llvm-pdbdump] More advanced class definition dumping.
Previously the dumping of class definitions was very primitive,
and it made it hard to do more than the most trivial of output
formats when dumping. As such, we would only dump one line for
each field, and then dump non-layout items like nested types
and enums.
With this patch, we do a complete analysis of the object
hierarchy including aggregate types, bases, virtual bases,
vftable analysis, etc. The only immediately visible effects
of this are that a) we can now dump a line for the vfptr where
before we would treat that as padding, and b) we now don't
treat virtual bases that come at the end of a class as padding
since we have a more detailed analysis of the class's storage
usage.
In subsequent patches, we should be able to use this analysis
to display a complete graphical view of a class's layout including
recursing arbitrarily deep into an object's base class / aggregate
member hierarchy.
llvm-svn: 300133
2017-04-13 01:18:21 +02:00
|
|
|
cl::opt<ClassDefinitionFormat> ClassFormat(
|
|
|
|
"class-definitions", cl::desc("Class definition format"),
|
2017-04-24 19:47:52 +02:00
|
|
|
cl::init(ClassDefinitionFormat::All),
|
[llvm-pdbdump] More advanced class definition dumping.
Previously the dumping of class definitions was very primitive,
and it made it hard to do more than the most trivial of output
formats when dumping. As such, we would only dump one line for
each field, and then dump non-layout items like nested types
and enums.
With this patch, we do a complete analysis of the object
hierarchy including aggregate types, bases, virtual bases,
vftable analysis, etc. The only immediately visible effects
of this are that a) we can now dump a line for the vfptr where
before we would treat that as padding, and b) we now don't
treat virtual bases that come at the end of a class as padding
since we have a more detailed analysis of the class's storage
usage.
In subsequent patches, we should be able to use this analysis
to display a complete graphical view of a class's layout including
recursing arbitrarily deep into an object's base class / aggregate
member hierarchy.
llvm-svn: 300133
2017-04-13 01:18:21 +02:00
|
|
|
cl::values(
|
2017-04-24 19:47:52 +02:00
|
|
|
clEnumValN(ClassDefinitionFormat::All, "all",
|
2017-04-13 01:18:51 +02:00
|
|
|
"Display all class members including data, constants, "
|
2017-04-13 23:11:00 +02:00
|
|
|
"typedefs, functions, etc"),
|
2017-04-24 19:47:52 +02:00
|
|
|
clEnumValN(ClassDefinitionFormat::Layout, "layout",
|
[llvm-pdbdump] More advanced class definition dumping.
Previously the dumping of class definitions was very primitive,
and it made it hard to do more than the most trivial of output
formats when dumping. As such, we would only dump one line for
each field, and then dump non-layout items like nested types
and enums.
With this patch, we do a complete analysis of the object
hierarchy including aggregate types, bases, virtual bases,
vftable analysis, etc. The only immediately visible effects
of this are that a) we can now dump a line for the vfptr where
before we would treat that as padding, and b) we now don't
treat virtual bases that come at the end of a class as padding
since we have a more detailed analysis of the class's storage
usage.
In subsequent patches, we should be able to use this analysis
to display a complete graphical view of a class's layout including
recursing arbitrarily deep into an object's base class / aggregate
member hierarchy.
llvm-svn: 300133
2017-04-13 01:18:21 +02:00
|
|
|
"Only display members that contribute to class size."),
|
|
|
|
clEnumValN(ClassDefinitionFormat::None, "none",
|
|
|
|
"Don't display class definitions")),
|
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-04-24 19:47:52 +02:00
|
|
|
cl::opt<uint32_t> ClassRecursionDepth(
|
|
|
|
"class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"),
|
|
|
|
cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-04-07 01:43:12 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
|
|
|
|
cl::sub(PrettySubcommand));
|
2015-03-02 05:39:56 +01:00
|
|
|
cl::opt<bool>
|
|
|
|
All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-03-01 07:49:49 +01:00
|
|
|
|
2015-05-01 22:24:26 +02:00
|
|
|
cl::opt<uint64_t> LoadAddress(
|
|
|
|
"load-address",
|
|
|
|
cl::desc("Assume the module is loaded at the specified address"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
2017-03-15 21:17:58 +01:00
|
|
|
cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
|
2017-03-23 16:28:15 +01:00
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<cl::boolOrDefault>
|
|
|
|
ColorOutput("color-output",
|
|
|
|
cl::desc("Override use of color (default = isatty)"),
|
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::list<std::string> ExcludeTypes(
|
|
|
|
"exclude-types", cl::desc("Exclude types by regular expression"),
|
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::list<std::string> ExcludeSymbols(
|
|
|
|
"exclude-symbols", cl::desc("Exclude symbols by regular expression"),
|
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::list<std::string> ExcludeCompilands(
|
|
|
|
"exclude-compilands", cl::desc("Exclude compilands by regular expression"),
|
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-29 21:49:06 +02:00
|
|
|
|
|
|
|
cl::list<std::string> IncludeTypes(
|
|
|
|
"include-types",
|
|
|
|
cl::desc("Include only types which match a regular expression"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-29 21:49:06 +02:00
|
|
|
cl::list<std::string> IncludeSymbols(
|
|
|
|
"include-symbols",
|
|
|
|
cl::desc("Include only symbols which match a regular expression"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-29 21:49:06 +02:00
|
|
|
cl::list<std::string> IncludeCompilands(
|
|
|
|
"include-compilands",
|
|
|
|
cl::desc("Include only compilands those which match a regular expression"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2017-04-13 23:11:00 +02:00
|
|
|
cl::opt<uint32_t> SizeThreshold(
|
|
|
|
"min-type-size", cl::desc("Displays only those types which are greater "
|
|
|
|
"than or equal to the specified size."),
|
|
|
|
cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<uint32_t> PaddingThreshold(
|
|
|
|
"min-class-padding", cl::desc("Displays only those classes which have at "
|
|
|
|
"least the specified amount of padding."),
|
|
|
|
cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2017-04-25 22:22:29 +02:00
|
|
|
cl::opt<uint32_t> ImmediatePaddingThreshold(
|
|
|
|
"min-class-padding-imm",
|
|
|
|
cl::desc("Displays only those classes which have at least the specified "
|
|
|
|
"amount of immediate padding, ignoring padding internal to bases "
|
|
|
|
"and aggregates."),
|
|
|
|
cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-29 21:49:06 +02:00
|
|
|
|
2015-03-02 05:39:56 +01:00
|
|
|
cl::opt<bool> ExcludeCompilerGenerated(
|
|
|
|
"no-compiler-generated",
|
|
|
|
cl::desc("Don't show compiler generated types and symbols"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-03-02 05:39:56 +01:00
|
|
|
cl::opt<bool>
|
|
|
|
ExcludeSystemLibraries("no-system-libs",
|
|
|
|
cl::desc("Don't show symbols from system libraries"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2017-04-07 01:43:39 +02:00
|
|
|
|
2015-03-04 07:09:53 +01:00
|
|
|
cl::opt<bool> NoEnumDefs("no-enum-definitions",
|
|
|
|
cl::desc("Don't display full enum definitions"),
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-01-27 21:46:21 +01:00
|
|
|
}
|
|
|
|
|
2017-03-14 00:28:25 +01:00
|
|
|
namespace diff {
|
|
|
|
cl::opt<bool> Pedantic("pedantic",
|
|
|
|
cl::desc("Finds all differences (even structural ones "
|
|
|
|
"that produce otherwise identical PDBs)"),
|
|
|
|
cl::sub(DiffSubcommand));
|
|
|
|
|
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<first> <second>"),
|
|
|
|
cl::OneOrMore, cl::sub(DiffSubcommand));
|
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
namespace raw {
|
2016-05-28 20:25:15 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::OptionCategory MsfOptions("MSF Container Options");
|
|
|
|
cl::OptionCategory TypeOptions("Type Record Options");
|
|
|
|
cl::OptionCategory FileOptions("Module & File Options");
|
|
|
|
cl::OptionCategory SymbolOptions("Symbol Options");
|
|
|
|
cl::OptionCategory MiscOptions("Miscellaneous Options");
|
2016-05-04 18:09:04 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
// MSF OPTIONS
|
|
|
|
cl::opt<bool> DumpHeaders("headers", cl::desc("dump PDB headers"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpStreamBlocks("stream-blocks",
|
|
|
|
cl::desc("dump PDB stream blocks"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpStreamSummary("stream-summary",
|
|
|
|
cl::desc("dump summary of the PDB streams"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
2016-08-01 23:19:45 +02:00
|
|
|
cl::opt<bool> DumpPageStats(
|
|
|
|
"page-stats",
|
|
|
|
cl::desc("dump allocation stats of the pages in the MSF file"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
2016-09-09 20:17:52 +02:00
|
|
|
cl::opt<std::string>
|
|
|
|
DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
|
|
|
|
cl::desc("Dump binary data from specified range."),
|
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
|
|
|
llvm::Optional<BlockRange> DumpBlockRange;
|
|
|
|
|
2017-04-28 02:43:38 +02:00
|
|
|
cl::list<std::string>
|
2016-09-09 20:17:52 +02:00
|
|
|
DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
|
2017-04-28 02:43:38 +02:00
|
|
|
cl::desc("Dump binary data from specified streams. Format "
|
|
|
|
"is SN[:Start][@Size]"),
|
2016-09-09 20:17:52 +02:00
|
|
|
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
2016-05-04 18:09:04 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
// TYPE OPTIONS
|
2017-01-12 23:28:15 +01:00
|
|
|
cl::opt<bool>
|
|
|
|
CompactRecords("compact-records",
|
|
|
|
cl::desc("Dump type and symbol records with less detail"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::opt<bool>
|
|
|
|
DumpTpiRecords("tpi-records",
|
|
|
|
cl::desc("dump CodeView type records from TPI stream"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpTpiRecordBytes(
|
|
|
|
"tpi-record-bytes",
|
|
|
|
cl::desc("dump CodeView type record raw bytes from TPI stream"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool>
|
|
|
|
DumpIpiRecords("ipi-records",
|
|
|
|
cl::desc("dump CodeView type records from IPI stream"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpIpiRecordBytes(
|
|
|
|
"ipi-record-bytes",
|
|
|
|
cl::desc("dump CodeView type record raw bytes from IPI stream"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
|
|
|
|
|
|
|
// MODULE & FILE OPTIONS
|
|
|
|
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
|
|
|
|
cl::cat(FileOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
|
|
|
|
cl::cat(FileOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpLineInfo("line-info",
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::desc("dump file and line information"),
|
|
|
|
cl::cat(FileOptions), cl::sub(RawSubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
|
|
|
|
// SYMBOL OPTIONS
|
2016-10-21 21:43:19 +02:00
|
|
|
cl::opt<bool> DumpGlobals("globals", cl::desc("dump globals stream data"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool>
|
|
|
|
DumpSymRecordBytes("sym-record-bytes",
|
|
|
|
cl::desc("dump CodeView symbol record raw bytes"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
2016-06-02 20:20:20 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
// MISCELLANEOUS OPTIONS
|
2017-01-20 23:42:09 +01:00
|
|
|
cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
|
|
|
|
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::opt<bool> DumpSectionContribs("section-contribs",
|
|
|
|
cl::desc("dump section contributions"),
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
|
|
|
|
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpSectionHeaders("section-headers",
|
|
|
|
cl::desc("dump section headers"),
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
|
|
|
cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
|
|
|
|
cl::sub(RawSubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
|
|
|
|
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
2016-05-13 23:21:53 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
|
|
|
cl::OneOrMore, cl::sub(RawSubcommand));
|
|
|
|
}
|
2016-06-02 07:07:49 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
namespace yaml2pdb {
|
|
|
|
cl::opt<std::string>
|
|
|
|
YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
|
|
|
|
cl::sub(YamlToPdbSubcommand));
|
2016-06-02 07:07:49 +02:00
|
|
|
|
2017-05-17 22:46:48 +02:00
|
|
|
cl::opt<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input YAML file>"), cl::Required,
|
|
|
|
cl::sub(YamlToPdbSubcommand));
|
2016-06-30 19:42:48 +02:00
|
|
|
}
|
2016-06-02 07:07:49 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
namespace pdb2yaml {
|
2016-07-11 23:45:09 +02:00
|
|
|
cl::opt<bool>
|
|
|
|
NoFileHeaders("no-file-headers",
|
|
|
|
cl::desc("Do not dump MSF file headers (you will not be able "
|
|
|
|
"to generate a fresh PDB from the resulting YAML)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-03-15 23:18:53 +01:00
|
|
|
cl::opt<bool> Minimal("minimal",
|
|
|
|
cl::desc("Don't write fields with default values"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-11 23:45:09 +02:00
|
|
|
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::opt<bool> StreamMetadata(
|
|
|
|
"stream-metadata",
|
|
|
|
cl::desc("Dump the number of streams and each stream's size"),
|
2016-07-11 23:45:09 +02:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-06-30 19:43:00 +02:00
|
|
|
cl::opt<bool> StreamDirectory(
|
|
|
|
"stream-directory",
|
|
|
|
cl::desc("Dump each stream's block map (implies -stream-metadata)"),
|
2016-07-11 23:45:09 +02:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-16 00:16:56 +02:00
|
|
|
cl::opt<bool> PdbStream("pdb-stream",
|
|
|
|
cl::desc("Dump the PDB Stream (Stream 1)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-01-20 23:42:09 +01:00
|
|
|
|
|
|
|
cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-07-16 00:16:56 +02:00
|
|
|
cl::opt<bool> DbiStream("dbi-stream",
|
|
|
|
cl::desc("Dump the DBI Stream (Stream 2)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-22 17:46:37 +02:00
|
|
|
cl::opt<bool>
|
|
|
|
DbiModuleInfo("dbi-module-info",
|
|
|
|
cl::desc("Dump DBI Module Information (implies -dbi-stream)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-10-08 03:12:01 +02:00
|
|
|
cl::opt<bool> DbiModuleSyms(
|
|
|
|
"dbi-module-syms",
|
|
|
|
cl::desc("Dump DBI Module Information (implies -dbi-module-info)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-07-22 17:46:37 +02:00
|
|
|
cl::opt<bool> DbiModuleSourceFileInfo(
|
|
|
|
"dbi-module-source-info",
|
|
|
|
cl::desc(
|
2017-04-25 22:22:02 +02:00
|
|
|
"Dump DBI Module Source File Information (implies -dbi-module-info)"),
|
2016-07-22 17:46:37 +02:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-06-06 20:39:21 +02:00
|
|
|
|
2017-04-25 22:22:02 +02:00
|
|
|
cl::opt<bool>
|
|
|
|
DbiModuleSourceLineInfo("dbi-module-lines",
|
|
|
|
cl::desc("Dump DBI Module Source Line Information "
|
|
|
|
"(implies -dbi-module-source-info)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-08-18 18:49:29 +02:00
|
|
|
cl::opt<bool> TpiStream("tpi-stream",
|
|
|
|
cl::desc("Dump the TPI Stream (Stream 3)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-09-15 20:22:31 +02:00
|
|
|
cl::opt<bool> IpiStream("ipi-stream",
|
|
|
|
cl::desc("Dump the IPI Stream (Stream 5)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
cl::list<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input PDB file>"), cl::Required,
|
|
|
|
cl::sub(PdbToYamlSubcommand));
|
2016-05-24 22:31:48 +02:00
|
|
|
}
|
2017-02-01 19:30:22 +01:00
|
|
|
|
|
|
|
namespace analyze {
|
|
|
|
cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"),
|
|
|
|
cl::sub(AnalyzeSubcommand), cl::init(false));
|
|
|
|
cl::list<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input PDB file>"), cl::Required,
|
|
|
|
cl::sub(AnalyzeSubcommand));
|
|
|
|
}
|
2017-05-19 01:03:41 +02:00
|
|
|
|
|
|
|
namespace merge {
|
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
|
|
|
cl::OneOrMore, cl::sub(MergeSubcommand));
|
|
|
|
cl::opt<std::string>
|
|
|
|
PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"),
|
|
|
|
cl::sub(MergeSubcommand));
|
|
|
|
}
|
2016-04-29 01:47:27 +02:00
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
static ExitOnError ExitOnErr;
|
|
|
|
|
2016-06-14 22:48:36 +02:00
|
|
|
static void yamlToPdb(StringRef Path) {
|
2016-07-22 21:56:26 +02:00
|
|
|
BumpPtrAllocator Allocator;
|
2016-06-14 22:48:36 +02:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
|
|
|
|
MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
|
|
|
|
/*RequiresNullTerminator=*/false);
|
|
|
|
|
|
|
|
if (ErrorOrBuffer.getError()) {
|
|
|
|
ExitOnErr(make_error<GenericError>(generic_error_code::invalid_path, Path));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<MemoryBuffer> &Buffer = ErrorOrBuffer.get();
|
|
|
|
|
|
|
|
llvm::yaml::Input In(Buffer->getBuffer());
|
2016-09-09 19:46:17 +02:00
|
|
|
pdb::yaml::PdbObject YamlObj(Allocator);
|
2016-06-14 22:48:36 +02:00
|
|
|
In >> YamlObj;
|
|
|
|
|
2016-07-22 21:56:26 +02:00
|
|
|
PDBFileBuilder Builder(Allocator);
|
2016-07-11 23:45:26 +02:00
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
uint32_t BlockSize = 4096;
|
|
|
|
if (YamlObj.Headers.hasValue())
|
|
|
|
BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
|
|
|
|
ExitOnErr(Builder.initialize(BlockSize));
|
2016-09-15 01:00:02 +02:00
|
|
|
// Add each of the reserved streams. We ignore stream metadata in the
|
|
|
|
// yaml, because we will reconstruct our own view of the streams. For
|
|
|
|
// example, the YAML may say that there were 20 streams in the original
|
|
|
|
// PDB, but maybe we only dump a subset of those 20 streams, so we will
|
|
|
|
// have fewer, and the ones we do have may end up with different indices
|
|
|
|
// than the ones in the original PDB. So we just start with a clean slate.
|
|
|
|
for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
|
|
|
|
ExitOnErr(Builder.getMsfBuilder().addStream(0));
|
2016-07-06 20:05:57 +02:00
|
|
|
|
2017-01-20 23:42:09 +01:00
|
|
|
if (YamlObj.StringTable.hasValue()) {
|
|
|
|
auto &Strings = Builder.getStringTableBuilder();
|
|
|
|
for (auto S : *YamlObj.StringTable)
|
|
|
|
Strings.insert(S);
|
|
|
|
}
|
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
pdb::yaml::PdbInfoStream DefaultInfoStream;
|
|
|
|
pdb::yaml::PdbDbiStream DefaultDbiStream;
|
|
|
|
pdb::yaml::PdbTpiStream DefaultTpiStream;
|
2017-05-22 23:07:43 +02:00
|
|
|
pdb::yaml::PdbTpiStream DefaultIpiStream;
|
2017-03-15 23:18:53 +01:00
|
|
|
|
|
|
|
const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream);
|
|
|
|
|
|
|
|
auto &InfoBuilder = Builder.getInfoBuilder();
|
|
|
|
InfoBuilder.setAge(Info.Age);
|
|
|
|
InfoBuilder.setGuid(Info.Guid);
|
|
|
|
InfoBuilder.setSignature(Info.Signature);
|
|
|
|
InfoBuilder.setVersion(Info.Version);
|
2017-03-16 21:19:11 +01:00
|
|
|
for (auto F : Info.Features)
|
|
|
|
InfoBuilder.addFeature(F);
|
2017-03-15 23:18:53 +01:00
|
|
|
|
2017-05-03 19:11:40 +02:00
|
|
|
auto &Strings = Builder.getStringTableBuilder().getStrings();
|
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream);
|
|
|
|
auto &DbiBuilder = Builder.getDbiBuilder();
|
|
|
|
DbiBuilder.setAge(Dbi.Age);
|
|
|
|
DbiBuilder.setBuildNumber(Dbi.BuildNumber);
|
|
|
|
DbiBuilder.setFlags(Dbi.Flags);
|
|
|
|
DbiBuilder.setMachineType(Dbi.MachineType);
|
|
|
|
DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld);
|
|
|
|
DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion);
|
|
|
|
DbiBuilder.setVersionHeader(Dbi.VerHeader);
|
|
|
|
for (const auto &MI : Dbi.ModInfos) {
|
2017-03-16 21:19:11 +01:00
|
|
|
auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
|
2017-03-15 23:18:53 +01:00
|
|
|
|
|
|
|
for (auto S : MI.SourceFiles)
|
|
|
|
ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S));
|
|
|
|
if (MI.Modi.hasValue()) {
|
|
|
|
const auto &ModiStream = *MI.Modi;
|
|
|
|
ModiBuilder.setObjFileName(MI.Obj);
|
|
|
|
for (auto Symbol : ModiStream.Symbols)
|
|
|
|
ModiBuilder.addSymbol(Symbol.Record);
|
2016-07-22 17:46:37 +02:00
|
|
|
}
|
2017-05-02 01:27:42 +02:00
|
|
|
if (MI.FileLineInfo.hasValue()) {
|
|
|
|
const auto &FLI = *MI.FileLineInfo;
|
|
|
|
|
|
|
|
// File Checksums must be emitted before line information, because line
|
|
|
|
// info records use offsets into the checksum buffer to reference a file's
|
|
|
|
// source file name.
|
2017-05-03 19:11:40 +02:00
|
|
|
auto Checksums =
|
|
|
|
llvm::make_unique<ModuleDebugFileChecksumFragment>(Strings);
|
2017-05-02 01:27:42 +02:00
|
|
|
auto &ChecksumRef = *Checksums;
|
|
|
|
if (!FLI.FileChecksums.empty()) {
|
2017-05-03 19:11:40 +02:00
|
|
|
for (auto &FC : FLI.FileChecksums)
|
|
|
|
Checksums->addChecksum(FC.FileName, FC.Kind, FC.ChecksumBytes.Bytes);
|
2017-05-02 01:27:42 +02:00
|
|
|
}
|
|
|
|
ModiBuilder.setC13FileChecksums(std::move(Checksums));
|
|
|
|
|
|
|
|
for (const auto &Fragment : FLI.LineFragments) {
|
2017-05-03 19:11:40 +02:00
|
|
|
auto Lines =
|
|
|
|
llvm::make_unique<ModuleDebugLineFragment>(ChecksumRef, Strings);
|
2017-05-02 01:27:42 +02:00
|
|
|
Lines->setCodeSize(Fragment.CodeSize);
|
|
|
|
Lines->setRelocationAddress(Fragment.RelocSegment,
|
|
|
|
Fragment.RelocOffset);
|
|
|
|
Lines->setFlags(Fragment.Flags);
|
|
|
|
for (const auto &LC : Fragment.Blocks) {
|
2017-05-03 19:11:40 +02:00
|
|
|
Lines->createBlock(LC.FileName);
|
2017-05-02 01:27:42 +02:00
|
|
|
if (Lines->hasColumnInfo()) {
|
|
|
|
for (const auto &Item : zip(LC.Lines, LC.Columns)) {
|
|
|
|
auto &L = std::get<0>(Item);
|
|
|
|
auto &C = std::get<1>(Item);
|
|
|
|
uint32_t LE = L.LineStart + L.EndDelta;
|
|
|
|
Lines->addLineAndColumnInfo(
|
|
|
|
L.Offset, LineInfo(L.LineStart, LE, L.IsStatement),
|
|
|
|
C.StartColumn, C.EndColumn);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const auto &L : LC.Lines) {
|
|
|
|
uint32_t LE = L.LineStart + L.EndDelta;
|
|
|
|
Lines->addLineInfo(L.Offset,
|
|
|
|
LineInfo(L.LineStart, LE, L.IsStatement));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-02 18:56:09 +02:00
|
|
|
ModiBuilder.addC13Fragment(std::move(Lines));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &Inlinee : FLI.Inlinees) {
|
|
|
|
auto Inlinees = llvm::make_unique<ModuleDebugInlineeLineFragment>(
|
2017-05-03 21:42:06 +02:00
|
|
|
ChecksumRef, Inlinee.HasExtraFiles);
|
2017-05-02 18:56:09 +02:00
|
|
|
for (const auto &Site : Inlinee.Sites) {
|
2017-05-03 19:11:40 +02:00
|
|
|
Inlinees->addInlineSite(Site.Inlinee, Site.FileName,
|
|
|
|
Site.SourceLineNum);
|
2017-05-02 18:56:09 +02:00
|
|
|
if (!Inlinee.HasExtraFiles)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (auto EF : Site.ExtraFiles) {
|
2017-05-03 19:11:40 +02:00
|
|
|
Inlinees->addExtraFile(EF);
|
2017-05-02 18:56:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ModiBuilder.addC13Fragment(std::move(Inlinees));
|
2017-05-02 01:27:42 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-11 23:45:26 +02:00
|
|
|
}
|
|
|
|
|
2017-03-15 23:18:53 +01:00
|
|
|
auto &TpiBuilder = Builder.getTpiBuilder();
|
|
|
|
const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
|
|
|
|
TpiBuilder.setVersionHeader(Tpi.Version);
|
|
|
|
for (const auto &R : Tpi.Records)
|
2017-04-04 02:56:34 +02:00
|
|
|
TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
|
2017-03-15 23:18:53 +01:00
|
|
|
|
2017-05-22 23:07:43 +02:00
|
|
|
const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream);
|
2017-03-15 23:18:53 +01:00
|
|
|
auto &IpiBuilder = Builder.getIpiBuilder();
|
|
|
|
IpiBuilder.setVersionHeader(Ipi.Version);
|
|
|
|
for (const auto &R : Ipi.Records)
|
2017-05-22 23:07:43 +02:00
|
|
|
IpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash);
|
2016-09-15 20:22:31 +02:00
|
|
|
|
2016-09-30 22:34:44 +02:00
|
|
|
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
|
2016-06-14 22:48:36 +02:00
|
|
|
}
|
|
|
|
|
2017-03-14 00:28:25 +01:00
|
|
|
static PDBFile &loadPDB(StringRef Path, std::unique_ptr<IPDBSession> &Session) {
|
|
|
|
ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session));
|
|
|
|
|
|
|
|
NativeSession *NS = static_cast<NativeSession *>(Session.get());
|
|
|
|
return NS->getPDBFile();
|
|
|
|
}
|
|
|
|
|
2016-07-06 20:05:57 +02:00
|
|
|
static void pdb2Yaml(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2017-03-14 00:28:25 +01:00
|
|
|
auto &File = loadPDB(Path, Session);
|
2016-07-06 20:05:57 +02:00
|
|
|
|
|
|
|
auto O = llvm::make_unique<YAMLOutputStyle>(File);
|
|
|
|
O = llvm::make_unique<YAMLOutputStyle>(File);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
static void dumpRaw(StringRef Path) {
|
2016-04-29 01:47:27 +02:00
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2017-03-14 00:28:25 +01:00
|
|
|
auto &File = loadPDB(Path, Session);
|
2016-05-06 22:51:57 +02:00
|
|
|
|
2016-07-06 20:05:57 +02:00
|
|
|
auto O = llvm::make_unique<LLVMOutputStyle>(File);
|
2016-06-30 19:42:48 +02:00
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-02-01 19:30:22 +01:00
|
|
|
static void dumpAnalysis(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2017-03-14 00:28:25 +01:00
|
|
|
auto &File = loadPDB(Path, Session);
|
2017-02-01 19:30:22 +01:00
|
|
|
auto O = llvm::make_unique<AnalysisStyle>(File);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-03-14 00:28:25 +01:00
|
|
|
static void diff(StringRef Path1, StringRef Path2) {
|
|
|
|
std::unique_ptr<IPDBSession> Session1;
|
|
|
|
std::unique_ptr<IPDBSession> Session2;
|
|
|
|
|
|
|
|
auto &File1 = loadPDB(Path1, Session1);
|
|
|
|
auto &File2 = loadPDB(Path2, Session2);
|
|
|
|
|
|
|
|
auto O = llvm::make_unique<DiffStyle>(File1, File2);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-05-14 03:13:40 +02:00
|
|
|
bool opts::pretty::shouldDumpSymLevel(SymLevel Search) {
|
|
|
|
if (SymTypes.empty())
|
|
|
|
return true;
|
|
|
|
if (llvm::find(SymTypes, Search) != SymTypes.end())
|
|
|
|
return true;
|
|
|
|
if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end())
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) {
|
|
|
|
auto SymbolType = Symbol.getType();
|
|
|
|
const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
|
|
|
|
|
|
|
|
return RawType.getLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool opts::pretty::compareFunctionSymbols(
|
|
|
|
const std::unique_ptr<PDBSymbolFunc> &F1,
|
|
|
|
const std::unique_ptr<PDBSymbolFunc> &F2) {
|
|
|
|
assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
|
|
|
|
|
|
|
|
if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
|
|
|
|
return F1->getName() < F2->getName();
|
|
|
|
|
|
|
|
// Note that we intentionally sort in descending order on length, since
|
|
|
|
// long functions are more interesting than short functions.
|
|
|
|
return F1->getLength() > F2->getLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool opts::pretty::compareDataSymbols(
|
|
|
|
const std::unique_ptr<PDBSymbolData> &F1,
|
|
|
|
const std::unique_ptr<PDBSymbolData> &F2) {
|
|
|
|
assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None);
|
|
|
|
|
|
|
|
if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name)
|
|
|
|
return F1->getName() < F2->getName();
|
|
|
|
|
|
|
|
// Note that we intentionally sort in descending order on length, since
|
|
|
|
// large types are more interesting than short ones.
|
|
|
|
return getTypeLength(*F1) > getTypeLength(*F2);
|
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
static void dumpPretty(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2016-04-29 01:47:27 +02:00
|
|
|
|
2017-03-15 21:17:58 +01:00
|
|
|
const auto ReaderType =
|
|
|
|
opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
|
|
|
|
ExitOnErr(loadDataForPDB(ReaderType, Path, Session));
|
2016-04-29 01:47:27 +02:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::LoadAddress)
|
|
|
|
Session->setLoadAddress(opts::pretty::LoadAddress);
|
2015-01-27 23:40:14 +01:00
|
|
|
|
2017-03-23 16:28:15 +01:00
|
|
|
auto &Stream = outs();
|
|
|
|
const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET
|
|
|
|
? Stream.has_colors()
|
|
|
|
: opts::pretty::ColorOutput == cl::BOU_TRUE;
|
|
|
|
LinePrinter Printer(2, UseColor, Stream);
|
2015-02-27 10:15:59 +01:00
|
|
|
|
2015-02-10 23:43:25 +01:00
|
|
|
auto GlobalScope(Session->getGlobalScope());
|
2015-02-22 23:03:38 +01:00
|
|
|
std::string FileName(GlobalScope->getSymbolsFileName());
|
|
|
|
|
2015-02-27 10:15:59 +01:00
|
|
|
WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
|
|
|
|
Printer.Indent();
|
2015-02-22 23:03:38 +01:00
|
|
|
uint64_t FileSize = 0;
|
2015-02-27 10:15:59 +01:00
|
|
|
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
|
2015-10-15 03:27:19 +02:00
|
|
|
if (!sys::fs::file_size(FileName, FileSize)) {
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer << ": " << FileSize << " bytes";
|
|
|
|
} else {
|
|
|
|
Printer << ": (Unable to obtain file size)";
|
|
|
|
}
|
|
|
|
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
|
|
|
|
Printer << ": " << GlobalScope->getGuid();
|
|
|
|
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
|
|
|
|
Printer << ": " << GlobalScope->getAge();
|
|
|
|
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
|
|
|
|
Printer << ": ";
|
2015-02-22 23:03:38 +01:00
|
|
|
if (GlobalScope->hasCTypes())
|
|
|
|
outs() << "HasCTypes ";
|
|
|
|
if (GlobalScope->hasPrivateSymbols())
|
|
|
|
outs() << "HasPrivateSymbols ";
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.Unindent();
|
2015-02-22 23:03:38 +01:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Compilands) {
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
|
|
|
|
<< "---COMPILANDS---";
|
|
|
|
Printer.Indent();
|
2015-02-27 10:15:18 +01:00
|
|
|
auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
|
2015-02-27 10:15:59 +01:00
|
|
|
CompilandDumper Dumper(Printer);
|
2016-03-08 22:42:24 +01:00
|
|
|
CompilandDumpFlags options = CompilandDumper::Flags::None;
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Lines)
|
2016-03-08 22:42:24 +01:00
|
|
|
options = options | CompilandDumper::Flags::Lines;
|
2015-02-27 10:15:18 +01:00
|
|
|
while (auto Compiland = Compilands->getNext())
|
2016-03-08 22:42:24 +01:00
|
|
|
Dumper.start(*Compiland, options);
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.Unindent();
|
2015-02-27 10:15:18 +01:00
|
|
|
}
|
|
|
|
|
2017-04-07 01:43:12 +02:00
|
|
|
if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) {
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
|
|
|
|
Printer.Indent();
|
2015-03-04 07:09:53 +01:00
|
|
|
TypeDumper Dumper(Printer);
|
2015-03-01 07:51:29 +01:00
|
|
|
Dumper.start(*GlobalScope);
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.Unindent();
|
2015-02-22 23:03:38 +01:00
|
|
|
}
|
2015-01-28 01:33:00 +01:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Symbols) {
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
|
|
|
|
Printer.Indent();
|
2015-02-12 22:09:24 +01:00
|
|
|
auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
|
2015-02-27 10:15:59 +01:00
|
|
|
CompilandDumper Dumper(Printer);
|
2015-02-22 23:03:38 +01:00
|
|
|
while (auto Compiland = Compilands->getNext())
|
2015-03-01 07:51:29 +01:00
|
|
|
Dumper.start(*Compiland, true);
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.Unindent();
|
2015-02-27 10:15:18 +01:00
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Globals) {
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
|
|
|
|
Printer.Indent();
|
2017-05-14 03:13:40 +02:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) {
|
2015-02-27 10:15:59 +01:00
|
|
|
FunctionDumper Dumper(Printer);
|
2015-02-27 10:15:18 +01:00
|
|
|
auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
|
2017-05-14 03:13:40 +02:00
|
|
|
if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
|
|
|
|
while (auto Function = Functions->getNext()) {
|
|
|
|
Printer.NewLine();
|
|
|
|
Dumper.start(*Function, FunctionDumper::PointerType::None);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::vector<std::unique_ptr<PDBSymbolFunc>> Funcs;
|
|
|
|
while (auto Func = Functions->getNext())
|
|
|
|
Funcs.push_back(std::move(Func));
|
|
|
|
std::sort(Funcs.begin(), Funcs.end(),
|
|
|
|
opts::pretty::compareFunctionSymbols);
|
|
|
|
for (const auto &Func : Funcs) {
|
|
|
|
Printer.NewLine();
|
|
|
|
Dumper.start(*Func, FunctionDumper::PointerType::None);
|
|
|
|
}
|
2015-02-27 10:15:59 +01:00
|
|
|
}
|
2015-02-27 10:15:18 +01:00
|
|
|
}
|
2017-05-14 03:13:40 +02:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) {
|
2015-02-27 10:15:18 +01:00
|
|
|
auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
|
2015-02-27 10:15:59 +01:00
|
|
|
VariableDumper Dumper(Printer);
|
2017-05-14 03:13:40 +02:00
|
|
|
if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) {
|
|
|
|
while (auto Var = Vars->getNext())
|
|
|
|
Dumper.start(*Var);
|
|
|
|
} else {
|
|
|
|
std::vector<std::unique_ptr<PDBSymbolData>> Datas;
|
|
|
|
while (auto Var = Vars->getNext())
|
|
|
|
Datas.push_back(std::move(Var));
|
|
|
|
std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols);
|
|
|
|
for (const auto &Var : Datas)
|
|
|
|
Dumper.start(*Var);
|
|
|
|
}
|
2015-02-27 10:15:18 +01:00
|
|
|
}
|
2017-05-14 03:13:40 +02:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) {
|
2015-02-27 10:15:18 +01:00
|
|
|
auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
|
2015-02-27 10:15:59 +01:00
|
|
|
CompilandDumper Dumper(Printer);
|
2015-02-27 10:15:18 +01:00
|
|
|
while (auto Thunk = Thunks->getNext())
|
2015-03-01 07:51:29 +01:00
|
|
|
Dumper.dump(*Thunk);
|
2015-02-27 10:15:18 +01:00
|
|
|
}
|
2015-02-27 10:15:59 +01:00
|
|
|
Printer.Unindent();
|
2015-01-28 01:33:00 +01:00
|
|
|
}
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Externals) {
|
2015-05-01 22:24:26 +02:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
|
|
|
|
Printer.Indent();
|
|
|
|
ExternalSymbolDumper Dumper(Printer);
|
|
|
|
Dumper.start(*GlobalScope);
|
|
|
|
}
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::Lines) {
|
2016-03-08 22:42:24 +01:00
|
|
|
Printer.NewLine();
|
|
|
|
}
|
2015-01-28 01:33:00 +01:00
|
|
|
outs().flush();
|
|
|
|
}
|
|
|
|
|
2017-05-19 01:03:41 +02:00
|
|
|
static void mergePdbs() {
|
|
|
|
BumpPtrAllocator Allocator;
|
|
|
|
TypeTableBuilder MergedTpi(Allocator);
|
|
|
|
TypeTableBuilder MergedIpi(Allocator);
|
|
|
|
|
|
|
|
// Create a Tpi and Ipi type table with all types from all input files.
|
|
|
|
for (const auto &Path : opts::merge::InputFilenames) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
|
|
|
auto &File = loadPDB(Path, Session);
|
2017-05-22 23:07:43 +02:00
|
|
|
SmallVector<TypeIndex, 128> TypeMap;
|
|
|
|
SmallVector<TypeIndex, 128> IdMap;
|
2017-05-19 01:03:41 +02:00
|
|
|
if (File.hasPDBTpiStream()) {
|
|
|
|
auto &Tpi = ExitOnErr(File.getPDBTpiStream());
|
2017-05-22 23:07:43 +02:00
|
|
|
ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr,
|
2017-05-24 02:35:32 +02:00
|
|
|
Tpi.typeArray()));
|
2017-05-19 01:03:41 +02:00
|
|
|
}
|
|
|
|
if (File.hasPDBIpiStream()) {
|
|
|
|
auto &Ipi = ExitOnErr(File.getPDBIpiStream());
|
2017-05-22 23:07:43 +02:00
|
|
|
ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap,
|
2017-05-24 02:35:32 +02:00
|
|
|
Ipi.typeArray()));
|
2017-05-19 01:03:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then write the PDB.
|
|
|
|
PDBFileBuilder Builder(Allocator);
|
|
|
|
ExitOnErr(Builder.initialize(4096));
|
|
|
|
// Add each of the reserved streams. We might not put any data in them,
|
|
|
|
// but at least they have to be present.
|
|
|
|
for (uint32_t I = 0; I < kSpecialStreamCount; ++I)
|
|
|
|
ExitOnErr(Builder.getMsfBuilder().addStream(0));
|
|
|
|
|
|
|
|
auto &DestTpi = Builder.getTpiBuilder();
|
|
|
|
auto &DestIpi = Builder.getIpiBuilder();
|
[PDB] Hash types up front when merging types instead of using StringMap
Summary:
First, StringMap uses llvm::HashString, which is only good for short
identifiers and really bad for large blobs of binary data like type
records. Moving to `DenseMap<StringRef, TypeIndex>` with some tricks for
memory allocation fixes that.
Unfortunately, that didn't buy very much performance. Profiling showed
that we spend a long time during DenseMap growth rehashing existing
entries. Also, in general, DenseMap is faster when the keys are small.
This change takes that to the logical conclusion by introducing a small
wrapper value type around a pointer to key data. The key data contains a
precomputed hash, the original record data (pointer and size), and the
type index, which is the "value" of our original map.
This reduces the time to produce llvm-as.exe and llvm-as.pdb from ~15s
on my machine to 3.5s, which is about a 4x improvement.
Reviewers: zturner, inglorion, ruiu
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D33428
llvm-svn: 303665
2017-05-23 20:23:59 +02:00
|
|
|
MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef<uint8_t> Data) {
|
|
|
|
DestTpi.addTypeRecord(Data, None);
|
|
|
|
});
|
|
|
|
MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef<uint8_t> Data) {
|
|
|
|
DestIpi.addTypeRecord(Data, None);
|
|
|
|
});
|
2017-05-19 01:03:41 +02:00
|
|
|
|
2017-05-19 08:25:09 +02:00
|
|
|
SmallString<64> OutFile(opts::merge::PdbOutputFile);
|
2017-05-19 01:03:41 +02:00
|
|
|
if (OutFile.empty()) {
|
|
|
|
OutFile = opts::merge::InputFilenames[0];
|
|
|
|
llvm::sys::path::replace_extension(OutFile, "merged.pdb");
|
|
|
|
}
|
|
|
|
ExitOnErr(Builder.commit(OutFile));
|
|
|
|
}
|
|
|
|
|
2015-01-27 21:46:21 +01:00
|
|
|
int main(int argc_, const char *argv_[]) {
|
|
|
|
// Print a stack trace if we signal out.
|
2016-06-09 02:53:21 +02:00
|
|
|
sys::PrintStackTraceOnErrorSignal(argv_[0]);
|
2015-01-27 21:46:21 +01:00
|
|
|
PrettyStackTraceProgram X(argc_, argv_);
|
|
|
|
|
2016-05-28 20:25:15 +02:00
|
|
|
ExitOnErr.setBanner("llvm-pdbdump: ");
|
|
|
|
|
2015-01-27 21:46:21 +01:00
|
|
|
SmallVector<const char *, 256> argv;
|
2015-10-15 03:27:19 +02:00
|
|
|
SpecificBumpPtrAllocator<char> ArgAllocator;
|
2016-05-28 20:25:15 +02:00
|
|
|
ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
|
|
|
|
argv, makeArrayRef(argv_, argc_), ArgAllocator)));
|
2015-01-27 21:46:21 +01:00
|
|
|
|
|
|
|
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
|
|
|
|
|
|
|
cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
|
2016-09-09 20:17:52 +02:00
|
|
|
if (!opts::raw::DumpBlockRangeOpt.empty()) {
|
|
|
|
llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
|
|
|
|
llvm::SmallVector<llvm::StringRef, 2> Matches;
|
|
|
|
if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) {
|
|
|
|
errs() << "Argument '" << opts::raw::DumpBlockRangeOpt
|
|
|
|
<< "' invalid format.\n";
|
|
|
|
errs().flush();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
opts::raw::DumpBlockRange.emplace();
|
|
|
|
Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min);
|
|
|
|
if (!Matches[3].empty()) {
|
|
|
|
opts::raw::DumpBlockRange->Max.emplace();
|
|
|
|
Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max);
|
|
|
|
}
|
|
|
|
}
|
2016-03-08 22:42:24 +01:00
|
|
|
|
2017-01-12 23:28:15 +01:00
|
|
|
if (opts::RawSubcommand) {
|
|
|
|
if (opts::raw::RawAll) {
|
|
|
|
opts::raw::DumpHeaders = true;
|
|
|
|
opts::raw::DumpModules = true;
|
|
|
|
opts::raw::DumpModuleFiles = true;
|
|
|
|
opts::raw::DumpModuleSyms = true;
|
|
|
|
opts::raw::DumpGlobals = true;
|
|
|
|
opts::raw::DumpPublics = true;
|
|
|
|
opts::raw::DumpSectionHeaders = true;
|
|
|
|
opts::raw::DumpStreamSummary = true;
|
|
|
|
opts::raw::DumpPageStats = true;
|
|
|
|
opts::raw::DumpStreamBlocks = true;
|
|
|
|
opts::raw::DumpTpiRecords = true;
|
|
|
|
opts::raw::DumpTpiHash = true;
|
|
|
|
opts::raw::DumpIpiRecords = true;
|
|
|
|
opts::raw::DumpSectionMap = true;
|
|
|
|
opts::raw::DumpSectionContribs = true;
|
|
|
|
opts::raw::DumpLineInfo = true;
|
|
|
|
opts::raw::DumpFpo = true;
|
2017-01-20 23:42:09 +01:00
|
|
|
opts::raw::DumpStringTable = true;
|
2017-01-12 23:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (opts::raw::CompactRecords &&
|
|
|
|
(opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) {
|
|
|
|
errs() << "-compact-records is incompatible with -tpi-record-bytes and "
|
|
|
|
"-ipi-record-bytes.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
2015-03-02 05:39:56 +01:00
|
|
|
}
|
2015-01-27 21:46:21 +01:00
|
|
|
|
2016-06-02 07:07:49 +02:00
|
|
|
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
|
2015-01-27 21:46:21 +01:00
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::PdbToYamlSubcommand) {
|
2016-07-06 20:05:57 +02:00
|
|
|
pdb2Yaml(opts::pdb2yaml::InputFilename.front());
|
2016-06-30 19:42:48 +02:00
|
|
|
} else if (opts::YamlToPdbSubcommand) {
|
2017-05-17 22:46:48 +02:00
|
|
|
if (opts::yaml2pdb::YamlPdbOutputFile.empty()) {
|
|
|
|
SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue());
|
|
|
|
sys::path::replace_extension(OutputFilename, ".pdb");
|
|
|
|
opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str();
|
|
|
|
}
|
|
|
|
yamlToPdb(opts::yaml2pdb::InputFilename);
|
2017-02-01 19:30:22 +01:00
|
|
|
} else if (opts::AnalyzeSubcommand) {
|
|
|
|
dumpAnalysis(opts::analyze::InputFilename.front());
|
2016-06-30 19:42:48 +02:00
|
|
|
} else if (opts::PrettySubcommand) {
|
|
|
|
if (opts::pretty::Lines)
|
|
|
|
opts::pretty::Compilands = true;
|
|
|
|
|
|
|
|
if (opts::pretty::All) {
|
|
|
|
opts::pretty::Compilands = true;
|
|
|
|
opts::pretty::Symbols = true;
|
|
|
|
opts::pretty::Globals = true;
|
|
|
|
opts::pretty::Types = true;
|
|
|
|
opts::pretty::Externals = true;
|
|
|
|
opts::pretty::Lines = true;
|
|
|
|
}
|
|
|
|
|
2017-04-07 01:43:12 +02:00
|
|
|
if (opts::pretty::Types) {
|
|
|
|
opts::pretty::Classes = true;
|
|
|
|
opts::pretty::Typedefs = true;
|
|
|
|
opts::pretty::Enums = true;
|
|
|
|
}
|
|
|
|
|
2016-06-30 19:42:48 +02:00
|
|
|
// When adding filters for excluded compilands and types, we need to
|
2016-09-09 20:17:52 +02:00
|
|
|
// remember that these are regexes. So special characters such as * and \
|
|
|
|
// need to be escaped in the regex. In the case of a literal \, this means
|
|
|
|
// it needs to be escaped again in the C++. So matching a single \ in the
|
|
|
|
// input requires 4 \es in the C++.
|
2016-06-30 19:42:48 +02:00
|
|
|
if (opts::pretty::ExcludeCompilerGenerated) {
|
|
|
|
opts::pretty::ExcludeTypes.push_back("__vc_attributes");
|
|
|
|
opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*");
|
|
|
|
}
|
|
|
|
if (opts::pretty::ExcludeSystemLibraries) {
|
|
|
|
opts::pretty::ExcludeCompilands.push_back(
|
|
|
|
"f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld");
|
|
|
|
opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt");
|
|
|
|
opts::pretty::ExcludeCompilands.push_back(
|
|
|
|
"d:\\\\th.obj.x86fre\\\\minkernel");
|
|
|
|
}
|
|
|
|
std::for_each(opts::pretty::InputFilenames.begin(),
|
|
|
|
opts::pretty::InputFilenames.end(), dumpPretty);
|
|
|
|
} else if (opts::RawSubcommand) {
|
|
|
|
std::for_each(opts::raw::InputFilenames.begin(),
|
|
|
|
opts::raw::InputFilenames.end(), dumpRaw);
|
2017-03-14 00:28:25 +01:00
|
|
|
} else if (opts::DiffSubcommand) {
|
|
|
|
if (opts::diff::InputFilenames.size() != 2) {
|
|
|
|
errs() << "diff subcommand expects exactly 2 arguments.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]);
|
2017-05-19 01:03:41 +02:00
|
|
|
} else if (opts::MergeSubcommand) {
|
|
|
|
if (opts::merge::InputFilenames.size() < 2) {
|
|
|
|
errs() << "merge subcommand requires at least 2 input files.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
mergePdbs();
|
2016-06-14 22:48:36 +02:00
|
|
|
}
|
2015-01-27 21:46:21 +01:00
|
|
|
|
2016-05-06 22:51:57 +02:00
|
|
|
outs().flush();
|
2015-01-27 21:46:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|