|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "jsnativestack.h" |
|
8 |
|
9 #ifdef XP_WIN |
|
10 # include "jswin.h" |
|
11 |
|
12 #elif defined(XP_MACOSX) || defined(DARWIN) || defined(XP_UNIX) |
|
13 # include <pthread.h> |
|
14 |
|
15 # if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) |
|
16 # include <pthread_np.h> |
|
17 # endif |
|
18 |
|
19 # if defined(ANDROID) |
|
20 # include <sys/types.h> |
|
21 # include <unistd.h> |
|
22 # endif |
|
23 |
|
24 #else |
|
25 # error "Unsupported platform" |
|
26 |
|
27 #endif |
|
28 |
|
29 #if defined(XP_WIN) |
|
30 |
|
31 void * |
|
32 js::GetNativeStackBaseImpl() |
|
33 { |
|
34 # if defined(_M_IX86) && defined(_MSC_VER) |
|
35 /* |
|
36 * offset 0x18 from the FS segment register gives a pointer to |
|
37 * the thread information block for the current thread |
|
38 */ |
|
39 NT_TIB* pTib; |
|
40 __asm { |
|
41 MOV EAX, FS:[18h] |
|
42 MOV pTib, EAX |
|
43 } |
|
44 return static_cast<void*>(pTib->StackBase); |
|
45 |
|
46 # elif defined(_M_X64) |
|
47 PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); |
|
48 return reinterpret_cast<void*>(pTib->StackBase); |
|
49 |
|
50 # elif defined(_WIN32) && defined(__GNUC__) |
|
51 NT_TIB* pTib; |
|
52 asm ("movl %%fs:0x18, %0\n" : "=r" (pTib)); |
|
53 return static_cast<void*>(pTib->StackBase); |
|
54 |
|
55 # endif |
|
56 } |
|
57 |
|
58 #elif defined(SOLARIS) |
|
59 |
|
60 #include <ucontext.h> |
|
61 |
|
62 JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); |
|
63 |
|
64 void * |
|
65 js::GetNativeStackBaseImpl() |
|
66 { |
|
67 stack_t st; |
|
68 stack_getbounds(&st); |
|
69 return static_cast<char*>(st.ss_sp) + st.ss_size; |
|
70 } |
|
71 |
|
72 #elif defined(AIX) |
|
73 |
|
74 #include <ucontext.h> |
|
75 |
|
76 JS_STATIC_ASSERT(JS_STACK_GROWTH_DIRECTION < 0); |
|
77 |
|
78 void * |
|
79 js::GetNativeStackBaseImpl() |
|
80 { |
|
81 ucontext_t context; |
|
82 getcontext(&context); |
|
83 return static_cast<char*>(context.uc_stack.ss_sp) + |
|
84 context.uc_stack.ss_size; |
|
85 } |
|
86 |
|
87 #else /* XP_UNIX */ |
|
88 |
|
89 void * |
|
90 js::GetNativeStackBaseImpl() |
|
91 { |
|
92 pthread_t thread = pthread_self(); |
|
93 # if defined(XP_MACOSX) || defined(DARWIN) |
|
94 return pthread_get_stackaddr_np(thread); |
|
95 |
|
96 # else |
|
97 pthread_attr_t sattr; |
|
98 pthread_attr_init(&sattr); |
|
99 # if defined(__OpenBSD__) |
|
100 stack_t ss; |
|
101 # elif defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(NETBSD) |
|
102 /* e.g. on FreeBSD 4.8 or newer, neundorf@kde.org */ |
|
103 pthread_attr_get_np(thread, &sattr); |
|
104 # else |
|
105 /* |
|
106 * FIXME: this function is non-portable; |
|
107 * other POSIX systems may have different np alternatives |
|
108 */ |
|
109 pthread_getattr_np(thread, &sattr); |
|
110 # endif |
|
111 |
|
112 void *stackBase = 0; |
|
113 size_t stackSize = 0; |
|
114 int rc; |
|
115 # if defined(__OpenBSD__) |
|
116 rc = pthread_stackseg_np(pthread_self(), &ss); |
|
117 stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size); |
|
118 stackSize = ss.ss_size; |
|
119 # elif defined(ANDROID) |
|
120 if (gettid() == getpid()) { |
|
121 // bionic's pthread_attr_getstack doesn't tell the truth for the main |
|
122 // thread (see bug 846670). So we scan /proc/self/maps to find the |
|
123 // segment which contains the stack. |
|
124 rc = -1; |
|
125 FILE *fs = fopen("/proc/self/maps", "r"); |
|
126 if (fs) { |
|
127 char line[100]; |
|
128 unsigned long stackAddr = (unsigned long)&sattr; |
|
129 while (fgets(line, sizeof(line), fs) != nullptr) { |
|
130 unsigned long stackStart; |
|
131 unsigned long stackEnd; |
|
132 if (sscanf(line, "%lx-%lx ", &stackStart, &stackEnd) == 2 && |
|
133 stackAddr >= stackStart && stackAddr < stackEnd) { |
|
134 stackBase = (void *)stackStart; |
|
135 stackSize = stackEnd - stackStart; |
|
136 rc = 0; |
|
137 break; |
|
138 } |
|
139 } |
|
140 fclose(fs); |
|
141 } |
|
142 } else |
|
143 // For non main-threads pthread allocates the stack itself so it tells |
|
144 // the truth. |
|
145 rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); |
|
146 # else |
|
147 rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); |
|
148 # endif |
|
149 if (rc) |
|
150 MOZ_CRASH(); |
|
151 JS_ASSERT(stackBase); |
|
152 pthread_attr_destroy(&sattr); |
|
153 |
|
154 # if JS_STACK_GROWTH_DIRECTION > 0 |
|
155 return stackBase; |
|
156 # else |
|
157 return static_cast<char*>(stackBase) + stackSize; |
|
158 # endif |
|
159 # endif |
|
160 } |
|
161 |
|
162 #endif /* !XP_WIN */ |