1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "PrettyTypeDumper.h"
11 #include "LinePrinter.h"
12 #include "PrettyBuiltinDumper.h"
13 #include "PrettyClassDefinitionDumper.h"
14 #include "PrettyEnumDumper.h"
15 #include "PrettyFunctionDumper.h"
16 #include "PrettyTypedefDumper.h"
17 #include "llvm-pdbutil.h"
19 #include "llvm/DebugInfo/PDB/IPDBSession.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
25 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
26 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
27 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
28 #include "llvm/DebugInfo/PDB/UDTLayout.h"
29 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/FormatVariadic.h"
33 using namespace llvm::pdb;
35 using LayoutPtr = std::unique_ptr<ClassLayout>;
37 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
39 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
40 return S1->getName() < S2->getName();
43 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
44 return S1->getSize() < S2->getSize();
47 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
48 return S1->deepPaddingSize() < S2->deepPaddingSize();
51 static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
52 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
53 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
57 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
58 return S1->immediatePadding() < S2->immediatePadding();
61 static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
62 const LayoutPtr &S2) {
63 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
64 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
68 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
70 case opts::pretty::ClassSortMode::Name:
72 case opts::pretty::ClassSortMode::Size:
74 case opts::pretty::ClassSortMode::Padding:
75 return ComparePadding;
76 case opts::pretty::ClassSortMode::PaddingPct:
77 return ComparePaddingPct;
78 case opts::pretty::ClassSortMode::PaddingImmediate:
79 return ComparePaddingImmediate;
80 case opts::pretty::ClassSortMode::PaddingPctImmediate:
81 return ComparePaddingPctImmediate;
87 template <typename Enumerator>
88 static std::vector<std::unique_ptr<ClassLayout>>
89 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
90 uint32_t UnfilteredCount) {
91 std::vector<std::unique_ptr<ClassLayout>> Filtered;
93 Filtered.reserve(UnfilteredCount);
94 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
96 if (UnfilteredCount > 10000) {
97 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
100 uint32_t Examined = 0;
101 uint32_t Discarded = 0;
102 while (auto Class = E.getNext()) {
104 if (Examined % 10000 == 0) {
105 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
106 Examined, UnfilteredCount, Discarded);
110 if (Class->getUnmodifiedTypeId() != 0) {
115 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
120 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
121 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
125 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
130 Filtered.push_back(std::move(Layout));
134 llvm::sort(Filtered, Comp);
138 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
140 template <typename T>
141 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
145 static bool isTypeExcluded(LinePrinter &Printer,
146 const PDBSymbolTypeEnum &Enum) {
147 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
149 // Dump member enums when dumping their class definition.
150 if (nullptr != Enum.getClassParent())
155 static bool isTypeExcluded(LinePrinter &Printer,
156 const PDBSymbolTypeTypedef &Typedef) {
157 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
160 template <typename SymbolT>
161 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
162 TypeDumper &TD, StringRef Label) {
163 if (auto Children = Exe.findAllChildren<SymbolT>()) {
165 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
166 Printer << ": (" << Children->getChildCount() << " items)";
168 while (auto Child = Children->getNext()) {
169 if (isTypeExcluded(Printer, *Child))
179 static void printClassDecl(LinePrinter &Printer,
180 const PDBSymbolTypeUDT &Class) {
181 if (Class.getUnmodifiedTypeId() != 0) {
182 if (Class.isConstType())
183 WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
184 if (Class.isVolatileType())
185 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
186 if (Class.isUnalignedType())
187 WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
189 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
190 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
193 void TypeDumper::start(const PDBSymbolExe &Exe) {
194 if (opts::pretty::Enums)
195 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
197 if (opts::pretty::Funcsigs)
198 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
199 "Function Signatures");
201 if (opts::pretty::Typedefs)
202 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
204 if (opts::pretty::Arrays)
205 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
207 if (opts::pretty::Pointers)
208 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
210 if (opts::pretty::VTShapes)
211 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
214 if (opts::pretty::Classes) {
215 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
216 uint32_t All = Classes->getChildCount();
219 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
221 bool Precompute = false;
223 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
225 // If we're using no sort mode, then we can start getting immediate output
226 // from the tool by just filtering as we go, rather than processing
227 // everything up front so that we can sort it. This makes the tool more
228 // responsive. So only precompute the filtered/sorted set of classes if
229 // necessary due to the specified options.
230 std::vector<LayoutPtr> Filtered;
231 uint32_t Shown = All;
233 Filtered = filterAndSortClassDefs(Printer, *Classes, All);
235 Shown = Filtered.size();
238 Printer << ": (Showing " << Shown << " items";
240 Printer << ", " << (All - Shown) << " filtered";
244 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
245 // the DIA enumerator and filter on the fly.
247 for (auto &Class : Filtered)
248 dumpClassLayout(*Class);
250 while (auto Class = Classes->getNext()) {
251 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
254 // No point duplicating a full class layout. Just print the modified
255 // declaration and continue.
256 if (Class->getUnmodifiedTypeId() != 0) {
258 printClassDecl(Printer, *Class);
262 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
263 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
266 dumpClassLayout(*Layout);
275 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
276 assert(opts::pretty::Enums);
278 EnumDumper Dumper(Printer);
279 Dumper.start(Symbol);
282 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
283 BuiltinDumper BD(Printer);
287 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
288 printClassDecl(Printer, Symbol);
291 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
292 assert(opts::pretty::Typedefs);
294 TypedefDumper Dumper(Printer);
295 Dumper.start(Symbol);
298 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
299 auto ElementType = Symbol.getElementType();
301 ElementType->dump(*this);
303 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
307 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
308 FunctionDumper Dumper(Printer);
309 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
312 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
313 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
315 if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
316 FunctionDumper Dumper(Printer);
317 FunctionDumper::PointerType PT =
318 Symbol.isReference() ? FunctionDumper::PointerType::Reference
319 : FunctionDumper::PointerType::Pointer;
320 Dumper.start(*FS, nullptr, PT);
324 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
325 printClassDecl(Printer, *UDT);
330 if (auto Parent = Symbol.getClassParent()) {
331 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
333 Printer << " " << UDT->getName() << "::";
336 if (Symbol.isReference())
338 else if (Symbol.isRValueReference())
344 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
345 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
348 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
349 assert(opts::pretty::Classes);
351 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
352 WithColor(Printer, PDB_ColorItem::Keyword).get()
353 << Class.getClass().getUdtKind() << " ";
354 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
356 ClassDefinitionDumper Dumper(Printer);