1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org> 4 * 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. 9 * 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. 14 * 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 18 * 19 */ 20 21 #include "config.h" 22 #include "StackBounds.h" 23 24 #if OS(DARWIN) 25 26 #include <mach/task.h> 27 #include <mach/thread_act.h> 28 #include <pthread.h> 29 30 #elif OS(WINDOWS) 31 32 #include <windows.h> 33 34 #elif OS(HAIKU) 35 36 #include <OS.h> 37 38 #elif OS(SOLARIS) 39 40 #include <thread.h> 41 42 #elif OS(QNX) 43 44 #include <fcntl.h> 45 #include <sys/procfs.h> 46 #include <stdio.h> 47 #include <errno.h> 48 49 #elif OS(UNIX) 50 51 #include <pthread.h> 52 #if HAVE(PTHREAD_NP_H) 53 #include <pthread_np.h> 54 #endif 55 56 #endif 57 58 namespace WTF { 59 60 // Bug 26276 - Need a mechanism to determine stack extent 61 // 62 // These platforms should now be working correctly: 63 // DARWIN, QNX, UNIX, SYMBIAN 64 // These platforms are not: 65 // WINDOWS, SOLARIS, OPENBSD, HAIKU, WINCE 66 // 67 // FIXME: remove this! - this code unsafely guesses at stack sizes! 68 #if OS(WINDOWS) || OS(SOLARIS) || OS(OPENBSD) || OS(HAIKU) 69 // Based on the current limit used by the JSC parser, guess the stack size. 70 static const ptrdiff_t estimatedStackSize = 128 * sizeof(void*) * 1024; 71 // This method assumes the stack is growing downwards. 72 static void* estimateStackBound(void* origin) 73 { 74 return static_cast<char*>(origin) - estimatedStackSize; 75 } 76 #endif 77 78 #if OS(DARWIN) 79 80 void StackBounds::initialize() 81 { 82 pthread_t thread = pthread_self(); 83 m_origin = pthread_get_stackaddr_np(thread); 84 m_bound = static_cast<char*>(m_origin) - pthread_get_stacksize_np(thread); 85 } 86 87 #elif OS(QNX) 88 89 void StackBounds::initialize() 90 { 91 void* stackBase = 0; 92 size_t stackSize = 0; 93 pthread_t thread = pthread_self(); 94 95 struct _debug_thread_info threadInfo; 96 memset(&threadInfo, 0, sizeof(threadInfo)); 97 threadInfo.tid = pthread_self(); 98 int fd = open("/proc/self", O_RDONLY); 99 if (fd == -1) { 100 LOG_ERROR("Unable to open /proc/self (errno: %d)", errno); 101 CRASH(); 102 } 103 devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0); 104 close(fd); 105 stackBase = reinterpret_cast<void*>(threadInfo.stkbase); 106 stackSize = threadInfo.stksize; 107 ASSERT(stackBase); 108 109 m_bound = stackBase; 110 m_origin = static_cast<char*>(stackBase) + stackSize; 111 } 112 113 #elif OS(SOLARIS) 114 115 void StackBounds::initialize() 116 { 117 stack_t s; 118 thr_stksegment(&s); 119 m_origin = s.ss_sp; 120 m_bound = estimateStackBound(m_origin); 121 } 122 123 #elif OS(OPENBSD) 124 125 void StackBounds::initialize() 126 { 127 pthread_t thread = pthread_self(); 128 stack_t stack; 129 pthread_stackseg_np(thread, &stack); 130 m_origin = stack.ss_sp; 131 m_bound = estimateStackBound(m_origin); 132 } 133 134 #elif OS(SYMBIAN) 135 136 void StackBounds::initialize() 137 { 138 TThreadStackInfo info; 139 RThread thread; 140 thread.StackInfo(info); 141 m_origin = (void*)info.iBase; 142 m_bound = (void*)info.iLimit; 143 } 144 145 #elif OS(HAIKU) 146 147 void StackBounds::initialize() 148 { 149 thread_info threadInfo; 150 get_thread_info(find_thread(NULL), &threadInfo); 151 m_origin = threadInfo.stack_end; 152 m_bound = estimateStackBound(m_origin); 153 } 154 155 #elif OS(UNIX) 156 157 void StackBounds::initialize() 158 { 159 void* stackBase = 0; 160 size_t stackSize = 0; 161 162 pthread_t thread = pthread_self(); 163 pthread_attr_t sattr; 164 pthread_attr_init(&sattr); 165 #if HAVE(PTHREAD_NP_H) || OS(NETBSD) 166 // e.g. on FreeBSD 5.4, neundorf (at) kde.org 167 pthread_attr_get_np(thread, &sattr); 168 #else 169 // FIXME: this function is non-portable; other POSIX systems may have different np alternatives 170 pthread_getattr_np(thread, &sattr); 171 #endif 172 int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize); 173 (void)rc; // FIXME: Deal with error code somehow? Seems fatal. 174 ASSERT(stackBase); 175 pthread_attr_destroy(&sattr); 176 m_bound = stackBase; 177 m_origin = static_cast<char*>(stackBase) + stackSize; 178 } 179 180 #elif OS(WINCE) 181 182 static bool detectGrowingDownward(void* previousFrame) 183 { 184 // Find the address of this stack frame by taking the address of a local variable. 185 int thisFrame; 186 return previousFrame > &thisFrame; 187 } 188 189 static inline bool isPageWritable(void* page) 190 { 191 MEMORY_BASIC_INFORMATION memoryInformation; 192 DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation)); 193 194 // return false on error, including ptr outside memory 195 if (result != sizeof(memoryInformation)) 196 return false; 197 198 DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE); 199 return protect == PAGE_READWRITE 200 || protect == PAGE_WRITECOPY 201 || protect == PAGE_EXECUTE_READWRITE 202 || protect == PAGE_EXECUTE_WRITECOPY; 203 } 204 205 static inline void* getLowerStackBound(char* currentPage, DWORD pageSize) 206 { 207 while (currentPage > 0) { 208 // check for underflow 209 if (currentPage >= reinterpret_cast<char*>(pageSize)) 210 currentPage -= pageSize; 211 else 212 currentPage = 0; 213 214 if (!isPageWritable(currentPage)) 215 return currentPage + pageSize; 216 } 217 218 return 0; 219 } 220 221 static inline void* getUpperStackBound(char* currentPage, DWORD pageSize) 222 { 223 do { 224 // guaranteed to complete because isPageWritable returns false at end of memory 225 currentPage += pageSize; 226 } while (isPageWritable(currentPage)); 227 228 return currentPage - pageSize; 229 } 230 231 void StackBounds::initialize() 232 { 233 // find the address of this stack frame by taking the address of a local variable 234 void* thisFrame = &thisFrame; 235 bool isGrowingDownward = detectGrowingDownward(thisFrame); 236 237 SYSTEM_INFO systemInfo; 238 GetSystemInfo(&systemInfo); 239 DWORD pageSize = systemInfo.dwPageSize; 240 241 // scan all of memory starting from this frame, and return the last writeable page found 242 char* currentPage = reinterpret_cast<char*>(reinterpret_cast<DWORD>(thisFrame) & ~(pageSize - 1)); 243 void* lowerStackBound = getLowerStackBound(currentPage, pageSize); 244 void* upperStackBound = getUpperStackBound(currentPage, pageSize); 245 246 m_origin = isGrowingDownward ? upperStackBound : lowerStackBound; 247 m_bound = isGrowingDownward ? lowerStackBound : upperStackBound; 248 } 249 250 #elif OS(WINDOWS) 251 252 void StackBounds::initialize() 253 { 254 #if CPU(X86) && COMPILER(MSVC) 255 // offset 0x18 from the FS segment register gives a pointer to 256 // the thread information block for the current thread 257 NT_TIB* pTib; 258 __asm { 259 MOV EAX, FS:[18h] 260 MOV pTib, EAX 261 } 262 m_origin = static_cast<void*>(pTib->StackBase); 263 #elif CPU(X86) && COMPILER(GCC) 264 // offset 0x18 from the FS segment register gives a pointer to 265 // the thread information block for the current thread 266 NT_TIB* pTib; 267 asm ( "movl %%fs:0x18, %0\n" 268 : "=r" (pTib) 269 ); 270 m_origin = static_cast<void*>(pTib->StackBase); 271 #elif CPU(X86_64) 272 PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb()); 273 m_origin = reinterpret_cast<void*>(pTib->StackBase); 274 #else 275 #error Need a way to get the stack bounds on this platform (Windows) 276 #endif 277 // Looks like we should be able to get pTib->StackLimit 278 m_bound = estimateStackBound(m_origin); 279 } 280 281 #else 282 #error Need a way to get the stack bounds on this platform 283 #endif 284 285 } // namespace WTF 286