mirror of
https://github.com/RPCS3/llvm.git
synced 2025-05-24 06:16:28 +00:00

When dumping classes, show where padding occurs, and at the end of the class print statistics about how many bytes total of padding exist in a class. Since PDB doesn't specifically contain information about padding, we have to mimic this by sort of reversing a small portion of the record layout algorithm (e.g. looking at offsets and sizes and trying to determine whether something is part of the same field or a new field). Differential Revision: https://reviews.llvm.org/D31800 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299869 91177308-0d34-0410-b5e6-96231b3b80d8
210 lines
6.8 KiB
C++
210 lines
6.8 KiB
C++
//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PrettyClassDefinitionDumper.h"
|
|
|
|
#include "LinePrinter.h"
|
|
#include "PrettyEnumDumper.h"
|
|
#include "PrettyFunctionDumper.h"
|
|
#include "PrettyTypedefDumper.h"
|
|
#include "PrettyVariableDumper.h"
|
|
#include "llvm-pdbdump.h"
|
|
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/DebugInfo/PDB/IPDBSession.h"
|
|
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
|
|
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Format.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::pdb;
|
|
|
|
ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
|
|
: PDBSymDumper(true), Printer(P) {}
|
|
|
|
static void analyzePadding(const PDBSymbolTypeUDT &Class, BitVector &Padding,
|
|
uint32_t &FirstFieldOffset) {
|
|
Padding.resize(Class.getLength(), true);
|
|
auto Children = Class.findAllChildren<PDBSymbolData>();
|
|
bool IsFirst = true;
|
|
FirstFieldOffset = Class.getLength();
|
|
|
|
while (auto Data = Children->getNext()) {
|
|
// Ignore data members which are not relative to this. Usually these are
|
|
// static data members or constexpr and occupy no space. We also need to
|
|
// handle BitFields since the PDB doesn't consider them ThisRel, but they
|
|
// still occupy space in the record layout.
|
|
auto LocType = Data->getLocationType();
|
|
if (LocType != PDB_LocType::ThisRel && LocType != PDB_LocType::BitField)
|
|
continue;
|
|
|
|
uint64_t Start = Data->getOffset();
|
|
if (IsFirst) {
|
|
FirstFieldOffset = Start;
|
|
IsFirst = false;
|
|
}
|
|
|
|
auto VarType = Data->getType();
|
|
uint64_t Size = VarType->getRawSymbol().getLength();
|
|
Padding.reset(Start, Start + Size);
|
|
}
|
|
|
|
// Unmark anything that comes before the first field so it doesn't get
|
|
// counted as padding. In reality this is going to be vptrs or base class
|
|
// members, but we don't correctly handle that yet.
|
|
// FIXME: Handle it.
|
|
Padding.reset(0, FirstFieldOffset);
|
|
}
|
|
|
|
void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
|
|
assert(opts::pretty::ClassFormat !=
|
|
opts::pretty::ClassDefinitionFormat::None);
|
|
|
|
uint32_t Size = Class.getLength();
|
|
uint32_t FirstFieldOffset = 0;
|
|
BitVector Padding;
|
|
analyzePadding(Class, Padding, FirstFieldOffset);
|
|
|
|
if (opts::pretty::OnlyPaddingClasses && (Padding.count() == 0))
|
|
return;
|
|
|
|
Printer.NewLine();
|
|
WithColor(Printer, PDB_ColorItem::Comment).get() << "// sizeof = " << Size;
|
|
Printer.NewLine();
|
|
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
|
|
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
|
|
|
|
auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
|
|
if (Bases->getChildCount() > 0) {
|
|
Printer.Indent();
|
|
Printer.NewLine();
|
|
Printer << ":";
|
|
uint32_t BaseIndex = 0;
|
|
while (auto Base = Bases->getNext()) {
|
|
Printer << " ";
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
|
|
if (Base->isVirtualBaseClass())
|
|
WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
|
|
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
|
|
if (++BaseIndex < Bases->getChildCount()) {
|
|
Printer.NewLine();
|
|
Printer << ",";
|
|
}
|
|
}
|
|
Printer.Unindent();
|
|
}
|
|
|
|
Printer << " {";
|
|
auto Children = Class.findAllChildren();
|
|
Printer.Indent();
|
|
int DumpedCount = 0;
|
|
|
|
int NextPaddingByte = Padding.find_first();
|
|
while (auto Child = Children->getNext()) {
|
|
if (auto Data = llvm::dyn_cast<PDBSymbolData>(Child.get())) {
|
|
if (Data->getDataKind() == PDB_DataKind::Member && NextPaddingByte >= 0) {
|
|
// If there are padding bytes remaining, see if this field is the first
|
|
// to cross a padding boundary, and print a padding field indicator if
|
|
// so.
|
|
int Off = Data->getOffset();
|
|
if (Off > NextPaddingByte) {
|
|
uint32_t Amount = Off - NextPaddingByte;
|
|
Printer.NewLine();
|
|
WithColor(Printer, PDB_ColorItem::Padding).get()
|
|
<< "<padding> (" << Amount << " bytes)";
|
|
assert(Padding.find_next_unset(NextPaddingByte) == Off);
|
|
NextPaddingByte = Padding.find_next(Off);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (auto Func = Child->cast<PDBSymbolFunc>()) {
|
|
if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
|
|
continue;
|
|
|
|
if (Func->getLength() == 0 && !Func->isPureVirtual() &&
|
|
!Func->isIntroVirtualFunction())
|
|
continue;
|
|
}
|
|
|
|
++DumpedCount;
|
|
Child->dump(*this);
|
|
}
|
|
|
|
if (NextPaddingByte >= 0) {
|
|
uint32_t Amount = Size - NextPaddingByte;
|
|
Printer.NewLine();
|
|
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
|
|
<< " bytes)";
|
|
}
|
|
Printer.Unindent();
|
|
if (DumpedCount > 0)
|
|
Printer.NewLine();
|
|
Printer << "}";
|
|
Printer.NewLine();
|
|
if (Padding.count() > 0) {
|
|
APFloat Pct(100.0 * (double)Padding.count() /
|
|
(double)(Size - FirstFieldOffset));
|
|
SmallString<8> PctStr;
|
|
Pct.toString(PctStr, 4);
|
|
WithColor(Printer, PDB_ColorItem::Padding).get()
|
|
<< "Total padding " << Padding.count() << " bytes (" << PctStr
|
|
<< "% of class size)";
|
|
Printer.NewLine();
|
|
}
|
|
}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
|
|
VariableDumper Dumper(Printer);
|
|
Dumper.start(Symbol);
|
|
}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
|
|
if (Printer.IsSymbolExcluded(Symbol.getName()))
|
|
return;
|
|
|
|
Printer.NewLine();
|
|
FunctionDumper Dumper(Printer);
|
|
Dumper.start(Symbol, FunctionDumper::PointerType::None);
|
|
}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
|
|
if (Printer.IsTypeExcluded(Symbol.getName()))
|
|
return;
|
|
|
|
Printer.NewLine();
|
|
EnumDumper Dumper(Printer);
|
|
Dumper.start(Symbol);
|
|
}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
|
|
if (Printer.IsTypeExcluded(Symbol.getName()))
|
|
return;
|
|
|
|
Printer.NewLine();
|
|
TypedefDumper Dumper(Printer);
|
|
Dumper.start(Symbol);
|
|
}
|
|
|
|
void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
|