blob: ed78cb42da683d55afbeb7a2a083aaecec52c944 [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
Zachary Turnerf04d6e82017-01-20 22:41:15 +000010#include "llvm/DebugInfo/PDB/Raw/StringTable.h"
Zachary Turner0eace0b2016-05-02 18:09:14 +000011
12#include "llvm/ADT/ArrayRef.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000013#include "llvm/DebugInfo/MSF/StreamReader.h"
Rui Ueyama170988f2016-06-08 23:11:14 +000014#include "llvm/DebugInfo/PDB/Raw/Hash.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000015#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Rui Ueyamadcd32932017-01-15 00:36:02 +000016#include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
Zachary Turner0eace0b2016-05-02 18:09:14 +000017#include "llvm/Support/Endian.h"
18
19using namespace llvm;
Zachary Turnerbac69d32016-07-22 19:56:05 +000020using namespace llvm::msf;
Zachary Turner0eace0b2016-05-02 18:09:14 +000021using namespace llvm::support;
22using namespace llvm::pdb;
23
Zachary Turnerf04d6e82017-01-20 22:41:15 +000024StringTable::StringTable() : Signature(0), HashVersion(0), NameCount(0) {}
Zachary Turner0eace0b2016-05-02 18:09:14 +000025
Zachary Turnerf04d6e82017-01-20 22:41:15 +000026Error StringTable::load(StreamReader &Stream) {
27 const StringTableHeader *H;
Zachary Turner8dbe3622016-05-27 01:54:44 +000028 if (auto EC = Stream.readObject(H))
Zachary Turner819e77d2016-05-06 20:51:57 +000029 return EC;
30
Zachary Turnerf04d6e82017-01-20 22:41:15 +000031 if (H->Signature != StringTableSignature)
Zachary Turner819e77d2016-05-06 20:51:57 +000032 return make_error<RawError>(raw_error_code::corrupt_file,
33 "Invalid hash table signature");
Zachary Turner8dbe3622016-05-27 01:54:44 +000034 if (H->HashVersion != 1 && H->HashVersion != 2)
Zachary Turner819e77d2016-05-06 20:51:57 +000035 return make_error<RawError>(raw_error_code::corrupt_file,
36 "Unsupported hash version");
Zachary Turner0eace0b2016-05-02 18:09:14 +000037
Zachary Turner8dbe3622016-05-27 01:54:44 +000038 Signature = H->Signature;
39 HashVersion = H->HashVersion;
40 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
David Majnemer836937e2016-05-27 16:16:56 +000041 return joinErrors(std::move(EC),
42 make_error<RawError>(raw_error_code::corrupt_file,
43 "Invalid hash table byte length"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000044
Zachary Turner8dbe3622016-05-27 01:54:44 +000045 const support::ulittle32_t *HashCount;
46 if (auto EC = Stream.readObject(HashCount))
Zachary Turner819e77d2016-05-06 20:51:57 +000047 return EC;
48
Zachary Turnerb393d952016-05-27 03:51:53 +000049 if (auto EC = Stream.readArray(IDs, *HashCount))
David Majnemer836937e2016-05-27 16:16:56 +000050 return joinErrors(std::move(EC),
51 make_error<RawError>(raw_error_code::corrupt_file,
52 "Could not read bucket array"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000053
54 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
Zachary Turner819e77d2016-05-06 20:51:57 +000055 return make_error<RawError>(raw_error_code::corrupt_file,
56 "Missing name count");
Zachary Turner0eace0b2016-05-02 18:09:14 +000057
Zachary Turner819e77d2016-05-06 20:51:57 +000058 if (auto EC = Stream.readInteger(NameCount))
59 return EC;
60 return Error::success();
Zachary Turner0eace0b2016-05-02 18:09:14 +000061}
62
Zachary Turnerf04d6e82017-01-20 22:41:15 +000063StringRef StringTable::getStringForID(uint32_t ID) const {
Zachary Turner0eace0b2016-05-02 18:09:14 +000064 if (ID == IDs[0])
65 return StringRef();
66
Zachary Turner8dbe3622016-05-27 01:54:44 +000067 // NamesBuffer is a buffer of null terminated strings back to back. ID is
68 // the starting offset of the string we're looking for. So just seek into
69 // the desired offset and a read a null terminated stream from that offset.
70 StringRef Result;
Zachary Turnerbac69d32016-07-22 19:56:05 +000071 StreamReader NameReader(NamesBuffer);
Zachary Turner8dbe3622016-05-27 01:54:44 +000072 NameReader.setOffset(ID);
73 if (auto EC = NameReader.readZeroString(Result))
74 consumeError(std::move(EC));
75 return Result;
Zachary Turner0eace0b2016-05-02 18:09:14 +000076}
77
Zachary Turnerf04d6e82017-01-20 22:41:15 +000078uint32_t StringTable::getIDForString(StringRef Str) const {
Rui Ueyamaf05f3602016-06-08 23:15:09 +000079 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
Zachary Turner0eace0b2016-05-02 18:09:14 +000080 size_t Count = IDs.size();
81 uint32_t Start = Hash % Count;
82 for (size_t I = 0; I < Count; ++I) {
83 // The hash is just a starting point for the search, but if it
84 // doesn't work we should find the string no matter what, because
85 // we iterate the entire array.
86 uint32_t Index = (Start + I) % Count;
87
88 uint32_t ID = IDs[Index];
89 StringRef S = getStringForID(ID);
90 if (S == Str)
91 return ID;
92 }
93 // IDs[0] contains the ID of the "invalid" entry.
94 return IDs[0];
95}
96
Zachary Turnerf04d6e82017-01-20 22:41:15 +000097FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const {
Zachary Turnerb393d952016-05-27 03:51:53 +000098 return IDs;
99}