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