PrettyTypeDumper.cpp revision 360784
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
32using namespace llvm;
33using namespace llvm::pdb;
34
35using LayoutPtr = std::unique_ptr<ClassLayout>;
36
37typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
38
39static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
40  return S1->getName() < S2->getName();
41}
42
43static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
44  return S1->getSize() < S2->getSize();
45}
46
47static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
48  return S1->deepPaddingSize() < S2->deepPaddingSize();
49}
50
51static 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
57static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
58  return S1->immediatePadding() < S2->immediatePadding();
59}
60
61static 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
68static 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
87template <typename Enumerator>
88static std::vector<std::unique_ptr<ClassLayout>>
89filterAndSortClassDefs(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
138TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
139
140template <typename T>
141static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
142  return false;
143}
144
145static 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
155static bool isTypeExcluded(LinePrinter &Printer,
156                           const PDBSymbolTypeTypedef &Typedef) {
157  return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
158}
159
160template <typename SymbolT>
161static 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
179static 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
193void 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
275void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
276  assert(opts::pretty::Enums);
277
278  EnumDumper Dumper(Printer);
279  Dumper.start(Symbol);
280}
281
282void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
283  BuiltinDumper BD(Printer);
284  BD.start(Symbol);
285}
286
287void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
288  printClassDecl(Printer, Symbol);
289}
290
291void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
292  assert(opts::pretty::Typedefs);
293
294  TypedefDumper Dumper(Printer);
295  Dumper.start(Symbol);
296}
297
298void 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
307void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
308  FunctionDumper Dumper(Printer);
309  Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
310}
311
312void 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
344void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
345  Printer.format("<vtshape ({0} methods)>", Symbol.getCount());
346}
347
348void 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