1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* ptrace.c: Sparc process tracing support.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7*4882a593Smuzhiyun * and David Mosberger.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Added Linux support -miguel (weird, eh?, the original code was meant
10*4882a593Smuzhiyun * to emulate SunOS).
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/sched.h>
15*4882a593Smuzhiyun #include <linux/mm.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <linux/ptrace.h>
18*4882a593Smuzhiyun #include <linux/user.h>
19*4882a593Smuzhiyun #include <linux/smp.h>
20*4882a593Smuzhiyun #include <linux/security.h>
21*4882a593Smuzhiyun #include <linux/signal.h>
22*4882a593Smuzhiyun #include <linux/regset.h>
23*4882a593Smuzhiyun #include <linux/elf.h>
24*4882a593Smuzhiyun #include <linux/tracehook.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <linux/uaccess.h>
27*4882a593Smuzhiyun #include <asm/cacheflush.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include "kernel.h"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* #define ALLOW_INIT_TRACING */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * Called by kernel/ptrace.c when detaching..
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * Make sure single step bits etc are not set.
37*4882a593Smuzhiyun */
ptrace_disable(struct task_struct * child)38*4882a593Smuzhiyun void ptrace_disable(struct task_struct *child)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun /* nothing to do */
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun enum sparc_regset {
44*4882a593Smuzhiyun REGSET_GENERAL,
45*4882a593Smuzhiyun REGSET_FP,
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
regwindow32_get(struct task_struct * target,const struct pt_regs * regs,u32 * uregs)48*4882a593Smuzhiyun static int regwindow32_get(struct task_struct *target,
49*4882a593Smuzhiyun const struct pt_regs *regs,
50*4882a593Smuzhiyun u32 *uregs)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun unsigned long reg_window = regs->u_regs[UREG_I6];
53*4882a593Smuzhiyun int size = 16 * sizeof(u32);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun if (target == current) {
56*4882a593Smuzhiyun if (copy_from_user(uregs, (void __user *)reg_window, size))
57*4882a593Smuzhiyun return -EFAULT;
58*4882a593Smuzhiyun } else {
59*4882a593Smuzhiyun if (access_process_vm(target, reg_window, uregs, size,
60*4882a593Smuzhiyun FOLL_FORCE) != size)
61*4882a593Smuzhiyun return -EFAULT;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun return 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
regwindow32_set(struct task_struct * target,const struct pt_regs * regs,u32 * uregs)66*4882a593Smuzhiyun static int regwindow32_set(struct task_struct *target,
67*4882a593Smuzhiyun const struct pt_regs *regs,
68*4882a593Smuzhiyun u32 *uregs)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun unsigned long reg_window = regs->u_regs[UREG_I6];
71*4882a593Smuzhiyun int size = 16 * sizeof(u32);
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (target == current) {
74*4882a593Smuzhiyun if (copy_to_user((void __user *)reg_window, uregs, size))
75*4882a593Smuzhiyun return -EFAULT;
76*4882a593Smuzhiyun } else {
77*4882a593Smuzhiyun if (access_process_vm(target, reg_window, uregs, size,
78*4882a593Smuzhiyun FOLL_FORCE | FOLL_WRITE) != size)
79*4882a593Smuzhiyun return -EFAULT;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
genregs32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)84*4882a593Smuzhiyun static int genregs32_get(struct task_struct *target,
85*4882a593Smuzhiyun const struct user_regset *regset,
86*4882a593Smuzhiyun struct membuf to)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun const struct pt_regs *regs = target->thread.kregs;
89*4882a593Smuzhiyun u32 uregs[16];
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (target == current)
92*4882a593Smuzhiyun flush_user_windows();
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun membuf_write(&to, regs->u_regs, 16 * sizeof(u32));
95*4882a593Smuzhiyun if (!to.left)
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun if (regwindow32_get(target, regs, uregs))
98*4882a593Smuzhiyun return -EFAULT;
99*4882a593Smuzhiyun membuf_write(&to, uregs, 16 * sizeof(u32));
100*4882a593Smuzhiyun membuf_store(&to, regs->psr);
101*4882a593Smuzhiyun membuf_store(&to, regs->pc);
102*4882a593Smuzhiyun membuf_store(&to, regs->npc);
103*4882a593Smuzhiyun membuf_store(&to, regs->y);
104*4882a593Smuzhiyun return membuf_zero(&to, 2 * sizeof(u32));
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
genregs32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)107*4882a593Smuzhiyun static int genregs32_set(struct task_struct *target,
108*4882a593Smuzhiyun const struct user_regset *regset,
109*4882a593Smuzhiyun unsigned int pos, unsigned int count,
110*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct pt_regs *regs = target->thread.kregs;
113*4882a593Smuzhiyun u32 uregs[16];
114*4882a593Smuzhiyun u32 psr;
115*4882a593Smuzhiyun int ret;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (target == current)
118*4882a593Smuzhiyun flush_user_windows();
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
121*4882a593Smuzhiyun regs->u_regs,
122*4882a593Smuzhiyun 0, 16 * sizeof(u32));
123*4882a593Smuzhiyun if (ret || !count)
124*4882a593Smuzhiyun return ret;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (regwindow32_get(target, regs, uregs))
127*4882a593Smuzhiyun return -EFAULT;
128*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
129*4882a593Smuzhiyun uregs,
130*4882a593Smuzhiyun 16 * sizeof(u32), 32 * sizeof(u32));
131*4882a593Smuzhiyun if (ret)
132*4882a593Smuzhiyun return ret;
133*4882a593Smuzhiyun if (regwindow32_set(target, regs, uregs))
134*4882a593Smuzhiyun return -EFAULT;
135*4882a593Smuzhiyun if (!count)
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
139*4882a593Smuzhiyun &psr,
140*4882a593Smuzhiyun 32 * sizeof(u32), 33 * sizeof(u32));
141*4882a593Smuzhiyun if (ret)
142*4882a593Smuzhiyun return ret;
143*4882a593Smuzhiyun regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
144*4882a593Smuzhiyun (psr & (PSR_ICC | PSR_SYSCALL));
145*4882a593Smuzhiyun if (!count)
146*4882a593Smuzhiyun return 0;
147*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
148*4882a593Smuzhiyun ®s->pc,
149*4882a593Smuzhiyun 33 * sizeof(u32), 34 * sizeof(u32));
150*4882a593Smuzhiyun if (ret || !count)
151*4882a593Smuzhiyun return ret;
152*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
153*4882a593Smuzhiyun ®s->npc,
154*4882a593Smuzhiyun 34 * sizeof(u32), 35 * sizeof(u32));
155*4882a593Smuzhiyun if (ret || !count)
156*4882a593Smuzhiyun return ret;
157*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
158*4882a593Smuzhiyun ®s->y,
159*4882a593Smuzhiyun 35 * sizeof(u32), 36 * sizeof(u32));
160*4882a593Smuzhiyun if (ret || !count)
161*4882a593Smuzhiyun return ret;
162*4882a593Smuzhiyun return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
163*4882a593Smuzhiyun 36 * sizeof(u32), 38 * sizeof(u32));
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
fpregs32_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)166*4882a593Smuzhiyun static int fpregs32_get(struct task_struct *target,
167*4882a593Smuzhiyun const struct user_regset *regset,
168*4882a593Smuzhiyun struct membuf to)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun #if 0
171*4882a593Smuzhiyun if (target == current)
172*4882a593Smuzhiyun save_and_clear_fpu();
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun membuf_write(&to, target->thread.float_regs, 32 * sizeof(u32));
176*4882a593Smuzhiyun membuf_zero(&to, sizeof(u32));
177*4882a593Smuzhiyun membuf_write(&to, &target->thread.fsr, sizeof(u32));
178*4882a593Smuzhiyun membuf_store(&to, (u32)((1 << 8) | (8 << 16)));
179*4882a593Smuzhiyun return membuf_zero(&to, 64 * sizeof(u32));
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
fpregs32_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)182*4882a593Smuzhiyun static int fpregs32_set(struct task_struct *target,
183*4882a593Smuzhiyun const struct user_regset *regset,
184*4882a593Smuzhiyun unsigned int pos, unsigned int count,
185*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun unsigned long *fpregs = target->thread.float_regs;
188*4882a593Smuzhiyun int ret;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #if 0
191*4882a593Smuzhiyun if (target == current)
192*4882a593Smuzhiyun save_and_clear_fpu();
193*4882a593Smuzhiyun #endif
194*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
195*4882a593Smuzhiyun fpregs,
196*4882a593Smuzhiyun 0, 32 * sizeof(u32));
197*4882a593Smuzhiyun if (!ret)
198*4882a593Smuzhiyun user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
199*4882a593Smuzhiyun 32 * sizeof(u32),
200*4882a593Smuzhiyun 33 * sizeof(u32));
201*4882a593Smuzhiyun if (!ret)
202*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
203*4882a593Smuzhiyun &target->thread.fsr,
204*4882a593Smuzhiyun 33 * sizeof(u32),
205*4882a593Smuzhiyun 34 * sizeof(u32));
206*4882a593Smuzhiyun if (!ret)
207*4882a593Smuzhiyun ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
208*4882a593Smuzhiyun 34 * sizeof(u32), -1);
209*4882a593Smuzhiyun return ret;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun static const struct user_regset sparc32_regsets[] = {
213*4882a593Smuzhiyun /* Format is:
214*4882a593Smuzhiyun * G0 --> G7
215*4882a593Smuzhiyun * O0 --> O7
216*4882a593Smuzhiyun * L0 --> L7
217*4882a593Smuzhiyun * I0 --> I7
218*4882a593Smuzhiyun * PSR, PC, nPC, Y, WIM, TBR
219*4882a593Smuzhiyun */
220*4882a593Smuzhiyun [REGSET_GENERAL] = {
221*4882a593Smuzhiyun .core_note_type = NT_PRSTATUS,
222*4882a593Smuzhiyun .n = 38,
223*4882a593Smuzhiyun .size = sizeof(u32), .align = sizeof(u32),
224*4882a593Smuzhiyun .regset_get = genregs32_get, .set = genregs32_set
225*4882a593Smuzhiyun },
226*4882a593Smuzhiyun /* Format is:
227*4882a593Smuzhiyun * F0 --> F31
228*4882a593Smuzhiyun * empty 32-bit word
229*4882a593Smuzhiyun * FSR (32--bit word)
230*4882a593Smuzhiyun * FPU QUEUE COUNT (8-bit char)
231*4882a593Smuzhiyun * FPU QUEUE ENTRYSIZE (8-bit char)
232*4882a593Smuzhiyun * FPU ENABLED (8-bit char)
233*4882a593Smuzhiyun * empty 8-bit char
234*4882a593Smuzhiyun * FPU QUEUE (64 32-bit ints)
235*4882a593Smuzhiyun */
236*4882a593Smuzhiyun [REGSET_FP] = {
237*4882a593Smuzhiyun .core_note_type = NT_PRFPREG,
238*4882a593Smuzhiyun .n = 99,
239*4882a593Smuzhiyun .size = sizeof(u32), .align = sizeof(u32),
240*4882a593Smuzhiyun .regset_get = fpregs32_get, .set = fpregs32_set
241*4882a593Smuzhiyun },
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun
getregs_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)244*4882a593Smuzhiyun static int getregs_get(struct task_struct *target,
245*4882a593Smuzhiyun const struct user_regset *regset,
246*4882a593Smuzhiyun struct membuf to)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun const struct pt_regs *regs = target->thread.kregs;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (target == current)
251*4882a593Smuzhiyun flush_user_windows();
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun membuf_store(&to, regs->psr);
254*4882a593Smuzhiyun membuf_store(&to, regs->pc);
255*4882a593Smuzhiyun membuf_store(&to, regs->npc);
256*4882a593Smuzhiyun membuf_store(&to, regs->y);
257*4882a593Smuzhiyun return membuf_write(&to, regs->u_regs + 1, 15 * sizeof(u32));
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
setregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)260*4882a593Smuzhiyun static int setregs_set(struct task_struct *target,
261*4882a593Smuzhiyun const struct user_regset *regset,
262*4882a593Smuzhiyun unsigned int pos, unsigned int count,
263*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun struct pt_regs *regs = target->thread.kregs;
266*4882a593Smuzhiyun u32 v[4];
267*4882a593Smuzhiyun int ret;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (target == current)
270*4882a593Smuzhiyun flush_user_windows();
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
273*4882a593Smuzhiyun v,
274*4882a593Smuzhiyun 0, 4 * sizeof(u32));
275*4882a593Smuzhiyun if (ret)
276*4882a593Smuzhiyun return ret;
277*4882a593Smuzhiyun regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
278*4882a593Smuzhiyun (v[0] & (PSR_ICC | PSR_SYSCALL));
279*4882a593Smuzhiyun regs->pc = v[1];
280*4882a593Smuzhiyun regs->npc = v[2];
281*4882a593Smuzhiyun regs->y = v[3];
282*4882a593Smuzhiyun return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
283*4882a593Smuzhiyun regs->u_regs + 1,
284*4882a593Smuzhiyun 4 * sizeof(u32) , 19 * sizeof(u32));
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
getfpregs_get(struct task_struct * target,const struct user_regset * regset,struct membuf to)287*4882a593Smuzhiyun static int getfpregs_get(struct task_struct *target,
288*4882a593Smuzhiyun const struct user_regset *regset,
289*4882a593Smuzhiyun struct membuf to)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun #if 0
292*4882a593Smuzhiyun if (target == current)
293*4882a593Smuzhiyun save_and_clear_fpu();
294*4882a593Smuzhiyun #endif
295*4882a593Smuzhiyun membuf_write(&to, &target->thread.float_regs, 32 * sizeof(u32));
296*4882a593Smuzhiyun membuf_write(&to, &target->thread.fsr, sizeof(u32));
297*4882a593Smuzhiyun return membuf_zero(&to, 35 * sizeof(u32));
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
setfpregs_set(struct task_struct * target,const struct user_regset * regset,unsigned int pos,unsigned int count,const void * kbuf,const void __user * ubuf)300*4882a593Smuzhiyun static int setfpregs_set(struct task_struct *target,
301*4882a593Smuzhiyun const struct user_regset *regset,
302*4882a593Smuzhiyun unsigned int pos, unsigned int count,
303*4882a593Smuzhiyun const void *kbuf, const void __user *ubuf)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun unsigned long *fpregs = target->thread.float_regs;
306*4882a593Smuzhiyun int ret;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun #if 0
309*4882a593Smuzhiyun if (target == current)
310*4882a593Smuzhiyun save_and_clear_fpu();
311*4882a593Smuzhiyun #endif
312*4882a593Smuzhiyun ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
313*4882a593Smuzhiyun fpregs,
314*4882a593Smuzhiyun 0, 32 * sizeof(u32));
315*4882a593Smuzhiyun if (ret)
316*4882a593Smuzhiyun return ret;
317*4882a593Smuzhiyun return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
318*4882a593Smuzhiyun &target->thread.fsr,
319*4882a593Smuzhiyun 32 * sizeof(u32),
320*4882a593Smuzhiyun 33 * sizeof(u32));
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun static const struct user_regset ptrace32_regsets[] = {
324*4882a593Smuzhiyun [REGSET_GENERAL] = {
325*4882a593Smuzhiyun .n = 19, .size = sizeof(u32),
326*4882a593Smuzhiyun .regset_get = getregs_get, .set = setregs_set,
327*4882a593Smuzhiyun },
328*4882a593Smuzhiyun [REGSET_FP] = {
329*4882a593Smuzhiyun .n = 68, .size = sizeof(u32),
330*4882a593Smuzhiyun .regset_get = getfpregs_get, .set = setfpregs_set,
331*4882a593Smuzhiyun },
332*4882a593Smuzhiyun };
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun static const struct user_regset_view ptrace32_view = {
335*4882a593Smuzhiyun .regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun static const struct user_regset_view user_sparc32_view = {
339*4882a593Smuzhiyun .name = "sparc", .e_machine = EM_SPARC,
340*4882a593Smuzhiyun .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun
task_user_regset_view(struct task_struct * task)343*4882a593Smuzhiyun const struct user_regset_view *task_user_regset_view(struct task_struct *task)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun return &user_sparc32_view;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun struct fps {
349*4882a593Smuzhiyun unsigned long regs[32];
350*4882a593Smuzhiyun unsigned long fsr;
351*4882a593Smuzhiyun unsigned long flags;
352*4882a593Smuzhiyun unsigned long extra;
353*4882a593Smuzhiyun unsigned long fpqd;
354*4882a593Smuzhiyun struct fq {
355*4882a593Smuzhiyun unsigned long *insnaddr;
356*4882a593Smuzhiyun unsigned long insn;
357*4882a593Smuzhiyun } fpq[16];
358*4882a593Smuzhiyun };
359*4882a593Smuzhiyun
arch_ptrace(struct task_struct * child,long request,unsigned long addr,unsigned long data)360*4882a593Smuzhiyun long arch_ptrace(struct task_struct *child, long request,
361*4882a593Smuzhiyun unsigned long addr, unsigned long data)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
364*4882a593Smuzhiyun void __user *addr2p;
365*4882a593Smuzhiyun struct pt_regs __user *pregs;
366*4882a593Smuzhiyun struct fps __user *fps;
367*4882a593Smuzhiyun int ret;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun addr2p = (void __user *) addr2;
370*4882a593Smuzhiyun pregs = (struct pt_regs __user *) addr;
371*4882a593Smuzhiyun fps = (struct fps __user *) addr;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun switch(request) {
374*4882a593Smuzhiyun case PTRACE_GETREGS: {
375*4882a593Smuzhiyun ret = copy_regset_to_user(child, &ptrace32_view,
376*4882a593Smuzhiyun REGSET_GENERAL, 0,
377*4882a593Smuzhiyun 19 * sizeof(u32),
378*4882a593Smuzhiyun pregs);
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun case PTRACE_SETREGS: {
383*4882a593Smuzhiyun ret = copy_regset_from_user(child, &ptrace32_view,
384*4882a593Smuzhiyun REGSET_GENERAL, 0,
385*4882a593Smuzhiyun 19 * sizeof(u32),
386*4882a593Smuzhiyun pregs);
387*4882a593Smuzhiyun break;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun case PTRACE_GETFPREGS: {
391*4882a593Smuzhiyun ret = copy_regset_to_user(child, &ptrace32_view,
392*4882a593Smuzhiyun REGSET_FP, 0,
393*4882a593Smuzhiyun 68 * sizeof(u32),
394*4882a593Smuzhiyun fps);
395*4882a593Smuzhiyun break;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun case PTRACE_SETFPREGS: {
399*4882a593Smuzhiyun ret = copy_regset_from_user(child, &ptrace32_view,
400*4882a593Smuzhiyun REGSET_FP, 0,
401*4882a593Smuzhiyun 33 * sizeof(u32),
402*4882a593Smuzhiyun fps);
403*4882a593Smuzhiyun break;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun case PTRACE_READTEXT:
407*4882a593Smuzhiyun case PTRACE_READDATA:
408*4882a593Smuzhiyun ret = ptrace_readdata(child, addr, addr2p, data);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (ret == data)
411*4882a593Smuzhiyun ret = 0;
412*4882a593Smuzhiyun else if (ret >= 0)
413*4882a593Smuzhiyun ret = -EIO;
414*4882a593Smuzhiyun break;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun case PTRACE_WRITETEXT:
417*4882a593Smuzhiyun case PTRACE_WRITEDATA:
418*4882a593Smuzhiyun ret = ptrace_writedata(child, addr2p, addr, data);
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (ret == data)
421*4882a593Smuzhiyun ret = 0;
422*4882a593Smuzhiyun else if (ret >= 0)
423*4882a593Smuzhiyun ret = -EIO;
424*4882a593Smuzhiyun break;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun default:
427*4882a593Smuzhiyun if (request == PTRACE_SPARC_DETACH)
428*4882a593Smuzhiyun request = PTRACE_DETACH;
429*4882a593Smuzhiyun ret = ptrace_request(child, request, addr, data);
430*4882a593Smuzhiyun break;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun return ret;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
syscall_trace(struct pt_regs * regs,int syscall_exit_p)436*4882a593Smuzhiyun asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun int ret = 0;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (test_thread_flag(TIF_SYSCALL_TRACE)) {
441*4882a593Smuzhiyun if (syscall_exit_p)
442*4882a593Smuzhiyun tracehook_report_syscall_exit(regs, 0);
443*4882a593Smuzhiyun else
444*4882a593Smuzhiyun ret = tracehook_report_syscall_entry(regs);
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun return ret;
448*4882a593Smuzhiyun }
449