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 "PrettyBuiltinDumper.h"
12 #include "PrettyClassDefinitionDumper.h"
13 #include "PrettyEnumDumper.h"
14 #include "PrettyFunctionDumper.h"
15 #include "PrettyTypedefDumper.h"
16 #include "llvm-pdbutil.h"
18 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
19 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
20 #include "llvm/DebugInfo/PDB/IPDBSession.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
25 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
26 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
27 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
28 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
29 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
30 #include "llvm/DebugInfo/PDB/UDTLayout.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/FormatVariadic.h"
35 using namespace llvm::pdb
;
37 using LayoutPtr
= std::unique_ptr
<ClassLayout
>;
39 typedef bool (*CompareFunc
)(const LayoutPtr
&S1
, const LayoutPtr
&S2
);
41 static bool CompareNames(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
42 return S1
->getName() < S2
->getName();
45 static bool CompareSizes(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
46 return S1
->getSize() < S2
->getSize();
49 static bool ComparePadding(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
50 return S1
->deepPaddingSize() < S2
->deepPaddingSize();
53 static bool ComparePaddingPct(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
54 double Pct1
= (double)S1
->deepPaddingSize() / (double)S1
->getSize();
55 double Pct2
= (double)S2
->deepPaddingSize() / (double)S2
->getSize();
59 static bool ComparePaddingImmediate(const LayoutPtr
&S1
, const LayoutPtr
&S2
) {
60 return S1
->immediatePadding() < S2
->immediatePadding();
63 static bool ComparePaddingPctImmediate(const LayoutPtr
&S1
,
64 const LayoutPtr
&S2
) {
65 double Pct1
= (double)S1
->immediatePadding() / (double)S1
->getSize();
66 double Pct2
= (double)S2
->immediatePadding() / (double)S2
->getSize();
70 static CompareFunc
getComparisonFunc(opts::pretty::ClassSortMode Mode
) {
72 case opts::pretty::ClassSortMode::Name
:
74 case opts::pretty::ClassSortMode::Size
:
76 case opts::pretty::ClassSortMode::Padding
:
77 return ComparePadding
;
78 case opts::pretty::ClassSortMode::PaddingPct
:
79 return ComparePaddingPct
;
80 case opts::pretty::ClassSortMode::PaddingImmediate
:
81 return ComparePaddingImmediate
;
82 case opts::pretty::ClassSortMode::PaddingPctImmediate
:
83 return ComparePaddingPctImmediate
;
89 template <typename Enumerator
>
90 static std::vector
<std::unique_ptr
<ClassLayout
>>
91 filterAndSortClassDefs(LinePrinter
&Printer
, Enumerator
&E
,
92 uint32_t UnfilteredCount
) {
93 std::vector
<std::unique_ptr
<ClassLayout
>> Filtered
;
95 Filtered
.reserve(UnfilteredCount
);
96 CompareFunc Comp
= getComparisonFunc(opts::pretty::ClassOrder
);
98 if (UnfilteredCount
> 10000) {
99 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount
);
102 uint32_t Examined
= 0;
103 uint32_t Discarded
= 0;
104 while (auto Class
= E
.getNext()) {
106 if (Examined
% 10000 == 0) {
107 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
108 Examined
, UnfilteredCount
, Discarded
);
112 if (Class
->getUnmodifiedTypeId() != 0) {
117 if (Printer
.IsTypeExcluded(Class
->getName(), Class
->getLength())) {
122 auto Layout
= std::make_unique
<ClassLayout
>(std::move(Class
));
123 if (Layout
->deepPaddingSize() < opts::pretty::PaddingThreshold
) {
127 if (Layout
->immediatePadding() < opts::pretty::ImmediatePaddingThreshold
) {
132 Filtered
.push_back(std::move(Layout
));
136 llvm::sort(Filtered
, Comp
);
140 TypeDumper::TypeDumper(LinePrinter
&P
) : PDBSymDumper(true), Printer(P
) {}
142 template <typename T
>
143 static bool isTypeExcluded(LinePrinter
&Printer
, const T
&Symbol
) {
147 static bool isTypeExcluded(LinePrinter
&Printer
,
148 const PDBSymbolTypeEnum
&Enum
) {
149 if (Printer
.IsTypeExcluded(Enum
.getName(), Enum
.getLength()))
151 // Dump member enums when dumping their class definition.
152 if (nullptr != Enum
.getClassParent())
157 static bool isTypeExcluded(LinePrinter
&Printer
,
158 const PDBSymbolTypeTypedef
&Typedef
) {
159 return Printer
.IsTypeExcluded(Typedef
.getName(), Typedef
.getLength());
162 template <typename SymbolT
>
163 static void dumpSymbolCategory(LinePrinter
&Printer
, const PDBSymbolExe
&Exe
,
164 TypeDumper
&TD
, StringRef Label
) {
165 if (auto Children
= Exe
.findAllChildren
<SymbolT
>()) {
167 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Label
;
168 Printer
<< ": (" << Children
->getChildCount() << " items)";
170 while (auto Child
= Children
->getNext()) {
171 if (isTypeExcluded(Printer
, *Child
))
181 static void printClassDecl(LinePrinter
&Printer
,
182 const PDBSymbolTypeUDT
&Class
) {
183 if (Class
.getUnmodifiedTypeId() != 0) {
184 if (Class
.isConstType())
185 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "const ";
186 if (Class
.isVolatileType())
187 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "volatile ";
188 if (Class
.isUnalignedType())
189 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << "unaligned ";
191 WithColor(Printer
, PDB_ColorItem::Keyword
).get() << Class
.getUdtKind() << " ";
192 WithColor(Printer
, PDB_ColorItem::Type
).get() << Class
.getName();
195 void TypeDumper::start(const PDBSymbolExe
&Exe
) {
196 if (opts::pretty::Enums
)
197 dumpSymbolCategory
<PDBSymbolTypeEnum
>(Printer
, Exe
, *this, "Enums");
199 if (opts::pretty::Funcsigs
)
200 dumpSymbolCategory
<PDBSymbolTypeFunctionSig
>(Printer
, Exe
, *this,
201 "Function Signatures");
203 if (opts::pretty::Typedefs
)
204 dumpSymbolCategory
<PDBSymbolTypeTypedef
>(Printer
, Exe
, *this, "Typedefs");
206 if (opts::pretty::Arrays
)
207 dumpSymbolCategory
<PDBSymbolTypeArray
>(Printer
, Exe
, *this, "Arrays");
209 if (opts::pretty::Pointers
)
210 dumpSymbolCategory
<PDBSymbolTypePointer
>(Printer
, Exe
, *this, "Pointers");
212 if (opts::pretty::VTShapes
)
213 dumpSymbolCategory
<PDBSymbolTypeVTableShape
>(Printer
, Exe
, *this,
216 if (opts::pretty::Classes
) {
217 if (auto Classes
= Exe
.findAllChildren
<PDBSymbolTypeUDT
>()) {
218 uint32_t All
= Classes
->getChildCount();
221 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << "Classes";
223 bool Precompute
= false;
225 (opts::pretty::ClassOrder
!= opts::pretty::ClassSortMode::None
);
227 // If we're using no sort mode, then we can start getting immediate output
228 // from the tool by just filtering as we go, rather than processing
229 // everything up front so that we can sort it. This makes the tool more
230 // responsive. So only precompute the filtered/sorted set of classes if
231 // necessary due to the specified options.
232 std::vector
<LayoutPtr
> Filtered
;
233 uint32_t Shown
= All
;
235 Filtered
= filterAndSortClassDefs(Printer
, *Classes
, All
);
237 Shown
= Filtered
.size();
240 Printer
<< ": (Showing " << Shown
<< " items";
242 Printer
<< ", " << (All
- Shown
) << " filtered";
246 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate
247 // the DIA enumerator and filter on the fly.
249 for (auto &Class
: Filtered
)
250 dumpClassLayout(*Class
);
252 while (auto Class
= Classes
->getNext()) {
253 if (Printer
.IsTypeExcluded(Class
->getName(), Class
->getLength()))
256 // No point duplicating a full class layout. Just print the modified
257 // declaration and continue.
258 if (Class
->getUnmodifiedTypeId() != 0) {
260 printClassDecl(Printer
, *Class
);
264 auto Layout
= std::make_unique
<ClassLayout
>(std::move(Class
));
265 if (Layout
->deepPaddingSize() < opts::pretty::PaddingThreshold
)
268 dumpClassLayout(*Layout
);
277 void TypeDumper::dump(const PDBSymbolTypeEnum
&Symbol
) {
278 assert(opts::pretty::Enums
);
280 EnumDumper
Dumper(Printer
);
281 Dumper
.start(Symbol
);
284 void TypeDumper::dump(const PDBSymbolTypeBuiltin
&Symbol
) {
285 BuiltinDumper
BD(Printer
);
289 void TypeDumper::dump(const PDBSymbolTypeUDT
&Symbol
) {
290 printClassDecl(Printer
, Symbol
);
293 void TypeDumper::dump(const PDBSymbolTypeTypedef
&Symbol
) {
294 assert(opts::pretty::Typedefs
);
296 TypedefDumper
Dumper(Printer
);
297 Dumper
.start(Symbol
);
300 void TypeDumper::dump(const PDBSymbolTypeArray
&Symbol
) {
301 auto ElementType
= Symbol
.getElementType();
303 ElementType
->dump(*this);
305 WithColor(Printer
, PDB_ColorItem::LiteralValue
).get() << Symbol
.getCount();
309 void TypeDumper::dump(const PDBSymbolTypeFunctionSig
&Symbol
) {
310 FunctionDumper
Dumper(Printer
);
311 Dumper
.start(Symbol
, nullptr, FunctionDumper::PointerType::None
);
314 void TypeDumper::dump(const PDBSymbolTypePointer
&Symbol
) {
315 std::unique_ptr
<PDBSymbol
> P
= Symbol
.getPointeeType();
317 if (auto *FS
= dyn_cast
<PDBSymbolTypeFunctionSig
>(P
.get())) {
318 FunctionDumper
Dumper(Printer
);
319 FunctionDumper::PointerType PT
=
320 Symbol
.isReference() ? FunctionDumper::PointerType::Reference
321 : FunctionDumper::PointerType::Pointer
;
322 Dumper
.start(*FS
, nullptr, PT
);
326 if (auto *UDT
= dyn_cast
<PDBSymbolTypeUDT
>(P
.get())) {
327 printClassDecl(Printer
, *UDT
);
332 if (auto Parent
= Symbol
.getClassParent()) {
333 auto UDT
= llvm::unique_dyn_cast
<PDBSymbolTypeUDT
>(std::move(Parent
));
335 Printer
<< " " << UDT
->getName() << "::";
338 if (Symbol
.isReference())
340 else if (Symbol
.isRValueReference())
346 void TypeDumper::dump(const PDBSymbolTypeVTableShape
&Symbol
) {
347 Printer
.format("<vtshape ({0} methods)>", Symbol
.getCount());
350 void TypeDumper::dumpClassLayout(const ClassLayout
&Class
) {
351 assert(opts::pretty::Classes
);
353 if (opts::pretty::ClassFormat
== opts::pretty::ClassDefinitionFormat::None
) {
354 WithColor(Printer
, PDB_ColorItem::Keyword
).get()
355 << Class
.getClass().getUdtKind() << " ";
356 WithColor(Printer
, PDB_ColorItem::Type
).get() << Class
.getName();
358 ClassDefinitionDumper
Dumper(Printer
);