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 "PrettyBuiltinDumper.h"
12 #include "PrettyClassDefinitionDumper.h"
13 #include "PrettyEnumDumper.h"
14 #include "PrettyFunctionDumper.h"
15 #include "PrettyTypedefDumper.h"
16 #include "llvm-pdbutil.h"
17
18 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
19 #include "llvm/DebugInfo/PDB/IPDBLineNumber.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/PDBSymbolTypeVTableShape.h"
30 #include "llvm/DebugInfo/PDB/UDTLayout.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/FormatVariadic.h"
33
34 using namespace llvm;
35 using namespace llvm::pdb;
36
37 using LayoutPtr = std::unique_ptr<ClassLayout>;
38
39 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
40
CompareNames(const LayoutPtr & S1,const LayoutPtr & S2)41 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
42 return S1->getName() < S2->getName();
43 }
44
CompareSizes(const LayoutPtr & S1,const LayoutPtr & S2)45 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
46 return S1->getSize() < S2->getSize();
47 }
48
ComparePadding(const LayoutPtr & S1,const LayoutPtr & S2)49 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
50 return S1->deepPaddingSize() < S2->deepPaddingSize();
51 }
52
ComparePaddingPct(const LayoutPtr & S1,const LayoutPtr & S2)53 static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
54 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
55 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
56 return Pct1 < Pct2;
57 }
58
ComparePaddingImmediate(const LayoutPtr & S1,const LayoutPtr & S2)59 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
60 return S1->immediatePadding() < S2->immediatePadding();
61 }
62
ComparePaddingPctImmediate(const LayoutPtr & S1,const LayoutPtr & S2)63 static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
64 const LayoutPtr &S2) {
65 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
66 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
67 return Pct1 < Pct2;
68 }
69
getComparisonFunc(opts::pretty::ClassSortMode Mode)70 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
71 switch (Mode) {
72 case opts::pretty::ClassSortMode::Name:
73 return CompareNames;
74 case opts::pretty::ClassSortMode::Size:
75 return CompareSizes;
76 case opts::pretty::ClassSortMode::Padding:
77 return ComparePadding;
78 case opts::pretty::ClassSortMode::PaddingPct:
79 return ComparePaddingPct;
80 case opts::pretty::ClassSortMode::PaddingImmediate:
81 return ComparePaddingImmediate;
82 case opts::pretty::ClassSortMode::PaddingPctImmediate:
83 return ComparePaddingPctImmediate;
84 default:
85 return nullptr;
86 }
87 }
88
89 template <typename Enumerator>
90 static std::vector<std::unique_ptr<ClassLayout>>
filterAndSortClassDefs(LinePrinter & Printer,Enumerator & E,uint32_t UnfilteredCount)91 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
92 uint32_t UnfilteredCount) {
93 std::vector<std::unique_ptr<ClassLayout>> Filtered;
94
95 Filtered.reserve(UnfilteredCount);
96 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
97
98 if (UnfilteredCount > 10000) {
99 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
100 errs().flush();
101 }
102 uint32_t Examined = 0;
103 uint32_t Discarded = 0;
104 while (auto Class = E.getNext()) {
105 ++Examined;
106 if (Examined % 10000 == 0) {
107 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
108 Examined, UnfilteredCount, Discarded);
109 errs().flush();
110 }
111
112 if (Class->getUnmodifiedTypeId() != 0) {
113 ++Discarded;
114 continue;
115 }
116
117 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
118 ++Discarded;
119 continue;
120 }
121
122 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
123 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
124 ++Discarded;
125 continue;
126 }
127 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
128 ++Discarded;
129 continue;
130 }
131
132 Filtered.push_back(std::move(Layout));
133 }
134
135 if (Comp)
136 llvm::sort(Filtered, Comp);
137 return Filtered;
138 }
139
TypeDumper(LinePrinter & P)140 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
141
142 template <typename T>
isTypeExcluded(LinePrinter & Printer,const T & Symbol)143 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
144 return false;
145 }
146
isTypeExcluded(LinePrinter & Printer,const PDBSymbolTypeEnum & Enum)147 static bool isTypeExcluded(LinePrinter &Printer,
148 const PDBSymbolTypeEnum &Enum) {
149 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
150 return true;
151 // Dump member enums when dumping their class definition.
152 if (nullptr != Enum.getClassParent())
153 return true;
154 return false;
155 }
156
isTypeExcluded(LinePrinter & Printer,const PDBSymbolTypeTypedef & Typedef)157 static bool isTypeExcluded(LinePrinter &Printer,
158 const PDBSymbolTypeTypedef &Typedef) {
159 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
160 }
161
162 template <typename SymbolT>
dumpSymbolCategory(LinePrinter & Printer,const PDBSymbolExe & Exe,TypeDumper & TD,StringRef Label)163 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
164 TypeDumper &TD, StringRef Label) {
165 if (auto Children = Exe.findAllChildren<SymbolT>()) {
166 Printer.NewLine();
167 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
168 Printer << ": (" << Children->getChildCount() << " items)";
169 Printer.Indent();
170 while (auto Child = Children->getNext()) {
171 if (isTypeExcluded(Printer, *Child))
172 continue;
173
174 Printer.NewLine();
175 Child->dump(TD);
176 }
177 Printer.Unindent();
178 }
179 }
180
printClassDecl(LinePrinter & Printer,const PDBSymbolTypeUDT & Class)181 static void printClassDecl(LinePrinter &Printer,
182 const PDBSymbolTypeUDT &Class) {
183 if (Class.getUnmodifiedTypeId() != 0) {
184 if (Class.isConstType())
185 WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
186 if (Class.isVolatileType())
187 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
188 if (Class.isUnalignedType())
189 WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
190 }
191 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
192 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
193 }
194
start(const PDBSymbolExe & Exe)195 void TypeDumper::start(const PDBSymbolExe &Exe) {
196 if (opts::pretty::Enums)
197 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
198
199 if (opts::pretty::Funcsigs)
200 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
201 "Function Signatures");
202
203 if (opts::pretty::Typedefs)
204 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
205
206 if (opts::pretty::Arrays)
207 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays");
208
209 if (opts::pretty::Pointers)
210 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
211
212 if (opts::pretty::VTShapes)
213 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this,
214 "VFTable Shapes");
215
216 if (opts::pretty::Classes) {
217 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
218 uint32_t All = Classes->getChildCount();
219
220 Printer.NewLine();
221 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
222
223 bool Precompute = false;
224 Precompute =
225 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
226
227 // If we're using no sort mode, then we can start getting immediate output
228 // from the tool by just filtering as we go, rather than processing
229 // everything up front so that we can sort it. This makes the tool more
230 // responsive. So only precompute the filtered/sorted set of classes if
231 // necessary due to the specified options.
232 std::vector<LayoutPtr> Filtered;
233 uint32_t Shown = All;
234 if (Precompute) {
235 Filtered = filterAndSortClassDefs(Printer, *Classes, All);
236
237 Shown = Filtered.size();
238 }
239
240 Printer << ": (Showing " << Shown << " items";
241 if (Shown < All)
242 Printer << ", " << (All - Shown) << " filtered";
243 Printer << ")";
244 Printer.Indent();
245
246 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
247 // the DIA enumerator and filter on the fly.
248 if (Precompute) {
249 for (auto &Class : Filtered)
250 dumpClassLayout(*Class);
251 } else {
252 while (auto Class = Classes->getNext()) {
253 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
254 continue;
255
256 // No point duplicating a full class layout. Just print the modified
257 // declaration and continue.
258 if (Class->getUnmodifiedTypeId() != 0) {
259 Printer.NewLine();
260 printClassDecl(Printer, *Class);
261 continue;
262 }
263
264 auto Layout = std::make_unique<ClassLayout>(std::move(Class));
265 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
266 continue;
267
268 dumpClassLayout(*Layout);
269 }
270 }
271
272 Printer.Unindent();
273 }
274 }
275 }
276
dump(const PDBSymbolTypeEnum & Symbol)277 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
278 assert(opts::pretty::Enums);
279
280 EnumDumper Dumper(Printer);
281 Dumper.start(Symbol);
282 }
283
dump(const PDBSymbolTypeBuiltin & Symbol)284 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
285 BuiltinDumper BD(Printer);
286 BD.start(Symbol);
287 }
288
dump(const PDBSymbolTypeUDT & Symbol)289 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
290 printClassDecl(Printer, Symbol);
291 }
292
dump(const PDBSymbolTypeTypedef & Symbol)293 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
294 assert(opts::pretty::Typedefs);
295
296 TypedefDumper Dumper(Printer);
297 Dumper.start(Symbol);
298 }
299
dump(const PDBSymbolTypeArray & Symbol)300 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) {
301 auto ElementType = Symbol.getElementType();
302
303 ElementType->dump(*this);
304 Printer << "[";
305 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount();
306 Printer << "]";
307 }
308
dump(const PDBSymbolTypeFunctionSig & Symbol)309 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
310 FunctionDumper Dumper(Printer);
311 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
312 }
313
dump(const PDBSymbolTypePointer & Symbol)314 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
315 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
316
317 if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
318 FunctionDumper Dumper(Printer);
319 FunctionDumper::PointerType PT =
320 Symbol.isReference() ? FunctionDumper::PointerType::Reference
321 : FunctionDumper::PointerType::Pointer;
322 Dumper.start(*FS, nullptr, PT);
323 return;
324 }
325
326 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
327 printClassDecl(Printer, *UDT);
328 } else if (P) {
329 P->dump(*this);
330 }
331
332 if (auto Parent = Symbol.getClassParent()) {
333 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
334 if (UDT)
335 Printer << " " << UDT->getName() << "::";
336 }
337
338 if (Symbol.isReference())
339 Printer << "&";
340 else if (Symbol.isRValueReference())
341 Printer << "&&";
342 else
343 Printer << "*";
344 }
345
dump(const PDBSymbolTypeVTableShape & Symbol)346 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
347 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
348 }
349
dumpClassLayout(const ClassLayout & Class)350 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
351 assert(opts::pretty::Classes);
352
353 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
354 WithColor(Printer, PDB_ColorItem::Keyword).get()
355 << Class.getClass().getUdtKind() << " ";
356 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
357 } else {
358 ClassDefinitionDumper Dumper(Printer);
359 Dumper.start(Class);
360 }
361 }
362