blob: 6cdf6dde04d9f4e0cb609218ed3c84c1c6c44554 [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"
Adrian McCarthy6b6b8c42017-01-25 22:38:55 +000014#include "llvm/DebugInfo/PDB/Native/HashTable.h"
15#include "llvm/DebugInfo/PDB/Native/RawError.h"
Zachary Turnerd9dc2822017-03-02 20:52:51 +000016#include "llvm/Support/BinaryStreamReader.h"
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000017#include "llvm/Support/BinaryStreamRef.h"
18#include "llvm/Support/BinaryStreamWriter.h"
19#include "llvm/Support/Endian.h"
Eugene Zelenko570e39a2016-11-23 23:16:32 +000020#include "llvm/Support/Error.h"
21#include <algorithm>
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000022#include <cassert>
Eugene Zelenko570e39a2016-11-23 23:16:32 +000023#include <cstdint>
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000024#include <tuple>
Zachary Turnerf34e0162016-04-26 16:20:00 +000025
26using namespace llvm;
Zachary Turner2f09b502016-04-29 17:28:47 +000027using namespace llvm::pdb;
Zachary Turnerf34e0162016-04-26 16:20:00 +000028
Zachary Turner1affd802017-06-25 03:51:42 +000029// FIXME: This shouldn't be necessary, but if we insert the strings in any
30// other order, cvdump cannot read the generated name map. This suggests that
31// we may be using the wrong hash function. A closer inspection of the cvdump
32// source code may reveal something, but for now this at least makes us work,
33// even if only by accident.
34static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names",
35 "/src/headerblock"};
36
Zachary Turnerf04d6e82017-01-20 22:41:15 +000037NamedStreamMap::NamedStreamMap() = default;
Zachary Turnerf34e0162016-04-26 16:20:00 +000038
Zachary Turner120faca2017-02-27 22:11:43 +000039Error NamedStreamMap::load(BinaryStreamReader &Stream) {
Zachary Turner60667ca2017-01-20 22:41:40 +000040 Mapping.clear();
41 FinalizedHashTable.clear();
42 FinalizedInfo.reset();
43
Zachary Turner11036a92017-01-19 23:31:24 +000044 uint32_t StringBufferSize;
Zachary Turner695ed562017-02-28 00:04:07 +000045 if (auto EC = Stream.readInteger(StringBufferSize))
David Majnemer836937e2016-05-27 16:16:56 +000046 return joinErrors(std::move(EC),
47 make_error<RawError>(raw_error_code::corrupt_file,
Zachary Turner11036a92017-01-19 23:31:24 +000048 "Expected string buffer size"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000049
Zachary Turner120faca2017-02-27 22:11:43 +000050 BinaryStreamRef StringsBuffer;
Zachary Turner11036a92017-01-19 23:31:24 +000051 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
52 return EC;
Zachary Turnerf34e0162016-04-26 16:20:00 +000053
Zachary Turner11036a92017-01-19 23:31:24 +000054 HashTable OffsetIndexMap;
55 if (auto EC = OffsetIndexMap.load(Stream))
56 return EC;
Zachary Turnerf34e0162016-04-26 16:20:00 +000057
Zachary Turner11036a92017-01-19 23:31:24 +000058 uint32_t NameOffset;
59 uint32_t NameIndex;
60 for (const auto &Entry : OffsetIndexMap) {
61 std::tie(NameOffset, NameIndex) = Entry;
Zachary Turnerf34e0162016-04-26 16:20:00 +000062
63 // Compute the offset of the start of the string relative to the stream.
Zachary Turner120faca2017-02-27 22:11:43 +000064 BinaryStreamReader NameReader(StringsBuffer);
Zachary Turner11036a92017-01-19 23:31:24 +000065 NameReader.setOffset(NameOffset);
Zachary Turnerf34e0162016-04-26 16:20:00 +000066 // Pump out our c-string from the stream.
Zachary Turner8dbe3622016-05-27 01:54:44 +000067 StringRef Str;
Zachary Turner120faca2017-02-27 22:11:43 +000068 if (auto EC = NameReader.readCString(Str))
David Majnemer836937e2016-05-27 16:16:56 +000069 return joinErrors(std::move(EC),
70 make_error<RawError>(raw_error_code::corrupt_file,
71 "Expected name map name"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000072
Zachary Turnerf34e0162016-04-26 16:20:00 +000073 // Add this to a string-map from name to stream number.
74 Mapping.insert({Str, NameIndex});
75 }
76
Zachary Turner819e77d2016-05-06 20:51:57 +000077 return Error::success();
Zachary Turnerf34e0162016-04-26 16:20:00 +000078}
79
Zachary Turner120faca2017-02-27 22:11:43 +000080Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
Zachary Turner60667ca2017-01-20 22:41:40 +000081 assert(FinalizedInfo.hasValue());
82
83 // The first field is the number of bytes of string data.
Zachary Turner695ed562017-02-28 00:04:07 +000084 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
Zachary Turner60667ca2017-01-20 22:41:40 +000085 return EC;
86
Zachary Turner1affd802017-06-25 03:51:42 +000087 for (const auto &Name : OrderedStreamNames) {
88 auto Item = Mapping.find(Name);
Zachary Turner3a11fdf2017-07-07 20:25:39 +000089 if (Item == Mapping.end())
90 continue;
Zachary Turner1affd802017-06-25 03:51:42 +000091 if (auto EC = Writer.writeCString(Item->getKey()))
Zachary Turner60667ca2017-01-20 22:41:40 +000092 return EC;
93 }
94
95 // And finally the Offset Index map.
96 if (auto EC = FinalizedHashTable.commit(Writer))
97 return EC;
98
99 return Error::success();
100}
101
102uint32_t NamedStreamMap::finalize() {
103 if (FinalizedInfo.hasValue())
104 return FinalizedInfo->SerializedLength;
105
106 // Build the finalized hash table.
107 FinalizedHashTable.clear();
108 FinalizedInfo.emplace();
Zachary Turner1affd802017-06-25 03:51:42 +0000109
110 for (const auto &Name : OrderedStreamNames) {
111 auto Item = Mapping.find(Name);
Zachary Turner3a11fdf2017-07-07 20:25:39 +0000112 if (Item == Mapping.end())
113 continue;
Zachary Turner1affd802017-06-25 03:51:42 +0000114 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue());
115 FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1;
Zachary Turner60667ca2017-01-20 22:41:40 +0000116 }
117
118 // Number of bytes of string data.
119 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
120 // Followed by that many actual bytes of string data.
121 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
122 // Followed by the mapping from Offset to Index.
123 FinalizedInfo->SerializedLength +=
124 FinalizedHashTable.calculateSerializedLength();
125 return FinalizedInfo->SerializedLength;
126}
127
Zachary Turnerf04d6e82017-01-20 22:41:15 +0000128iterator_range<StringMapConstIterator<uint32_t>>
129NamedStreamMap::entries() const {
Eugene Zelenko570e39a2016-11-23 23:16:32 +0000130 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
131 Mapping.end());
Zachary Turner85ed80b2016-05-25 03:43:17 +0000132}
133
Zachary Turner02278ce2017-03-16 20:18:41 +0000134uint32_t NamedStreamMap::size() const { return Mapping.size(); }
135
Zachary Turner60667ca2017-01-20 22:41:40 +0000136bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
137 auto Iter = Mapping.find(Stream);
Zachary Turnerf34e0162016-04-26 16:20:00 +0000138 if (Iter == Mapping.end())
139 return false;
Zachary Turner60667ca2017-01-20 22:41:40 +0000140 StreamNo = Iter->second;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000141 return true;
142}
Zachary Turner60667ca2017-01-20 22:41:40 +0000143
144void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
145 FinalizedInfo.reset();
146 Mapping[Stream] = StreamNo;
147}
148
149void NamedStreamMap::remove(StringRef Stream) {
150 FinalizedInfo.reset();
151 Mapping.erase(Stream);
152}