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
|