blob: 2b13d96f08ec819c158b3731b35350b7d6a50eba [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 Turnerf04d6e82017-01-20 22:41:15 +000023StringTable::StringTable() : Signature(0), HashVersion(0), NameCount(0) {}
Zachary Turner0eace0b2016-05-02 18:09:14 +000024
Zachary Turner120faca2017-02-27 22:11:43 +000025Error StringTable::load(BinaryStreamReader &Stream) {
Zachary Turnerf04d6e82017-01-20 22:41:15 +000026 const StringTableHeader *H;
Zachary Turner8dbe3622016-05-27 01:54:44 +000027 if (auto EC = Stream.readObject(H))
Zachary Turner819e77d2016-05-06 20:51:57 +000028 return EC;
29
Zachary Turnerf04d6e82017-01-20 22:41:15 +000030 if (H->Signature != StringTableSignature)
Zachary Turner819e77d2016-05-06 20:51:57 +000031 return make_error<RawError>(raw_error_code::corrupt_file,
32 "Invalid hash table signature");
Zachary Turner8dbe3622016-05-27 01:54:44 +000033 if (H->HashVersion != 1 && H->HashVersion != 2)
Zachary Turner819e77d2016-05-06 20:51:57 +000034 return make_error<RawError>(raw_error_code::corrupt_file,
35 "Unsupported hash version");
Zachary Turner0eace0b2016-05-02 18:09:14 +000036
Zachary Turner8dbe3622016-05-27 01:54:44 +000037 Signature = H->Signature;
38 HashVersion = H->HashVersion;
39 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize))
David Majnemer836937e2016-05-27 16:16:56 +000040 return joinErrors(std::move(EC),
41 make_error<RawError>(raw_error_code::corrupt_file,
42 "Invalid hash table byte length"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000043
Zachary Turner8dbe3622016-05-27 01:54:44 +000044 const support::ulittle32_t *HashCount;
45 if (auto EC = Stream.readObject(HashCount))
Zachary Turner819e77d2016-05-06 20:51:57 +000046 return EC;
47
Zachary Turnerb393d952016-05-27 03:51:53 +000048 if (auto EC = Stream.readArray(IDs, *HashCount))
David Majnemer836937e2016-05-27 16:16:56 +000049 return joinErrors(std::move(EC),
50 make_error<RawError>(raw_error_code::corrupt_file,
51 "Could not read bucket array"));
Zachary Turner0eace0b2016-05-02 18:09:14 +000052
53 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t))
Zachary Turner819e77d2016-05-06 20:51:57 +000054 return make_error<RawError>(raw_error_code::corrupt_file,
55 "Missing name count");
Zachary Turner0eace0b2016-05-02 18:09:14 +000056
Zachary Turner695ed562017-02-28 00:04:07 +000057 if (auto EC = Stream.readInteger(NameCount))
Zachary Turner819e77d2016-05-06 20:51:57 +000058 return EC;
59 return Error::success();
Zachary Turner0eace0b2016-05-02 18:09:14 +000060}
61
Zachary Turnerf04d6e82017-01-20 22:41:15 +000062StringRef StringTable::getStringForID(uint32_t ID) const {
Zachary Turner0eace0b2016-05-02 18:09:14 +000063 if (ID == IDs[0])
64 return StringRef();
65
Zachary Turner8dbe3622016-05-27 01:54:44 +000066 // NamesBuffer is a buffer of null terminated strings back to back. ID is
67 // the starting offset of the string we're looking for. So just seek into
68 // the desired offset and a read a null terminated stream from that offset.
69 StringRef Result;
Zachary Turner120faca2017-02-27 22:11:43 +000070 BinaryStreamReader NameReader(NamesBuffer);
Zachary Turner8dbe3622016-05-27 01:54:44 +000071 NameReader.setOffset(ID);
Zachary Turner120faca2017-02-27 22:11:43 +000072 if (auto EC = NameReader.readCString(Result))
Zachary Turner8dbe3622016-05-27 01:54:44 +000073 consumeError(std::move(EC));
74 return Result;
Zachary Turner0eace0b2016-05-02 18:09:14 +000075}
76
Zachary Turnerf04d6e82017-01-20 22:41:15 +000077uint32_t StringTable::getIDForString(StringRef Str) const {
Rui Ueyamaf05f3602016-06-08 23:15:09 +000078 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
Zachary Turner0eace0b2016-05-02 18:09:14 +000079 size_t Count = IDs.size();
80 uint32_t Start = Hash % Count;
81 for (size_t I = 0; I < Count; ++I) {
82 // The hash is just a starting point for the search, but if it
83 // doesn't work we should find the string no matter what, because
84 // we iterate the entire array.
85 uint32_t Index = (Start + I) % Count;
86
87 uint32_t ID = IDs[Index];
88 StringRef S = getStringForID(ID);
89 if (S == Str)
90 return ID;
91 }
92 // IDs[0] contains the ID of the "invalid" entry.
93 return IDs[0];
94}
95
Zachary Turnerf04d6e82017-01-20 22:41:15 +000096FixedStreamArray<support::ulittle32_t> StringTable::name_ids() const {
Zachary Turnerb393d952016-05-27 03:51:53 +000097 return IDs;
98}