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
26using namespace llvm;
27using namespace llvm::pdb;
28
29PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
30    LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
31    : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
32      ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
33
34bool 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
97void 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
107void 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
142bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
143  uint32_t Limit = opts::pretty::ClassRecursionDepth;
144  if (Limit == 0)
145    return true;
146  return RecursionLevel < Limit;
147}
148
149void 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
170void 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
179void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
180  DumpedAnything = true;
181  Printer.NewLine();
182  EnumDumper Dumper(Printer);
183  Dumper.start(Symbol);
184}
185
186void PrettyClassLayoutGraphicalDumper::dump(
187    const PDBSymbolTypeTypedef &Symbol) {
188  DumpedAnything = true;
189  Printer.NewLine();
190  TypedefDumper Dumper(Printer);
191  Dumper.start(Symbol);
192}
193
194void PrettyClassLayoutGraphicalDumper::dump(
195    const PDBSymbolTypeBuiltin &Symbol) {}
196
197void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
198
199void 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