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