blob: 7eae7489a0e3b6d528f841e9979e1b130906839b [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
Zachary Turner8dbe3622016-05-27 01:54:44 +000087 const Header *H;
88 if (auto EC = Stream.readObject(H))
Zachary Turner819e77d2016-05-06 20:51:57 +000089 return EC;
90
Zachary Turner8dbe3622016-05-27 01:54:44 +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 Turner8dbe3622016-05-27 01:54:44 +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
Zachary Turner8dbe3622016-05-27 01:54:44 +000098 Signature = H->Signature;
99 HashVersion = H->HashVersion;
100 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
Zachary Turner819e77d2016-05-06 20:51:57 +0000101 return make_error<RawError>(raw_error_code::corrupt_file,
102 "Invalid hash table byte length");
Zachary Turner0eace0b2016-05-02 18:09:14 +0000103
Zachary Turner8dbe3622016-05-27 01:54:44 +0000104 const support::ulittle32_t *HashCount;
105 if (auto EC = Stream.readObject(HashCount))
Zachary Turner819e77d2016-05-06 20:51:57 +0000106 return EC;
107
Zachary Turner8dbe3622016-05-27 01:54:44 +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
Zachary Turner8dbe3622016-05-27 01:54:44 +0000127 // NamesBuffer is a buffer of null terminated strings back to back. ID is
128 // the starting offset of the string we're looking for. So just seek into
129 // the desired offset and a read a null terminated stream from that offset.
130 StringRef Result;
131 codeview::StreamReader NameReader(NamesBuffer);
132 NameReader.setOffset(ID);
133 if (auto EC = NameReader.readZeroString(Result))
134 consumeError(std::move(EC));
135 return Result;
Zachary Turner0eace0b2016-05-02 18:09:14 +0000136}
137
138uint32_t NameHashTable::getIDForString(StringRef Str) const {
139 uint32_t Hash = (HashVersion == 1) ? HashStringV1(Str) : HashStringV2(Str);
140 size_t Count = IDs.size();
141 uint32_t Start = Hash % Count;
142 for (size_t I = 0; I < Count; ++I) {
143 // The hash is just a starting point for the search, but if it
144 // doesn't work we should find the string no matter what, because
145 // we iterate the entire array.
146 uint32_t Index = (Start + I) % Count;
147
148 uint32_t ID = IDs[Index];
149 StringRef S = getStringForID(ID);
150 if (S == Str)
151 return ID;
152 }
153 // IDs[0] contains the ID of the "invalid" entry.
154 return IDs[0];
155}
156
Rui Ueyamab12b1582016-05-25 04:07:17 +0000157ArrayRef<uint32_t> NameHashTable::name_ids() const { return IDs; }