DataBufferMemoryMap.cpp revision 263363
131567Ssef//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===// 2204977Simp// 331899Ssef// The LLVM Compiler Infrastructure 431899Ssef// 531899Ssef// This file is distributed under the University of Illinois Open Source 631899Ssef// License. See LICENSE.TXT for details. 731899Ssef// 831899Ssef//===----------------------------------------------------------------------===// 931899Ssef 1031899Ssef 1131899Ssef#include <errno.h> 1231899Ssef#include <fcntl.h> 1331899Ssef#include <limits.h> 1431899Ssef#include <sys/stat.h> 1531899Ssef#ifdef _WIN32 1631899Ssef#include "lldb/Host/windows/windows.h" 1731899Ssef#else 1831899Ssef#include <sys/mman.h> 1931899Ssef#endif 2031899Ssef 2131899Ssef#include "lldb/Core/DataBufferMemoryMap.h" 2231899Ssef#include "lldb/Core/Error.h" 2331899Ssef#include "lldb/Host/File.h" 2431899Ssef#include "lldb/Host/FileSpec.h" 2531899Ssef#include "lldb/Host/Host.h" 2631899Ssef#include "lldb/Core/Log.h" 2731899Ssef#include "lldb/lldb-private-log.h" 2831899Ssef 2931899Ssefusing namespace lldb; 3031899Ssefusing namespace lldb_private; 3131899Ssef 32290052Sjhb//---------------------------------------------------------------------- 33290052Sjhb// Default Constructor 3432275Scharnier//---------------------------------------------------------------------- 35290052SjhbDataBufferMemoryMap::DataBufferMemoryMap() : 3632275Scharnier m_mmap_addr(NULL), 37168569Sdelphij m_mmap_size(0), 3885301Sdes m_data(NULL), 3985301Sdes m_size(0) 4085301Sdes{ 4185301Sdes} 4231567Ssef 4331567Ssef//---------------------------------------------------------------------- 44101282Smdodd// Virtual destructor since this class inherits from a pure virtual 4531567Ssef// base class. 46179051Sjhb//---------------------------------------------------------------------- 4731567SsefDataBufferMemoryMap::~DataBufferMemoryMap() 48290052Sjhb{ 49290052Sjhb Clear(); 50240562Szont} 51240005Szont 52290052Sjhb//---------------------------------------------------------------------- 53240562Szont// Return a pointer to the bytes owned by this object, or NULL if 5431567Ssef// the object contains no bytes. 55240562Szont//---------------------------------------------------------------------- 56290052Sjhbuint8_t * 57240562SzontDataBufferMemoryMap::GetBytes() 58240005Szont{ 59290052Sjhb return m_data; 60240005Szont} 6131567Ssef 62240005Szont//---------------------------------------------------------------------- 63240005Szont// Return a const pointer to the bytes owned by this object, or NULL 64240005Szont// if the object contains no bytes. 65240005Szont//---------------------------------------------------------------------- 66240005Szontconst uint8_t * 67240005SzontDataBufferMemoryMap::GetBytes() const 68240005Szont{ 69290052Sjhb return m_data; 70290052Sjhb} 71290052Sjhb 72290052Sjhb//---------------------------------------------------------------------- 73290052Sjhb// Return the number of bytes this object currently contains. 74290052Sjhb//---------------------------------------------------------------------- 75290052Sjhbuint64_t 76290052SjhbDataBufferMemoryMap::GetByteSize() const 77290052Sjhb{ 78290052Sjhb return m_size; 79290052Sjhb} 80290052Sjhb 81290052Sjhb//---------------------------------------------------------------------- 82240005Szont// Reverts this object to an empty state by unmapping any memory 8331567Ssef// that is currently owned. 84290052Sjhb//---------------------------------------------------------------------- 8531567Ssefvoid 8631567SsefDataBufferMemoryMap::Clear() 8731567Ssef{ 8831567Ssef if (m_mmap_addr != NULL) 8931567Ssef { 90228396Sed Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); 91240005Szont if (log) 92240005Szont log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size); 93240005Szont#ifdef _WIN32 94240005Szont UnmapViewOfFile(m_mmap_addr); 95240005Szont#else 9631567Ssef ::munmap((void *)m_mmap_addr, m_mmap_size); 9731567Ssef#endif 9831567Ssef m_mmap_addr = NULL; 99240005Szont m_mmap_size = 0; 10031567Ssef m_data = NULL; 10131567Ssef m_size = 0; 102290052Sjhb } 103290052Sjhb} 104290052Sjhb 105122348Smarcel//---------------------------------------------------------------------- 106240005Szont// Memory map "length" bytes from "file" starting "offset" 107240562Szont// bytes into the file. If "length" is set to SIZE_MAX, then 108290052Sjhb// map as many bytes as possible. 10931567Ssef// 110240562Szont// Returns the number of bytes mapped starting from the requested 111240562Szont// offset. 112240005Szont//---------------------------------------------------------------------- 113240005Szontsize_t 114240005SzontDataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec, 11531567Ssef lldb::offset_t offset, 116290052Sjhb lldb::offset_t length, 117290052Sjhb bool writeable) 118290052Sjhb{ 119296010Sjhb if (filespec != NULL) 120296010Sjhb { 121101374Smdodd Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); 122290052Sjhb if (log) 123290052Sjhb { 124290052Sjhb log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i", 125290052Sjhb filespec->GetPath().c_str(), 126290052Sjhb offset, 127240005Szont length, 128240005Szont writeable); 129171055Sdelphij } 130290052Sjhb char path[PATH_MAX]; 131240005Szont if (filespec->GetPath(path, sizeof(path))) 132290052Sjhb { 133290052Sjhb uint32_t options = File::eOpenOptionRead; 134171055Sdelphij if (writeable) 135290052Sjhb options |= File::eOpenOptionWrite; 136290052Sjhb 137290052Sjhb File file; 138290052Sjhb Error error (file.Open(path, options)); 139290052Sjhb if (error.Success()) 140290052Sjhb { 141290052Sjhb const bool fd_is_file = true; 142101282Smdodd return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file); 143290052Sjhb } 144 } 145 } 146 // We should only get here if there was an error 147 Clear(); 148 return 0; 149} 150 151 152#ifdef _WIN32 153static size_t win32memmapalignment = 0; 154void LoadWin32MemMapAlignment () 155{ 156 SYSTEM_INFO data; 157 GetSystemInfo(&data); 158 win32memmapalignment = data.dwAllocationGranularity; 159} 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//---------------------------------------------------------------------- 174size_t 175DataBufferMemoryMap::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(); 220 lldb::offset_t realoffset = offset; 221 lldb::offset_t delta = 0; 222 if (realoffset % win32memmapalignment != 0) { 223 realoffset = realoffset / win32memmapalignment * win32memmapalignment; 224 delta = offset - realoffset; 225 } 226 227 LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta); 228 m_mmap_addr = (uint8_t *)data; 229 if (!data) { 230 Error error; 231 error.SetErrorToErrno (); 232 } else { 233 m_data = m_mmap_addr + delta; 234 m_size = length; 235 } 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} 324