1 //===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ 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 "PrettyTypeDumper.h" 10 11 #include "PrettyBuiltinDumper.h" 12 #include "PrettyClassDefinitionDumper.h" 13 #include "PrettyEnumDumper.h" 14 #include "PrettyFunctionDumper.h" 15 #include "PrettyTypedefDumper.h" 16 #include "llvm-pdbutil.h" 17 18 #include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h" 19 #include "llvm/DebugInfo/PDB/IPDBLineNumber.h" 20 #include "llvm/DebugInfo/PDB/IPDBSession.h" 21 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" 22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" 23 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" 24 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" 25 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" 26 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" 27 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" 28 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" 29 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" 30 #include "llvm/DebugInfo/PDB/UDTLayout.h" 31 #include "llvm/Support/Compiler.h" 32 #include "llvm/Support/FormatVariadic.h" 33 34 using namespace llvm; 35 using namespace llvm::pdb; 36 37 using LayoutPtr = std::unique_ptr<ClassLayout>; 38 39 typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); 40 41 static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { 42 return S1->getName() < S2->getName(); 43 } 44 45 static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { 46 return S1->getSize() < S2->getSize(); 47 } 48 49 static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { 50 return S1->deepPaddingSize() < S2->deepPaddingSize(); 51 } 52 53 static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { 54 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); 55 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); 56 return Pct1 < Pct2; 57 } 58 59 static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) { 60 return S1->immediatePadding() < S2->immediatePadding(); 61 } 62 63 static bool ComparePaddingPctImmediate(const LayoutPtr &S1, 64 const LayoutPtr &S2) { 65 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize(); 66 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize(); 67 return Pct1 < Pct2; 68 } 69 70 static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { 71 switch (Mode) { 72 case opts::pretty::ClassSortMode::Name: 73 return CompareNames; 74 case opts::pretty::ClassSortMode::Size: 75 return CompareSizes; 76 case opts::pretty::ClassSortMode::Padding: 77 return ComparePadding; 78 case opts::pretty::ClassSortMode::PaddingPct: 79 return ComparePaddingPct; 80 case opts::pretty::ClassSortMode::PaddingImmediate: 81 return ComparePaddingImmediate; 82 case opts::pretty::ClassSortMode::PaddingPctImmediate: 83 return ComparePaddingPctImmediate; 84 default: 85 return nullptr; 86 } 87 } 88 89 template <typename Enumerator> 90 static std::vector<std::unique_ptr<ClassLayout>> 91 filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, 92 uint32_t UnfilteredCount) { 93 std::vector<std::unique_ptr<ClassLayout>> Filtered; 94 95 Filtered.reserve(UnfilteredCount); 96 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); 97 98 if (UnfilteredCount > 10000) { 99 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); 100 errs().flush(); 101 } 102 uint32_t Examined = 0; 103 uint32_t Discarded = 0; 104 while (auto Class = E.getNext()) { 105 ++Examined; 106 if (Examined % 10000 == 0) { 107 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", 108 Examined, UnfilteredCount, Discarded); 109 errs().flush(); 110 } 111 112 if (Class->getUnmodifiedTypeId() != 0) { 113 ++Discarded; 114 continue; 115 } 116 117 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { 118 ++Discarded; 119 continue; 120 } 121 122 auto Layout = std::make_unique<ClassLayout>(std::move(Class)); 123 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { 124 ++Discarded; 125 continue; 126 } 127 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) { 128 ++Discarded; 129 continue; 130 } 131 132 Filtered.push_back(std::move(Layout)); 133 } 134 135 if (Comp) 136 llvm::sort(Filtered, Comp); 137 return Filtered; 138 } 139 140 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} 141 142 template <typename T> 143 static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) { 144 return false; 145 } 146 147 static bool isTypeExcluded(LinePrinter &Printer, 148 const PDBSymbolTypeEnum &Enum) { 149 if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength())) 150 return true; 151 // Dump member enums when dumping their class definition. 152 if (nullptr != Enum.getClassParent()) 153 return true; 154 return false; 155 } 156 157 static bool isTypeExcluded(LinePrinter &Printer, 158 const PDBSymbolTypeTypedef &Typedef) { 159 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength()); 160 } 161 162 template <typename SymbolT> 163 static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe, 164 TypeDumper &TD, StringRef Label) { 165 if (auto Children = Exe.findAllChildren<SymbolT>()) { 166 Printer.NewLine(); 167 WithColor(Printer, PDB_ColorItem::Identifier).get() << Label; 168 Printer << ": (" << Children->getChildCount() << " items)"; 169 Printer.Indent(); 170 while (auto Child = Children->getNext()) { 171 if (isTypeExcluded(Printer, *Child)) 172 continue; 173 174 Printer.NewLine(); 175 Child->dump(TD); 176 } 177 Printer.Unindent(); 178 } 179 } 180 181 static void printClassDecl(LinePrinter &Printer, 182 const PDBSymbolTypeUDT &Class) { 183 if (Class.getUnmodifiedTypeId() != 0) { 184 if (Class.isConstType()) 185 WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; 186 if (Class.isVolatileType()) 187 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; 188 if (Class.isUnalignedType()) 189 WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned "; 190 } 191 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; 192 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); 193 } 194 195 void TypeDumper::start(const PDBSymbolExe &Exe) { 196 if (opts::pretty::Enums) 197 dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums"); 198 199 if (opts::pretty::Funcsigs) 200 dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this, 201 "Function Signatures"); 202 203 if (opts::pretty::Typedefs) 204 dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs"); 205 206 if (opts::pretty::Arrays) 207 dumpSymbolCategory<PDBSymbolTypeArray>(Printer, Exe, *this, "Arrays"); 208 209 if (opts::pretty::Pointers) 210 dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers"); 211 212 if (opts::pretty::VTShapes) 213 dumpSymbolCategory<PDBSymbolTypeVTableShape>(Printer, Exe, *this, 214 "VFTable Shapes"); 215 216 if (opts::pretty::Classes) { 217 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) { 218 uint32_t All = Classes->getChildCount(); 219 220 Printer.NewLine(); 221 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; 222 223 bool Precompute = false; 224 Precompute = 225 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); 226 227 // If we're using no sort mode, then we can start getting immediate output 228 // from the tool by just filtering as we go, rather than processing 229 // everything up front so that we can sort it. This makes the tool more 230 // responsive. So only precompute the filtered/sorted set of classes if 231 // necessary due to the specified options. 232 std::vector<LayoutPtr> Filtered; 233 uint32_t Shown = All; 234 if (Precompute) { 235 Filtered = filterAndSortClassDefs(Printer, *Classes, All); 236 237 Shown = Filtered.size(); 238 } 239 240 Printer << ": (Showing " << Shown << " items"; 241 if (Shown < All) 242 Printer << ", " << (All - Shown) << " filtered"; 243 Printer << ")"; 244 Printer.Indent(); 245 246 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate 247 // the DIA enumerator and filter on the fly. 248 if (Precompute) { 249 for (auto &Class : Filtered) 250 dumpClassLayout(*Class); 251 } else { 252 while (auto Class = Classes->getNext()) { 253 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) 254 continue; 255 256 // No point duplicating a full class layout. Just print the modified 257 // declaration and continue. 258 if (Class->getUnmodifiedTypeId() != 0) { 259 Printer.NewLine(); 260 printClassDecl(Printer, *Class); 261 continue; 262 } 263 264 auto Layout = std::make_unique<ClassLayout>(std::move(Class)); 265 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) 266 continue; 267 268 dumpClassLayout(*Layout); 269 } 270 } 271 272 Printer.Unindent(); 273 } 274 } 275 } 276 277 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { 278 assert(opts::pretty::Enums); 279 280 EnumDumper Dumper(Printer); 281 Dumper.start(Symbol); 282 } 283 284 void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { 285 BuiltinDumper BD(Printer); 286 BD.start(Symbol); 287 } 288 289 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { 290 printClassDecl(Printer, Symbol); 291 } 292 293 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { 294 assert(opts::pretty::Typedefs); 295 296 TypedefDumper Dumper(Printer); 297 Dumper.start(Symbol); 298 } 299 300 void TypeDumper::dump(const PDBSymbolTypeArray &Symbol) { 301 auto ElementType = Symbol.getElementType(); 302 303 ElementType->dump(*this); 304 Printer << "["; 305 WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getCount(); 306 Printer << "]"; 307 } 308 309 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { 310 FunctionDumper Dumper(Printer); 311 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); 312 } 313 314 void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) { 315 std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType(); 316 317 if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) { 318 FunctionDumper Dumper(Printer); 319 FunctionDumper::PointerType PT = 320 Symbol.isReference() ? FunctionDumper::PointerType::Reference 321 : FunctionDumper::PointerType::Pointer; 322 Dumper.start(*FS, nullptr, PT); 323 return; 324 } 325 326 if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) { 327 printClassDecl(Printer, *UDT); 328 } else if (P) { 329 P->dump(*this); 330 } 331 332 if (auto Parent = Symbol.getClassParent()) { 333 auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent)); 334 if (UDT) 335 Printer << " " << UDT->getName() << "::"; 336 } 337 338 if (Symbol.isReference()) 339 Printer << "&"; 340 else if (Symbol.isRValueReference()) 341 Printer << "&&"; 342 else 343 Printer << "*"; 344 } 345 346 void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) { 347 Printer.format("<vtshape ({0} methods)>", Symbol.getCount()); 348 } 349 350 void TypeDumper::dumpClassLayout(const ClassLayout &Class) { 351 assert(opts::pretty::Classes); 352 353 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { 354 WithColor(Printer, PDB_ColorItem::Keyword).get() 355 << Class.getClass().getUdtKind() << " "; 356 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); 357 } else { 358 ClassDefinitionDumper Dumper(Printer); 359 Dumper.start(Class); 360 } 361 } 362