2017-04-16 16:01:22 +00:00
|
|
|
//===- 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/TypeDatabase.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.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/TypeRecords.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();
|
|
|
|
|
2017-05-08 17:12:57 +00:00
|
|
|
TypeDatabase TypeDB(Tpi->getNumTypeRecords());
|
2017-04-16 16:01:22 +00:00
|
|
|
TypeDatabaseVisitor DBV(TypeDB);
|
|
|
|
TypeVisitorCallbackPipeline Pipeline;
|
|
|
|
HashLookupVisitor Hasher(*Tpi);
|
|
|
|
// Add them to the database
|
|
|
|
Pipeline.addCallbackToPipeline(DBV);
|
|
|
|
// Store their hash values
|
|
|
|
Pipeline.addCallbackToPipeline(Hasher);
|
|
|
|
|
2017-05-17 20:22:39 +00:00
|
|
|
if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline))
|
|
|
|
return EC;
|
2017-04-16 16:01:22 +00:00
|
|
|
|
|
|
|
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 = TypeDB.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 = TypeDB.getTypeName(TI);
|
|
|
|
const CVType &HeadRecord = TypeDB.getTypeRecord(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", A.second,
|
|
|
|
getLeafTypeName(HeadRecord.Type), TypeName);
|
|
|
|
for (const auto &Chain : Collisions) {
|
|
|
|
if (Chain.TI == TI)
|
|
|
|
continue;
|
|
|
|
const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI);
|
|
|
|
outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
|
|
|
|
getLeafTypeName(TailRecord.Type),
|
|
|
|
TypeDB.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();
|
|
|
|
}
|