1254721Semaste//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste
11254721Semaste#include <errno.h>
12254721Semaste#include <fcntl.h>
13254721Semaste#include <limits.h>
14254721Semaste#include <sys/stat.h>
15263363Semaste#ifdef _WIN32
16263363Semaste#include "lldb/Host/windows/windows.h"
17263363Semaste#else
18254721Semaste#include <sys/mman.h>
19263363Semaste#endif
20254721Semaste
21254721Semaste#include "lldb/Core/DataBufferMemoryMap.h"
22254721Semaste#include "lldb/Core/Error.h"
23254721Semaste#include "lldb/Host/File.h"
24254721Semaste#include "lldb/Host/FileSpec.h"
25254721Semaste#include "lldb/Host/Host.h"
26254721Semaste#include "lldb/Core/Log.h"
27254721Semaste#include "lldb/lldb-private-log.h"
28254721Semaste
29254721Semasteusing namespace lldb;
30254721Semasteusing namespace lldb_private;
31254721Semaste
32254721Semaste//----------------------------------------------------------------------
33254721Semaste// Default Constructor
34254721Semaste//----------------------------------------------------------------------
35254721SemasteDataBufferMemoryMap::DataBufferMemoryMap() :
36254721Semaste    m_mmap_addr(NULL),
37254721Semaste    m_mmap_size(0),
38254721Semaste    m_data(NULL),
39254721Semaste    m_size(0)
40254721Semaste{
41254721Semaste}
42254721Semaste
43254721Semaste//----------------------------------------------------------------------
44254721Semaste// Virtual destructor since this class inherits from a pure virtual
45254721Semaste// base class.
46254721Semaste//----------------------------------------------------------------------
47254721SemasteDataBufferMemoryMap::~DataBufferMemoryMap()
48254721Semaste{
49254721Semaste    Clear();
50254721Semaste}
51254721Semaste
52254721Semaste//----------------------------------------------------------------------
53254721Semaste// Return a pointer to the bytes owned by this object, or NULL if
54254721Semaste// the object contains no bytes.
55254721Semaste//----------------------------------------------------------------------
56254721Semasteuint8_t *
57254721SemasteDataBufferMemoryMap::GetBytes()
58254721Semaste{
59254721Semaste    return m_data;
60254721Semaste}
61254721Semaste
62254721Semaste//----------------------------------------------------------------------
63254721Semaste// Return a const pointer to the bytes owned by this object, or NULL
64254721Semaste// if the object contains no bytes.
65254721Semaste//----------------------------------------------------------------------
66254721Semasteconst uint8_t *
67254721SemasteDataBufferMemoryMap::GetBytes() const
68254721Semaste{
69254721Semaste    return m_data;
70254721Semaste}
71254721Semaste
72254721Semaste//----------------------------------------------------------------------
73254721Semaste// Return the number of bytes this object currently contains.
74254721Semaste//----------------------------------------------------------------------
75254721Semasteuint64_t
76254721SemasteDataBufferMemoryMap::GetByteSize() const
77254721Semaste{
78254721Semaste    return m_size;
79254721Semaste}
80254721Semaste
81254721Semaste//----------------------------------------------------------------------
82254721Semaste// Reverts this object to an empty state by unmapping any memory
83254721Semaste// that is currently owned.
84254721Semaste//----------------------------------------------------------------------
85254721Semastevoid
86254721SemasteDataBufferMemoryMap::Clear()
87254721Semaste{
88254721Semaste    if (m_mmap_addr != NULL)
89254721Semaste    {
90254721Semaste        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
91254721Semaste        if (log)
92254721Semaste            log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size);
93263363Semaste#ifdef _WIN32
94263363Semaste        UnmapViewOfFile(m_mmap_addr);
95263363Semaste#else
96254721Semaste        ::munmap((void *)m_mmap_addr, m_mmap_size);
97263363Semaste#endif
98254721Semaste        m_mmap_addr = NULL;
99254721Semaste        m_mmap_size = 0;
100254721Semaste        m_data = NULL;
101254721Semaste        m_size = 0;
102254721Semaste    }
103254721Semaste}
104254721Semaste
105254721Semaste//----------------------------------------------------------------------
106254721Semaste// Memory map "length" bytes from "file" starting "offset"
107254721Semaste// bytes into the file. If "length" is set to SIZE_MAX, then
108254721Semaste// map as many bytes as possible.
109254721Semaste//
110254721Semaste// Returns the number of bytes mapped starting from the requested
111254721Semaste// offset.
112254721Semaste//----------------------------------------------------------------------
113254721Semastesize_t
114254721SemasteDataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
115254721Semaste                                            lldb::offset_t offset,
116254721Semaste                                            lldb::offset_t length,
117254721Semaste                                            bool writeable)
118254721Semaste{
119254721Semaste    if (filespec != NULL)
120254721Semaste    {
121254721Semaste        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
122254721Semaste        if (log)
123254721Semaste        {
124254721Semaste            log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
125254721Semaste                        filespec->GetPath().c_str(),
126254721Semaste                        offset,
127254721Semaste                        length,
128254721Semaste                        writeable);
129254721Semaste        }
130254721Semaste        char path[PATH_MAX];
131254721Semaste        if (filespec->GetPath(path, sizeof(path)))
132254721Semaste        {
133254721Semaste            uint32_t options = File::eOpenOptionRead;
134254721Semaste            if (writeable)
135254721Semaste                options |= File::eOpenOptionWrite;
136254721Semaste
137254721Semaste            File file;
138254721Semaste            Error error (file.Open(path, options));
139254721Semaste            if (error.Success())
140254721Semaste            {
141254721Semaste                const bool fd_is_file = true;
142254721Semaste                return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
143254721Semaste            }
144254721Semaste        }
145254721Semaste    }
146254721Semaste    // We should only get here if there was an error
147254721Semaste    Clear();
148254721Semaste    return 0;
149254721Semaste}
150263363Semaste
151263363Semaste
152263363Semaste#ifdef _WIN32
153263363Semastestatic size_t win32memmapalignment = 0;
154263363Semastevoid LoadWin32MemMapAlignment ()
155263363Semaste{
156263363Semaste  SYSTEM_INFO data;
157263363Semaste  GetSystemInfo(&data);
158263363Semaste  win32memmapalignment = data.dwAllocationGranularity;
159263363Semaste}
160263363Semaste#endif
161254721Semaste
162254721Semaste//----------------------------------------------------------------------
163254721Semaste// The file descriptor FD is assumed to already be opened as read only
164254721Semaste// and the STAT structure is assumed to a valid pointer and already
165254721Semaste// containing valid data from a call to stat().
166254721Semaste//
167254721Semaste// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
168254721Semaste// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
169254721Semaste// as possible.
170254721Semaste//
171254721Semaste// RETURNS
172254721Semaste//  Number of bytes mapped starting from the requested offset.
173254721Semaste//----------------------------------------------------------------------
174254721Semastesize_t
175254721SemasteDataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
176254721Semaste                                                  lldb::offset_t offset,
177254721Semaste                                                  lldb::offset_t length,
178254721Semaste                                                  bool writeable,
179254721Semaste                                                  bool fd_is_file)
180254721Semaste{
181254721Semaste    Clear();
182254721Semaste    if (fd >= 0)
183254721Semaste    {
184254721Semaste        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
185254721Semaste        if (log)
186254721Semaste        {
187263363Semaste#ifdef _WIN32
188263363Semaste            log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%p, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
189263363Semaste#else
190254721Semaste            log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
191263363Semaste#endif
192254721Semaste                        fd,
193254721Semaste                        offset,
194254721Semaste                        length,
195254721Semaste                        writeable,
196254721Semaste                        fd_is_file);
197254721Semaste        }
198263363Semaste#ifdef _WIN32
199263363Semaste        HANDLE handle = (HANDLE)_get_osfhandle(fd);
200263363Semaste        DWORD file_size_low, file_size_high;
201263363Semaste        file_size_low = GetFileSize(handle, &file_size_high);
202263363Semaste        const size_t file_size = (file_size_high << 32) | file_size_low;
203263363Semaste        const size_t max_bytes_available = file_size - offset;
204263363Semaste        if (length == SIZE_MAX)
205263363Semaste        {
206263363Semaste            length = max_bytes_available;
207263363Semaste        }
208263363Semaste        else if (length > max_bytes_available)
209263363Semaste        {
210263363Semaste            // Cap the length if too much data was requested
211263363Semaste            length = max_bytes_available;
212263363Semaste        }
213263363Semaste
214263363Semaste        if (length > 0)
215263363Semaste        {
216263363Semaste            HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL);
217263363Semaste            if (fileMapping != NULL)
218263363Semaste            {
219263363Semaste                if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
220263363Semaste                lldb::offset_t realoffset = offset;
221263363Semaste                lldb::offset_t delta = 0;
222263363Semaste                if (realoffset % win32memmapalignment != 0) {
223263363Semaste                  realoffset = realoffset / win32memmapalignment * win32memmapalignment;
224263363Semaste                  delta = offset - realoffset;
225263363Semaste	              }
226263363Semaste
227263363Semaste                LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
228263363Semaste                m_mmap_addr = (uint8_t *)data;
229263363Semaste                if (!data) {
230263363Semaste                  Error error;
231263363Semaste                  error.SetErrorToErrno ();
232263363Semaste                } else {
233263363Semaste                  m_data = m_mmap_addr + delta;
234263363Semaste                  m_size = length;
235263363Semaste                }
236263363Semaste                CloseHandle(fileMapping);
237263363Semaste            }
238263363Semaste        }
239263363Semaste#else
240254721Semaste        struct stat stat;
241254721Semaste        if (::fstat(fd, &stat) == 0)
242254721Semaste        {
243254721Semaste            if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
244254721Semaste            {
245254721Semaste                const size_t max_bytes_available = stat.st_size - offset;
246254721Semaste                if (length == SIZE_MAX)
247254721Semaste                {
248254721Semaste                    length = max_bytes_available;
249254721Semaste                }
250254721Semaste                else if (length > max_bytes_available)
251254721Semaste                {
252254721Semaste                    // Cap the length if too much data was requested
253254721Semaste                    length = max_bytes_available;
254254721Semaste                }
255254721Semaste
256254721Semaste                if (length > 0)
257254721Semaste                {
258254721Semaste                    int prot = PROT_READ;
259254721Semaste                    if (writeable)
260254721Semaste                        prot |= PROT_WRITE;
261254721Semaste
262254721Semaste                    int flags = MAP_PRIVATE;
263254721Semaste                    if (fd_is_file)
264254721Semaste                        flags |= MAP_FILE;
265254721Semaste
266254721Semaste                    m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
267254721Semaste                    Error error;
268254721Semaste
269254721Semaste                    if (m_mmap_addr == (void*)-1)
270254721Semaste                    {
271254721Semaste                        error.SetErrorToErrno ();
272254721Semaste                        if (error.GetError() == EINVAL)
273254721Semaste                        {
274254721Semaste                            // We may still have a shot at memory mapping if we align things correctly
275254721Semaste                            size_t page_offset = offset % Host::GetPageSize();
276254721Semaste                            if (page_offset != 0)
277254721Semaste                            {
278254721Semaste                                m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
279254721Semaste                                if (m_mmap_addr == (void*)-1)
280254721Semaste                                {
281254721Semaste                                    // Failed to map file
282254721Semaste                                    m_mmap_addr = NULL;
283254721Semaste                                }
284254721Semaste                                else if (m_mmap_addr != NULL)
285254721Semaste                                {
286254721Semaste                                    // We recovered and were able to memory map
287254721Semaste                                    // after we aligned things to page boundaries
288254721Semaste
289254721Semaste                                    // Save the actual mmap'ed size
290254721Semaste                                    m_mmap_size = length + page_offset;
291254721Semaste                                    // Our data is at an offset into the the mapped data
292254721Semaste                                    m_data = m_mmap_addr + page_offset;
293254721Semaste                                    // Our pretend size is the size that was requestd
294254721Semaste                                    m_size = length;
295254721Semaste                                }
296254721Semaste                            }
297254721Semaste                        }
298254721Semaste                        if (error.GetError() == ENOMEM)
299254721Semaste                        {
300254721Semaste                           error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
301254721Semaste                        }
302254721Semaste                    }
303254721Semaste                    else
304254721Semaste                    {
305254721Semaste                        // We were able to map the requested data in one chunk
306254721Semaste                        // where our mmap and actual data are the same.
307254721Semaste                        m_mmap_size = length;
308254721Semaste                        m_data = m_mmap_addr;
309254721Semaste                        m_size = length;
310254721Semaste                    }
311254721Semaste
312254721Semaste                    if (log)
313254721Semaste                    {
314254721Semaste                        log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s",
315254721Semaste                                    m_mmap_addr, m_mmap_size, error.AsCString());
316254721Semaste                    }
317254721Semaste                }
318254721Semaste            }
319254721Semaste        }
320263363Semaste#endif
321254721Semaste    }
322254721Semaste    return GetByteSize ();
323254721Semaste}
324