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