diff options
Diffstat (limited to 'arch/um/sys-x86_64')
-rw-r--r-- | arch/um/sys-x86_64/ptrace.c | 22 | ||||
-rw-r--r-- | arch/um/sys-x86_64/signal.c | 56 | ||||
-rw-r--r-- | arch/um/sys-x86_64/user-offsets.c | 6 |
3 files changed, 68 insertions, 16 deletions
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 74eee5c7c6dd..147bbf05cbc2 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <asm/ptrace.h> | 8 | #include <asm/ptrace.h> |
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/mm.h> | ||
11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
12 | #include <asm/elf.h> | 13 | #include <asm/elf.h> |
13 | 14 | ||
@@ -136,9 +137,28 @@ void arch_switch(void) | |||
136 | */ | 137 | */ |
137 | } | 138 | } |
138 | 139 | ||
140 | /* XXX Mostly copied from sys-i386 */ | ||
139 | int is_syscall(unsigned long addr) | 141 | int is_syscall(unsigned long addr) |
140 | { | 142 | { |
141 | panic("is_syscall"); | 143 | unsigned short instr; |
144 | int n; | ||
145 | |||
146 | n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); | ||
147 | if(n){ | ||
148 | /* access_process_vm() grants access to vsyscall and stub, | ||
149 | * while copy_from_user doesn't. Maybe access_process_vm is | ||
150 | * slow, but that doesn't matter, since it will be called only | ||
151 | * in case of singlestepping, if copy_from_user failed. | ||
152 | */ | ||
153 | n = access_process_vm(current, addr, &instr, sizeof(instr), 0); | ||
154 | if(n != sizeof(instr)) { | ||
155 | printk("is_syscall : failed to read instruction from " | ||
156 | "0x%lx\n", addr); | ||
157 | return(1); | ||
158 | } | ||
159 | } | ||
160 | /* sysenter */ | ||
161 | return(instr == 0x050f); | ||
142 | } | 162 | } |
143 | 163 | ||
144 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) | 164 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) |
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index fe1d065332b1..e75c4e1838b0 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c | |||
@@ -55,7 +55,8 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, | |||
55 | } | 55 | } |
56 | 56 | ||
57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | 57 | int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, |
58 | struct pt_regs *regs, unsigned long mask) | 58 | struct pt_regs *regs, unsigned long mask, |
59 | unsigned long sp) | ||
59 | { | 60 | { |
60 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; | 61 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
61 | int err = 0; | 62 | int err = 0; |
@@ -70,7 +71,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
70 | err |= PUTREG(regs, RDI, to, rdi); | 71 | err |= PUTREG(regs, RDI, to, rdi); |
71 | err |= PUTREG(regs, RSI, to, rsi); | 72 | err |= PUTREG(regs, RSI, to, rsi); |
72 | err |= PUTREG(regs, RBP, to, rbp); | 73 | err |= PUTREG(regs, RBP, to, rbp); |
73 | err |= PUTREG(regs, RSP, to, rsp); | 74 | /* Must use orignal RSP, which is passed in, rather than what's in |
75 | * the pt_regs, because that's already been updated to point at the | ||
76 | * signal frame. | ||
77 | */ | ||
78 | err |= __put_user(sp, &to->rsp); | ||
74 | err |= PUTREG(regs, RBX, to, rbx); | 79 | err |= PUTREG(regs, RBX, to, rbx); |
75 | err |= PUTREG(regs, RDX, to, rdx); | 80 | err |= PUTREG(regs, RDX, to, rdx); |
76 | err |= PUTREG(regs, RCX, to, rcx); | 81 | err |= PUTREG(regs, RCX, to, rcx); |
@@ -102,7 +107,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, | |||
102 | 107 | ||
103 | #ifdef CONFIG_MODE_TT | 108 | #ifdef CONFIG_MODE_TT |
104 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | 109 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, |
105 | int fpsize) | 110 | int fpsize) |
106 | { | 111 | { |
107 | struct _fpstate *to_fp, *from_fp; | 112 | struct _fpstate *to_fp, *from_fp; |
108 | unsigned long sigs; | 113 | unsigned long sigs; |
@@ -120,7 +125,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, | |||
120 | } | 125 | } |
121 | 126 | ||
122 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | 127 | int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, |
123 | struct sigcontext *from, int fpsize) | 128 | struct sigcontext *from, int fpsize, unsigned long sp) |
124 | { | 129 | { |
125 | struct _fpstate *to_fp, *from_fp; | 130 | struct _fpstate *to_fp, *from_fp; |
126 | int err; | 131 | int err; |
@@ -128,11 +133,17 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, | |||
128 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); | 133 | to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); |
129 | from_fp = from->fpstate; | 134 | from_fp = from->fpstate; |
130 | err = copy_to_user(to, from, sizeof(*to)); | 135 | err = copy_to_user(to, from, sizeof(*to)); |
136 | /* The SP in the sigcontext is the updated one for the signal | ||
137 | * delivery. The sp passed in is the original, and this needs | ||
138 | * to be restored, so we stick it in separately. | ||
139 | */ | ||
140 | err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); | ||
141 | |||
131 | if(from_fp != NULL){ | 142 | if(from_fp != NULL){ |
132 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | 143 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); |
133 | err |= copy_to_user(to_fp, from_fp, fpsize); | 144 | err |= copy_to_user(to_fp, from_fp, fpsize); |
134 | } | 145 | } |
135 | return(err); | 146 | return err; |
136 | } | 147 | } |
137 | 148 | ||
138 | #endif | 149 | #endif |
@@ -148,11 +159,12 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |||
148 | } | 159 | } |
149 | 160 | ||
150 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, | 161 | static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, |
151 | struct pt_regs *from, unsigned long mask) | 162 | struct pt_regs *from, unsigned long mask, |
163 | unsigned long sp) | ||
152 | { | 164 | { |
153 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | 165 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), |
154 | sizeof(*fp)), | 166 | sizeof(*fp), sp), |
155 | copy_sc_to_user_skas(to, fp, from, mask))); | 167 | copy_sc_to_user_skas(to, fp, from, mask, sp))); |
156 | } | 168 | } |
157 | 169 | ||
158 | struct rt_sigframe | 170 | struct rt_sigframe |
@@ -170,6 +182,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
170 | { | 182 | { |
171 | struct rt_sigframe __user *frame; | 183 | struct rt_sigframe __user *frame; |
172 | struct _fpstate __user *fp = NULL; | 184 | struct _fpstate __user *fp = NULL; |
185 | unsigned long save_sp = PT_REGS_RSP(regs); | ||
173 | int err = 0; | 186 | int err = 0; |
174 | struct task_struct *me = current; | 187 | struct task_struct *me = current; |
175 | 188 | ||
@@ -193,14 +206,25 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
193 | goto out; | 206 | goto out; |
194 | } | 207 | } |
195 | 208 | ||
209 | /* Update SP now because the page fault handler refuses to extend | ||
210 | * the stack if the faulting address is too far below the current | ||
211 | * SP, which frame now certainly is. If there's an error, the original | ||
212 | * value is restored on the way out. | ||
213 | * When writing the sigcontext to the stack, we have to write the | ||
214 | * original value, so that's passed to copy_sc_to_user, which does | ||
215 | * the right thing with it. | ||
216 | */ | ||
217 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
218 | |||
196 | /* Create the ucontext. */ | 219 | /* Create the ucontext. */ |
197 | err |= __put_user(0, &frame->uc.uc_flags); | 220 | err |= __put_user(0, &frame->uc.uc_flags); |
198 | err |= __put_user(0, &frame->uc.uc_link); | 221 | err |= __put_user(0, &frame->uc.uc_link); |
199 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 222 | err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
200 | err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), | 223 | err |= __put_user(sas_ss_flags(save_sp), |
201 | &frame->uc.uc_stack.ss_flags); | 224 | &frame->uc.uc_stack.ss_flags); |
202 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); | 225 | err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); |
203 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); | 226 | err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0], |
227 | save_sp); | ||
204 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); | 228 | err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); |
205 | if (sizeof(*set) == 16) { | 229 | if (sizeof(*set) == 16) { |
206 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); | 230 | __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); |
@@ -217,10 +241,10 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
217 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); | 241 | err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
218 | else | 242 | else |
219 | /* could use a vstub here */ | 243 | /* could use a vstub here */ |
220 | goto out; | 244 | goto restore_sp; |
221 | 245 | ||
222 | if (err) | 246 | if (err) |
223 | goto out; | 247 | goto restore_sp; |
224 | 248 | ||
225 | /* Set up registers for signal handler */ | 249 | /* Set up registers for signal handler */ |
226 | { | 250 | { |
@@ -238,10 +262,12 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, | |||
238 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; | 262 | PT_REGS_RSI(regs) = (unsigned long) &frame->info; |
239 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; | 263 | PT_REGS_RDX(regs) = (unsigned long) &frame->uc; |
240 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; | 264 | PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; |
241 | |||
242 | PT_REGS_RSP(regs) = (unsigned long) frame; | ||
243 | out: | 265 | out: |
244 | return(err); | 266 | return err; |
267 | |||
268 | restore_sp: | ||
269 | PT_REGS_RSP(regs) = save_sp; | ||
270 | return err; | ||
245 | } | 271 | } |
246 | 272 | ||
247 | long sys_rt_sigreturn(struct pt_regs *regs) | 273 | long sys_rt_sigreturn(struct pt_regs *regs) |
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c index 7bd54a921cf7..899cebb57c3f 100644 --- a/arch/um/sys-x86_64/user-offsets.c +++ b/arch/um/sys-x86_64/user-offsets.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <stddef.h> | 2 | #include <stddef.h> |
3 | #include <signal.h> | 3 | #include <signal.h> |
4 | #include <sys/poll.h> | ||
4 | #define __FRAME_OFFSETS | 5 | #define __FRAME_OFFSETS |
5 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
6 | #include <asm/types.h> | 7 | #include <asm/types.h> |
@@ -88,4 +89,9 @@ void foo(void) | |||
88 | DEFINE_LONGS(HOST_IP, RIP); | 89 | DEFINE_LONGS(HOST_IP, RIP); |
89 | DEFINE_LONGS(HOST_SP, RSP); | 90 | DEFINE_LONGS(HOST_SP, RSP); |
90 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); | 91 | DEFINE(UM_FRAME_SIZE, sizeof(struct user_regs_struct)); |
92 | |||
93 | /* XXX Duplicated between i386 and x86_64 */ | ||
94 | DEFINE(UM_POLLIN, POLLIN); | ||
95 | DEFINE(UM_POLLPRI, POLLPRI); | ||
96 | DEFINE(UM_POLLOUT, POLLOUT); | ||
91 | } | 97 | } |