1 //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- 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 "PrettyClassLayoutGraphicalDumper.h"
11 #include "LinePrinter.h"
12 #include "PrettyClassDefinitionDumper.h"
13 #include "PrettyEnumDumper.h"
14 #include "PrettyFunctionDumper.h"
15 #include "PrettyTypedefDumper.h"
16 #include "PrettyVariableDumper.h"
17 #include "PrettyVariableDumper.h"
18 #include "llvm-pdbutil.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
23 #include "llvm/DebugInfo/PDB/UDTLayout.h"
24 #include "llvm/Support/Format.h"
27 using namespace llvm::pdb
;
29 PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
30 LinePrinter
&P
, uint32_t RecurseLevel
, uint32_t InitialOffset
)
31 : PDBSymDumper(true), Printer(P
), RecursionLevel(RecurseLevel
),
32 ClassOffsetZero(InitialOffset
), CurrentAbsoluteOffset(InitialOffset
) {}
34 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase
&Layout
) {
36 if (RecursionLevel
== 1 &&
37 opts::pretty::ClassFormat
== opts::pretty::ClassDefinitionFormat::All
) {
38 for (auto &Other
: Layout
.other_items())
40 for (auto &Func
: Layout
.funcs())
44 const BitVector
&UseMap
= Layout
.usedBytes();
45 int NextPaddingByte
= UseMap
.find_first_unset();
47 for (auto &Item
: Layout
.layout_items()) {
48 // Calculate the absolute offset of the first byte of the next field.
49 uint32_t RelativeOffset
= Item
->getOffsetInParent();
50 CurrentAbsoluteOffset
= ClassOffsetZero
+ RelativeOffset
;
52 // This might be an empty base, in which case it could extend outside the
53 // bounds of the parent class.
54 if (RelativeOffset
< UseMap
.size() && (Item
->getSize() > 0)) {
55 // If there is any remaining padding in this class, and the offset of the
56 // new item is after the padding, then we must have just jumped over some
57 // padding. Print a padding row and then look for where the next block
59 if ((NextPaddingByte
>= 0) &&
60 (RelativeOffset
> uint32_t(NextPaddingByte
))) {
61 printPaddingRow(RelativeOffset
- NextPaddingByte
);
62 NextPaddingByte
= UseMap
.find_next_unset(RelativeOffset
);
67 if (Item
->isVBPtr()) {
68 VTableLayoutItem
&Layout
= static_cast<VTableLayoutItem
&>(*CurrentItem
);
70 VariableDumper
VarDumper(Printer
);
71 VarDumper
.startVbptr(CurrentAbsoluteOffset
, Layout
.getSize());
73 if (auto Sym
= Item
->getSymbol())
77 if (Item
->getLayoutSize() > 0) {
78 uint32_t Prev
= RelativeOffset
+ Item
->getLayoutSize() - 1;
79 if (Prev
< UseMap
.size())
80 NextPaddingByte
= UseMap
.find_next_unset(Prev
);
84 auto TailPadding
= Layout
.tailPadding();
85 if (TailPadding
> 0) {
86 if (TailPadding
!= 1 || Layout
.getSize() != 1) {
88 WithColor(Printer
, PDB_ColorItem::Padding
).get()
89 << "<padding> (" << TailPadding
<< " bytes)";
90 DumpedAnything
= true;
94 return DumpedAnything
;
97 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount
) {
102 WithColor(Printer
, PDB_ColorItem::Padding
).get() << "<padding> (" << Amount
104 DumpedAnything
= true;
107 void PrettyClassLayoutGraphicalDumper::dump(
108 const PDBSymbolTypeBaseClass
&Symbol
) {
109 assert(CurrentItem
!= nullptr);
112 BaseClassLayout
&Layout
= static_cast<BaseClassLayout
&>(*CurrentItem
);
114 std::string Label
= "base";
115 if (Layout
.isVirtualBase()) {
116 Label
.insert(Label
.begin(), 'v');
117 if (Layout
.getBase().isIndirectVirtualBaseClass())
118 Label
.insert(Label
.begin(), 'i');
120 Printer
<< Label
<< " ";
122 uint32_t Size
= Layout
.isEmptyBase() ? 1 : Layout
.getLayoutSize();
124 WithColor(Printer
, PDB_ColorItem::Offset
).get()
125 << "+" << format_hex(CurrentAbsoluteOffset
, 4) << " [sizeof=" << Size
128 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Layout
.getName();
130 if (shouldRecurse()) {
132 uint32_t ChildOffsetZero
= ClassOffsetZero
+ Layout
.getOffsetInParent();
133 PrettyClassLayoutGraphicalDumper
BaseDumper(Printer
, RecursionLevel
+ 1,
135 DumpedAnything
|= BaseDumper
.start(Layout
);
139 DumpedAnything
= true;
142 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
143 uint32_t Limit
= opts::pretty::ClassRecursionDepth
;
146 return RecursionLevel
< Limit
;
149 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData
&Symbol
) {
150 VariableDumper
VarDumper(Printer
);
151 VarDumper
.start(Symbol
, ClassOffsetZero
);
153 if (CurrentItem
!= nullptr) {
154 DataMemberLayoutItem
&Layout
=
155 static_cast<DataMemberLayoutItem
&>(*CurrentItem
);
157 if (Layout
.hasUDTLayout() && shouldRecurse()) {
158 uint32_t ChildOffsetZero
= ClassOffsetZero
+ Layout
.getOffsetInParent();
160 PrettyClassLayoutGraphicalDumper
TypeDumper(Printer
, RecursionLevel
+ 1,
162 TypeDumper
.start(Layout
.getUDTLayout());
167 DumpedAnything
= true;
170 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable
&Symbol
) {
171 assert(CurrentItem
!= nullptr);
173 VariableDumper
VarDumper(Printer
);
174 VarDumper
.start(Symbol
, ClassOffsetZero
);
176 DumpedAnything
= true;
179 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum
&Symbol
) {
180 DumpedAnything
= true;
182 EnumDumper
Dumper(Printer
);
183 Dumper
.start(Symbol
);
186 void PrettyClassLayoutGraphicalDumper::dump(
187 const PDBSymbolTypeTypedef
&Symbol
) {
188 DumpedAnything
= true;
190 TypedefDumper
Dumper(Printer
);
191 Dumper
.start(Symbol
);
194 void PrettyClassLayoutGraphicalDumper::dump(
195 const PDBSymbolTypeBuiltin
&Symbol
) {}
197 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT
&Symbol
) {}
199 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc
&Symbol
) {
200 if (Printer
.IsSymbolExcluded(Symbol
.getName()))
202 if (Symbol
.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated
)
204 if (Symbol
.getLength() == 0 && !Symbol
.isPureVirtual() &&
205 !Symbol
.isIntroVirtualFunction())
208 DumpedAnything
= true;
210 FunctionDumper
Dumper(Printer
);
211 Dumper
.start(Symbol
, FunctionDumper::PointerType::None
);