PrettyTypeDumper.cpp revision 319780
1//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "PrettyTypeDumper.h"
11
12#include "LinePrinter.h"
13#include "PrettyBuiltinDumper.h"
14#include "PrettyClassDefinitionDumper.h"
15#include "PrettyEnumDumper.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/PDBSymbolTypeBuiltin.h"
22#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
23#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
24#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
25#include "llvm/DebugInfo/PDB/UDTLayout.h"
26#include "llvm/Support/Compiler.h"
27#include "llvm/Support/FormatVariadic.h"
28
29using namespace llvm;
30using namespace llvm::pdb;
31
32using LayoutPtr = std::unique_ptr<ClassLayout>;
33
34typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
35
36static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
37  return S1->getName() < S2->getName();
38}
39
40static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
41  return S1->getSize() < S2->getSize();
42}
43
44static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
45  return S1->deepPaddingSize() < S2->deepPaddingSize();
46}
47
48static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) {
49  double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize();
50  double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize();
51  return Pct1 < Pct2;
52}
53
54static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
55  return S1->immediatePadding() < S2->immediatePadding();
56}
57
58static bool ComparePaddingPctImmediate(const LayoutPtr &S1,
59                                       const LayoutPtr &S2) {
60  double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize();
61  double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize();
62  return Pct1 < Pct2;
63}
64
65static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) {
66  switch (Mode) {
67  case opts::pretty::ClassSortMode::Name:
68    return CompareNames;
69  case opts::pretty::ClassSortMode::Size:
70    return CompareSizes;
71  case opts::pretty::ClassSortMode::Padding:
72    return ComparePadding;
73  case opts::pretty::ClassSortMode::PaddingPct:
74    return ComparePaddingPct;
75  case opts::pretty::ClassSortMode::PaddingImmediate:
76    return ComparePaddingImmediate;
77  case opts::pretty::ClassSortMode::PaddingPctImmediate:
78    return ComparePaddingPctImmediate;
79  default:
80    return nullptr;
81  }
82}
83
84template <typename Enumerator>
85static std::vector<std::unique_ptr<ClassLayout>>
86filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
87                       uint32_t UnfilteredCount) {
88  std::vector<std::unique_ptr<ClassLayout>> Filtered;
89
90  Filtered.reserve(UnfilteredCount);
91  CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder);
92
93  if (UnfilteredCount > 10000) {
94    errs() << formatv("Filtering and sorting {0} types", UnfilteredCount);
95    errs().flush();
96  }
97  uint32_t Examined = 0;
98  uint32_t Discarded = 0;
99  while (auto Class = E.getNext()) {
100    ++Examined;
101    if (Examined % 10000 == 0) {
102      errs() << formatv("Examined {0}/{1} items.  {2} items discarded\n",
103                        Examined, UnfilteredCount, Discarded);
104      errs().flush();
105    }
106
107    if (Class->getUnmodifiedTypeId() != 0) {
108      ++Discarded;
109      continue;
110    }
111
112    if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
113      ++Discarded;
114      continue;
115    }
116
117    auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
118    if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) {
119      ++Discarded;
120      continue;
121    }
122    if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) {
123      ++Discarded;
124      continue;
125    }
126
127    Filtered.push_back(std::move(Layout));
128  }
129
130  if (Comp)
131    std::sort(Filtered.begin(), Filtered.end(), Comp);
132  return Filtered;
133}
134
135TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
136
137void TypeDumper::start(const PDBSymbolExe &Exe) {
138  auto Children = Exe.findAllChildren();
139  if (opts::pretty::Enums) {
140    if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
141      Printer.NewLine();
142      WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
143      Printer << ": (" << Enums->getChildCount() << " items)";
144      Printer.Indent();
145      while (auto Enum = Enums->getNext())
146        Enum->dump(*this);
147      Printer.Unindent();
148    }
149  }
150
151  if (opts::pretty::Typedefs) {
152    if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
153      Printer.NewLine();
154      WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
155      Printer << ": (" << Typedefs->getChildCount() << " items)";
156      Printer.Indent();
157      while (auto Typedef = Typedefs->getNext())
158        Typedef->dump(*this);
159      Printer.Unindent();
160    }
161  }
162
163  if (opts::pretty::Classes) {
164    if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
165      uint32_t All = Classes->getChildCount();
166
167      Printer.NewLine();
168      WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
169
170      bool Precompute = false;
171      Precompute =
172          (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
173
174      // If we're using no sort mode, then we can start getting immediate output
175      // from the tool by just filtering as we go, rather than processing
176      // everything up front so that we can sort it.  This makes the tool more
177      // responsive.  So only precompute the filtered/sorted set of classes if
178      // necessary due to the specified options.
179      std::vector<LayoutPtr> Filtered;
180      uint32_t Shown = All;
181      if (Precompute) {
182        Filtered = filterAndSortClassDefs(Printer, *Classes, All);
183
184        Shown = Filtered.size();
185      }
186
187      Printer << ": (Showing " << Shown << " items";
188      if (Shown < All)
189        Printer << ", " << (All - Shown) << " filtered";
190      Printer << ")";
191      Printer.Indent();
192
193      // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
194      // the DIA enumerator and filter on the fly.
195      if (Precompute) {
196        for (auto &Class : Filtered)
197          dumpClassLayout(*Class);
198      } else {
199        while (auto Class = Classes->getNext()) {
200          if (Class->getUnmodifiedTypeId() != 0)
201            continue;
202
203          if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
204            continue;
205
206          auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
207          if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
208            continue;
209
210          dumpClassLayout(*Layout);
211        }
212      }
213
214      Printer.Unindent();
215    }
216  }
217}
218
219void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
220  assert(opts::pretty::Enums);
221
222  if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
223    return;
224  // Dump member enums when dumping their class definition.
225  if (nullptr != Symbol.getClassParent())
226    return;
227
228  Printer.NewLine();
229  EnumDumper Dumper(Printer);
230  Dumper.start(Symbol);
231}
232
233void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
234  assert(opts::pretty::Typedefs);
235
236  if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
237    return;
238
239  Printer.NewLine();
240  TypedefDumper Dumper(Printer);
241  Dumper.start(Symbol);
242}
243
244void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
245  assert(opts::pretty::Classes);
246
247  if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
248    Printer.NewLine();
249    WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
250    WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
251  } else {
252    ClassDefinitionDumper Dumper(Printer);
253    Dumper.start(Class);
254  }
255}
256