362 lines · cpp
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-exception6//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 34using namespace llvm;35using namespace llvm::pdb;36 37using LayoutPtr = std::unique_ptr<ClassLayout>;38 39typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2);40 41static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) {42 return S1->getName() < S2->getName();43}44 45static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) {46 return S1->getSize() < S2->getSize();47}48 49static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) {50 return S1->deepPaddingSize() < S2->deepPaddingSize();51}52 53static 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 59static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) {60 return S1->immediatePadding() < S2->immediatePadding();61}62 63static 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 70static 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 89template <typename Enumerator>90static std::vector<std::unique_ptr<ClassLayout>>91filterAndSortClassDefs(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 140TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}141 142template <typename T>143static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {144 return false;145}146 147static 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 157static bool isTypeExcluded(LinePrinter &Printer,158 const PDBSymbolTypeTypedef &Typedef) {159 return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());160}161 162template <typename SymbolT>163static 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 181static 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 195void 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 output228 // from the tool by just filtering as we go, rather than processing229 // everything up front so that we can sort it. This makes the tool more230 // responsive. So only precompute the filtered/sorted set of classes if231 // 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 iterate247 // 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 modified257 // 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 277void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {278 assert(opts::pretty::Enums);279 280 EnumDumper Dumper(Printer);281 Dumper.start(Symbol);282}283 284void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {285 BuiltinDumper BD(Printer);286 BD.start(Symbol);287}288 289void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {290 printClassDecl(Printer, Symbol);291}292 293void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {294 assert(opts::pretty::Typedefs);295 296 TypedefDumper Dumper(Printer);297 Dumper.start(Symbol);298}299 300void 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 309void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {310 FunctionDumper Dumper(Printer);311 Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);312}313 314void 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::Reference321 : 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 else343 Printer << "*";344}345 346void TypeDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {347 Printer.format("<vtshape ({0} methods)>", Symbol.getCount());348}349 350void 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