1 //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PrettyClassLayoutGraphicalDumper.h"
11 
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"
20 
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"
26 
27 using namespace llvm;
28 using namespace llvm::pdb;
29 
PrettyClassLayoutGraphicalDumper(LinePrinter & P,uint32_t RecurseLevel,uint32_t InitialOffset)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 
start(const UDTLayoutBase & Layout)35 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
36 
37   if (RecursionLevel == 1 &&
38       opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
39     for (auto &Other : Layout.other_items())
40       Other->dump(*this);
41     for (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 (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 
printPaddingRow(uint32_t Amount)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 
dump(const PDBSymbolTypeBaseClass & Symbol)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 
shouldRecurse() const143 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
144   uint32_t Limit = opts::pretty::ClassRecursionDepth;
145   if (Limit == 0)
146     return true;
147   return RecursionLevel < Limit;
148 }
149 
dump(const PDBSymbolData & Symbol)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 
dump(const PDBSymbolTypeVTable & Symbol)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 
dump(const PDBSymbolTypeEnum & Symbol)180 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
181   DumpedAnything = true;
182   Printer.NewLine();
183   EnumDumper Dumper(Printer);
184   Dumper.start(Symbol);
185 }
186 
dump(const PDBSymbolTypeTypedef & Symbol)187 void PrettyClassLayoutGraphicalDumper::dump(
188     const PDBSymbolTypeTypedef &Symbol) {
189   DumpedAnything = true;
190   Printer.NewLine();
191   TypedefDumper Dumper(Printer);
192   Dumper.start(Symbol);
193 }
194 
dump(const PDBSymbolTypeBuiltin & Symbol)195 void PrettyClassLayoutGraphicalDumper::dump(
196     const PDBSymbolTypeBuiltin &Symbol) {}
197 
dump(const PDBSymbolTypeUDT & Symbol)198 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
199 
dump(const PDBSymbolFunc & Symbol)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