1 //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PrettyClassLayoutGraphicalDumper.h"
10 
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"
18 
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"
26 
27 using namespace llvm;
28 using namespace llvm::pdb;
29 
30 PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
31     LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
32     : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
33       ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
34 
35 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
36 
37   if (RecursionLevel == 1 &&
38       opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
39     for (const auto &Other : Layout.other_items())
40       Other->dump(*this);
41     for (const auto &Func : Layout.funcs())
42       Func->dump(*this);
43   }
44 
45   const BitVector &UseMap = Layout.usedBytes();
46   int NextPaddingByte = UseMap.find_first_unset();
47 
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;
52 
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
59       // of padding begins.
60       if ((NextPaddingByte >= 0) &&
61           (RelativeOffset > uint32_t(NextPaddingByte))) {
62         printPaddingRow(RelativeOffset - NextPaddingByte);
63         NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
64       }
65     }
66 
67     CurrentItem = Item;
68     if (Item->isVBPtr()) {
69       VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
70 
71       VariableDumper VarDumper(Printer);
72       VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
73     } else {
74       if (auto Sym = Item->getSymbol())
75         Sym->dump(*this);
76     }
77 
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);
82     }
83   }
84 
85   auto TailPadding = Layout.tailPadding();
86   if (TailPadding > 0) {
87     if (TailPadding != 1 || Layout.getSize() != 1) {
88       Printer.NewLine();
89       WithColor(Printer, PDB_ColorItem::Padding).get()
90           << "<padding> (" << TailPadding << " bytes)";
91       DumpedAnything = true;
92     }
93   }
94 
95   return DumpedAnything;
96 }
97 
98 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
99   if (Amount == 0)
100     return;
101 
102   Printer.NewLine();
103   WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
104                                                    << " bytes)";
105   DumpedAnything = true;
106 }
107 
108 void PrettyClassLayoutGraphicalDumper::dump(
109     const PDBSymbolTypeBaseClass &Symbol) {
110   assert(CurrentItem != nullptr);
111 
112   Printer.NewLine();
113   BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
114 
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');
120   }
121   Printer << Label << " ";
122 
123   uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
124 
125   WithColor(Printer, PDB_ColorItem::Offset).get()
126       << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
127       << "] ";
128 
129   WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
130 
131   if (shouldRecurse()) {
132     Printer.Indent();
133     uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
134     PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
135                                                 ChildOffsetZero);
136     DumpedAnything |= BaseDumper.start(Layout);
137     Printer.Unindent();
138   }
139 
140   DumpedAnything = true;
141 }
142 
143 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
144   uint32_t Limit = opts::pretty::ClassRecursionDepth;
145   if (Limit == 0)
146     return true;
147   return RecursionLevel < Limit;
148 }
149 
150 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
151   VariableDumper VarDumper(Printer);
152   VarDumper.start(Symbol, ClassOffsetZero);
153 
154   if (CurrentItem != nullptr) {
155     DataMemberLayoutItem &Layout =
156         static_cast<DataMemberLayoutItem &>(*CurrentItem);
157 
158     if (Layout.hasUDTLayout() && shouldRecurse()) {
159       uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
160       Printer.Indent();
161       PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
162                                                   ChildOffsetZero);
163       TypeDumper.start(Layout.getUDTLayout());
164       Printer.Unindent();
165     }
166   }
167 
168   DumpedAnything = true;
169 }
170 
171 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
172   assert(CurrentItem != nullptr);
173 
174   VariableDumper VarDumper(Printer);
175   VarDumper.start(Symbol, ClassOffsetZero);
176 
177   DumpedAnything = true;
178 }
179 
180 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
181   DumpedAnything = true;
182   Printer.NewLine();
183   EnumDumper Dumper(Printer);
184   Dumper.start(Symbol);
185 }
186 
187 void PrettyClassLayoutGraphicalDumper::dump(
188     const PDBSymbolTypeTypedef &Symbol) {
189   DumpedAnything = true;
190   Printer.NewLine();
191   TypedefDumper Dumper(Printer);
192   Dumper.start(Symbol);
193 }
194 
195 void PrettyClassLayoutGraphicalDumper::dump(
196     const PDBSymbolTypeBuiltin &Symbol) {}
197 
198 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
199 
200 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
201   if (Printer.IsSymbolExcluded(Symbol.getName()))
202     return;
203   if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
204     return;
205   if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
206       !Symbol.isIntroVirtualFunction())
207     return;
208 
209   DumpedAnything = true;
210   Printer.NewLine();
211   FunctionDumper Dumper(Printer);
212   Dumper.start(Symbol, FunctionDumper::PointerType::None);
213 }
214