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