diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /tools/llvm-pdbdump/llvm-pdbdump.cpp | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) |
Diffstat (limited to 'tools/llvm-pdbdump/llvm-pdbdump.cpp')
-rw-r--r-- | tools/llvm-pdbdump/llvm-pdbdump.cpp | 327 |
1 files changed, 241 insertions, 86 deletions
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index d3495e524abc..06c2afc0bc78 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// // -// Dumps debug information present in PDB files. This utility makes use of -// the Microsoft Windows SDK, so will not compile or run on non-Windows -// platforms. +// Dumps debug information present in PDB files. // //===----------------------------------------------------------------------===// #include "llvm-pdbdump.h" + +#include "Analyze.h" +#include "Diff.h" #include "LLVMOutputStyle.h" #include "LinePrinter.h" #include "OutputStyle.h" @@ -29,29 +30,31 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#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/ModInfoBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" -#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/COM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" @@ -78,6 +81,9 @@ cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); cl::SubCommand PrettySubcommand("pretty", "Dump semantic information about types and symbols"); + +cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files"); + cl::SubCommand YamlToPdbSubcommand("yaml2pdb", "Generate a PDB file from a YAML description"); @@ -85,8 +91,12 @@ cl::SubCommand PdbToYamlSubcommand("pdb2yaml", "Generate a detailed YAML description of a PDB File"); +cl::SubCommand + AnalyzeSubcommand("analyze", + "Analyze various aspects of a PDB's structure"); + cl::OptionCategory TypeCategory("Symbol Type Options"); -cl::OptionCategory FilterCategory("Filtering Options"); +cl::OptionCategory FilterCategory("Filtering and Sorting Options"); cl::OptionCategory OtherOptions("Other Options"); namespace pretty { @@ -102,8 +112,41 @@ cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory), - cl::sub(PrettySubcommand)); +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)); +cl::opt<ClassSortMode> ClassOrder( + "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), + 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")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt<ClassDefinitionFormat> ClassFormat( + "class-definitions", cl::desc("Class definition format"), + cl::init(ClassDefinitionFormat::Standard), + cl::values( + clEnumValN(ClassDefinitionFormat::Standard, "all-members", + "Display all class members including data, constants, " + "typedefs, functions, etc"), + clEnumValN(ClassDefinitionFormat::Layout, "layout-members", + "Only display members that contribute to class size."), + clEnumValN(ClassDefinitionFormat::Graphical, "graphical", + "Display graphical representation of each class's layout."), + clEnumValN(ClassDefinitionFormat::None, "none", + "Don't display class definitions")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt<bool> @@ -114,6 +157,12 @@ cl::opt<uint64_t> LoadAddress( "load-address", cl::desc("Assume the module is loaded at the specified address"), cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt<bool> Native("native", cl::desc("Use native PDB reader instead of DIA"), + 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)); cl::list<std::string> ExcludeTypes( "exclude-types", cl::desc("Exclude types by regular expression"), cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); @@ -136,6 +185,14 @@ cl::list<std::string> IncludeCompilands( "include-compilands", cl::desc("Include only compilands those which match a regular expression"), cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +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)); cl::opt<bool> ExcludeCompilerGenerated( "no-compiler-generated", @@ -145,14 +202,23 @@ cl::opt<bool> ExcludeSystemLibraries("no-system-libs", cl::desc("Don't show symbols from system libraries"), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt<bool> NoClassDefs("no-class-definitions", - cl::desc("Don't display full class definitions"), - cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + cl::opt<bool> NoEnumDefs("no-enum-definitions", cl::desc("Don't display full enum definitions"), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); } +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)); +} + namespace raw { cl::OptionCategory MsfOptions("MSF Container Options"); @@ -187,6 +253,11 @@ cl::list<uint32_t> // TYPE OPTIONS cl::opt<bool> + CompactRecords("compact-records", + cl::desc("Dump type and symbol records with less detail"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); + +cl::opt<bool> DumpTpiRecords("tpi-records", cl::desc("dump CodeView type records from TPI stream"), cl::cat(TypeOptions), cl::sub(RawSubcommand)); @@ -227,6 +298,9 @@ cl::opt<bool> cl::cat(SymbolOptions), cl::sub(RawSubcommand)); // MISCELLANEOUS OPTIONS +cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::opt<bool> DumpSectionContribs("section-contribs", cl::desc("dump section contributions"), cl::cat(MiscOptions), cl::sub(RawSubcommand)); @@ -262,6 +336,9 @@ cl::opt<bool> 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)); +cl::opt<bool> Minimal("minimal", + cl::desc("Don't write fields with default values"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); cl::opt<bool> StreamMetadata( "stream-metadata", @@ -274,6 +351,10 @@ cl::opt<bool> StreamDirectory( cl::opt<bool> PdbStream("pdb-stream", cl::desc("Dump the PDB Stream (Stream 1)"), cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt<bool> StringTable("string-table", cl::desc("Dump the PDB String Table"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + cl::opt<bool> DbiStream("dbi-stream", cl::desc("Dump the DBI Stream (Stream 2)"), cl::sub(PdbToYamlSubcommand), cl::init(false)); @@ -305,6 +386,14 @@ cl::list<std::string> InputFilename(cl::Positional, cl::desc("<input PDB file>"), cl::Required, cl::sub(PdbToYamlSubcommand)); } + +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)); +} } static ExitOnError ExitOnErr; @@ -324,13 +413,13 @@ static void yamlToPdb(StringRef Path) { llvm::yaml::Input In(Buffer->getBuffer()); pdb::yaml::PdbObject YamlObj(Allocator); In >> YamlObj; - if (!YamlObj.Headers.hasValue()) - ExitOnErr(make_error<GenericError>(generic_error_code::unspecified, - "Yaml does not contain MSF headers")); PDBFileBuilder Builder(Allocator); - ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock.BlockSize)); + uint32_t BlockSize = 4096; + if (YamlObj.Headers.hasValue()) + BlockSize = YamlObj.Headers->SuperBlock.BlockSize; + ExitOnErr(Builder.initialize(BlockSize)); // 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 @@ -340,56 +429,74 @@ static void yamlToPdb(StringRef Path) { for (uint32_t I = 0; I < kSpecialStreamCount; ++I) ExitOnErr(Builder.getMsfBuilder().addStream(0)); - if (YamlObj.PdbStream.hasValue()) { - auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(YamlObj.PdbStream->Age); - InfoBuilder.setGuid(YamlObj.PdbStream->Guid); - InfoBuilder.setSignature(YamlObj.PdbStream->Signature); - InfoBuilder.setVersion(YamlObj.PdbStream->Version); - for (auto &NM : YamlObj.PdbStream->NamedStreams) - InfoBuilder.getNamedStreamsBuilder().addMapping(NM.StreamName, - NM.StreamNumber); + if (YamlObj.StringTable.hasValue()) { + auto &Strings = Builder.getStringTableBuilder(); + for (auto S : *YamlObj.StringTable) + Strings.insert(S); } - if (YamlObj.DbiStream.hasValue()) { - auto &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(YamlObj.DbiStream->Age); - DbiBuilder.setBuildNumber(YamlObj.DbiStream->BuildNumber); - DbiBuilder.setFlags(YamlObj.DbiStream->Flags); - DbiBuilder.setMachineType(YamlObj.DbiStream->MachineType); - DbiBuilder.setPdbDllRbld(YamlObj.DbiStream->PdbDllRbld); - DbiBuilder.setPdbDllVersion(YamlObj.DbiStream->PdbDllVersion); - DbiBuilder.setVersionHeader(YamlObj.DbiStream->VerHeader); - for (const auto &MI : YamlObj.DbiStream->ModInfos) { - ExitOnErr(DbiBuilder.addModuleInfo(MI.Obj, MI.Mod)); - for (auto S : MI.SourceFiles) - ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); + pdb::yaml::PdbInfoStream DefaultInfoStream; + pdb::yaml::PdbDbiStream DefaultDbiStream; + pdb::yaml::PdbTpiStream DefaultTpiStream; + + 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); + for (auto F : Info.Features) + InfoBuilder.addFeature(F); + + 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) { + auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); + + 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); } } - if (YamlObj.TpiStream.hasValue()) { - auto &TpiBuilder = Builder.getTpiBuilder(); - TpiBuilder.setVersionHeader(YamlObj.TpiStream->Version); - for (const auto &R : YamlObj.TpiStream->Records) - TpiBuilder.addTypeRecord(R.Record); - } + auto &TpiBuilder = Builder.getTpiBuilder(); + const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); + TpiBuilder.setVersionHeader(Tpi.Version); + for (const auto &R : Tpi.Records) + TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash); - if (YamlObj.IpiStream.hasValue()) { - auto &IpiBuilder = Builder.getIpiBuilder(); - IpiBuilder.setVersionHeader(YamlObj.IpiStream->Version); - for (const auto &R : YamlObj.IpiStream->Records) - IpiBuilder.addTypeRecord(R.Record); - } + const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultTpiStream); + auto &IpiBuilder = Builder.getIpiBuilder(); + IpiBuilder.setVersionHeader(Ipi.Version); + for (const auto &R : Ipi.Records) + TpiBuilder.addTypeRecord(R.Record.data(), R.Record.Hash); ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); } +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(); +} + static void pdb2Yaml(StringRef Path) { std::unique_ptr<IPDBSession> Session; - ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session)); + auto &File = loadPDB(Path, Session); - RawSession *RS = static_cast<RawSession *>(Session.get()); - PDBFile &File = RS->getPDBFile(); auto O = llvm::make_unique<YAMLOutputStyle>(File); O = llvm::make_unique<YAMLOutputStyle>(File); @@ -398,24 +505,48 @@ static void pdb2Yaml(StringRef Path) { static void dumpRaw(StringRef Path) { std::unique_ptr<IPDBSession> Session; - ExitOnErr(loadDataForPDB(PDB_ReaderType::Raw, Path, Session)); + auto &File = loadPDB(Path, Session); - RawSession *RS = static_cast<RawSession *>(Session.get()); - PDBFile &File = RS->getPDBFile(); auto O = llvm::make_unique<LLVMOutputStyle>(File); ExitOnErr(O->dump()); } +static void dumpAnalysis(StringRef Path) { + std::unique_ptr<IPDBSession> Session; + auto &File = loadPDB(Path, Session); + auto O = llvm::make_unique<AnalysisStyle>(File); + + ExitOnErr(O->dump()); +} + +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()); +} + static void dumpPretty(StringRef Path) { std::unique_ptr<IPDBSession> Session; - ExitOnErr(loadDataForPDB(PDB_ReaderType::DIA, Path, Session)); + const auto ReaderType = + opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; + ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); if (opts::pretty::LoadAddress) Session->setLoadAddress(opts::pretty::LoadAddress); - LinePrinter Printer(2, outs()); + 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); auto GlobalScope(Session->getGlobalScope()); std::string FileName(GlobalScope->getSymbolsFileName()); @@ -465,7 +596,7 @@ static void dumpPretty(StringRef Path) { Printer.Unindent(); } - if (opts::pretty::Types) { + if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; Printer.Indent(); @@ -556,24 +687,34 @@ int main(int argc_, const char *argv_[]) { } } - if (opts::RawSubcommand && 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; + 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; + opts::raw::DumpStringTable = true; + } + + 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); + } } llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); @@ -582,6 +723,8 @@ int main(int argc_, const char *argv_[]) { pdb2Yaml(opts::pdb2yaml::InputFilename.front()); } else if (opts::YamlToPdbSubcommand) { yamlToPdb(opts::yaml2pdb::InputFilename.front()); + } else if (opts::AnalyzeSubcommand) { + dumpAnalysis(opts::analyze::InputFilename.front()); } else if (opts::PrettySubcommand) { if (opts::pretty::Lines) opts::pretty::Compilands = true; @@ -595,6 +738,12 @@ int main(int argc_, const char *argv_[]) { opts::pretty::Lines = true; } + if (opts::pretty::Types) { + opts::pretty::Classes = true; + opts::pretty::Typedefs = true; + opts::pretty::Enums = true; + } + // When adding filters for excluded compilands and types, we need to // 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 @@ -616,6 +765,12 @@ int main(int argc_, const char *argv_[]) { } else if (opts::RawSubcommand) { std::for_each(opts::raw::InputFilenames.begin(), opts::raw::InputFilenames.end(), dumpRaw); + } 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]); } outs().flush(); |