mirror of
https://github.com/RPCS3/llvm.git
synced 2026-01-31 01:25:19 +01:00
Now that we've moved to C++14, we no longer need the llvm::make_unique implementation from STLExtras.h. This patch is a mechanical replacement of (hopefully) all the llvm::make_unique instances across the monorepo. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369013 91177308-0d34-0410-b5e6-96231b3b80d8
360 lines
11 KiB
C++
360 lines
11 KiB
C++
//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PrettyTypeDumper.h"
|
|
|
|
#include "LinePrinter.h"
|
|
#include "PrettyBuiltinDumper.h"
|
|
#include "PrettyClassDefinitionDumper.h"
|
|
#include "PrettyEnumDumper.h"
|
|
#include "PrettyFunctionDumper.h"
|
|
#include "PrettyTypedefDumper.h"
|
|
#include "llvm-pdbutil.h"
|
|
|
|
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.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 = std::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)
|
|
llvm::sort(Filtered, Comp);
|
|
return Filtered;
|
|
}
|
|
|
|
TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
|
|
|
|
template <typename T>
|
|
static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
|
|
return false;
|
|
}
|
|
|
|
static bool isTypeExcluded(LinePrinter &Printer,
|
|
const PDBSymbolTypeEnum &Enum) {
|
|
if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
|
|
return true;
|
|
// Dump member enums when dumping their class definition.
|
|
if (nullptr != Enum.getClassParent())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static bool isTypeExcluded(LinePrinter &Printer,
|
|
const PDBSymbolTypeTypedef &Typedef) {
|
|
return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
|
|
}
|
|
|
|
template <typename SymbolT>
|
|
static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
|
|
TypeDumper &TD, StringRef Label) {
|
|
if (auto Children = Exe.findAllChildren<SymbolT>()) {
|
|
Printer.NewLine();
|
|
WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
|
|
Printer << ": (" << Children->getChildCount() << " items)";
|
|
Printer.Indent();
|
|
while (auto Child = Children->getNext()) {
|
|
if (isTypeExcluded(Printer, *Child))
|
|
continue;
|
|
|
|
Printer.NewLine();
|
|
Child->dump(TD);
|
|
}
|
|
Printer.Unindent();
|
|
}
|
|
}
|
|
|
|
static void printClassDecl(LinePrinter &Printer,
|
|
const PDBSymbolTypeUDT &Class) {
|
|
if (Class.getUnmodifiedTypeId() != 0) {
|
|
if (Class.isConstType())
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
|
|
if (Class.isVolatileType())
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
|
|
if (Class.isUnalignedType())
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
|
|
}
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
|
|
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
|
|
}
|
|
|
|
void TypeDumper::start(const PDBSymbolExe &Exe) {
|
|
if (opts::pretty::Enums)
|
|
dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
|
|
|
|
if (opts::pretty::Funcsigs)
|
|
dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
|
|
"Function Signatures");
|
|
|
|
if (opts::pretty::Typedefs)
|
|
dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
|
|
|
|
if (opts::pretty::Arrays)
|
|
dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
|
|
|
|
if (opts::pretty::Pointers)
|
|
dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
|
|
|
|
if (opts::pretty::VTShapes)
|
|
dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
|
|
"VFTable Shapes");
|
|
|
|
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 (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
|
|
continue;
|
|
|
|
// No point duplicating a full class layout. Just print the modified
|
|
// declaration and continue.
|
|
if (Class->getUnmodifiedTypeId() != 0) {
|
|
Printer.NewLine();
|
|
printClassDecl(Printer, *Class);
|
|
continue;
|
|
}
|
|
|
|
auto Layout = std::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);
|
|
|
|
EnumDumper Dumper(Printer);
|
|
Dumper.start(Symbol);
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
|
|
BuiltinDumper BD(Printer);
|
|
BD.start(Symbol);
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
|
printClassDecl(Printer, Symbol);
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
|
assert(opts::pretty::Typedefs);
|
|
|
|
TypedefDumper Dumper(Printer);
|
|
Dumper.start(Symbol);
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
|
|
auto ElementType = Symbol.getElementType();
|
|
|
|
ElementType->dump(*this);
|
|
Printer << "[";
|
|
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
|
|
Printer << "]";
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
|
|
FunctionDumper Dumper(Printer);
|
|
Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
|
|
std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
|
|
|
|
if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
|
|
FunctionDumper Dumper(Printer);
|
|
FunctionDumper::PointerType PT =
|
|
Symbol.isReference() ? FunctionDumper::PointerType::Reference
|
|
: FunctionDumper::PointerType::Pointer;
|
|
Dumper.start(*FS, nullptr, PT);
|
|
return;
|
|
}
|
|
|
|
if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
|
|
printClassDecl(Printer, *UDT);
|
|
} else if (P) {
|
|
P->dump(*this);
|
|
}
|
|
|
|
if (auto Parent = Symbol.getClassParent()) {
|
|
auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
|
|
if (UDT)
|
|
Printer << " " << UDT->getName() << "::";
|
|
}
|
|
|
|
if (Symbol.isReference())
|
|
Printer << "&";
|
|
else if (Symbol.isRValueReference())
|
|
Printer << "&&";
|
|
else
|
|
Printer << "*";
|
|
}
|
|
|
|
void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
|
|
Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
|
|
}
|
|
|
|
void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
|
|
assert(opts::pretty::Classes);
|
|
|
|
if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get()
|
|
<< Class.getClass().getUdtKind() << " ";
|
|
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
|
|
} else {
|
|
ClassDefinitionDumper Dumper(Printer);
|
|
Dumper.start(Class);
|
|
}
|
|
}
|