root/arch/sparc/kernel/ptrace_64.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ptrace_disable
  2. flush_ptrace_access
  3. get_from_target
  4. set_to_target
  5. regwindow64_get
  6. regwindow64_set
  7. genregs64_get
  8. genregs64_set
  9. fpregs64_get
  10. fpregs64_set
  11. genregs32_get
  12. genregs32_set
  13. fpregs32_get
  14. fpregs32_set
  15. task_user_regset_view
  16. compat_arch_ptrace
  17. arch_ptrace
  18. syscall_trace_enter
  19. syscall_trace_leave
  20. regs_query_register_offset
  21. regs_within_kernel_stack
  22. regs_get_kernel_stack_nth

   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 }

/* [<][>][^][v][top][bottom][index][help] */