From: Zachary Turner Date: Sun, 14 May 2017 01:13:40 +0000 (+0000) Subject: [llvm-pdbdump] Add the option to sort functions and data. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4afda8f7b68be1098d191017ef04967aadde1099;p=llvm [llvm-pdbdump] Add the option to sort functions and data. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302998 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test b/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test index 0bb3e001d3a..997cdd9f6ba 100644 --- a/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test +++ b/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test @@ -1,5 +1,5 @@ -; RUN: llvm-pdbdump pretty -symbols %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT_FPO %s -; RUN: llvm-pdbdump pretty -symbols %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s +; RUN: llvm-pdbdump pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT_FPO %s +; RUN: llvm-pdbdump pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s ; RUN: llvm-pdbdump pretty -types %p/../Inputs/symbolformat.pdb > %t.types ; RUN: FileCheck --check-prefix=TYPES_FORMAT %s < %t.types ; RUN: FileCheck --check-prefix=TYPES_1 %s < %t.types diff --git a/test/tools/llvm-pdbdump/Inputs/FilterTest.cpp b/test/tools/llvm-pdbdump/Inputs/FilterTest.cpp index bcf9360d4a9..4dd5581e2fc 100644 --- a/test/tools/llvm-pdbdump/Inputs/FilterTest.cpp +++ b/test/tools/llvm-pdbdump/Inputs/FilterTest.cpp @@ -10,6 +10,8 @@ public: void MemberFunc() {} + int foo() const { return IntMemberVar; } + private: int IntMemberVar; double DoubleMemberVar; @@ -18,10 +20,26 @@ private: int IntGlobalVar; double DoubleGlobalVar; typedef int GlobalTypedef; +char OneByte; +char TwoBytes[2]; +char ThreeBytes[3]; + enum GlobalEnum { GlobalEnumVal1 } GlobalEnumVar; +int CFunc() { + return (int)OneByte * 2; +} +int BFunc() { + return 42; +} +int AFunc() { + static FilterTestClass FC; + + return (CFunc() + BFunc()) * IntGlobalVar + FC.foo(); +} + int main(int argc, char **argv) { FilterTestClass TestClass; GlobalTypedef v1; diff --git a/test/tools/llvm-pdbdump/Inputs/FilterTest.pdb b/test/tools/llvm-pdbdump/Inputs/FilterTest.pdb index 5f01ec701b8..ce7e017f915 100644 Binary files a/test/tools/llvm-pdbdump/Inputs/FilterTest.pdb and b/test/tools/llvm-pdbdump/Inputs/FilterTest.pdb differ diff --git a/test/tools/llvm-pdbdump/regex-filter.test b/test/tools/llvm-pdbdump/regex-filter.test index d2f500e88c3..36c3da33e2e 100644 --- a/test/tools/llvm-pdbdump/regex-filter.test +++ b/test/tools/llvm-pdbdump/regex-filter.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pretty -symbols -globals -types %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbdump pretty -module-syms -globals -types %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=NO_FILTER %s ; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \ @@ -11,15 +11,15 @@ ; RUN: llvm-pdbdump pretty -classes -typedefs %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=EXCLUDE_ENUMS %s -; RUN: llvm-pdbdump pretty -types -symbols -globals -exclude-symbols="MemberVar|GlobalVar" \ +; RUN: llvm-pdbdump pretty -types -module-syms -globals -exclude-symbols="MemberVar|GlobalVar" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_VARS %s ; RUN: llvm-pdbdump pretty -types -exclude-types="FilterTestClass" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_WHOLE_CLASS %s -; RUN: llvm-pdbdump pretty -symbols -globals -exclude-compilands="FilterTest.obj" \ +; RUN: llvm-pdbdump pretty -module-syms -globals -exclude-compilands="FilterTest.obj" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_COMPILAND %s ; RUN: llvm-pdbdump pretty -types -include-types="FilterTestClass" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_TYPES %s -; RUN: llvm-pdbdump pretty -types -symbols -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \ +; RUN: llvm-pdbdump pretty -types -module-syms -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_VARS %s ; NO_FILTER: ---TYPES--- diff --git a/test/tools/llvm-pdbdump/symbol-filters.test b/test/tools/llvm-pdbdump/symbol-filters.test new file mode 100644 index 00000000000..d12d2aa8be0 --- /dev/null +++ b/test/tools/llvm-pdbdump/symbol-filters.test @@ -0,0 +1,74 @@ +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data %p/Inputs/FilterTest.pdb \ +; RUN: | FileCheck --check-prefix=ONLY_DATA %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=thunks %p/Inputs/FilterTest.pdb \ +; RUN: | FileCheck --check-prefix=ONLY_THUNKS %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs %p/Inputs/FilterTest.pdb \ +; RUN: | FileCheck --check-prefix=ONLY_FUNCS %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs -sym-types=data \ +; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=TWO_TYPES %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data \ +; RUN: -symbol-order=name %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=NAME_SORT_DATA %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data \ +; RUN: -symbol-order=size %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=SIZE_SORT_DATA %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs \ +; RUN: -symbol-order=name %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=NAME_SORT_FUNCS %s + +; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs \ +; RUN: -symbol-order=size %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=SIZE_SORT_FUNCS %s + +; ONLY_DATA-NOT: func +; ONLY_DATA-NOT: thunk +; ONLY_DATA-DAG: data {{.*}} static char OneByte +; ONLY_DATA-DAG: data {{.*}} static double DoubleGlobalVar +; ONLY_DATA-DAG: data {{.*}} static char TwoBytes[2] +; ONLY_DATA-DAG: data {{.*}} static char ThreeBytes[3] +; ONLY_DATA-DAG: data {{.*}} static int IntGlobalVar +; ONLY_DATA-DAG: data {{.*}} static GlobalEnum GlobalEnumVar + +; ONLY_FUNCS-NOT: data +; ONLY_FUNCS-NOT: thunk +; ONLY_FUNCS: func {{.*}} int __cdecl main(int argc, char** argv) +; ONLY_FUNCS: func {{.*}} int __cdecl CFunc() +; ONLY_FUNCS: func {{.*}} int __cdecl BFunc() +; ONLY_FUNCS: func {{.*}} int __cdecl AFunc() +; ONLY_FUNCS: func {{.*}} int FilterTestClass::foo() + +; ONLY_THUNKS-NOT: func +; ONLY_THUNKS-NOT: data +; ONLY_THUNKS-DAG: thunk {{.*}} (TrampIncremental) + +; TWO_TYPES-NOT: thunk +; TWO_TYPES-DAG: func {{.*}} int __cdecl main(int argc, char** argv) +; TWO_TYPES-DAG: data {{.*}} static double DoubleGlobalVar + +; NAME_SORT_DATA: data {{.*}} static double DoubleGlobalVar +; NAME_SORT_DATA: data {{.*}} static GlobalEnum GlobalEnumVar +; NAME_SORT_DATA: data {{.*}} static int IntGlobalVar +; NAME_SORT_DATA: data {{.*}} static char OneByte +; NAME_SORT_DATA: data {{.*}} static char ThreeBytes[3] +; NAME_SORT_DATA: data {{.*}} static char TwoBytes[2] + +; SIZE_SORT_DATA: data {{.*}}sizeof=8{{.*}}double DoubleGlobalVar +; SIZE_SORT_DATA-DAG: data {{.*}}sizeof=4{{.*}}GlobalEnum GlobalEnumVar +; SIZE_SORT_DATA-DAG: data {{.*}}sizeof=4{{.*}}int IntGlobalVar +; SIZE_SORT_DATA: data {{.*}}sizeof=3{{.*}}char ThreeBytes[3] +; SIZE_SORT_DATA: data {{.*}}sizeof=2{{.*}}char TwoBytes[2] +; SIZE_SORT_DATA: data {{.*}}sizeof=1{{.*}}char OneByte + +; NAME_SORT_FUNCS: func {{.*}}sizeof= 40{{.*}}AFunc +; NAME_SORT_FUNCS: func {{.*}}sizeof= 10{{.*}}BFunc +; NAME_SORT_FUNCS: func {{.*}}sizeof= 14{{.*}}CFunc +; NAME_SORT_FUNCS: func {{.*}}sizeof= 16{{.*}}FilterTestClass::foo +; NAME_SORT_FUNCS: func {{.*}}sizeof= 7{{.*}}main + +; SIZE_SORT_FUNCS: func {{.*}}sizeof= 40{{.*}}AFunc +; SIZE_SORT_FUNCS: func {{.*}}sizeof= 16{{.*}}FilterTestClass::foo +; SIZE_SORT_FUNCS: func {{.*}}sizeof= 14{{.*}}CFunc +; SIZE_SORT_FUNCS: func {{.*}}sizeof= 10{{.*}}BFunc +; SIZE_SORT_FUNCS: func {{.*}}sizeof= 7{{.*}}main diff --git a/tools/llvm-pdbdump/PrettyCompilandDumper.cpp b/tools/llvm-pdbdump/PrettyCompilandDumper.cpp index 6257313e3e1..9cf7bf82a16 100644 --- a/tools/llvm-pdbdump/PrettyCompilandDumper.cpp +++ b/tools/llvm-pdbdump/PrettyCompilandDumper.cpp @@ -115,6 +115,8 @@ void CompilandDumper::start(const PDBSymbolCompiland &Symbol, } void CompilandDumper::dump(const PDBSymbolData &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data)) + return; if (Printer.IsSymbolExcluded(Symbol.getName())) return; @@ -125,11 +127,17 @@ void CompilandDumper::dump(const PDBSymbolData &Symbol) { Printer << "data: "; WithColor(Printer, PDB_ColorItem::Address).get() << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]"; + + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; + break; case PDB_LocType::Constant: Printer << "constant: "; WithColor(Printer, PDB_ColorItem::LiteralValue).get() << "[" << Symbol.getValue() << "]"; + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; break; default: Printer << "data(unexpected type=" << LocType << ")"; @@ -140,6 +148,8 @@ void CompilandDumper::dump(const PDBSymbolData &Symbol) { } void CompilandDumper::dump(const PDBSymbolFunc &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) + return; if (Symbol.getLength() == 0) return; if (Printer.IsSymbolExcluded(Symbol.getName())) @@ -162,6 +172,8 @@ void CompilandDumper::dump(const PDBSymbolLabel &Symbol) { } void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) + return; if (Printer.IsSymbolExcluded(Symbol.getName())) return; diff --git a/tools/llvm-pdbdump/PrettyFunctionDumper.cpp b/tools/llvm-pdbdump/PrettyFunctionDumper.cpp index b0be33c157c..8b2043989b8 100644 --- a/tools/llvm-pdbdump/PrettyFunctionDumper.cpp +++ b/tools/llvm-pdbdump/PrettyFunctionDumper.cpp @@ -26,6 +26,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" using namespace llvm; using namespace llvm::codeview; @@ -119,14 +120,19 @@ void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) { WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10); if (auto DebugStart = Symbol.findOneChild()) { uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart; - WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << Prologue; + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("+{0,2}", Prologue); } Printer << " - "; WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10); if (auto DebugEnd = Symbol.findOneChild()) { uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress(); - WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue; + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("-{0,2}", Epilogue); } + + WithColor(Printer, PDB_ColorItem::Comment).get() + << formatv(" | sizeof={0,3}", Symbol.getLength()); Printer << "] ("; if (Symbol.hasFramePointer()) { diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 4cdd87620c8..0e5913fa3c9 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -110,12 +110,22 @@ cl::list InputFilenames(cl::Positional, cl::opt Compilands("compilands", cl::desc("Display compilands"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Symbols("symbols", cl::desc("Display symbols for each compiland"), +cl::opt Symbols("module-syms", + cl::desc("Display symbols for each compiland"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Globals("globals", cl::desc("Dump global symbols"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Externals("externals", cl::desc("Dump external symbols"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::list 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)"))); + cl::opt Types("types", cl::desc("Display all types (implies -classes, -enums, -typedefs)"), @@ -126,6 +136,16 @@ cl::opt Enums("enums", cl::desc("Display enum types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt 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)); + cl::opt ClassOrder( "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), cl::values( @@ -620,6 +640,49 @@ static void diff(StringRef Path1, StringRef Path2) { ExitOnErr(O->dump()); } +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 &F1, + const std::unique_ptr &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 &F1, + const std::unique_ptr &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); +} + static void dumpPretty(StringRef Path) { std::unique_ptr Session; @@ -708,21 +771,42 @@ static void dumpPretty(StringRef Path) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; Printer.Indent(); - { + if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { FunctionDumper Dumper(Printer); auto Functions = GlobalScope->findAllChildren(); - while (auto Function = Functions->getNext()) { - Printer.NewLine(); - Dumper.start(*Function, FunctionDumper::PointerType::None); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Function = Functions->getNext()) { + Printer.NewLine(); + Dumper.start(*Function, FunctionDumper::PointerType::None); + } + } else { + std::vector> Funcs; + while (auto Func = Functions->getNext()) + Funcs.push_back(std::move(Func)); + std::sort(Funcs.begin(), Funcs.end(), + opts::pretty::compareFunctionSymbols); + for (const auto &Func : Funcs) { + Printer.NewLine(); + Dumper.start(*Func, FunctionDumper::PointerType::None); + } } } - { + if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { auto Vars = GlobalScope->findAllChildren(); VariableDumper Dumper(Printer); - while (auto Var = Vars->getNext()) - Dumper.start(*Var); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Var = Vars->getNext()) + Dumper.start(*Var); + } else { + std::vector> Datas; + while (auto Var = Vars->getNext()) + Datas.push_back(std::move(Var)); + std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols); + for (const auto &Var : Datas) + Dumper.start(*Var); + } } - { + if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { auto Thunks = GlobalScope->findAllChildren(); CompilandDumper Dumper(Printer); while (auto Thunk = Thunks->getNext()) diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index 8b1dde9399b..e38b32c6a34 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -14,6 +14,17 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" +#include +#include + +namespace llvm { +namespace pdb { +class PDBSymbolData; +class PDBSymbolFunc; +uint32_t getTypeLength(const PDBSymbolData &Symbol); +} +} + namespace opts { namespace pretty { @@ -29,6 +40,17 @@ enum class ClassSortMode { PaddingPctImmediate }; +enum class SymbolSortMode { None, Name, Size }; + +enum class SymLevel { Functions, Data, Thunks, All }; + +bool shouldDumpSymLevel(SymLevel Level); +bool compareFunctionSymbols( + const std::unique_ptr &F1, + const std::unique_ptr &F2); +bool compareDataSymbols(const std::unique_ptr &F1, + const std::unique_ptr &F2); + extern llvm::cl::opt Compilands; extern llvm::cl::opt Symbols; extern llvm::cl::opt Globals; @@ -45,6 +67,7 @@ extern llvm::cl::list ExcludeCompilands; extern llvm::cl::list IncludeTypes; extern llvm::cl::list IncludeSymbols; extern llvm::cl::list IncludeCompilands; +extern llvm::cl::opt SymbolOrder; extern llvm::cl::opt ClassOrder; extern llvm::cl::opt SizeThreshold; extern llvm::cl::opt PaddingThreshold;