blob: 2ecb02d1412da44446e70251e9b6f5bc8a8f664d [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"
13#include "llvm/DebugInfo/PDB/Raw/ByteStream.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/DebugInfo/PDB/Raw/StreamReader.h"
16#include "llvm/Support/Endian.h"
17
18using namespace llvm;
19using namespace llvm::support;
20using namespace llvm::pdb;
21
Zachary Turner0eace0b2016-05-02 18:09:14 +000022static inline uint32_t HashStringV1(StringRef Str) {
23 uint32_t Result = 0;
24 uint32_t Size = Str.size();
25
26 ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
27 Size / 4);
28
29 for (auto Value : Longs)
30 Result ^= Value;
31
32 const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
33 uint32_t RemainderSize = Size - Longs.size() * 4;
34
35 // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the
36 // possibly remaining 1 byte.
37 if (RemainderSize >= 2) {
Zachary Turnera801dc12016-05-02 18:36:58 +000038 uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
39 Result ^= static_cast<uint32_t>(Value);
Zachary Turner0eace0b2016-05-02 18:09:14 +000040 Remainder += 2;
41 RemainderSize -= 2;
42 }
43
44 // hash possible odd byte
45 if (RemainderSize == 1) {
46 Result ^= *(Remainder++);
47 }
48
49 const uint32_t toLowerMask = 0x20202020;
50 Result |= toLowerMask;
51 Result ^= (Result >> 11);
52
53 return Result ^ (Result >> 16);
54}
55
56static inline uint32_t HashStringV2(StringRef Str) {
57 uint32_t Hash = 0xb170a1bf;
58
59 ArrayRef<char> Buffer(Str.begin(), Str.end());
60
61 ArrayRef<ulittle32_t> Items(
62 reinterpret_cast<const ulittle32_t *>(Buffer.data()),
63 Buffer.size() / sizeof(ulittle32_t));
64 for (ulittle32_t Item : Items) {
65 Hash += Item;
66 Hash += (Hash << 10);
67 Hash ^= (Hash >> 6);
68 }
69 Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
70 for (uint8_t Item : Buffer) {
71 Hash += Item;
72 Hash += (Hash << 10);
73 Hash ^= (Hash >> 6);
74 }
75
76 return Hash * 1664525L + 1013904223L;
77}
78
79NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {}
80
Zachary Turner819e77d2016-05-06 20:51:57 +000081Error NameHashTable::load(StreamReader &Stream) {
Zachary Turner0eace0b2016-05-02 18:09:14 +000082 struct Header {
83 support::ulittle32_t Signature;
84 support::ulittle32_t HashVersion;
85 support::ulittle32_t ByteSize;
86 };
87
88 Header H;
Zachary Turner819e77d2016-05-06 20:51:57 +000089 if (auto EC = Stream.readObject(&H))
90 return EC;
91
Zachary Turner0eace0b2016-05-02 18:09:14 +000092 if (H.Signature != 0xEFFEEFFE)
Zachary Turner819e77d2016-05-06 20:51:57 +000093 return make_error<RawError>(raw_error_code::corrupt_file,
94 "Invalid hash table signature");
Zachary Turner0eace0b2016-05-02 18:09:14 +000095 if (H.HashVersion != 1 && H.HashVersion != 2)
Zachary Turner819e77d2016-05-06 20:51:57 +000096 return make_error<RawError>(raw_error_code::corrupt_file,
97 "Unsupported hash version");
Zachary Turner0eace0b2016-05-02 18:09:14 +000098
99 Signature = H.Signature;
100 HashVersion = H.HashVersion;
Zachary Turner819e77d2016-05-06 20:51:57 +0000101 if (auto EC = NamesBuffer.initialize(Stream, H.ByteSize))
102 return make_error<RawError>(raw_error_code::corrupt_file,
103 "Invalid hash table byte length");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000104
105 support::ulittle32_t HashCount;
Zachary Turner819e77d2016-05-06 20:51:57 +0000106 if (auto EC = Stream.readObject(&HashCount))
107 return EC;
108
Zachary Turner0eace0b2016-05-02 18:09:14 +0000109 std::vector<support::ulittle32_t> BucketArray(HashCount);
Zachary Turner819e77d2016-05-06 20:51:57 +0000110 if (auto EC = Stream.readArray<support::ulittle32_t>(BucketArray))
111 return make_error<RawError>(raw_error_code::corrupt_file,
112 "Could not read bucket array");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000113 IDs.assign(BucketArray.begin(), BucketArray.end());
114
115 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
Zachary Turner819e77d2016-05-06 20:51:57 +0000116 return make_error<RawError>(raw_error_code::corrupt_file,
117 "Missing name count");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000118
Zachary Turner819e77d2016-05-06 20:51:57 +0000119 if (auto EC = Stream.readInteger(NameCount))
120 return EC;
121 return Error::success();
Zachary Turner0eace0b2016-05-02 18:09:14 +0000122}
123
124StringRef NameHashTable::getStringForID(uint32_t ID) const {
125 if (ID == IDs[0])
126 return StringRef();
127
128 return StringRef(NamesBuffer.str().begin() + ID);
129}
130
131uint32_t NameHashTable::getIDForString(StringRef Str) const {
132 uint32_t Hash = (HashVersion == 1) ? HashStringV1(Str) : HashStringV2(Str);
133 size_t Count = IDs.size();
134 uint32_t Start = Hash % Count;
135 for (size_t I = 0; I < Count; ++I) {
136 // The hash is just a starting point for the search, but if it
137 // doesn't work we should find the string no matter what, because
138 // we iterate the entire array.
139 uint32_t Index = (Start + I) % Count;
140
141 uint32_t ID = IDs[Index];
142 StringRef S = getStringForID(ID);
143 if (S == Str)
144 return ID;
145 }
146 // IDs[0] contains the ID of the "invalid" entry.
147 return IDs[0];
148}
149
150ArrayRef<uint32_t> NameHashTable::name_ids() const {
151 return ArrayRef<uint32_t>(IDs).slice(1, NameCount);
152}