2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "StackBounds.h"
26 #include <mach/task.h>
27 #include <mach/thread_act.h>
45 #include <sys/procfs.h>
52 #if HAVE(PTHREAD_NP_H)
53 #include <pthread_np.h>
58 #include <WTFThreadData.h>
62 // Bug 26276 - Need a mechanism to determine stack extent
64 // These platforms should now be working correctly:
65 // DARWIN, QNX, UNIX, SYMBIAN
66 // These platforms are not:
67 // WINDOWS, SOLARIS, OPENBSD, HAIKU, WINCE
69 // FIXME: remove this! - this code unsafely guesses at stack sizes!
70 #if OS(WINDOWS) || OS(SOLARIS) || OS(OPENBSD) || OS(HAIKU)
71 // Based on the current limit used by the JSC parser, guess the stack size.
72 static const ptrdiff_t estimatedStackSize
= 128 * sizeof(void*) * 1024;
73 // This method assumes the stack is growing downwards.
74 static void* estimateStackBound(void* origin
)
76 return static_cast<char*>(origin
) - estimatedStackSize
;
82 void StackBounds::initialize()
84 pthread_t thread
= pthread_self();
85 m_origin
= pthread_get_stackaddr_np(thread
);
86 m_bound
= static_cast<char*>(m_origin
) - pthread_get_stacksize_np(thread
);
89 void StackBounds::checkConsistency() const
92 // Skip consistency check if this StackBounds was initialized
93 // on a different thread than the current thread.
94 const StackBounds
* stack
= &wtfThreadData().stack();
98 void* currentPosition
= ¤tPosition
;
99 ASSERT(m_origin
!= m_bound
);
100 ASSERT(isGrowingDownward()
101 ? (currentPosition
< m_origin
&& currentPosition
> m_bound
)
102 : (currentPosition
> m_origin
&& currentPosition
< m_bound
));
108 void StackBounds::initialize()
111 size_t stackSize
= 0;
112 pthread_t thread
= pthread_self();
114 struct _debug_thread_info threadInfo
;
115 memset(&threadInfo
, 0, sizeof(threadInfo
));
116 threadInfo
.tid
= pthread_self();
117 int fd
= open("/proc/self", O_RDONLY
);
119 LOG_ERROR("Unable to open /proc/self (errno: %d)", errno
);
122 devctl(fd
, DCMD_PROC_TIDSTATUS
, &threadInfo
, sizeof(threadInfo
), 0);
124 stackBase
= reinterpret_cast<void*>(threadInfo
.stkbase
);
125 stackSize
= threadInfo
.stksize
;
129 m_origin
= static_cast<char*>(stackBase
) + stackSize
;
134 void StackBounds::initialize()
139 m_bound
= estimateStackBound(m_origin
);
144 void StackBounds::initialize()
146 pthread_t thread
= pthread_self();
148 pthread_stackseg_np(thread
, &stack
);
149 m_origin
= stack
.ss_sp
;
150 m_bound
= estimateStackBound(m_origin
);
155 void StackBounds::initialize()
157 TThreadStackInfo info
;
159 thread
.StackInfo(info
);
160 m_origin
= (void*)info
.iBase
;
161 m_bound
= (void*)info
.iLimit
;
166 void StackBounds::initialize()
168 thread_info threadInfo
;
169 get_thread_info(find_thread(NULL
), &threadInfo
);
170 m_origin
= threadInfo
.stack_end
;
171 m_bound
= estimateStackBound(m_origin
);
176 void StackBounds::initialize()
179 size_t stackSize
= 0;
181 pthread_t thread
= pthread_self();
182 pthread_attr_t sattr
;
183 pthread_attr_init(&sattr
);
184 #if HAVE(PTHREAD_NP_H) || OS(NETBSD)
185 // e.g. on FreeBSD 5.4, neundorf@kde.org
186 pthread_attr_get_np(thread
, &sattr
);
188 // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
189 pthread_getattr_np(thread
, &sattr
);
191 int rc
= pthread_attr_getstack(&sattr
, &stackBase
, &stackSize
);
192 (void)rc
; // FIXME: Deal with error code somehow? Seems fatal.
194 pthread_attr_destroy(&sattr
);
196 m_origin
= static_cast<char*>(stackBase
) + stackSize
;
201 static bool detectGrowingDownward(void* previousFrame
)
203 // Find the address of this stack frame by taking the address of a local variable.
205 return previousFrame
> &thisFrame
;
208 static inline bool isPageWritable(void* page
)
210 MEMORY_BASIC_INFORMATION memoryInformation
;
211 DWORD result
= VirtualQuery(page
, &memoryInformation
, sizeof(memoryInformation
));
213 // return false on error, including ptr outside memory
214 if (result
!= sizeof(memoryInformation
))
217 DWORD protect
= memoryInformation
.Protect
& ~(PAGE_GUARD
| PAGE_NOCACHE
);
218 return protect
== PAGE_READWRITE
219 || protect
== PAGE_WRITECOPY
220 || protect
== PAGE_EXECUTE_READWRITE
221 || protect
== PAGE_EXECUTE_WRITECOPY
;
224 static inline void* getLowerStackBound(char* currentPage
, DWORD pageSize
)
226 while (currentPage
> 0) {
227 // check for underflow
228 if (currentPage
>= reinterpret_cast<char*>(pageSize
))
229 currentPage
-= pageSize
;
233 if (!isPageWritable(currentPage
))
234 return currentPage
+ pageSize
;
240 static inline void* getUpperStackBound(char* currentPage
, DWORD pageSize
)
243 // guaranteed to complete because isPageWritable returns false at end of memory
244 currentPage
+= pageSize
;
245 } while (isPageWritable(currentPage
));
247 return currentPage
- pageSize
;
250 void StackBounds::initialize()
252 // find the address of this stack frame by taking the address of a local variable
253 void* thisFrame
= &thisFrame
;
254 bool isGrowingDownward
= detectGrowingDownward(thisFrame
);
256 SYSTEM_INFO systemInfo
;
257 GetSystemInfo(&systemInfo
);
258 DWORD pageSize
= systemInfo
.dwPageSize
;
260 // scan all of memory starting from this frame, and return the last writeable page found
261 char* currentPage
= reinterpret_cast<char*>(reinterpret_cast<DWORD
>(thisFrame
) & ~(pageSize
- 1));
262 void* lowerStackBound
= getLowerStackBound(currentPage
, pageSize
);
263 void* upperStackBound
= getUpperStackBound(currentPage
, pageSize
);
265 m_origin
= isGrowingDownward
? upperStackBound
: lowerStackBound
;
266 m_bound
= isGrowingDownward
? lowerStackBound
: upperStackBound
;
271 void StackBounds::initialize()
273 #if CPU(X86) && COMPILER(MSVC)
274 // offset 0x18 from the FS segment register gives a pointer to
275 // the thread information block for the current thread
281 m_origin
= static_cast<void*>(pTib
->StackBase
);
282 #elif CPU(X86) && COMPILER(GCC)
283 // offset 0x18 from the FS segment register gives a pointer to
284 // the thread information block for the current thread
286 asm ( "movl %%fs:0x18, %0\n"
289 m_origin
= static_cast<void*>(pTib
->StackBase
);
291 PNT_TIB64 pTib
= reinterpret_cast<PNT_TIB64
>(NtCurrentTeb());
292 m_origin
= reinterpret_cast<void*>(pTib
->StackBase
);
294 #error Need a way to get the stack bounds on this platform (Windows)
296 // Looks like we should be able to get pTib->StackLimit
297 m_bound
= estimateStackBound(m_origin
);
301 #error Need a way to get the stack bounds on this platform