Home | History | Annotate | Download | only in linux
      1 // Copyright (c) 2011, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile.
     31 // See memory_mapped_file.h for details.
     32 
     33 #include "common/linux/memory_mapped_file.h"
     34 
     35 #include <fcntl.h>
     36 #include <sys/mman.h>
     37 #if defined(__ANDROID__)
     38 #include <sys/stat.h>
     39 #endif
     40 #include <unistd.h>
     41 
     42 #include "common/memory_range.h"
     43 #include "third_party/lss/linux_syscall_support.h"
     44 
     45 namespace google_breakpad {
     46 
     47 MemoryMappedFile::MemoryMappedFile() {}
     48 
     49 MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) {
     50   Map(path, offset);
     51 }
     52 
     53 MemoryMappedFile::~MemoryMappedFile() {
     54   Unmap();
     55 }
     56 
     57 #include <unistd.h>
     58 
     59 bool MemoryMappedFile::Map(const char* path, size_t offset) {
     60   Unmap();
     61 
     62   int fd = sys_open(path, O_RDONLY, 0);
     63   if (fd == -1) {
     64     return false;
     65   }
     66 
     67 #if defined(__x86_64__) || defined(__aarch64__) || \
     68    (defined(__mips__) && _MIPS_SIM == _ABI64)
     69 
     70   struct kernel_stat st;
     71   if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
     72 #else
     73   struct kernel_stat64 st;
     74   if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) {
     75 #endif
     76     sys_close(fd);
     77     return false;
     78   }
     79 
     80   // Strangely file size can be negative, but we check above that it is not.
     81   size_t file_len = static_cast<size_t>(st.st_size);
     82   // If the file does not extend beyond the offset, simply use an empty
     83   // MemoryRange and return true. Don't bother to call mmap()
     84   // even though mmap() can handle an empty file on some platforms.
     85   if (offset >= file_len) {
     86     sys_close(fd);
     87     return true;
     88   }
     89 
     90 #if defined(__x86_64__) || defined(__aarch64__) || \
     91    (defined(__mips__) && _MIPS_SIM == _ABI64)
     92   void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset);
     93 #else
     94   if ((offset & 4095) != 0) {
     95     // Not page aligned.
     96     sys_close(fd);
     97     return false;
     98   }
     99   void* data = sys_mmap2(
    100       NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset >> 12);
    101 #endif
    102   sys_close(fd);
    103   if (data == MAP_FAILED) {
    104     return false;
    105   }
    106 
    107   content_.Set(data, file_len - offset);
    108   return true;
    109 }
    110 
    111 void MemoryMappedFile::Unmap() {
    112   if (content_.data()) {
    113     sys_munmap(const_cast<uint8_t*>(content_.data()), content_.length());
    114     content_.Set(NULL, 0);
    115   }
    116 }
    117 
    118 }  // namespace google_breakpad
    119