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