| //===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "Analyze.h" | |
| #include "llvm/ADT/DenseSet.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" | |
| #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" | |
| #include "llvm/DebugInfo/CodeView/TypeRecord.h" | |
| #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" | |
| #include "llvm/DebugInfo/PDB/Native/PDBFile.h" | |
| #include "llvm/DebugInfo/PDB/Native/RawError.h" | |
| #include "llvm/DebugInfo/PDB/Native/TpiStream.h" | |
| #include "llvm/Support/FormatVariadic.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <list> | |
| using namespace llvm; | |
| using namespace llvm::codeview; | |
| using namespace llvm::pdb; | |
| static StringRef getLeafTypeName(TypeLeafKind LT) { | |
| switch (LT) { | |
| #define TYPE_RECORD(ename, value, name) \ | |
| case ename: \ | |
| return #name; | |
| #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" | |
| default: | |
| break; | |
| } | |
| return "UnknownLeaf"; | |
| } | |
| namespace { | |
| struct HashLookupVisitor : public TypeVisitorCallbacks { | |
| struct Entry { | |
| TypeIndex TI; | |
| CVType Record; | |
| }; | |
| explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {} | |
| Error visitTypeBegin(CVType &Record) override { | |
| uint32_t H = Tpi.getHashValues()[I]; | |
| Record.Hash = H; | |
| TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex); | |
| Lookup[H].push_back(Entry{TI, Record}); | |
| ++I; | |
| return Error::success(); | |
| } | |
| uint32_t I = 0; | |
| DenseMap<uint32_t, std::list<Entry>> Lookup; | |
| TpiStream &Tpi; | |
| }; | |
| } | |
| AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {} | |
| Error AnalysisStyle::dump() { | |
| auto Tpi = File.getPDBTpiStream(); | |
| if (!Tpi) | |
| return Tpi.takeError(); | |
| HashLookupVisitor Hasher(*Tpi); | |
| uint32_t RecordCount = Tpi->getNumTypeRecords(); | |
| auto Offsets = Tpi->getTypeIndexOffsets(); | |
| auto Types = llvm::make_unique<LazyRandomTypeCollection>( | |
| Tpi->typeArray(), RecordCount, Offsets); | |
| if (auto EC = codeview::visitTypeStream(*Types, Hasher)) | |
| return EC; | |
| auto &Adjusters = Tpi->getHashAdjusters(); | |
| DenseSet<uint32_t> AdjusterSet; | |
| for (const auto &Adj : Adjusters) { | |
| assert(AdjusterSet.find(Adj.second) == AdjusterSet.end()); | |
| AdjusterSet.insert(Adj.second); | |
| } | |
| uint32_t Count = 0; | |
| outs() << "Searching for hash collisions\n"; | |
| for (const auto &H : Hasher.Lookup) { | |
| if (H.second.size() <= 1) | |
| continue; | |
| ++Count; | |
| outs() << formatv("Hash: {0}, Count: {1} records\n", H.first, | |
| H.second.size()); | |
| for (const auto &R : H.second) { | |
| auto Iter = AdjusterSet.find(R.TI.getIndex()); | |
| StringRef Prefix; | |
| if (Iter != AdjusterSet.end()) { | |
| Prefix = "[HEAD]"; | |
| AdjusterSet.erase(Iter); | |
| } | |
| StringRef LeafName = getLeafTypeName(R.Record.Type); | |
| uint32_t TI = R.TI.getIndex(); | |
| StringRef TypeName = Types->getTypeName(R.TI); | |
| outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, | |
| TypeName); | |
| } | |
| } | |
| outs() << "\n"; | |
| outs() << "Dumping hash adjustment chains\n"; | |
| for (const auto &A : Tpi->getHashAdjusters()) { | |
| TypeIndex TI(A.second); | |
| StringRef TypeName = Types->getTypeName(TI); | |
| const CVType &HeadRecord = Types->getType(TI); | |
| assert(HeadRecord.Hash.hasValue()); | |
| auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); | |
| if (CollisionsIter == Hasher.Lookup.end()) | |
| continue; | |
| const auto &Collisions = CollisionsIter->second; | |
| outs() << TypeName << "\n"; | |
| outs() << formatv(" [HEAD] {0:x} {1} {2}\n", uint32_t(A.second), | |
| getLeafTypeName(HeadRecord.Type), TypeName); | |
| for (const auto &Chain : Collisions) { | |
| if (Chain.TI == TI) | |
| continue; | |
| const CVType &TailRecord = Types->getType(Chain.TI); | |
| outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), | |
| getLeafTypeName(TailRecord.Type), | |
| Types->getTypeName(Chain.TI)); | |
| } | |
| } | |
| outs() << formatv("There are {0} orphaned hash adjusters\n", | |
| AdjusterSet.size()); | |
| for (const auto &Adj : AdjusterSet) { | |
| outs() << formatv(" {0}\n", Adj); | |
| } | |
| uint32_t DistinctHashValues = Hasher.Lookup.size(); | |
| outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues); | |
| return Error::success(); | |
| } |