1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "PrettyTypeDumper.h"
10
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"
18
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"
31
32 using namespace llvm;
33 using namespace llvm::pdb;
34
35 using LayoutPtr = std::unique_ptr<ClassLayout>;
36
37 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
38
CompareNames(const LayoutPtr & S1,const LayoutPtr & S2)39 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
40 return S1->getName() < S2->getName();
41 }
42
CompareSizes(const LayoutPtr & S1,const LayoutPtr & S2)43 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
44 return S1->getSize() < S2->getSize();
45 }
46
ComparePadding(const LayoutPtr & S1,const LayoutPtr & S2)47 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
48 return S1->deepPaddingSize() < S2->deepPaddingSize();
49 }
50
ComparePaddingPct(const LayoutPtr & S1,const LayoutPtr & S2)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();
54 return Pct1 < Pct2;
55 }
56
ComparePaddingImmediate(const LayoutPtr & S1,const LayoutPtr & S2)57 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
58 return S1->immediatePadding() < S2->immediatePadding();
59 }
60
ComparePaddingPctImmediate(const LayoutPtr & S1,const LayoutPtr & S2)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();
65 return Pct1 < Pct2;
66 }
67
getComparisonFunc(opts::pretty::ClassSortMode Mode)68 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
69 switch (Mode) {
70 case opts::pretty::ClassSortMode::Name:
71 return CompareNames;
72 case opts::pretty::ClassSortMode::Size:
73 return CompareSizes;
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;
82 default:
83 return nullptr;
84 }
85 }
86
87 template <typename Enumerator>
88 static std::vector<std::unique_ptr<ClassLayout>>
filterAndSortClassDefs(LinePrinter & Printer,Enumerator & E,uint32_t UnfilteredCount)89 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
90 uint32_t UnfilteredCount) {
91 std::vector<std::unique_ptr<ClassLayout>> Filtered;
92
93 Filtered.reserve(UnfilteredCount);
94 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
95
96 if (UnfilteredCount > 10000) {
97 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
98 errs().flush();
99 }
100 uint32_t Examined = 0;
101 uint32_t Discarded = 0;
102 while (auto Class = E.getNext()) {
103 ++Examined;
104 if (Examined % 10000 == 0) {
105 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
106 Examined, UnfilteredCount, Discarded);
107 errs().flush();
108 }
109
110 if (Class->getUnmodifiedTypeId() != 0) {
111 ++Discarded;
112 continue;
113 }
114
115 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
116 ++Discarded;
117 continue;
118 }
119
120 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
121 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
122 ++Discarded;
123 continue;
124 }
125 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
126 ++Discarded;
127 continue;
128 }
129
130 Filtered.push_back(std::move(Layout));
131 }
132
133 if (Comp)
134 llvm::sort(Filtered, Comp);
135 return Filtered;
136 }
137
TypeDumper(LinePrinter & P)138 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
139
140 template <typename T>
isTypeExcluded(LinePrinter & Printer,const T & Symbol)141 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
142 return false;
143 }
144
isTypeExcluded(LinePrinter & Printer,const PDBSymbolTypeEnum & Enum)145 static bool isTypeExcluded(LinePrinter &Printer,
146 const PDBSymbolTypeEnum &Enum) {
147 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
148 return true;
149 // Dump member enums when dumping their class definition.
150 if (nullptr != Enum.getClassParent())
151 return true;
152 return false;
153 }
154
isTypeExcluded(LinePrinter & Printer,const PDBSymbolTypeTypedef & Typedef)155 static bool isTypeExcluded(LinePrinter &Printer,
156 const PDBSymbolTypeTypedef &Typedef) {
157 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
158 }
159
160 template <typename SymbolT>
dumpSymbolCategory(LinePrinter & Printer,const PDBSymbolExe & Exe,TypeDumper & TD,StringRef Label)161 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
162 TypeDumper &TD, StringRef Label) {
163 if (auto Children = Exe.findAllChildren<SymbolT>()) {
164 Printer.NewLine();
165 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
166 Printer << ": (" << Children->getChildCount() << " items)";
167 Printer.Indent();
168 while (auto Child = Children->getNext()) {
169 if (isTypeExcluded(Printer, *Child))
170 continue;
171
172 Printer.NewLine();
173 Child->dump(TD);
174 }
175 Printer.Unindent();
176 }
177 }
178
printClassDecl(LinePrinter & Printer,const PDBSymbolTypeUDT & Class)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 ";
188 }
189 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
190 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
191 }
192
start(const PDBSymbolExe & Exe)193 void TypeDumper::start(const PDBSymbolExe &Exe) {
194 if (opts::pretty::Enums)
195 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
196
197 if (opts::pretty::Funcsigs)
198 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
199 "Function Signatures");
200
201 if (opts::pretty::Typedefs)
202 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
203
204 if (opts::pretty::Arrays)
205 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
206
207 if (opts::pretty::Pointers)
208 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
209
210 if (opts::pretty::VTShapes)
211 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
212 "VFTable Shapes");
213
214 if (opts::pretty::Classes) {
215 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
216 uint32_t All = Classes->getChildCount();
217
218 Printer.NewLine();
219 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
220
221 bool Precompute = false;
222 Precompute =
223 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
224
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;
232 if (Precompute) {
233 Filtered = filterAndSortClassDefs(Printer, *Classes, All);
234
235 Shown = Filtered.size();
236 }
237
238 Printer << ": (Showing " << Shown << " items";
239 if (Shown < All)
240 Printer << ", " << (All - Shown) << " filtered";
241 Printer << ")";
242 Printer.Indent();
243
244 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
245 // the DIA enumerator and filter on the fly.
246 if (Precompute) {
247 for (auto &Class : Filtered)
248 dumpClassLayout(*Class);
249 } else {
250 while (auto Class = Classes->getNext()) {
251 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
252 continue;
253
254 // No point duplicating a full class layout. Just print the modified
255 // declaration and continue.
256 if (Class->getUnmodifiedTypeId() != 0) {
257 Printer.NewLine();
258 printClassDecl(Printer, *Class);
259 continue;
260 }
261
262 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
263 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
264 continue;
265
266 dumpClassLayout(*Layout);
267 }
268 }
269
270 Printer.Unindent();
271 }
272 }
273 }
274
dump(const PDBSymbolTypeEnum & Symbol)275 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
276 assert(opts::pretty::Enums);
277
278 EnumDumper Dumper(Printer);
279 Dumper.start(Symbol);
280 }
281
dump(const PDBSymbolTypeBuiltin & Symbol)282 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
283 BuiltinDumper BD(Printer);
284 BD.start(Symbol);
285 }
286
dump(const PDBSymbolTypeUDT & Symbol)287 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
288 printClassDecl(Printer, Symbol);
289 }
290
dump(const PDBSymbolTypeTypedef & Symbol)291 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
292 assert(opts::pretty::Typedefs);
293
294 TypedefDumper Dumper(Printer);
295 Dumper.start(Symbol);
296 }
297
dump(const PDBSymbolTypeArray & Symbol)298 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
299 auto ElementType = Symbol.getElementType();
300
301 ElementType->dump(*this);
302 Printer << "[";
303 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
304 Printer << "]";
305 }
306
dump(const PDBSymbolTypeFunctionSig & Symbol)307 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
308 FunctionDumper Dumper(Printer);
309 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
310 }
311
dump(const PDBSymbolTypePointer & Symbol)312 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
313 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
314
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);
321 return;
322 }
323
324 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
325 printClassDecl(Printer, *UDT);
326 } else if (P) {
327 P->dump(*this);
328 }
329
330 if (auto Parent = Symbol.getClassParent()) {
331 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
332 if (UDT)
333 Printer << " " << UDT->getName() << "::";
334 }
335
336 if (Symbol.isReference())
337 Printer << "&";
338 else if (Symbol.isRValueReference())
339 Printer << "&&";
340 else
341 Printer << "*";
342 }
343
dump(const PDBSymbolTypeVTableShape & Symbol)344 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
345 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
346 }
347
dumpClassLayout(const ClassLayout & Class)348 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
349 assert(opts::pretty::Classes);
350
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();
355 } else {
356 ClassDefinitionDumper Dumper(Printer);
357 Dumper.start(Class);
358 }
359 }
360