blob: 983b6ebf36afcdcfebf07b97695b8be61dbbf1db [file] [log] [blame]
Eugene Zelenko4fcfc192017-06-30 23:06:03 +00001//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
Zachary Turnerf34e0162016-04-26 16:20:00 +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/NamedStreamMap.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000011#include "llvm/ADT/StringMap.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/iterator_range.h"
Zachary Turnercafd4762018-02-16 20:46:04 +000014#include "llvm/DebugInfo/PDB/Native/Hash.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000015#include "llvm/DebugInfo/PDB/Native/HashTable.h"
16#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turnerd9dc2822017-03-02 20:52:51 +000017#include "llvm/Support/BinaryStreamReader.h"
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000018#include "llvm/Support/BinaryStreamRef.h"
19#include "llvm/Support/BinaryStreamWriter.h"
20#include "llvm/Support/Endian.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000021#include "llvm/Support/Error.h"
22#include <algorithm>
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000023#include <cassert>
Eugene Zelenko570e39a2016-11-23 23:16:32 +000024#include <cstdint>
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000025#include <tuple>
Zachary Turnerf34e0162016-04-26 16:20:00 +000026
27using namespace llvm;
Zachary Turner2f09b502016-04-29 17:28:47 +000028using namespace llvm::pdb;
Zachary Turnerf34e0162016-04-26 16:20:00 +000029
Zachary Turnercafd4762018-02-16 20:46:04 +000030namespace {
31struct NamedStreamMapTraits {
32 static uint16_t hash(StringRef S, const NamedStreamMap &NS) {
33 // In the reference implementation, this uses
34 // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod).
35 // Here, the type HASH is a typedef of unsigned short.
36 // ** It is not a bug that we truncate the result of hashStringV1, in fact
37 // it is a bug if we do not! **
38 return static_cast<uint16_t>(hashStringV1(S));
39 }
40 static StringRef realKey(uint32_t Offset, const NamedStreamMap &NS) {
41 return NS.getString(Offset);
42 }
43 static uint32_t lowerKey(StringRef S, NamedStreamMap &NS) {
44 return NS.appendStringData(S);
45 }
46};
47} // namespace
Zachary Turner1affd802017-06-25 03:51:42 +000048
Zachary Turnercafd4762018-02-16 20:46:04 +000049NamedStreamMap::NamedStreamMap() {}
Zachary Turnerf34e0162016-04-26 16:20:00 +000050
Zachary Turner120faca2017-02-27 22:11:43 +000051Error NamedStreamMap::load(BinaryStreamReader &Stream) {
Zachary Turner11036a92017-01-19 23:31:24 +000052 uint32_t StringBufferSize;
Zachary Turner695ed562017-02-28 00:04:07 +000053 if (auto EC = Stream.readInteger(StringBufferSize))
David Majnemer836937e2016-05-27 16:16:56 +000054 return joinErrors(std::move(EC),
55 make_error<RawError>(raw_error_code::corrupt_file,
Zachary Turner11036a92017-01-19 23:31:24 +000056 "Expected string buffer size"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000057
Zachary Turnercafd4762018-02-16 20:46:04 +000058 StringRef Buffer;
59 if (auto EC = Stream.readFixedString(Buffer, StringBufferSize))
Zachary Turner11036a92017-01-19 23:31:24 +000060 return EC;
Zachary Turnercafd4762018-02-16 20:46:04 +000061 NamesBuffer.assign(Buffer.begin(), Buffer.end());
Zachary Turnerf34e0162016-04-26 16:20:00 +000062
Zachary Turnercafd4762018-02-16 20:46:04 +000063 return OffsetIndexMap.load(Stream);
Zachary Turnerf34e0162016-04-26 16:20:00 +000064}
65
Zachary Turner120faca2017-02-27 22:11:43 +000066Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
Zachary Turner60667ca2017-01-20 22:41:40 +000067 // The first field is the number of bytes of string data.
Zachary Turnercafd4762018-02-16 20:46:04 +000068 if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size()))
Zachary Turner60667ca2017-01-20 22:41:40 +000069 return EC;
70
Zachary Turnercafd4762018-02-16 20:46:04 +000071 // Then the actual string data.
72 StringRef Data(NamesBuffer.data(), NamesBuffer.size());
73 if (auto EC = Writer.writeFixedString(Data))
74 return EC;
Zachary Turner60667ca2017-01-20 22:41:40 +000075
76 // And finally the Offset Index map.
Zachary Turnercafd4762018-02-16 20:46:04 +000077 if (auto EC = OffsetIndexMap.commit(Writer))
Zachary Turner60667ca2017-01-20 22:41:40 +000078 return EC;
79
80 return Error::success();
81}
82
Zachary Turnercafd4762018-02-16 20:46:04 +000083uint32_t NamedStreamMap::calculateSerializedLength() const {
84 return sizeof(uint32_t) // String data size
85 + NamesBuffer.size() // String data
86 + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map
Zachary Turner60667ca2017-01-20 22:41:40 +000087}
88
Zachary Turnercafd4762018-02-16 20:46:04 +000089uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); }
90
91StringRef NamedStreamMap::getString(uint32_t Offset) const {
92 assert(NamesBuffer.size() > Offset);
93 return StringRef(NamesBuffer.data() + Offset);
Zachary Turner85ed80b2016-05-25 03:43:17 +000094}
95
Zachary Turnercafd4762018-02-16 20:46:04 +000096uint32_t NamedStreamMap::hashString(uint32_t Offset) const {
97 return hashStringV1(getString(Offset));
98}
Zachary Turner02278ce2017-03-16 20:18:41 +000099
Zachary Turner60667ca2017-01-20 22:41:40 +0000100bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
Zachary Turnercafd4762018-02-16 20:46:04 +0000101 auto Iter = OffsetIndexMap.find_as<NamedStreamMapTraits>(Stream, *this);
102 if (Iter == OffsetIndexMap.end())
Zachary Turnerf34e0162016-04-26 16:20:00 +0000103 return false;
Zachary Turnercafd4762018-02-16 20:46:04 +0000104 StreamNo = (*Iter).second;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000105 return true;
106}
Zachary Turner60667ca2017-01-20 22:41:40 +0000107
Zachary Turnercafd4762018-02-16 20:46:04 +0000108StringMap<uint32_t> NamedStreamMap::entries() const {
109 StringMap<uint32_t> Result;
110 for (const auto &Entry : OffsetIndexMap) {
111 StringRef Stream(NamesBuffer.data() + Entry.first);
112 Result.try_emplace(Stream, Entry.second);
113 }
114 return Result;
Zachary Turner60667ca2017-01-20 22:41:40 +0000115}
116
Zachary Turnercafd4762018-02-16 20:46:04 +0000117uint32_t NamedStreamMap::appendStringData(StringRef S) {
118 uint32_t Offset = NamesBuffer.size();
119 NamesBuffer.insert(NamesBuffer.end(), S.begin(), S.end());
120 NamesBuffer.push_back('\0');
121 return Offset;
122}
123
124void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
125 OffsetIndexMap.set_as<NamedStreamMapTraits>(Stream, StreamNo, *this);
Zachary Turner60667ca2017-01-20 22:41:40 +0000126}