[llvm-pdbdump] Add the option to sort functions and data.

llvm-svn: 302998
This commit is contained in:
Zachary Turner 2017-05-14 01:13:40 +00:00
parent 754c1618ec
commit 0683be2ebc
9 changed files with 234 additions and 17 deletions

View File

@ -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

View File

@ -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;

View File

@ -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---

View File

@ -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

View File

@ -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;

View File

@ -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<PDBSymbolFuncDebugStart>()) {
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<PDBSymbolFuncDebugEnd>()) {
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()) {

View File

@ -110,12 +110,22 @@ cl::list<std::string> InputFilenames(cl::Positional,
cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
cl::opt<bool> Symbols("module-syms",
cl::desc("Display symbols for each compiland"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
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::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)")));
cl::opt<bool>
Types("types",
cl::desc("Display all types (implies -classes, -enums, -typedefs)"),
@ -126,6 +136,16 @@ 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<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));
cl::opt<ClassSortMode> 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<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);
}
static void dumpPretty(StringRef Path) {
std::unique_ptr<IPDBSession> 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<PDBSymbolFunc>();
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<std::unique_ptr<PDBSymbolFunc>> Funcs;
while (auto Func = Functions->getNext())
Funcs.push_back(std::move(Func));
std::sort(Funcs.begin(), Funcs.end(),
opts::pretty::compareFunctionSymbols);
for (const auto &Func : Funcs) {
Printer.NewLine();
Dumper.start(*Func, FunctionDumper::PointerType::None);
}
}
}
{
if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) {
auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
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<std::unique_ptr<PDBSymbolData>> Datas;
while (auto Var = Vars->getNext())
Datas.push_back(std::move(Var));
std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols);
for (const auto &Var : Datas)
Dumper.start(*Var);
}
}
{
if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) {
auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
CompilandDumper Dumper(Printer);
while (auto Thunk = Thunks->getNext())

View File

@ -14,6 +14,17 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <stdint.h>
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<llvm::pdb::PDBSymbolFunc> &F1,
const std::unique_ptr<llvm::pdb::PDBSymbolFunc> &F2);
bool compareDataSymbols(const std::unique_ptr<llvm::pdb::PDBSymbolData> &F1,
const std::unique_ptr<llvm::pdb::PDBSymbolData> &F2);
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;
extern llvm::cl::opt<bool> Globals;
@ -45,6 +67,7 @@ extern llvm::cl::list<std::string> ExcludeCompilands;
extern llvm::cl::list<std::string> IncludeTypes;
extern llvm::cl::list<std::string> IncludeSymbols;
extern llvm::cl::list<std::string> IncludeCompilands;
extern llvm::cl::opt<SymbolSortMode> SymbolOrder;
extern llvm::cl::opt<ClassSortMode> ClassOrder;
extern llvm::cl::opt<uint32_t> SizeThreshold;
extern llvm::cl::opt<uint32_t> PaddingThreshold;