//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include #include #include #include #include #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/Error.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" using namespace lldb_private; //---------------------------------------------------------------------- // Default Constructor //---------------------------------------------------------------------- DataBufferMemoryMap::DataBufferMemoryMap() : m_mmap_addr(NULL), m_mmap_size(0), m_data(NULL), m_size(0) { } //---------------------------------------------------------------------- // Virtual destructor since this class inherits from a pure virtual // base class. //---------------------------------------------------------------------- DataBufferMemoryMap::~DataBufferMemoryMap() { Clear(); } //---------------------------------------------------------------------- // Return a pointer to the bytes owned by this object, or NULL if // the object contains no bytes. //---------------------------------------------------------------------- uint8_t * DataBufferMemoryMap::GetBytes() { return m_data; } //---------------------------------------------------------------------- // Return a const pointer to the bytes owned by this object, or NULL // if the object contains no bytes. //---------------------------------------------------------------------- const uint8_t * DataBufferMemoryMap::GetBytes() const { return m_data; } //---------------------------------------------------------------------- // Return the number of bytes this object currently contains. //---------------------------------------------------------------------- size_t DataBufferMemoryMap::GetByteSize() const { return m_size; } //---------------------------------------------------------------------- // Reverts this object to an empty state by unmapping any memory // that is currently owned. //---------------------------------------------------------------------- void DataBufferMemoryMap::Clear() { if (m_mmap_addr != NULL) { ::munmap((void *)m_mmap_addr, m_mmap_size); m_mmap_addr = NULL; m_mmap_size = 0; m_data = NULL; m_size = 0; } } //---------------------------------------------------------------------- // Memory map "length" bytes from "file" starting "offset" // bytes into the file. If "length" is set to SIZE_MAX, then // map as many bytes as possible. // // Returns the number of bytes mapped starting from the requested // offset. //---------------------------------------------------------------------- size_t DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* file, off_t offset, size_t length, bool writeable) { if (file != NULL) { char path[PATH_MAX]; if (file->GetPath(path, sizeof(path))) { int oflag = 0; if (writeable) oflag = O_RDWR; else oflag = O_RDONLY; int fd = ::open(path, oflag, 0); if (fd >= 0) { const bool fd_is_file = true; MemoryMapFromFileDescriptor (fd, offset, length, writeable, fd_is_file); ::close(fd); return GetByteSize(); } else { //error.SetErrorToErrno(); return 0; } } } // We should only get here if there was an error Clear(); return 0; } //---------------------------------------------------------------------- // The file descriptor FD is assumed to already be opened as read only // and the STAT structure is assumed to a valid pointer and already // containing valid data from a call to stat(). // // Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into // the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes // as possible. // // RETURNS // Number of bytes mapped starting from the requested offset. //---------------------------------------------------------------------- size_t DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, off_t offset, size_t length, bool writeable, bool fd_is_file) { Clear(); if (fd >= 0) { struct stat stat; if (::fstat(fd, &stat) == 0) { if (S_ISREG(stat.st_mode) && (stat.st_size > offset)) { const size_t max_bytes_available = stat.st_size - offset; if (length == SIZE_MAX) { length = max_bytes_available; } else if (length > max_bytes_available) { // Cap the length if too much data was requested length = max_bytes_available; } if (length > 0) { int prot = PROT_READ; if (writeable) prot |= PROT_WRITE; int flags = MAP_SHARED; if (fd_is_file) flags |= MAP_FILE; m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset); if (m_mmap_addr == (void*)-1) { Error error; error.SetErrorToErrno (); if (error.GetError() == EINVAL) { // We may still have a shot at memory mapping if we align things correctly size_t page_offset = offset % Host::GetPageSize(); if (page_offset != 0) { m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset); if (m_mmap_addr == (void*)-1) { // Failed to map file m_mmap_addr = NULL; } else if (m_mmap_addr != NULL) { // We recovered and were able to memory map // after we aligned things to page boundaries // Save the actual mmap'ed size m_mmap_size = length + page_offset; // Our data is at an offset into the the mapped data m_data = m_mmap_addr + page_offset; // Our pretend size is the size that was requestd m_size = length; } } } } else { // We were able to map the requested data in one chunk // where our mmap and actual data are the same. m_mmap_size = length; m_data = m_mmap_addr; m_size = length; } } } } ::close (fd); } return GetByteSize (); }