root/arch/xtensa/kernel/ptrace.c

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

DEFINITIONS

This source file includes following definitions.
  1. gpr_get
  2. gpr_set
  3. tie_get
  4. tie_set
  5. task_user_regset_view
  6. user_enable_single_step
  7. user_disable_single_step
  8. ptrace_disable
  9. ptrace_getregs
  10. ptrace_setregs
  11. ptrace_getxregs
  12. ptrace_setxregs
  13. ptrace_peekusr
  14. ptrace_pokeusr
  15. ptrace_hbptriggered
  16. ptrace_hbp_create
  17. ptrace_gethbpregs
  18. ptrace_sethbpregs
  19. arch_ptrace
  20. do_syscall_trace_enter
  21. do_syscall_trace_leave

   1 /*
   2  * This file is subject to the terms and conditions of the GNU General Public
   3  * License.  See the file "COPYING" in the main directory of this archive
   4  * for more details.
   5  *
   6  * Copyright (C) 2001 - 2007  Tensilica Inc.
   7  *
   8  * Joe Taylor   <joe@tensilica.com, joetylr@yahoo.com>
   9  * Chris Zankel <chris@zankel.net>
  10  * Scott Foehner<sfoehner@yahoo.com>,
  11  * Kevin Chea
  12  * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
  13  */
  14 
  15 #include <linux/errno.h>
  16 #include <linux/hw_breakpoint.h>
  17 #include <linux/kernel.h>
  18 #include <linux/mm.h>
  19 #include <linux/perf_event.h>
  20 #include <linux/ptrace.h>
  21 #include <linux/regset.h>
  22 #include <linux/sched.h>
  23 #include <linux/sched/task_stack.h>
  24 #include <linux/security.h>
  25 #include <linux/signal.h>
  26 #include <linux/smp.h>
  27 #include <linux/tracehook.h>
  28 #include <linux/uaccess.h>
  29 
  30 #define CREATE_TRACE_POINTS
  31 #include <trace/events/syscalls.h>
  32 
  33 #include <asm/coprocessor.h>
  34 #include <asm/elf.h>
  35 #include <asm/page.h>
  36 #include <asm/pgtable.h>
  37 #include <asm/ptrace.h>
  38 
  39 static int gpr_get(struct task_struct *target,
  40                    const struct user_regset *regset,
  41                    unsigned int pos, unsigned int count,
  42                    void *kbuf, void __user *ubuf)
  43 {
  44         struct pt_regs *regs = task_pt_regs(target);
  45         struct user_pt_regs newregs = {
  46                 .pc = regs->pc,
  47                 .ps = regs->ps & ~(1 << PS_EXCM_BIT),
  48                 .lbeg = regs->lbeg,
  49                 .lend = regs->lend,
  50                 .lcount = regs->lcount,
  51                 .sar = regs->sar,
  52                 .threadptr = regs->threadptr,
  53                 .windowbase = regs->windowbase,
  54                 .windowstart = regs->windowstart,
  55         };
  56 
  57         memcpy(newregs.a,
  58                regs->areg + XCHAL_NUM_AREGS - regs->windowbase * 4,
  59                regs->windowbase * 16);
  60         memcpy(newregs.a + regs->windowbase * 4,
  61                regs->areg,
  62                (WSBITS - regs->windowbase) * 16);
  63 
  64         return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  65                                    &newregs, 0, -1);
  66 }
  67 
  68 static int gpr_set(struct task_struct *target,
  69                    const struct user_regset *regset,
  70                    unsigned int pos, unsigned int count,
  71                    const void *kbuf, const void __user *ubuf)
  72 {
  73         int ret;
  74         struct user_pt_regs newregs = {0};
  75         struct pt_regs *regs;
  76         const u32 ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
  77 
  78         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
  79         if (ret)
  80                 return ret;
  81 
  82         if (newregs.windowbase >= XCHAL_NUM_AREGS / 4)
  83                 return -EINVAL;
  84 
  85         regs = task_pt_regs(target);
  86         regs->pc = newregs.pc;
  87         regs->ps = (regs->ps & ~ps_mask) | (newregs.ps & ps_mask);
  88         regs->lbeg = newregs.lbeg;
  89         regs->lend = newregs.lend;
  90         regs->lcount = newregs.lcount;
  91         regs->sar = newregs.sar;
  92         regs->threadptr = newregs.threadptr;
  93 
  94         if (newregs.windowbase != regs->windowbase ||
  95             newregs.windowstart != regs->windowstart) {
  96                 u32 rotws, wmask;
  97 
  98                 rotws = (((newregs.windowstart |
  99                            (newregs.windowstart << WSBITS)) >>
 100                           newregs.windowbase) &
 101                          ((1 << WSBITS) - 1)) & ~1;
 102                 wmask = ((rotws ? WSBITS + 1 - ffs(rotws) : 0) << 4) |
 103                         (rotws & 0xF) | 1;
 104                 regs->windowbase = newregs.windowbase;
 105                 regs->windowstart = newregs.windowstart;
 106                 regs->wmask = wmask;
 107         }
 108 
 109         memcpy(regs->areg + XCHAL_NUM_AREGS - newregs.windowbase * 4,
 110                newregs.a, newregs.windowbase * 16);
 111         memcpy(regs->areg, newregs.a + newregs.windowbase * 4,
 112                (WSBITS - newregs.windowbase) * 16);
 113 
 114         return 0;
 115 }
 116 
 117 static int tie_get(struct task_struct *target,
 118                    const struct user_regset *regset,
 119                    unsigned int pos, unsigned int count,
 120                    void *kbuf, void __user *ubuf)
 121 {
 122         int ret;
 123         struct pt_regs *regs = task_pt_regs(target);
 124         struct thread_info *ti = task_thread_info(target);
 125         elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL);
 126 
 127         if (!newregs)
 128                 return -ENOMEM;
 129 
 130         newregs->opt = regs->xtregs_opt;
 131         newregs->user = ti->xtregs_user;
 132 
 133 #if XTENSA_HAVE_COPROCESSORS
 134         /* Flush all coprocessor registers to memory. */
 135         coprocessor_flush_all(ti);
 136         newregs->cp0 = ti->xtregs_cp.cp0;
 137         newregs->cp1 = ti->xtregs_cp.cp1;
 138         newregs->cp2 = ti->xtregs_cp.cp2;
 139         newregs->cp3 = ti->xtregs_cp.cp3;
 140         newregs->cp4 = ti->xtregs_cp.cp4;
 141         newregs->cp5 = ti->xtregs_cp.cp5;
 142         newregs->cp6 = ti->xtregs_cp.cp6;
 143         newregs->cp7 = ti->xtregs_cp.cp7;
 144 #endif
 145         ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 146                                   newregs, 0, -1);
 147         kfree(newregs);
 148         return ret;
 149 }
 150 
 151 static int tie_set(struct task_struct *target,
 152                    const struct user_regset *regset,
 153                    unsigned int pos, unsigned int count,
 154                    const void *kbuf, const void __user *ubuf)
 155 {
 156         int ret;
 157         struct pt_regs *regs = task_pt_regs(target);
 158         struct thread_info *ti = task_thread_info(target);
 159         elf_xtregs_t *newregs = kzalloc(sizeof(elf_xtregs_t), GFP_KERNEL);
 160 
 161         if (!newregs)
 162                 return -ENOMEM;
 163 
 164         ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 165                                  newregs, 0, -1);
 166 
 167         if (ret)
 168                 goto exit;
 169         regs->xtregs_opt = newregs->opt;
 170         ti->xtregs_user = newregs->user;
 171 
 172 #if XTENSA_HAVE_COPROCESSORS
 173         /* Flush all coprocessors before we overwrite them. */
 174         coprocessor_flush_all(ti);
 175         coprocessor_release_all(ti);
 176         ti->xtregs_cp.cp0 = newregs->cp0;
 177         ti->xtregs_cp.cp1 = newregs->cp1;
 178         ti->xtregs_cp.cp2 = newregs->cp2;
 179         ti->xtregs_cp.cp3 = newregs->cp3;
 180         ti->xtregs_cp.cp4 = newregs->cp4;
 181         ti->xtregs_cp.cp5 = newregs->cp5;
 182         ti->xtregs_cp.cp6 = newregs->cp6;
 183         ti->xtregs_cp.cp7 = newregs->cp7;
 184 #endif
 185 exit:
 186         kfree(newregs);
 187         return ret;
 188 }
 189 
 190 enum xtensa_regset {
 191         REGSET_GPR,
 192         REGSET_TIE,
 193 };
 194 
 195 static const struct user_regset xtensa_regsets[] = {
 196         [REGSET_GPR] = {
 197                 .core_note_type = NT_PRSTATUS,
 198                 .n = sizeof(struct user_pt_regs) / sizeof(u32),
 199                 .size = sizeof(u32),
 200                 .align = sizeof(u32),
 201                 .get = gpr_get,
 202                 .set = gpr_set,
 203         },
 204         [REGSET_TIE] = {
 205                 .core_note_type = NT_PRFPREG,
 206                 .n = sizeof(elf_xtregs_t) / sizeof(u32),
 207                 .size = sizeof(u32),
 208                 .align = sizeof(u32),
 209                 .get = tie_get,
 210                 .set = tie_set,
 211         },
 212 };
 213 
 214 static const struct user_regset_view user_xtensa_view = {
 215         .name = "xtensa",
 216         .e_machine = EM_XTENSA,
 217         .regsets = xtensa_regsets,
 218         .n = ARRAY_SIZE(xtensa_regsets)
 219 };
 220 
 221 const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 222 {
 223         return &user_xtensa_view;
 224 }
 225 
 226 void user_enable_single_step(struct task_struct *child)
 227 {
 228         child->ptrace |= PT_SINGLESTEP;
 229 }
 230 
 231 void user_disable_single_step(struct task_struct *child)
 232 {
 233         child->ptrace &= ~PT_SINGLESTEP;
 234 }
 235 
 236 /*
 237  * Called by kernel/ptrace.c when detaching to disable single stepping.
 238  */
 239 
 240 void ptrace_disable(struct task_struct *child)
 241 {
 242         /* Nothing to do.. */
 243 }
 244 
 245 static int ptrace_getregs(struct task_struct *child, void __user *uregs)
 246 {
 247         return copy_regset_to_user(child, &user_xtensa_view, REGSET_GPR,
 248                                    0, sizeof(xtensa_gregset_t), uregs);
 249 }
 250 
 251 static int ptrace_setregs(struct task_struct *child, void __user *uregs)
 252 {
 253         return copy_regset_from_user(child, &user_xtensa_view, REGSET_GPR,
 254                                      0, sizeof(xtensa_gregset_t), uregs);
 255 }
 256 
 257 static int ptrace_getxregs(struct task_struct *child, void __user *uregs)
 258 {
 259         return copy_regset_to_user(child, &user_xtensa_view, REGSET_TIE,
 260                                    0, sizeof(elf_xtregs_t), uregs);
 261 }
 262 
 263 static int ptrace_setxregs(struct task_struct *child, void __user *uregs)
 264 {
 265         return copy_regset_from_user(child, &user_xtensa_view, REGSET_TIE,
 266                                      0, sizeof(elf_xtregs_t), uregs);
 267 }
 268 
 269 static int ptrace_peekusr(struct task_struct *child, long regno,
 270                           long __user *ret)
 271 {
 272         struct pt_regs *regs;
 273         unsigned long tmp;
 274 
 275         regs = task_pt_regs(child);
 276         tmp = 0;  /* Default return value. */
 277 
 278         switch(regno) {
 279         case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
 280                 tmp = regs->areg[regno - REG_AR_BASE];
 281                 break;
 282 
 283         case REG_A_BASE ... REG_A_BASE + 15:
 284                 tmp = regs->areg[regno - REG_A_BASE];
 285                 break;
 286 
 287         case REG_PC:
 288                 tmp = regs->pc;
 289                 break;
 290 
 291         case REG_PS:
 292                 /* Note: PS.EXCM is not set while user task is running;
 293                  * its being set in regs is for exception handling
 294                  * convenience.
 295                  */
 296                 tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
 297                 break;
 298 
 299         case REG_WB:
 300                 break;          /* tmp = 0 */
 301 
 302         case REG_WS:
 303                 {
 304                         unsigned long wb = regs->windowbase;
 305                         unsigned long ws = regs->windowstart;
 306                         tmp = ((ws >> wb) | (ws << (WSBITS - wb))) &
 307                                 ((1 << WSBITS) - 1);
 308                         break;
 309                 }
 310         case REG_LBEG:
 311                 tmp = regs->lbeg;
 312                 break;
 313 
 314         case REG_LEND:
 315                 tmp = regs->lend;
 316                 break;
 317 
 318         case REG_LCOUNT:
 319                 tmp = regs->lcount;
 320                 break;
 321 
 322         case REG_SAR:
 323                 tmp = regs->sar;
 324                 break;
 325 
 326         case SYSCALL_NR:
 327                 tmp = regs->syscall;
 328                 break;
 329 
 330         default:
 331                 return -EIO;
 332         }
 333         return put_user(tmp, ret);
 334 }
 335 
 336 static int ptrace_pokeusr(struct task_struct *child, long regno, long val)
 337 {
 338         struct pt_regs *regs;
 339         regs = task_pt_regs(child);
 340 
 341         switch (regno) {
 342         case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
 343                 regs->areg[regno - REG_AR_BASE] = val;
 344                 break;
 345 
 346         case REG_A_BASE ... REG_A_BASE + 15:
 347                 regs->areg[regno - REG_A_BASE] = val;
 348                 break;
 349 
 350         case REG_PC:
 351                 regs->pc = val;
 352                 break;
 353 
 354         case SYSCALL_NR:
 355                 regs->syscall = val;
 356                 break;
 357 
 358         default:
 359                 return -EIO;
 360         }
 361         return 0;
 362 }
 363 
 364 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 365 static void ptrace_hbptriggered(struct perf_event *bp,
 366                                 struct perf_sample_data *data,
 367                                 struct pt_regs *regs)
 368 {
 369         int i;
 370         struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
 371 
 372         if (bp->attr.bp_type & HW_BREAKPOINT_X) {
 373                 for (i = 0; i < XCHAL_NUM_IBREAK; ++i)
 374                         if (current->thread.ptrace_bp[i] == bp)
 375                                 break;
 376                 i <<= 1;
 377         } else {
 378                 for (i = 0; i < XCHAL_NUM_DBREAK; ++i)
 379                         if (current->thread.ptrace_wp[i] == bp)
 380                                 break;
 381                 i = (i << 1) | 1;
 382         }
 383 
 384         force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address);
 385 }
 386 
 387 static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
 388 {
 389         struct perf_event_attr attr;
 390 
 391         ptrace_breakpoint_init(&attr);
 392 
 393         /* Initialise fields to sane defaults. */
 394         attr.bp_addr    = 0;
 395         attr.bp_len     = 1;
 396         attr.bp_type    = type;
 397         attr.disabled   = 1;
 398 
 399         return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL,
 400                                            tsk);
 401 }
 402 
 403 /*
 404  * Address bit 0 choose instruction (0) or data (1) break register, bits
 405  * 31..1 are the register number.
 406  * Both PTRACE_GETHBPREGS and PTRACE_SETHBPREGS transfer two 32-bit words:
 407  * address (0) and control (1).
 408  * Instruction breakpoint contorl word is 0 to clear breakpoint, 1 to set.
 409  * Data breakpoint control word bit 31 is 'trigger on store', bit 30 is
 410  * 'trigger on load, bits 29..0 are length. Length 0 is used to clear a
 411  * breakpoint. To set a breakpoint length must be a power of 2 in the range
 412  * 1..64 and the address must be length-aligned.
 413  */
 414 
 415 static long ptrace_gethbpregs(struct task_struct *child, long addr,
 416                               long __user *datap)
 417 {
 418         struct perf_event *bp;
 419         u32 user_data[2] = {0};
 420         bool dbreak = addr & 1;
 421         unsigned idx = addr >> 1;
 422 
 423         if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
 424             (dbreak && idx >= XCHAL_NUM_DBREAK))
 425                 return -EINVAL;
 426 
 427         if (dbreak)
 428                 bp = child->thread.ptrace_wp[idx];
 429         else
 430                 bp = child->thread.ptrace_bp[idx];
 431 
 432         if (bp) {
 433                 user_data[0] = bp->attr.bp_addr;
 434                 user_data[1] = bp->attr.disabled ? 0 : bp->attr.bp_len;
 435                 if (dbreak) {
 436                         if (bp->attr.bp_type & HW_BREAKPOINT_R)
 437                                 user_data[1] |= DBREAKC_LOAD_MASK;
 438                         if (bp->attr.bp_type & HW_BREAKPOINT_W)
 439                                 user_data[1] |= DBREAKC_STOR_MASK;
 440                 }
 441         }
 442 
 443         if (copy_to_user(datap, user_data, sizeof(user_data)))
 444                 return -EFAULT;
 445 
 446         return 0;
 447 }
 448 
 449 static long ptrace_sethbpregs(struct task_struct *child, long addr,
 450                               long __user *datap)
 451 {
 452         struct perf_event *bp;
 453         struct perf_event_attr attr;
 454         u32 user_data[2];
 455         bool dbreak = addr & 1;
 456         unsigned idx = addr >> 1;
 457         int bp_type = 0;
 458 
 459         if ((!dbreak && idx >= XCHAL_NUM_IBREAK) ||
 460             (dbreak && idx >= XCHAL_NUM_DBREAK))
 461                 return -EINVAL;
 462 
 463         if (copy_from_user(user_data, datap, sizeof(user_data)))
 464                 return -EFAULT;
 465 
 466         if (dbreak) {
 467                 bp = child->thread.ptrace_wp[idx];
 468                 if (user_data[1] & DBREAKC_LOAD_MASK)
 469                         bp_type |= HW_BREAKPOINT_R;
 470                 if (user_data[1] & DBREAKC_STOR_MASK)
 471                         bp_type |= HW_BREAKPOINT_W;
 472         } else {
 473                 bp = child->thread.ptrace_bp[idx];
 474                 bp_type = HW_BREAKPOINT_X;
 475         }
 476 
 477         if (!bp) {
 478                 bp = ptrace_hbp_create(child,
 479                                        bp_type ? bp_type : HW_BREAKPOINT_RW);
 480                 if (IS_ERR(bp))
 481                         return PTR_ERR(bp);
 482                 if (dbreak)
 483                         child->thread.ptrace_wp[idx] = bp;
 484                 else
 485                         child->thread.ptrace_bp[idx] = bp;
 486         }
 487 
 488         attr = bp->attr;
 489         attr.bp_addr = user_data[0];
 490         attr.bp_len = user_data[1] & ~(DBREAKC_LOAD_MASK | DBREAKC_STOR_MASK);
 491         attr.bp_type = bp_type;
 492         attr.disabled = !attr.bp_len;
 493 
 494         return modify_user_hw_breakpoint(bp, &attr);
 495 }
 496 #endif
 497 
 498 long arch_ptrace(struct task_struct *child, long request,
 499                  unsigned long addr, unsigned long data)
 500 {
 501         int ret = -EPERM;
 502         void __user *datap = (void __user *) data;
 503 
 504         switch (request) {
 505         case PTRACE_PEEKUSR:    /* read register specified by addr. */
 506                 ret = ptrace_peekusr(child, addr, datap);
 507                 break;
 508 
 509         case PTRACE_POKEUSR:    /* write register specified by addr. */
 510                 ret = ptrace_pokeusr(child, addr, data);
 511                 break;
 512 
 513         case PTRACE_GETREGS:
 514                 ret = ptrace_getregs(child, datap);
 515                 break;
 516 
 517         case PTRACE_SETREGS:
 518                 ret = ptrace_setregs(child, datap);
 519                 break;
 520 
 521         case PTRACE_GETXTREGS:
 522                 ret = ptrace_getxregs(child, datap);
 523                 break;
 524 
 525         case PTRACE_SETXTREGS:
 526                 ret = ptrace_setxregs(child, datap);
 527                 break;
 528 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 529         case PTRACE_GETHBPREGS:
 530                 ret = ptrace_gethbpregs(child, addr, datap);
 531                 break;
 532 
 533         case PTRACE_SETHBPREGS:
 534                 ret = ptrace_sethbpregs(child, addr, datap);
 535                 break;
 536 #endif
 537         default:
 538                 ret = ptrace_request(child, request, addr, data);
 539                 break;
 540         }
 541 
 542         return ret;
 543 }
 544 
 545 void do_syscall_trace_enter(struct pt_regs *regs)
 546 {
 547         if (test_thread_flag(TIF_SYSCALL_TRACE) &&
 548             tracehook_report_syscall_entry(regs))
 549                 regs->syscall = NO_SYSCALL;
 550 
 551         if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 552                 trace_sys_enter(regs, syscall_get_nr(current, regs));
 553 }
 554 
 555 void do_syscall_trace_leave(struct pt_regs *regs)
 556 {
 557         int step;
 558 
 559         if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 560                 trace_sys_exit(regs, regs_return_value(regs));
 561 
 562         step = test_thread_flag(TIF_SINGLESTEP);
 563 
 564         if (step || test_thread_flag(TIF_SYSCALL_TRACE))
 565                 tracehook_report_syscall_exit(regs, step);
 566 }

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