| /* |
| * Copyright (c) 2009 Cisco Systems, Inc. All Rights Reserved. |
| * Copyright (c) 2009 FUJITSU LIMITED. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * Further, this software is distributed without any warranty that it is |
| * free of the rightful claim of any third person regarding infringement |
| * or the like. Any license provided herein, whether implied or |
| * otherwise, applies only to this software file. Patent licenses, if |
| * any, provided herein do not apply to combinations of this program with |
| * other software, or any other product whatsoever. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Author: Liu Bo <liubo2009@cn.fujitsu.com> |
| * Author: Garrett Cooper <yanegomi@gmail.com> |
| * |
| */ |
| |
| #ifndef LTP_RT_SIGACTION_H |
| #define LTP_RT_SIGACTION_H |
| |
| #include "ltp_signal.h" |
| |
| #define INVAL_SA_PTR ((void *)-1) |
| |
| struct kernel_sigaction { |
| __sighandler_t k_sa_handler; |
| unsigned long sa_flags; |
| void (*sa_restorer) (void); |
| sigset_t sa_mask; |
| }; |
| |
| /* This macro marks if (struct sigaction) has .sa_restorer member */ |
| #if !defined(__ia64__) && !defined(__alpha__) && !defined(__hppa__) && !defined(__mips__) |
| # define HAVE_SA_RESTORER |
| #endif |
| |
| #ifdef __x86_64__ |
| |
| /* |
| * From asm/signal.h -- this value isn't exported anywhere outside of glibc and |
| * asm/signal.h and is only required for the rt_sig* function family because |
| * sigaction(2), et all, appends this if necessary to |
| * (struct sigaction).sa_flags. HEH. |
| * |
| * I do #undef though, just in case... |
| * |
| * Also, from .../arch/x86/kernel/signal.c:448 for v2.6.30 (something or |
| * other): |
| * |
| * x86-64 should always use SA_RESTORER. |
| * |
| * -- thus SA_RESTORER must always be defined along with |
| * (struct sigaction).sa_restorer for this architecture. |
| */ |
| #undef SA_RESTORER |
| #define SA_RESTORER 0x04000000 |
| |
| void (*restore_rt)(void); |
| |
| static void handler_h(int signal) |
| { |
| return; |
| } |
| |
| /* Setup an initial signal handler for signal number = sig for x86_64. */ |
| static inline int sig_initial(int sig) |
| { |
| int ret_code = -1; |
| struct sigaction act, oact; |
| |
| act.sa_handler = handler_h; |
| act.sa_flags = 0; |
| /* Clear out the signal set. */ |
| if (sigemptyset(&act.sa_mask) < 0) { |
| /* Add the signal to the mask set. */ |
| } else if (sigaddset(&act.sa_mask, sig) < 0) { |
| /* Set act.sa_restorer via syscall(2) */ |
| } else if (sigaction(sig, &act, &oact) < 0) { |
| /* Copy oact.sa_restorer via syscall(2) */ |
| } else if (sigaction(sig, &act, &oact) < 0) { |
| /* And voila -- we just tricked the kernel into giving us our |
| * restorer function! */ |
| } else { |
| restore_rt = oact.sa_restorer; |
| ret_code = 0; |
| } |
| |
| return ret_code; |
| } |
| |
| #endif /* __x86_64__ */ |
| |
| #ifdef __sparc__ |
| # if defined __arch64__ || defined __sparcv9 |
| |
| /* |
| * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c |
| */ |
| |
| extern char *__rt_sig_stub; |
| |
| static void __attribute__((used)) __rt_sigreturn_stub(void) |
| { |
| __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" |
| "ta 0x6d\n\t" |
| : /* no outputs */ |
| : "i" (__NR_rt_sigreturn)); |
| } |
| |
| # else /* sparc32 */ |
| |
| /* |
| * Based on glibc/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c |
| */ |
| |
| extern char *__rt_sig_stub, *__sig_stub; |
| |
| static void __attribute__((used)) __rt_sigreturn_stub(void) |
| { |
| __asm__ ("__rt_sig_stub: mov %0, %%g1\n\t" |
| "ta 0x10\n\t" |
| : /* no outputs */ |
| : "i" (__NR_rt_sigreturn)); |
| } |
| |
| static void __attribute__((used)) __sigreturn_stub(void) |
| { |
| __asm__ ("__sig_stub: mov %0, %%g1\n\t" |
| "ta 0x10\n\t" |
| : /* no outputs */ |
| : "i" (__NR_sigreturn)); |
| } |
| |
| # endif |
| #endif /* __sparc__ */ |
| |
| #ifdef __arc__ |
| |
| #undef SA_RESTORER |
| #define SA_RESTORER 0x04000000 |
| |
| /* |
| * based on uClibc/libc/sysdeps/linux/arc/sigaction.c |
| */ |
| static void |
| __attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void) |
| { |
| __asm__ ( |
| "mov r8, %0 \n\t" |
| #ifdef __ARCHS__ |
| "trap_s 0 \n\t" |
| #else |
| "trap0 \n\t" |
| #endif |
| : /* no outputs */ |
| : "i" (__NR_rt_sigreturn) |
| : "r8"); |
| } |
| #endif |
| |
| /* This is a wrapper for __NR_rt_sigaction syscall. |
| * act/oact values of INVAL_SA_PTR is used to pass |
| * an invalid pointer to syscall(__NR_rt_sigaction) |
| * |
| * Based on glibc/sysdeps/unix/sysv/linux/{...}/sigaction.c |
| */ |
| |
| static int ltp_rt_sigaction(int signum, const struct sigaction *act, |
| struct sigaction *oact, size_t sigsetsize) |
| { |
| int ret; |
| struct kernel_sigaction kact, koact; |
| struct kernel_sigaction *kact_p = NULL; |
| struct kernel_sigaction *koact_p = NULL; |
| |
| if (act == INVAL_SA_PTR) { |
| kact_p = INVAL_SA_PTR; |
| } else if (act) { |
| kact.k_sa_handler = act->sa_handler; |
| memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t)); |
| kact.sa_flags = act->sa_flags; |
| kact.sa_restorer = NULL; |
| |
| kact_p = &kact; |
| } |
| |
| if (oact == INVAL_SA_PTR) |
| koact_p = INVAL_SA_PTR; |
| else if (oact) |
| koact_p = &koact; |
| |
| #ifdef __x86_64__ |
| sig_initial(signum); |
| #endif |
| |
| #if defined __x86_64__ || defined __arc__ |
| kact.sa_flags |= SA_RESTORER; |
| kact.sa_restorer = restore_rt; |
| #endif |
| |
| #ifdef __sparc__ |
| unsigned long stub = 0; |
| # if defined __arch64__ || defined __sparcv9 |
| stub = ((unsigned long) &__rt_sig_stub) - 8; |
| # else /* sparc32 */ |
| if ((kact.sa_flags & SA_SIGINFO) != 0) |
| stub = ((unsigned long) &__rt_sig_stub) - 8; |
| else |
| stub = ((unsigned long) &__sig_stub) - 8; |
| # endif |
| #endif |
| |
| |
| #ifdef __sparc__ |
| ret = ltp_syscall(__NR_rt_sigaction, signum, |
| kact_p, koact_p, |
| stub, sigsetsize); |
| #else |
| ret = ltp_syscall(__NR_rt_sigaction, signum, |
| kact_p, koact_p, |
| sigsetsize); |
| #endif |
| |
| if (ret >= 0) { |
| if (oact && (oact != INVAL_SA_PTR)) { |
| oact->sa_handler = koact.k_sa_handler; |
| memcpy(&oact->sa_mask, &koact.sa_mask, |
| sizeof(sigset_t)); |
| oact->sa_flags = koact.sa_flags; |
| #ifdef HAVE_SA_RESTORER |
| oact->sa_restorer = koact.sa_restorer; |
| #endif |
| } |
| } |
| |
| return ret; |
| } |
| |
| #endif /* LTP_RT_SIGACTION_H */ |