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 "PrettyClassDefinitionDumper.h"
12 #include "PrettyEnumDumper.h"
13 #include "PrettyFunctionDumper.h"
14 #include "PrettyTypedefDumper.h"
15 #include "PrettyVariableDumper.h"
16 #include "PrettyVariableDumper.h"
17 #include "llvm-pdbutil.h"
19 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
24 #include "llvm/DebugInfo/PDB/UDTLayout.h"
25 #include "llvm/Support/Format.h"
28 using namespace llvm::pdb
;
30 PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
31 LinePrinter
&P
, uint32_t RecurseLevel
, uint32_t InitialOffset
)
32 : PDBSymDumper(true), Printer(P
), RecursionLevel(RecurseLevel
),
33 ClassOffsetZero(InitialOffset
), CurrentAbsoluteOffset(InitialOffset
) {}
35 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase
&Layout
) {
37 if (RecursionLevel
== 1 &&
38 opts::pretty::ClassFormat
== opts::pretty::ClassDefinitionFormat::All
) {
39 for (const auto &Other
: Layout
.other_items())
41 for (const auto &Func
: Layout
.funcs())
45 const BitVector
&UseMap
= Layout
.usedBytes();
46 int NextPaddingByte
= UseMap
.find_first_unset();
48 for (const auto &Item
: Layout
.layout_items()) {
49 // Calculate the absolute offset of the first byte of the next field.
50 uint32_t RelativeOffset
= Item
->getOffsetInParent();
51 CurrentAbsoluteOffset
= ClassOffsetZero
+ RelativeOffset
;
53 // This might be an empty base, in which case it could extend outside the
54 // bounds of the parent class.
55 if (RelativeOffset
< UseMap
.size() && (Item
->getSize() > 0)) {
56 // If there is any remaining padding in this class, and the offset of the
57 // new item is after the padding, then we must have just jumped over some
58 // padding. Print a padding row and then look for where the next block
60 if ((NextPaddingByte
>= 0) &&
61 (RelativeOffset
> uint32_t(NextPaddingByte
))) {
62 printPaddingRow(RelativeOffset
- NextPaddingByte
);
63 NextPaddingByte
= UseMap
.find_next_unset(RelativeOffset
);
68 if (Item
->isVBPtr()) {
69 VTableLayoutItem
&Layout
= static_cast<VTableLayoutItem
&>(*CurrentItem
);
71 VariableDumper
VarDumper(Printer
);
72 VarDumper
.startVbptr(CurrentAbsoluteOffset
, Layout
.getSize());
74 if (auto Sym
= Item
->getSymbol())
78 if (Item
->getLayoutSize() > 0) {
79 uint32_t Prev
= RelativeOffset
+ Item
->getLayoutSize() - 1;
80 if (Prev
< UseMap
.size())
81 NextPaddingByte
= UseMap
.find_next_unset(Prev
);
85 auto TailPadding
= Layout
.tailPadding();
86 if (TailPadding
> 0) {
87 if (TailPadding
!= 1 || Layout
.getSize() != 1) {
89 WithColor(Printer
, PDB_ColorItem::Padding
).get()
90 << "<padding> (" << TailPadding
<< " bytes)";
91 DumpedAnything
= true;
95 return DumpedAnything
;
98 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount
) {
103 WithColor(Printer
, PDB_ColorItem::Padding
).get() << "<padding> (" << Amount
105 DumpedAnything
= true;
108 void PrettyClassLayoutGraphicalDumper::dump(
109 const PDBSymbolTypeBaseClass
&Symbol
) {
110 assert(CurrentItem
!= nullptr);
113 BaseClassLayout
&Layout
= static_cast<BaseClassLayout
&>(*CurrentItem
);
115 std::string Label
= "base";
116 if (Layout
.isVirtualBase()) {
117 Label
.insert(Label
.begin(), 'v');
118 if (Layout
.getBase().isIndirectVirtualBaseClass())
119 Label
.insert(Label
.begin(), 'i');
121 Printer
<< Label
<< " ";
123 uint32_t Size
= Layout
.isEmptyBase() ? 1 : Layout
.getLayoutSize();
125 WithColor(Printer
, PDB_ColorItem::Offset
).get()
126 << "+" << format_hex(CurrentAbsoluteOffset
, 4) << " [sizeof=" << Size
129 WithColor(Printer
, PDB_ColorItem::Identifier
).get() << Layout
.getName();
131 if (shouldRecurse()) {
133 uint32_t ChildOffsetZero
= ClassOffsetZero
+ Layout
.getOffsetInParent();
134 PrettyClassLayoutGraphicalDumper
BaseDumper(Printer
, RecursionLevel
+ 1,
136 DumpedAnything
|= BaseDumper
.start(Layout
);
140 DumpedAnything
= true;
143 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
144 uint32_t Limit
= opts::pretty::ClassRecursionDepth
;
147 return RecursionLevel
< Limit
;
150 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData
&Symbol
) {
151 VariableDumper
VarDumper(Printer
);
152 VarDumper
.start(Symbol
, ClassOffsetZero
);
154 if (CurrentItem
!= nullptr) {
155 DataMemberLayoutItem
&Layout
=
156 static_cast<DataMemberLayoutItem
&>(*CurrentItem
);
158 if (Layout
.hasUDTLayout() && shouldRecurse()) {
159 uint32_t ChildOffsetZero
= ClassOffsetZero
+ Layout
.getOffsetInParent();
161 PrettyClassLayoutGraphicalDumper
TypeDumper(Printer
, RecursionLevel
+ 1,
163 TypeDumper
.start(Layout
.getUDTLayout());
168 DumpedAnything
= true;
171 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable
&Symbol
) {
172 assert(CurrentItem
!= nullptr);
174 VariableDumper
VarDumper(Printer
);
175 VarDumper
.start(Symbol
, ClassOffsetZero
);
177 DumpedAnything
= true;
180 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum
&Symbol
) {
181 DumpedAnything
= true;
183 EnumDumper
Dumper(Printer
);
184 Dumper
.start(Symbol
);
187 void PrettyClassLayoutGraphicalDumper::dump(
188 const PDBSymbolTypeTypedef
&Symbol
) {
189 DumpedAnything
= true;
191 TypedefDumper
Dumper(Printer
);
192 Dumper
.start(Symbol
);
195 void PrettyClassLayoutGraphicalDumper::dump(
196 const PDBSymbolTypeBuiltin
&Symbol
) {}
198 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT
&Symbol
) {}
200 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc
&Symbol
) {
201 if (Printer
.IsSymbolExcluded(Symbol
.getName()))
203 if (Symbol
.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated
)
205 if (Symbol
.getLength() == 0 && !Symbol
.isPureVirtual() &&
206 !Symbol
.isIntroVirtualFunction())
209 DumpedAnything
= true;
211 FunctionDumper
Dumper(Printer
);
212 Dumper
.start(Symbol
, FunctionDumper::PointerType::None
);