frame_kern.c 4.18 KB
Newer Older
1 2 3 4 5 6 7 8
/* 
 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
 * Licensed under the GPL
 */

#include "asm/ptrace.h"
#include "asm/uaccess.h"
#include "asm/signal.h"
9 10
#include "asm/uaccess.h"
#include "asm/ucontext.h"
11 12 13
#include "frame_kern.h"
#include "sigcontext.h"
#include "sysdep/ptrace.h"
14 15
#include "choose-mode.h"
#include "mode.h"
16 17 18 19

static int copy_restorer(void (*restorer)(void), unsigned long start, 
			 unsigned long sr_index, int sr_relative)
{
20 21 22 23 24 25
	unsigned long sr;

	if(sr_relative){
		sr = (unsigned long) restorer;
		sr += start + sr_index;
		restorer = (void (*)(void)) sr;
26
	}
27 28 29 30 31

	return(copy_to_user((void *) (start + sr_index), &restorer, 
			    sizeof(restorer)));
}

32 33
static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, 
			   struct arch_frame_data *arch)
34
{
35 36 37
	return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), 
					      arch),
			   copy_sc_to_user_skas(to, fp, &from->regs,
38 39
						current->thread.cr2,
						current->thread.err)));
40 41
}

42 43 44 45 46 47 48 49 50 51 52 53 54 55
static int copy_ucontext_to_user(struct ucontext *uc, void *fp, sigset_t *set,
				 unsigned long sp)
{
	int err = 0;

	err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
	err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
	err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
	err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs,
			       &signal_frame_si.common.arch);
	err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
	return(err);
}

56 57 58 59 60
int setup_signal_stack_si(unsigned long stack_top, int sig, 
			  unsigned long handler, void (*restorer)(void), 
			  struct pt_regs *regs, siginfo_t *info, 
			  sigset_t *mask)
{
61 62
	unsigned long start;
	void *sip, *ucp, *fp;
63

64
	start = stack_top - signal_frame_si.common.len;
65
	sip = (void *) (start + signal_frame_si.si_index);
66 67
	ucp = (void *) (start + signal_frame_si.uc_index);
	fp = (void *) (((unsigned long) ucp) + sizeof(struct ucontext));
68 69 70 71

	if(restorer == NULL)
		panic("setup_signal_stack_si - no restorer");

72
	if(copy_to_user((void *) start, signal_frame_si.common.data,
73 74 75
			signal_frame_si.common.len) ||
	   copy_to_user((void *) (start + signal_frame_si.common.sig_index), 
			&sig, sizeof(sig)) ||
76 77 78
	   copy_siginfo_to_user(sip, info) ||
	   copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
			sizeof(sip)) ||
79 80 81
	   copy_ucontext_to_user(ucp, fp, mask, PT_REGS_SP(regs)) ||
	   copy_to_user((void *) (start + signal_frame_si.ucp_index), &ucp,
			sizeof(ucp)) ||
82 83
	   copy_restorer(restorer, start, signal_frame_si.common.sr_index,
			 signal_frame_si.common.sr_relative))
84 85 86
		return(1);
	
	PT_REGS_IP(regs) = handler;
87
	PT_REGS_SP(regs) = start + signal_frame_si.common.sp_index;
88 89 90 91 92 93 94
	return(0);
}

int setup_signal_stack_sc(unsigned long stack_top, int sig, 
			  unsigned long handler, void (*restorer)(void), 
			  struct pt_regs *regs, sigset_t *mask)
{
95 96
	struct frame_common *frame = &signal_frame_sc_sr.common;
	void *user_sc;
97
	int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
98 99 100 101 102 103 104 105 106 107 108 109
	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);
	}
110

111 112 113
	sigs = start + frame->len;
	if(copy_to_user((void *) start, frame->data, frame->len) ||
	   copy_to_user((void *) (start + frame->sig_index), &sig, 
114
			sizeof(sig)) ||
115 116
	   copy_sc_to_user(user_sc, NULL, regs, 
			   &signal_frame_sc.common.arch) ||
117 118
	   copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
	   copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
119
	   copy_restorer(restorer, start, frame->sr_index, frame->sr_relative))
120 121 122
		return(1);

	PT_REGS_IP(regs) = handler;
123
	PT_REGS_SP(regs) = start + frame->sp_index;
124 125 126 127 128 129 130 131 132 133 134 135 136 137

	return(0);
}

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-file-style: "linux"
 * End:
 */