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