10b57cec5SDimitry Andric //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "PrettyClassLayoutGraphicalDumper.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "PrettyClassDefinitionDumper.h"
120b57cec5SDimitry Andric #include "PrettyEnumDumper.h"
130b57cec5SDimitry Andric #include "PrettyFunctionDumper.h"
140b57cec5SDimitry Andric #include "PrettyTypedefDumper.h"
150b57cec5SDimitry Andric #include "PrettyVariableDumper.h"
160b57cec5SDimitry Andric #include "PrettyVariableDumper.h"
170b57cec5SDimitry Andric #include "llvm-pdbutil.h"
180b57cec5SDimitry Andric 
1981ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
2281ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
230b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
240b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/UDTLayout.h"
250b57cec5SDimitry Andric #include "llvm/Support/Format.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric using namespace llvm::pdb;
290b57cec5SDimitry Andric 
PrettyClassLayoutGraphicalDumper(LinePrinter & P,uint32_t RecurseLevel,uint32_t InitialOffset)300b57cec5SDimitry Andric PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
310b57cec5SDimitry Andric     LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset)
320b57cec5SDimitry Andric     : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel),
330b57cec5SDimitry Andric       ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {}
340b57cec5SDimitry Andric 
start(const UDTLayoutBase & Layout)350b57cec5SDimitry Andric bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric   if (RecursionLevel == 1 &&
380b57cec5SDimitry Andric       opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) {
39bdd1243dSDimitry Andric     for (const auto &Other : Layout.other_items())
400b57cec5SDimitry Andric       Other->dump(*this);
41bdd1243dSDimitry Andric     for (const auto &Func : Layout.funcs())
420b57cec5SDimitry Andric       Func->dump(*this);
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   const BitVector &UseMap = Layout.usedBytes();
460b57cec5SDimitry Andric   int NextPaddingByte = UseMap.find_first_unset();
470b57cec5SDimitry Andric 
48bdd1243dSDimitry Andric   for (const auto &Item : Layout.layout_items()) {
490b57cec5SDimitry Andric     // Calculate the absolute offset of the first byte of the next field.
500b57cec5SDimitry Andric     uint32_t RelativeOffset = Item->getOffsetInParent();
510b57cec5SDimitry Andric     CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric     // This might be an empty base, in which case it could extend outside the
540b57cec5SDimitry Andric     // bounds of the parent class.
550b57cec5SDimitry Andric     if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) {
560b57cec5SDimitry Andric       // If there is any remaining padding in this class, and the offset of the
570b57cec5SDimitry Andric       // new item is after the padding, then we must have just jumped over some
580b57cec5SDimitry Andric       // padding.  Print a padding row and then look for where the next block
590b57cec5SDimitry Andric       // of padding begins.
600b57cec5SDimitry Andric       if ((NextPaddingByte >= 0) &&
610b57cec5SDimitry Andric           (RelativeOffset > uint32_t(NextPaddingByte))) {
620b57cec5SDimitry Andric         printPaddingRow(RelativeOffset - NextPaddingByte);
630b57cec5SDimitry Andric         NextPaddingByte = UseMap.find_next_unset(RelativeOffset);
640b57cec5SDimitry Andric       }
650b57cec5SDimitry Andric     }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric     CurrentItem = Item;
680b57cec5SDimitry Andric     if (Item->isVBPtr()) {
690b57cec5SDimitry Andric       VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric       VariableDumper VarDumper(Printer);
720b57cec5SDimitry Andric       VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize());
730b57cec5SDimitry Andric     } else {
740b57cec5SDimitry Andric       if (auto Sym = Item->getSymbol())
750b57cec5SDimitry Andric         Sym->dump(*this);
760b57cec5SDimitry Andric     }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     if (Item->getLayoutSize() > 0) {
790b57cec5SDimitry Andric       uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1;
800b57cec5SDimitry Andric       if (Prev < UseMap.size())
810b57cec5SDimitry Andric         NextPaddingByte = UseMap.find_next_unset(Prev);
820b57cec5SDimitry Andric     }
830b57cec5SDimitry Andric   }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   auto TailPadding = Layout.tailPadding();
860b57cec5SDimitry Andric   if (TailPadding > 0) {
870b57cec5SDimitry Andric     if (TailPadding != 1 || Layout.getSize() != 1) {
880b57cec5SDimitry Andric       Printer.NewLine();
890b57cec5SDimitry Andric       WithColor(Printer, PDB_ColorItem::Padding).get()
900b57cec5SDimitry Andric           << "<padding> (" << TailPadding << " bytes)";
910b57cec5SDimitry Andric       DumpedAnything = true;
920b57cec5SDimitry Andric     }
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   return DumpedAnything;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
printPaddingRow(uint32_t Amount)980b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
990b57cec5SDimitry Andric   if (Amount == 0)
1000b57cec5SDimitry Andric     return;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   Printer.NewLine();
1030b57cec5SDimitry Andric   WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
1040b57cec5SDimitry Andric                                                    << " bytes)";
1050b57cec5SDimitry Andric   DumpedAnything = true;
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
dump(const PDBSymbolTypeBaseClass & Symbol)1080b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(
1090b57cec5SDimitry Andric     const PDBSymbolTypeBaseClass &Symbol) {
1100b57cec5SDimitry Andric   assert(CurrentItem != nullptr);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   Printer.NewLine();
1130b57cec5SDimitry Andric   BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem);
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   std::string Label = "base";
1160b57cec5SDimitry Andric   if (Layout.isVirtualBase()) {
1170b57cec5SDimitry Andric     Label.insert(Label.begin(), 'v');
1180b57cec5SDimitry Andric     if (Layout.getBase().isIndirectVirtualBaseClass())
1190b57cec5SDimitry Andric       Label.insert(Label.begin(), 'i');
1200b57cec5SDimitry Andric   }
1210b57cec5SDimitry Andric   Printer << Label << " ";
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize();
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   WithColor(Printer, PDB_ColorItem::Offset).get()
1260b57cec5SDimitry Andric       << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size
1270b57cec5SDimitry Andric       << "] ";
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName();
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   if (shouldRecurse()) {
1320b57cec5SDimitry Andric     Printer.Indent();
1330b57cec5SDimitry Andric     uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
1340b57cec5SDimitry Andric     PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1,
1350b57cec5SDimitry Andric                                                 ChildOffsetZero);
1360b57cec5SDimitry Andric     DumpedAnything |= BaseDumper.start(Layout);
1370b57cec5SDimitry Andric     Printer.Unindent();
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   DumpedAnything = true;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
shouldRecurse() const1430b57cec5SDimitry Andric bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const {
1440b57cec5SDimitry Andric   uint32_t Limit = opts::pretty::ClassRecursionDepth;
1450b57cec5SDimitry Andric   if (Limit == 0)
1460b57cec5SDimitry Andric     return true;
1470b57cec5SDimitry Andric   return RecursionLevel < Limit;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
dump(const PDBSymbolData & Symbol)1500b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {
1510b57cec5SDimitry Andric   VariableDumper VarDumper(Printer);
1520b57cec5SDimitry Andric   VarDumper.start(Symbol, ClassOffsetZero);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   if (CurrentItem != nullptr) {
1550b57cec5SDimitry Andric     DataMemberLayoutItem &Layout =
1560b57cec5SDimitry Andric         static_cast<DataMemberLayoutItem &>(*CurrentItem);
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric     if (Layout.hasUDTLayout() && shouldRecurse()) {
1590b57cec5SDimitry Andric       uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent();
1600b57cec5SDimitry Andric       Printer.Indent();
1610b57cec5SDimitry Andric       PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1,
1620b57cec5SDimitry Andric                                                   ChildOffsetZero);
1630b57cec5SDimitry Andric       TypeDumper.start(Layout.getUDTLayout());
1640b57cec5SDimitry Andric       Printer.Unindent();
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   DumpedAnything = true;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
dump(const PDBSymbolTypeVTable & Symbol)1710b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
1720b57cec5SDimitry Andric   assert(CurrentItem != nullptr);
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   VariableDumper VarDumper(Printer);
1750b57cec5SDimitry Andric   VarDumper.start(Symbol, ClassOffsetZero);
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   DumpedAnything = true;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
dump(const PDBSymbolTypeEnum & Symbol)1800b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {
1810b57cec5SDimitry Andric   DumpedAnything = true;
1820b57cec5SDimitry Andric   Printer.NewLine();
1830b57cec5SDimitry Andric   EnumDumper Dumper(Printer);
1840b57cec5SDimitry Andric   Dumper.start(Symbol);
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
dump(const PDBSymbolTypeTypedef & Symbol)1870b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(
1880b57cec5SDimitry Andric     const PDBSymbolTypeTypedef &Symbol) {
1890b57cec5SDimitry Andric   DumpedAnything = true;
1900b57cec5SDimitry Andric   Printer.NewLine();
1910b57cec5SDimitry Andric   TypedefDumper Dumper(Printer);
1920b57cec5SDimitry Andric   Dumper.start(Symbol);
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
dump(const PDBSymbolTypeBuiltin & Symbol)1950b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(
1960b57cec5SDimitry Andric     const PDBSymbolTypeBuiltin &Symbol) {}
1970b57cec5SDimitry Andric 
dump(const PDBSymbolTypeUDT & Symbol)1980b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
1990b57cec5SDimitry Andric 
dump(const PDBSymbolFunc & Symbol)2000b57cec5SDimitry Andric void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {
2010b57cec5SDimitry Andric   if (Printer.IsSymbolExcluded(Symbol.getName()))
2020b57cec5SDimitry Andric     return;
2030b57cec5SDimitry Andric   if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
2040b57cec5SDimitry Andric     return;
2050b57cec5SDimitry Andric   if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
2060b57cec5SDimitry Andric       !Symbol.isIntroVirtualFunction())
2070b57cec5SDimitry Andric     return;
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   DumpedAnything = true;
2100b57cec5SDimitry Andric   Printer.NewLine();
2110b57cec5SDimitry Andric   FunctionDumper Dumper(Printer);
2120b57cec5SDimitry Andric   Dumper.start(Symbol, FunctionDumper::PointerType::None);
2130b57cec5SDimitry Andric }
214