LCOV - code coverage report
Current view: top level - src/base/platform - platform-linux.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 42 78 53.8 %
Date: 2017-10-20 Functions: 9 11 81.8 %

          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             : #include <cmath>
      39             : 
      40             : #undef MAP_TYPE
      41             : 
      42             : #include "src/base/macros.h"
      43             : #include "src/base/platform/platform-posix-time.h"
      44             : #include "src/base/platform/platform-posix.h"
      45             : #include "src/base/platform/platform.h"
      46             : 
      47             : namespace v8 {
      48             : namespace base {
      49             : 
      50             : #ifdef __arm__
      51             : 
      52             : bool OS::ArmUsingHardFloat() {
      53             : // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
      54             : // the Floating Point ABI used (PCS stands for Procedure Call Standard).
      55             : // We use these as well as a couple of other defines to statically determine
      56             : // what FP ABI used.
      57             : // GCC versions 4.4 and below don't support hard-fp.
      58             : // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
      59             : // __ARM_PCS_VFP.
      60             : 
      61             : #define GCC_VERSION \
      62             :   (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
      63             : #if GCC_VERSION >= 40600 && !defined(__clang__)
      64             : #if defined(__ARM_PCS_VFP)
      65             :   return true;
      66             : #else
      67             :   return false;
      68             : #endif
      69             : 
      70             : #elif GCC_VERSION < 40500 && !defined(__clang__)
      71             :   return false;
      72             : 
      73             : #else
      74             : #if defined(__ARM_PCS_VFP)
      75             :   return true;
      76             : #elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
      77             :     !defined(__VFP_FP__)
      78             :   return false;
      79             : #else
      80             : #error \
      81             :     "Your version of compiler does not report the FP ABI compiled for."     \
      82             :        "Please report it on this issue"                                        \
      83             :        "http://code.google.com/p/v8/issues/detail?id=2140"
      84             : 
      85             : #endif
      86             : #endif
      87             : #undef GCC_VERSION
      88             : }
      89             : 
      90             : #endif  // def __arm__
      91             : 
      92       54993 : TimezoneCache* OS::CreateTimezoneCache() {
      93      109986 :   return new PosixDefaultTimezoneCache();
      94             : }
      95             : 
      96             : // Constants used for mmap.
      97             : static const int kMmapFd = -1;
      98             : static const int kMmapFdOffset = 0;
      99             : 
     100         207 : void* OS::Allocate(const size_t requested, size_t* allocated,
     101             :                    OS::MemoryPermission access, void* hint) {
     102         207 :   const size_t msize = RoundUp(requested, AllocateAlignment());
     103         207 :   int prot = GetProtectionFromMemoryPermission(access);
     104             :   void* mbase = mmap(hint, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, kMmapFd,
     105         207 :                      kMmapFdOffset);
     106         207 :   if (mbase == MAP_FAILED) return nullptr;
     107         207 :   *allocated = msize;
     108         207 :   return mbase;
     109             : }
     110             : 
     111             : // static
     112      555566 : void* OS::ReserveRegion(size_t size, void* hint) {
     113             :   void* result =
     114             :       mmap(hint, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
     115      555566 :            kMmapFd, kMmapFdOffset);
     116             : 
     117      555568 :   if (result == MAP_FAILED) return nullptr;
     118      555544 :   return result;
     119             : }
     120             : 
     121             : // static
     122      494817 : void* OS::ReserveAlignedRegion(size_t size, size_t alignment, void* hint,
     123             :                                size_t* allocated) {
     124             :   DCHECK_EQ(alignment % OS::AllocateAlignment(), 0);
     125             :   hint = AlignedAddress(hint, alignment);
     126             :   size_t request_size =
     127      494817 :       RoundUp(size + alignment, static_cast<intptr_t>(OS::AllocateAlignment()));
     128      494820 :   void* result = ReserveRegion(request_size, hint);
     129      494821 :   if (result == nullptr) {
     130          12 :     *allocated = 0;
     131          12 :     return nullptr;
     132             :   }
     133             : 
     134             :   uint8_t* base = static_cast<uint8_t*>(result);
     135      494809 :   uint8_t* aligned_base = RoundUp(base, alignment);
     136             :   DCHECK_LE(base, aligned_base);
     137             : 
     138             :   // Unmap extra memory reserved before and after the desired block.
     139      494809 :   if (aligned_base != base) {
     140           1 :     size_t prefix_size = static_cast<size_t>(aligned_base - base);
     141           1 :     OS::Free(base, prefix_size);
     142           1 :     request_size -= prefix_size;
     143             :   }
     144             : 
     145      494809 :   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
     146             :   DCHECK_LE(aligned_size, request_size);
     147             : 
     148      494809 :   if (aligned_size != request_size) {
     149      494809 :     size_t suffix_size = request_size - aligned_size;
     150      494809 :     OS::Free(aligned_base + aligned_size, suffix_size);
     151             :     request_size -= suffix_size;
     152             :   }
     153             : 
     154             :   DCHECK(aligned_size == request_size);
     155             : 
     156      494809 :   *allocated = aligned_size;
     157      494809 :   return static_cast<void*>(aligned_base);
     158             : }
     159             : 
     160             : // static
     161     1171369 : bool OS::CommitRegion(void* address, size_t size, bool is_executable) {
     162     1171369 :   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
     163     1171369 :   if (MAP_FAILED == mmap(address, size, prot,
     164             :                          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, kMmapFd,
     165     1171369 :                          kMmapFdOffset)) {
     166             :     return false;
     167             :   }
     168             : 
     169     1171369 :   return true;
     170             : }
     171             : 
     172             : // static
     173      481250 : bool OS::UncommitRegion(void* address, size_t size) {
     174             :   return mmap(address, size, PROT_NONE,
     175             :               MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, kMmapFd,
     176      481250 :               kMmapFdOffset) != MAP_FAILED;
     177             : }
     178             : 
     179             : // static
     180      540418 : bool OS::ReleaseRegion(void* address, size_t size) {
     181      540418 :   return munmap(address, size) == 0;
     182             : }
     183             : 
     184             : // static
     185      109926 : bool OS::ReleasePartialRegion(void* address, size_t size) {
     186      109926 :   return munmap(address, size) == 0;
     187             : }
     188             : 
     189             : // static
     190        4127 : bool OS::HasLazyCommits() { return true; }
     191             : 
     192           0 : std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
     193             :   std::vector<SharedLibraryAddress> result;
     194             :   // This function assumes that the layout of the file is as follows:
     195             :   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
     196             :   // If we encounter an unexpected situation we abort scanning further entries.
     197           0 :   FILE* fp = fopen("/proc/self/maps", "r");
     198           0 :   if (fp == nullptr) return result;
     199             : 
     200             :   // Allocate enough room to be able to store a full file name.
     201             :   const int kLibNameLen = FILENAME_MAX + 1;
     202           0 :   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
     203             : 
     204             :   // This loop will terminate once the scanning hits an EOF.
     205             :   while (true) {
     206             :     uintptr_t start, end, offset;
     207             :     char attr_r, attr_w, attr_x, attr_p;
     208             :     // Parse the addresses and permission bits at the beginning of the line.
     209           0 :     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
     210           0 :     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
     211           0 :     if (fscanf(fp, "%" V8PRIxPTR, &offset) != 1) break;
     212             : 
     213             :     // Adjust {start} based on {offset}.
     214           0 :     start -= offset;
     215             : 
     216             :     int c;
     217           0 :     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
     218             :       // Found a read-only executable entry. Skip characters until we reach
     219             :       // the beginning of the filename or the end of the line.
     220           0 :       do {
     221           0 :         c = getc(fp);
     222           0 :       } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
     223           0 :       if (c == EOF) break;  // EOF: Was unexpected, just exit.
     224             : 
     225             :       // Process the filename if found.
     226           0 :       if ((c == '/') || (c == '[')) {
     227             :         // Push the '/' or '[' back into the stream to be read below.
     228           0 :         ungetc(c, fp);
     229             : 
     230             :         // Read to the end of the line. Exit if the read fails.
     231           0 :         if (fgets(lib_name, kLibNameLen, fp) == nullptr) break;
     232             : 
     233             :         // Drop the newline character read by fgets. We do not need to check
     234             :         // for a zero-length string because we know that we at least read the
     235             :         // '/' or '[' character.
     236           0 :         lib_name[strlen(lib_name) - 1] = '\0';
     237             :       } else {
     238             :         // No library name found, just record the raw address range.
     239             :         snprintf(lib_name, kLibNameLen, "%08" V8PRIxPTR "-%08" V8PRIxPTR, start,
     240           0 :                  end);
     241             :       }
     242           0 :       result.push_back(SharedLibraryAddress(lib_name, start, end));
     243             :     } else {
     244             :       // Entry not describing executable data. Skip to end of line to set up
     245             :       // reading the next entry.
     246           0 :       do {
     247           0 :         c = getc(fp);
     248           0 :       } while ((c != EOF) && (c != '\n'));
     249           0 :       if (c == EOF) break;
     250             :     }
     251             :   }
     252           0 :   free(lib_name);
     253           0 :   fclose(fp);
     254           0 :   return result;
     255             : }
     256             : 
     257           0 : void OS::SignalCodeMovingGC() {
     258             :   // Support for ll_prof.py.
     259             :   //
     260             :   // The Linux profiler built into the kernel logs all mmap's with
     261             :   // PROT_EXEC so that analysis tools can properly attribute ticks. We
     262             :   // do a mmap with a name known by ll_prof.py and immediately munmap
     263             :   // it. This injects a GC marker into the stream of events generated
     264             :   // by the kernel and allows us to synchronize V8 code log and the
     265             :   // kernel log.
     266           0 :   long size = sysconf(_SC_PAGESIZE);  // NOLINT(runtime/int)
     267           0 :   FILE* f = fopen(OS::GetGCFakeMMapFile(), "w+");
     268           0 :   if (f == nullptr) {
     269           0 :     OS::PrintError("Failed to open %s\n", OS::GetGCFakeMMapFile());
     270           0 :     OS::Abort();
     271             :   }
     272             :   void* addr = mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_EXEC,
     273           0 :                     MAP_PRIVATE, fileno(f), 0);
     274             :   DCHECK_NE(MAP_FAILED, addr);
     275           0 :   OS::Free(addr, size);
     276           0 :   fclose(f);
     277           0 : }
     278             : 
     279             : }  // namespace base
     280             : }  // namespace v8

Generated by: LCOV version 1.10