blob: 0f6086395ad1c19a08abc6af97938a698be3d8c8 [file] [log] [blame]
//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "PrettyTypeDumper.h"
#include "LinePrinter.h"
#include "PrettyBuiltinDumper.h"
#include "PrettyClassDefinitionDumper.h"
#include "PrettyEnumDumper.h"
#include "PrettyTypedefDumper.h"
#include "llvm-pdbutil.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
using namespace llvm::pdb;
using LayoutPtr = std::unique_ptr<ClassLayout>;
typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
return S1->getName() < S2->getName();
}
static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
return S1->getSize() < S2->getSize();
}
static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
return S1->deepPaddingSize() < S2->deepPaddingSize();
}
static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
return Pct1 < Pct2;
}
static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
return S1->immediatePadding() < S2->immediatePadding();
}
static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
const LayoutPtr &S2) {
double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
return Pct1 < Pct2;
}
static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
switch (Mode) {
case opts::pretty::ClassSortMode::Name:
return CompareNames;
case opts::pretty::ClassSortMode::Size:
return CompareSizes;
case opts::pretty::ClassSortMode::Padding:
return ComparePadding;
case opts::pretty::ClassSortMode::PaddingPct:
return ComparePaddingPct;
case opts::pretty::ClassSortMode::PaddingImmediate:
return ComparePaddingImmediate;
case opts::pretty::ClassSortMode::PaddingPctImmediate:
return ComparePaddingPctImmediate;
default:
return nullptr;
}
}
template <typename Enumerator>
static std::vector<std::unique_ptr<ClassLayout>>
filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
uint32_t UnfilteredCount) {
std::vector<std::unique_ptr<ClassLayout>> Filtered;
Filtered.reserve(UnfilteredCount);
CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
if (UnfilteredCount > 10000) {
errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
errs().flush();
}
uint32_t Examined = 0;
uint32_t Discarded = 0;
while (auto Class = E.getNext()) {
++Examined;
if (Examined % 10000 == 0) {
errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
Examined, UnfilteredCount, Discarded);
errs().flush();
}
if (Class->getUnmodifiedTypeId() != 0) {
++Discarded;
continue;
}
if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
++Discarded;
continue;
}
auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
++Discarded;
continue;
}
if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
++Discarded;
continue;
}
Filtered.push_back(std::move(Layout));
}
if (Comp)
std::sort(Filtered.begin(), Filtered.end(), Comp);
return Filtered;
}
TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
void TypeDumper::start(const PDBSymbolExe &Exe) {
auto Children = Exe.findAllChildren();
if (opts::pretty::Enums) {
if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
Printer << ": (" << Enums->getChildCount() << " items)";
Printer.Indent();
while (auto Enum = Enums->getNext())
Enum->dump(*this);
Printer.Unindent();
}
}
if (opts::pretty::Typedefs) {
if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
Printer << ": (" << Typedefs->getChildCount() << " items)";
Printer.Indent();
while (auto Typedef = Typedefs->getNext())
Typedef->dump(*this);
Printer.Unindent();
}
}
if (opts::pretty::Classes) {
if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
uint32_t All = Classes->getChildCount();
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
bool Precompute = false;
Precompute =
(opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
// If we're using no sort mode, then we can start getting immediate output
// from the tool by just filtering as we go, rather than processing
// everything up front so that we can sort it. This makes the tool more
// responsive. So only precompute the filtered/sorted set of classes if
// necessary due to the specified options.
std::vector<LayoutPtr> Filtered;
uint32_t Shown = All;
if (Precompute) {
Filtered = filterAndSortClassDefs(Printer, *Classes, All);
Shown = Filtered.size();
}
Printer << ": (Showing " << Shown << " items";
if (Shown < All)
Printer << ", " << (All - Shown) << " filtered";
Printer << ")";
Printer.Indent();
// If we pre-computed, iterate the filtered/sorted list, otherwise iterate
// the DIA enumerator and filter on the fly.
if (Precompute) {
for (auto &Class : Filtered)
dumpClassLayout(*Class);
} else {
while (auto Class = Classes->getNext()) {
if (Class->getUnmodifiedTypeId() != 0)
continue;
if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
continue;
auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
continue;
dumpClassLayout(*Layout);
}
}
Printer.Unindent();
}
}
}
void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
assert(opts::pretty::Enums);
if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
// Dump member enums when dumping their class definition.
if (nullptr != Symbol.getClassParent())
return;
Printer.NewLine();
EnumDumper Dumper(Printer);
Dumper.start(Symbol);
}
void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
assert(opts::pretty::Typedefs);
if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
Printer.NewLine();
TypedefDumper Dumper(Printer);
Dumper.start(Symbol);
}
void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
assert(opts::pretty::Classes);
if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
} else {
ClassDefinitionDumper Dumper(Printer);
Dumper.start(Class);
}
}