blob: ceeca10c5c52c296b534af76d1f9b00e7f266433 [file] [log] [blame]
Zachary Turnerf04d6e82017-01-20 22:41:15 +00001//===- NamedStreamMap.cpp - PDB Named Stream Map ----------------*- C++ -*-===//
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"
Zachary Turner11036a92017-01-19 23:31:24 +000011
David Majnemer36b7b082016-06-04 22:47:39 +000012#include "llvm/ADT/SparseBitVector.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000013#include "llvm/ADT/StringMap.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/iterator_range.h"
Zachary Turnerd2684b72017-02-25 00:33:34 +000016#include "llvm/DebugInfo/MSF/BinaryStreamReader.h"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000017#include "llvm/DebugInfo/PDB/Native/HashTable.h"
18#include "llvm/DebugInfo/PDB/Native/RawError.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000019#include "llvm/Support/Error.h"
20#include <algorithm>
21#include <cstdint>
Zachary Turnerf34e0162016-04-26 16:20:00 +000022
23using namespace llvm;
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000024using namespace llvm::msf;
Zachary Turner2f09b502016-04-29 17:28:47 +000025using namespace llvm::pdb;
Zachary Turnerf34e0162016-04-26 16:20:00 +000026
Zachary Turnerf04d6e82017-01-20 22:41:15 +000027NamedStreamMap::NamedStreamMap() = default;
Zachary Turnerf34e0162016-04-26 16:20:00 +000028
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000029Error NamedStreamMap::load(StreamReader &Stream) {
Zachary Turner60667ca2017-01-20 22:41:40 +000030 Mapping.clear();
31 FinalizedHashTable.clear();
32 FinalizedInfo.reset();
33
Zachary Turner11036a92017-01-19 23:31:24 +000034 uint32_t StringBufferSize;
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000035 if (auto EC = Stream.readInteger(StringBufferSize, llvm::support::little))
David Majnemer836937e2016-05-27 16:16:56 +000036 return joinErrors(std::move(EC),
37 make_error<RawError>(raw_error_code::corrupt_file,
Zachary Turner11036a92017-01-19 23:31:24 +000038 "Expected string buffer size"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000039
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000040 msf::ReadableStreamRef StringsBuffer;
Zachary Turner11036a92017-01-19 23:31:24 +000041 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
42 return EC;
Zachary Turnerf34e0162016-04-26 16:20:00 +000043
Zachary Turner11036a92017-01-19 23:31:24 +000044 HashTable OffsetIndexMap;
45 if (auto EC = OffsetIndexMap.load(Stream))
46 return EC;
Zachary Turnerf34e0162016-04-26 16:20:00 +000047
Zachary Turner11036a92017-01-19 23:31:24 +000048 uint32_t NameOffset;
49 uint32_t NameIndex;
50 for (const auto &Entry : OffsetIndexMap) {
51 std::tie(NameOffset, NameIndex) = Entry;
Zachary Turnerf34e0162016-04-26 16:20:00 +000052
53 // Compute the offset of the start of the string relative to the stream.
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000054 msf::StreamReader NameReader(StringsBuffer);
Zachary Turner11036a92017-01-19 23:31:24 +000055 NameReader.setOffset(NameOffset);
Zachary Turnerf34e0162016-04-26 16:20:00 +000056 // Pump out our c-string from the stream.
Zachary Turner8dbe3622016-05-27 01:54:44 +000057 StringRef Str;
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000058 if (auto EC = NameReader.readZeroString(Str))
David Majnemer836937e2016-05-27 16:16:56 +000059 return joinErrors(std::move(EC),
60 make_error<RawError>(raw_error_code::corrupt_file,
61 "Expected name map name"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000062
Zachary Turnerf34e0162016-04-26 16:20:00 +000063 // Add this to a string-map from name to stream number.
64 Mapping.insert({Str, NameIndex});
65 }
66
Zachary Turner819e77d2016-05-06 20:51:57 +000067 return Error::success();
Zachary Turnerf34e0162016-04-26 16:20:00 +000068}
69
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000070Error NamedStreamMap::commit(msf::StreamWriter &Writer) const {
Zachary Turner60667ca2017-01-20 22:41:40 +000071 assert(FinalizedInfo.hasValue());
72
73 // The first field is the number of bytes of string data.
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000074 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes,
75 llvm::support::little))
Zachary Turner60667ca2017-01-20 22:41:40 +000076 return EC;
77
78 // Now all of the string data itself.
79 for (const auto &Item : Mapping) {
NAKAMURA Takumi05a75e42017-02-25 17:04:23 +000080 if (auto EC = Writer.writeZeroString(Item.getKey()))
Zachary Turner60667ca2017-01-20 22:41:40 +000081 return EC;
82 }
83
84 // And finally the Offset Index map.
85 if (auto EC = FinalizedHashTable.commit(Writer))
86 return EC;
87
88 return Error::success();
89}
90
91uint32_t NamedStreamMap::finalize() {
92 if (FinalizedInfo.hasValue())
93 return FinalizedInfo->SerializedLength;
94
95 // Build the finalized hash table.
96 FinalizedHashTable.clear();
97 FinalizedInfo.emplace();
98 for (const auto &Item : Mapping) {
99 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue());
100 FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1;
101 }
102
103 // Number of bytes of string data.
104 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
105 // Followed by that many actual bytes of string data.
106 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
107 // Followed by the mapping from Offset to Index.
108 FinalizedInfo->SerializedLength +=
109 FinalizedHashTable.calculateSerializedLength();
110 return FinalizedInfo->SerializedLength;
111}
112
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000113iterator_range<StringMapConstIterator<uint32_t>>
114NamedStreamMap::entries() const {
Eugene Zelenko570e39a2016-11-23 23:16:32 +0000115 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
116 Mapping.end());
Zachary Turner85ed80b2016-05-25 03:43:17 +0000117}
118
Zachary Turner60667ca2017-01-20 22:41:40 +0000119bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
120 auto Iter = Mapping.find(Stream);
Zachary Turnerf34e0162016-04-26 16:20:00 +0000121 if (Iter == Mapping.end())
122 return false;
Zachary Turner60667ca2017-01-20 22:41:40 +0000123 StreamNo = Iter->second;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000124 return true;
125}
Zachary Turner60667ca2017-01-20 22:41:40 +0000126
127void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
128 FinalizedInfo.reset();
129 Mapping[Stream] = StreamNo;
130}
131
132void NamedStreamMap::remove(StringRef Stream) {
133 FinalizedInfo.reset();
134 Mapping.erase(Stream);
135}