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 @@
#include "sysdep/frame.h"
struct sc_frame {
struct frame_common {
void *data;
int len;
int sig_index;
int sc_index;
int sr_index;
int sr_relative;
int sp_index;
};
struct sc_frame {
struct frame_common common;
int sc_index;
struct arch_frame_data arch;
};
extern struct sc_frame signal_frame_sc;
extern struct sc_frame signal_frame_sc_sr;
struct si_frame {
void *data;
int len;
int sig_index;
struct frame_common common;
int sip_index;
int si_index;
int sr_index;
int sr_relative;
int sp_index;
};
extern struct si_frame signal_frame_si;
extern void capture_signal_stack(void);
extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
#endif
......
......@@ -20,7 +20,8 @@ static inline void *sp_to_rt_sc(unsigned long sp)
{
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);
}
......@@ -28,7 +29,8 @@ static inline void *sp_to_mask(unsigned long sp)
{
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);
}
......@@ -38,7 +40,8 @@ static inline void *sp_to_rt_mask(unsigned long sp)
{
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;
return((void *) mask);
}
......
......@@ -12,6 +12,7 @@
#include <sched.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <asm/page.h>
#include <asm/ptrace.h>
......@@ -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);
exit(1);
}
if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
printf("capture_stack : Expected exit status 0, "
if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){
printf("capture_stack : Expected exit signal 9, "
"got status = 0x%x\n", status);
exit(1);
}
......@@ -103,28 +104,61 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
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;
struct sigaction sa;
stack_t ss = ((stack_t) { .ss_sp = common->stack,
.ss_flags = 0,
.ss_size = common->size });
int err;
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
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){
printf("sigaltstack failed - errno = %d\n", errno);
_exit(1);
kill(getpid(), SIGKILL);
}
if(restorer){
struct sigaction sa;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
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);
_exit(1);
kill(getpid(), SIGKILL);
}
os_stop_process(os_getpid());
......@@ -133,13 +167,12 @@ static void child_common(void *sp, int size, sighandler_t handler, int flags)
/* Changed only during early boot */
struct sc_frame signal_frame_sc;
struct sc_frame signal_frame_sc_sr;
struct sc_frame_raw {
void *stack;
int size;
unsigned long sig;
struct common_raw common;
unsigned long sc;
unsigned long sr;
unsigned long sp;
int restorer;
struct arch_frame_data_raw arch;
};
......@@ -148,20 +181,20 @@ static struct sc_frame_raw *raw_sc = NULL;
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->sr = frame_restorer();
raw_sc->sp = frame_sp();
setup_arch_frame_raw(&raw_sc->arch, &sc);
os_stop_process(os_getpid());
_exit(0);
kill(getpid(), SIGKILL);
}
static int sc_child(void *arg)
{
raw_sc = arg;
child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler,
0);
child_common(&raw_sc->common, (sighandler_t) sc_handler,
raw_sc->restorer, 0);
return(-1);
}
......@@ -169,13 +202,9 @@ static int sc_child(void *arg)
struct si_frame signal_frame_si;
struct si_frame_raw {
void *stack;
int size;
unsigned long sig;
struct common_raw common;
unsigned long sip;
unsigned long si;
unsigned long sr;
unsigned long sp;
};
/* Changed only during early boot */
......@@ -183,23 +212,59 @@ static struct si_frame_raw *raw_si = NULL;
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->si = (unsigned long) si;
raw_si->sr = frame_restorer();
raw_si->sp = frame_sp();
os_stop_process(os_getpid());
_exit(0);
kill(getpid(), SIGKILL);
}
static int si_child(void *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);
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)
{
struct sc_frame_raw raw_sc;
......@@ -220,54 +285,29 @@ void capture_signal_stack(void)
top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
sig_top = (unsigned long) sigstack + PAGE_SIZE;
raw_sc.stack = sigstack;
raw_sc.size = PAGE_SIZE;
signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
sig_top, &signal_frame_sc.data);
/* These are the offsets within signal_frame_sc.data (counting from
* the bottom) of sig, sc, SA_RESTORER, and the initial sp.
*/
/* Get the sigcontext, no sigrestorer layout */
raw_sc.restorer = 0;
base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_sc.common);
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.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);
/* 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;
raw_si.size = PAGE_SIZE;
signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
sig_top, &signal_frame_si.data);
base = sig_top - signal_frame_si.len;
signal_frame_si.sig_index = raw_si.sig - base;
base = capture_stack_common(si_child, &raw_si, &raw_si.common,
(void *) top, sigstack, PAGE_SIZE,
&signal_frame_si.common);
signal_frame_si.sip_index = raw_si.sip - 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) ||
(munmap(sigstack, PAGE_SIZE) < 0)){
......@@ -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.
* Emacs will notice this stuff at the end of the file and automatically
......
......@@ -13,16 +13,25 @@
static int copy_restorer(void (*restorer)(void), unsigned long start,
unsigned long sr_index, int sr_relative)
{
if(restorer != 0){
if(copy_to_user((void *) (start + sr_index), &restorer,
sizeof(restorer)))
return(1);
}
else if(sr_relative){
unsigned long *sr = (unsigned long *) (start + sr_index);
*sr += (unsigned long) sr;
unsigned long sr;
if(sr_relative){
sr = (unsigned long) restorer;
sr += start + sr_index;
restorer = (void (*)(void)) 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,
......@@ -34,27 +43,30 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
void *sip;
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;
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);
if(copy_sc_to_user((void *) sc, regs->regs.sc,
&signal_frame_sc.arch) ||
copy_to_user((void *) start, signal_frame_si.data,
signal_frame_si.len) ||
copy_to_user((void *) (start + signal_frame_si.sig_index), &sig,
sizeof(sig)) ||
if(restorer == NULL)
panic("setup_signal_stack_si - no restorer");
if(copy_sc_to_user((void *) sc, regs) ||
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_to_user((void *) (start + signal_frame_si.sip_index), &sip,
sizeof(sip)) ||
copy_to_user((void *) sigs, mask, sig_size) ||
copy_restorer(restorer, start, signal_frame_si.sr_index,
signal_frame_si.sr_relative))
copy_restorer(restorer, start, signal_frame_si.common.sr_index,
signal_frame_si.common.sr_relative))
return(1);
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);
}
......@@ -62,26 +74,35 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
unsigned long handler, void (*restorer)(void),
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);
unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size;
void *user_sc = (void *) (start + signal_frame_sc.sc_index);
unsigned long sigs, sr;
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;
if(copy_to_user((void *) start, signal_frame_sc.data,
signal_frame_sc.len) ||
copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
sigs = start + frame->len;
if(copy_to_user((void *) start, frame->data, frame->len) ||
copy_to_user((void *) (start + frame->sig_index), &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((void *) sigs, &mask->sig[1], sig_size) ||
copy_restorer(restorer, start, signal_frame_sc.sr_index,
signal_frame_sc.sr_relative))
copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
return(1);
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);
}
......
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