1317760Sdim//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===//
2317760Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317760Sdim//
7317760Sdim//===----------------------------------------------------------------------===//
8317760Sdim
9317760Sdim#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
10317760Sdim
11317760Sdim#include "llvm/ADT/ArrayRef.h"
12317760Sdim#include "llvm/DebugInfo/PDB/Native/Hash.h"
13317760Sdim#include "llvm/DebugInfo/PDB/Native/RawError.h"
14317760Sdim#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
15317760Sdim#include "llvm/Support/BinaryStreamReader.h"
16317760Sdim#include "llvm/Support/Endian.h"
17317760Sdim
18317760Sdimusing namespace llvm;
19317760Sdimusing namespace llvm::support;
20317760Sdimusing namespace llvm::pdb;
21317760Sdim
22320970Sdimuint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; }
23317760Sdimuint32_t PDBStringTable::getNameCount() const { return NameCount; }
24317760Sdimuint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; }
25317760Sdimuint32_t PDBStringTable::getSignature() const { return Header->Signature; }
26317760Sdim
27317760SdimError PDBStringTable::readHeader(BinaryStreamReader &Reader) {
28317760Sdim  if (auto EC = Reader.readObject(Header))
29317760Sdim    return EC;
30317760Sdim
31317760Sdim  if (Header->Signature != PDBStringTableSignature)
32317760Sdim    return make_error<RawError>(raw_error_code::corrupt_file,
33317760Sdim                                "Invalid hash table signature");
34317760Sdim  if (Header->HashVersion != 1 && Header->HashVersion != 2)
35317760Sdim    return make_error<RawError>(raw_error_code::corrupt_file,
36317760Sdim                                "Unsupported hash version");
37317760Sdim
38317760Sdim  assert(Reader.bytesRemaining() == 0);
39317760Sdim  return Error::success();
40317760Sdim}
41317760Sdim
42317760SdimError PDBStringTable::readStrings(BinaryStreamReader &Reader) {
43317760Sdim  BinaryStreamRef Stream;
44317760Sdim  if (auto EC = Reader.readStreamRef(Stream))
45317760Sdim    return EC;
46317760Sdim
47317760Sdim  if (auto EC = Strings.initialize(Stream)) {
48317760Sdim    return joinErrors(std::move(EC),
49317760Sdim                      make_error<RawError>(raw_error_code::corrupt_file,
50317760Sdim                                           "Invalid hash table byte length"));
51317760Sdim  }
52317760Sdim
53317760Sdim  assert(Reader.bytesRemaining() == 0);
54317760Sdim  return Error::success();
55317760Sdim}
56317760Sdim
57320041Sdimconst codeview::DebugStringTableSubsectionRef &
58320041SdimPDBStringTable::getStringTable() const {
59319547Sdim  return Strings;
60319547Sdim}
61319547Sdim
62317760SdimError PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
63317760Sdim  const support::ulittle32_t *HashCount;
64317760Sdim  if (auto EC = Reader.readObject(HashCount))
65317760Sdim    return EC;
66317760Sdim
67317760Sdim  if (auto EC = Reader.readArray(IDs, *HashCount)) {
68317760Sdim    return joinErrors(std::move(EC),
69317760Sdim                      make_error<RawError>(raw_error_code::corrupt_file,
70317760Sdim                                           "Could not read bucket array"));
71317760Sdim  }
72317760Sdim
73317760Sdim  return Error::success();
74317760Sdim}
75317760Sdim
76317760SdimError PDBStringTable::readEpilogue(BinaryStreamReader &Reader) {
77317760Sdim  if (auto EC = Reader.readInteger(NameCount))
78317760Sdim    return EC;
79317760Sdim
80317760Sdim  assert(Reader.bytesRemaining() == 0);
81317760Sdim  return Error::success();
82317760Sdim}
83317760Sdim
84317760SdimError PDBStringTable::reload(BinaryStreamReader &Reader) {
85317760Sdim
86317760Sdim  BinaryStreamReader SectionReader;
87317760Sdim
88317760Sdim  std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader));
89317760Sdim  if (auto EC = readHeader(SectionReader))
90317760Sdim    return EC;
91317760Sdim
92317760Sdim  std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize);
93317760Sdim  if (auto EC = readStrings(SectionReader))
94317760Sdim    return EC;
95317760Sdim
96317760Sdim  // We don't know how long the hash table is until we parse it, so let the
97317760Sdim  // function responsible for doing that figure it out.
98317760Sdim  if (auto EC = readHashTable(Reader))
99317760Sdim    return EC;
100317760Sdim
101317760Sdim  std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t));
102317760Sdim  if (auto EC = readEpilogue(SectionReader))
103317760Sdim    return EC;
104317760Sdim
105317760Sdim  assert(Reader.bytesRemaining() == 0);
106317760Sdim  return Error::success();
107317760Sdim}
108317760Sdim
109317760SdimExpected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const {
110317760Sdim  return Strings.getString(ID);
111317760Sdim}
112317760Sdim
113317760SdimExpected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const {
114317760Sdim  uint32_t Hash =
115317760Sdim      (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
116317760Sdim  size_t Count = IDs.size();
117317760Sdim  uint32_t Start = Hash % Count;
118317760Sdim  for (size_t I = 0; I < Count; ++I) {
119317760Sdim    // The hash is just a starting point for the search, but if it
120317760Sdim    // doesn't work we should find the string no matter what, because
121317760Sdim    // we iterate the entire array.
122317760Sdim    uint32_t Index = (Start + I) % Count;
123317760Sdim
124341825Sdim    // If we find 0, it means the item isn't in the hash table.
125317760Sdim    uint32_t ID = IDs[Index];
126341825Sdim    if (ID == 0)
127341825Sdim      return make_error<RawError>(raw_error_code::no_entry);
128317760Sdim    auto ExpectedStr = getStringForID(ID);
129317760Sdim    if (!ExpectedStr)
130317760Sdim      return ExpectedStr.takeError();
131317760Sdim
132317760Sdim    if (*ExpectedStr == Str)
133317760Sdim      return ID;
134317760Sdim  }
135317760Sdim  return make_error<RawError>(raw_error_code::no_entry);
136317760Sdim}
137317760Sdim
138317760SdimFixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
139317760Sdim  return IDs;
140317760Sdim}
141