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