1 //===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "PrettyClassLayoutGraphicalDumper.h" 10 11 #include "LinePrinter.h" 12 #include "PrettyClassDefinitionDumper.h" 13 #include "PrettyEnumDumper.h" 14 #include "PrettyFunctionDumper.h" 15 #include "PrettyTypedefDumper.h" 16 #include "PrettyVariableDumper.h" 17 #include "PrettyVariableDumper.h" 18 #include "llvm-pdbutil.h" 19 20 #include "llvm/DebugInfo/PDB/PDBSymbolData.h" 21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" 22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" 23 #include "llvm/DebugInfo/PDB/UDTLayout.h" 24 #include "llvm/Support/Format.h" 25 26 using namespace llvm; 27 using namespace llvm::pdb; 28 29 PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( 30 LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset) 31 : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel), 32 ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {} 33 34 bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { 35 36 if (RecursionLevel == 1 && 37 opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) { 38 for (auto &Other : Layout.other_items()) 39 Other->dump(*this); 40 for (auto &Func : Layout.funcs()) 41 Func->dump(*this); 42 } 43 44 const BitVector &UseMap = Layout.usedBytes(); 45 int NextPaddingByte = UseMap.find_first_unset(); 46 47 for (auto &Item : Layout.layout_items()) { 48 // Calculate the absolute offset of the first byte of the next field. 49 uint32_t RelativeOffset = Item->getOffsetInParent(); 50 CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; 51 52 // This might be an empty base, in which case it could extend outside the 53 // bounds of the parent class. 54 if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { 55 // If there is any remaining padding in this class, and the offset of the 56 // new item is after the padding, then we must have just jumped over some 57 // padding. Print a padding row and then look for where the next block 58 // of padding begins. 59 if ((NextPaddingByte >= 0) && 60 (RelativeOffset > uint32_t(NextPaddingByte))) { 61 printPaddingRow(RelativeOffset - NextPaddingByte); 62 NextPaddingByte = UseMap.find_next_unset(RelativeOffset); 63 } 64 } 65 66 CurrentItem = Item; 67 if (Item->isVBPtr()) { 68 VTableLayoutItem &Layout = static_cast<VTableLayoutItem &>(*CurrentItem); 69 70 VariableDumper VarDumper(Printer); 71 VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); 72 } else { 73 if (auto Sym = Item->getSymbol()) 74 Sym->dump(*this); 75 } 76 77 if (Item->getLayoutSize() > 0) { 78 uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; 79 if (Prev < UseMap.size()) 80 NextPaddingByte = UseMap.find_next_unset(Prev); 81 } 82 } 83 84 auto TailPadding = Layout.tailPadding(); 85 if (TailPadding > 0) { 86 if (TailPadding != 1 || Layout.getSize() != 1) { 87 Printer.NewLine(); 88 WithColor(Printer, PDB_ColorItem::Padding).get() 89 << "<padding> (" << TailPadding << " bytes)"; 90 DumpedAnything = true; 91 } 92 } 93 94 return DumpedAnything; 95 } 96 97 void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { 98 if (Amount == 0) 99 return; 100 101 Printer.NewLine(); 102 WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount 103 << " bytes)"; 104 DumpedAnything = true; 105 } 106 107 void PrettyClassLayoutGraphicalDumper::dump( 108 const PDBSymbolTypeBaseClass &Symbol) { 109 assert(CurrentItem != nullptr); 110 111 Printer.NewLine(); 112 BaseClassLayout &Layout = static_cast<BaseClassLayout &>(*CurrentItem); 113 114 std::string Label = "base"; 115 if (Layout.isVirtualBase()) { 116 Label.insert(Label.begin(), 'v'); 117 if (Layout.getBase().isIndirectVirtualBaseClass()) 118 Label.insert(Label.begin(), 'i'); 119 } 120 Printer << Label << " "; 121 122 uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); 123 124 WithColor(Printer, PDB_ColorItem::Offset).get() 125 << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size 126 << "] "; 127 128 WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); 129 130 if (shouldRecurse()) { 131 Printer.Indent(); 132 uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); 133 PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1, 134 ChildOffsetZero); 135 DumpedAnything |= BaseDumper.start(Layout); 136 Printer.Unindent(); 137 } 138 139 DumpedAnything = true; 140 } 141 142 bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const { 143 uint32_t Limit = opts::pretty::ClassRecursionDepth; 144 if (Limit == 0) 145 return true; 146 return RecursionLevel < Limit; 147 } 148 149 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { 150 VariableDumper VarDumper(Printer); 151 VarDumper.start(Symbol, ClassOffsetZero); 152 153 if (CurrentItem != nullptr) { 154 DataMemberLayoutItem &Layout = 155 static_cast<DataMemberLayoutItem &>(*CurrentItem); 156 157 if (Layout.hasUDTLayout() && shouldRecurse()) { 158 uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); 159 Printer.Indent(); 160 PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1, 161 ChildOffsetZero); 162 TypeDumper.start(Layout.getUDTLayout()); 163 Printer.Unindent(); 164 } 165 } 166 167 DumpedAnything = true; 168 } 169 170 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { 171 assert(CurrentItem != nullptr); 172 173 VariableDumper VarDumper(Printer); 174 VarDumper.start(Symbol, ClassOffsetZero); 175 176 DumpedAnything = true; 177 } 178 179 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) { 180 DumpedAnything = true; 181 Printer.NewLine(); 182 EnumDumper Dumper(Printer); 183 Dumper.start(Symbol); 184 } 185 186 void PrettyClassLayoutGraphicalDumper::dump( 187 const PDBSymbolTypeTypedef &Symbol) { 188 DumpedAnything = true; 189 Printer.NewLine(); 190 TypedefDumper Dumper(Printer); 191 Dumper.start(Symbol); 192 } 193 194 void PrettyClassLayoutGraphicalDumper::dump( 195 const PDBSymbolTypeBuiltin &Symbol) {} 196 197 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} 198 199 void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) { 200 if (Printer.IsSymbolExcluded(Symbol.getName())) 201 return; 202 if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) 203 return; 204 if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && 205 !Symbol.isIntroVirtualFunction()) 206 return; 207 208 DumpedAnything = true; 209 Printer.NewLine(); 210 FunctionDumper Dumper(Printer); 211 Dumper.start(Symbol, FunctionDumper::PointerType::None); 212 } 213