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

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

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

~ [ 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