summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/wtf/StackBounds.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/wtf/StackBounds.cpp')
-rw-r--r--Source/JavaScriptCore/wtf/StackBounds.cpp283
1 files changed, 283 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/wtf/StackBounds.cpp b/Source/JavaScriptCore/wtf/StackBounds.cpp
new file mode 100644
index 0000000..f83695e
--- /dev/null
+++ b/Source/JavaScriptCore/wtf/StackBounds.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "StackBounds.h"
+
+#if OS(DARWIN)
+
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <pthread.h>
+
+#elif OS(WINDOWS)
+
+#include <windows.h>
+
+#elif OS(HAIKU)
+
+#include <OS.h>
+
+#elif OS(SOLARIS)
+
+#include <thread.h>
+
+#elif OS(QNX)
+
+#include <fcntl.h>
+#include <sys/procfs.h>
+#include <stdio.h>
+#include <errno.h>
+
+#elif OS(UNIX)
+
+#include <pthread.h>
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#endif
+
+#endif
+
+namespace WTF {
+
+// Bug 26276 - Need a mechanism to determine stack extent
+//
+// These platforms should now be working correctly:
+// DARWIN, WINDOWS-CPU(X86), QNX, UNIX, WINCE
+// These platforms are not:
+// WINDOWS-CPU(X86_64), SOLARIS, OPENBSD, SYMBIAN, HAIKU
+//
+// FIXME: remove this! - this code unsafely guesses at stack sizes!
+#if (OS(WINDOWS) && CPU(X86_64)) || OS(SOLARIS) || OS(OPENBSD) || OS(SYMBIAN) || OS(HAIKU)
+// Based on the current limit used by the JSC parser, guess the stack size.
+static const ptrdiff_t estimatedStackSize = 128 * sizeof(void*) * 1024;
+// This method assumes the stack is growing downwards.
+static void* estimateStackBound(void* origin)
+{
+ return static_cast<char*>(origin) - estimatedStackSize;
+}
+#endif
+
+#if OS(DARWIN)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ m_origin = pthread_get_stackaddr_np(thread);
+ m_bound = static_cast<char*>(m_origin) - pthread_get_stacksize_np(thread);
+}
+
+#elif OS(QNX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+ pthread_t thread = pthread_self();
+
+ struct _debug_thread_info threadInfo;
+ memset(&threadInfo, 0, sizeof(threadInfo));
+ threadInfo.tid = pthread_self();
+ int fd = open("/proc/self", O_RDONLY);
+ if (fd == -1) {
+ LOG_ERROR("Unable to open /proc/self (errno: %d)", errno);
+ CRASH();
+ }
+ devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0);
+ close(fd);
+ stackBase = reinterpret_cast<void*>(threadInfo.stkbase);
+ stackSize = threadInfo.stksize;
+ ASSERT(stackBase);
+
+ m_bound = stackBase;
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(SOLARIS)
+
+void StackBounds::initialize()
+{
+ stack_t s;
+ thr_stksegment(&s);
+ m_origin = s.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(OPENBSD)
+
+void StackBounds::initialize()
+{
+ pthread_t thread = pthread_self();
+ stack_t stack;
+ pthread_stackseg_np(thread, &stack);
+ m_origin = stack.ss_sp;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(SYMBIAN)
+
+void StackBounds::initialize()
+{
+ TThreadStackInfo info;
+ RThread thread;
+ thread.StackInfo(info);
+ m_origin = (void*)info.iBase;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(HAIKU)
+
+void StackBounds::initialize()
+{
+ thread_info threadInfo;
+ get_thread_info(find_thread(NULL), &threadInfo);
+ m_origin = threadInfo.stack_end;
+ m_bound = estimateStackBound(m_origin);
+}
+
+#elif OS(UNIX)
+
+void StackBounds::initialize()
+{
+ void* stackBase = 0;
+ size_t stackSize = 0;
+
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
+ // e.g. on FreeBSD 5.4, neundorf@kde.org
+ pthread_attr_get_np(thread, &sattr);
+#else
+ // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+ pthread_getattr_np(thread, &sattr);
+#endif
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
+ ASSERT(stackBase);
+ pthread_attr_destroy(&sattr);
+ m_bound = stackBase;
+ m_origin = static_cast<char*>(stackBase) + stackSize;
+}
+
+#elif OS(WINCE)
+
+static bool detectGrowingDownward(void* previousFrame)
+{
+ // Find the address of this stack frame by taking the address of a local variable.
+ int thisFrame;
+ return previousFrame > &thisFrame;
+}
+
+static inline bool isPageWritable(void* page)
+{
+ MEMORY_BASIC_INFORMATION memoryInformation;
+ DWORD result = VirtualQuery(page, &memoryInformation, sizeof(memoryInformation));
+
+ // return false on error, including ptr outside memory
+ if (result != sizeof(memoryInformation))
+ return false;
+
+ DWORD protect = memoryInformation.Protect & ~(PAGE_GUARD | PAGE_NOCACHE);
+ return protect == PAGE_READWRITE
+ || protect == PAGE_WRITECOPY
+ || protect == PAGE_EXECUTE_READWRITE
+ || protect == PAGE_EXECUTE_WRITECOPY;
+}
+
+static inline void* getLowerStackBound(char* currentPage, DWORD pageSize)
+{
+ while (currentPage > 0) {
+ // check for underflow
+ if (currentPage >= reinterpret_cast<char*>(pageSize))
+ currentPage -= pageSize;
+ else
+ currentPage = 0;
+
+ if (!isPageWritable(currentPage))
+ return currentPage + pageSize;
+ }
+
+ return 0;
+}
+
+static inline void* getUpperStackBound(char* currentPage, DWORD pageSize)
+{
+ do {
+ // guaranteed to complete because isPageWritable returns false at end of memory
+ currentPage += pageSize;
+ } while (isPageWritable(currentPage));
+
+ return currentPage - pageSize;
+}
+
+void StackBounds::initialize()
+{
+ // find the address of this stack frame by taking the address of a local variable
+ void* thisFrame = &thisFrame;
+ bool isGrowingDownward = detectGrowingDownward(thisFrame);
+
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ DWORD pageSize = systemInfo.dwPageSize;
+
+ // scan all of memory starting from this frame, and return the last writeable page found
+ char* currentPage = reinterpret_cast<char*>(reinterpret_cast<DWORD>(thisFrame) & ~(pageSize - 1));
+ void* lowerStackBound = getLowerStackBound(currentPage, pageSize);
+ void* upperStackBound = getUpperStackBound(currentPage, pageSize);
+
+ m_origin = isGrowingDownward ? upperStackBound : lowerStackBound;
+ m_bound = isGrowingDownward ? lowerStackBound : upperStackBound;
+}
+
+#elif OS(WINDOWS) && (CPU(X86) || CPU(X86_64))
+
+void StackBounds::initialize()
+{
+#if CPU(X86)
+ // Offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread.
+ NT_TIB* pTib;
+#if COMPILER(MSVC)
+ __asm {
+ MOV EAX, FS:[18h]
+ MOV pTib, EAX
+ }
+#else
+ asm ( "movl %%fs:0x18, %0\n"
+ : "=r" (pTib)
+ );
+#endif
+ // See http://en.wikipedia.org/wiki/Win32_Thread_Information_Block for more information!
+ void* pDeallocationStack = reinterpret_cast<char*>(pTib) + 0xE0C;
+ m_origin = static_cast<void*>(pTib->StackBase);
+ m_bound = *static_cast<void**>(pDeallocationStack);
+#elif CPU(X86_64)
+ PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+ m_origin = reinterpret_cast<void*>(pTib->StackBase);
+ m_bound = estimateStackBound(m_origin);
+#endif
+}
+
+#else
+#error Need a way to get the stack bounds on this platform.
+#endif
+
+} // namespace WTF