LCOV - code coverage report
Current view: top level - src/base/platform - platform-linux.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 62 96 64.6 %
Date: 2017-04-26 Functions: 17 19 89.5 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : // Platform-specific code for Linux goes here. For the POSIX-compatible
       6             : // parts, the implementation is in platform-posix.cc.
       7             : 
       8             : #include <pthread.h>
       9             : #include <semaphore.h>
      10             : #include <signal.h>
      11             : #include <stdio.h>
      12             : #include <stdlib.h>
      13             : #include <sys/prctl.h>
      14             : #include <sys/resource.h>
      15             : #include <sys/syscall.h>
      16             : #include <sys/time.h>
      17             : 
      18             : // Ubuntu Dapper requires memory pages to be marked as
      19             : // executable. Otherwise, OS raises an exception when executing code
      20             : // in that page.
      21             : #include <errno.h>
      22             : #include <fcntl.h>  // open
      23             : #include <stdarg.h>
      24             : #include <strings.h>    // index
      25             : #include <sys/mman.h>   // mmap & munmap
      26             : #include <sys/stat.h>   // open
      27             : #include <sys/types.h>  // mmap & munmap
      28             : #include <unistd.h>     // sysconf
      29             : 
      30             : // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
      31             : // Old versions of the C library <signal.h> didn't define the type.
      32             : #if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
      33             :     (defined(__arm__) || defined(__aarch64__)) &&                 \
      34             :     !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
      35             : #include <asm/sigcontext.h>  // NOLINT
      36             : #endif
      37             : 
      38             : #if defined(LEAK_SANITIZER)
      39             : #include <sanitizer/lsan_interface.h>
      40             : #endif
      41             : 
      42             : #include <cmath>
      43             : 
      44             : #undef MAP_TYPE
      45             : 
      46             : #include "src/base/macros.h"
      47             : #include "src/base/platform/platform-posix.h"
      48             : #include "src/base/platform/platform.h"
      49             : 
      50             : namespace v8 {
      51             : namespace base {
      52             : 
      53             : #ifdef __arm__
      54             : 
      55             : bool OS::ArmUsingHardFloat() {
      56             : // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
      57             : // the Floating Point ABI used (PCS stands for Procedure Call Standard).
      58             : // We use these as well as a couple of other defines to statically determine
      59             : // what FP ABI used.
      60             : // GCC versions 4.4 and below don't support hard-fp.
      61             : // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
      62             : // __ARM_PCS_VFP.
      63             : 
      64             : #define GCC_VERSION \
      65             :   (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
      66             : #if GCC_VERSION >= 40600 && !defined(__clang__)
      67             : #if defined(__ARM_PCS_VFP)
      68             :   return true;
      69             : #else
      70             :   return false;
      71             : #endif
      72             : 
      73             : #elif GCC_VERSION < 40500 && !defined(__clang__)
      74             :   return false;
      75             : 
      76             : #else
      77             : #if defined(__ARM_PCS_VFP)
      78             :   return true;
      79             : #elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
      80             :     !defined(__VFP_FP__)
      81             :   return false;
      82             : #else
      83             : #error \
      84             :     "Your version of compiler does not report the FP ABI compiled for."     \
      85             :        "Please report it on this issue"                                        \
      86             :        "http://code.google.com/p/v8/issues/detail?id=2140"
      87             : 
      88             : #endif
      89             : #endif
      90             : #undef GCC_VERSION
      91             : }
      92             : 
      93             : #endif  // def __arm__
      94             : 
      95      121550 : TimezoneCache* OS::CreateTimezoneCache() { return new PosixTimezoneCache(); }
      96             : 
      97        1733 : void* OS::Allocate(const size_t requested, size_t* allocated,
      98             :                    bool is_executable) {
      99        1733 :   const size_t msize = RoundUp(requested, AllocateAlignment());
     100        1733 :   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
     101        1733 :   void* addr = OS::GetRandomMmapAddr();
     102        1733 :   void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     103        1733 :   if (mbase == MAP_FAILED) return NULL;
     104        1733 :   *allocated = msize;
     105        1733 :   return mbase;
     106             : }
     107             : 
     108           0 : std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
     109             :   std::vector<SharedLibraryAddress> result;
     110             :   // This function assumes that the layout of the file is as follows:
     111             :   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
     112             :   // If we encounter an unexpected situation we abort scanning further entries.
     113           0 :   FILE* fp = fopen("/proc/self/maps", "r");
     114           0 :   if (fp == NULL) return result;
     115             : 
     116             :   // Allocate enough room to be able to store a full file name.
     117             :   const int kLibNameLen = FILENAME_MAX + 1;
     118           0 :   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
     119             : 
     120             :   // This loop will terminate once the scanning hits an EOF.
     121             :   while (true) {
     122             :     uintptr_t start, end;
     123             :     char attr_r, attr_w, attr_x, attr_p;
     124             :     // Parse the addresses and permission bits at the beginning of the line.
     125           0 :     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
     126           0 :     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
     127             : 
     128             :     int c;
     129           0 :     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
     130             :       // Found a read-only executable entry. Skip characters until we reach
     131             :       // the beginning of the filename or the end of the line.
     132           0 :       do {
     133           0 :         c = getc(fp);
     134           0 :       } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
     135           0 :       if (c == EOF) break;  // EOF: Was unexpected, just exit.
     136             : 
     137             :       // Process the filename if found.
     138           0 :       if ((c == '/') || (c == '[')) {
     139             :         // Push the '/' or '[' back into the stream to be read below.
     140           0 :         ungetc(c, fp);
     141             : 
     142             :         // Read to the end of the line. Exit if the read fails.
     143           0 :         if (fgets(lib_name, kLibNameLen, fp) == NULL) break;
     144             : 
     145             :         // Drop the newline character read by fgets. We do not need to check
     146             :         // for a zero-length string because we know that we at least read the
     147             :         // '/' or '[' character.
     148           0 :         lib_name[strlen(lib_name) - 1] = '\0';
     149             :       } else {
     150             :         // No library name found, just record the raw address range.
     151             :         snprintf(lib_name, kLibNameLen, "%08" V8PRIxPTR "-%08" V8PRIxPTR, start,
     152           0 :                  end);
     153             :       }
     154           0 :       result.push_back(SharedLibraryAddress(lib_name, start, end));
     155             :     } else {
     156             :       // Entry not describing executable data. Skip to end of line to set up
     157             :       // reading the next entry.
     158           0 :       do {
     159           0 :         c = getc(fp);
     160           0 :       } while ((c != EOF) && (c != '\n'));
     161           0 :       if (c == EOF) break;
     162             :     }
     163             :   }
     164           0 :   free(lib_name);
     165           0 :   fclose(fp);
     166           0 :   return result;
     167             : }
     168             : 
     169           0 : void OS::SignalCodeMovingGC() {
     170             :   // Support for ll_prof.py.
     171             :   //
     172             :   // The Linux profiler built into the kernel logs all mmap's with
     173             :   // PROT_EXEC so that analysis tools can properly attribute ticks. We
     174             :   // do a mmap with a name known by ll_prof.py and immediately munmap
     175             :   // it. This injects a GC marker into the stream of events generated
     176             :   // by the kernel and allows us to synchronize V8 code log and the
     177             :   // kernel log.
     178           0 :   long size = sysconf(_SC_PAGESIZE);  // NOLINT(runtime/int)
     179           0 :   FILE* f = fopen(OS::GetGCFakeMMapFile(), "w+");
     180           0 :   if (f == NULL) {
     181           0 :     OS::PrintError("Failed to open %s\n", OS::GetGCFakeMMapFile());
     182           0 :     OS::Abort();
     183             :   }
     184             :   void* addr = mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_EXEC,
     185           0 :                     MAP_PRIVATE, fileno(f), 0);
     186             :   DCHECK_NE(MAP_FAILED, addr);
     187           0 :   OS::Free(addr, size);
     188           0 :   fclose(f);
     189           0 : }
     190             : 
     191             : // Constants used for mmap.
     192             : static const int kMmapFd = -1;
     193             : static const int kMmapFdOffset = 0;
     194             : 
     195     1911319 : VirtualMemory::VirtualMemory() : address_(NULL), size_(0) {}
     196             : 
     197      121578 : VirtualMemory::VirtualMemory(size_t size)
     198      121578 :     : address_(ReserveRegion(size)), size_(size) {}
     199             : 
     200      544411 : VirtualMemory::VirtualMemory(size_t size, size_t alignment)
     201      544411 :     : address_(NULL), size_(0) {
     202             :   DCHECK((alignment % OS::AllocateAlignment()) == 0);
     203             :   size_t request_size =
     204      544411 :       RoundUp(size + alignment, static_cast<intptr_t>(OS::AllocateAlignment()));
     205             :   void* reservation =
     206             :       mmap(OS::GetRandomMmapAddr(), request_size, PROT_NONE,
     207      544412 :            MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, kMmapFd, kMmapFdOffset);
     208     1088826 :   if (reservation == MAP_FAILED) return;
     209             : 
     210             :   uint8_t* base = static_cast<uint8_t*>(reservation);
     211      544413 :   uint8_t* aligned_base = RoundUp(base, alignment);
     212             :   DCHECK_LE(base, aligned_base);
     213             : 
     214             :   // Unmap extra memory reserved before and after the desired block.
     215      544413 :   if (aligned_base != base) {
     216      479787 :     size_t prefix_size = static_cast<size_t>(aligned_base - base);
     217      479787 :     OS::Free(base, prefix_size);
     218      479787 :     request_size -= prefix_size;
     219             :   }
     220             : 
     221      544413 :   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
     222             :   DCHECK_LE(aligned_size, request_size);
     223             : 
     224      544413 :   if (aligned_size != request_size) {
     225      544413 :     size_t suffix_size = request_size - aligned_size;
     226      544413 :     OS::Free(aligned_base + aligned_size, suffix_size);
     227             :     request_size -= suffix_size;
     228             :   }
     229             : 
     230             :   DCHECK(aligned_size == request_size);
     231             : 
     232      544413 :   address_ = static_cast<void*>(aligned_base);
     233      544413 :   size_ = aligned_size;
     234             : #if defined(LEAK_SANITIZER)
     235             :   __lsan_register_root_region(address_, size_);
     236             : #endif
     237             : }
     238             : 
     239     2882267 : VirtualMemory::~VirtualMemory() {
     240     2700856 :   if (IsReserved()) {
     241             :     bool result = ReleaseRegion(address(), size());
     242             :     DCHECK(result);
     243             :     USE(result);
     244             :   }
     245     2700856 : }
     246             : 
     247     4945791 : bool VirtualMemory::IsReserved() { return address_ != NULL; }
     248             : 
     249     3061413 : void VirtualMemory::Reset() {
     250     3061413 :   address_ = NULL;
     251     3061413 :   size_ = 0;
     252     3061413 : }
     253             : 
     254     1405019 : bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
     255     1405019 :   CHECK(InVM(address, size));
     256     1405019 :   return CommitRegion(address, size, is_executable);
     257             : }
     258             : 
     259      449071 : bool VirtualMemory::Uncommit(void* address, size_t size) {
     260      449071 :   CHECK(InVM(address, size));
     261      449072 :   return UncommitRegion(address, size);
     262             : }
     263             : 
     264      811736 : bool VirtualMemory::Guard(void* address) {
     265     1623472 :   CHECK(InVM(address, OS::CommitPageSize()));
     266      811736 :   OS::Guard(address, OS::CommitPageSize());
     267      811736 :   return true;
     268             : }
     269             : 
     270      129826 : void* VirtualMemory::ReserveRegion(size_t size) {
     271             :   void* result =
     272             :       mmap(OS::GetRandomMmapAddr(), size, PROT_NONE,
     273      129826 :            MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, kMmapFd, kMmapFdOffset);
     274             : 
     275      129826 :   if (result == MAP_FAILED) return NULL;
     276             : 
     277             : #if defined(LEAK_SANITIZER)
     278             :   __lsan_register_root_region(result, size);
     279             : #endif
     280      129826 :   return result;
     281             : }
     282             : 
     283     1432869 : bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
     284     1432869 :   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
     285     1432870 :   if (MAP_FAILED == mmap(base, size, prot,
     286             :                          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, kMmapFd,
     287     1432869 :                          kMmapFdOffset)) {
     288             :     return false;
     289             :   }
     290             : 
     291     1432870 :   return true;
     292             : }
     293             : 
     294      365188 : bool VirtualMemory::UncommitRegion(void* base, size_t size) {
     295             :   return mmap(base, size, PROT_NONE,
     296             :               MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, kMmapFd,
     297      814259 :               kMmapFdOffset) != MAP_FAILED;
     298             : }
     299             : 
     300          37 : bool VirtualMemory::ReleasePartialRegion(void* base, size_t size,
     301             :                                          void* free_start, size_t free_size) {
     302             : #if defined(LEAK_SANITIZER)
     303             :   __lsan_unregister_root_region(base, size);
     304             :   __lsan_register_root_region(base, size - free_size);
     305             : #endif
     306          37 :   return munmap(free_start, free_size) == 0;
     307             : }
     308             : 
     309      476247 : bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
     310             : #if defined(LEAK_SANITIZER)
     311             :   __lsan_unregister_root_region(base, size);
     312             : #endif
     313      657658 :   return munmap(base, size) == 0;
     314             : }
     315             : 
     316        1579 : bool VirtualMemory::HasLazyCommits() { return true; }
     317             : 
     318             : }  // namespace base
     319             : }  // namespace v8

Generated by: LCOV version 1.10