• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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