/src/3rdparty/webkit/Source/JavaScriptCore/wtf/StackBounds.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 287 lines · 194 code · 51 blank · 42 comment · 21 complexity · 19c334ccdbe48b9f93a9268e2fa806a2 MD5 · raw file

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