~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sparc/kernel/ptrace_64.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* ptrace.c: Sparc process tracing support.
  2  *
  3  * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net)
  4  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  5  *
  6  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
  7  * and David Mosberger.
  8  *
  9  * Added Linux support -miguel (weird, eh?, the original code was meant
 10  * to emulate SunOS).
 11  */
 12 
 13 #include <linux/kernel.h>
 14 #include <linux/sched.h>
 15 #include <linux/sched/task_stack.h>
 16 #include <linux/mm.h>
 17 #include <linux/errno.h>
 18 #include <linux/export.h>
 19 #include <linux/ptrace.h>
 20 #include <linux/user.h>
 21 #include <linux/smp.h>
 22 #include <linux/security.h>
 23 #include <linux/seccomp.h>
 24 #include <linux/audit.h>
 25 #include <linux/signal.h>
 26 #include <linux/regset.h>
 27 #include <linux/tracehook.h>
 28 #include <trace/syscall.h>
 29 #include <linux/compat.h>
 30 #include <linux/elf.h>
 31 #include <linux/context_tracking.h>
 32 
 33 #include <asm/asi.h>
 34 #include <asm/pgtable.h>
 35 #include <linux/uaccess.h>
 36 #include <asm/psrcompat.h>
 37 #include <asm/visasm.h>
 38 #include <asm/spitfire.h>
 39 #include <asm/page.h>
 40 #include <asm/cpudata.h>
 41 #include <asm/cacheflush.h>
 42 
 43 #define CREATE_TRACE_POINTS
 44 #include <trace/events/syscalls.h>
 45 
 46 #include "entry.h"
 47 
 48 /* #define ALLOW_INIT_TRACING */
 49 
 50 struct pt_regs_offset {
 51         const char *name;
 52         int offset;
 53 };
 54 
 55 #define REG_OFFSET_NAME(n, r) \
 56         {.name = n, .offset = (PT_V9_##r)}
 57 #define REG_OFFSET_END {.name = NULL, .offset = 0}
 58 
 59 static const struct pt_regs_offset regoffset_table[] = {
 60         REG_OFFSET_NAME("g0", G0),
 61         REG_OFFSET_NAME("g1", G1),
 62         REG_OFFSET_NAME("g2", G2),
 63         REG_OFFSET_NAME("g3", G3),
 64         REG_OFFSET_NAME("g4", G4),
 65         REG_OFFSET_NAME("g5", G5),
 66         REG_OFFSET_NAME("g6", G6),
 67         REG_OFFSET_NAME("g7", G7),
 68 
 69         REG_OFFSET_NAME("i0", I0),
 70         REG_OFFSET_NAME("i1", I1),
 71         REG_OFFSET_NAME("i2", I2),
 72         REG_OFFSET_NAME("i3", I3),
 73         REG_OFFSET_NAME("i4", I4),
 74         REG_OFFSET_NAME("i5", I5),
 75         REG_OFFSET_NAME("i6", I6),
 76         REG_OFFSET_NAME("i7", I7),
 77 
 78         REG_OFFSET_NAME("tstate", TSTATE),
 79         REG_OFFSET_NAME("pc", TPC),
 80         REG_OFFSET_NAME("npc", TNPC),
 81         REG_OFFSET_NAME("y", Y),
 82         REG_OFFSET_NAME("lr", I7),
 83 
 84         REG_OFFSET_END,
 85 };
 86 
 87 /*
 88  * Called by kernel/ptrace.c when detaching..
 89  *
 90  * Make sure single step bits etc are not set.
 91  */
 92 void ptrace_disable(struct task_struct *child)
 93 {
 94         /* nothing to do */
 95 }
 96 
 97 /* To get the necessary page struct, access_process_vm() first calls
 98  * get_user_pages().  This has done a flush_dcache_page() on the
 99  * accessed page.  Then our caller (copy_{to,from}_user_page()) did
100  * to memcpy to read/write the data from that page.
101  *
102  * Now, the only thing we have to do is:
103  * 1) flush the D-cache if it's possible than an illegal alias
104  *    has been created
105  * 2) flush the I-cache if this is pre-cheetah and we did a write
106  */
107 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
108                          unsigned long uaddr, void *kaddr,
109                          unsigned long len, int write)
110 {
111         BUG_ON(len > PAGE_SIZE);
112 
113         if (tlb_type == hypervisor)
114                 return;
115 
116         preempt_disable();
117 
118 #ifdef DCACHE_ALIASING_POSSIBLE
119         /* If bit 13 of the kernel address we used to access the
120          * user page is the same as the virtual address that page
121          * is mapped to in the user's address space, we can skip the
122          * D-cache flush.
123          */
124         if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) {
125                 unsigned long start = __pa(kaddr);
126                 unsigned long end = start + len;
127                 unsigned long dcache_line_size;
128 
129                 dcache_line_size = local_cpu_data().dcache_line_size;
130 
131                 if (tlb_type == spitfire) {
132                         for (; start < end; start += dcache_line_size)
133                                 spitfire_put_dcache_tag(start & 0x3fe0, 0x0);
134                 } else {
135                         start &= ~(dcache_line_size - 1);
136                         for (; start < end; start += dcache_line_size)
137                                 __asm__ __volatile__(
138                                         "stxa %%g0, [%0] %1\n\t"
139                                         "membar #Sync"
140                                         : /* no outputs */
141                                         : "r" (start),
142                                         "i" (ASI_DCACHE_INVALIDATE));
143                 }
144         }
145 #endif
146         if (write && tlb_type == spitfire) {
147                 unsigned long start = (unsigned long) kaddr;
148                 unsigned long end = start + len;
149                 unsigned long icache_line_size;
150 
151                 icache_line_size = local_cpu_data().icache_line_size;
152 
153                 for (; start < end; start += icache_line_size)
154                         flushi(start);
155         }
156 
157         preempt_enable();
158 }
159 EXPORT_SYMBOL_GPL(flush_ptrace_access);
160 
161 static int get_from_target(struct task_struct *target, unsigned long uaddr,
162                            void *kbuf, int len)
163 {
164         if (target == current) {
165                 if (copy_from_user(kbuf, (void __user *) uaddr, len))
166                         return -EFAULT;
167         } else {
168                 int len2 = access_process_vm(target, uaddr, kbuf, len,
169                                 FOLL_FORCE);
170                 if (len2 != len)
171                         return -EFAULT;
172         }
173         return 0;
174 }
175 
176 static int set_to_target(struct task_struct *target, unsigned long uaddr,
177                          void *kbuf, int len)
178 {
179         if (target == current) {
180                 if (copy_to_user((void __user *) uaddr, kbuf, len))
181                         return -EFAULT;
182         } else {
183                 int len2 = access_process_vm(target, uaddr, kbuf, len,
184                                 FOLL_FORCE | FOLL_WRITE);
185                 if (len2 != len)
186                         return -EFAULT;
187         }
188         return 0;
189 }
190 
191 static int regwindow64_get(struct task_struct *target,
192                            const struct pt_regs *regs,
193                            struct reg_window *wbuf)
194 {
195         unsigned long rw_addr = regs->u_regs[UREG_I6];
196 
197         if (!test_thread_64bit_stack(rw_addr)) {
198                 struct reg_window32 win32;
199                 int i;
200 
201                 if (get_from_target(target, rw_addr, &win32, sizeof(win32)))
202                         return -EFAULT;
203                 for (i = 0; i < 8; i++)
204                         wbuf->locals[i] = win32.locals[i];
205                 for (i = 0; i < 8; i++)
206                         wbuf->ins[i] = win32.ins[i];
207         } else {
208                 rw_addr += STACK_BIAS;
209                 if (get_from_target(target, rw_addr, wbuf, sizeof(*wbuf)))
210                         return -EFAULT;
211         }
212 
213         return 0;
214 }
215 
216 static int regwindow64_set(struct task_struct *target,
217                            const struct pt_regs *regs,
218                            struct reg_window *wbuf)
219 {
220         unsigned long rw_addr = regs->u_regs[UREG_I6];
221 
222         if (!test_thread_64bit_stack(rw_addr)) {
223                 struct reg_window32 win32;
224                 int i;
225 
226                 for (i = 0; i < 8; i++)
227                         win32.locals[i] = wbuf->locals[i];
228                 for (i = 0; i < 8; i++)
229                         win32.ins[i] = wbuf->ins[i];
230 
231                 if (set_to_target(target, rw_addr, &win32, sizeof(win32)))
232                         return -EFAULT;
233         } else {
234                 rw_addr += STACK_BIAS;
235                 if (set_to_target(target, rw_addr, wbuf, sizeof(*wbuf)))
236                         return -EFAULT;
237         }
238 
239         return 0;
240 }
241 
242 enum sparc_regset {
243         REGSET_GENERAL,
244         REGSET_FP,
245 };
246 
247 static int genregs64_get(struct task_struct *target,
248                          const struct user_regset *regset,
249                          unsigned int pos, unsigned int count,
250                          void *kbuf, void __user *ubuf)
251 {
252         const struct pt_regs *regs = task_pt_regs(target);
253         int ret;
254 
255         if (target == current)
256                 flushw_user();
257 
258         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
259                                   regs->u_regs,
260                                   0, 16 * sizeof(u64));
261         if (!ret && count && pos < (32 * sizeof(u64))) {
262                 struct reg_window window;
263 
264                 if (regwindow64_get(target, regs, &window))
265                         return -EFAULT;
266                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
267                                           &window,
268                                           16 * sizeof(u64),
269                                           32 * sizeof(u64));
270         }
271 
272         if (!ret) {
273                 /* TSTATE, TPC, TNPC */
274                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
275                                           &regs->tstate,
276                                           32 * sizeof(u64),
277                                           35 * sizeof(u64));
278         }
279 
280         if (!ret) {
281                 unsigned long y = regs->y;
282 
283                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
284                                           &y,
285                                           35 * sizeof(u64),
286                                           36 * sizeof(u64));
287         }
288 
289         if (!ret) {
290                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
291                                                36 * sizeof(u64), -1);
292 
293         }
294         return ret;
295 }
296 
297 static int genregs64_set(struct task_struct *target,
298                          const struct user_regset *regset,
299                          unsigned int pos, unsigned int count,
300                          const void *kbuf, const void __user *ubuf)
301 {
302         struct pt_regs *regs = task_pt_regs(target);
303         int ret;
304 
305         if (target == current)
306                 flushw_user();
307 
308         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
309                                  regs->u_regs,
310                                  0, 16 * sizeof(u64));
311         if (!ret && count && pos < (32 * sizeof(u64))) {
312                 struct reg_window window;
313 
314                 if (regwindow64_get(target, regs, &window))
315                         return -EFAULT;
316 
317                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
318                                          &window,
319                                          16 * sizeof(u64),
320                                          32 * sizeof(u64));
321 
322                 if (!ret &&
323                     regwindow64_set(target, regs, &window))
324                         return -EFAULT;
325         }
326 
327         if (!ret && count > 0) {
328                 unsigned long tstate;
329 
330                 /* TSTATE */
331                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
332                                          &tstate,
333                                          32 * sizeof(u64),
334                                          33 * sizeof(u64));
335                 if (!ret) {
336                         /* Only the condition codes and the "in syscall"
337                          * state can be modified in the %tstate register.
338                          */
339                         tstate &= (TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
340                         regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
341                         regs->tstate |= tstate;
342                 }
343         }
344 
345         if (!ret) {
346                 /* TPC, TNPC */
347                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
348                                          &regs->tpc,
349                                          33 * sizeof(u64),
350                                          35 * sizeof(u64));
351         }
352 
353         if (!ret) {
354                 unsigned long y = regs->y;
355 
356                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
357                                          &y,
358                                          35 * sizeof(u64),
359                                          36 * sizeof(u64));
360                 if (!ret)
361                         regs->y = y;
362         }
363 
364         if (!ret)
365                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
366                                                 36 * sizeof(u64), -1);
367 
368         return ret;
369 }
370 
371 static int fpregs64_get(struct task_struct *target,
372                         const struct user_regset *regset,
373                         unsigned int pos, unsigned int count,
374                         void *kbuf, void __user *ubuf)
375 {
376         const unsigned long *fpregs = task_thread_info(target)->fpregs;
377         unsigned long fprs, fsr, gsr;
378         int ret;
379 
380         if (target == current)
381                 save_and_clear_fpu();
382 
383         fprs = task_thread_info(target)->fpsaved[0];
384 
385         if (fprs & FPRS_DL)
386                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
387                                           fpregs,
388                                           0, 16 * sizeof(u64));
389         else
390                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
391                                                0,
392                                                16 * sizeof(u64));
393 
394         if (!ret) {
395                 if (fprs & FPRS_DU)
396                         ret = user_regset_copyout(&pos, &count,
397                                                   &kbuf, &ubuf,
398                                                   fpregs + 16,
399                                                   16 * sizeof(u64),
400                                                   32 * sizeof(u64));
401                 else
402                         ret = user_regset_copyout_zero(&pos, &count,
403                                                        &kbuf, &ubuf,
404                                                        16 * sizeof(u64),
405                                                        32 * sizeof(u64));
406         }
407 
408         if (fprs & FPRS_FEF) {
409                 fsr = task_thread_info(target)->xfsr[0];
410                 gsr = task_thread_info(target)->gsr[0];
411         } else {
412                 fsr = gsr = 0;
413         }
414 
415         if (!ret)
416                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
417                                           &fsr,
418                                           32 * sizeof(u64),
419                                           33 * sizeof(u64));
420         if (!ret)
421                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
422                                           &gsr,
423                                           33 * sizeof(u64),
424                                           34 * sizeof(u64));
425         if (!ret)
426                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
427                                           &fprs,
428                                           34 * sizeof(u64),
429                                           35 * sizeof(u64));
430 
431         if (!ret)
432                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
433                                                35 * sizeof(u64), -1);
434 
435         return ret;
436 }
437 
438 static int fpregs64_set(struct task_struct *target,
439                         const struct user_regset *regset,
440                         unsigned int pos, unsigned int count,
441                         const void *kbuf, const void __user *ubuf)
442 {
443         unsigned long *fpregs = task_thread_info(target)->fpregs;
444         unsigned long fprs;
445         int ret;
446 
447         if (target == current)
448                 save_and_clear_fpu();
449 
450         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
451                                  fpregs,
452                                  0, 32 * sizeof(u64));
453         if (!ret)
454                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
455                                          task_thread_info(target)->xfsr,
456                                          32 * sizeof(u64),
457                                          33 * sizeof(u64));
458         if (!ret)
459                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
460                                          task_thread_info(target)->gsr,
461                                          33 * sizeof(u64),
462                                          34 * sizeof(u64));
463 
464         fprs = task_thread_info(target)->fpsaved[0];
465         if (!ret && count > 0) {
466                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
467                                          &fprs,
468                                          34 * sizeof(u64),
469                                          35 * sizeof(u64));
470         }
471 
472         fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU);
473         task_thread_info(target)->fpsaved[0] = fprs;
474 
475         if (!ret)
476                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
477                                                 35 * sizeof(u64), -1);
478         return ret;
479 }
480 
481 static const struct user_regset sparc64_regsets[] = {
482         /* Format is:
483          *      G0 --> G7
484          *      O0 --> O7
485          *      L0 --> L7
486          *      I0 --> I7
487          *      TSTATE, TPC, TNPC, Y
488          */
489         [REGSET_GENERAL] = {
490                 .core_note_type = NT_PRSTATUS,
491                 .n = 36,
492                 .size = sizeof(u64), .align = sizeof(u64),
493                 .get = genregs64_get, .set = genregs64_set
494         },
495         /* Format is:
496          *      F0 --> F63
497          *      FSR
498          *      GSR
499          *      FPRS
500          */
501         [REGSET_FP] = {
502                 .core_note_type = NT_PRFPREG,
503                 .n = 35,
504                 .size = sizeof(u64), .align = sizeof(u64),
505                 .get = fpregs64_get, .set = fpregs64_set
506         },
507 };
508 
509 static const struct user_regset_view user_sparc64_view = {
510         .name = "sparc64", .e_machine = EM_SPARCV9,
511         .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets)
512 };
513 
514 #ifdef CONFIG_COMPAT
515 static int genregs32_get(struct task_struct *target,
516                          const struct user_regset *regset,
517                          unsigned int pos, unsigned int count,
518                          void *kbuf, void __user *ubuf)
519 {
520         const struct pt_regs *regs = task_pt_regs(target);
521         compat_ulong_t __user *reg_window;
522         compat_ulong_t *k = kbuf;
523         compat_ulong_t __user *u = ubuf;
524         compat_ulong_t reg;
525 
526         if (target == current)
527                 flushw_user();
528 
529         pos /= sizeof(reg);
530         count /= sizeof(reg);
531 
532         if (kbuf) {
533                 for (; count > 0 && pos < 16; count--)
534                         *k++ = regs->u_regs[pos++];
535 
536                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
537                 reg_window -= 16;
538                 if (target == current) {
539                         for (; count > 0 && pos < 32; count--) {
540                                 if (get_user(*k++, &reg_window[pos++]))
541                                         return -EFAULT;
542                         }
543                 } else {
544                         for (; count > 0 && pos < 32; count--) {
545                                 if (access_process_vm(target,
546                                                       (unsigned long)
547                                                       &reg_window[pos],
548                                                       k, sizeof(*k),
549                                                       FOLL_FORCE)
550                                     != sizeof(*k))
551                                         return -EFAULT;
552                                 k++;
553                                 pos++;
554                         }
555                 }
556         } else {
557                 for (; count > 0 && pos < 16; count--) {
558                         if (put_user((compat_ulong_t) regs->u_regs[pos++], u++))
559                                 return -EFAULT;
560                 }
561 
562                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
563                 reg_window -= 16;
564                 if (target == current) {
565                         for (; count > 0 && pos < 32; count--) {
566                                 if (get_user(reg, &reg_window[pos++]) ||
567                                     put_user(reg, u++))
568                                         return -EFAULT;
569                         }
570                 } else {
571                         for (; count > 0 && pos < 32; count--) {
572                                 if (access_process_vm(target,
573                                                       (unsigned long)
574                                                       &reg_window[pos],
575                                                       &reg, sizeof(reg),
576                                                       FOLL_FORCE)
577                                     != sizeof(reg))
578                                         return -EFAULT;
579                                 if (access_process_vm(target,
580                                                       (unsigned long) u,
581                                                       &reg, sizeof(reg),
582                                                       FOLL_FORCE | FOLL_WRITE)
583                                     != sizeof(reg))
584                                         return -EFAULT;
585                                 pos++;
586                                 u++;
587                         }
588                 }
589         }
590         while (count > 0) {
591                 switch (pos) {
592                 case 32: /* PSR */
593                         reg = tstate_to_psr(regs->tstate);
594                         break;
595                 case 33: /* PC */
596                         reg = regs->tpc;
597                         break;
598                 case 34: /* NPC */
599                         reg = regs->tnpc;
600                         break;
601                 case 35: /* Y */
602                         reg = regs->y;
603                         break;
604                 case 36: /* WIM */
605                 case 37: /* TBR */
606                         reg = 0;
607                         break;
608                 default:
609                         goto finish;
610                 }
611 
612                 if (kbuf)
613                         *k++ = reg;
614                 else if (put_user(reg, u++))
615                         return -EFAULT;
616                 pos++;
617                 count--;
618         }
619 finish:
620         pos *= sizeof(reg);
621         count *= sizeof(reg);
622 
623         return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
624                                         38 * sizeof(reg), -1);
625 }
626 
627 static int genregs32_set(struct task_struct *target,
628                          const struct user_regset *regset,
629                          unsigned int pos, unsigned int count,
630                          const void *kbuf, const void __user *ubuf)
631 {
632         struct pt_regs *regs = task_pt_regs(target);
633         compat_ulong_t __user *reg_window;
634         const compat_ulong_t *k = kbuf;
635         const compat_ulong_t __user *u = ubuf;
636         compat_ulong_t reg;
637 
638         if (target == current)
639                 flushw_user();
640 
641         pos /= sizeof(reg);
642         count /= sizeof(reg);
643 
644         if (kbuf) {
645                 for (; count > 0 && pos < 16; count--)
646                         regs->u_regs[pos++] = *k++;
647 
648                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
649                 reg_window -= 16;
650                 if (target == current) {
651                         for (; count > 0 && pos < 32; count--) {
652                                 if (put_user(*k++, &reg_window[pos++]))
653                                         return -EFAULT;
654                         }
655                 } else {
656                         for (; count > 0 && pos < 32; count--) {
657                                 if (access_process_vm(target,
658                                                       (unsigned long)
659                                                       &reg_window[pos],
660                                                       (void *) k,
661                                                       sizeof(*k),
662                                                       FOLL_FORCE | FOLL_WRITE)
663                                     != sizeof(*k))
664                                         return -EFAULT;
665                                 k++;
666                                 pos++;
667                         }
668                 }
669         } else {
670                 for (; count > 0 && pos < 16; count--) {
671                         if (get_user(reg, u++))
672                                 return -EFAULT;
673                         regs->u_regs[pos++] = reg;
674                 }
675 
676                 reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6];
677                 reg_window -= 16;
678                 if (target == current) {
679                         for (; count > 0 && pos < 32; count--) {
680                                 if (get_user(reg, u++) ||
681                                     put_user(reg, &reg_window[pos++]))
682                                         return -EFAULT;
683                         }
684                 } else {
685                         for (; count > 0 && pos < 32; count--) {
686                                 if (access_process_vm(target,
687                                                       (unsigned long)
688                                                       u,
689                                                       &reg, sizeof(reg),
690                                                       FOLL_FORCE)
691                                     != sizeof(reg))
692                                         return -EFAULT;
693                                 if (access_process_vm(target,
694                                                       (unsigned long)
695                                                       &reg_window[pos],
696                                                       &reg, sizeof(reg),
697                                                       FOLL_FORCE | FOLL_WRITE)
698                                     != sizeof(reg))
699                                         return -EFAULT;
700                                 pos++;
701                                 u++;
702                         }
703                 }
704         }
705         while (count > 0) {
706                 unsigned long tstate;
707 
708                 if (kbuf)
709                         reg = *k++;
710                 else if (get_user(reg, u++))
711                         return -EFAULT;
712 
713                 switch (pos) {
714                 case 32: /* PSR */
715                         tstate = regs->tstate;
716                         tstate &= ~(TSTATE_ICC | TSTATE_XCC | TSTATE_SYSCALL);
717                         tstate |= psr_to_tstate_icc(reg);
718                         if (reg & PSR_SYSCALL)
719                                 tstate |= TSTATE_SYSCALL;
720                         regs->tstate = tstate;
721                         break;
722                 case 33: /* PC */
723                         regs->tpc = reg;
724                         break;
725                 case 34: /* NPC */
726                         regs->tnpc = reg;
727                         break;
728                 case 35: /* Y */
729                         regs->y = reg;
730                         break;
731                 case 36: /* WIM */
732                 case 37: /* TBR */
733                         break;
734                 default:
735                         goto finish;
736                 }
737 
738                 pos++;
739                 count--;
740         }
741 finish:
742         pos *= sizeof(reg);
743         count *= sizeof(reg);
744 
745         return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
746                                          38 * sizeof(reg), -1);
747 }
748 
749 static int fpregs32_get(struct task_struct *target,
750                         const struct user_regset *regset,
751                         unsigned int pos, unsigned int count,
752                         void *kbuf, void __user *ubuf)
753 {
754         const unsigned long *fpregs = task_thread_info(target)->fpregs;
755         compat_ulong_t enabled;
756         unsigned long fprs;
757         compat_ulong_t fsr;
758         int ret = 0;
759 
760         if (target == current)
761                 save_and_clear_fpu();
762 
763         fprs = task_thread_info(target)->fpsaved[0];
764         if (fprs & FPRS_FEF) {
765                 fsr = task_thread_info(target)->xfsr[0];
766                 enabled = 1;
767         } else {
768                 fsr = 0;
769                 enabled = 0;
770         }
771 
772         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
773                                   fpregs,
774                                   0, 32 * sizeof(u32));
775 
776         if (!ret)
777                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
778                                                32 * sizeof(u32),
779                                                33 * sizeof(u32));
780         if (!ret)
781                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
782                                           &fsr,
783                                           33 * sizeof(u32),
784                                           34 * sizeof(u32));
785 
786         if (!ret) {
787                 compat_ulong_t val;
788 
789                 val = (enabled << 8) | (8 << 16);
790                 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
791                                           &val,
792                                           34 * sizeof(u32),
793                                           35 * sizeof(u32));
794         }
795 
796         if (!ret)
797                 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
798                                                35 * sizeof(u32), -1);
799 
800         return ret;
801 }
802 
803 static int fpregs32_set(struct task_struct *target,
804                         const struct user_regset *regset,
805                         unsigned int pos, unsigned int count,
806                         const void *kbuf, const void __user *ubuf)
807 {
808         unsigned long *fpregs = task_thread_info(target)->fpregs;
809         unsigned long fprs;
810         int ret;
811 
812         if (target == current)
813                 save_and_clear_fpu();
814 
815         fprs = task_thread_info(target)->fpsaved[0];
816 
817         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
818                                  fpregs,
819                                  0, 32 * sizeof(u32));
820         if (!ret)
821                 user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
822                                           32 * sizeof(u32),
823                                           33 * sizeof(u32));
824         if (!ret && count > 0) {
825                 compat_ulong_t fsr;
826                 unsigned long val;
827 
828                 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
829                                          &fsr,
830                                          33 * sizeof(u32),
831                                          34 * sizeof(u32));
832                 if (!ret) {
833                         val = task_thread_info(target)->xfsr[0];
834                         val &= 0xffffffff00000000UL;
835                         val |= fsr;
836                         task_thread_info(target)->xfsr[0] = val;
837                 }
838         }
839 
840         fprs |= (FPRS_FEF | FPRS_DL);
841         task_thread_info(target)->fpsaved[0] = fprs;
842 
843         if (!ret)
844                 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
845                                                 34 * sizeof(u32), -1);
846         return ret;
847 }
848 
849 static const struct user_regset sparc32_regsets[] = {
850         /* Format is:
851          *      G0 --> G7
852          *      O0 --> O7
853          *      L0 --> L7
854          *      I0 --> I7
855          *      PSR, PC, nPC, Y, WIM, TBR
856          */
857         [REGSET_GENERAL] = {
858                 .core_note_type = NT_PRSTATUS,
859                 .n = 38,
860                 .size = sizeof(u32), .align = sizeof(u32),
861                 .get = genregs32_get, .set = genregs32_set
862         },
863         /* Format is:
864          *      F0 --> F31
865          *      empty 32-bit word
866          *      FSR (32--bit word)
867          *      FPU QUEUE COUNT (8-bit char)
868          *      FPU QUEUE ENTRYSIZE (8-bit char)
869          *      FPU ENABLED (8-bit char)
870          *      empty 8-bit char
871          *      FPU QUEUE (64 32-bit ints)
872          */
873         [REGSET_FP] = {
874                 .core_note_type = NT_PRFPREG,
875                 .n = 99,
876                 .size = sizeof(u32), .align = sizeof(u32),
877                 .get = fpregs32_get, .set = fpregs32_set
878         },
879 };
880 
881 static const struct user_regset_view user_sparc32_view = {
882         .name = "sparc", .e_machine = EM_SPARC,
883         .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
884 };
885 #endif /* CONFIG_COMPAT */
886 
887 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
888 {
889 #ifdef CONFIG_COMPAT
890         if (test_tsk_thread_flag(task, TIF_32BIT))
891                 return &user_sparc32_view;
892 #endif
893         return &user_sparc64_view;
894 }
895 
896 #ifdef CONFIG_COMPAT
897 struct compat_fps {
898         unsigned int regs[32];
899         unsigned int fsr;
900         unsigned int flags;
901         unsigned int extra;
902         unsigned int fpqd;
903         struct compat_fq {
904                 unsigned int insnaddr;
905                 unsigned int insn;
906         } fpq[16];
907 };
908 
909 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
910                         compat_ulong_t caddr, compat_ulong_t cdata)
911 {
912         const struct user_regset_view *view = task_user_regset_view(current);
913         compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4];
914         struct pt_regs32 __user *pregs;
915         struct compat_fps __user *fps;
916         unsigned long addr2 = caddr2;
917         unsigned long addr = caddr;
918         unsigned long data = cdata;
919         int ret;
920 
921         pregs = (struct pt_regs32 __user *) addr;
922         fps = (struct compat_fps __user *) addr;
923 
924         switch (request) {
925         case PTRACE_PEEKUSR:
926                 ret = (addr != 0) ? -EIO : 0;
927                 break;
928 
929         case PTRACE_GETREGS:
930                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
931                                           32 * sizeof(u32),
932                                           4 * sizeof(u32),
933                                           &pregs->psr);
934                 if (!ret)
935                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
936                                                   1 * sizeof(u32),
937                                                   15 * sizeof(u32),
938                                                   &pregs->u_regs[0]);
939                 break;
940 
941         case PTRACE_SETREGS:
942                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
943                                             32 * sizeof(u32),
944                                             4 * sizeof(u32),
945                                             &pregs->psr);
946                 if (!ret)
947                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
948                                                     1 * sizeof(u32),
949                                                     15 * sizeof(u32),
950                                                     &pregs->u_regs[0]);
951                 break;
952 
953         case PTRACE_GETFPREGS:
954                 ret = copy_regset_to_user(child, view, REGSET_FP,
955                                           0 * sizeof(u32),
956                                           32 * sizeof(u32),
957                                           &fps->regs[0]);
958                 if (!ret)
959                         ret = copy_regset_to_user(child, view, REGSET_FP,
960                                                   33 * sizeof(u32),
961                                                   1 * sizeof(u32),
962                                                   &fps->fsr);
963                 if (!ret) {
964                         if (__put_user(0, &fps->flags) ||
965                             __put_user(0, &fps->extra) ||
966                             __put_user(0, &fps->fpqd) ||
967                             clear_user(&fps->fpq[0], 32 * sizeof(unsigned int)))
968                                 ret = -EFAULT;
969                 }
970                 break;
971 
972         case PTRACE_SETFPREGS:
973                 ret = copy_regset_from_user(child, view, REGSET_FP,
974                                             0 * sizeof(u32),
975                                             32 * sizeof(u32),
976                                             &fps->regs[0]);
977                 if (!ret)
978                         ret = copy_regset_from_user(child, view, REGSET_FP,
979                                                     33 * sizeof(u32),
980                                                     1 * sizeof(u32),
981                                                     &fps->fsr);
982                 break;
983 
984         case PTRACE_READTEXT:
985         case PTRACE_READDATA:
986                 ret = ptrace_readdata(child, addr,
987                                       (char __user *)addr2, data);
988                 if (ret == data)
989                         ret = 0;
990                 else if (ret >= 0)
991                         ret = -EIO;
992                 break;
993 
994         case PTRACE_WRITETEXT:
995         case PTRACE_WRITEDATA:
996                 ret = ptrace_writedata(child, (char __user *) addr2,
997                                        addr, data);
998                 if (ret == data)
999                         ret = 0;
1000                 else if (ret >= 0)
1001                         ret = -EIO;
1002                 break;
1003 
1004         default:
1005                 if (request == PTRACE_SPARC_DETACH)
1006                         request = PTRACE_DETACH;
1007                 ret = compat_ptrace_request(child, request, addr, data);
1008                 break;
1009         }
1010 
1011         return ret;
1012 }
1013 #endif /* CONFIG_COMPAT */
1014 
1015 struct fps {
1016         unsigned int regs[64];
1017         unsigned long fsr;
1018 };
1019 
1020 long arch_ptrace(struct task_struct *child, long request,
1021                  unsigned long addr, unsigned long data)
1022 {
1023         const struct user_regset_view *view = task_user_regset_view(current);
1024         unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
1025         struct pt_regs __user *pregs;
1026         struct fps __user *fps;
1027         void __user *addr2p;
1028         int ret;
1029 
1030         pregs = (struct pt_regs __user *) addr;
1031         fps = (struct fps __user *) addr;
1032         addr2p = (void __user *) addr2;
1033 
1034         switch (request) {
1035         case PTRACE_PEEKUSR:
1036                 ret = (addr != 0) ? -EIO : 0;
1037                 break;
1038 
1039         case PTRACE_GETREGS64:
1040                 ret = copy_regset_to_user(child, view, REGSET_GENERAL,
1041                                           1 * sizeof(u64),
1042                                           15 * sizeof(u64),
1043                                           &pregs->u_regs[0]);
1044                 if (!ret) {
1045                         /* XXX doesn't handle 'y' register correctly XXX */
1046                         ret = copy_regset_to_user(child, view, REGSET_GENERAL,
1047                                                   32 * sizeof(u64),
1048                                                   4 * sizeof(u64),
1049                                                   &pregs->tstate);
1050                 }
1051                 break;
1052 
1053         case PTRACE_SETREGS64:
1054                 ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1055                                             1 * sizeof(u64),
1056                                             15 * sizeof(u64),
1057                                             &pregs->u_regs[0]);
1058                 if (!ret) {
1059                         /* XXX doesn't handle 'y' register correctly XXX */
1060                         ret = copy_regset_from_user(child, view, REGSET_GENERAL,
1061                                                     32 * sizeof(u64),
1062                                                     4 * sizeof(u64),
1063                                                     &pregs->tstate);
1064                 }
1065                 break;
1066 
1067         case PTRACE_GETFPREGS64:
1068                 ret = copy_regset_to_user(child, view, REGSET_FP,
1069                                           0 * sizeof(u64),
1070                                           33 * sizeof(u64),
1071                                           fps);
1072                 break;
1073 
1074         case PTRACE_SETFPREGS64:
1075                 ret = copy_regset_from_user(child, view, REGSET_FP,
1076                                           0 * sizeof(u64),
1077                                           33 * sizeof(u64),
1078                                           fps);
1079                 break;
1080 
1081         case PTRACE_READTEXT:
1082         case PTRACE_READDATA:
1083                 ret = ptrace_readdata(child, addr, addr2p, data);
1084                 if (ret == data)
1085                         ret = 0;
1086                 else if (ret >= 0)
1087                         ret = -EIO;
1088                 break;
1089 
1090         case PTRACE_WRITETEXT:
1091         case PTRACE_WRITEDATA:
1092                 ret = ptrace_writedata(child, addr2p, addr, data);
1093                 if (ret == data)
1094                         ret = 0;
1095                 else if (ret >= 0)
1096                         ret = -EIO;
1097                 break;
1098 
1099         default:
1100                 if (request == PTRACE_SPARC_DETACH)
1101                         request = PTRACE_DETACH;
1102                 ret = ptrace_request(child, request, addr, data);
1103                 break;
1104         }
1105 
1106         return ret;
1107 }
1108 
1109 asmlinkage int syscall_trace_enter(struct pt_regs *regs)
1110 {
1111         int ret = 0;
1112 
1113         /* do the secure computing check first */
1114         secure_computing_strict(regs->u_regs[UREG_G1]);
1115 
1116         if (test_thread_flag(TIF_NOHZ))
1117                 user_exit();
1118 
1119         if (test_thread_flag(TIF_SYSCALL_TRACE))
1120                 ret = tracehook_report_syscall_entry(regs);
1121 
1122         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1123                 trace_sys_enter(regs, regs->u_regs[UREG_G1]);
1124 
1125         audit_syscall_entry(regs->u_regs[UREG_G1], regs->u_regs[UREG_I0],
1126                             regs->u_regs[UREG_I1], regs->u_regs[UREG_I2],
1127                             regs->u_regs[UREG_I3]);
1128 
1129         return ret;
1130 }
1131 
1132 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
1133 {
1134         if (test_thread_flag(TIF_NOHZ))
1135                 user_exit();
1136 
1137         audit_syscall_exit(regs);
1138 
1139         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
1140                 trace_sys_exit(regs, regs->u_regs[UREG_I0]);
1141 
1142         if (test_thread_flag(TIF_SYSCALL_TRACE))
1143                 tracehook_report_syscall_exit(regs, 0);
1144 
1145         if (test_thread_flag(TIF_NOHZ))
1146                 user_enter();
1147 }
1148 
1149 /**
1150  * regs_query_register_offset() - query register offset from its name
1151  * @name:       the name of a register
1152  *
1153  * regs_query_register_offset() returns the offset of a register in struct
1154  * pt_regs from its name. If the name is invalid, this returns -EINVAL;
1155  */
1156 int regs_query_register_offset(const char *name)
1157 {
1158         const struct pt_regs_offset *roff;
1159 
1160         for (roff = regoffset_table; roff->name != NULL; roff++)
1161                 if (!strcmp(roff->name, name))
1162                         return roff->offset;
1163         return -EINVAL;
1164 }
1165 
1166 /**
1167  * regs_within_kernel_stack() - check the address in the stack
1168  * @regs:       pt_regs which contains kernel stack pointer.
1169  * @addr:       address which is checked.
1170  *
1171  * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
1172  * If @addr is within the kernel stack, it returns true. If not, returns false.
1173  */
1174 static inline int regs_within_kernel_stack(struct pt_regs *regs,
1175                                            unsigned long addr)
1176 {
1177         unsigned long ksp = kernel_stack_pointer(regs) + STACK_BIAS;
1178         return ((addr & ~(THREAD_SIZE - 1))  ==
1179                 (ksp & ~(THREAD_SIZE - 1)));
1180 }
1181 
1182 /**
1183  * regs_get_kernel_stack_nth() - get Nth entry of the stack
1184  * @regs:       pt_regs which contains kernel stack pointer.
1185  * @n:          stack entry number.
1186  *
1187  * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
1188  * is specified by @regs. If the @n th entry is NOT in the kernel stack,
1189  * this returns 0.
1190  */
1191 unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
1192 {
1193         unsigned long ksp = kernel_stack_pointer(regs) + STACK_BIAS;
1194         unsigned long *addr = (unsigned long *)ksp;
1195         addr += n;
1196         if (regs_within_kernel_stack(regs, (unsigned long)addr))
1197                 return *addr;
1198         else
1199                 return 0;
1200 }
1201 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp