1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "PrettyTypeDumper.h"
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"
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"
33 using namespace llvm::pdb
;
35 using LayoutPtr
= std::unique_ptr
<ClassLayout
>;
37 typedef bool (*CompareFunc
)(const LayoutPtr
&S1
, const LayoutPtr
&S2
);
39 static bool CompareNames(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
40 return S1
->getName() < S2
->getName();
43 static bool CompareSizes(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
44 return S1
->getSize() < S2
->getSize();
47 static bool ComparePadding(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
48 return S1
->deepPaddingSize() < S2
->deepPaddingSize();
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();
57 static bool ComparePaddingImmediate(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
58 return S1
->immediatePadding() < S2
->immediatePadding();
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();
68 static CompareFunc
getComparisonFunc(opts::pretty::ClassSortMode Mode
) {
70 case opts::pretty::ClassSortMode::Name
:
72 case opts::pretty::ClassSortMode::Size
:
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
;
87 template <typename Enumerator
>
88 static std::vector
<std::unique_ptr
<ClassLayout
>>
89 filterAndSortClassDefs(LinePrinter
&Printer
, Enumerator
&E
,
90 uint32_t UnfilteredCount
) {
91 std::vector
<std::unique_ptr
<ClassLayout
>> Filtered
;
93 Filtered
.reserve(UnfilteredCount
);
94 CompareFunc Comp
= getComparisonFunc(opts::pretty::ClassOrder
);
96 if (UnfilteredCount
> 10000) {
97 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount
);
100 uint32_t Examined
= 0;
101 uint32_t Discarded
= 0;
102 while (auto Class
= E
.getNext()) {
104 if (Examined
% 10000 == 0) {
105 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
106 Examined
, UnfilteredCount
, Discarded
);
110 if (Class
->getUnmodifiedTypeId() != 0) {
115 if (Printer
.IsTypeExcluded(Class
->getName(), Class
->getLength())) {
120 auto Layout
= std::make_unique
<ClassLayout
>(std::move(Class
));
121 if (Layout
->deepPaddingSize() < opts::pretty::PaddingThreshold
) {
125 if (Layout
->immediatePadding() < opts::pretty::ImmediatePaddingThreshold
) {
130 Filtered
.push_back(std::move(Layout
));
134 llvm::sort(Filtered
, Comp
);
138 TypeDumper::TypeDumper(LinePrinter
&P
) : PDBSymDumper(true), Printer(P
) {}
140 template <typename T
>
141 static bool isTypeExcluded(LinePrinter
&Printer
, const T
&Symbol
) {
145 static bool isTypeExcluded(LinePrinter
&Printer
,
146 const PDBSymbolTypeEnum
&Enum
) {
147 if (Printer
.IsTypeExcluded(Enum
.getName(), Enum
.getLength()))
149 // Dump member enums when dumping their class definition.
150 if (nullptr != Enum
.getClassParent())
155 static bool isTypeExcluded(LinePrinter
&Printer
,
156 const PDBSymbolTypeTypedef
&Typedef
) {
157 return Printer
.IsTypeExcluded(Typedef
.getName(), Typedef
.getLength());
160 template <typename SymbolT
>
161 static void dumpSymbolCategory(LinePrinter
&Printer
, const PDBSymbolExe
&Exe
,
162 TypeDumper
&TD
, StringRef Label
) {
163 if (auto Children
= Exe
.findAllChildren
<SymbolT
>()) {
165 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Label
;
166 Printer
<< ": (" << Children
->getChildCount() << " items)";
168 while (auto Child
= Children
->getNext()) {
169 if (isTypeExcluded(Printer
, *Child
))
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 ";
189 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << Class
.getUdtKind() << " ";
190 WithColor(Printer
, PDB_ColorItem::Type
).get() << Class
.getName();
193 void TypeDumper::start(const PDBSymbolExe
&Exe
) {
194 if (opts::pretty::Enums
)
195 dumpSymbolCategory
<PDBSymbolTypeEnum
>(Printer
, Exe
, *this, "Enums");
197 if (opts::pretty::Funcsigs
)
198 dumpSymbolCategory
<PDBSymbolTypeFunctionSig
>(Printer
, Exe
, *this,
199 "Function Signatures");
201 if (opts::pretty::Typedefs
)
202 dumpSymbolCategory
<PDBSymbolTypeTypedef
>(Printer
, Exe
, *this, "Typedefs");
204 if (opts::pretty::Arrays
)
205 dumpSymbolCategory
<PDBSymbolTypeArray
>(Printer
, Exe
, *this, "Arrays");
207 if (opts::pretty::Pointers
)
208 dumpSymbolCategory
<PDBSymbolTypePointer
>(Printer
, Exe
, *this, "Pointers");
210 if (opts::pretty::VTShapes
)
211 dumpSymbolCategory
<PDBSymbolTypeVTableShape
>(Printer
, Exe
, *this,
214 if (opts::pretty::Classes
) {
215 if (auto Classes
= Exe
.findAllChildren
<PDBSymbolTypeUDT
>()) {
216 uint32_t All
= Classes
->getChildCount();
219 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << "Classes";
221 bool Precompute
= false;
223 (opts::pretty::ClassOrder
!= opts::pretty::ClassSortMode::None
);
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
;
233 Filtered
= filterAndSortClassDefs(Printer
, *Classes
, All
);
235 Shown
= Filtered
.size();
238 Printer
<< ": (Showing " << Shown
<< " items";
240 Printer
<< ", " << (All
- Shown
) << " filtered";
244 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
245 // the DIA enumerator and filter on the fly.
247 for (auto &Class
: Filtered
)
248 dumpClassLayout(*Class
);
250 while (auto Class
= Classes
->getNext()) {
251 if (Printer
.IsTypeExcluded(Class
->getName(), Class
->getLength()))
254 // No point duplicating a full class layout. Just print the modified
255 // declaration and continue.
256 if (Class
->getUnmodifiedTypeId() != 0) {
258 printClassDecl(Printer
, *Class
);
262 auto Layout
= std::make_unique
<ClassLayout
>(std::move(Class
));
263 if (Layout
->deepPaddingSize() < opts::pretty::PaddingThreshold
)
266 dumpClassLayout(*Layout
);
275 void TypeDumper::dump(const PDBSymbolTypeEnum
&Symbol
) {
276 assert(opts::pretty::Enums
);
278 EnumDumper
Dumper(Printer
);
279 Dumper
.start(Symbol
);
282 void TypeDumper::dump(const PDBSymbolTypeBuiltin
&Symbol
) {
283 BuiltinDumper
BD(Printer
);
287 void TypeDumper::dump(const PDBSymbolTypeUDT
&Symbol
) {
288 printClassDecl(Printer
, Symbol
);
291 void TypeDumper::dump(const PDBSymbolTypeTypedef
&Symbol
) {
292 assert(opts::pretty::Typedefs
);
294 TypedefDumper
Dumper(Printer
);
295 Dumper
.start(Symbol
);
298 void TypeDumper::dump(const PDBSymbolTypeArray
&Symbol
) {
299 auto ElementType
= Symbol
.getElementType();
301 ElementType
->dump(*this);
303 WithColor(Printer
, PDB_ColorItem::LiteralValue
).get() << Symbol
.getCount();
307 void TypeDumper::dump(const PDBSymbolTypeFunctionSig
&Symbol
) {
308 FunctionDumper
Dumper(Printer
);
309 Dumper
.start(Symbol
, nullptr, FunctionDumper::PointerType::None
);
312 void TypeDumper::dump(const PDBSymbolTypePointer
&Symbol
) {
313 std::unique_ptr
<PDBSymbol
> P
= Symbol
.getPointeeType();
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
);
324 if (auto *UDT
= dyn_cast
<PDBSymbolTypeUDT
>(P
.get())) {
325 printClassDecl(Printer
, *UDT
);
330 if (auto Parent
= Symbol
.getClassParent()) {
331 auto UDT
= llvm::unique_dyn_cast
<PDBSymbolTypeUDT
>(std::move(Parent
));
333 Printer
<< " " << UDT
->getName() << "::";
336 if (Symbol
.isReference())
338 else if (Symbol
.isRValueReference())
344 void TypeDumper::dump(const PDBSymbolTypeVTableShape
&Symbol
) {
345 Printer
.format("<vtshape ({0} methods)>", Symbol
.getCount());
348 void TypeDumper::dumpClassLayout(const ClassLayout
&Class
) {
349 assert(opts::pretty::Classes
);
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();
356 ClassDefinitionDumper
Dumper(Printer
);