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