blob: a542a51b188ad8eab7859b224a447580a40ac4ad [file] [log] [blame]
Zachary Turner0eace0b2016-05-02 18:09:14 +00001//===- NameHashTable.cpp - PDB Name Hash Table ------------------*- 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 "llvm/DebugInfo/PDB/Raw/NameHashTable.h"
11
12#include "llvm/ADT/ArrayRef.h"
Zachary Turnerd5d37dc2016-05-25 20:37:03 +000013#include "llvm/DebugInfo/CodeView/StreamReader.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000014#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Zachary Turner0eace0b2016-05-02 18:09:14 +000015#include "llvm/Support/Endian.h"
16
17using namespace llvm;
18using namespace llvm::support;
19using namespace llvm::pdb;
20
Zachary Turner0eace0b2016-05-02 18:09:14 +000021static inline uint32_t HashStringV1(StringRef Str) {
22 uint32_t Result = 0;
23 uint32_t Size = Str.size();
24
25 ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
26 Size / 4);
27
28 for (auto Value : Longs)
29 Result ^= Value;
30
31 const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
32 uint32_t RemainderSize = Size - Longs.size() * 4;
33
34 // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the
35 // possibly remaining 1 byte.
36 if (RemainderSize >= 2) {
Zachary Turnera801dc12016-05-02 18:36:58 +000037 uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
38 Result ^= static_cast<uint32_t>(Value);
Zachary Turner0eace0b2016-05-02 18:09:14 +000039 Remainder += 2;
40 RemainderSize -= 2;
41 }
42
43 // hash possible odd byte
44 if (RemainderSize == 1) {
45 Result ^= *(Remainder++);
46 }
47
48 const uint32_t toLowerMask = 0x20202020;
49 Result |= toLowerMask;
50 Result ^= (Result >> 11);
51
52 return Result ^ (Result >> 16);
53}
54
55static inline uint32_t HashStringV2(StringRef Str) {
56 uint32_t Hash = 0xb170a1bf;
57
58 ArrayRef<char> Buffer(Str.begin(), Str.end());
59
60 ArrayRef<ulittle32_t> Items(
61 reinterpret_cast<const ulittle32_t *>(Buffer.data()),
62 Buffer.size() / sizeof(ulittle32_t));
63 for (ulittle32_t Item : Items) {
64 Hash += Item;
65 Hash += (Hash << 10);
66 Hash ^= (Hash >> 6);
67 }
68 Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
69 for (uint8_t Item : Buffer) {
70 Hash += Item;
71 Hash += (Hash << 10);
72 Hash ^= (Hash >> 6);
73 }
74
75 return Hash * 1664525L + 1013904223L;
76}
77
78NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {}
79
Zachary Turnerd5d37dc2016-05-25 20:37:03 +000080Error NameHashTable::load(codeview::StreamReader &Stream) {
Zachary Turner0eace0b2016-05-02 18:09:14 +000081 struct Header {
82 support::ulittle32_t Signature;
83 support::ulittle32_t HashVersion;
84 support::ulittle32_t ByteSize;
85 };
86
87 Header H;
Zachary Turner819e77d2016-05-06 20:51:57 +000088 if (auto EC = Stream.readObject(&H))
89 return EC;
90
Zachary Turner0eace0b2016-05-02 18:09:14 +000091 if (H.Signature != 0xEFFEEFFE)
Zachary Turner819e77d2016-05-06 20:51:57 +000092 return make_error<RawError>(raw_error_code::corrupt_file,
93 "Invalid hash table signature");
Zachary Turner0eace0b2016-05-02 18:09:14 +000094 if (H.HashVersion != 1 && H.HashVersion != 2)
Zachary Turner819e77d2016-05-06 20:51:57 +000095 return make_error<RawError>(raw_error_code::corrupt_file,
96 "Unsupported hash version");
Zachary Turner0eace0b2016-05-02 18:09:14 +000097
98 Signature = H.Signature;
99 HashVersion = H.HashVersion;
Zachary Turner819e77d2016-05-06 20:51:57 +0000100 if (auto EC = NamesBuffer.initialize(Stream, H.ByteSize))
101 return make_error<RawError>(raw_error_code::corrupt_file,
102 "Invalid hash table byte length");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000103
104 support::ulittle32_t HashCount;
Zachary Turner819e77d2016-05-06 20:51:57 +0000105 if (auto EC = Stream.readObject(&HashCount))
106 return EC;
107
Zachary Turner0eace0b2016-05-02 18:09:14 +0000108 std::vector<support::ulittle32_t> BucketArray(HashCount);
Zachary Turner819e77d2016-05-06 20:51:57 +0000109 if (auto EC = Stream.readArray<support::ulittle32_t>(BucketArray))
110 return make_error<RawError>(raw_error_code::corrupt_file,
111 "Could not read bucket array");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000112 IDs.assign(BucketArray.begin(), BucketArray.end());
113
114 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
Zachary Turner819e77d2016-05-06 20:51:57 +0000115 return make_error<RawError>(raw_error_code::corrupt_file,
116 "Missing name count");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000117
Zachary Turner819e77d2016-05-06 20:51:57 +0000118 if (auto EC = Stream.readInteger(NameCount))
119 return EC;
120 return Error::success();
Zachary Turner0eace0b2016-05-02 18:09:14 +0000121}
122
123StringRef NameHashTable::getStringForID(uint32_t ID) const {
124 if (ID == IDs[0])
125 return StringRef();
126
127 return StringRef(NamesBuffer.str().begin() + ID);
128}
129
130uint32_t NameHashTable::getIDForString(StringRef Str) const {
131 uint32_t Hash = (HashVersion == 1) ? HashStringV1(Str) : HashStringV2(Str);
132 size_t Count = IDs.size();
133 uint32_t Start = Hash % Count;
134 for (size_t I = 0; I < Count; ++I) {
135 // The hash is just a starting point for the search, but if it
136 // doesn't work we should find the string no matter what, because
137 // we iterate the entire array.
138 uint32_t Index = (Start + I) % Count;
139
140 uint32_t ID = IDs[Index];
141 StringRef S = getStringForID(ID);
142 if (S == Str)
143 return ID;
144 }
145 // IDs[0] contains the ID of the "invalid" entry.
146 return IDs[0];
147}
148
Rui Ueyamab12b1582016-05-25 04:07:17 +0000149ArrayRef<uint32_t> NameHashTable::name_ids() const { return IDs; }