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