1 //===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
16 #include "lldb/Host/windows/windows.h"
21 #include "llvm/Support/MathExtras.h"
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"
32 using namespace lldb_private;
34 //----------------------------------------------------------------------
35 // Default Constructor
36 //----------------------------------------------------------------------
37 DataBufferMemoryMap::DataBufferMemoryMap() :
45 //----------------------------------------------------------------------
46 // Virtual destructor since this class inherits from a pure virtual
48 //----------------------------------------------------------------------
49 DataBufferMemoryMap::~DataBufferMemoryMap()
54 //----------------------------------------------------------------------
55 // Return a pointer to the bytes owned by this object, or NULL if
56 // the object contains no bytes.
57 //----------------------------------------------------------------------
59 DataBufferMemoryMap::GetBytes()
64 //----------------------------------------------------------------------
65 // Return a const pointer to the bytes owned by this object, or NULL
66 // if the object contains no bytes.
67 //----------------------------------------------------------------------
69 DataBufferMemoryMap::GetBytes() const
74 //----------------------------------------------------------------------
75 // Return the number of bytes this object currently contains.
76 //----------------------------------------------------------------------
78 DataBufferMemoryMap::GetByteSize() const
83 //----------------------------------------------------------------------
84 // Reverts this object to an empty state by unmapping any memory
85 // that is currently owned.
86 //----------------------------------------------------------------------
88 DataBufferMemoryMap::Clear()
90 if (m_mmap_addr != NULL)
92 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
94 log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size);
96 UnmapViewOfFile(m_mmap_addr);
98 ::munmap((void *)m_mmap_addr, m_mmap_size);
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.
112 // Returns the number of bytes mapped starting from the requested
114 //----------------------------------------------------------------------
116 DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
117 lldb::offset_t offset,
121 if (filespec != NULL)
123 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
126 log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
127 filespec->GetPath().c_str(),
133 if (filespec->GetPath(path, sizeof(path)))
135 uint32_t options = File::eOpenOptionRead;
137 options |= File::eOpenOptionWrite;
140 Error error (file.Open(path, options));
143 const bool fd_is_file = true;
144 return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
148 // We should only get here if there was an error
155 static size_t win32memmapalignment = 0;
156 void LoadWin32MemMapAlignment ()
159 GetSystemInfo(&data);
160 win32memmapalignment = data.dwAllocationGranularity;
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().
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
174 // Number of bytes mapped starting from the requested offset.
175 //----------------------------------------------------------------------
177 DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
178 lldb::offset_t offset,
186 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
189 log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
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)
205 // Cap the length if too much data was requested
206 length = max_bytes_mappable;
211 HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL);
212 if (fileMapping != NULL)
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;
222 LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
223 m_mmap_addr = (uint8_t *)data;
226 error.SetErrorToErrno ();
228 m_data = m_mmap_addr + delta;
231 CloseHandle(fileMapping);
236 if (::fstat(fd, &stat) == 0)
238 if (S_ISREG(stat.st_mode) &&
239 (stat.st_size > static_cast<off_t>(offset)))
241 const size_t max_bytes_available = stat.st_size - offset;
242 if (length == SIZE_MAX)
244 length = max_bytes_available;
246 else if (length > max_bytes_available)
248 // Cap the length if too much data was requested
249 length = max_bytes_available;
254 int prot = PROT_READ;
258 int flags = MAP_PRIVATE;
262 m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
265 if (m_mmap_addr == (void*)-1)
267 error.SetErrorToErrno ();
268 if (error.GetError() == EINVAL)
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)
274 m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
275 if (m_mmap_addr == (void*)-1)
277 // Failed to map file
280 else if (m_mmap_addr != NULL)
282 // We recovered and were able to memory map
283 // after we aligned things to page boundaries
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
294 if (error.GetError() == ENOMEM)
296 error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
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;
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());
318 return GetByteSize ();