blob: f2c801221693a4c41211e37193d75c6b0b970a40 [file] [log] [blame]
Zachary Turnerbac69d32016-07-22 19:56:05 +00001//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===//
Zachary Turner6ba65de2016-04-29 17:22:58 +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 Turnerbac69d32016-07-22 19:56:05 +000010#include "llvm/DebugInfo/Msf/MappedBlockStream.h"
11#include "llvm/DebugInfo/Msf/DirectoryStreamData.h"
12#include "llvm/DebugInfo/Msf/IMsfStreamData.h"
13#include "llvm/DebugInfo/Msf/IndexedStreamData.h"
14#include "llvm/DebugInfo/Msf/MsfError.h"
Zachary Turner6ba65de2016-04-29 17:22:58 +000015
16using namespace llvm;
Zachary Turnerbac69d32016-07-22 19:56:05 +000017using namespace llvm::msf;
Zachary Turner6ba65de2016-04-29 17:22:58 +000018
Zachary Turnera1657a92016-06-08 17:26:39 +000019namespace {
Zachary Turnerbac69d32016-07-22 19:56:05 +000020// This exists so that we can use make_unique (which requires a public default
21// constructor, while still keeping the constructor of MappedBlockStream
22// protected, forcing users to go through the `create` interface.
Zachary Turnera1657a92016-06-08 17:26:39 +000023class MappedBlockStreamImpl : public MappedBlockStream {
24public:
Zachary Turnerbac69d32016-07-22 19:56:05 +000025 MappedBlockStreamImpl(std::unique_ptr<IMsfStreamData> Data,
26 const IMsfFile &File)
Zachary Turnera1657a92016-06-08 17:26:39 +000027 : MappedBlockStream(std::move(Data), File) {}
28};
29}
30
Zachary Turner5acb4ac2016-06-10 05:09:12 +000031typedef std::pair<uint32_t, uint32_t> Interval;
32static Interval intersect(const Interval &I1, const Interval &I2) {
33 return std::make_pair(std::max(I1.first, I2.first),
34 std::min(I1.second, I2.second));
35}
36
Zachary Turnerbac69d32016-07-22 19:56:05 +000037MappedBlockStream::MappedBlockStream(std::unique_ptr<IMsfStreamData> Data,
38 const IMsfFile &File)
39 : Msf(File), Data(std::move(Data)) {}
Zachary Turner6ba65de2016-04-29 17:22:58 +000040
Zachary Turner8dbe3622016-05-27 01:54:44 +000041Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
42 ArrayRef<uint8_t> &Buffer) const {
43 // Make sure we aren't trying to read beyond the end of the stream.
Zachary Turnerd8447992016-06-07 05:28:55 +000044 if (Size > Data->getLength())
Zachary Turnerbac69d32016-07-22 19:56:05 +000045 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turnerd8447992016-06-07 05:28:55 +000046 if (Offset > Data->getLength() - Size)
Zachary Turnerbac69d32016-07-22 19:56:05 +000047 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turner8dbe3622016-05-27 01:54:44 +000048
49 if (tryReadContiguously(Offset, Size, Buffer))
50 return Error::success();
51
52 auto CacheIter = CacheMap.find(Offset);
53 if (CacheIter != CacheMap.end()) {
Zachary Turner5acb4ac2016-06-10 05:09:12 +000054 // Try to find an alloc that was large enough for this request.
55 for (auto &Entry : CacheIter->second) {
56 if (Entry.size() >= Size) {
57 Buffer = Entry.slice(0, Size);
58 return Error::success();
59 }
60 }
61 }
62
63 // We couldn't find a buffer that started at the correct offset (the most
64 // common scenario). Try to see if there is a buffer that starts at some
65 // other offset but overlaps the desired range.
66 for (auto &CacheItem : CacheMap) {
67 Interval RequestExtent = std::make_pair(Offset, Offset + Size);
68
69 // We already checked this one on the fast path above.
70 if (CacheItem.first == Offset)
71 continue;
72 // If the initial extent of the cached item is beyond the ending extent
73 // of the request, there is no overlap.
74 if (CacheItem.first >= Offset + Size)
75 continue;
76
77 // We really only have to check the last item in the list, since we append
78 // in order of increasing length.
79 if (CacheItem.second.empty())
80 continue;
81
82 auto CachedAlloc = CacheItem.second.back();
83 // If the initial extent of the request is beyond the ending extent of
84 // the cached item, there is no overlap.
85 Interval CachedExtent =
86 std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size());
87 if (RequestExtent.first >= CachedExtent.first + CachedExtent.second)
88 continue;
89
90 Interval Intersection = intersect(CachedExtent, RequestExtent);
91 // Only use this if the entire request extent is contained in the cached
92 // extent.
93 if (Intersection != RequestExtent)
94 continue;
95
96 uint32_t CacheRangeOffset =
97 AbsoluteDifference(CachedExtent.first, Intersection.first);
98 Buffer = CachedAlloc.slice(CacheRangeOffset, Size);
Zachary Turner8dbe3622016-05-27 01:54:44 +000099 return Error::success();
100 }
101
102 // Otherwise allocate a large enough buffer in the pool, memcpy the data
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000103 // into it, and return an ArrayRef to that. Do not touch existing pool
104 // allocations, as existing clients may be holding a pointer which must
105 // not be invalidated.
Zachary Turner97609bb2016-06-10 21:47:26 +0000106 uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8));
Zachary Turner8dbe3622016-05-27 01:54:44 +0000107 if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size)))
108 return EC;
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000109
110 if (CacheIter != CacheMap.end()) {
111 CacheIter->second.emplace_back(WriteBuffer, Size);
112 } else {
113 std::vector<CacheEntry> List;
114 List.emplace_back(WriteBuffer, Size);
115 CacheMap.insert(std::make_pair(Offset, List));
116 }
Zachary Turner8dbe3622016-05-27 01:54:44 +0000117 Buffer = ArrayRef<uint8_t>(WriteBuffer, Size);
118 return Error::success();
119}
120
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000121Error MappedBlockStream::readLongestContiguousChunk(
122 uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
123 // Make sure we aren't trying to read beyond the end of the stream.
124 if (Offset >= Data->getLength())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000125 return make_error<MsfError>(msf_error_code::insufficient_buffer);
126 uint32_t First = Offset / Msf.getBlockSize();
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000127 uint32_t Last = First;
128
129 auto BlockList = Data->getStreamBlocks();
Zachary Turnerbac69d32016-07-22 19:56:05 +0000130 while (Last < Msf.getBlockCount() - 1) {
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000131 if (BlockList[Last] != BlockList[Last + 1] - 1)
132 break;
133 ++Last;
134 }
135
Zachary Turnerbac69d32016-07-22 19:56:05 +0000136 uint32_t OffsetInFirstBlock = Offset % Msf.getBlockSize();
137 uint32_t BytesFromFirstBlock = Msf.getBlockSize() - OffsetInFirstBlock;
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000138 uint32_t BlockSpan = Last - First + 1;
139 uint32_t ByteSpan =
Zachary Turnerbac69d32016-07-22 19:56:05 +0000140 BytesFromFirstBlock + (BlockSpan - 1) * Msf.getBlockSize();
141 auto Result = Msf.getBlockData(BlockList[First], Msf.getBlockSize());
David Majnemer6211b1f2016-07-10 03:34:47 +0000142 if (!Result)
143 return Result.takeError();
144 Buffer = Result->drop_front(OffsetInFirstBlock);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000145 Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan);
146 return Error::success();
147}
148
Zachary Turnerd8447992016-06-07 05:28:55 +0000149uint32_t MappedBlockStream::getLength() const { return Data->getLength(); }
150
Zachary Turnerab58ae82016-06-30 17:43:00 +0000151Error MappedBlockStream::commit() const { return Error::success(); }
152
Zachary Turner8dbe3622016-05-27 01:54:44 +0000153bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size,
154 ArrayRef<uint8_t> &Buffer) const {
155 // Attempt to fulfill the request with a reference directly into the stream.
156 // This can work even if the request crosses a block boundary, provided that
157 // all subsequent blocks are contiguous. For example, a 10k read with a 4k
158 // block size can be filled with a reference if, from the starting offset,
159 // 3 blocks in a row are contiguous.
Zachary Turnerbac69d32016-07-22 19:56:05 +0000160 uint32_t BlockNum = Offset / Msf.getBlockSize();
161 uint32_t OffsetInBlock = Offset % Msf.getBlockSize();
Zachary Turner8dbe3622016-05-27 01:54:44 +0000162 uint32_t BytesFromFirstBlock =
Zachary Turnerbac69d32016-07-22 19:56:05 +0000163 std::min(Size, Msf.getBlockSize() - OffsetInBlock);
Zachary Turner8dbe3622016-05-27 01:54:44 +0000164 uint32_t NumAdditionalBlocks =
Zachary Turnerbac69d32016-07-22 19:56:05 +0000165 llvm::alignTo(Size - BytesFromFirstBlock, Msf.getBlockSize()) /
166 Msf.getBlockSize();
Zachary Turner8dbe3622016-05-27 01:54:44 +0000167
Zachary Turnerd8447992016-06-07 05:28:55 +0000168 auto BlockList = Data->getStreamBlocks();
Zachary Turner8dbe3622016-05-27 01:54:44 +0000169 uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1;
170 uint32_t E = BlockList[BlockNum];
171 for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) {
172 if (BlockList[I + BlockNum] != E)
173 return false;
174 }
175
176 uint32_t FirstBlockAddr = BlockList[BlockNum];
Zachary Turnerbac69d32016-07-22 19:56:05 +0000177 auto Result = Msf.getBlockData(FirstBlockAddr, Msf.getBlockSize());
David Majnemer6211b1f2016-07-10 03:34:47 +0000178 if (!Result) {
179 consumeError(Result.takeError());
180 return false;
181 }
182 auto Data = Result->drop_front(OffsetInBlock);
Zachary Turnere6fee882016-06-07 20:38:37 +0000183 Buffer = ArrayRef<uint8_t>(Data.data(), Size);
Zachary Turner8dbe3622016-05-27 01:54:44 +0000184 return true;
185}
186
Zachary Turner819e77d2016-05-06 20:51:57 +0000187Error MappedBlockStream::readBytes(uint32_t Offset,
188 MutableArrayRef<uint8_t> Buffer) const {
Zachary Turnerbac69d32016-07-22 19:56:05 +0000189 uint32_t BlockNum = Offset / Msf.getBlockSize();
190 uint32_t OffsetInBlock = Offset % Msf.getBlockSize();
Zachary Turner6ba65de2016-04-29 17:22:58 +0000191
192 // Make sure we aren't trying to read beyond the end of the stream.
Zachary Turnerd8447992016-06-07 05:28:55 +0000193 if (Buffer.size() > Data->getLength())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000194 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turnerd8447992016-06-07 05:28:55 +0000195 if (Offset > Data->getLength() - Buffer.size())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000196 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turner6ba65de2016-04-29 17:22:58 +0000197
198 uint32_t BytesLeft = Buffer.size();
199 uint32_t BytesWritten = 0;
200 uint8_t *WriteBuffer = Buffer.data();
Zachary Turnerd8447992016-06-07 05:28:55 +0000201 auto BlockList = Data->getStreamBlocks();
Zachary Turner6ba65de2016-04-29 17:22:58 +0000202 while (BytesLeft > 0) {
203 uint32_t StreamBlockAddr = BlockList[BlockNum];
204
Zachary Turnerbac69d32016-07-22 19:56:05 +0000205 auto Result = Msf.getBlockData(StreamBlockAddr, Msf.getBlockSize());
David Majnemer6211b1f2016-07-10 03:34:47 +0000206 if (!Result)
207 return Result.takeError();
Zachary Turner6ba65de2016-04-29 17:22:58 +0000208
David Majnemer6211b1f2016-07-10 03:34:47 +0000209 auto Data = *Result;
Zachary Turnere6fee882016-06-07 20:38:37 +0000210 const uint8_t *ChunkStart = Data.data() + OffsetInBlock;
Zachary Turner6ba65de2016-04-29 17:22:58 +0000211 uint32_t BytesInChunk =
Zachary Turnerbac69d32016-07-22 19:56:05 +0000212 std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock);
Zachary Turner6ba65de2016-04-29 17:22:58 +0000213 ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk);
214
215 BytesWritten += BytesInChunk;
216 BytesLeft -= BytesInChunk;
217 ++BlockNum;
218 OffsetInBlock = 0;
219 }
220
Zachary Turner819e77d2016-05-06 20:51:57 +0000221 return Error::success();
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000222}
Zachary Turnerf5c59652016-05-03 00:28:21 +0000223
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000224Error MappedBlockStream::writeBytes(uint32_t Offset,
225 ArrayRef<uint8_t> Buffer) const {
226 // Make sure we aren't trying to write beyond the end of the stream.
227 if (Buffer.size() > Data->getLength())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000228 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000229
230 if (Offset > Data->getLength() - Buffer.size())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000231 return make_error<MsfError>(msf_error_code::insufficient_buffer);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000232
Zachary Turnerbac69d32016-07-22 19:56:05 +0000233 uint32_t BlockNum = Offset / Msf.getBlockSize();
234 uint32_t OffsetInBlock = Offset % Msf.getBlockSize();
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000235
236 uint32_t BytesLeft = Buffer.size();
237 auto BlockList = Data->getStreamBlocks();
238 uint32_t BytesWritten = 0;
239 while (BytesLeft > 0) {
240 uint32_t StreamBlockAddr = BlockList[BlockNum];
241 uint32_t BytesToWriteInChunk =
Zachary Turnerbac69d32016-07-22 19:56:05 +0000242 std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock);
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000243
244 const uint8_t *Chunk = Buffer.data() + BytesWritten;
245 ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk);
Zachary Turnerbac69d32016-07-22 19:56:05 +0000246 if (auto EC = Msf.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData))
Zachary Turner5acb4ac2016-06-10 05:09:12 +0000247 return EC;
248
249 BytesLeft -= BytesToWriteInChunk;
250 BytesWritten += BytesToWriteInChunk;
251 ++BlockNum;
252 OffsetInBlock = 0;
253 }
254
255 // If this write overlapped a read which previously came from the pool,
256 // someone may still be holding a pointer to that alloc which is now invalid.
257 // Compute the overlapping range and update the cache entry, so any
258 // outstanding buffers are automatically updated.
259 for (const auto &MapEntry : CacheMap) {
260 // If the end of the written extent precedes the beginning of the cached
261 // extent, ignore this map entry.
262 if (Offset + BytesWritten < MapEntry.first)
263 continue;
264 for (const auto &Alloc : MapEntry.second) {
265 // If the end of the cached extent precedes the beginning of the written
266 // extent, ignore this alloc.
267 if (MapEntry.first + Alloc.size() < Offset)
268 continue;
269
270 // If we get here, they are guaranteed to overlap.
271 Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten);
272 Interval CachedInterval =
273 std::make_pair(MapEntry.first, MapEntry.first + Alloc.size());
274 // If they overlap, we need to write the new data into the overlapping
275 // range.
276 auto Intersection = intersect(WriteInterval, CachedInterval);
277 assert(Intersection.first <= Intersection.second);
278
279 uint32_t Length = Intersection.second - Intersection.first;
280 uint32_t SrcOffset =
281 AbsoluteDifference(WriteInterval.first, Intersection.first);
282 uint32_t DestOffset =
283 AbsoluteDifference(CachedInterval.first, Intersection.first);
284 ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length);
285 }
286 }
287
288 return Error::success();
Zachary Turnerf5c59652016-05-03 00:28:21 +0000289}
Zachary Turner90b8b8d2016-05-31 22:41:52 +0000290
291uint32_t MappedBlockStream::getNumBytesCopied() const {
292 return static_cast<uint32_t>(Pool.getBytesAllocated());
293}
Zachary Turnera1657a92016-06-08 17:26:39 +0000294
295Expected<std::unique_ptr<MappedBlockStream>>
296MappedBlockStream::createIndexedStream(uint32_t StreamIdx,
Zachary Turnerbac69d32016-07-22 19:56:05 +0000297 const IMsfFile &File) {
Zachary Turnera1657a92016-06-08 17:26:39 +0000298 if (StreamIdx >= File.getNumStreams())
Zachary Turnerbac69d32016-07-22 19:56:05 +0000299 return make_error<MsfError>(msf_error_code::no_stream);
Zachary Turnera1657a92016-06-08 17:26:39 +0000300
301 auto Data = llvm::make_unique<IndexedStreamData>(StreamIdx, File);
302 return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File);
303}
304
305Expected<std::unique_ptr<MappedBlockStream>>
Zachary Turnerbac69d32016-07-22 19:56:05 +0000306MappedBlockStream::createDirectoryStream(uint32_t Length,
307 ArrayRef<support::ulittle32_t> Blocks,
308 const IMsfFile &File) {
309 auto Data = llvm::make_unique<DirectoryStreamData>(Length, Blocks);
Zachary Turnera1657a92016-06-08 17:26:39 +0000310 return llvm::make_unique<MappedBlockStreamImpl>(std::move(Data), File);
311}