1 //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PrettyClassLayoutGraphicalDumper.h"
12 #include "LinePrinter.h"
13 #include "PrettyClassDefinitionDumper.h"
14 #include "PrettyEnumDumper.h"
15 #include "PrettyFunctionDumper.h"
16 #include "PrettyTypedefDumper.h"
17 #include "PrettyVariableDumper.h"
18 #include "PrettyVariableDumper.h"
19 #include "llvm-pdbutil.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.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 (auto &Other : Layout.other_items())
41 for (auto &Func : Layout.funcs())
45 const BitVector &UseMap = Layout.usedBytes();
46 int NextPaddingByte = UseMap.find_first_unset();
48 for (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 // Since there is storage there, it should be set! However, this might
54 // be an empty base, in which case it could extend outside the bounds of
56 if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
57 assert(UseMap.test(RelativeOffset));
59 // If there is any remaining padding in this class, and the offset of the
60 // new item is after the padding, then we must have just jumped over some
61 // padding. Print a padding row and then look for where the next block
63 if ((NextPaddingByte >= 0) &&
64 (RelativeOffset > uint32_t(NextPaddingByte))) {
65 printPaddingRow(RelativeOffset - NextPaddingByte);
66 NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
71 if (Item->isVBPtr()) {
72 VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
74 VariableDumper VarDumper(Printer);
75 VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
77 if (auto Sym = Item->getSymbol())
81 if (Item->getLayoutSize() > 0) {
82 uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
83 if (Prev < UseMap.size())
84 NextPaddingByte = UseMap.find_next_unset(Prev);
88 auto TailPadding = Layout.tailPadding();
89 if (TailPadding > 0) {
90 if (TailPadding != 1 || Layout.getSize() != 1) {
92 WithColor(Printer, PDB_ColorItem::Padding).get()
93 << "<padding> (" << TailPadding << " bytes)";
94 DumpedAnything = true;
98 return DumpedAnything;
101 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
106 WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
108 DumpedAnything = true;
111 void PrettyClassLayoutGraphicalDumper::dump(
112 const PDBSymbolTypeBaseClass &Symbol) {
113 assert(CurrentItem != nullptr);
116 BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
118 std::string Label = "base";
119 if (Layout.isVirtualBase()) {
120 Label.insert(Label.begin(), 'v');
121 if (Layout.getBase().isIndirectVirtualBaseClass())
122 Label.insert(Label.begin(), 'i');
124 Printer << Label << " ";
126 uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
128 WithColor(Printer, PDB_ColorItem::Offset).get()
129 << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
132 WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
134 if (shouldRecurse()) {
136 uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
137 PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
139 DumpedAnything |= BaseDumper.start(Layout);
143 DumpedAnything = true;
146 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
147 uint32_t Limit = opts::pretty::ClassRecursionDepth;
150 return RecursionLevel < Limit;
153 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
154 VariableDumper VarDumper(Printer);
155 VarDumper.start(Symbol, ClassOffsetZero);
157 if (CurrentItem != nullptr) {
158 DataMemberLayoutItem &Layout =
159 static_cast<DataMemberLayoutItem &>(*CurrentItem);
161 if (Layout.hasUDTLayout() && shouldRecurse()) {
162 uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
164 PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
166 TypeDumper.start(Layout.getUDTLayout());
171 DumpedAnything = true;
174 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
175 assert(CurrentItem != nullptr);
177 VariableDumper VarDumper(Printer);
178 VarDumper.start(Symbol, ClassOffsetZero);
180 DumpedAnything = true;
183 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
184 DumpedAnything = true;
186 EnumDumper Dumper(Printer);
187 Dumper.start(Symbol);
190 void PrettyClassLayoutGraphicalDumper::dump(
191 const PDBSymbolTypeTypedef &Symbol) {
192 DumpedAnything = true;
194 TypedefDumper Dumper(Printer);
195 Dumper.start(Symbol);
198 void PrettyClassLayoutGraphicalDumper::dump(
199 const PDBSymbolTypeBuiltin &Symbol) {}
201 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
203 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
204 if (Printer.IsSymbolExcluded(Symbol.getName()))
206 if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
208 if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
209 !Symbol.isIntroVirtualFunction())
212 DumpedAnything = true;
214 FunctionDumper Dumper(Printer);
215 Dumper.start(Symbol, FunctionDumper::PointerType::None);