1f37b6182SDimitry Andric //===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===//
2f37b6182SDimitry Andric //
3f37b6182SDimitry Andric //                     The LLVM Compiler Infrastructure
4f37b6182SDimitry Andric //
5f37b6182SDimitry Andric // This file is distributed under the University of Illinois Open Source
6f37b6182SDimitry Andric // License. See LICENSE.TXT for details.
7f37b6182SDimitry Andric //
8f37b6182SDimitry Andric //===----------------------------------------------------------------------===//
9f37b6182SDimitry Andric 
10f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
11f37b6182SDimitry Andric 
12f37b6182SDimitry Andric #include "llvm/ADT/ArrayRef.h"
13f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/Hash.h"
14f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
15f37b6182SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
16f37b6182SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
17f37b6182SDimitry Andric #include "llvm/Support/Endian.h"
18f37b6182SDimitry Andric 
19f37b6182SDimitry Andric using namespace llvm;
20f37b6182SDimitry Andric using namespace llvm::support;
21f37b6182SDimitry Andric using namespace llvm::pdb;
22f37b6182SDimitry Andric 
getByteSize() const23c4394386SDimitry Andric uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; }
getNameCount() const24f37b6182SDimitry Andric uint32_t PDBStringTable::getNameCount() const { return NameCount; }
getHashVersion() const25f37b6182SDimitry Andric uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; }
getSignature() const26f37b6182SDimitry Andric uint32_t PDBStringTable::getSignature() const { return Header->Signature; }
27f37b6182SDimitry Andric 
readHeader(BinaryStreamReader & Reader)28f37b6182SDimitry Andric Error PDBStringTable::readHeader(BinaryStreamReader &Reader) {
29f37b6182SDimitry Andric   if (auto EC = Reader.readObject(Header))
30f37b6182SDimitry Andric     return EC;
31f37b6182SDimitry Andric 
32f37b6182SDimitry Andric   if (Header->Signature != PDBStringTableSignature)
33f37b6182SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
34f37b6182SDimitry Andric                                 "Invalid hash table signature");
35f37b6182SDimitry Andric   if (Header->HashVersion != 1 && Header->HashVersion != 2)
36f37b6182SDimitry Andric     return make_error<RawError>(raw_error_code::corrupt_file,
37f37b6182SDimitry Andric                                 "Unsupported hash version");
38f37b6182SDimitry Andric 
39f37b6182SDimitry Andric   assert(Reader.bytesRemaining() == 0);
40f37b6182SDimitry Andric   return Error::success();
41f37b6182SDimitry Andric }
42f37b6182SDimitry Andric 
readStrings(BinaryStreamReader & Reader)43f37b6182SDimitry Andric Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
44f37b6182SDimitry Andric   BinaryStreamRef Stream;
45f37b6182SDimitry Andric   if (auto EC = Reader.readStreamRef(Stream))
46f37b6182SDimitry Andric     return EC;
47f37b6182SDimitry Andric 
48f37b6182SDimitry Andric   if (auto EC = Strings.initialize(Stream)) {
49f37b6182SDimitry Andric     return joinErrors(std::move(EC),
50f37b6182SDimitry Andric                       make_error<RawError>(raw_error_code::corrupt_file,
51f37b6182SDimitry Andric                                            "Invalid hash table byte length"));
52f37b6182SDimitry Andric   }
53f37b6182SDimitry Andric 
54f37b6182SDimitry Andric   assert(Reader.bytesRemaining() == 0);
55f37b6182SDimitry Andric   return Error::success();
56f37b6182SDimitry Andric }
57f37b6182SDimitry Andric 
5824d58133SDimitry Andric const codeview::DebugStringTableSubsectionRef &
getStringTable() const5924d58133SDimitry Andric PDBStringTable::getStringTable() const {
606d97bb29SDimitry Andric   return Strings;
616d97bb29SDimitry Andric }
626d97bb29SDimitry Andric 
readHashTable(BinaryStreamReader & Reader)63f37b6182SDimitry Andric Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
64f37b6182SDimitry Andric   const support::ulittle32_t *HashCount;
65f37b6182SDimitry Andric   if (auto EC = Reader.readObject(HashCount))
66f37b6182SDimitry Andric     return EC;
67f37b6182SDimitry Andric 
68f37b6182SDimitry Andric   if (auto EC = Reader.readArray(IDs, *HashCount)) {
69f37b6182SDimitry Andric     return joinErrors(std::move(EC),
70f37b6182SDimitry Andric                       make_error<RawError>(raw_error_code::corrupt_file,
71f37b6182SDimitry Andric                                            "Could not read bucket array"));
72f37b6182SDimitry Andric   }
73f37b6182SDimitry Andric 
74f37b6182SDimitry Andric   return Error::success();
75f37b6182SDimitry Andric }
76f37b6182SDimitry Andric 
readEpilogue(BinaryStreamReader & Reader)77f37b6182SDimitry Andric Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) {
78f37b6182SDimitry Andric   if (auto EC = Reader.readInteger(NameCount))
79f37b6182SDimitry Andric     return EC;
80f37b6182SDimitry Andric 
81f37b6182SDimitry Andric   assert(Reader.bytesRemaining() == 0);
82f37b6182SDimitry Andric   return Error::success();
83f37b6182SDimitry Andric }
84f37b6182SDimitry Andric 
reload(BinaryStreamReader & Reader)85f37b6182SDimitry Andric Error PDBStringTable::reload(BinaryStreamReader &Reader) {
86f37b6182SDimitry Andric 
87f37b6182SDimitry Andric   BinaryStreamReader SectionReader;
88f37b6182SDimitry Andric 
89f37b6182SDimitry Andric   std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader));
90f37b6182SDimitry Andric   if (auto EC = readHeader(SectionReader))
91f37b6182SDimitry Andric     return EC;
92f37b6182SDimitry Andric 
93f37b6182SDimitry Andric   std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize);
94f37b6182SDimitry Andric   if (auto EC = readStrings(SectionReader))
95f37b6182SDimitry Andric     return EC;
96f37b6182SDimitry Andric 
97f37b6182SDimitry Andric   // We don't know how long the hash table is until we parse it, so let the
98f37b6182SDimitry Andric   // function responsible for doing that figure it out.
99f37b6182SDimitry Andric   if (auto EC = readHashTable(Reader))
100f37b6182SDimitry Andric     return EC;
101f37b6182SDimitry Andric 
102f37b6182SDimitry Andric   std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t));
103f37b6182SDimitry Andric   if (auto EC = readEpilogue(SectionReader))
104f37b6182SDimitry Andric     return EC;
105f37b6182SDimitry Andric 
106f37b6182SDimitry Andric   assert(Reader.bytesRemaining() == 0);
107f37b6182SDimitry Andric   return Error::success();
108f37b6182SDimitry Andric }
109f37b6182SDimitry Andric 
getStringForID(uint32_t ID) const110f37b6182SDimitry Andric Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const {
111f37b6182SDimitry Andric   return Strings.getString(ID);
112f37b6182SDimitry Andric }
113f37b6182SDimitry Andric 
getIDForString(StringRef Str) const114f37b6182SDimitry Andric Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const {
115f37b6182SDimitry Andric   uint32_t Hash =
116f37b6182SDimitry Andric       (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
117f37b6182SDimitry Andric   size_t Count = IDs.size();
118f37b6182SDimitry Andric   uint32_t Start = Hash % Count;
119f37b6182SDimitry Andric   for (size_t I = 0; I < Count; ++I) {
120f37b6182SDimitry Andric     // The hash is just a starting point for the search, but if it
121f37b6182SDimitry Andric     // doesn't work we should find the string no matter what, because
122f37b6182SDimitry Andric     // we iterate the entire array.
123f37b6182SDimitry Andric     uint32_t Index = (Start + I) % Count;
124f37b6182SDimitry Andric 
125*4ba319b5SDimitry Andric     // If we find 0, it means the item isn't in the hash table.
126f37b6182SDimitry Andric     uint32_t ID = IDs[Index];
127*4ba319b5SDimitry Andric     if (ID == 0)
128*4ba319b5SDimitry Andric       return make_error<RawError>(raw_error_code::no_entry);
129f37b6182SDimitry Andric     auto ExpectedStr = getStringForID(ID);
130f37b6182SDimitry Andric     if (!ExpectedStr)
131f37b6182SDimitry Andric       return ExpectedStr.takeError();
132f37b6182SDimitry Andric 
133f37b6182SDimitry Andric     if (*ExpectedStr == Str)
134f37b6182SDimitry Andric       return ID;
135f37b6182SDimitry Andric   }
136f37b6182SDimitry Andric   return make_error<RawError>(raw_error_code::no_entry);
137f37b6182SDimitry Andric }
138f37b6182SDimitry Andric 
name_ids() const139f37b6182SDimitry Andric FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
140f37b6182SDimitry Andric   return IDs;
141f37b6182SDimitry Andric }
142