|
@@ -19,11 +19,10 @@
|
|
|
#include "contextSwitch.h"
|
|
#include "contextSwitch.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
|
-#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#ifdef THREAD_SIMPLE_IMPL
|
|
#ifdef THREAD_SIMPLE_IMPL
|
|
|
|
|
|
|
|
-#ifdef HAVE_UCONTEXT_H
|
|
|
|
|
|
|
+#if defined(HAVE_UCONTEXT_H)
|
|
|
|
|
|
|
|
/* The getcontext() / setcontext() implementation. Easy-peasy. */
|
|
/* The getcontext() / setcontext() implementation. Easy-peasy. */
|
|
|
|
|
|
|
@@ -81,7 +80,6 @@ switch_to_thread_context(struct ThreadContext *context) {
|
|
|
abort();
|
|
abort();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
#else
|
|
#else
|
|
|
|
|
|
|
|
/* The setjmp() / longjmp() implementation. A bit hackier. */
|
|
/* The setjmp() / longjmp() implementation. A bit hackier. */
|
|
@@ -90,25 +88,62 @@ switch_to_thread_context(struct ThreadContext *context) {
|
|
|
then call setjmp() to record that stack pointer in the
|
|
then call setjmp() to record that stack pointer in the
|
|
|
_jmp_context. Then restore back to the original stack pointer. */
|
|
_jmp_context. Then restore back to the original stack pointer. */
|
|
|
|
|
|
|
|
|
|
+#if defined(__i386__)
|
|
|
|
|
+/* Here is own own implementation of setjmp and longjmp for I386, via
|
|
|
|
|
+ GNU syntax. */
|
|
|
|
|
+
|
|
|
|
|
+int cs_setjmp(cs_jmp_buf env);
|
|
|
|
|
+void cs_longjmp(cs_jmp_buf env);
|
|
|
|
|
+
|
|
|
|
|
+__asm__
|
|
|
|
|
+("cs_setjmp:\n"
|
|
|
|
|
+ "popl %edx\n"
|
|
|
|
|
+ "popl %eax\n"
|
|
|
|
|
+ "pushl %eax\n"
|
|
|
|
|
+ "movl %ebx,0(%eax)\n"
|
|
|
|
|
+ "movl %edi,4(%eax)\n"
|
|
|
|
|
+ "movl %esi,8(%eax)\n"
|
|
|
|
|
+ "movl %ebp,12(%eax)\n"
|
|
|
|
|
+ "movl %esp,16(%eax)\n"
|
|
|
|
|
+ "movl %edx,20(%eax)\n"
|
|
|
|
|
+ "fnsave 24(%eax)\n"
|
|
|
|
|
+ "xorl %eax,%eax\n"
|
|
|
|
|
+ "jmp *%edx\n");
|
|
|
|
|
+
|
|
|
|
|
+__asm__
|
|
|
|
|
+("cs_longjmp:\n"
|
|
|
|
|
+ "popl %edx\n"
|
|
|
|
|
+ "popl %eax\n"
|
|
|
|
|
+ "movl 0(%eax),%ebx\n"
|
|
|
|
|
+ "movl 4(%eax),%edi\n"
|
|
|
|
|
+ "movl 8(%eax),%esi\n"
|
|
|
|
|
+ "movl 12(%eax),%ebp\n"
|
|
|
|
|
+ "movl 16(%eax),%esp\n"
|
|
|
|
|
+ "movl 20(%eax),%edx\n"
|
|
|
|
|
+ "frstor 24(%eax)\n"
|
|
|
|
|
+ "mov $1,%eax\n"
|
|
|
|
|
+ "jmp *%edx\n");
|
|
|
|
|
+
|
|
|
|
|
+#endif /* __i386__ */
|
|
|
|
|
|
|
|
/* Ideally, including setjmp.h would have defined JB_SP, which will
|
|
/* Ideally, including setjmp.h would have defined JB_SP, which will
|
|
|
tell us where in the context structure we can muck with the stack
|
|
tell us where in the context structure we can muck with the stack
|
|
|
pointer. If it didn't define this symbol, we have to guess it. */
|
|
pointer. If it didn't define this symbol, we have to guess it. */
|
|
|
-#ifndef JB_SP
|
|
|
|
|
|
|
+#ifndef CS_JB_SP
|
|
|
|
|
|
|
|
#if defined(IS_OSX) && defined(__i386__)
|
|
#if defined(IS_OSX) && defined(__i386__)
|
|
|
/* We have determined this value empirically, via test_setjmp.cxx in
|
|
/* We have determined this value empirically, via test_setjmp.cxx in
|
|
|
this directory. */
|
|
this directory. */
|
|
|
-#define JB_SP 9
|
|
|
|
|
|
|
+#define CS_JB_SP 9
|
|
|
|
|
|
|
|
#elif defined(WIN32)
|
|
#elif defined(WIN32)
|
|
|
/* We have determined this value empirically, via test_setjmp.cxx in
|
|
/* We have determined this value empirically, via test_setjmp.cxx in
|
|
|
this directory. */
|
|
this directory. */
|
|
|
-#define JB_SP 4
|
|
|
|
|
|
|
+#define CS_JB_SP 4
|
|
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
-#endif /* JB_SP */
|
|
|
|
|
|
|
+#endif /* CS_JB_SP */
|
|
|
|
|
|
|
|
static struct ThreadContext *st_context;
|
|
static struct ThreadContext *st_context;
|
|
|
static unsigned char *st_stack;
|
|
static unsigned char *st_stack;
|
|
@@ -116,21 +151,25 @@ static size_t st_stack_size;
|
|
|
static ContextFunction *st_thread_func;
|
|
static ContextFunction *st_thread_func;
|
|
|
static void *st_data;
|
|
static void *st_data;
|
|
|
|
|
|
|
|
-static jmp_buf orig_stack;
|
|
|
|
|
|
|
+static cs_jmp_buf orig_stack;
|
|
|
|
|
|
|
|
-static void
|
|
|
|
|
|
|
+/* We can't declare this function static--gcc might want to inline it
|
|
|
|
|
+ in that case, and then the code crashes. I hope this doesn't mean
|
|
|
|
|
+ that the stack is still not getting restored correctly in the above
|
|
|
|
|
+ assembly code. */
|
|
|
|
|
+void
|
|
|
setup_context_2(void) {
|
|
setup_context_2(void) {
|
|
|
/* Here we are running on the new stack. Copy the key data onto our
|
|
/* Here we are running on the new stack. Copy the key data onto our
|
|
|
new stack. */
|
|
new stack. */
|
|
|
ContextFunction *volatile thread_func = st_thread_func;
|
|
ContextFunction *volatile thread_func = st_thread_func;
|
|
|
void *volatile data = st_data;
|
|
void *volatile data = st_data;
|
|
|
|
|
|
|
|
- if (setjmp(st_context->_jmp_context) == 0) {
|
|
|
|
|
|
|
+ if (cs_setjmp(st_context->_jmp_context) == 0) {
|
|
|
/* The _jmp_context is set up and ready to run. Now restore the
|
|
/* The _jmp_context is set up and ready to run. Now restore the
|
|
|
original stack and return. We can't simply return from this
|
|
original stack and return. We can't simply return from this
|
|
|
function, since it might overwrite some of the stack data on
|
|
function, since it might overwrite some of the stack data on
|
|
|
the way out. */
|
|
the way out. */
|
|
|
- longjmp(orig_stack, 1);
|
|
|
|
|
|
|
+ cs_longjmp(orig_stack);
|
|
|
|
|
|
|
|
/* Shouldn't get here. */
|
|
/* Shouldn't get here. */
|
|
|
abort();
|
|
abort();
|
|
@@ -148,23 +187,23 @@ static void
|
|
|
setup_context_1(void) {
|
|
setup_context_1(void) {
|
|
|
/* Save the current stack frame so we can return to it (at the end
|
|
/* Save the current stack frame so we can return to it (at the end
|
|
|
of setup_context_2()). */
|
|
of setup_context_2()). */
|
|
|
- if (setjmp(orig_stack) == 0) {
|
|
|
|
|
|
|
+ if (cs_setjmp(orig_stack) == 0) {
|
|
|
/* First, switch to the new stack. Save the current context using
|
|
/* First, switch to the new stack. Save the current context using
|
|
|
setjmp(). This saves out all of the processor register values,
|
|
setjmp(). This saves out all of the processor register values,
|
|
|
though it doesn't muck with the stack. */
|
|
though it doesn't muck with the stack. */
|
|
|
- static jmp_buf temp;
|
|
|
|
|
- if (setjmp(temp) == 0) {
|
|
|
|
|
|
|
+ static cs_jmp_buf temp;
|
|
|
|
|
+ if (cs_setjmp(temp) == 0) {
|
|
|
/* This is the initial return from setjmp. Still the original
|
|
/* This is the initial return from setjmp. Still the original
|
|
|
stack. */
|
|
stack. */
|
|
|
|
|
|
|
|
/* Now we overwrite the stack pointer value in the saved
|
|
/* Now we overwrite the stack pointer value in the saved
|
|
|
register context. This doesn't work with all implementations
|
|
register context. This doesn't work with all implementations
|
|
|
of setjmp/longjmp. */
|
|
of setjmp/longjmp. */
|
|
|
- (*(void **)&temp[JB_SP]) = (st_stack + st_stack_size);
|
|
|
|
|
|
|
+ (*(void **)&temp[CS_JB_SP]) = (st_stack + st_stack_size);
|
|
|
|
|
|
|
|
/* And finally, we place ourselves on the new stack by using
|
|
/* And finally, we place ourselves on the new stack by using
|
|
|
longjmp() to reload the modified context. */
|
|
longjmp() to reload the modified context. */
|
|
|
- longjmp(temp, 1);
|
|
|
|
|
|
|
+ cs_longjmp(temp);
|
|
|
|
|
|
|
|
/* Shouldn't get here. */
|
|
/* Shouldn't get here. */
|
|
|
abort();
|
|
abort();
|
|
@@ -198,7 +237,7 @@ init_thread_context(struct ThreadContext *context,
|
|
|
|
|
|
|
|
void save_thread_context(struct ThreadContext *context,
|
|
void save_thread_context(struct ThreadContext *context,
|
|
|
ContextFunction *next_context, void *data) {
|
|
ContextFunction *next_context, void *data) {
|
|
|
- if (setjmp(context->_jmp_context) != 0) {
|
|
|
|
|
|
|
+ if (cs_setjmp(context->_jmp_context) != 0) {
|
|
|
/* We have just returned from longjmp. In this case, return from
|
|
/* We have just returned from longjmp. In this case, return from
|
|
|
the function. The stack is still good. */
|
|
the function. The stack is still good. */
|
|
|
return;
|
|
return;
|
|
@@ -217,7 +256,7 @@ void save_thread_context(struct ThreadContext *context,
|
|
|
|
|
|
|
|
void
|
|
void
|
|
|
switch_to_thread_context(struct ThreadContext *context) {
|
|
switch_to_thread_context(struct ThreadContext *context) {
|
|
|
- longjmp(context->_jmp_context, 1);
|
|
|
|
|
|
|
+ cs_longjmp(context->_jmp_context);
|
|
|
|
|
|
|
|
/* Shouldn't get here. */
|
|
/* Shouldn't get here. */
|
|
|
abort();
|
|
abort();
|