1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PrettyTypeDumper.h"
12 #include "LinePrinter.h"
13 #include "PrettyBuiltinDumper.h"
14 #include "PrettyClassDefinitionDumper.h"
15 #include "PrettyEnumDumper.h"
16 #include "PrettyFunctionDumper.h"
17 #include "PrettyTypedefDumper.h"
18 #include "llvm-pdbutil.h"
20 #include "llvm/DebugInfo/PDB/IPDBSession.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
25 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
26 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
27 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
28 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
29 #include "llvm/DebugInfo/PDB/UDTLayout.h"
30 #include "llvm/Support/Compiler.h"
31 #include "llvm/Support/FormatVariadic.h"
34 using namespace llvm::pdb;
36 using LayoutPtr = std::unique_ptr<ClassLayout>;
38 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
40 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
41 return S1->getName() < S2->getName();
44 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
45 return S1->getSize() < S2->getSize();
48 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
49 return S1->deepPaddingSize() < S2->deepPaddingSize();
52 static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
53 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
54 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
58 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
59 return S1->immediatePadding() < S2->immediatePadding();
62 static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
63 const LayoutPtr &S2) {
64 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
65 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
69 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
71 case opts::pretty::ClassSortMode::Name:
73 case opts::pretty::ClassSortMode::Size:
75 case opts::pretty::ClassSortMode::Padding:
76 return ComparePadding;
77 case opts::pretty::ClassSortMode::PaddingPct:
78 return ComparePaddingPct;
79 case opts::pretty::ClassSortMode::PaddingImmediate:
80 return ComparePaddingImmediate;
81 case opts::pretty::ClassSortMode::PaddingPctImmediate:
82 return ComparePaddingPctImmediate;
88 template <typename Enumerator>
89 static std::vector<std::unique_ptr<ClassLayout>>
90 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
91 uint32_t UnfilteredCount) {
92 std::vector<std::unique_ptr<ClassLayout>> Filtered;
94 Filtered.reserve(UnfilteredCount);
95 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
97 if (UnfilteredCount > 10000) {
98 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
101 uint32_t Examined = 0;
102 uint32_t Discarded = 0;
103 while (auto Class = E.getNext()) {
105 if (Examined % 10000 == 0) {
106 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
107 Examined, UnfilteredCount, Discarded);
111 if (Class->getUnmodifiedTypeId() != 0) {
116 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
121 auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
122 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
126 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
131 Filtered.push_back(std::move(Layout));
135 llvm::sort(Filtered, Comp);
139 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
141 template <typename T>
142 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
146 static bool isTypeExcluded(LinePrinter &Printer,
147 const PDBSymbolTypeEnum &Enum) {
148 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
150 // Dump member enums when dumping their class definition.
151 if (nullptr != Enum.getClassParent())
156 static bool isTypeExcluded(LinePrinter &Printer,
157 const PDBSymbolTypeTypedef &Typedef) {
158 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
161 template <typename SymbolT>
162 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
163 TypeDumper &TD, StringRef Label) {
164 if (auto Children = Exe.findAllChildren<SymbolT>()) {
166 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
167 Printer << ": (" << Children->getChildCount() << " items)";
169 while (auto Child = Children->getNext()) {
170 if (isTypeExcluded(Printer, *Child))
180 static void printClassDecl(LinePrinter &Printer,
181 const PDBSymbolTypeUDT &Class) {
182 if (Class.getUnmodifiedTypeId() != 0) {
183 if (Class.isConstType())
184 WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
185 if (Class.isVolatileType())
186 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
187 if (Class.isUnalignedType())
188 WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
190 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
191 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
194 void TypeDumper::start(const PDBSymbolExe &Exe) {
195 if (opts::pretty::Enums)
196 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
198 if (opts::pretty::Funcsigs)
199 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
200 "Function Signatures");
202 if (opts::pretty::Typedefs)
203 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
205 if (opts::pretty::Arrays)
206 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
208 if (opts::pretty::Pointers)
209 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
211 if (opts::pretty::VTShapes)
212 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
215 if (opts::pretty::Classes) {
216 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
217 uint32_t All = Classes->getChildCount();
220 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
222 bool Precompute = false;
224 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
226 // If we're using no sort mode, then we can start getting immediate output
227 // from the tool by just filtering as we go, rather than processing
228 // everything up front so that we can sort it. This makes the tool more
229 // responsive. So only precompute the filtered/sorted set of classes if
230 // necessary due to the specified options.
231 std::vector<LayoutPtr> Filtered;
232 uint32_t Shown = All;
234 Filtered = filterAndSortClassDefs(Printer, *Classes, All);
236 Shown = Filtered.size();
239 Printer << ": (Showing " << Shown << " items";
241 Printer << ", " << (All - Shown) << " filtered";
245 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
246 // the DIA enumerator and filter on the fly.
248 for (auto &Class : Filtered)
249 dumpClassLayout(*Class);
251 while (auto Class = Classes->getNext()) {
252 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
255 // No point duplicating a full class layout. Just print the modified
256 // declaration and continue.
257 if (Class->getUnmodifiedTypeId() != 0) {
259 printClassDecl(Printer, *Class);
263 auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
264 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
267 dumpClassLayout(*Layout);
276 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
277 assert(opts::pretty::Enums);
279 EnumDumper Dumper(Printer);
280 Dumper.start(Symbol);
283 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
284 BuiltinDumper BD(Printer);
288 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
289 printClassDecl(Printer, Symbol);
292 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
293 assert(opts::pretty::Typedefs);
295 TypedefDumper Dumper(Printer);
296 Dumper.start(Symbol);
299 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
300 auto ElementType = Symbol.getElementType();
302 ElementType->dump(*this);
304 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
308 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
309 FunctionDumper Dumper(Printer);
310 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
313 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
314 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
316 if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
317 FunctionDumper Dumper(Printer);
318 FunctionDumper::PointerType PT =
319 Symbol.isReference() ? FunctionDumper::PointerType::Reference
320 : FunctionDumper::PointerType::Pointer;
321 Dumper.start(*FS, nullptr, PT);
325 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
326 printClassDecl(Printer, *UDT);
331 if (auto Parent = Symbol.getClassParent()) {
332 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
334 Printer << " " << UDT->getName() << "::";
337 if (Symbol.isReference())
339 else if (Symbol.isRValueReference())
345 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
346 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
349 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
350 assert(opts::pretty::Classes);
352 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
353 WithColor(Printer, PDB_ColorItem::Keyword).get()
354 << Class.getClass().getUdtKind() << " ";
355 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
357 ClassDefinitionDumper Dumper(Printer);