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 "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"
19 
20 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
25 #include "llvm/DebugInfo/PDB/UDTLayout.h"
26 #include "llvm/Support/Format.h"
27 
28 using namespace llvm;
29 using namespace llvm::pdb;
30 
31 PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
32     LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
33     : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
34       ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
35 
36 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
37 
38   if (RecursionLevel == 1 &&
39       opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
40     for (auto &Other : Layout.other_items())
41       Other->dump(*this);
42     for (auto &Func : Layout.funcs())
43       Func->dump(*this);
44   }
45 
46   const BitVector &UseMap = Layout.usedBytes();
47   int NextPaddingByte = UseMap.find_first_unset();
48 
49   for (auto &Item : Layout.layout_items()) {
50     // Calculate the absolute offset of the first byte of the next field.
51     uint32_t RelativeOffset = Item->getOffsetInParent();
52     CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
53 
54     // This might be an empty base, in which case it could extend outside the
55     // bounds of the parent class.
56     if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
57       // If there is any remaining padding in this class, and the offset of the
58       // new item is after the padding, then we must have just jumped over some
59       // padding.  Print a padding row and then look for where the next block
60       // of padding begins.
61       if ((NextPaddingByte >= 0) &&
62           (RelativeOffset > uint32_t(NextPaddingByte))) {
63         printPaddingRow(RelativeOffset - NextPaddingByte);
64         NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
65       }
66     }
67 
68     CurrentItem = Item;
69     if (Item->isVBPtr()) {
70       VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
71 
72       VariableDumper VarDumper(Printer);
73       VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
74     } else {
75       if (auto Sym = Item->getSymbol())
76         Sym->dump(*this);
77     }
78 
79     if (Item->getLayoutSize() > 0) {
80       uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
81       if (Prev < UseMap.size())
82         NextPaddingByte = UseMap.find_next_unset(Prev);
83     }
84   }
85 
86   auto TailPadding = Layout.tailPadding();
87   if (TailPadding > 0) {
88     if (TailPadding != 1 || Layout.getSize() != 1) {
89       Printer.NewLine();
90       WithColor(Printer, PDB_ColorItem::Padding).get()
91           << "<padding> (" << TailPadding << " bytes)";
92       DumpedAnything = true;
93     }
94   }
95 
96   return DumpedAnything;
97 }
98 
99 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
100   if (Amount == 0)
101     return;
102 
103   Printer.NewLine();
104   WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
105                                                    << " bytes)";
106   DumpedAnything = true;
107 }
108 
109 void PrettyClassLayoutGraphicalDumper::dump(
110     const PDBSymbolTypeBaseClass &Symbol) {
111   assert(CurrentItem != nullptr);
112 
113   Printer.NewLine();
114   BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
115 
116   std::string Label = "base";
117   if (Layout.isVirtualBase()) {
118     Label.insert(Label.begin(), 'v');
119     if (Layout.getBase().isIndirectVirtualBaseClass())
120       Label.insert(Label.begin(), 'i');
121   }
122   Printer << Label << " ";
123 
124   uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
125 
126   WithColor(Printer, PDB_ColorItem::Offset).get()
127       << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
128       << "] ";
129 
130   WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
131 
132   if (shouldRecurse()) {
133     Printer.Indent();
134     uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
135     PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
136                                                 ChildOffsetZero);
137     DumpedAnything |= BaseDumper.start(Layout);
138     Printer.Unindent();
139   }
140 
141   DumpedAnything = true;
142 }
143 
144 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
145   uint32_t Limit = opts::pretty::ClassRecursionDepth;
146   if (Limit == 0)
147     return true;
148   return RecursionLevel < Limit;
149 }
150 
151 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
152   VariableDumper VarDumper(Printer);
153   VarDumper.start(Symbol, ClassOffsetZero);
154 
155   if (CurrentItem != nullptr) {
156     DataMemberLayoutItem &Layout =
157         static_cast<DataMemberLayoutItem &>(*CurrentItem);
158 
159     if (Layout.hasUDTLayout() && shouldRecurse()) {
160       uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
161       Printer.Indent();
162       PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
163                                                   ChildOffsetZero);
164       TypeDumper.start(Layout.getUDTLayout());
165       Printer.Unindent();
166     }
167   }
168 
169   DumpedAnything = true;
170 }
171 
172 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
173   assert(CurrentItem != nullptr);
174 
175   VariableDumper VarDumper(Printer);
176   VarDumper.start(Symbol, ClassOffsetZero);
177 
178   DumpedAnything = true;
179 }
180 
181 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
182   DumpedAnything = true;
183   Printer.NewLine();
184   EnumDumper Dumper(Printer);
185   Dumper.start(Symbol);
186 }
187 
188 void PrettyClassLayoutGraphicalDumper::dump(
189     const PDBSymbolTypeTypedef &Symbol) {
190   DumpedAnything = true;
191   Printer.NewLine();
192   TypedefDumper Dumper(Printer);
193   Dumper.start(Symbol);
194 }
195 
196 void PrettyClassLayoutGraphicalDumper::dump(
197     const PDBSymbolTypeBuiltin &Symbol) {}
198 
199 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
200 
201 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
202   if (Printer.IsSymbolExcluded(Symbol.getName()))
203     return;
204   if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
205     return;
206   if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
207       !Symbol.isIntroVirtualFunction())
208     return;
209 
210   DumpedAnything = true;
211   Printer.NewLine();
212   FunctionDumper Dumper(Printer);
213   Dumper.start(Symbol, FunctionDumper::PointerType::None);
214 }
215