2017-06-10 04:46:17 +08:00
|
|
|
//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
|
2015-01-28 04:46:21 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2017-03-14 07:28:25 +08:00
|
|
|
// Dumps debug information present in PDB files.
|
2015-01-28 04:46:21 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-10 04:46:17 +08:00
|
|
|
#include "llvm-pdbutil.h"
|
2017-02-02 02:30:22 +08:00
|
|
|
|
|
|
|
#include "Analyze.h"
|
2017-06-23 04:58:11 +08:00
|
|
|
#include "BytesOutputStyle.h"
|
2017-06-23 04:57:39 +08:00
|
|
|
#include "DumpOutputStyle.h"
|
2018-03-30 00:28:20 +08:00
|
|
|
#include "ExplainOutputStyle.h"
|
2017-09-02 04:06:56 +08:00
|
|
|
#include "InputFile.h"
|
2015-02-27 17:15:59 +08:00
|
|
|
#include "LinePrinter.h"
|
2016-06-04 03:28:33 +08:00
|
|
|
#include "OutputStyle.h"
|
2018-07-07 05:01:42 +08:00
|
|
|
#include "PrettyClassDefinitionDumper.h"
|
2017-01-11 08:35:43 +08:00
|
|
|
#include "PrettyCompilandDumper.h"
|
2018-07-07 05:01:42 +08:00
|
|
|
#include "PrettyEnumDumper.h"
|
2017-01-11 08:35:43 +08:00
|
|
|
#include "PrettyExternalSymbolDumper.h"
|
|
|
|
#include "PrettyFunctionDumper.h"
|
|
|
|
#include "PrettyTypeDumper.h"
|
2018-07-07 05:01:42 +08:00
|
|
|
#include "PrettyTypedefDumper.h"
|
2017-01-11 08:35:43 +08:00
|
|
|
#include "PrettyVariableDumper.h"
|
2016-06-07 04:37:05 +08:00
|
|
|
#include "YAMLOutputStyle.h"
|
2015-02-23 06:03:38 +08:00
|
|
|
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2015-10-15 09:27:19 +08:00
|
|
|
#include "llvm/ADT/BitVector.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2017-05-02 07:27:42 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2017-09-02 04:06:56 +08:00
|
|
|
#include "llvm/BinaryFormat/Magic.h"
|
2015-02-11 06:47:14 +08:00
|
|
|
#include "llvm/Config/config.h"
|
2017-12-01 02:39:50 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
|
2017-05-31 00:36:15 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
|
2017-05-20 03:26:58 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
2017-12-01 02:39:50 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
|
2017-06-14 23:59:27 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
|
2017-05-19 07:03:41 +08:00
|
|
|
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
2016-07-30 04:56:36 +08:00
|
|
|
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
2016-05-07 04:51:57 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/GenericError.h"
|
2015-02-11 06:43:25 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
|
2018-03-14 01:46:06 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
|
2015-02-11 06:43:25 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
|
2015-02-13 17:09:03 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
2017-04-28 00:11:19 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
|
2017-01-26 06:38:55 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
2018-04-03 02:35:21 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
2017-01-26 06:38:55 +08:00
|
|
|
#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-03 02:00:13 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
2017-01-26 06:38:55 +08: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 17:09:03 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDB.h"
|
2015-02-11 06:43:25 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
|
2015-02-27 17:15:18 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
2015-02-13 17:09:03 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
|
2015-02-27 17:15:18 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
2018-07-07 05:01:42 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
|
2015-02-27 17:15:18 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
|
2018-07-07 05:01:42 +08:00
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
2017-03-03 04:52:51 +08:00
|
|
|
#include "llvm/Support/BinaryByteStream.h"
|
2016-06-02 13:07:49 +08:00
|
|
|
#include "llvm/Support/COM.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2016-06-15 04:48:36 +08:00
|
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
2015-02-23 06:03:38 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
2018-04-14 02:26:06 +08:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2017-08-21 22:53:25 +08:00
|
|
|
#include "llvm/Support/LineIterator.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2015-10-15 09:27:19 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2017-05-18 04:46:48 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
2015-02-13 17:09:03 +08:00
|
|
|
#include "llvm/Support/Process.h"
|
2016-09-10 02:17:52 +08:00
|
|
|
#include "llvm/Support/Regex.h"
|
2016-05-05 00:09:04 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2016-04-22 20:04:42 +08:00
|
|
|
#include "llvm/Support/Signals.h"
|
2016-04-26 01:38:08 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2015-01-28 04:46:21 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
2016-06-03 11:25:59 +08:00
|
|
|
using namespace llvm::codeview;
|
2016-07-23 03:56:05 +08:00
|
|
|
using namespace llvm::msf;
|
2016-04-30 01:28:47 +08:00
|
|
|
using namespace llvm::pdb;
|
2015-01-28 04:46:21 +08:00
|
|
|
|
|
|
|
namespace opts {
|
2015-02-16 04:27:53 +08:00
|
|
|
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
|
2017-06-23 04:58:11 +08:00
|
|
|
cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::SubCommand
|
|
|
|
PrettySubcommand("pretty",
|
|
|
|
"Dump semantic information about types and symbols");
|
2017-03-14 07:28:25 +08:00
|
|
|
|
2016-07-01 01:43:00 +08:00
|
|
|
cl::SubCommand
|
|
|
|
YamlToPdbSubcommand("yaml2pdb",
|
|
|
|
"Generate a PDB file from a YAML description");
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::SubCommand
|
|
|
|
PdbToYamlSubcommand("pdb2yaml",
|
|
|
|
"Generate a detailed YAML description of a PDB File");
|
2015-01-28 04:46:21 +08:00
|
|
|
|
2017-02-02 02:30:22 +08:00
|
|
|
cl::SubCommand
|
|
|
|
AnalyzeSubcommand("analyze",
|
|
|
|
"Analyze various aspects of a PDB's structure");
|
|
|
|
|
2017-05-19 07:03:41 +08:00
|
|
|
cl::SubCommand MergeSubcommand("merge",
|
|
|
|
"Merge multiple PDBs into a single PDB");
|
|
|
|
|
2018-03-30 00:28:20 +08:00
|
|
|
cl::SubCommand ExplainSubcommand("explain",
|
|
|
|
"Explain the meaning of a file offset");
|
|
|
|
|
2018-04-03 02:35:21 +08:00
|
|
|
cl::SubCommand ExportSubcommand("export",
|
|
|
|
"Write binary data from a stream to a file");
|
|
|
|
|
2015-03-02 12:39:56 +08: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 07:18:21 +08:00
|
|
|
cl::OptionCategory FilterCategory("Filtering and Sorting Options");
|
2015-05-02 04:24:26 +08:00
|
|
|
cl::OptionCategory OtherOptions("Other Options");
|
2016-07-01 01:42:48 +08:00
|
|
|
|
2017-06-27 01:22:36 +08:00
|
|
|
cl::ValuesClass ChunkValues = cl::values(
|
|
|
|
clEnumValN(ModuleSubsection::CrossScopeExports, "cme",
|
|
|
|
"Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::CrossScopeImports, "cmi",
|
|
|
|
"Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::FileChecksums, "fc",
|
|
|
|
"File checksums (DEBUG_S_CHECKSUMS subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::InlineeLines, "ilines",
|
|
|
|
"Inlinee lines (DEBUG_S_INLINEELINES subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::Lines, "lines",
|
|
|
|
"Lines (DEBUG_S_LINES subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::StringTable, "strings",
|
|
|
|
"String Table (DEBUG_S_STRINGTABLE subsection) (not "
|
|
|
|
"typically present in PDB file)"),
|
|
|
|
clEnumValN(ModuleSubsection::FrameData, "frames",
|
|
|
|
"Frame Data (DEBUG_S_FRAMEDATA subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::Symbols, "symbols",
|
|
|
|
"Symbols (DEBUG_S_SYMBOLS subsection) (not typically "
|
|
|
|
"present in PDB file)"),
|
|
|
|
clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas",
|
|
|
|
"COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"),
|
|
|
|
clEnumValN(ModuleSubsection::Unknown, "unknown",
|
|
|
|
"Any subsection not covered by another option"),
|
|
|
|
clEnumValN(ModuleSubsection::All, "all", "All known subsections"));
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
namespace pretty {
|
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
|
|
|
cl::OneOrMore, cl::sub(PrettySubcommand));
|
2015-03-02 12:39:56 +08:00
|
|
|
|
2018-03-14 01:46:06 +08:00
|
|
|
cl::opt<bool> InjectedSources("injected-sources",
|
|
|
|
cl::desc("Display injected sources"),
|
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
|
|
|
cl::opt<bool> ShowInjectedSourceContent(
|
|
|
|
"injected-source-content",
|
|
|
|
cl::desc("When displaying an injected source, display the file content"),
|
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
|
|
|
|
2018-07-07 05:01:42 +08:00
|
|
|
cl::list<std::string> WithName(
|
|
|
|
"with-name",
|
|
|
|
cl::desc("Display any symbol or type with the specified exact name"),
|
|
|
|
cl::cat(TypeCategory), cl::ZeroOrMore, cl::sub(PrettySubcommand));
|
|
|
|
|
2015-03-02 12:39:56 +08:00
|
|
|
cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-05-14 09:13:40 +08:00
|
|
|
cl::opt<bool> Symbols("module-syms",
|
|
|
|
cl::desc("Display symbols for each compiland"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-03-02 12:39:56 +08:00
|
|
|
cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-05-02 04:24:26 +08:00
|
|
|
cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2017-05-14 09:13:40 +08: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 07:43:12 +08: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 09:13:40 +08: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-14 05:11:00 +08:00
|
|
|
cl::opt<ClassSortMode> ClassOrder(
|
|
|
|
"class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None),
|
2017-04-25 01:47:24 +08: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-26 04:22:29 +08: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-14 05:11:00 +08: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 07:18:21 +08:00
|
|
|
cl::opt<ClassDefinitionFormat> ClassFormat(
|
|
|
|
"class-definitions", cl::desc("Class definition format"),
|
2017-04-25 01:47:52 +08: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 07:18:21 +08:00
|
|
|
cl::values(
|
2017-04-25 01:47:52 +08:00
|
|
|
clEnumValN(ClassDefinitionFormat::All, "all",
|
2017-04-13 07:18:51 +08:00
|
|
|
"Display all class members including data, constants, "
|
2017-04-14 05:11:00 +08:00
|
|
|
"typedefs, functions, etc"),
|
2017-04-25 01:47:52 +08: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 07:18:21 +08: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-25 01:47:52 +08: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 07:43:12 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
|
|
|
|
cl::sub(PrettySubcommand));
|
2015-03-02 12:39:56 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
|
2015-03-01 14:49:49 +08:00
|
|
|
|
2015-05-02 04:24:26 +08:00
|
|
|
cl::opt<uint64_t> LoadAddress(
|
|
|
|
"load-address",
|
|
|
|
cl::desc("Assume the module is loaded at the specified address"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(OtherOptions), cl::sub(PrettySubcommand));
|
2017-03-16 04:17:58 +08:00
|
|
|
cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"),
|
2017-03-23 23:28:15 +08: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-07-01 01:42:48 +08: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-30 03:49:06 +08:00
|
|
|
|
|
|
|
cl::list<std::string> IncludeTypes(
|
|
|
|
"include-types",
|
|
|
|
cl::desc("Include only types which match a regular expression"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-30 03:49:06 +08:00
|
|
|
cl::list<std::string> IncludeSymbols(
|
|
|
|
"include-symbols",
|
|
|
|
cl::desc("Include only symbols which match a regular expression"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-09-30 03:49:06 +08:00
|
|
|
cl::list<std::string> IncludeCompilands(
|
|
|
|
"include-compilands",
|
|
|
|
cl::desc("Include only compilands those which match a regular expression"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2017-04-14 05:11:00 +08: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-26 04:22:29 +08: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-30 03:49:06 +08:00
|
|
|
|
2015-03-02 12:39:56 +08:00
|
|
|
cl::opt<bool> ExcludeCompilerGenerated(
|
|
|
|
"no-compiler-generated",
|
|
|
|
cl::desc("Don't show compiler generated types and symbols"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-03-02 12:39:56 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
ExcludeSystemLibraries("no-system-libs",
|
|
|
|
cl::desc("Don't show symbols from system libraries"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2017-04-07 07:43:39 +08:00
|
|
|
|
2015-03-04 14:09:53 +08:00
|
|
|
cl::opt<bool> NoEnumDefs("no-enum-definitions",
|
|
|
|
cl::desc("Don't display full enum definitions"),
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
2015-01-28 04:46:21 +08:00
|
|
|
}
|
|
|
|
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::OptionCategory FileOptions("Module & File Options");
|
|
|
|
|
2017-06-23 04:58:11 +08:00
|
|
|
namespace bytes {
|
2017-06-24 05:11:54 +08:00
|
|
|
cl::OptionCategory MsfBytes("MSF File Options");
|
|
|
|
cl::OptionCategory DbiBytes("Dbi Stream Options");
|
|
|
|
cl::OptionCategory PdbBytes("PDB Stream Options");
|
2017-06-24 05:50:54 +08:00
|
|
|
cl::OptionCategory Types("Type Options");
|
2017-06-24 07:08:57 +08:00
|
|
|
cl::OptionCategory ModuleCategory("Module Options");
|
2017-06-24 05:11:54 +08:00
|
|
|
|
2017-06-24 03:54:44 +08:00
|
|
|
llvm::Optional<NumberRange> DumpBlockRange;
|
|
|
|
llvm::Optional<NumberRange> DumpByteRange;
|
|
|
|
|
|
|
|
cl::opt<std::string> DumpBlockRangeOpt(
|
|
|
|
"block-range", cl::value_desc("start[-end]"),
|
|
|
|
cl::desc("Dump binary data from specified range of blocks."),
|
2017-06-24 05:11:54 +08:00
|
|
|
cl::sub(BytesSubcommand), cl::cat(MsfBytes));
|
2017-06-23 04:58:11 +08:00
|
|
|
|
|
|
|
cl::opt<std::string>
|
2017-06-24 03:54:44 +08:00
|
|
|
DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"),
|
|
|
|
cl::desc("Dump binary data from specified range of bytes"),
|
2017-06-24 05:11:54 +08:00
|
|
|
cl::sub(BytesSubcommand), cl::cat(MsfBytes));
|
2017-06-23 04:58:11 +08:00
|
|
|
|
|
|
|
cl::list<std::string>
|
|
|
|
DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
|
|
|
|
cl::desc("Dump binary data from specified streams. Format "
|
|
|
|
"is SN[:Start][@Size]"),
|
2017-06-24 05:11:54 +08:00
|
|
|
cl::sub(BytesSubcommand), cl::cat(MsfBytes));
|
2017-06-23 04:58:11 +08:00
|
|
|
|
2017-06-24 04:18:38 +08:00
|
|
|
cl::opt<bool> NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"),
|
2017-06-24 05:11:54 +08:00
|
|
|
cl::sub(BytesSubcommand), cl::cat(PdbBytes));
|
2017-08-03 06:25:52 +08:00
|
|
|
cl::opt<bool> Fpm("fpm", cl::desc("Dump free page map"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(MsfBytes));
|
2017-06-24 05:11:54 +08:00
|
|
|
|
|
|
|
cl::opt<bool> SectionContributions("sc", cl::desc("Dump section contributions"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
|
|
|
cl::opt<bool> SectionMap("sm", cl::desc("Dump section map"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
|
|
|
cl::opt<bool> ModuleInfos("modi", cl::desc("Dump module info"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
|
|
|
cl::opt<bool> FileInfo("files", cl::desc("Dump source file info"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
|
|
|
cl::opt<bool> TypeServerMap("type-server", cl::desc("Dump type server map"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
|
|
|
cl::opt<bool> ECData("ec", cl::desc("Dump edit and continue map"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(DbiBytes));
|
2017-06-24 04:18:38 +08:00
|
|
|
|
2017-06-24 05:50:54 +08:00
|
|
|
cl::list<uint32_t>
|
|
|
|
TypeIndex("type",
|
|
|
|
cl::desc("Dump the type record with the given type index"),
|
|
|
|
cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
|
|
|
|
cl::cat(TypeCategory));
|
|
|
|
cl::list<uint32_t>
|
|
|
|
IdIndex("id", cl::desc("Dump the id record with the given type index"),
|
|
|
|
cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand),
|
|
|
|
cl::cat(TypeCategory));
|
2017-06-24 07:08:57 +08:00
|
|
|
|
|
|
|
cl::opt<uint32_t> ModuleIndex(
|
|
|
|
"mod",
|
|
|
|
cl::desc(
|
|
|
|
"Limit options in the Modules category to the specified module index"),
|
|
|
|
cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
|
|
|
|
cl::opt<bool> ModuleSyms("syms", cl::desc("Dump symbol record substream"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
|
|
|
|
cl::opt<bool> ModuleC11("c11-chunks", cl::Hidden,
|
|
|
|
cl::desc("Dump C11 CodeView debug chunks"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
|
2017-06-27 01:22:36 +08:00
|
|
|
cl::opt<bool> ModuleC13("chunks",
|
|
|
|
cl::desc("Dump C13 CodeView debug chunk subsection"),
|
2017-06-24 07:08:57 +08:00
|
|
|
cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
|
2017-06-27 01:22:36 +08:00
|
|
|
cl::opt<bool> SplitChunks(
|
|
|
|
"split-chunks",
|
|
|
|
cl::desc(
|
|
|
|
"When dumping debug chunks, show a different section for each chunk"),
|
|
|
|
cl::sub(BytesSubcommand), cl::cat(ModuleCategory));
|
2017-06-23 04:58:11 +08:00
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
|
|
|
cl::OneOrMore, cl::sub(BytesSubcommand));
|
|
|
|
|
|
|
|
} // namespace bytes
|
|
|
|
|
2017-06-23 04:57:39 +08:00
|
|
|
namespace dump {
|
2016-05-29 02:25:15 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::OptionCategory MsfOptions("MSF Container Options");
|
|
|
|
cl::OptionCategory TypeOptions("Type Record Options");
|
|
|
|
cl::OptionCategory SymbolOptions("Symbol Options");
|
|
|
|
cl::OptionCategory MiscOptions("Miscellaneous Options");
|
2016-05-05 00:09:04 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
// MSF OPTIONS
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpStreams("streams",
|
|
|
|
cl::desc("dump summary of the PDB streams"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
2017-06-24 04:28:14 +08:00
|
|
|
cl::opt<bool> DumpStreamBlocks(
|
|
|
|
"stream-blocks",
|
|
|
|
cl::desc("Add block information to the output of -streams"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
2017-09-01 04:43:22 +08:00
|
|
|
cl::opt<bool> DumpSymbolStats(
|
|
|
|
"sym-stats",
|
|
|
|
cl::desc("Dump a detailed breakdown of symbol usage/size for each module"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
|
|
|
|
|
|
|
cl::opt<bool> DumpUdtStats(
|
|
|
|
"udt-stats",
|
|
|
|
cl::desc("Dump a detailed breakdown of S_UDT record usage / stats"),
|
|
|
|
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
2016-05-05 00:09:04 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
// TYPE OPTIONS
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpTypes("types",
|
|
|
|
cl::desc("dump CodeView type records from TPI stream"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpTypeData(
|
|
|
|
"type-data",
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::desc("dump CodeView type record raw bytes from TPI stream"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
|
2017-06-16 07:04:42 +08:00
|
|
|
cl::opt<bool> DumpTypeExtras("type-extras",
|
|
|
|
cl::desc("dump type hashes and index offsets"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
|
2017-06-17 07:42:15 +08:00
|
|
|
cl::list<uint32_t> DumpTypeIndex(
|
2017-07-06 02:43:25 +08:00
|
|
|
"type-index", cl::ZeroOrMore, cl::CommaSeparated,
|
2017-06-17 07:42:15 +08:00
|
|
|
cl::desc("only dump types with the specified hexadecimal type index"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-17 07:42:15 +08:00
|
|
|
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpIds("ids",
|
|
|
|
cl::desc("dump CodeView type records from IPI stream"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::opt<bool>
|
2017-06-16 06:24:24 +08:00
|
|
|
DumpIdData("id-data",
|
|
|
|
cl::desc("dump CodeView type record raw bytes from IPI stream"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
|
2017-06-16 07:04:42 +08:00
|
|
|
cl::opt<bool> DumpIdExtras("id-extras",
|
|
|
|
cl::desc("dump id hashes and index offsets"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-17 07:42:15 +08:00
|
|
|
cl::list<uint32_t> DumpIdIndex(
|
2017-07-06 02:43:25 +08:00
|
|
|
"id-index", cl::ZeroOrMore, cl::CommaSeparated,
|
2017-06-17 07:42:15 +08:00
|
|
|
cl::desc("only dump ids with the specified hexadecimal type index"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
2017-06-16 07:04:42 +08:00
|
|
|
|
2017-07-01 02:15:47 +08:00
|
|
|
cl::opt<bool> DumpTypeDependents(
|
|
|
|
"dependents",
|
|
|
|
cl::desc("In conjunection with -type-index and -id-index, dumps the entire "
|
|
|
|
"dependency graph for the specified index instead of "
|
|
|
|
"just the single record with the specified index"),
|
|
|
|
cl::cat(TypeOptions), cl::sub(DumpSubcommand));
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
// SYMBOL OPTIONS
|
2017-07-26 08:40:36 +08:00
|
|
|
cl::opt<bool> DumpGlobals("globals", cl::desc("dump Globals symbol records"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
|
|
|
cl::opt<bool> DumpGlobalExtras("global-extras", cl::desc("dump Globals hashes"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2017-06-16 04:55:51 +08:00
|
|
|
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2017-07-22 02:28:55 +08:00
|
|
|
cl::opt<bool> DumpPublicExtras("public-extras",
|
|
|
|
cl::desc("dump Publics hashes and address maps"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2018-07-06 10:59:25 +08:00
|
|
|
cl::opt<bool>
|
|
|
|
DumpGSIRecords("gsi-records",
|
|
|
|
cl::desc("dump public / global common record stream"),
|
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::opt<bool>
|
2017-06-16 06:24:24 +08:00
|
|
|
DumpSymRecordBytes("sym-data",
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::desc("dump CodeView symbol record raw bytes"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
|
2016-06-03 02:20:20 +08:00
|
|
|
|
2017-06-16 06:24:24 +08:00
|
|
|
// MODULE & FILE OPTIONS
|
|
|
|
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::opt<bool> DumpModuleFiles(
|
|
|
|
"files",
|
2017-06-16 07:56:19 +08:00
|
|
|
cl::desc("Dump the source files that contribute to each module's."),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 07:56:19 +08:00
|
|
|
cl::opt<bool> DumpLines(
|
|
|
|
"l",
|
|
|
|
cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 07:56:19 +08:00
|
|
|
cl::opt<bool> DumpInlineeLines(
|
|
|
|
"il",
|
|
|
|
cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 08:04:24 +08:00
|
|
|
cl::opt<bool> DumpXmi(
|
|
|
|
"xmi",
|
|
|
|
cl::desc(
|
|
|
|
"dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 08:04:24 +08:00
|
|
|
cl::opt<bool> DumpXme(
|
|
|
|
"xme",
|
|
|
|
cl::desc(
|
|
|
|
"dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-08-04 07:11:52 +08:00
|
|
|
cl::opt<uint32_t> DumpModi("modi", cl::Optional,
|
|
|
|
cl::desc("For all options that iterate over "
|
|
|
|
"modules, limit to the specified module"),
|
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-08-21 22:53:25 +08:00
|
|
|
cl::opt<bool> JustMyCode("jmc", cl::Optional,
|
|
|
|
cl::desc("For all options that iterate over modules, "
|
|
|
|
"ignore modules from system libraries"),
|
|
|
|
cl::cat(FileOptions), cl::sub(DumpSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
// MISCELLANEOUS OPTIONS
|
2018-03-24 02:43:39 +08:00
|
|
|
cl::opt<bool> DumpNamedStreams("named-streams",
|
|
|
|
cl::desc("dump PDB named stream table"),
|
|
|
|
cl::cat(MiscOptions), cl::sub(DumpSubcommand));
|
|
|
|
|
2017-01-21 06:42:09 +08:00
|
|
|
cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MiscOptions), cl::sub(DumpSubcommand));
|
2018-03-24 02:43:39 +08:00
|
|
|
cl::opt<bool> DumpStringTableDetails("string-table-details",
|
|
|
|
cl::desc("dump PDB String Table Details"),
|
|
|
|
cl::cat(MiscOptions),
|
|
|
|
cl::sub(DumpSubcommand));
|
2017-01-21 06:42:09 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::opt<bool> DumpSectionContribs("section-contribs",
|
|
|
|
cl::desc("dump section contributions"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MiscOptions),
|
|
|
|
cl::sub(DumpSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MiscOptions), cl::sub(DumpSubcommand));
|
2017-08-05 04:02:38 +08:00
|
|
|
cl::opt<bool> DumpSectionHeaders("section-headers",
|
|
|
|
cl::desc("Dump image section headers"),
|
|
|
|
cl::cat(MiscOptions), cl::sub(DumpSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
|
2016-07-01 01:43:00 +08:00
|
|
|
cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::cat(MiscOptions), cl::sub(DumpSubcommand));
|
2016-05-14 05:21:53 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
cl::list<std::string> InputFilenames(cl::Positional,
|
|
|
|
cl::desc("<input PDB files>"),
|
2017-06-23 04:57:39 +08:00
|
|
|
cl::OneOrMore, cl::sub(DumpSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
}
|
2016-06-02 13:07:49 +08:00
|
|
|
|
2016-07-01 01:42:48 +08: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 13:07:49 +08:00
|
|
|
|
2017-05-18 04:46:48 +08:00
|
|
|
cl::opt<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input YAML file>"), cl::Required,
|
|
|
|
cl::sub(YamlToPdbSubcommand));
|
2016-07-01 01:42:48 +08:00
|
|
|
}
|
2016-06-02 13:07:49 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
namespace pdb2yaml {
|
2017-05-27 07:46:20 +08:00
|
|
|
cl::opt<bool> All("all",
|
|
|
|
cl::desc("Dump everything we know how to dump."),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::opt<bool> NoFileHeaders("no-file-headers",
|
|
|
|
cl::desc("Do not dump MSF file headers"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-03-16 06:18:53 +08:00
|
|
|
cl::opt<bool> Minimal("minimal",
|
|
|
|
cl::desc("Don't write fields with default values"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-12 05:45:09 +08:00
|
|
|
|
2016-07-01 01:43:00 +08:00
|
|
|
cl::opt<bool> StreamMetadata(
|
|
|
|
"stream-metadata",
|
|
|
|
cl::desc("Dump the number of streams and each stream's size"),
|
2016-07-12 05:45:09 +08:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-01 01:43:00 +08:00
|
|
|
cl::opt<bool> StreamDirectory(
|
|
|
|
"stream-directory",
|
|
|
|
cl::desc("Dump each stream's block map (implies -stream-metadata)"),
|
2016-07-12 05:45:09 +08:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2016-07-16 06:16:56 +08:00
|
|
|
cl::opt<bool> PdbStream("pdb-stream",
|
|
|
|
cl::desc("Dump the PDB Stream (Stream 1)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-01-21 06:42:09 +08:00
|
|
|
|
|
|
|
cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-07-16 06:16:56 +08:00
|
|
|
cl::opt<bool> DbiStream("dbi-stream",
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::desc("Dump the DBI Stream Headers (Stream 2)"),
|
2016-07-16 06:16:56 +08:00
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
2017-04-26 04:22:02 +08:00
|
|
|
|
2016-08-19 00:49:29 +08:00
|
|
|
cl::opt<bool> TpiStream("tpi-stream",
|
|
|
|
cl::desc("Dump the TPI Stream (Stream 3)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2016-09-16 02:22:31 +08:00
|
|
|
cl::opt<bool> IpiStream("ipi-stream",
|
|
|
|
cl::desc("Dump the IPI Stream (Stream 5)"),
|
|
|
|
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
|
|
|
|
2017-06-09 07:39:33 +08:00
|
|
|
// MODULE & FILE OPTIONS
|
|
|
|
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::cat(FileOptions),
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::sub(PdbToYamlSubcommand));
|
|
|
|
cl::list<ModuleSubsection> DumpModuleSubsections(
|
|
|
|
"subsections", cl::ZeroOrMore, cl::CommaSeparated,
|
2017-06-27 01:22:36 +08:00
|
|
|
cl::desc("dump subsections from each module's debug stream"), ChunkValues,
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
|
2017-06-16 06:24:24 +08:00
|
|
|
cl::cat(FileOptions),
|
2017-06-09 07:39:33 +08:00
|
|
|
cl::sub(PdbToYamlSubcommand));
|
2017-06-16 06:24:24 +08:00
|
|
|
|
|
|
|
cl::list<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input PDB file>"), cl::Required,
|
|
|
|
cl::sub(PdbToYamlSubcommand));
|
|
|
|
} // namespace pdb2yaml
|
2017-06-09 07:39:33 +08:00
|
|
|
|
2017-02-02 02:30:22 +08: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 07:03:41 +08: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));
|
|
|
|
}
|
2018-03-30 00:28:20 +08:00
|
|
|
|
|
|
|
namespace explain {
|
|
|
|
cl::list<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input PDB file>"), cl::Required,
|
|
|
|
cl::sub(ExplainSubcommand));
|
|
|
|
|
2018-03-31 01:16:50 +08:00
|
|
|
cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"),
|
|
|
|
cl::sub(ExplainSubcommand), cl::OneOrMore);
|
2018-04-05 01:29:09 +08:00
|
|
|
|
|
|
|
cl::opt<InputFileType> InputType(
|
|
|
|
"input-type", cl::desc("Specify how to interpret the input file"),
|
|
|
|
cl::init(InputFileType::PDBFile), cl::Optional, cl::sub(ExplainSubcommand),
|
|
|
|
cl::values(clEnumValN(InputFileType::PDBFile, "pdb-file",
|
|
|
|
"Treat input as a PDB file (default)"),
|
|
|
|
clEnumValN(InputFileType::PDBStream, "pdb-stream",
|
|
|
|
"Treat input as raw contents of PDB stream"),
|
|
|
|
clEnumValN(InputFileType::DBIStream, "dbi-stream",
|
|
|
|
"Treat input as raw contents of DBI stream"),
|
|
|
|
clEnumValN(InputFileType::Names, "names-stream",
|
|
|
|
"Treat input as raw contents of /names named stream"),
|
|
|
|
clEnumValN(InputFileType::ModuleStream, "mod-stream",
|
|
|
|
"Treat input as raw contents of a module stream")));
|
2018-03-30 00:28:20 +08:00
|
|
|
} // namespace explain
|
2018-04-03 02:35:21 +08:00
|
|
|
|
|
|
|
namespace exportstream {
|
|
|
|
cl::list<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input PDB file>"), cl::Required,
|
|
|
|
cl::sub(ExportSubcommand));
|
|
|
|
cl::opt<std::string> OutputFile("out",
|
|
|
|
cl::desc("The file to write the stream to"),
|
|
|
|
cl::Required, cl::sub(ExportSubcommand));
|
|
|
|
cl::opt<std::string>
|
|
|
|
Stream("stream", cl::Required,
|
|
|
|
cl::desc("The index or name of the stream whose contents to export"),
|
|
|
|
cl::sub(ExportSubcommand));
|
|
|
|
cl::opt<bool> ForceName("name",
|
|
|
|
cl::desc("Force the interpretation of -stream as a "
|
|
|
|
"string, even if it is a valid integer"),
|
|
|
|
cl::sub(ExportSubcommand), cl::Optional,
|
|
|
|
cl::init(false));
|
|
|
|
} // namespace exportstream
|
2016-04-29 07:47:27 +08:00
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
static ExitOnError ExitOnErr;
|
|
|
|
|
2016-06-15 04:48:36 +08:00
|
|
|
static void yamlToPdb(StringRef Path) {
|
2016-07-23 03:56:26 +08:00
|
|
|
BumpPtrAllocator Allocator;
|
2016-06-15 04:48:36 +08: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-10 01:46:17 +08:00
|
|
|
pdb::yaml::PdbObject YamlObj(Allocator);
|
2016-06-15 04:48:36 +08:00
|
|
|
In >> YamlObj;
|
|
|
|
|
2016-07-23 03:56:26 +08:00
|
|
|
PDBFileBuilder Builder(Allocator);
|
2016-07-12 05:45:26 +08:00
|
|
|
|
2017-03-16 06:18:53 +08:00
|
|
|
uint32_t BlockSize = 4096;
|
|
|
|
if (YamlObj.Headers.hasValue())
|
|
|
|
BlockSize = YamlObj.Headers->SuperBlock.BlockSize;
|
|
|
|
ExitOnErr(Builder.initialize(BlockSize));
|
2016-09-15 07:00:02 +08: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-07 02:05:57 +08:00
|
|
|
|
2017-06-14 23:59:27 +08:00
|
|
|
StringsAndChecksums Strings;
|
|
|
|
Strings.setStrings(std::make_shared<DebugStringTableSubsection>());
|
|
|
|
|
2017-01-21 06:42:09 +08:00
|
|
|
if (YamlObj.StringTable.hasValue()) {
|
|
|
|
for (auto S : *YamlObj.StringTable)
|
2017-06-14 23:59:27 +08:00
|
|
|
Strings.strings()->insert(S);
|
2017-01-21 06:42:09 +08:00
|
|
|
}
|
|
|
|
|
2017-03-16 06:18:53 +08:00
|
|
|
pdb::yaml::PdbInfoStream DefaultInfoStream;
|
|
|
|
pdb::yaml::PdbDbiStream DefaultDbiStream;
|
|
|
|
pdb::yaml::PdbTpiStream DefaultTpiStream;
|
2017-05-23 05:07:43 +08:00
|
|
|
pdb::yaml::PdbTpiStream DefaultIpiStream;
|
2017-03-16 06:18:53 +08: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-17 04:19:11 +08:00
|
|
|
for (auto F : Info.Features)
|
|
|
|
InfoBuilder.addFeature(F);
|
2017-03-16 06:18:53 +08: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-17 04:19:11 +08:00
|
|
|
auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod));
|
2017-05-26 02:04:17 +08:00
|
|
|
ModiBuilder.setObjFileName(MI.Obj);
|
2017-03-16 06:18:53 +08:00
|
|
|
|
|
|
|
for (auto S : MI.SourceFiles)
|
2017-09-08 04:39:46 +08:00
|
|
|
ExitOnErr(DbiBuilder.addModuleSourceFile(ModiBuilder, S));
|
2017-03-16 06:18:53 +08:00
|
|
|
if (MI.Modi.hasValue()) {
|
|
|
|
const auto &ModiStream = *MI.Modi;
|
2017-06-02 05:52:41 +08:00
|
|
|
for (auto Symbol : ModiStream.Symbols) {
|
|
|
|
ModiBuilder.addSymbol(
|
|
|
|
Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb));
|
|
|
|
}
|
2016-07-22 23:46:37 +08:00
|
|
|
}
|
2017-05-03 00:56:09 +08:00
|
|
|
|
2017-06-14 23:59:27 +08:00
|
|
|
// Each module has its own checksum subsection, so scan for it every time.
|
|
|
|
Strings.setChecksums(nullptr);
|
|
|
|
CodeViewYAML::initializeStringsAndChecksums(MI.Subsections, Strings);
|
|
|
|
|
2017-06-09 08:28:08 +08:00
|
|
|
auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList(
|
|
|
|
Allocator, MI.Subsections, Strings));
|
2017-06-03 03:49:14 +08:00
|
|
|
for (auto &SS : CodeViewSubsections) {
|
2017-06-14 23:59:27 +08:00
|
|
|
ModiBuilder.addDebugSubsection(SS);
|
2017-05-02 07:27:42 +08:00
|
|
|
}
|
2016-07-12 05:45:26 +08:00
|
|
|
}
|
|
|
|
|
2017-03-16 06:18:53 +08:00
|
|
|
auto &TpiBuilder = Builder.getTpiBuilder();
|
|
|
|
const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream);
|
|
|
|
TpiBuilder.setVersionHeader(Tpi.Version);
|
2017-12-01 02:39:50 +08:00
|
|
|
AppendingTypeTableBuilder TS(Allocator);
|
2017-05-31 05:53:05 +08:00
|
|
|
for (const auto &R : Tpi.Records) {
|
[CodeView] Refactor / Rewrite TypeSerializer and TypeTableBuilder.
The motivation behind this patch is that future directions require us to
be able to compute the hash value of records independently of actually
using them for de-duplication.
The current structure of TypeSerializer / TypeTableBuilder being a
single entry point that takes an unserialized type record, and then
hashes and de-duplicates it is not flexible enough to allow this.
At the same time, the existing TypeSerializer is already extremely
complex for this very reason -- it tries to be too many things. In
addition to serializing, hashing, and de-duplicating, ti also supports
splitting up field list records and adding continuations. All of this
functionality crammed into this one class makes it very complicated to
work with and hard to maintain.
To solve all of these problems, I've re-written everything from scratch
and split the functionality into separate pieces that can easily be
reused. The end result is that one class TypeSerializer is turned into 3
new classes SimpleTypeSerializer, ContinuationRecordBuilder, and
TypeTableBuilder, each of which in isolation is simple and
straightforward.
A quick summary of these new classes and their responsibilities are:
- SimpleTypeSerializer : Turns a non-FieldList leaf type into a series of
bytes. Does not do any hashing. Every time you call it, it will
re-serialize and return bytes again. The same instance can be re-used
over and over to avoid re-allocations, and in exchange for this
optimization the bytes returned by the serializer only live until the
caller attempts to serialize a new record.
- ContinuationRecordBuilder : Turns a FieldList-like record into a series
of fragments. Does not do any hashing. Like SimpleTypeSerializer,
returns references to privately owned bytes, so the storage is
invalidated as soon as the caller tries to re-use the instance. Works
equally well for LF_FIELDLIST as it does for LF_METHODLIST, solving a
long-standing theoretical limitation of the previous implementation.
- TypeTableBuilder : Accepts sequences of bytes that the user has already
serialized, and inserts them by de-duplicating with a hash table. For
the sake of convenience and efficiency, this class internally stores a
SimpleTypeSerializer so that it can accept unserialized records. The
same is not true of ContinuationRecordBuilder. The user is required to
create their own instance of ContinuationRecordBuilder.
Differential Revision: https://reviews.llvm.org/D40518
llvm-svn: 319198
2017-11-29 02:33:17 +08:00
|
|
|
CVType Type = R.toCodeViewRecord(TS);
|
2017-05-31 05:53:05 +08:00
|
|
|
TpiBuilder.addTypeRecord(Type.RecordData, None);
|
|
|
|
}
|
2017-03-16 06:18:53 +08:00
|
|
|
|
2017-05-23 05:07:43 +08:00
|
|
|
const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream);
|
2017-03-16 06:18:53 +08:00
|
|
|
auto &IpiBuilder = Builder.getIpiBuilder();
|
|
|
|
IpiBuilder.setVersionHeader(Ipi.Version);
|
2017-05-31 05:53:05 +08:00
|
|
|
for (const auto &R : Ipi.Records) {
|
[CodeView] Refactor / Rewrite TypeSerializer and TypeTableBuilder.
The motivation behind this patch is that future directions require us to
be able to compute the hash value of records independently of actually
using them for de-duplication.
The current structure of TypeSerializer / TypeTableBuilder being a
single entry point that takes an unserialized type record, and then
hashes and de-duplicates it is not flexible enough to allow this.
At the same time, the existing TypeSerializer is already extremely
complex for this very reason -- it tries to be too many things. In
addition to serializing, hashing, and de-duplicating, ti also supports
splitting up field list records and adding continuations. All of this
functionality crammed into this one class makes it very complicated to
work with and hard to maintain.
To solve all of these problems, I've re-written everything from scratch
and split the functionality into separate pieces that can easily be
reused. The end result is that one class TypeSerializer is turned into 3
new classes SimpleTypeSerializer, ContinuationRecordBuilder, and
TypeTableBuilder, each of which in isolation is simple and
straightforward.
A quick summary of these new classes and their responsibilities are:
- SimpleTypeSerializer : Turns a non-FieldList leaf type into a series of
bytes. Does not do any hashing. Every time you call it, it will
re-serialize and return bytes again. The same instance can be re-used
over and over to avoid re-allocations, and in exchange for this
optimization the bytes returned by the serializer only live until the
caller attempts to serialize a new record.
- ContinuationRecordBuilder : Turns a FieldList-like record into a series
of fragments. Does not do any hashing. Like SimpleTypeSerializer,
returns references to privately owned bytes, so the storage is
invalidated as soon as the caller tries to re-use the instance. Works
equally well for LF_FIELDLIST as it does for LF_METHODLIST, solving a
long-standing theoretical limitation of the previous implementation.
- TypeTableBuilder : Accepts sequences of bytes that the user has already
serialized, and inserts them by de-duplicating with a hash table. For
the sake of convenience and efficiency, this class internally stores a
SimpleTypeSerializer so that it can accept unserialized records. The
same is not true of ContinuationRecordBuilder. The user is required to
create their own instance of ContinuationRecordBuilder.
Differential Revision: https://reviews.llvm.org/D40518
llvm-svn: 319198
2017-11-29 02:33:17 +08:00
|
|
|
CVType Type = R.toCodeViewRecord(TS);
|
2017-05-31 05:53:05 +08:00
|
|
|
IpiBuilder.addTypeRecord(Type.RecordData, None);
|
|
|
|
}
|
2016-09-16 02:22:31 +08:00
|
|
|
|
2017-06-14 23:59:27 +08:00
|
|
|
Builder.getStringTableBuilder().setStrings(*Strings.strings());
|
|
|
|
|
2016-10-01 04:34:44 +08:00
|
|
|
ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile));
|
2016-06-15 04:48:36 +08:00
|
|
|
}
|
|
|
|
|
2017-03-14 07:28:25 +08: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-07 02:05:57 +08:00
|
|
|
static void pdb2Yaml(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2017-03-14 07:28:25 +08:00
|
|
|
auto &File = loadPDB(Path, Session);
|
2016-07-07 02:05:57 +08:00
|
|
|
|
|
|
|
auto O = llvm::make_unique<YAMLOutputStyle>(File);
|
|
|
|
O = llvm::make_unique<YAMLOutputStyle>(File);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
static void dumpRaw(StringRef Path) {
|
2017-09-02 04:06:56 +08:00
|
|
|
InputFile IF = ExitOnErr(InputFile::open(Path));
|
2016-07-01 01:42:48 +08:00
|
|
|
|
2017-09-02 04:06:56 +08:00
|
|
|
auto O = llvm::make_unique<DumpOutputStyle>(IF);
|
2016-07-01 01:42:48 +08:00
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-06-23 04:58:11 +08:00
|
|
|
static void dumpBytes(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
|
|
|
auto &File = loadPDB(Path, Session);
|
|
|
|
|
|
|
|
auto O = llvm::make_unique<BytesOutputStyle>(File);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-02-02 02:30:22 +08:00
|
|
|
static void dumpAnalysis(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2017-03-14 07:28:25 +08:00
|
|
|
auto &File = loadPDB(Path, Session);
|
2017-02-02 02:30:22 +08:00
|
|
|
auto O = llvm::make_unique<AnalysisStyle>(File);
|
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
|
|
|
|
2017-05-14 09:13:40 +08: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);
|
|
|
|
}
|
|
|
|
|
2018-03-14 01:46:06 +08:00
|
|
|
static std::string stringOr(std::string Str, std::string IfEmpty) {
|
|
|
|
return (Str.empty()) ? IfEmpty : Str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) {
|
|
|
|
auto Sources = Session.getInjectedSources();
|
|
|
|
if (0 == Sources->getChildCount()) {
|
|
|
|
Printer.printLine("There are no injected sources.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (auto IS = Sources->getNext()) {
|
|
|
|
Printer.NewLine();
|
|
|
|
std::string File = stringOr(IS->getFileName(), "<null>");
|
|
|
|
uint64_t Size = IS->getCodeByteSize();
|
|
|
|
std::string Obj = stringOr(IS->getObjectFileName(), "<null>");
|
|
|
|
std::string VFName = stringOr(IS->getVirtualFileName(), "<null>");
|
|
|
|
uint32_t CRC = IS->getCrc32();
|
|
|
|
|
|
|
|
std::string CompressionStr;
|
|
|
|
llvm::raw_string_ostream Stream(CompressionStr);
|
|
|
|
Stream << IS->getCompression();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Path).get() << File;
|
|
|
|
Printer << " (";
|
|
|
|
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Size;
|
|
|
|
Printer << " bytes): ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "obj";
|
|
|
|
Printer << "=";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Path).get() << Obj;
|
|
|
|
Printer << ", ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "vname";
|
|
|
|
Printer << "=";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Path).get() << VFName;
|
|
|
|
Printer << ", ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "crc";
|
|
|
|
Printer << "=";
|
|
|
|
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << CRC;
|
|
|
|
Printer << ", ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "compression";
|
|
|
|
Printer << "=";
|
|
|
|
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Stream.str();
|
|
|
|
|
|
|
|
if (!opts::pretty::ShowInjectedSourceContent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Set the indent level to 0 when printing file content.
|
|
|
|
int Indent = Printer.getIndentLevel();
|
|
|
|
Printer.Unindent(Indent);
|
|
|
|
|
|
|
|
Printer.printLine(IS->getCode());
|
|
|
|
|
|
|
|
// Re-indent back to the original level.
|
|
|
|
Printer.Indent(Indent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
static void dumpPretty(StringRef Path) {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2016-04-29 07:47:27 +08:00
|
|
|
|
2017-03-16 04:17:58 +08:00
|
|
|
const auto ReaderType =
|
|
|
|
opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA;
|
|
|
|
ExitOnErr(loadDataForPDB(ReaderType, Path, Session));
|
2016-04-29 07:47:27 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::LoadAddress)
|
|
|
|
Session->setLoadAddress(opts::pretty::LoadAddress);
|
2015-01-28 06:40:14 +08:00
|
|
|
|
2017-03-23 23:28:15 +08: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 17:15:59 +08:00
|
|
|
|
2015-02-11 06:43:25 +08:00
|
|
|
auto GlobalScope(Session->getGlobalScope());
|
2018-03-07 10:23:08 +08:00
|
|
|
if (!GlobalScope)
|
|
|
|
return;
|
2015-02-23 06:03:38 +08:00
|
|
|
std::string FileName(GlobalScope->getSymbolsFileName());
|
|
|
|
|
2015-02-27 17:15:59 +08:00
|
|
|
WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
|
|
|
|
WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
|
|
|
|
Printer.Indent();
|
2015-02-23 06:03:38 +08:00
|
|
|
uint64_t FileSize = 0;
|
2015-02-27 17:15:59 +08:00
|
|
|
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
|
2015-10-15 09:27:19 +08:00
|
|
|
if (!sys::fs::file_size(FileName, FileSize)) {
|
2015-02-27 17:15:59 +08: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-23 06:03:38 +08:00
|
|
|
if (GlobalScope->hasCTypes())
|
|
|
|
outs() << "HasCTypes ";
|
|
|
|
if (GlobalScope->hasPrivateSymbols())
|
|
|
|
outs() << "HasPrivateSymbols ";
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.Unindent();
|
2015-02-23 06:03:38 +08:00
|
|
|
|
2018-07-07 05:01:42 +08:00
|
|
|
if (!opts::pretty::WithName.empty()) {
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
|
|
|
|
<< "---SYMBOLS & TYPES BY NAME---";
|
|
|
|
|
|
|
|
for (StringRef Name : opts::pretty::WithName) {
|
|
|
|
auto Symbols = GlobalScope->findChildren(
|
|
|
|
PDB_SymType::None, Name, PDB_NameSearchFlags::NS_CaseSensitive);
|
|
|
|
if (!Symbols || Symbols->getChildCount() == 0) {
|
|
|
|
Printer.formatLine("[not found] - {0}", Name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Printer.formatLine("[{0} occurrences] - {1}", Symbols->getChildCount(),
|
|
|
|
Name);
|
|
|
|
|
|
|
|
AutoIndent Indent(Printer);
|
|
|
|
Printer.NewLine();
|
|
|
|
|
|
|
|
while (auto Symbol = Symbols->getNext()) {
|
|
|
|
switch (Symbol->getSymTag()) {
|
|
|
|
case PDB_SymType::Typedef: {
|
|
|
|
TypedefDumper TD(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolTypeTypedef> T =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolTypeTypedef>(std::move(Symbol));
|
|
|
|
TD.start(*T);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::Enum: {
|
|
|
|
EnumDumper ED(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolTypeEnum> E =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolTypeEnum>(std::move(Symbol));
|
|
|
|
ED.start(*E);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::UDT: {
|
|
|
|
ClassDefinitionDumper CD(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolTypeUDT> C =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Symbol));
|
|
|
|
CD.start(*C);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::BaseClass:
|
|
|
|
case PDB_SymType::Friend: {
|
|
|
|
TypeDumper TD(Printer);
|
|
|
|
Symbol->dump(TD);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::Function: {
|
|
|
|
FunctionDumper FD(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolFunc> F =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolFunc>(std::move(Symbol));
|
|
|
|
FD.start(*F, FunctionDumper::PointerType::None);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::Data: {
|
|
|
|
VariableDumper VD(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolData> D =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolData>(std::move(Symbol));
|
|
|
|
VD.start(*D);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PDB_SymType::PublicSymbol: {
|
|
|
|
ExternalSymbolDumper ED(Printer);
|
|
|
|
std::unique_ptr<PDBSymbolPublicSymbol> PS =
|
|
|
|
llvm::unique_dyn_cast<PDBSymbolPublicSymbol>(std::move(Symbol));
|
|
|
|
ED.dump(*PS);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unexpected symbol tag!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
llvm::outs().flush();
|
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::Compilands) {
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
|
|
|
|
<< "---COMPILANDS---";
|
2018-03-07 10:23:08 +08:00
|
|
|
if (auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>()) {
|
|
|
|
Printer.Indent();
|
|
|
|
CompilandDumper Dumper(Printer);
|
|
|
|
CompilandDumpFlags options = CompilandDumper::Flags::None;
|
|
|
|
if (opts::pretty::Lines)
|
|
|
|
options = options | CompilandDumper::Flags::Lines;
|
|
|
|
while (auto Compiland = Compilands->getNext())
|
|
|
|
Dumper.start(*Compiland, options);
|
|
|
|
Printer.Unindent();
|
|
|
|
}
|
2015-02-27 17:15:18 +08:00
|
|
|
}
|
|
|
|
|
2017-04-07 07:43:12 +08:00
|
|
|
if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) {
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
|
|
|
|
Printer.Indent();
|
2015-03-04 14:09:53 +08:00
|
|
|
TypeDumper Dumper(Printer);
|
2015-03-01 14:51:29 +08:00
|
|
|
Dumper.start(*GlobalScope);
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.Unindent();
|
2015-02-23 06:03:38 +08:00
|
|
|
}
|
2015-01-28 08:33:00 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::Symbols) {
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
|
2018-03-07 10:23:08 +08:00
|
|
|
if (auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>()) {
|
|
|
|
Printer.Indent();
|
|
|
|
CompilandDumper Dumper(Printer);
|
|
|
|
while (auto Compiland = Compilands->getNext())
|
|
|
|
Dumper.start(*Compiland, true);
|
|
|
|
Printer.Unindent();
|
|
|
|
}
|
2015-02-27 17:15:18 +08:00
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::Globals) {
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
|
|
|
|
Printer.Indent();
|
2017-05-14 09:13:40 +08:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) {
|
2018-03-07 10:23:08 +08:00
|
|
|
if (auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>()) {
|
|
|
|
FunctionDumper Dumper(Printer);
|
|
|
|
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));
|
2018-04-02 05:24:53 +08:00
|
|
|
llvm::sort(Funcs.begin(), Funcs.end(),
|
|
|
|
opts::pretty::compareFunctionSymbols);
|
2018-03-07 10:23:08 +08:00
|
|
|
for (const auto &Func : Funcs) {
|
|
|
|
Printer.NewLine();
|
|
|
|
Dumper.start(*Func, FunctionDumper::PointerType::None);
|
|
|
|
}
|
2017-05-14 09:13:40 +08:00
|
|
|
}
|
2015-02-27 17:15:59 +08:00
|
|
|
}
|
2015-02-27 17:15:18 +08:00
|
|
|
}
|
2017-05-14 09:13:40 +08:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) {
|
2018-03-07 10:23:08 +08:00
|
|
|
if (auto Vars = GlobalScope->findAllChildren<PDBSymbolData>()) {
|
|
|
|
VariableDumper Dumper(Printer);
|
|
|
|
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));
|
2018-04-02 05:24:53 +08:00
|
|
|
llvm::sort(Datas.begin(), Datas.end(),
|
|
|
|
opts::pretty::compareDataSymbols);
|
2018-03-07 10:23:08 +08:00
|
|
|
for (const auto &Var : Datas)
|
|
|
|
Dumper.start(*Var);
|
|
|
|
}
|
2017-05-14 09:13:40 +08:00
|
|
|
}
|
2015-02-27 17:15:18 +08:00
|
|
|
}
|
2017-05-14 09:13:40 +08:00
|
|
|
if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) {
|
2018-03-07 10:23:08 +08:00
|
|
|
if (auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>()) {
|
|
|
|
CompilandDumper Dumper(Printer);
|
|
|
|
while (auto Thunk = Thunks->getNext())
|
|
|
|
Dumper.dump(*Thunk);
|
|
|
|
}
|
2015-02-27 17:15:18 +08:00
|
|
|
}
|
2015-02-27 17:15:59 +08:00
|
|
|
Printer.Unindent();
|
2015-01-28 08:33:00 +08:00
|
|
|
}
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::Externals) {
|
2015-05-02 04:24:26 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
|
|
|
|
Printer.Indent();
|
|
|
|
ExternalSymbolDumper Dumper(Printer);
|
|
|
|
Dumper.start(*GlobalScope);
|
|
|
|
}
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::pretty::Lines) {
|
2016-03-09 05:42:24 +08:00
|
|
|
Printer.NewLine();
|
|
|
|
}
|
2018-03-14 01:46:06 +08:00
|
|
|
if (opts::pretty::InjectedSources) {
|
|
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::SectionHeader).get()
|
|
|
|
<< "---INJECTED SOURCES---";
|
|
|
|
AutoIndent Indent1(Printer);
|
|
|
|
|
|
|
|
if (ReaderType == PDB_ReaderType::Native)
|
|
|
|
Printer.printLine(
|
|
|
|
"Injected sources are not supported with the native reader.");
|
|
|
|
else
|
|
|
|
dumpInjectedSources(Printer, *Session);
|
|
|
|
}
|
|
|
|
|
2015-01-28 08:33:00 +08:00
|
|
|
outs().flush();
|
|
|
|
}
|
|
|
|
|
2017-05-19 07:03:41 +08:00
|
|
|
static void mergePdbs() {
|
|
|
|
BumpPtrAllocator Allocator;
|
2017-12-01 02:39:50 +08:00
|
|
|
MergingTypeTableBuilder MergedTpi(Allocator);
|
|
|
|
MergingTypeTableBuilder MergedIpi(Allocator);
|
2017-05-19 07:03:41 +08:00
|
|
|
|
|
|
|
// 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-23 05:07:43 +08:00
|
|
|
SmallVector<TypeIndex, 128> TypeMap;
|
|
|
|
SmallVector<TypeIndex, 128> IdMap;
|
2017-05-19 07:03:41 +08:00
|
|
|
if (File.hasPDBTpiStream()) {
|
|
|
|
auto &Tpi = ExitOnErr(File.getPDBTpiStream());
|
2017-07-18 04:28:06 +08:00
|
|
|
ExitOnErr(
|
|
|
|
codeview::mergeTypeRecords(MergedTpi, TypeMap, Tpi.typeArray()));
|
2017-05-19 07:03:41 +08:00
|
|
|
}
|
|
|
|
if (File.hasPDBIpiStream()) {
|
|
|
|
auto &Ipi = ExitOnErr(File.getPDBIpiStream());
|
2017-05-23 05:07:43 +08:00
|
|
|
ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap,
|
2017-05-24 08:35:32 +08:00
|
|
|
Ipi.typeArray()));
|
2017-05-19 07:03:41 +08: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();
|
2017-11-30 03:35:21 +08:00
|
|
|
MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, const CVType &Type) {
|
|
|
|
DestTpi.addTypeRecord(Type.RecordData, None);
|
[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-24 02:23:59 +08:00
|
|
|
});
|
2017-11-30 03:35:21 +08:00
|
|
|
MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, const CVType &Type) {
|
|
|
|
DestIpi.addTypeRecord(Type.RecordData, None);
|
[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-24 02:23:59 +08:00
|
|
|
});
|
2017-06-13 05:34:53 +08:00
|
|
|
Builder.getInfoBuilder().addFeature(PdbRaw_FeatureSig::VC140);
|
2017-05-19 07:03:41 +08:00
|
|
|
|
2017-05-19 14:25:09 +08:00
|
|
|
SmallString<64> OutFile(opts::merge::PdbOutputFile);
|
2017-05-19 07:03:41 +08:00
|
|
|
if (OutFile.empty()) {
|
|
|
|
OutFile = opts::merge::InputFilenames[0];
|
|
|
|
llvm::sys::path::replace_extension(OutFile, "merged.pdb");
|
|
|
|
}
|
|
|
|
ExitOnErr(Builder.commit(OutFile));
|
|
|
|
}
|
|
|
|
|
2018-03-30 00:28:20 +08:00
|
|
|
static void explain() {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
2018-04-05 01:29:09 +08:00
|
|
|
InputFile IF =
|
|
|
|
ExitOnErr(InputFile::open(opts::explain::InputFilename.front(), true));
|
2018-03-30 00:28:20 +08:00
|
|
|
|
2018-03-31 01:16:50 +08:00
|
|
|
for (uint64_t Off : opts::explain::Offsets) {
|
2018-04-05 01:29:09 +08:00
|
|
|
auto O = llvm::make_unique<ExplainOutputStyle>(IF, Off);
|
2018-03-31 01:16:50 +08:00
|
|
|
|
|
|
|
ExitOnErr(O->dump());
|
|
|
|
}
|
2018-03-30 00:28:20 +08:00
|
|
|
}
|
|
|
|
|
2018-04-03 02:35:21 +08:00
|
|
|
static void exportStream() {
|
|
|
|
std::unique_ptr<IPDBSession> Session;
|
|
|
|
PDBFile &File = loadPDB(opts::exportstream::InputFilename.front(), Session);
|
|
|
|
|
|
|
|
std::unique_ptr<MappedBlockStream> SourceStream;
|
|
|
|
uint32_t Index = 0;
|
|
|
|
bool Success = false;
|
|
|
|
std::string OutFileName = opts::exportstream::OutputFile;
|
|
|
|
|
|
|
|
if (!opts::exportstream::ForceName) {
|
|
|
|
// First try to parse it as an integer, if it fails fall back to treating it
|
|
|
|
// as a named stream.
|
|
|
|
if (to_integer(opts::exportstream::Stream, Index)) {
|
|
|
|
if (Index >= File.getNumStreams()) {
|
|
|
|
errs() << "Error: " << Index << " is not a valid stream index.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
Success = true;
|
|
|
|
outs() << "Dumping contents of stream index " << Index << " to file "
|
|
|
|
<< OutFileName << ".\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Success) {
|
|
|
|
InfoStream &IS = cantFail(File.getPDBInfoStream());
|
|
|
|
Index = ExitOnErr(IS.getNamedStreamIndex(opts::exportstream::Stream));
|
|
|
|
outs() << "Dumping contents of stream '" << opts::exportstream::Stream
|
|
|
|
<< "' (index " << Index << ") to file " << OutFileName << ".\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceStream = MappedBlockStream::createIndexedStream(
|
|
|
|
File.getMsfLayout(), File.getMsfBuffer(), Index, File.getAllocator());
|
|
|
|
auto OutFile = ExitOnErr(
|
|
|
|
FileOutputBuffer::create(OutFileName, SourceStream->getLength()));
|
|
|
|
FileBufferByteStream DestStream(std::move(OutFile), llvm::support::little);
|
|
|
|
BinaryStreamWriter Writer(DestStream);
|
|
|
|
ExitOnErr(Writer.writeStreamRef(*SourceStream));
|
|
|
|
ExitOnErr(DestStream.commit());
|
|
|
|
}
|
|
|
|
|
2017-06-24 03:54:44 +08:00
|
|
|
static bool parseRange(StringRef Str,
|
|
|
|
Optional<opts::bytes::NumberRange> &Parsed) {
|
|
|
|
if (Str.empty())
|
2017-06-23 04:58:11 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
llvm::Regex R("^([^-]+)(-([^-]+))?$");
|
|
|
|
llvm::SmallVector<llvm::StringRef, 2> Matches;
|
2017-06-24 03:54:44 +08:00
|
|
|
if (!R.match(Str, &Matches))
|
2017-06-23 04:58:11 +08:00
|
|
|
return false;
|
|
|
|
|
2017-06-24 03:54:44 +08:00
|
|
|
Parsed.emplace();
|
|
|
|
if (!to_integer(Matches[1], Parsed->Min))
|
2017-06-23 04:58:11 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!Matches[3].empty()) {
|
2017-06-24 03:54:44 +08:00
|
|
|
Parsed->Max.emplace();
|
|
|
|
if (!to_integer(Matches[3], *Parsed->Max))
|
2017-06-23 04:58:11 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-27 01:22:36 +08:00
|
|
|
static void simplifyChunkList(llvm::cl::list<opts::ModuleSubsection> &Chunks) {
|
|
|
|
// If this list contains "All" plus some other stuff, remove the other stuff
|
|
|
|
// and just keep "All" in the list.
|
|
|
|
if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All))
|
|
|
|
return;
|
|
|
|
Chunks.reset();
|
|
|
|
Chunks.push_back(opts::ModuleSubsection::All);
|
|
|
|
}
|
|
|
|
|
2018-04-14 02:26:06 +08:00
|
|
|
int main(int Argc, const char **Argv) {
|
|
|
|
InitLLVM X(Argc, Argv);
|
2017-06-10 04:46:17 +08:00
|
|
|
ExitOnErr.setBanner("llvm-pdbutil: ");
|
2016-05-29 02:25:15 +08:00
|
|
|
|
2018-04-14 02:26:06 +08:00
|
|
|
cl::ParseCommandLineOptions(Argc, Argv, "LLVM PDB Dumper\n");
|
2017-06-24 03:54:44 +08:00
|
|
|
|
|
|
|
if (opts::BytesSubcommand) {
|
|
|
|
if (!parseRange(opts::bytes::DumpBlockRangeOpt,
|
|
|
|
opts::bytes::DumpBlockRange)) {
|
|
|
|
errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
|
|
|
|
<< "' invalid format.\n";
|
|
|
|
errs().flush();
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!parseRange(opts::bytes::DumpByteRangeOpt,
|
|
|
|
opts::bytes::DumpByteRange)) {
|
|
|
|
errs() << "Argument '" << opts::bytes::DumpByteRangeOpt
|
|
|
|
<< "' invalid format.\n";
|
|
|
|
errs().flush();
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-09-10 02:17:52 +08:00
|
|
|
}
|
2016-03-09 05:42:24 +08:00
|
|
|
|
2017-06-23 04:57:39 +08:00
|
|
|
if (opts::DumpSubcommand) {
|
|
|
|
if (opts::dump::RawAll) {
|
2017-09-01 04:43:22 +08:00
|
|
|
opts::dump::DumpGlobals = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpInlineeLines = true;
|
|
|
|
opts::dump::DumpIds = true;
|
2017-09-01 04:43:22 +08:00
|
|
|
opts::dump::DumpIdExtras = true;
|
|
|
|
opts::dump::DumpLines = true;
|
|
|
|
opts::dump::DumpModules = true;
|
|
|
|
opts::dump::DumpModuleFiles = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpPublics = true;
|
|
|
|
opts::dump::DumpSectionContribs = true;
|
2017-09-01 04:43:22 +08:00
|
|
|
opts::dump::DumpSectionHeaders = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpSectionMap = true;
|
|
|
|
opts::dump::DumpStreams = true;
|
2017-06-24 04:28:14 +08:00
|
|
|
opts::dump::DumpStreamBlocks = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpStringTable = true;
|
2018-03-24 02:43:39 +08:00
|
|
|
opts::dump::DumpStringTableDetails = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpSummary = true;
|
|
|
|
opts::dump::DumpSymbols = true;
|
2017-09-01 04:43:22 +08:00
|
|
|
opts::dump::DumpSymbolStats = true;
|
2017-06-23 04:57:39 +08:00
|
|
|
opts::dump::DumpTypes = true;
|
|
|
|
opts::dump::DumpTypeExtras = true;
|
2017-09-01 04:43:22 +08:00
|
|
|
opts::dump::DumpUdtStats = true;
|
|
|
|
opts::dump::DumpXme = true;
|
|
|
|
opts::dump::DumpXmi = true;
|
2017-01-13 06:28:15 +08:00
|
|
|
}
|
2015-03-02 12:39:56 +08:00
|
|
|
}
|
2017-06-09 07:39:33 +08:00
|
|
|
if (opts::PdbToYamlSubcommand) {
|
|
|
|
if (opts::pdb2yaml::All) {
|
|
|
|
opts::pdb2yaml::StreamMetadata = true;
|
|
|
|
opts::pdb2yaml::StreamDirectory = true;
|
|
|
|
opts::pdb2yaml::PdbStream = true;
|
|
|
|
opts::pdb2yaml::StringTable = true;
|
|
|
|
opts::pdb2yaml::DbiStream = true;
|
|
|
|
opts::pdb2yaml::TpiStream = true;
|
|
|
|
opts::pdb2yaml::IpiStream = true;
|
2017-06-16 06:24:24 +08:00
|
|
|
opts::pdb2yaml::DumpModules = true;
|
|
|
|
opts::pdb2yaml::DumpModuleFiles = true;
|
|
|
|
opts::pdb2yaml::DumpModuleSyms = true;
|
|
|
|
opts::pdb2yaml::DumpModuleSubsections.push_back(
|
|
|
|
opts::ModuleSubsection::All);
|
2017-06-09 07:39:33 +08:00
|
|
|
}
|
2017-06-27 01:22:36 +08:00
|
|
|
simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections);
|
2017-06-16 06:24:24 +08:00
|
|
|
|
|
|
|
if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
|
|
|
|
opts::pdb2yaml::DumpModules = true;
|
|
|
|
|
|
|
|
if (opts::pdb2yaml::DumpModules)
|
|
|
|
opts::pdb2yaml::DbiStream = true;
|
2017-06-09 07:39:33 +08:00
|
|
|
}
|
2015-01-28 04:46:21 +08:00
|
|
|
|
2016-06-02 13:07:49 +08:00
|
|
|
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
|
2015-01-28 04:46:21 +08:00
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
if (opts::PdbToYamlSubcommand) {
|
2016-07-07 02:05:57 +08:00
|
|
|
pdb2Yaml(opts::pdb2yaml::InputFilename.front());
|
2016-07-01 01:42:48 +08:00
|
|
|
} else if (opts::YamlToPdbSubcommand) {
|
2017-05-18 04:46:48 +08: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-02 02:30:22 +08:00
|
|
|
} else if (opts::AnalyzeSubcommand) {
|
|
|
|
dumpAnalysis(opts::analyze::InputFilename.front());
|
2016-07-01 01:42:48 +08: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 07:43:12 +08:00
|
|
|
if (opts::pretty::Types) {
|
|
|
|
opts::pretty::Classes = true;
|
|
|
|
opts::pretty::Typedefs = true;
|
|
|
|
opts::pretty::Enums = true;
|
|
|
|
}
|
|
|
|
|
2016-07-01 01:42:48 +08:00
|
|
|
// When adding filters for excluded compilands and types, we need to
|
2016-09-10 02:17:52 +08: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-07-01 01:42:48 +08: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");
|
2017-11-30 03:29:25 +08:00
|
|
|
opts::pretty::ExcludeCompilands.push_back(
|
|
|
|
"d:\\\\th.obj.x86fre\\\\minkernel");
|
|
|
|
}
|
|
|
|
llvm::for_each(opts::pretty::InputFilenames, dumpPretty);
|
|
|
|
} else if (opts::DumpSubcommand) {
|
|
|
|
llvm::for_each(opts::dump::InputFilenames, dumpRaw);
|
|
|
|
} else if (opts::BytesSubcommand) {
|
|
|
|
llvm::for_each(opts::bytes::InputFilenames, dumpBytes);
|
2017-05-19 07:03:41 +08:00
|
|
|
} else if (opts::MergeSubcommand) {
|
|
|
|
if (opts::merge::InputFilenames.size() < 2) {
|
|
|
|
errs() << "merge subcommand requires at least 2 input files.\n";
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
mergePdbs();
|
2018-03-30 00:28:20 +08:00
|
|
|
} else if (opts::ExplainSubcommand) {
|
|
|
|
explain();
|
2018-04-03 02:35:21 +08:00
|
|
|
} else if (opts::ExportSubcommand) {
|
|
|
|
exportStream();
|
2016-06-15 04:48:36 +08:00
|
|
|
}
|
2015-01-28 04:46:21 +08:00
|
|
|
|
2016-05-07 04:51:57 +08:00
|
|
|
outs().flush();
|
2015-01-28 04:46:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|