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