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