PrettyTypeDumper.cpp revision 321369
1//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "PrettyTypeDumper.h" 11 12#include "LinePrinter.h" 13#include "PrettyBuiltinDumper.h" 14#include "PrettyClassDefinitionDumper.h" 15#include "PrettyEnumDumper.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/PDBSymbolTypeBuiltin.h" 22#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" 23#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" 24#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" 25#include "llvm/DebugInfo/PDB/UDTLayout.h" 26#include "llvm/Support/Compiler.h" 27#include "llvm/Support/FormatVariadic.h" 28 29using namespace llvm; 30using namespace llvm::pdb; 31 32using LayoutPtr = std::unique_ptr<ClassLayout>; 33 34typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); 35 36static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { 37 return S1->getName() < S2->getName(); 38} 39 40static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { 41 return S1->getSize() < S2->getSize(); 42} 43 44static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { 45 return S1->deepPaddingSize() < S2->deepPaddingSize(); 46} 47 48static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { 49 double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); 50 double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); 51 return Pct1 < Pct2; 52} 53 54static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) { 55 return S1->immediatePadding() < S2->immediatePadding(); 56} 57 58static bool ComparePaddingPctImmediate(const LayoutPtr &S1, 59 const LayoutPtr &S2) { 60 double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize(); 61 double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize(); 62 return Pct1 < Pct2; 63} 64 65static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { 66 switch (Mode) { 67 case opts::pretty::ClassSortMode::Name: 68 return CompareNames; 69 case opts::pretty::ClassSortMode::Size: 70 return CompareSizes; 71 case opts::pretty::ClassSortMode::Padding: 72 return ComparePadding; 73 case opts::pretty::ClassSortMode::PaddingPct: 74 return ComparePaddingPct; 75 case opts::pretty::ClassSortMode::PaddingImmediate: 76 return ComparePaddingImmediate; 77 case opts::pretty::ClassSortMode::PaddingPctImmediate: 78 return ComparePaddingPctImmediate; 79 default: 80 return nullptr; 81 } 82} 83 84template <typename Enumerator> 85static std::vector<std::unique_ptr<ClassLayout>> 86filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, 87 uint32_t UnfilteredCount) { 88 std::vector<std::unique_ptr<ClassLayout>> Filtered; 89 90 Filtered.reserve(UnfilteredCount); 91 CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); 92 93 if (UnfilteredCount > 10000) { 94 errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); 95 errs().flush(); 96 } 97 uint32_t Examined = 0; 98 uint32_t Discarded = 0; 99 while (auto Class = E.getNext()) { 100 ++Examined; 101 if (Examined % 10000 == 0) { 102 errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", 103 Examined, UnfilteredCount, Discarded); 104 errs().flush(); 105 } 106 107 if (Class->getUnmodifiedTypeId() != 0) { 108 ++Discarded; 109 continue; 110 } 111 112 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { 113 ++Discarded; 114 continue; 115 } 116 117 auto Layout = llvm::make_unique<ClassLayout>(std::move(Class)); 118 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { 119 ++Discarded; 120 continue; 121 } 122 if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) { 123 ++Discarded; 124 continue; 125 } 126 127 Filtered.push_back(std::move(Layout)); 128 } 129 130 if (Comp) 131 std::sort(Filtered.begin(), Filtered.end(), Comp); 132 return Filtered; 133} 134 135TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} 136 137void TypeDumper::start(const PDBSymbolExe &Exe) { 138 auto Children = Exe.findAllChildren(); 139 if (opts::pretty::Enums) { 140 if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) { 141 Printer.NewLine(); 142 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums"; 143 Printer << ": (" << Enums->getChildCount() << " items)"; 144 Printer.Indent(); 145 while (auto Enum = Enums->getNext()) 146 Enum->dump(*this); 147 Printer.Unindent(); 148 } 149 } 150 151 if (opts::pretty::Typedefs) { 152 if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) { 153 Printer.NewLine(); 154 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs"; 155 Printer << ": (" << Typedefs->getChildCount() << " items)"; 156 Printer.Indent(); 157 while (auto Typedef = Typedefs->getNext()) 158 Typedef->dump(*this); 159 Printer.Unindent(); 160 } 161 } 162 163 if (opts::pretty::Classes) { 164 if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) { 165 uint32_t All = Classes->getChildCount(); 166 167 Printer.NewLine(); 168 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; 169 170 bool Precompute = false; 171 Precompute = 172 (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); 173 174 // If we're using no sort mode, then we can start getting immediate output 175 // from the tool by just filtering as we go, rather than processing 176 // everything up front so that we can sort it. This makes the tool more 177 // responsive. So only precompute the filtered/sorted set of classes if 178 // necessary due to the specified options. 179 std::vector<LayoutPtr> Filtered; 180 uint32_t Shown = All; 181 if (Precompute) { 182 Filtered = filterAndSortClassDefs(Printer, *Classes, All); 183 184 Shown = Filtered.size(); 185 } 186 187 Printer << ": (Showing " << Shown << " items"; 188 if (Shown < All) 189 Printer << ", " << (All - Shown) << " filtered"; 190 Printer << ")"; 191 Printer.Indent(); 192 193 // If we pre-computed, iterate the filtered/sorted list, otherwise iterate 194 // the DIA enumerator and filter on the fly. 195 if (Precompute) { 196 for (auto &Class : Filtered) 197 dumpClassLayout(*Class); 198 } else { 199 while (auto Class = Classes->getNext()) { 200 if (Class->getUnmodifiedTypeId() != 0) 201 continue; 202 203 if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) 204 continue; 205 206 auto Layout = llvm::make_unique<ClassLayout>(std::move(Class)); 207 if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) 208 continue; 209 210 dumpClassLayout(*Layout); 211 } 212 } 213 214 Printer.Unindent(); 215 } 216 } 217} 218 219void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { 220 assert(opts::pretty::Enums); 221 222 if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) 223 return; 224 // Dump member enums when dumping their class definition. 225 if (nullptr != Symbol.getClassParent()) 226 return; 227 228 Printer.NewLine(); 229 EnumDumper Dumper(Printer); 230 Dumper.start(Symbol); 231} 232 233void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { 234 assert(opts::pretty::Typedefs); 235 236 if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) 237 return; 238 239 Printer.NewLine(); 240 TypedefDumper Dumper(Printer); 241 Dumper.start(Symbol); 242} 243 244void TypeDumper::dumpClassLayout(const ClassLayout &Class) { 245 assert(opts::pretty::Classes); 246 247 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { 248 Printer.NewLine(); 249 WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; 250 WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName(); 251 } else { 252 ClassDefinitionDumper Dumper(Printer); 253 Dumper.start(Class); 254 } 255} 256