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 & mremap
26 #include <sys/stat.h>   // open
27 #include <sys/types.h>  // mmap & munmap
28 #include <unistd.h>     // sysconf
29 
30 #include <cmath>
31 
32 #undef MAP_TYPE
33 
34 #include "src/base/macros.h"
35 #include "src/base/platform/platform-posix-time.h"
36 #include "src/base/platform/platform-posix.h"
37 #include "src/base/platform/platform.h"
38 
39 namespace v8 {
40 namespace base {
41 
CreateTimezoneCache()42 TimezoneCache* OS::CreateTimezoneCache() {
43   return new PosixDefaultTimezoneCache();
44 }
45 
GetSharedLibraryAddresses()46 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
47   std::vector<SharedLibraryAddress> result;
48   // This function assumes that the layout of the file is as follows:
49   // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name]
50   // If we encounter an unexpected situation we abort scanning further entries.
51   FILE* fp = fopen("/proc/self/maps", "r");
52   if (fp == nullptr) return result;
53 
54   // Allocate enough room to be able to store a full file name.
55   const int kLibNameLen = FILENAME_MAX + 1;
56   char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen));
57 
58   // This loop will terminate once the scanning hits an EOF.
59   while (true) {
60     uintptr_t start, end, offset;
61     char attr_r, attr_w, attr_x, attr_p;
62     // Parse the addresses and permission bits at the beginning of the line.
63     if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break;
64     if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break;
65     if (fscanf(fp, "%" V8PRIxPTR, &offset) != 1) break;
66 
67     int c;
68     if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') {
69       // Found a read-only executable entry. Skip characters until we reach
70       // the beginning of the filename or the end of the line.
71       do {
72         c = getc(fp);
73       } while ((c != EOF) && (c != '\n') && (c != '/') && (c != '['));
74       if (c == EOF) break;  // EOF: Was unexpected, just exit.
75 
76       // Process the filename if found.
77       if ((c == '/') || (c == '[')) {
78         // Push the '/' or '[' back into the stream to be read below.
79         ungetc(c, fp);
80 
81         // Read to the end of the line. Exit if the read fails.
82         if (fgets(lib_name, kLibNameLen, fp) == nullptr) break;
83 
84         // Drop the newline character read by fgets. We do not need to check
85         // for a zero-length string because we know that we at least read the
86         // '/' or '[' character.
87         lib_name[strlen(lib_name) - 1] = '\0';
88       } else {
89         // No library name found, just record the raw address range.
90         snprintf(lib_name, kLibNameLen, "%08" V8PRIxPTR "-%08" V8PRIxPTR, start,
91                  end);
92       }
93 
94 #ifdef V8_OS_ANDROID
95       size_t lib_name_length = strlen(lib_name);
96       if (lib_name_length < 4 ||
97           strncmp(&lib_name[lib_name_length - 4], ".apk", 4) != 0) {
98         // Only adjust {start} based on {offset} if the file isn't the APK,
99         // since we load the library directly from the APK and don't want to
100         // apply the offset of the .so in the APK as the libraries offset.
101         start -= offset;
102       }
103 #else
104       // Adjust {start} based on {offset}.
105       start -= offset;
106 #endif
107 
108       result.push_back(SharedLibraryAddress(lib_name, start, end));
109     } else {
110       // Entry not describing executable data. Skip to end of line to set up
111       // reading the next entry.
112       do {
113         c = getc(fp);
114       } while ((c != EOF) && (c != '\n'));
115       if (c == EOF) break;
116     }
117   }
118   free(lib_name);
119   fclose(fp);
120   return result;
121 }
122 
SignalCodeMovingGC()123 void OS::SignalCodeMovingGC() {
124   // Support for ll_prof.py.
125   //
126   // The Linux profiler built into the kernel logs all mmap's with
127   // PROT_EXEC so that analysis tools can properly attribute ticks. We
128   // do a mmap with a name known by ll_prof.py and immediately munmap
129   // it. This injects a GC marker into the stream of events generated
130   // by the kernel and allows us to synchronize V8 code log and the
131   // kernel log.
132   long size = sysconf(_SC_PAGESIZE);  // NOLINT(runtime/int)
133   FILE* f = fopen(OS::GetGCFakeMMapFile(), "w+");
134   if (f == nullptr) {
135     OS::PrintError("Failed to open %s\n", OS::GetGCFakeMMapFile());
136     OS::Abort();
137   }
138   void* addr = mmap(OS::GetRandomMmapAddr(), size, PROT_READ | PROT_EXEC,
139                     MAP_PRIVATE, fileno(f), 0);
140   DCHECK_NE(MAP_FAILED, addr);
141   CHECK(Free(addr, size));
142   fclose(f);
143 }
144 
AdjustSchedulingParams()145 void OS::AdjustSchedulingParams() {}
146 
RemapShared(void * old_address,void * new_address,size_t size)147 void* OS::RemapShared(void* old_address, void* new_address, size_t size) {
148   void* result =
149       mremap(old_address, 0, size, MREMAP_FIXED | MREMAP_MAYMOVE, new_address);
150 
151   if (result == MAP_FAILED) {
152     return nullptr;
153   }
154   DCHECK(result == new_address);
155   return result;
156 }
157 
158 }  // namespace base
159 }  // namespace v8
160