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