//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "PrettyClassLayoutGraphicalDumper.h" #include "PrettyClassDefinitionDumper.h" #include "PrettyEnumDumper.h" #include "PrettyFunctionDumper.h" #include "PrettyTypedefDumper.h" #include "PrettyVariableDumper.h" #include "PrettyVariableDumper.h" #include "llvm-pdbutil.h" #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" #include "llvm/DebugInfo/PDB/UDTLayout.h" #include "llvm/Support/Format.h" using namespace llvm; using namespace llvm::pdb; PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset) : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel), ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {} bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { if (RecursionLevel == 1 && opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) { for (const auto &Other : Layout.other_items()) Other->dump(*this); for (const auto &Func : Layout.funcs()) Func->dump(*this); } const BitVector &UseMap = Layout.usedBytes(); int NextPaddingByte = UseMap.find_first_unset(); for (const auto &Item : Layout.layout_items()) { // Calculate the absolute offset of the first byte of the next field. uint32_t RelativeOffset = Item->getOffsetInParent(); CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; // This might be an empty base, in which case it could extend outside the // bounds of the parent class. if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { // If there is any remaining padding in this class, and the offset of the // new item is after the padding, then we must have just jumped over some // padding. Print a padding row and then look for where the next block // of padding begins. if ((NextPaddingByte >= 0) && (RelativeOffset > uint32_t(NextPaddingByte))) { printPaddingRow(RelativeOffset - NextPaddingByte); NextPaddingByte = UseMap.find_next_unset(RelativeOffset); } } CurrentItem = Item; if (Item->isVBPtr()) { VTableLayoutItem &Layout = static_cast(*CurrentItem); VariableDumper VarDumper(Printer); VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); } else { if (auto Sym = Item->getSymbol()) Sym->dump(*this); } if (Item->getLayoutSize() > 0) { uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; if (Prev < UseMap.size()) NextPaddingByte = UseMap.find_next_unset(Prev); } } auto TailPadding = Layout.tailPadding(); if (TailPadding > 0) { if (TailPadding != 1 || Layout.getSize() != 1) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << TailPadding << " bytes)"; DumpedAnything = true; } } return DumpedAnything; } void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { if (Amount == 0) return; Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount << " bytes)"; DumpedAnything = true; } void PrettyClassLayoutGraphicalDumper::dump( const PDBSymbolTypeBaseClass &Symbol) { assert(CurrentItem != nullptr); Printer.NewLine(); BaseClassLayout &Layout = static_cast(*CurrentItem); std::string Label = "base"; if (Layout.isVirtualBase()) { Label.insert(Label.begin(), 'v'); if (Layout.getBase().isIndirectVirtualBaseClass()) Label.insert(Label.begin(), 'i'); } Printer << Label << " "; uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size << "] "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); if (shouldRecurse()) { Printer.Indent(); uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1, ChildOffsetZero); DumpedAnything |= BaseDumper.start(Layout); Printer.Unindent(); } DumpedAnything = true; } bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const { uint32_t Limit = opts::pretty::ClassRecursionDepth; if (Limit == 0) return true; return RecursionLevel < Limit; } void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { VariableDumper VarDumper(Printer); VarDumper.start(Symbol, ClassOffsetZero); if (CurrentItem != nullptr) { DataMemberLayoutItem &Layout = static_cast(*CurrentItem); if (Layout.hasUDTLayout() && shouldRecurse()) { uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); Printer.Indent(); PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1, ChildOffsetZero); TypeDumper.start(Layout.getUDTLayout()); Printer.Unindent(); } } DumpedAnything = true; } void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { assert(CurrentItem != nullptr); VariableDumper VarDumper(Printer); VarDumper.start(Symbol, ClassOffsetZero); DumpedAnything = true; } void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) { DumpedAnything = true; Printer.NewLine(); EnumDumper Dumper(Printer); Dumper.start(Symbol); } void PrettyClassLayoutGraphicalDumper::dump( const PDBSymbolTypeTypedef &Symbol) { DumpedAnything = true; Printer.NewLine(); TypedefDumper Dumper(Printer); Dumper.start(Symbol); } void PrettyClassLayoutGraphicalDumper::dump( const PDBSymbolTypeBuiltin &Symbol) {} void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) { if (Printer.IsSymbolExcluded(Symbol.getName())) return; if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) return; if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && !Symbol.isIntroVirtualFunction()) return; DumpedAnything = true; Printer.NewLine(); FunctionDumper Dumper(Printer); Dumper.start(Symbol, FunctionDumper::PointerType::None); }