]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Core/DataBufferMemoryMap.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / source / Core / DataBufferMemoryMap.cpp
1 //===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
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
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <limits.h>
14 #include <sys/stat.h>
15 #ifdef _WIN32
16 #include "lldb/Host/windows/windows.h"
17 #else
18 #include <sys/mman.h>
19 #endif
20
21 #include "lldb/Core/DataBufferMemoryMap.h"
22 #include "lldb/Core/Error.h"
23 #include "lldb/Host/File.h"
24 #include "lldb/Host/FileSpec.h"
25 #include "lldb/Host/Host.h"
26 #include "lldb/Core/Log.h"
27 #include "lldb/lldb-private-log.h"
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 //----------------------------------------------------------------------
33 // Default Constructor
34 //----------------------------------------------------------------------
35 DataBufferMemoryMap::DataBufferMemoryMap() :
36     m_mmap_addr(NULL),
37     m_mmap_size(0),
38     m_data(NULL),
39     m_size(0)
40 {
41 }
42
43 //----------------------------------------------------------------------
44 // Virtual destructor since this class inherits from a pure virtual
45 // base class.
46 //----------------------------------------------------------------------
47 DataBufferMemoryMap::~DataBufferMemoryMap()
48 {
49     Clear();
50 }
51
52 //----------------------------------------------------------------------
53 // Return a pointer to the bytes owned by this object, or NULL if
54 // the object contains no bytes.
55 //----------------------------------------------------------------------
56 uint8_t *
57 DataBufferMemoryMap::GetBytes()
58 {
59     return m_data;
60 }
61
62 //----------------------------------------------------------------------
63 // Return a const pointer to the bytes owned by this object, or NULL
64 // if the object contains no bytes.
65 //----------------------------------------------------------------------
66 const uint8_t *
67 DataBufferMemoryMap::GetBytes() const
68 {
69     return m_data;
70 }
71
72 //----------------------------------------------------------------------
73 // Return the number of bytes this object currently contains.
74 //----------------------------------------------------------------------
75 uint64_t
76 DataBufferMemoryMap::GetByteSize() const
77 {
78     return m_size;
79 }
80
81 //----------------------------------------------------------------------
82 // Reverts this object to an empty state by unmapping any memory
83 // that is currently owned.
84 //----------------------------------------------------------------------
85 void
86 DataBufferMemoryMap::Clear()
87 {
88     if (m_mmap_addr != NULL)
89     {
90         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
91         if (log)
92             log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size);
93 #ifdef _WIN32
94         UnmapViewOfFile(m_mmap_addr);
95 #else
96         ::munmap((void *)m_mmap_addr, m_mmap_size);
97 #endif
98         m_mmap_addr = NULL;
99         m_mmap_size = 0;
100         m_data = NULL;
101         m_size = 0;
102     }
103 }
104
105 //----------------------------------------------------------------------
106 // Memory map "length" bytes from "file" starting "offset"
107 // bytes into the file. If "length" is set to SIZE_MAX, then
108 // map as many bytes as possible.
109 //
110 // Returns the number of bytes mapped starting from the requested
111 // offset.
112 //----------------------------------------------------------------------
113 size_t
114 DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
115                                             lldb::offset_t offset,
116                                             lldb::offset_t length,
117                                             bool writeable)
118 {
119     if (filespec != NULL)
120     {
121         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
122         if (log)
123         {
124             log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
125                         filespec->GetPath().c_str(),
126                         offset,
127                         length,
128                         writeable);
129         }
130         char path[PATH_MAX];
131         if (filespec->GetPath(path, sizeof(path)))
132         {
133             uint32_t options = File::eOpenOptionRead;
134             if (writeable)
135                 options |= File::eOpenOptionWrite;
136
137             File file;
138             Error error (file.Open(path, options));
139             if (error.Success())
140             {
141                 const bool fd_is_file = true;
142                 return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
143             }
144         }
145     }
146     // We should only get here if there was an error
147     Clear();
148     return 0;
149 }
150 \r
151 \r
152 #ifdef _WIN32\r
153 static size_t win32memmapalignment = 0;\r
154 void LoadWin32MemMapAlignment ()\r
155 {\r
156   SYSTEM_INFO data;\r
157   GetSystemInfo(&data);\r
158   win32memmapalignment = data.dwAllocationGranularity;\r
159 }\r
160 #endif
161
162 //----------------------------------------------------------------------
163 // The file descriptor FD is assumed to already be opened as read only
164 // and the STAT structure is assumed to a valid pointer and already
165 // containing valid data from a call to stat().
166 //
167 // Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
168 // the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
169 // as possible.
170 //
171 // RETURNS
172 //  Number of bytes mapped starting from the requested offset.
173 //----------------------------------------------------------------------
174 size_t
175 DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, 
176                                                   lldb::offset_t offset, 
177                                                   lldb::offset_t length,
178                                                   bool writeable,
179                                                   bool fd_is_file)
180 {
181     Clear();
182     if (fd >= 0)
183     {
184         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
185         if (log)
186         {
187 #ifdef _WIN32
188             log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%p, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
189 #else
190             log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
191 #endif
192                         fd,
193                         offset,
194                         length,
195                         writeable,
196                         fd_is_file);
197         }
198 #ifdef _WIN32
199         HANDLE handle = (HANDLE)_get_osfhandle(fd);
200         DWORD file_size_low, file_size_high;
201         file_size_low = GetFileSize(handle, &file_size_high);
202         const size_t file_size = (file_size_high << 32) | file_size_low;
203         const size_t max_bytes_available = file_size - offset;
204         if (length == SIZE_MAX)
205         {
206             length = max_bytes_available;
207         }
208         else if (length > max_bytes_available)
209         {
210             // Cap the length if too much data was requested
211             length = max_bytes_available;
212         }
213
214         if (length > 0)
215         {
216             HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL);
217             if (fileMapping != NULL)
218             {
219                 if (win32memmapalignment == 0) LoadWin32MemMapAlignment();\r
220                 lldb::offset_t realoffset = offset;\r
221                 lldb::offset_t delta = 0;\r
222                 if (realoffset % win32memmapalignment != 0) {\r
223                   realoffset = realoffset / win32memmapalignment * win32memmapalignment;\r
224                   delta = offset - realoffset;\r
225                       }
226 \r
227                 LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);\r
228                 m_mmap_addr = (uint8_t *)data;\r
229                 if (!data) {\r
230                   Error error; \r
231                   error.SetErrorToErrno ();\r
232                 } else {
233                   m_data = m_mmap_addr + delta;\r
234                   m_size = length;\r
235                 }\r
236                 CloseHandle(fileMapping);
237             }
238         }
239 #else
240         struct stat stat;
241         if (::fstat(fd, &stat) == 0)
242         {
243             if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
244             {
245                 const size_t max_bytes_available = stat.st_size - offset;
246                 if (length == SIZE_MAX)
247                 {
248                     length = max_bytes_available;
249                 }
250                 else if (length > max_bytes_available)
251                 {
252                     // Cap the length if too much data was requested
253                     length = max_bytes_available;
254                 }
255
256                 if (length > 0)
257                 {
258                     int prot = PROT_READ;
259                     if (writeable)
260                         prot |= PROT_WRITE;
261
262                     int flags = MAP_PRIVATE;
263                     if (fd_is_file)
264                         flags |= MAP_FILE;
265
266                     m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
267                     Error error;
268
269                     if (m_mmap_addr == (void*)-1)
270                     {
271                         error.SetErrorToErrno ();
272                         if (error.GetError() == EINVAL)
273                         {
274                             // We may still have a shot at memory mapping if we align things correctly
275                             size_t page_offset = offset % Host::GetPageSize();
276                             if (page_offset != 0)
277                             {
278                                 m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
279                                 if (m_mmap_addr == (void*)-1)
280                                 {
281                                     // Failed to map file
282                                     m_mmap_addr = NULL;
283                                 }
284                                 else if (m_mmap_addr != NULL)
285                                 {
286                                     // We recovered and were able to memory map
287                                     // after we aligned things to page boundaries
288
289                                     // Save the actual mmap'ed size
290                                     m_mmap_size = length + page_offset;
291                                     // Our data is at an offset into the the mapped data
292                                     m_data = m_mmap_addr + page_offset;
293                                     // Our pretend size is the size that was requestd
294                                     m_size = length;
295                                 }
296                             }
297                         }
298                         if (error.GetError() == ENOMEM)
299                         {
300                            error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
301                         }
302                     }
303                     else
304                     {
305                         // We were able to map the requested data in one chunk
306                         // where our mmap and actual data are the same.
307                         m_mmap_size = length;
308                         m_data = m_mmap_addr;
309                         m_size = length;
310                     }
311                     
312                     if (log)
313                     {
314                         log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s",
315                                     m_mmap_addr, m_mmap_size, error.AsCString());
316                     }
317                 }
318             }
319         }
320 #endif
321     }
322     return GetByteSize ();
323 }