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