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 #include <sys/mman.h> 16 17 #include "lldb/Core/DataBufferMemoryMap.h" 18 #include "lldb/Core/Error.h" 19 #include "lldb/Host/File.h" 20 #include "lldb/Host/FileSpec.h" 21 #include "lldb/Host/Host.h" 22 #include "lldb/Core/Log.h" 23 #include "lldb/lldb-private-log.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 //---------------------------------------------------------------------- 29 // Default Constructor 30 //---------------------------------------------------------------------- 31 DataBufferMemoryMap::DataBufferMemoryMap() : 32 m_mmap_addr(NULL), 33 m_mmap_size(0), 34 m_data(NULL), 35 m_size(0) 36 { 37 } 38 39 //---------------------------------------------------------------------- 40 // Virtual destructor since this class inherits from a pure virtual 41 // base class. 42 //---------------------------------------------------------------------- 43 DataBufferMemoryMap::~DataBufferMemoryMap() 44 { 45 Clear(); 46 } 47 48 //---------------------------------------------------------------------- 49 // Return a pointer to the bytes owned by this object, or NULL if 50 // the object contains no bytes. 51 //---------------------------------------------------------------------- 52 uint8_t * 53 DataBufferMemoryMap::GetBytes() 54 { 55 return m_data; 56 } 57 58 //---------------------------------------------------------------------- 59 // Return a const pointer to the bytes owned by this object, or NULL 60 // if the object contains no bytes. 61 //---------------------------------------------------------------------- 62 const uint8_t * 63 DataBufferMemoryMap::GetBytes() const 64 { 65 return m_data; 66 } 67 68 //---------------------------------------------------------------------- 69 // Return the number of bytes this object currently contains. 70 //---------------------------------------------------------------------- 71 uint64_t 72 DataBufferMemoryMap::GetByteSize() const 73 { 74 return m_size; 75 } 76 77 //---------------------------------------------------------------------- 78 // Reverts this object to an empty state by unmapping any memory 79 // that is currently owned. 80 //---------------------------------------------------------------------- 81 void 82 DataBufferMemoryMap::Clear() 83 { 84 if (m_mmap_addr != NULL) 85 { 86 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); 87 if (log) 88 log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size); 89 ::munmap((void *)m_mmap_addr, m_mmap_size); 90 m_mmap_addr = NULL; 91 m_mmap_size = 0; 92 m_data = NULL; 93 m_size = 0; 94 } 95 } 96 97 //---------------------------------------------------------------------- 98 // Memory map "length" bytes from "file" starting "offset" 99 // bytes into the file. If "length" is set to SIZE_MAX, then 100 // map as many bytes as possible. 101 // 102 // Returns the number of bytes mapped starting from the requested 103 // offset. 104 //---------------------------------------------------------------------- 105 size_t 106 DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec, 107 lldb::offset_t offset, 108 lldb::offset_t length, 109 bool writeable) 110 { 111 if (filespec != NULL) 112 { 113 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); 114 if (log) 115 { 116 log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i", 117 filespec->GetPath().c_str(), 118 offset, 119 length, 120 writeable); 121 } 122 char path[PATH_MAX]; 123 if (filespec->GetPath(path, sizeof(path))) 124 { 125 uint32_t options = File::eOpenOptionRead; 126 if (writeable) 127 options |= File::eOpenOptionWrite; 128 129 File file; 130 Error error (file.Open(path, options)); 131 if (error.Success()) 132 { 133 const bool fd_is_file = true; 134 return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file); 135 } 136 } 137 } 138 // We should only get here if there was an error 139 Clear(); 140 return 0; 141 } 142 143 144 //---------------------------------------------------------------------- 145 // The file descriptor FD is assumed to already be opened as read only 146 // and the STAT structure is assumed to a valid pointer and already 147 // containing valid data from a call to stat(). 148 // 149 // Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into 150 // the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes 151 // as possible. 152 // 153 // RETURNS 154 // Number of bytes mapped starting from the requested offset. 155 //---------------------------------------------------------------------- 156 size_t 157 DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, 158 lldb::offset_t offset, 159 lldb::offset_t length, 160 bool writeable, 161 bool fd_is_file) 162 { 163 Clear(); 164 if (fd >= 0) 165 { 166 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE)); 167 if (log) 168 { 169 log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)", 170 fd, 171 offset, 172 length, 173 writeable, 174 fd_is_file); 175 } 176 struct stat stat; 177 if (::fstat(fd, &stat) == 0) 178 { 179 if (S_ISREG(stat.st_mode) && (stat.st_size > offset)) 180 { 181 const size_t max_bytes_available = stat.st_size - offset; 182 if (length == SIZE_MAX) 183 { 184 length = max_bytes_available; 185 } 186 else if (length > max_bytes_available) 187 { 188 // Cap the length if too much data was requested 189 length = max_bytes_available; 190 } 191 192 if (length > 0) 193 { 194 int prot = PROT_READ; 195 if (writeable) 196 prot |= PROT_WRITE; 197 198 int flags = MAP_PRIVATE; 199 if (fd_is_file) 200 flags |= MAP_FILE; 201 202 m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset); 203 Error error; 204 205 if (m_mmap_addr == (void*)-1) 206 { 207 error.SetErrorToErrno (); 208 if (error.GetError() == EINVAL) 209 { 210 // We may still have a shot at memory mapping if we align things correctly 211 size_t page_offset = offset % Host::GetPageSize(); 212 if (page_offset != 0) 213 { 214 m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset); 215 if (m_mmap_addr == (void*)-1) 216 { 217 // Failed to map file 218 m_mmap_addr = NULL; 219 } 220 else if (m_mmap_addr != NULL) 221 { 222 // We recovered and were able to memory map 223 // after we aligned things to page boundaries 224 225 // Save the actual mmap'ed size 226 m_mmap_size = length + page_offset; 227 // Our data is at an offset into the the mapped data 228 m_data = m_mmap_addr + page_offset; 229 // Our pretend size is the size that was requestd 230 m_size = length; 231 } 232 } 233 } 234 if (error.GetError() == ENOMEM) 235 { 236 error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length); 237 } 238 } 239 else 240 { 241 // We were able to map the requested data in one chunk 242 // where our mmap and actual data are the same. 243 m_mmap_size = length; 244 m_data = m_mmap_addr; 245 m_size = length; 246 } 247 248 if (log) 249 { 250 log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s", 251 m_mmap_addr, m_mmap_size, error.AsCString()); 252 } 253 } 254 } 255 } 256 } 257 return GetByteSize (); 258 } 259