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