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