blob: ab4477ed7bad96ceb4a5c59dd9854db047643b81 [file] [log] [blame]
Zachary Turnerd50c0132017-02-01 18:30:22 +00001//===- Analyze.cpp - PDB analysis functions ---------------------*- 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 "Analyze.h"
11
12#include "llvm/ADT/DenseSet.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
15#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
16#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
17#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
18#include "llvm/DebugInfo/CodeView/TypeRecord.h"
19#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
20#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
21#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
22#include "llvm/DebugInfo/PDB/Native/RawError.h"
23#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/raw_ostream.h"
27
28#include <list>
29
30using namespace llvm;
31using namespace llvm::codeview;
32using namespace llvm::pdb;
33
34static StringRef getLeafTypeName(TypeLeafKind LT) {
35 switch (LT) {
36#define TYPE_RECORD(ename, value, name) \
37 case ename: \
38 return #name;
39#include "llvm/DebugInfo/CodeView/TypeRecords.def"
40 default:
41 break;
42 }
43 return "UnknownLeaf";
44}
45
46namespace {
47struct HashLookupVisitor : public TypeVisitorCallbacks {
48 struct Entry {
49 TypeIndex TI;
50 CVType Record;
51 };
52
53 explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {}
54
55 Error visitTypeBegin(CVType &Record) override {
56 uint32_t H = Tpi.getHashValues()[I];
57 Record.Hash = H;
58 TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex);
59 Lookup[H].push_back(Entry{TI, Record});
60 ++I;
61 return Error::success();
62 }
63
64 uint32_t I = 0;
65 DenseMap<uint32_t, std::list<Entry>> Lookup;
66 TpiStream &Tpi;
67};
68}
69
70AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {}
71
72Error AnalysisStyle::dump() {
73 auto Tpi = File.getPDBTpiStream();
74 if (!Tpi)
75 return Tpi.takeError();
76
Zachary Turner8c746732017-05-05 22:02:37 +000077 TypeDatabase TypeDB(Tpi->getNumTypeRecords());
Zachary Turnerd50c0132017-02-01 18:30:22 +000078 TypeDatabaseVisitor DBV(TypeDB);
Zachary Turnerd50c0132017-02-01 18:30:22 +000079 TypeVisitorCallbackPipeline Pipeline;
80 HashLookupVisitor Hasher(*Tpi);
Zachary Turnerd50c0132017-02-01 18:30:22 +000081 // Add them to the database
82 Pipeline.addCallbackToPipeline(DBV);
83 // Store their hash values
84 Pipeline.addCallbackToPipeline(Hasher);
85
Zachary Turner1d795c42017-05-17 16:39:06 +000086 if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline))
87 return EC;
Zachary Turnerd50c0132017-02-01 18:30:22 +000088
89 auto &Adjusters = Tpi->getHashAdjusters();
90 DenseSet<uint32_t> AdjusterSet;
91 for (const auto &Adj : Adjusters) {
92 assert(AdjusterSet.find(Adj.second) == AdjusterSet.end());
93 AdjusterSet.insert(Adj.second);
94 }
95
96 uint32_t Count = 0;
97 outs() << "Searching for hash collisions\n";
98 for (const auto &H : Hasher.Lookup) {
99 if (H.second.size() <= 1)
100 continue;
101 ++Count;
102 outs() << formatv("Hash: {0}, Count: {1} records\n", H.first,
103 H.second.size());
104 for (const auto &R : H.second) {
105 auto Iter = AdjusterSet.find(R.TI.getIndex());
106 StringRef Prefix;
107 if (Iter != AdjusterSet.end()) {
108 Prefix = "[HEAD]";
109 AdjusterSet.erase(Iter);
110 }
111 StringRef LeafName = getLeafTypeName(R.Record.Type);
112 uint32_t TI = R.TI.getIndex();
113 StringRef TypeName = TypeDB.getTypeName(R.TI);
114 outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI,
115 TypeName);
116 }
117 }
118
119 outs() << "\n";
120 outs() << "Dumping hash adjustment chains\n";
121 for (const auto &A : Tpi->getHashAdjusters()) {
122 TypeIndex TI(A.second);
123 StringRef TypeName = TypeDB.getTypeName(TI);
124 const CVType &HeadRecord = TypeDB.getTypeRecord(TI);
125 assert(HeadRecord.Hash.hasValue());
126
127 auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash);
128 if (CollisionsIter == Hasher.Lookup.end())
129 continue;
130
131 const auto &Collisions = CollisionsIter->second;
132 outs() << TypeName << "\n";
133 outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second,
134 getLeafTypeName(HeadRecord.Type), TypeName);
135 for (const auto &Chain : Collisions) {
136 if (Chain.TI == TI)
137 continue;
138 const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI);
139 outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(),
140 getLeafTypeName(TailRecord.Type),
141 TypeDB.getTypeName(Chain.TI));
142 }
143 }
144 outs() << formatv("There are {0} orphaned hash adjusters\n",
145 AdjusterSet.size());
146 for (const auto &Adj : AdjusterSet) {
147 outs() << formatv(" {0}\n", Adj);
148 }
149
150 uint32_t DistinctHashValues = Hasher.Lookup.size();
151 outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues);
152 return Error::success();
153}