/src/keystone/llvm/lib/Support/MemoryBuffer.cpp
Line | Count | Source |
1 | | //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// |
2 | | // |
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 | | // |
10 | | // This file implements the MemoryBuffer interface. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "llvm/Support/MemoryBuffer.h" |
15 | | #include "llvm/ADT/SmallString.h" |
16 | | #include "llvm/Config/config.h" |
17 | | #include "llvm/Support/Errc.h" |
18 | | #include "llvm/Support/Errno.h" |
19 | | #include "llvm/Support/FileSystem.h" |
20 | | #include "llvm/Support/MathExtras.h" |
21 | | #include "llvm/Support/Path.h" |
22 | | #include <cassert> |
23 | | #include <cerrno> |
24 | | #include <cstring> |
25 | | #include <new> |
26 | | #include <sys/types.h> |
27 | | #include <system_error> |
28 | | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
29 | | #include <unistd.h> |
30 | | #else |
31 | | #include <io.h> |
32 | | #endif |
33 | | using namespace llvm_ks; |
34 | | |
35 | | //===----------------------------------------------------------------------===// |
36 | | // MemoryBuffer implementation itself. |
37 | | //===----------------------------------------------------------------------===// |
38 | | |
39 | 477k | MemoryBuffer::~MemoryBuffer() { } |
40 | | |
41 | | /// init - Initialize this MemoryBuffer as a reference to externally allocated |
42 | | /// memory, memory that we know is already null terminated. |
43 | | void MemoryBuffer::init(const char *BufStart, const char *BufEnd, |
44 | 477k | bool RequiresNullTerminator) { |
45 | 477k | assert((!RequiresNullTerminator || BufEnd[0] == 0) && |
46 | 477k | "Buffer is not null terminated!"); |
47 | 477k | BufferStart = BufStart; |
48 | 477k | BufferEnd = BufEnd; |
49 | 477k | } |
50 | | |
51 | | //===----------------------------------------------------------------------===// |
52 | | // MemoryBufferMem implementation. |
53 | | //===----------------------------------------------------------------------===// |
54 | | |
55 | | /// CopyStringRef - Copies contents of a StringRef into a block of memory and |
56 | | /// null-terminates it. |
57 | 477k | static void CopyStringRef(char *Memory, StringRef Data) { |
58 | 477k | if (!Data.empty()) |
59 | 338k | memcpy(Memory, Data.data(), Data.size()); |
60 | 477k | Memory[Data.size()] = 0; // Null terminate string. |
61 | 477k | } |
62 | | |
63 | | namespace { |
64 | | struct NamedBufferAlloc { |
65 | | const Twine &Name; |
66 | 138k | NamedBufferAlloc(const Twine &Name) : Name(Name) {} |
67 | | }; |
68 | | } |
69 | | |
70 | 138k | void *operator new(size_t N, const NamedBufferAlloc &Alloc) { |
71 | 138k | SmallString<256> NameBuf; |
72 | 138k | StringRef NameRef = Alloc.Name.toStringRef(NameBuf); |
73 | | |
74 | 138k | char *Mem = static_cast<char *>(operator new(N + NameRef.size() + 1)); |
75 | 138k | CopyStringRef(Mem + N, NameRef); |
76 | 138k | return Mem; |
77 | 138k | } |
78 | | |
79 | | namespace { |
80 | | /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. |
81 | | class MemoryBufferMem : public MemoryBuffer { |
82 | | public: |
83 | 477k | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { |
84 | 477k | init(InputData.begin(), InputData.end(), RequiresNullTerminator); |
85 | 477k | } |
86 | | |
87 | 165k | const char *getBufferIdentifier() const override { |
88 | | // The name is stored after the class itself. |
89 | 165k | return reinterpret_cast<const char*>(this + 1); |
90 | 165k | } |
91 | | |
92 | 0 | BufferKind getBufferKind() const override { |
93 | 0 | return MemoryBuffer_Malloc; |
94 | 0 | } |
95 | | }; |
96 | | } |
97 | | |
98 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
99 | | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, |
100 | | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize); |
101 | | |
102 | | std::unique_ptr<MemoryBuffer> |
103 | | MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, |
104 | 138k | bool RequiresNullTerminator) { |
105 | 138k | auto *Ret = new (NamedBufferAlloc(BufferName)) |
106 | 138k | MemoryBufferMem(InputData, RequiresNullTerminator); |
107 | 138k | return std::unique_ptr<MemoryBuffer>(Ret); |
108 | 138k | } |
109 | | |
110 | | std::unique_ptr<MemoryBuffer> |
111 | 0 | MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { |
112 | 0 | return std::unique_ptr<MemoryBuffer>(getMemBuffer( |
113 | 0 | Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator)); |
114 | 0 | } |
115 | | |
116 | | std::unique_ptr<MemoryBuffer> |
117 | 338k | MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { |
118 | 338k | std::unique_ptr<MemoryBuffer> Buf = |
119 | 338k | getNewUninitMemBuffer(InputData.size(), BufferName); |
120 | 338k | if (!Buf) |
121 | 0 | return nullptr; |
122 | 338k | memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(), |
123 | 338k | InputData.size()); |
124 | 338k | return Buf; |
125 | 338k | } |
126 | | |
127 | | std::unique_ptr<MemoryBuffer> |
128 | 338k | MemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) { |
129 | | // Allocate space for the MemoryBuffer, the data and the name. It is important |
130 | | // that MemoryBuffer and data are aligned so PointerIntPair works with them. |
131 | | // TODO: Is 16-byte alignment enough? We copy small object files with large |
132 | | // alignment expectations into this buffer. |
133 | 338k | SmallString<256> NameBuf; |
134 | 338k | StringRef NameRef = BufferName.toStringRef(NameBuf); |
135 | 338k | size_t AlignedStringLen = |
136 | 338k | alignTo(sizeof(MemoryBufferMem) + NameRef.size() + 1, 16); |
137 | 338k | size_t RealLen = AlignedStringLen + Size + 1; |
138 | 338k | char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); |
139 | 338k | if (!Mem) |
140 | 0 | return nullptr; |
141 | | |
142 | | // The name is stored after the class itself. |
143 | 338k | CopyStringRef(Mem + sizeof(MemoryBufferMem), NameRef); |
144 | | |
145 | | // The buffer begins after the name and must be aligned. |
146 | 338k | char *Buf = Mem + AlignedStringLen; |
147 | 338k | Buf[Size] = 0; // Null terminate buffer. |
148 | | |
149 | 338k | auto *Ret = new (Mem) MemoryBufferMem(StringRef(Buf, Size), true); |
150 | 338k | return std::unique_ptr<MemoryBuffer>(Ret); |
151 | 338k | } |
152 | | |
153 | | std::unique_ptr<MemoryBuffer> |
154 | 0 | MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { |
155 | 0 | std::unique_ptr<MemoryBuffer> SB = getNewUninitMemBuffer(Size, BufferName); |
156 | 0 | if (!SB) |
157 | 0 | return nullptr; |
158 | 0 | memset(const_cast<char*>(SB->getBufferStart()), 0, Size); |
159 | 0 | return SB; |
160 | 0 | } |
161 | | |
162 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
163 | | MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize, |
164 | 0 | bool RequiresNullTerminator) { |
165 | 0 | SmallString<256> NameBuf; |
166 | 0 | StringRef NameRef = Filename.toStringRef(NameBuf); |
167 | |
|
168 | 0 | if (NameRef == "-") |
169 | 0 | return getSTDIN(); |
170 | 0 | return getFile(Filename, FileSize, RequiresNullTerminator); |
171 | 0 | } |
172 | | |
173 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
174 | | MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, |
175 | 0 | uint64_t Offset) { |
176 | 0 | return getFileAux(FilePath, -1, MapSize, Offset, false, false); |
177 | 0 | } |
178 | | |
179 | | |
180 | | //===----------------------------------------------------------------------===// |
181 | | // MemoryBuffer::getFile implementation. |
182 | | //===----------------------------------------------------------------------===// |
183 | | |
184 | | namespace { |
185 | | /// \brief Memory maps a file descriptor using sys::fs::mapped_file_region. |
186 | | /// |
187 | | /// This handles converting the offset into a legal offset on the platform. |
188 | | class MemoryBufferMMapFile : public MemoryBuffer { |
189 | | sys::fs::mapped_file_region MFR; |
190 | | |
191 | 0 | static uint64_t getLegalMapOffset(uint64_t Offset) { |
192 | 0 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); |
193 | 0 | } |
194 | | |
195 | 0 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { |
196 | 0 | return Len + (Offset - getLegalMapOffset(Offset)); |
197 | 0 | } |
198 | | |
199 | 0 | const char *getStart(uint64_t Len, uint64_t Offset) { |
200 | 0 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); |
201 | 0 | } |
202 | | |
203 | | public: |
204 | | MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, |
205 | | uint64_t Offset, std::error_code &EC) |
206 | 0 | : MFR(FD, sys::fs::mapped_file_region::readonly, |
207 | 0 | getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { |
208 | 0 | if (!EC) { |
209 | 0 | const char *Start = getStart(Len, Offset); |
210 | 0 | init(Start, Start + Len, RequiresNullTerminator); |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | 0 | const char *getBufferIdentifier() const override { |
215 | | // The name is stored after the class itself. |
216 | 0 | return reinterpret_cast<const char *>(this + 1); |
217 | 0 | } |
218 | | |
219 | 0 | BufferKind getBufferKind() const override { |
220 | 0 | return MemoryBuffer_MMap; |
221 | 0 | } |
222 | | }; |
223 | | } |
224 | | |
225 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
226 | 6 | getMemoryBufferForStream(int FD, const Twine &BufferName) { |
227 | 6 | const ssize_t ChunkSize = 4096*4; |
228 | 6 | SmallString<ChunkSize> Buffer; |
229 | 6 | ssize_t ReadBytes; |
230 | | // Read into Buffer until we hit EOF. |
231 | 6 | do { |
232 | 6 | Buffer.reserve(Buffer.size() + ChunkSize); |
233 | 6 | ReadBytes = read(FD, Buffer.end(), ChunkSize); |
234 | 6 | if (ReadBytes == -1) { |
235 | 6 | if (errno == EINTR) continue; |
236 | 6 | return std::error_code(errno, std::generic_category()); |
237 | 6 | } |
238 | 0 | Buffer.set_size(Buffer.size() + ReadBytes); |
239 | 0 | } while (ReadBytes != 0); |
240 | | |
241 | 0 | return MemoryBuffer::getMemBufferCopy(Buffer, BufferName); |
242 | 6 | } |
243 | | |
244 | | |
245 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
246 | | MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, |
247 | 63 | bool RequiresNullTerminator, bool IsVolatileSize) { |
248 | 63 | return getFileAux(Filename, FileSize, FileSize, 0, |
249 | 63 | RequiresNullTerminator, IsVolatileSize); |
250 | 63 | } |
251 | | |
252 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
253 | | getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, |
254 | | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
255 | | bool IsVolatileSize); |
256 | | |
257 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
258 | | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, |
259 | 63 | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) { |
260 | 63 | int FD; |
261 | 63 | std::error_code EC = sys::fs::openFileForRead(Filename, FD); |
262 | 63 | if (EC) |
263 | 57 | return EC; |
264 | | |
265 | 6 | ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = |
266 | 6 | getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset, |
267 | 6 | RequiresNullTerminator, IsVolatileSize); |
268 | 6 | close(FD); |
269 | 6 | return Ret; |
270 | 63 | } |
271 | | |
272 | | static bool shouldUseMmap(int FD, |
273 | | size_t FileSize, |
274 | | size_t MapSize, |
275 | | off_t Offset, |
276 | | bool RequiresNullTerminator, |
277 | | int PageSize, |
278 | 0 | bool IsVolatileSize) { |
279 | | // mmap may leave the buffer without null terminator if the file size changed |
280 | | // by the time the last page is mapped in, so avoid it if the file size is |
281 | | // likely to change. |
282 | 0 | if (IsVolatileSize) |
283 | 0 | return false; |
284 | | |
285 | | // We don't use mmap for small files because this can severely fragment our |
286 | | // address space. |
287 | 0 | if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize) |
288 | 0 | return false; |
289 | | |
290 | 0 | if (!RequiresNullTerminator) |
291 | 0 | return true; |
292 | | |
293 | | |
294 | | // If we don't know the file size, use fstat to find out. fstat on an open |
295 | | // file descriptor is cheaper than stat on a random path. |
296 | | // FIXME: this chunk of code is duplicated, but it avoids a fstat when |
297 | | // RequiresNullTerminator = false and MapSize != -1. |
298 | 0 | if (FileSize == size_t(-1)) { |
299 | 0 | sys::fs::file_status Status; |
300 | 0 | if (sys::fs::status(FD, Status)) |
301 | 0 | return false; |
302 | 0 | FileSize = Status.getSize(); |
303 | 0 | } |
304 | | |
305 | | // If we need a null terminator and the end of the map is inside the file, |
306 | | // we cannot use mmap. |
307 | 0 | size_t End = Offset + MapSize; |
308 | 0 | assert(End <= FileSize); |
309 | 0 | if (End != FileSize) |
310 | 0 | return false; |
311 | | |
312 | | // Don't try to map files that are exactly a multiple of the system page size |
313 | | // if we need a null terminator. |
314 | 0 | if ((FileSize & (PageSize -1)) == 0) |
315 | 0 | return false; |
316 | | |
317 | | #if defined(__CYGWIN__) |
318 | | // Don't try to map files that are exactly a multiple of the physical page size |
319 | | // if we need a null terminator. |
320 | | // FIXME: We should reorganize again getPageSize() on Win32. |
321 | | if ((FileSize & (4096 - 1)) == 0) |
322 | | return false; |
323 | | #endif |
324 | | |
325 | 0 | return true; |
326 | 0 | } |
327 | | |
328 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
329 | | getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, |
330 | | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
331 | 6 | bool IsVolatileSize) { |
332 | 6 | static int PageSize = 4096; |
333 | | |
334 | | // Default is to map the full file. |
335 | 6 | if (MapSize == uint64_t(-1)) { |
336 | | // If we don't know the file size, use fstat to find out. fstat on an open |
337 | | // file descriptor is cheaper than stat on a random path. |
338 | 6 | if (FileSize == uint64_t(-1)) { |
339 | 6 | sys::fs::file_status Status; |
340 | 6 | std::error_code EC = sys::fs::status(FD, Status); |
341 | 6 | if (EC) |
342 | 0 | return EC; |
343 | | |
344 | | // If this not a file or a block device (e.g. it's a named pipe |
345 | | // or character device), we can't trust the size. Create the memory |
346 | | // buffer by copying off the stream. |
347 | 6 | sys::fs::file_type Type = Status.type(); |
348 | 6 | if (Type != sys::fs::file_type::regular_file && |
349 | 6 | Type != sys::fs::file_type::block_file) |
350 | 6 | return getMemoryBufferForStream(FD, Filename); |
351 | | |
352 | 0 | FileSize = Status.getSize(); |
353 | 0 | } |
354 | 0 | MapSize = FileSize; |
355 | 0 | } |
356 | | |
357 | 0 | if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, |
358 | 0 | PageSize, IsVolatileSize)) { |
359 | 0 | std::error_code EC; |
360 | 0 | std::unique_ptr<MemoryBuffer> Result( |
361 | 0 | new (NamedBufferAlloc(Filename)) |
362 | 0 | MemoryBufferMMapFile(RequiresNullTerminator, FD, MapSize, Offset, EC)); |
363 | 0 | if (!EC) |
364 | 0 | return std::move(Result); |
365 | 0 | } |
366 | | |
367 | 0 | std::unique_ptr<MemoryBuffer> Buf = |
368 | 0 | MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); |
369 | 0 | if (!Buf) { |
370 | | // Failed to create a buffer. The only way it can fail is if |
371 | | // new(std::nothrow) returns 0. |
372 | 0 | return make_error_code(errc::not_enough_memory); |
373 | 0 | } |
374 | | |
375 | 0 | char *BufPtr = const_cast<char *>(Buf->getBufferStart()); |
376 | |
|
377 | 0 | size_t BytesLeft = MapSize; |
378 | | #ifndef HAVE_PREAD |
379 | | if (lseek(FD, Offset, SEEK_SET) == -1) |
380 | | return std::error_code(errno, std::generic_category()); |
381 | | #endif |
382 | |
|
383 | 0 | while (BytesLeft) { |
384 | 0 | #ifdef HAVE_PREAD |
385 | 0 | ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); |
386 | | #else |
387 | | ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); |
388 | | #endif |
389 | 0 | if (NumRead == -1) { |
390 | 0 | if (errno == EINTR) |
391 | 0 | continue; |
392 | | // Error while reading. |
393 | 0 | return std::error_code(errno, std::generic_category()); |
394 | 0 | } |
395 | 0 | if (NumRead == 0) { |
396 | 0 | memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer. |
397 | 0 | break; |
398 | 0 | } |
399 | 0 | BytesLeft -= NumRead; |
400 | 0 | BufPtr += NumRead; |
401 | 0 | } |
402 | | |
403 | 0 | return std::move(Buf); |
404 | 0 | } |
405 | | |
406 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
407 | | MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, |
408 | 0 | bool RequiresNullTerminator, bool IsVolatileSize) { |
409 | 0 | return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0, |
410 | 0 | RequiresNullTerminator, IsVolatileSize); |
411 | 0 | } |
412 | | |
413 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
414 | | MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, |
415 | 0 | int64_t Offset) { |
416 | 0 | assert(MapSize != uint64_t(-1)); |
417 | 0 | return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, |
418 | 0 | /*IsVolatileSize*/ false); |
419 | 0 | } |
420 | | |
421 | 0 | ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { |
422 | | // Read in all of the data from stdin, we cannot mmap stdin. |
423 | | // |
424 | | // FIXME: That isn't necessarily true, we should try to mmap stdin and |
425 | | // fallback if it fails. |
426 | |
|
427 | 0 | return getMemoryBufferForStream(0, "<stdin>"); |
428 | 0 | } |
429 | | |
430 | 0 | MemoryBufferRef MemoryBuffer::getMemBufferRef() const { |
431 | 0 | StringRef Data = getBuffer(); |
432 | 0 | StringRef Identifier = getBufferIdentifier(); |
433 | 0 | return MemoryBufferRef(Data, Identifier); |
434 | 0 | } |