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