1319780Sdim//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
2319780Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6319780Sdim//
7319780Sdim//===----------------------------------------------------------------------===//
8319780Sdim
9319780Sdim#include "PrettyClassLayoutGraphicalDumper.h"
10319780Sdim
11319780Sdim#include "LinePrinter.h"
12319780Sdim#include "PrettyClassDefinitionDumper.h"
13319780Sdim#include "PrettyEnumDumper.h"
14319780Sdim#include "PrettyFunctionDumper.h"
15319780Sdim#include "PrettyTypedefDumper.h"
16319780Sdim#include "PrettyVariableDumper.h"
17319780Sdim#include "PrettyVariableDumper.h"
18319780Sdim#include "llvm-pdbutil.h"
19319780Sdim
20319780Sdim#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
21319780Sdim#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
22319780Sdim#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
23319780Sdim#include "llvm/DebugInfo/PDB/UDTLayout.h"
24319780Sdim#include "llvm/Support/Format.h"
25319780Sdim
26319780Sdimusing namespace llvm;
27319780Sdimusing namespace llvm::pdb;
28319780Sdim
29319780SdimPrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
30319780Sdim    LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
31319780Sdim    : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
32319780Sdim      ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
33319780Sdim
34319780Sdimbool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
35319780Sdim
36319780Sdim  if (RecursionLevel == 1 &&
37319780Sdim      opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
38319780Sdim    for (auto &Other : Layout.other_items())
39319780Sdim      Other->dump(*this);
40319780Sdim    for (auto &Func : Layout.funcs())
41319780Sdim      Func->dump(*this);
42319780Sdim  }
43319780Sdim
44319780Sdim  const BitVector &UseMap = Layout.usedBytes();
45319780Sdim  int NextPaddingByte = UseMap.find_first_unset();
46319780Sdim
47319780Sdim  for (auto &Item : Layout.layout_items()) {
48319780Sdim    // Calculate the absolute offset of the first byte of the next field.
49319780Sdim    uint32_t RelativeOffset = Item->getOffsetInParent();
50319780Sdim    CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
51319780Sdim
52341825Sdim    // This might be an empty base, in which case it could extend outside the
53341825Sdim    // bounds of the parent class.
54319780Sdim    if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
55319780Sdim      // If there is any remaining padding in this class, and the offset of the
56319780Sdim      // new item is after the padding, then we must have just jumped over some
57319780Sdim      // padding.  Print a padding row and then look for where the next block
58319780Sdim      // of padding begins.
59319780Sdim      if ((NextPaddingByte >= 0) &&
60319780Sdim          (RelativeOffset > uint32_t(NextPaddingByte))) {
61319780Sdim        printPaddingRow(RelativeOffset - NextPaddingByte);
62319780Sdim        NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
63319780Sdim      }
64319780Sdim    }
65319780Sdim
66319780Sdim    CurrentItem = Item;
67319780Sdim    if (Item->isVBPtr()) {
68319780Sdim      VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
69319780Sdim
70319780Sdim      VariableDumper VarDumper(Printer);
71319780Sdim      VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
72319780Sdim    } else {
73319780Sdim      if (auto Sym = Item->getSymbol())
74319780Sdim        Sym->dump(*this);
75319780Sdim    }
76319780Sdim
77319780Sdim    if (Item->getLayoutSize() > 0) {
78319780Sdim      uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
79319780Sdim      if (Prev < UseMap.size())
80319780Sdim        NextPaddingByte = UseMap.find_next_unset(Prev);
81319780Sdim    }
82319780Sdim  }
83319780Sdim
84319780Sdim  auto TailPadding = Layout.tailPadding();
85319780Sdim  if (TailPadding > 0) {
86319780Sdim    if (TailPadding != 1 || Layout.getSize() != 1) {
87319780Sdim      Printer.NewLine();
88319780Sdim      WithColor(Printer, PDB_ColorItem::Padding).get()
89319780Sdim          << "<padding> (" << TailPadding << " bytes)";
90319780Sdim      DumpedAnything = true;
91319780Sdim    }
92319780Sdim  }
93319780Sdim
94319780Sdim  return DumpedAnything;
95319780Sdim}
96319780Sdim
97319780Sdimvoid PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
98319780Sdim  if (Amount == 0)
99319780Sdim    return;
100319780Sdim
101319780Sdim  Printer.NewLine();
102319780Sdim  WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
103319780Sdim                                                   << " bytes)";
104319780Sdim  DumpedAnything = true;
105319780Sdim}
106319780Sdim
107319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(
108319780Sdim    const PDBSymbolTypeBaseClass &Symbol) {
109319780Sdim  assert(CurrentItem != nullptr);
110319780Sdim
111319780Sdim  Printer.NewLine();
112319780Sdim  BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
113319780Sdim
114319780Sdim  std::string Label = "base";
115319780Sdim  if (Layout.isVirtualBase()) {
116319780Sdim    Label.insert(Label.begin(), 'v');
117319780Sdim    if (Layout.getBase().isIndirectVirtualBaseClass())
118319780Sdim      Label.insert(Label.begin(), 'i');
119319780Sdim  }
120319780Sdim  Printer << Label << " ";
121319780Sdim
122319780Sdim  uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
123319780Sdim
124319780Sdim  WithColor(Printer, PDB_ColorItem::Offset).get()
125319780Sdim      << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
126319780Sdim      << "] ";
127319780Sdim
128319780Sdim  WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
129319780Sdim
130319780Sdim  if (shouldRecurse()) {
131319780Sdim    Printer.Indent();
132319780Sdim    uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
133319780Sdim    PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
134319780Sdim                                                ChildOffsetZero);
135319780Sdim    DumpedAnything |= BaseDumper.start(Layout);
136319780Sdim    Printer.Unindent();
137319780Sdim  }
138319780Sdim
139319780Sdim  DumpedAnything = true;
140319780Sdim}
141319780Sdim
142319780Sdimbool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
143319780Sdim  uint32_t Limit = opts::pretty::ClassRecursionDepth;
144319780Sdim  if (Limit == 0)
145319780Sdim    return true;
146319780Sdim  return RecursionLevel < Limit;
147319780Sdim}
148319780Sdim
149319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
150319780Sdim  VariableDumper VarDumper(Printer);
151319780Sdim  VarDumper.start(Symbol, ClassOffsetZero);
152319780Sdim
153320041Sdim  if (CurrentItem != nullptr) {
154320041Sdim    DataMemberLayoutItem &Layout =
155320041Sdim        static_cast<DataMemberLayoutItem &>(*CurrentItem);
156320041Sdim
157320041Sdim    if (Layout.hasUDTLayout() && shouldRecurse()) {
158320041Sdim      uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
159320041Sdim      Printer.Indent();
160320041Sdim      PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
161320041Sdim                                                  ChildOffsetZero);
162320041Sdim      TypeDumper.start(Layout.getUDTLayout());
163320041Sdim      Printer.Unindent();
164320041Sdim    }
165319780Sdim  }
166319780Sdim
167319780Sdim  DumpedAnything = true;
168319780Sdim}
169319780Sdim
170319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
171319780Sdim  assert(CurrentItem != nullptr);
172319780Sdim
173319780Sdim  VariableDumper VarDumper(Printer);
174319780Sdim  VarDumper.start(Symbol, ClassOffsetZero);
175319780Sdim
176319780Sdim  DumpedAnything = true;
177319780Sdim}
178319780Sdim
179319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
180319780Sdim  DumpedAnything = true;
181319780Sdim  Printer.NewLine();
182319780Sdim  EnumDumper Dumper(Printer);
183319780Sdim  Dumper.start(Symbol);
184319780Sdim}
185319780Sdim
186319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(
187319780Sdim    const PDBSymbolTypeTypedef &Symbol) {
188319780Sdim  DumpedAnything = true;
189319780Sdim  Printer.NewLine();
190319780Sdim  TypedefDumper Dumper(Printer);
191319780Sdim  Dumper.start(Symbol);
192319780Sdim}
193319780Sdim
194319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(
195319780Sdim    const PDBSymbolTypeBuiltin &Symbol) {}
196319780Sdim
197319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
198319780Sdim
199319780Sdimvoid PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
200319780Sdim  if (Printer.IsSymbolExcluded(Symbol.getName()))
201319780Sdim    return;
202319780Sdim  if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
203319780Sdim    return;
204319780Sdim  if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
205319780Sdim      !Symbol.isIntroVirtualFunction())
206319780Sdim    return;
207319780Sdim
208319780Sdim  DumpedAnything = true;
209319780Sdim  Printer.NewLine();
210319780Sdim  FunctionDumper Dumper(Printer);
211319780Sdim  Dumper.start(Symbol, FunctionDumper::PointerType::None);
212319780Sdim}
213