We must not scratch any registers in signal bottom half handlers
because jit code that triggered signal is unaware that these registers
are modified.  We should save/restore all caller saved registers
before calling the bottom half handler. We do it in signal_bh_trampoline
assembly routine installed by install_signal_bh().

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/Makefile_32 |    1 +
 arch/x86/signal.c    |   15 ++++++++++++---
 arch/x86/signal_32.S |   42 ++++++++++++++++++++++++++++++++++++++++++
 include/vm/signal.h  |    7 ++++++-
 vm/signal.c          |   31 +++++++++++++++++++++++++++----
 5 files changed, 88 insertions(+), 8 deletions(-)
 create mode 100644 arch/x86/signal_32.S

diff --git a/arch/x86/Makefile_32 b/arch/x86/Makefile_32
index 8b37c34..7242102 100644
--- a/arch/x86/Makefile_32
+++ b/arch/x86/Makefile_32
@@ -10,5 +10,6 @@ ARCH_OBJS = \
        arch/x86/signal.o               \
        arch/x86/stack-frame.o          \
        arch/x86/unwind_32.o            \
+       arch/x86/signal_32.o            \
        arch/x86/use-def.o              \
        arch/x86/thread.o
diff --git a/arch/x86/signal.c b/arch/x86/signal.c
index f36464c..724ece8 100644
--- a/arch/x86/signal.c
+++ b/arch/x86/signal.c
@@ -32,6 +32,8 @@
 
 #include <vm/signal.h>
 
+extern void signal_bh_trampoline(void *bh);
+
 bool signal_from_native(void *ctx)
 {
        ucontext_t *uc;
@@ -65,12 +67,19 @@ int install_signal_bh(void *ctx, signal_bh_fn bh)
 
        uc = ctx;
 
+       stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP];
+
        /* push return address on stack */
-       stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP] - 1;
+       stack--;
        *stack = uc->uc_mcontext.gregs[REG_IP];
-       uc->uc_mcontext.gregs[REG_SP] -= sizeof(unsigned long);
 
-       uc->uc_mcontext.gregs[REG_IP] = (unsigned long)bh;
+       /* push bottom-half handler address on stack */
+       stack--;
+       *stack = bh;
+
+       uc->uc_mcontext.gregs[REG_SP] -= 2 * sizeof(unsigned long);
+
+       uc->uc_mcontext.gregs[REG_IP] = (unsigned long)signal_bh_trampoline;
 
        return 0;
 }
diff --git a/arch/x86/signal_32.S b/arch/x86/signal_32.S
new file mode 100644
index 0000000..af2d044
--- /dev/null
+++ b/arch/x86/signal_32.S
@@ -0,0 +1,42 @@
+.global signal_bh_trampoline
+.text
+
+/*
+ * signal_bh_trampoline - saves the caller saved registers and calls
+ *                        signal bottom half hanlder.
+ */
+signal_bh_trampoline:
+       push %ebp
+       mov %esp, %ebp
+
+       /* save caller saved registers */
+       pushl %eax
+       pushl %ecx
+       pushl %edx
+
+       /* push signal bottom half handler's argument - address of
+          faulting instruction. */
+       pushl 8(%ebp)
+
+       /* call the signal bottom half handler */
+       pushl $.bh_return
+       pushl 4(%ebp)
+       ret
+
+.bh_return:
+       /* cleanup call arguments */
+       addl $4,%esp
+
+       /* overwrite return address */
+       movl %eax, 8(%ebp)
+
+       /* restore caller saved registers */
+       popl %edx
+       popl %ecx
+       popl %eax
+
+       popl %ebp
+
+       /* Skip bottom half hanlder address pushed by signal_install_bh() */
+       addl $4,%esp
+       ret
diff --git a/include/vm/signal.h b/include/vm/signal.h
index dad9381..a188daf 100644
--- a/include/vm/signal.h
+++ b/include/vm/signal.h
@@ -1,7 +1,12 @@
 #ifndef VM_SIGNAL_H
 #define VM_SIGNAL_H
 
-typedef void (*signal_bh_fn)(void);
+/*
+ * Signal bottom half handler is called with the address of faulting
+ * instruction as argument. The address that handler returns is the
+ * address to which controll will be transfered when it returns.
+ */
+typedef unsigned long (*signal_bh_fn)(unsigned long);
 
 void setup_signal_handlers(void);
 int install_signal_bh(void *ctx, signal_bh_fn bh);
diff --git a/vm/signal.c b/vm/signal.c
index ea33596..c1dfdc7 100644
--- a/vm/signal.c
+++ b/vm/signal.c
@@ -37,17 +37,40 @@
 #include <stddef.h>
 #include <unistd.h>
 
-static void throw_arithmetic_exception(void)
+static unsigned long
+throw_from_signal_bh(unsigned long jit_addr)
+{
+       struct jit_stack_frame *frame;
+       struct compilation_unit *cu;
+
+       /*
+        * The frame chain looks like this here:
+        *
+        * 0  <throw_from_signal_bh>
+        * 1  <signal_bottom_half_handler>
+        * 2  <signal_bh_trampoline>
+        * 3  <jit_method>
+        *    ...
+        */
+       frame = __builtin_frame_address(3);
+
+       cu = get_cu_from_native_addr(jit_addr);
+
+       return (unsigned long)throw_exception_from(cu, frame,
+               (unsigned char *)jit_addr);
+}
+
+static unsigned long throw_arithmetic_exception(unsigned long src_addr)
 {
        signal_new_exception("java/lang/ArithmeticException",
                             "division by zero");
-       throw_from_native(0);
+       return throw_from_signal_bh(src_addr);
 }
 
-static void throw_null_pointer_exception(void)
+static unsigned long throw_null_pointer_exception(unsigned long src_addr)
 {
        signal_new_exception("java/lang/NullPointerException", NULL);
-       throw_from_native(0);
+       return throw_from_signal_bh(src_addr);
 }
 
 static void sigfpe_handler(int sig, siginfo_t *si, void *ctx)
-- 
1.6.0.6


------------------------------------------------------------------------------
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to