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