blob: 7e28389b838313f5a3a22dc1c309b0a9d401e8d4 [file] [log] [blame]
Zachary Turnerf04d6e82017-01-20 22:41:15 +00001//===- StringTable.cpp - PDB String Table -----------------------*- C++ -*-===//
Zachary Turner0eace0b2016-05-02 18:09:14 +00002//
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
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000010#include "llvm/DebugInfo/PDB/Native/StringTable.h"
Zachary Turner0eace0b2016-05-02 18:09:14 +000011
12#include "llvm/ADT/ArrayRef.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000013#include "llvm/DebugInfo/PDB/Native/Hash.h"
14#include "llvm/DebugInfo/PDB/Native/RawError.h"
15#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
Zachary Turnerd9dc2822017-03-02 20:52:51 +000016#include "llvm/Support/BinaryStreamReader.h"
Zachary Turner0eace0b2016-05-02 18:09:14 +000017#include "llvm/Support/Endian.h"
18
19using namespace llvm;
20using namespace llvm::support;
21using namespace llvm::pdb;
22
Zachary Turnerf1220082017-03-15 22:19:30 +000023StringTable::StringTable() {}
Zachary Turner0eace0b2016-05-02 18:09:14 +000024
Zachary Turner120faca2017-02-27 22:11:43 +000025Error StringTable::load(BinaryStreamReader &Stream) {
Zachary Turnerf1220082017-03-15 22:19:30 +000026 ByteSize = Stream.getLength();
27
Zachary Turnerf04d6e82017-01-20 22:41:15 +000028 const StringTableHeader *H;
Zachary Turner8dbe3622016-05-27 01:54:44 +000029 if (auto EC = Stream.readObject(H))
Zachary Turner819e77d2016-05-06 20:51:57 +000030 return EC;
31
Zachary Turnerf04d6e82017-01-20 22:41:15 +000032 if (H->Signature != StringTableSignature)
Zachary Turner819e77d2016-05-06 20:51:57 +000033 return make_error<RawError>(raw_error_code::corrupt_file,
34 "Invalid hash table signature");
Zachary Turner8dbe3622016-05-27 01:54:44 +000035 if (H->HashVersion != 1 && H->HashVersion != 2)
Zachary Turner819e77d2016-05-06 20:51:57 +000036 return make_error<RawError>(raw_error_code::corrupt_file,
37 "Unsupported hash version");
Zachary Turner0eace0b2016-05-02 18:09:14 +000038
Zachary Turner8dbe3622016-05-27 01:54:44 +000039 Signature = H->Signature;
40 HashVersion = H->HashVersion;
41 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
David Majnemer836937e2016-05-27 16:16:56 +000042 return joinErrors(std::move(EC),
43 make_error<RawError>(raw_error_code::corrupt_file,
44 "Invalid hash table byte length"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000045
Zachary Turner8dbe3622016-05-27 01:54:44 +000046 const support::ulittle32_t *HashCount;
47 if (auto EC = Stream.readObject(HashCount))
Zachary Turner819e77d2016-05-06 20:51:57 +000048 return EC;
49
Zachary Turnerb393d952016-05-27 03:51:53 +000050 if (auto EC = Stream.readArray(IDs, *HashCount))
David Majnemer836937e2016-05-27 16:16:56 +000051 return joinErrors(std::move(EC),
52 make_error<RawError>(raw_error_code::corrupt_file,
53 "Could not read bucket array"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000054
55 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
Zachary Turner819e77d2016-05-06 20:51:57 +000056 return make_error<RawError>(raw_error_code::corrupt_file,
57 "Missing name count");
Zachary Turner0eace0b2016-05-02 18:09:14 +000058
Zachary Turner695ed562017-02-28 00:04:07 +000059 if (auto EC = Stream.readInteger(NameCount))
Zachary Turner819e77d2016-05-06 20:51:57 +000060 return EC;
Zachary Turnerf1220082017-03-15 22:19:30 +000061
62 if (Stream.bytesRemaining() > 0)
63 return make_error<RawError>(raw_error_code::stream_too_long,
64 "Unexpected bytes found in string table");
65
Zachary Turner819e77d2016-05-06 20:51:57 +000066 return Error::success();
Zachary Turner0eace0b2016-05-02 18:09:14 +000067}
68
Zachary Turnerf1220082017-03-15 22:19:30 +000069uint32_t StringTable::getByteSize() const {
70 return ByteSize;
71}
72
Zachary Turnerf04d6e82017-01-20 22:41:15 +000073StringRef StringTable::getStringForID(uint32_t ID) const {
Zachary Turner0eace0b2016-05-02 18:09:14 +000074 if (ID == IDs[0])
75 return StringRef();
76
Zachary Turner8dbe3622016-05-27 01:54:44 +000077 // 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 StringRef Result;
Zachary Turner120faca2017-02-27 22:11:43 +000081 BinaryStreamReader NameReader(NamesBuffer);
Zachary Turner8dbe3622016-05-27 01:54:44 +000082 NameReader.setOffset(ID);
Zachary Turner120faca2017-02-27 22:11:43 +000083 if (auto EC = NameReader.readCString(Result))
Zachary Turner8dbe3622016-05-27 01:54:44 +000084 consumeError(std::move(EC));
85 return Result;
Zachary Turner0eace0b2016-05-02 18:09:14 +000086}
87
Zachary Turnerf04d6e82017-01-20 22:41:15 +000088uint32_t StringTable::getIDForString(StringRef Str) const {
Rui Ueyamaf05f3602016-06-08 23:15:09 +000089 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
Zachary Turner0eace0b2016-05-02 18:09:14 +000090 size_t Count = IDs.size();
91 uint32_t Start = Hash % Count;
92 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 uint32_t Index = (Start + I) % Count;
97
98 uint32_t ID = IDs[Index];
99 StringRef S = getStringForID(ID);
100 if (S == Str)
101 return ID;
102 }
103 // IDs[0] contains the ID of the "invalid" entry.
104 return IDs[0];
105}
106
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000107FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const {
Zachary Turnerb393d952016-05-27 03:51:53 +0000108 return IDs;
109}