Commit fd3f9c88 authored by Jeff Dike's avatar Jeff Dike

Merged the signal frame cleanups and fixes from 2.4.

parent 31a47189
...@@ -8,34 +8,34 @@ ...@@ -8,34 +8,34 @@
#include "sysdep/frame.h" #include "sysdep/frame.h"
struct sc_frame { struct frame_common {
void *data; void *data;
int len; int len;
int sig_index; int sig_index;
int sc_index;
int sr_index; int sr_index;
int sr_relative; int sr_relative;
int sp_index; int sp_index;
};
struct sc_frame {
struct frame_common common;
int sc_index;
struct arch_frame_data arch; struct arch_frame_data arch;
}; };
extern struct sc_frame signal_frame_sc; extern struct sc_frame signal_frame_sc;
extern struct sc_frame signal_frame_sc_sr;
struct si_frame { struct si_frame {
void *data; struct frame_common common;
int len;
int sig_index;
int sip_index; int sip_index;
int si_index; int si_index;
int sr_index;
int sr_relative;
int sp_index;
}; };
extern struct si_frame signal_frame_si; extern struct si_frame signal_frame_si;
extern void capture_signal_stack(void); extern void capture_signal_stack(void);
extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
#endif #endif
......
...@@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp) ...@@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp)
{ {
unsigned long sc; unsigned long sc;
sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4; sc = sp - signal_frame_si.common.sp_index +
signal_frame_si.common.len - 4;
return((void *) sc); return((void *) sc);
} }
...@@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp) ...@@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp)
{ {
unsigned long mask; unsigned long mask;
mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8; mask = sp - signal_frame_sc.common.sp_index +
signal_frame_sc.common.len - 8;
return((void *) mask); return((void *) mask);
} }
...@@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp) ...@@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp)
{ {
unsigned long mask; unsigned long mask;
mask = sp - signal_frame_si.sp_index + signal_frame_si.len + mask = sp - signal_frame_si.common.sp_index +
signal_frame_si.common.len +
sc_size(&signal_frame_sc.arch) - 4; sc_size(&signal_frame_sc.arch) - 4;
return((void *) mask); return((void *) mask);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <sched.h> #include <sched.h>
#include <errno.h> #include <errno.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, ...@@ -84,8 +85,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
printf("capture_stack : waitpid failed - errno = %d\n", errno); printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1); exit(1);
} }
if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
printf("capture_stack : Expected exit status 0, " printf("capture_stack : Expected exit signal 9, "
"got status = 0x%x\n", status); "got status = 0x%x\n", status);
exit(1); exit(1);
} }
...@@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, ...@@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
return(len); return(len);
} }
static void child_common(void *sp, int size, sighandler_t handler, int flags) struct common_raw {
void *stack;
int size;
unsigned long sig;
unsigned long sr;
unsigned long sp;
};
#define SA_RESTORER (0x04000000)
typedef unsigned long old_sigset_t;
struct old_sigaction {
__sighandler_t handler;
old_sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
static void child_common(struct common_raw *common, sighandler_t handler,
int restorer, int flags)
{ {
stack_t ss; stack_t ss = ((stack_t) { .ss_sp = common->stack,
struct sigaction sa; .ss_flags = 0,
.ss_size = common->size });
int err;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
printf("PTRACE_TRACEME failed, errno = %d\n", errno); printf("PTRACE_TRACEME failed, errno = %d\n", errno);
} }
ss.ss_sp = sp;
ss.ss_flags = 0;
ss.ss_size = size;
if(sigaltstack(&ss, NULL) < 0){ if(sigaltstack(&ss, NULL) < 0){
printf("sigaltstack failed - errno = %d\n", errno); printf("sigaltstack failed - errno = %d\n", errno);
_exit(1); kill(getpid(), SIGKILL);
} }
if(restorer){
struct sigaction sa;
sa.sa_handler = handler; sa.sa_handler = handler;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | flags; sa.sa_flags = SA_ONSTACK | flags;
if(sigaction(SIGUSR1, &sa, NULL) < 0){ err = sigaction(SIGUSR1, &sa, NULL);
}
else {
struct old_sigaction sa;
sa.handler = handler;
sa.sa_mask = 0;
sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER;
err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL);
}
if(err < 0){
printf("sigaction failed - errno = %d\n", errno); printf("sigaction failed - errno = %d\n", errno);
_exit(1); kill(getpid(), SIGKILL);
} }
os_stop_process(os_getpid()); os_stop_process(os_getpid());
...@@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags) ...@@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags)
/* Changed only during early boot */ /* Changed only during early boot */
struct sc_frame signal_frame_sc; struct sc_frame signal_frame_sc;
struct sc_frame signal_frame_sc_sr;
struct sc_frame_raw { struct sc_frame_raw {
void *stack; struct common_raw common;
int size;
unsigned long sig;
unsigned long sc; unsigned long sc;
unsigned long sr; int restorer;
unsigned long sp;
struct arch_frame_data_raw arch; struct arch_frame_data_raw arch;
}; };
...@@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL; ...@@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL;
static void sc_handler(int sig, struct sigcontext sc) static void sc_handler(int sig, struct sigcontext sc)
{ {
raw_sc->sig = (unsigned long) &sig; raw_sc->common.sig = (unsigned long) &sig;
raw_sc->common.sr = frame_restorer();
raw_sc->common.sp = frame_sp();
raw_sc->sc = (unsigned long) &sc; raw_sc->sc = (unsigned long) &sc;
raw_sc->sr = frame_restorer();
raw_sc->sp = frame_sp();
setup_arch_frame_raw(&raw_sc->arch, &sc); setup_arch_frame_raw(&raw_sc->arch, &sc);
os_stop_process(os_getpid()); os_stop_process(os_getpid());
_exit(0); kill(getpid(), SIGKILL);
} }
static int sc_child(void *arg) static int sc_child(void *arg)
{ {
raw_sc = arg; raw_sc = arg;
child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, child_common(&raw_sc->common, (sighandler_t) sc_handler,
0); raw_sc->restorer, 0);
return(-1); return(-1);
} }
...@@ -169,13 +202,9 @@ static int sc_child(void *arg) ...@@ -169,13 +202,9 @@ static int sc_child(void *arg)
struct si_frame signal_frame_si; struct si_frame signal_frame_si;
struct si_frame_raw { struct si_frame_raw {
void *stack; struct common_raw common;
int size;
unsigned long sig;
unsigned long sip; unsigned long sip;
unsigned long si; unsigned long si;
unsigned long sr;
unsigned long sp;
}; };
/* Changed only during early boot */ /* Changed only during early boot */
...@@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL; ...@@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL;
static void si_handler(int sig, siginfo_t *si) static void si_handler(int sig, siginfo_t *si)
{ {
raw_si->sig = (unsigned long) &sig; raw_si->common.sig = (unsigned long) &sig;
raw_si->common.sr = frame_restorer();
raw_si->common.sp = frame_sp();
raw_si->sip = (unsigned long) &si; raw_si->sip = (unsigned long) &si;
raw_si->si = (unsigned long) si; raw_si->si = (unsigned long) si;
raw_si->sr = frame_restorer();
raw_si->sp = frame_sp();
os_stop_process(os_getpid()); os_stop_process(os_getpid());
_exit(0); kill(getpid(), SIGKILL);
} }
static int si_child(void *arg) static int si_child(void *arg)
{ {
raw_si = arg; raw_si = arg;
child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler, child_common(&raw_si->common, (sighandler_t) si_handler, 1,
SA_SIGINFO); SA_SIGINFO);
return(-1); return(-1);
} }
static int relative_sr(unsigned long sr, int sr_index, void *stack,
void *framep)
{
unsigned long *srp = (unsigned long *) sr;
unsigned long frame = (unsigned long) framep;
if((*srp & PAGE_MASK) == (unsigned long) stack){
*srp -= sr;
*((unsigned long *) (frame + sr_index)) = *srp;
return(1);
}
else return(0);
}
static unsigned long capture_stack_common(int (*proc)(void *), void *arg,
struct common_raw *common_in,
void *top, void *sigstack,
int stack_len,
struct frame_common *common_out)
{
unsigned long sig_top = (unsigned long) sigstack + stack_len, base;
common_in->stack = (void *) sigstack;
common_in->size = stack_len;
common_out->len = capture_stack(proc, arg, top, sig_top,
&common_out->data);
base = sig_top - common_out->len;
common_out->sig_index = common_in->sig - base;
common_out->sp_index = common_in->sp - base;
common_out->sr_index = common_in->sr - base;
common_out->sr_relative = relative_sr(common_in->sr,
common_out->sr_index, sigstack,
common_out->data);
return(base);
}
void capture_signal_stack(void) void capture_signal_stack(void)
{ {
struct sc_frame_raw raw_sc; struct sc_frame_raw raw_sc;
...@@ -220,54 +285,29 @@ void capture_signal_stack(void) ...@@ -220,54 +285,29 @@ void capture_signal_stack(void)
top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
sig_top = (unsigned long) sigstack + PAGE_SIZE; sig_top = (unsigned long) sigstack + PAGE_SIZE;
raw_sc.stack = sigstack; /* Get the sigcontext, no sigrestorer layout */
raw_sc.size = PAGE_SIZE; raw_sc.restorer = 0;
signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top, base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
sig_top, &signal_frame_sc.data); (void *) top, sigstack, PAGE_SIZE,
&signal_frame_sc.common);
/* These are the offsets within signal_frame_sc.data (counting from
* the bottom) of sig, sc, SA_RESTORER, and the initial sp.
*/
base = sig_top - signal_frame_sc.len;
signal_frame_sc.sig_index = raw_sc.sig - base;
signal_frame_sc.sc_index = raw_sc.sc - base; signal_frame_sc.sc_index = raw_sc.sc - base;
signal_frame_sc.sr_index = raw_sc.sr - base;
if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) ==
(unsigned long) sigstack){
unsigned long *sr = (unsigned long *) raw_sc.sr;
unsigned long frame = (unsigned long) signal_frame_sc.data;
signal_frame_sc.sr_relative = 1;
*sr -= raw_sc.sr;
*((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
}
else signal_frame_sc.sr_relative = 0;
signal_frame_sc.sp_index = raw_sc.sp - base;
setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch); setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
/* Repeat for the siginfo variant */ /* Ditto for the sigcontext, sigrestorer layout */
raw_sc.restorer = 1;
base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_sc_sr.common);
signal_frame_sc_sr.sc_index = raw_sc.sc - base;
/* And the siginfo layout */
raw_si.stack = sigstack; base = capture_stack_common(si_child, &raw_si, &raw_si.common,
raw_si.size = PAGE_SIZE; (void *) top, sigstack, PAGE_SIZE,
signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top, &signal_frame_si.common);
sig_top, &signal_frame_si.data);
base = sig_top - signal_frame_si.len;
signal_frame_si.sig_index = raw_si.sig - base;
signal_frame_si.sip_index = raw_si.sip - base; signal_frame_si.sip_index = raw_si.sip - base;
signal_frame_si.si_index = raw_si.si - base; signal_frame_si.si_index = raw_si.si - base;
signal_frame_si.sr_index = raw_si.sr - base;
if((*((unsigned long *) raw_si.sr) & PAGE_MASK) ==
(unsigned long) sigstack){
unsigned long *sr = (unsigned long *) raw_si.sr;
unsigned long frame = (unsigned long) signal_frame_si.data;
signal_frame_sc.sr_relative = 1;
*sr -= raw_si.sr;
*((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
}
else signal_frame_si.sr_relative = 0;
signal_frame_si.sp_index = raw_si.sp - base;
if((munmap(stack, PAGE_SIZE) < 0) || if((munmap(stack, PAGE_SIZE) < 0) ||
(munmap(sigstack, PAGE_SIZE) < 0)){ (munmap(sigstack, PAGE_SIZE) < 0)){
...@@ -277,14 +317,6 @@ void capture_signal_stack(void) ...@@ -277,14 +317,6 @@ void capture_signal_stack(void)
} }
} }
void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
{
struct sigcontext *sc = sc_ptr;
SC_IP(sc) = ip;
SC_SP(sc) = sp;
}
/* /*
* Overrides for Emacs so that we follow Linus's tabbing style. * Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -13,16 +13,25 @@ ...@@ -13,16 +13,25 @@
static int copy_restorer(void (*restorer)(void), unsigned long start, static int copy_restorer(void (*restorer)(void), unsigned long start,
unsigned long sr_index, int sr_relative) unsigned long sr_index, int sr_relative)
{ {
if(restorer != 0){ unsigned long sr;
if(copy_to_user((void *) (start + sr_index), &restorer,
sizeof(restorer))) if(sr_relative){
return(1); sr = (unsigned long) restorer;
} sr += start + sr_index;
else if(sr_relative){ restorer = (void (*)(void)) sr;
unsigned long *sr = (unsigned long *) (start + sr_index);
*sr += (unsigned long) sr;
} }
return(0);
return(copy_to_user((void *) (start + sr_index), &restorer,
sizeof(restorer)));
}
static int copy_sc_to_user(void *to, struct pt_regs *from)
{
return(CHOOSE_MODE(copy_sc_to_user_tt(to, from->regs.mode.tt,
&signal_frame_sc_sr.arch),
copy_sc_to_user_skas(to, &from->regs,
current->thread.cr2,
current->thread.err)));
} }
int setup_signal_stack_si(unsigned long stack_top, int sig, int setup_signal_stack_si(unsigned long stack_top, int sig,
...@@ -34,27 +43,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, ...@@ -34,27 +43,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
void *sip; void *sip;
int sig_size = _NSIG_WORDS * sizeof(unsigned long); int sig_size = _NSIG_WORDS * sizeof(unsigned long);
start = stack_top - signal_frame_si.len - start = stack_top - signal_frame_si.common.len -
sc_size(&signal_frame_sc.arch) - sig_size; sc_size(&signal_frame_sc.arch) - sig_size;
sip = (void *) (start + signal_frame_si.si_index); sip = (void *) (start + signal_frame_si.si_index);
sc = start + signal_frame_si.len; sc = start + signal_frame_si.common.len;
sigs = sc + sc_size(&signal_frame_sc.arch); sigs = sc + sc_size(&signal_frame_sc.arch);
if(copy_sc_to_user((void *) sc, regs->regs.sc,
&signal_frame_sc.arch) || if(restorer == NULL)
copy_to_user((void *) start, signal_frame_si.data, panic("setup_signal_stack_si - no restorer");
signal_frame_si.len) ||
copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, if(copy_sc_to_user((void *) sc, regs) ||
sizeof(sig)) || copy_to_user((void *) start, signal_frame_si.common.data,
signal_frame_si.common.len) ||
copy_to_user((void *) (start + signal_frame_si.common.sig_index),
&sig, sizeof(sig)) ||
copy_siginfo_to_user(sip, info) || copy_siginfo_to_user(sip, info) ||
copy_to_user((void *) (start + signal_frame_si.sip_index), &sip, copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
sizeof(sip)) || sizeof(sip)) ||
copy_to_user((void *) sigs, mask, sig_size) || copy_to_user((void *) sigs, mask, sig_size) ||
copy_restorer(restorer, start, signal_frame_si.sr_index, copy_restorer(restorer, start, signal_frame_si.common.sr_index,
signal_frame_si.sr_relative)) signal_frame_si.common.sr_relative))
return(1); return(1);
PT_REGS_IP(regs) = handler; PT_REGS_IP(regs) = handler;
PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; PT_REGS_SP(regs) = start + signal_frame_sc.common.sp_index;
return(0); return(0);
} }
...@@ -62,26 +74,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, ...@@ -62,26 +74,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
unsigned long handler, void (*restorer)(void), unsigned long handler, void (*restorer)(void),
struct pt_regs *regs, sigset_t *mask) struct pt_regs *regs, sigset_t *mask)
{ {
struct frame_common *frame = &signal_frame_sc_sr.common;
void *user_sc;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size; unsigned long sigs, sr;
void *user_sc = (void *) (start + signal_frame_sc.sc_index); unsigned long start = stack_top - frame->len - sig_size;
user_sc = (void *) (start + signal_frame_sc_sr.sc_index);
if(restorer == NULL){
frame = &signal_frame_sc.common;
user_sc = (void *) (start + signal_frame_sc.sc_index);
sr = (unsigned long) frame->data;
sr += frame->sr_index;
sr = *((unsigned long *) sr);
restorer = ((void (*)(void)) sr);
}
sigs = start + signal_frame_sc.len; sigs = start + frame->len;
if(copy_to_user((void *) start, signal_frame_sc.data, if(copy_to_user((void *) start, frame->data, frame->len) ||
signal_frame_sc.len) || copy_to_user((void *) (start + frame->sig_index), &sig,
copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
sizeof(sig)) || sizeof(sig)) ||
copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) || copy_sc_to_user(user_sc, regs) ||
copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
copy_to_user((void *) sigs, &mask->sig[1], sig_size) || copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
copy_restorer(restorer, start, signal_frame_sc.sr_index, copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
signal_frame_sc.sr_relative))
return(1); return(1);
PT_REGS_IP(regs) = handler; PT_REGS_IP(regs) = handler;
PT_REGS_SP(regs) = start + signal_frame_sc.sp_index; PT_REGS_SP(regs) = start + frame->sp_index;
set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
return(0); return(0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment