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