Line data Source code
1 : //===- StringTable.cpp - PDB String 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/Native/StringTable.h"
11 :
12 : #include "llvm/ADT/ArrayRef.h"
13 : #include "llvm/DebugInfo/PDB/Native/Hash.h"
14 : #include "llvm/DebugInfo/PDB/Native/RawError.h"
15 : #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
16 : #include "llvm/Support/BinaryStreamReader.h"
17 : #include "llvm/Support/Endian.h"
18 :
19 : using namespace llvm;
20 : using namespace llvm::support;
21 : using namespace llvm::pdb;
22 :
23 72 : StringTable::StringTable() {}
24 :
25 20 : Error StringTable::load(BinaryStreamReader &Stream) {
26 20 : ByteSize = Stream.getLength();
27 :
28 : const StringTableHeader *H;
29 60 : if (auto EC = Stream.readObject(H))
30 0 : return EC;
31 :
32 40 : if (H->Signature != StringTableSignature)
33 : return make_error<RawError>(raw_error_code::corrupt_file,
34 0 : "Invalid hash table signature");
35 40 : if (H->HashVersion != 1 && H->HashVersion != 2)
36 : return make_error<RawError>(raw_error_code::corrupt_file,
37 0 : "Unsupported hash version");
38 :
39 40 : Signature = H->Signature;
40 40 : HashVersion = H->HashVersion;
41 80 : if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
42 0 : return joinErrors(std::move(EC),
43 0 : make_error<RawError>(raw_error_code::corrupt_file,
44 0 : "Invalid hash table byte length"));
45 :
46 : const support::ulittle32_t *HashCount;
47 60 : if (auto EC = Stream.readObject(HashCount))
48 0 : return EC;
49 :
50 80 : if (auto EC = Stream.readArray(IDs, *HashCount))
51 0 : return joinErrors(std::move(EC),
52 0 : make_error<RawError>(raw_error_code::corrupt_file,
53 0 : "Could not read bucket array"));
54 :
55 20 : if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
56 : return make_error<RawError>(raw_error_code::corrupt_file,
57 0 : "Missing name count");
58 :
59 60 : if (auto EC = Stream.readInteger(NameCount))
60 0 : return EC;
61 :
62 20 : if (Stream.bytesRemaining() > 0)
63 : return make_error<RawError>(raw_error_code::stream_too_long,
64 0 : "Unexpected bytes found in string table");
65 :
66 60 : return Error::success();
67 : }
68 :
69 0 : uint32_t StringTable::getByteSize() const {
70 0 : return ByteSize;
71 : }
72 :
73 60 : StringRef StringTable::getStringForID(uint32_t ID) const {
74 120 : if (ID == IDs[0])
75 20 : return StringRef();
76 :
77 : // NamesBuffer is a buffer of null terminated strings back to back. ID is
78 : // the starting offset of the string we're looking for. So just seek into
79 : // the desired offset and a read a null terminated stream from that offset.
80 40 : StringRef Result;
81 40 : BinaryStreamReader NameReader(NamesBuffer);
82 80 : NameReader.setOffset(ID);
83 120 : if (auto EC = NameReader.readCString(Result))
84 0 : consumeError(std::move(EC));
85 40 : return Result;
86 : }
87 :
88 3 : uint32_t StringTable::getIDForString(StringRef Str) const {
89 3 : uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
90 6 : size_t Count = IDs.size();
91 3 : uint32_t Start = Hash % Count;
92 4 : for (size_t I = 0; I < Count; ++I) {
93 : // The hash is just a starting point for the search, but if it
94 : // doesn't work we should find the string no matter what, because
95 : // we iterate the entire array.
96 4 : uint32_t Index = (Start + I) % Count;
97 :
98 8 : uint32_t ID = IDs[Index];
99 4 : StringRef S = getStringForID(ID);
100 4 : if (S == Str)
101 3 : return ID;
102 : }
103 : // IDs[0] contains the ID of the "invalid" entry.
104 0 : return IDs[0];
105 : }
106 :
107 7 : FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const {
108 7 : return IDs;
109 : }
|