// x86_64-signal.h - Catch runtime signals and turn them into exceptions
// on an x86_64 based GNU/Linux system.

/* Copyright (C) 2003  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */


#ifndef JAVA_SIGNAL_H
#define JAVA_SIGNAL_H 1

#include <signal.h>
#include <sys/syscall.h>

#ifdef __x86_64__

#define HANDLE_SEGV 1

#define SIGNAL_HANDLER(_name)	\
static void _Jv_##_name (int, siginfo_t *, void *_p)

extern "C" 
{
  struct kernel_sigaction 
  {
    void (*k_sa_sigaction)(int,siginfo_t *,void *);
    unsigned long k_sa_flags;
    void (*k_sa_restorer) (void);
    sigset_t k_sa_mask;
  };
}

#define MAKE_THROW_FRAME(_exception)					\
do									\
{									\
  /* Advance the program counter so that it is after the start of the	\
     instruction:  the x86_64 exception handler expects			\
     the PC to point to the instruction after a call. */		\
  struct ucontext *_uc = (struct ucontext *)_p;				\
  volatile struct sigcontext *_sc = (struct sigcontext *) &_uc->uc_mcontext; \
  _sc->rip += 2;							\
}									\
while (0)

#define RESTORE(name, syscall) RESTORE2 (name, syscall)
#define RESTORE2(name, syscall)			\
asm						\
  (						\
   ".byte 0  # Yes, this really is necessary\n" \
   ".align 16\n"				\
   "__" #name ":\n"				\
   "	movq $" #syscall ", %rax\n"		\
   "	syscall\n"				\
   );

/* The return code for realtime-signals.  */
RESTORE (restore_rt, __NR_rt_sigreturn)
static void restore_rt (void) asm ("__restore_rt");

#define INIT_SEGV						\
do								\
  {								\
    nullp = new java::lang::NullPointerException ();		\
    struct kernel_sigaction act;				\
    act.k_sa_sigaction = _Jv_catch_segv;			\
    sigemptyset (&act.k_sa_mask);				\
    act.k_sa_flags = SA_SIGINFO|0x4000000;			\
    act.k_sa_restorer = restore_rt;				\
    syscall (SYS_rt_sigaction, SIGSEGV, &act, NULL, _NSIG / 8);	\
  }								\
while (0)  

/* We use syscall(SYS_rt_sigaction) in INIT_SEGV instead of
 * sigaction() because on some systems the pthreads wrappers for
 * signal handlers are not compiled with unwind information, so it's
 * not possible to unwind through them.  This is a problem that will
 * go away if all systems ever have pthreads libraries that are
 * compiled with unwind info.  */

#else /* __x86_64__ */

/* This is for the 32-bit subsystem on on x86-64.  Catching signals
   doesn't yet work on that target.  */

#undef HANDLE_SEGV
#undef HANDLE_FPE

#define INIT_SEGV   do {} while (0)
#define INIT_FPE   do {} while (0)

#endif /* __x86_64__ */
#endif /* JAVA_SIGNAL_H */
