• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 using namespace llvm;
30 using namespace llvm::pdb;
31 
32 using LayoutPtr = std::unique_ptr<ClassLayout>;
33 
34 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);
35 
CompareNames(const LayoutPtr & S1,const LayoutPtr & S2)36 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {
37   return S1->getName() < S2->getName();
38 }
39 
CompareSizes(const LayoutPtr & S1,const LayoutPtr & S2)40 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {
41   return S1->getSize() < S2->getSize();
42 }
43 
ComparePadding(const LayoutPtr & S1,const LayoutPtr & S2)44 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {
45   return S1->deepPaddingSize() < S2->deepPaddingSize();
46 }
47 
ComparePaddingPct(const LayoutPtr & S1,const LayoutPtr & S2)48 static 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 
ComparePaddingImmediate(const LayoutPtr & S1,const LayoutPtr & S2)54 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {
55   return S1->immediatePadding() < S2->immediatePadding();
56 }
57 
ComparePaddingPctImmediate(const LayoutPtr & S1,const LayoutPtr & S2)58 static 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 
getComparisonFunc(opts::pretty::ClassSortMode Mode)65 static 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 
84 template <typename Enumerator>
85 static std::vector<std::unique_ptr<ClassLayout>>
filterAndSortClassDefs(LinePrinter & Printer,Enumerator & E,uint32_t UnfilteredCount)86 filterAndSortClassDefs(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     llvm::sort(Filtered.begin(), Filtered.end(), Comp);
132   return Filtered;
133 }
134 
TypeDumper(LinePrinter & P)135 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
136 
start(const PDBSymbolExe & Exe)137 void TypeDumper::start(const PDBSymbolExe &Exe) {
138   if (opts::pretty::Enums) {
139     if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
140       Printer.NewLine();
141       WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
142       Printer << ": (" << Enums->getChildCount() << " items)";
143       Printer.Indent();
144       while (auto Enum = Enums->getNext())
145         Enum->dump(*this);
146       Printer.Unindent();
147     }
148   }
149 
150   if (opts::pretty::Typedefs) {
151     if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
152       Printer.NewLine();
153       WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
154       Printer << ": (" << Typedefs->getChildCount() << " items)";
155       Printer.Indent();
156       while (auto Typedef = Typedefs->getNext())
157         Typedef->dump(*this);
158       Printer.Unindent();
159     }
160   }
161 
162   if (opts::pretty::Classes) {
163     if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
164       uint32_t All = Classes->getChildCount();
165 
166       Printer.NewLine();
167       WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
168 
169       bool Precompute = false;
170       Precompute =
171           (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None);
172 
173       // If we're using no sort mode, then we can start getting immediate output
174       // from the tool by just filtering as we go, rather than processing
175       // everything up front so that we can sort it.  This makes the tool more
176       // responsive.  So only precompute the filtered/sorted set of classes if
177       // necessary due to the specified options.
178       std::vector<LayoutPtr> Filtered;
179       uint32_t Shown = All;
180       if (Precompute) {
181         Filtered = filterAndSortClassDefs(Printer, *Classes, All);
182 
183         Shown = Filtered.size();
184       }
185 
186       Printer << ": (Showing " << Shown << " items";
187       if (Shown < All)
188         Printer << ", " << (All - Shown) << " filtered";
189       Printer << ")";
190       Printer.Indent();
191 
192       // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
193       // the DIA enumerator and filter on the fly.
194       if (Precompute) {
195         for (auto &Class : Filtered)
196           dumpClassLayout(*Class);
197       } else {
198         while (auto Class = Classes->getNext()) {
199           if (Class->getUnmodifiedTypeId() != 0)
200             continue;
201 
202           if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
203             continue;
204 
205           auto Layout = llvm::make_unique<ClassLayout>(std::move(Class));
206           if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
207             continue;
208 
209           dumpClassLayout(*Layout);
210         }
211       }
212 
213       Printer.Unindent();
214     }
215   }
216 }
217 
dump(const PDBSymbolTypeEnum & Symbol)218 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
219   assert(opts::pretty::Enums);
220 
221   if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
222     return;
223   // Dump member enums when dumping their class definition.
224   if (nullptr != Symbol.getClassParent())
225     return;
226 
227   Printer.NewLine();
228   EnumDumper Dumper(Printer);
229   Dumper.start(Symbol);
230 }
231 
dump(const PDBSymbolTypeTypedef & Symbol)232 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
233   assert(opts::pretty::Typedefs);
234 
235   if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
236     return;
237 
238   Printer.NewLine();
239   TypedefDumper Dumper(Printer);
240   Dumper.start(Symbol);
241 }
242 
dumpClassLayout(const ClassLayout & Class)243 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
244   assert(opts::pretty::Classes);
245 
246   if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
247     Printer.NewLine();
248     WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
249     WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName();
250   } else {
251     ClassDefinitionDumper Dumper(Printer);
252     Dumper.start(Class);
253   }
254 }
255