1 // Copyright 2013 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 QNX goes here. For the POSIX-compatible
6 // parts the implementation is in platform-posix.cc.
7 
8 #include <backtrace.h>
9 #include <pthread.h>
10 #include <semaphore.h>
11 #include <signal.h>
12 #include <stdlib.h>
13 #include <sys/resource.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <ucontext.h>
17 
18 // QNX requires memory pages to be marked as executable.
19 // Otherwise, the OS raises an exception when executing code in that page.
20 #include <errno.h>
21 #include <fcntl.h>      // open
22 #include <stdarg.h>
23 #include <strings.h>    // index
24 #include <sys/mman.h>   // mmap & munmap
25 #include <sys/procfs.h>
26 #include <sys/stat.h>   // open
27 #include <unistd.h>     // sysconf
28 
29 #include <cmath>
30 
31 #undef MAP_TYPE
32 
33 #include "src/base/macros.h"
34 #include "src/base/platform/platform.h"
35 
36 
37 namespace v8 {
38 namespace base {
39 
40 // 0 is never a valid thread id on Qnx since tids and pids share a
41 // name space and pid 0 is reserved (see man 2 kill).
42 static const pthread_t kNoThread = (pthread_t) 0;
43 
44 
45 #ifdef __arm__
46 
ArmUsingHardFloat()47 bool OS::ArmUsingHardFloat() {
48   // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
49   // the Floating Point ABI used (PCS stands for Procedure Call Standard).
50   // We use these as well as a couple of other defines to statically determine
51   // what FP ABI used.
52   // GCC versions 4.4 and below don't support hard-fp.
53   // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
54   // __ARM_PCS_VFP.
55 
56 #define GCC_VERSION (__GNUC__ * 10000                                          \
57                      + __GNUC_MINOR__ * 100                                    \
58                      + __GNUC_PATCHLEVEL__)
59 #if GCC_VERSION >= 40600
60 #if defined(__ARM_PCS_VFP)
61   return true;
62 #else
63   return false;
64 #endif
65 
66 #elif GCC_VERSION < 40500
67   return false;
68 
69 #else
70 #if defined(__ARM_PCS_VFP)
71   return true;
72 #elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
73       !defined(__VFP_FP__)
74   return false;
75 #else
76 #error "Your version of GCC does not report the FP ABI compiled for."          \
77        "Please report it on this issue"                                        \
78        "http://code.google.com/p/v8/issues/detail?id=2140"
79 
80 #endif
81 #endif
82 #undef GCC_VERSION
83 }
84 
85 #endif  // __arm__
86 
87 
LocalTimezone(double time,TimezoneCache * cache)88 const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
89   if (std::isnan(time)) return "";
90   time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
91   struct tm* t = localtime(&tv);  // NOLINT(runtime/threadsafe_fn)
92   if (NULL == t) return "";
93   return t->tm_zone;
94 }
95 
96 
LocalTimeOffset(TimezoneCache * cache)97 double OS::LocalTimeOffset(TimezoneCache* cache) {
98   time_t tv = time(NULL);
99   struct tm* t = localtime(&tv);  // NOLINT(runtime/threadsafe_fn)
100   // tm_gmtoff includes any daylight savings offset, so subtract it.
101   return static_cast<double>(t->tm_gmtoff * msPerSecond -
102                              (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
103 }
104 
105 
Allocate(const size_t requested,size_t * allocated,bool is_executable)106 void* OS::Allocate(const size_t requested,
107                    size_t* allocated,
108                    bool is_executable) {
109   const size_t msize = RoundUp(requested, AllocateAlignment());
110   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
111   void* addr = OS::GetRandomMmapAddr();
112   void* mbase = mmap(addr, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
113   if (mbase == MAP_FAILED) return NULL;
114   *allocated = msize;
115   return mbase;
116 }
117 
118 
GetSharedLibraryAddresses()119 std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
120   std::vector<SharedLibraryAddress> result;
121   procfs_mapinfo *mapinfos = NULL, *mapinfo;
122   int proc_fd, num, i;
123 
124   struct {
125     procfs_debuginfo info;
126     char buff[PATH_MAX];
127   } map;
128 
129   char buf[PATH_MAX + 1];
130   snprintf(buf, PATH_MAX + 1, "/proc/%d/as", getpid());
131 
132   if ((proc_fd = open(buf, O_RDONLY)) == -1) {
133     close(proc_fd);
134     return result;
135   }
136 
137   /* Get the number of map entries.  */
138   if (devctl(proc_fd, DCMD_PROC_MAPINFO, NULL, 0, &num) != EOK) {
139     close(proc_fd);
140     return result;
141   }
142 
143   mapinfos = reinterpret_cast<procfs_mapinfo *>(
144       malloc(num * sizeof(procfs_mapinfo)));
145   if (mapinfos == NULL) {
146     close(proc_fd);
147     return result;
148   }
149 
150   /* Fill the map entries.  */
151   if (devctl(proc_fd, DCMD_PROC_PAGEDATA,
152       mapinfos, num * sizeof(procfs_mapinfo), &num) != EOK) {
153     free(mapinfos);
154     close(proc_fd);
155     return result;
156   }
157 
158   for (i = 0; i < num; i++) {
159     mapinfo = mapinfos + i;
160     if (mapinfo->flags & MAP_ELF) {
161       map.info.vaddr = mapinfo->vaddr;
162       if (devctl(proc_fd, DCMD_PROC_MAPDEBUG, &map, sizeof(map), 0) != EOK) {
163         continue;
164       }
165       result.push_back(SharedLibraryAddress(
166           map.info.path, mapinfo->vaddr, mapinfo->vaddr + mapinfo->size));
167     }
168   }
169   free(mapinfos);
170   close(proc_fd);
171   return result;
172 }
173 
174 
SignalCodeMovingGC()175 void OS::SignalCodeMovingGC() {
176 }
177 
178 
179 // Constants used for mmap.
180 static const int kMmapFd = -1;
181 static const int kMmapFdOffset = 0;
182 
183 
VirtualMemory()184 VirtualMemory::VirtualMemory() : address_(NULL), size_(0) { }
185 
186 
VirtualMemory(size_t size)187 VirtualMemory::VirtualMemory(size_t size)
188     : address_(ReserveRegion(size)), size_(size) { }
189 
190 
VirtualMemory(size_t size,size_t alignment)191 VirtualMemory::VirtualMemory(size_t size, size_t alignment)
192     : address_(NULL), size_(0) {
193   DCHECK((alignment % OS::AllocateAlignment()) == 0);
194   size_t request_size = RoundUp(size + alignment,
195                                 static_cast<intptr_t>(OS::AllocateAlignment()));
196   void* reservation = mmap(OS::GetRandomMmapAddr(),
197                            request_size,
198                            PROT_NONE,
199                            MAP_PRIVATE | MAP_ANONYMOUS | MAP_LAZY,
200                            kMmapFd,
201                            kMmapFdOffset);
202   if (reservation == MAP_FAILED) return;
203 
204   uint8_t* base = static_cast<uint8_t*>(reservation);
205   uint8_t* aligned_base = RoundUp(base, alignment);
206   DCHECK_LE(base, aligned_base);
207 
208   // Unmap extra memory reserved before and after the desired block.
209   if (aligned_base != base) {
210     size_t prefix_size = static_cast<size_t>(aligned_base - base);
211     OS::Free(base, prefix_size);
212     request_size -= prefix_size;
213   }
214 
215   size_t aligned_size = RoundUp(size, OS::AllocateAlignment());
216   DCHECK_LE(aligned_size, request_size);
217 
218   if (aligned_size != request_size) {
219     size_t suffix_size = request_size - aligned_size;
220     OS::Free(aligned_base + aligned_size, suffix_size);
221     request_size -= suffix_size;
222   }
223 
224   DCHECK(aligned_size == request_size);
225 
226   address_ = static_cast<void*>(aligned_base);
227   size_ = aligned_size;
228 }
229 
230 
~VirtualMemory()231 VirtualMemory::~VirtualMemory() {
232   if (IsReserved()) {
233     bool result = ReleaseRegion(address(), size());
234     DCHECK(result);
235     USE(result);
236   }
237 }
238 
239 
IsReserved()240 bool VirtualMemory::IsReserved() {
241   return address_ != NULL;
242 }
243 
244 
Reset()245 void VirtualMemory::Reset() {
246   address_ = NULL;
247   size_ = 0;
248 }
249 
250 
Commit(void * address,size_t size,bool is_executable)251 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) {
252   return CommitRegion(address, size, is_executable);
253 }
254 
255 
Uncommit(void * address,size_t size)256 bool VirtualMemory::Uncommit(void* address, size_t size) {
257   return UncommitRegion(address, size);
258 }
259 
260 
Guard(void * address)261 bool VirtualMemory::Guard(void* address) {
262   OS::Guard(address, OS::CommitPageSize());
263   return true;
264 }
265 
266 
ReserveRegion(size_t size)267 void* VirtualMemory::ReserveRegion(size_t size) {
268   void* result = mmap(OS::GetRandomMmapAddr(),
269                       size,
270                       PROT_NONE,
271                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_LAZY,
272                       kMmapFd,
273                       kMmapFdOffset);
274 
275   if (result == MAP_FAILED) return NULL;
276 
277   return result;
278 }
279 
280 
CommitRegion(void * base,size_t size,bool is_executable)281 bool VirtualMemory::CommitRegion(void* base, size_t size, bool is_executable) {
282   int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0);
283   if (MAP_FAILED == mmap(base,
284                          size,
285                          prot,
286                          MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
287                          kMmapFd,
288                          kMmapFdOffset)) {
289     return false;
290   }
291 
292   return true;
293 }
294 
295 
UncommitRegion(void * base,size_t size)296 bool VirtualMemory::UncommitRegion(void* base, size_t size) {
297   return mmap(base,
298               size,
299               PROT_NONE,
300               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_LAZY,
301               kMmapFd,
302               kMmapFdOffset) != MAP_FAILED;
303 }
304 
305 
ReleaseRegion(void * base,size_t size)306 bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
307   return munmap(base, size) == 0;
308 }
309 
310 
HasLazyCommits()311 bool VirtualMemory::HasLazyCommits() {
312   return false;
313 }
314 
315 }  // namespace base
316 }  // namespace v8
317