linux/arch/arm64/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Based on arch/arm/kernel/ptrace.c
   3 *
   4 * By Ross Biro 1/23/92
   5 * edited by Linus Torvalds
   6 * ARM modifications Copyright (C) 2000 Russell King
   7 * Copyright (C) 2012 ARM Ltd.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/sched.h>
  24#include <linux/mm.h>
  25#include <linux/smp.h>
  26#include <linux/ptrace.h>
  27#include <linux/user.h>
  28#include <linux/security.h>
  29#include <linux/init.h>
  30#include <linux/signal.h>
  31#include <linux/uaccess.h>
  32#include <linux/perf_event.h>
  33#include <linux/hw_breakpoint.h>
  34#include <linux/regset.h>
  35#include <linux/tracehook.h>
  36#include <linux/elf.h>
  37
  38#include <asm/compat.h>
  39#include <asm/debug-monitors.h>
  40#include <asm/pgtable.h>
  41#include <asm/traps.h>
  42#include <asm/system_misc.h>
  43
  44/*
  45 * TODO: does not yet catch signals sent when the child dies.
  46 * in exit.c or in signal.c.
  47 */
  48
  49/*
  50 * Called by kernel/ptrace.c when detaching..
  51 */
  52void ptrace_disable(struct task_struct *child)
  53{
  54}
  55
  56#ifdef CONFIG_HAVE_HW_BREAKPOINT
  57/*
  58 * Handle hitting a HW-breakpoint.
  59 */
  60static void ptrace_hbptriggered(struct perf_event *bp,
  61                                struct perf_sample_data *data,
  62                                struct pt_regs *regs)
  63{
  64        struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
  65        siginfo_t info = {
  66                .si_signo       = SIGTRAP,
  67                .si_errno       = 0,
  68                .si_code        = TRAP_HWBKPT,
  69                .si_addr        = (void __user *)(bkpt->trigger),
  70        };
  71
  72#ifdef CONFIG_COMPAT
  73        int i;
  74
  75        if (!is_compat_task())
  76                goto send_sig;
  77
  78        for (i = 0; i < ARM_MAX_BRP; ++i) {
  79                if (current->thread.debug.hbp_break[i] == bp) {
  80                        info.si_errno = (i << 1) + 1;
  81                        break;
  82                }
  83        }
  84        for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) {
  85                if (current->thread.debug.hbp_watch[i] == bp) {
  86                        info.si_errno = -((i << 1) + 1);
  87                        break;
  88                }
  89        }
  90
  91send_sig:
  92#endif
  93        force_sig_info(SIGTRAP, &info, current);
  94}
  95
  96/*
  97 * Unregister breakpoints from this task and reset the pointers in
  98 * the thread_struct.
  99 */
 100void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
 101{
 102        int i;
 103        struct thread_struct *t = &tsk->thread;
 104
 105        for (i = 0; i < ARM_MAX_BRP; i++) {
 106                if (t->debug.hbp_break[i]) {
 107                        unregister_hw_breakpoint(t->debug.hbp_break[i]);
 108                        t->debug.hbp_break[i] = NULL;
 109                }
 110        }
 111
 112        for (i = 0; i < ARM_MAX_WRP; i++) {
 113                if (t->debug.hbp_watch[i]) {
 114                        unregister_hw_breakpoint(t->debug.hbp_watch[i]);
 115                        t->debug.hbp_watch[i] = NULL;
 116                }
 117        }
 118}
 119
 120void ptrace_hw_copy_thread(struct task_struct *tsk)
 121{
 122        memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
 123}
 124
 125static struct perf_event *ptrace_hbp_get_event(unsigned int note_type,
 126                                               struct task_struct *tsk,
 127                                               unsigned long idx)
 128{
 129        struct perf_event *bp = ERR_PTR(-EINVAL);
 130
 131        switch (note_type) {
 132        case NT_ARM_HW_BREAK:
 133                if (idx < ARM_MAX_BRP)
 134                        bp = tsk->thread.debug.hbp_break[idx];
 135                break;
 136        case NT_ARM_HW_WATCH:
 137                if (idx < ARM_MAX_WRP)
 138                        bp = tsk->thread.debug.hbp_watch[idx];
 139                break;
 140        }
 141
 142        return bp;
 143}
 144
 145static int ptrace_hbp_set_event(unsigned int note_type,
 146                                struct task_struct *tsk,
 147                                unsigned long idx,
 148                                struct perf_event *bp)
 149{
 150        int err = -EINVAL;
 151
 152        switch (note_type) {
 153        case NT_ARM_HW_BREAK:
 154                if (idx < ARM_MAX_BRP) {
 155                        tsk->thread.debug.hbp_break[idx] = bp;
 156                        err = 0;
 157                }
 158                break;
 159        case NT_ARM_HW_WATCH:
 160                if (idx < ARM_MAX_WRP) {
 161                        tsk->thread.debug.hbp_watch[idx] = bp;
 162                        err = 0;
 163                }
 164                break;
 165        }
 166
 167        return err;
 168}
 169
 170static struct perf_event *ptrace_hbp_create(unsigned int note_type,
 171                                            struct task_struct *tsk,
 172                                            unsigned long idx)
 173{
 174        struct perf_event *bp;
 175        struct perf_event_attr attr;
 176        int err, type;
 177
 178        switch (note_type) {
 179        case NT_ARM_HW_BREAK:
 180                type = HW_BREAKPOINT_X;
 181                break;
 182        case NT_ARM_HW_WATCH:
 183                type = HW_BREAKPOINT_RW;
 184                break;
 185        default:
 186                return ERR_PTR(-EINVAL);
 187        }
 188
 189        ptrace_breakpoint_init(&attr);
 190
 191        /*
 192         * Initialise fields to sane defaults
 193         * (i.e. values that will pass validation).
 194         */
 195        attr.bp_addr    = 0;
 196        attr.bp_len     = HW_BREAKPOINT_LEN_4;
 197        attr.bp_type    = type;
 198        attr.disabled   = 1;
 199
 200        bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk);
 201        if (IS_ERR(bp))
 202                return bp;
 203
 204        err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
 205        if (err)
 206                return ERR_PTR(err);
 207
 208        return bp;
 209}
 210
 211static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
 212                                     struct arch_hw_breakpoint_ctrl ctrl,
 213                                     struct perf_event_attr *attr)
 214{
 215        int err, len, type, disabled = !ctrl.enabled;
 216
 217        if (disabled) {
 218                len = 0;
 219                type = HW_BREAKPOINT_EMPTY;
 220        } else {
 221                err = arch_bp_generic_fields(ctrl, &len, &type);
 222                if (err)
 223                        return err;
 224
 225                switch (note_type) {
 226                case NT_ARM_HW_BREAK:
 227                        if ((type & HW_BREAKPOINT_X) != type)
 228                                return -EINVAL;
 229                        break;
 230                case NT_ARM_HW_WATCH:
 231                        if ((type & HW_BREAKPOINT_RW) != type)
 232                                return -EINVAL;
 233                        break;
 234                default:
 235                        return -EINVAL;
 236                }
 237        }
 238
 239        attr->bp_len    = len;
 240        attr->bp_type   = type;
 241        attr->disabled  = disabled;
 242
 243        return 0;
 244}
 245
 246static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info)
 247{
 248        u8 num;
 249        u32 reg = 0;
 250
 251        switch (note_type) {
 252        case NT_ARM_HW_BREAK:
 253                num = hw_breakpoint_slots(TYPE_INST);
 254                break;
 255        case NT_ARM_HW_WATCH:
 256                num = hw_breakpoint_slots(TYPE_DATA);
 257                break;
 258        default:
 259                return -EINVAL;
 260        }
 261
 262        reg |= debug_monitors_arch();
 263        reg <<= 8;
 264        reg |= num;
 265
 266        *info = reg;
 267        return 0;
 268}
 269
 270static int ptrace_hbp_get_ctrl(unsigned int note_type,
 271                               struct task_struct *tsk,
 272                               unsigned long idx,
 273                               u32 *ctrl)
 274{
 275        struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
 276
 277        if (IS_ERR(bp))
 278                return PTR_ERR(bp);
 279
 280        *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
 281        return 0;
 282}
 283
 284static int ptrace_hbp_get_addr(unsigned int note_type,
 285                               struct task_struct *tsk,
 286                               unsigned long idx,
 287                               u64 *addr)
 288{
 289        struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
 290
 291        if (IS_ERR(bp))
 292                return PTR_ERR(bp);
 293
 294        *addr = bp ? bp->attr.bp_addr : 0;
 295        return 0;
 296}
 297
 298static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type,
 299                                                        struct task_struct *tsk,
 300                                                        unsigned long idx)
 301{
 302        struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
 303
 304        if (!bp)
 305                bp = ptrace_hbp_create(note_type, tsk, idx);
 306
 307        return bp;
 308}
 309
 310static int ptrace_hbp_set_ctrl(unsigned int note_type,
 311                               struct task_struct *tsk,
 312                               unsigned long idx,
 313                               u32 uctrl)
 314{
 315        int err;
 316        struct perf_event *bp;
 317        struct perf_event_attr attr;
 318        struct arch_hw_breakpoint_ctrl ctrl;
 319
 320        bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
 321        if (IS_ERR(bp)) {
 322                err = PTR_ERR(bp);
 323                return err;
 324        }
 325
 326        attr = bp->attr;
 327        decode_ctrl_reg(uctrl, &ctrl);
 328        err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
 329        if (err)
 330                return err;
 331
 332        return modify_user_hw_breakpoint(bp, &attr);
 333}
 334
 335static int ptrace_hbp_set_addr(unsigned int note_type,
 336                               struct task_struct *tsk,
 337                               unsigned long idx,
 338                               u64 addr)
 339{
 340        int err;
 341        struct perf_event *bp;
 342        struct perf_event_attr attr;
 343
 344        bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
 345        if (IS_ERR(bp)) {
 346                err = PTR_ERR(bp);
 347                return err;
 348        }
 349
 350        attr = bp->attr;
 351        attr.bp_addr = addr;
 352        err = modify_user_hw_breakpoint(bp, &attr);
 353        return err;
 354}
 355
 356#define PTRACE_HBP_ADDR_SZ      sizeof(u64)
 357#define PTRACE_HBP_CTRL_SZ      sizeof(u32)
 358#define PTRACE_HBP_PAD_SZ       sizeof(u32)
 359
 360static int hw_break_get(struct task_struct *target,
 361                        const struct user_regset *regset,
 362                        unsigned int pos, unsigned int count,
 363                        void *kbuf, void __user *ubuf)
 364{
 365        unsigned int note_type = regset->core_note_type;
 366        int ret, idx = 0, offset, limit;
 367        u32 info, ctrl;
 368        u64 addr;
 369
 370        /* Resource info */
 371        ret = ptrace_hbp_get_resource_info(note_type, &info);
 372        if (ret)
 373                return ret;
 374
 375        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0,
 376                                  sizeof(info));
 377        if (ret)
 378                return ret;
 379
 380        /* Pad */
 381        offset = offsetof(struct user_hwdebug_state, pad);
 382        ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, offset,
 383                                       offset + PTRACE_HBP_PAD_SZ);
 384        if (ret)
 385                return ret;
 386
 387        /* (address, ctrl) registers */
 388        offset = offsetof(struct user_hwdebug_state, dbg_regs);
 389        limit = regset->n * regset->size;
 390        while (count && offset < limit) {
 391                ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
 392                if (ret)
 393                        return ret;
 394                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr,
 395                                          offset, offset + PTRACE_HBP_ADDR_SZ);
 396                if (ret)
 397                        return ret;
 398                offset += PTRACE_HBP_ADDR_SZ;
 399
 400                ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
 401                if (ret)
 402                        return ret;
 403                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl,
 404                                          offset, offset + PTRACE_HBP_CTRL_SZ);
 405                if (ret)
 406                        return ret;
 407                offset += PTRACE_HBP_CTRL_SZ;
 408
 409                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 410                                               offset,
 411                                               offset + PTRACE_HBP_PAD_SZ);
 412                if (ret)
 413                        return ret;
 414                offset += PTRACE_HBP_PAD_SZ;
 415                idx++;
 416        }
 417
 418        return 0;
 419}
 420
 421static int hw_break_set(struct task_struct *target,
 422                        const struct user_regset *regset,
 423                        unsigned int pos, unsigned int count,
 424                        const void *kbuf, const void __user *ubuf)
 425{
 426        unsigned int note_type = regset->core_note_type;
 427        int ret, idx = 0, offset, limit;
 428        u32 ctrl;
 429        u64 addr;
 430
 431        /* Resource info and pad */
 432        offset = offsetof(struct user_hwdebug_state, dbg_regs);
 433        ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
 434        if (ret)
 435                return ret;
 436
 437        /* (address, ctrl) registers */
 438        limit = regset->n * regset->size;
 439        while (count && offset < limit) {
 440                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
 441                                         offset, offset + PTRACE_HBP_ADDR_SZ);
 442                if (ret)
 443                        return ret;
 444                ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
 445                if (ret)
 446                        return ret;
 447                offset += PTRACE_HBP_ADDR_SZ;
 448
 449                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
 450                                         offset, offset + PTRACE_HBP_CTRL_SZ);
 451                if (ret)
 452                        return ret;
 453                ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
 454                if (ret)
 455                        return ret;
 456                offset += PTRACE_HBP_CTRL_SZ;
 457
 458                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 459                                                offset,
 460                                                offset + PTRACE_HBP_PAD_SZ);
 461                if (ret)
 462                        return ret;
 463                offset += PTRACE_HBP_PAD_SZ;
 464                idx++;
 465        }
 466
 467        return 0;
 468}
 469#endif  /* CONFIG_HAVE_HW_BREAKPOINT */
 470
 471static int gpr_get(struct task_struct *target,
 472                   const struct user_regset *regset,
 473                   unsigned int pos, unsigned int count,
 474                   void *kbuf, void __user *ubuf)
 475{
 476        struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs;
 477        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
 478}
 479
 480static int gpr_set(struct task_struct *target, const struct user_regset *regset,
 481                   unsigned int pos, unsigned int count,
 482                   const void *kbuf, const void __user *ubuf)
 483{
 484        int ret;
 485        struct user_pt_regs newregs;
 486
 487        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
 488        if (ret)
 489                return ret;
 490
 491        if (!valid_user_regs(&newregs))
 492                return -EINVAL;
 493
 494        task_pt_regs(target)->user_regs = newregs;
 495        return 0;
 496}
 497
 498/*
 499 * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
 500 */
 501static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 502                   unsigned int pos, unsigned int count,
 503                   void *kbuf, void __user *ubuf)
 504{
 505        struct user_fpsimd_state *uregs;
 506        uregs = &target->thread.fpsimd_state.user_fpsimd;
 507        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
 508}
 509
 510static int fpr_set(struct task_struct *target, const struct user_regset *regset,
 511                   unsigned int pos, unsigned int count,
 512                   const void *kbuf, const void __user *ubuf)
 513{
 514        int ret;
 515        struct user_fpsimd_state newstate;
 516
 517        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
 518        if (ret)
 519                return ret;
 520
 521        target->thread.fpsimd_state.user_fpsimd = newstate;
 522        return ret;
 523}
 524
 525static int tls_get(struct task_struct *target, const struct user_regset *regset,
 526                   unsigned int pos, unsigned int count,
 527                   void *kbuf, void __user *ubuf)
 528{
 529        unsigned long *tls = &target->thread.tp_value;
 530        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1);
 531}
 532
 533static int tls_set(struct task_struct *target, const struct user_regset *regset,
 534                   unsigned int pos, unsigned int count,
 535                   const void *kbuf, const void __user *ubuf)
 536{
 537        int ret;
 538        unsigned long tls;
 539
 540        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
 541        if (ret)
 542                return ret;
 543
 544        target->thread.tp_value = tls;
 545        return ret;
 546}
 547
 548enum aarch64_regset {
 549        REGSET_GPR,
 550        REGSET_FPR,
 551        REGSET_TLS,
 552#ifdef CONFIG_HAVE_HW_BREAKPOINT
 553        REGSET_HW_BREAK,
 554        REGSET_HW_WATCH,
 555#endif
 556};
 557
 558static const struct user_regset aarch64_regsets[] = {
 559        [REGSET_GPR] = {
 560                .core_note_type = NT_PRSTATUS,
 561                .n = sizeof(struct user_pt_regs) / sizeof(u64),
 562                .size = sizeof(u64),
 563                .align = sizeof(u64),
 564                .get = gpr_get,
 565                .set = gpr_set
 566        },
 567        [REGSET_FPR] = {
 568                .core_note_type = NT_PRFPREG,
 569                .n = sizeof(struct user_fpsimd_state) / sizeof(u32),
 570                /*
 571                 * We pretend we have 32-bit registers because the fpsr and
 572                 * fpcr are 32-bits wide.
 573                 */
 574                .size = sizeof(u32),
 575                .align = sizeof(u32),
 576                .get = fpr_get,
 577                .set = fpr_set
 578        },
 579        [REGSET_TLS] = {
 580                .core_note_type = NT_ARM_TLS,
 581                .n = 1,
 582                .size = sizeof(void *),
 583                .align = sizeof(void *),
 584                .get = tls_get,
 585                .set = tls_set,
 586        },
 587#ifdef CONFIG_HAVE_HW_BREAKPOINT
 588        [REGSET_HW_BREAK] = {
 589                .core_note_type = NT_ARM_HW_BREAK,
 590                .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
 591                .size = sizeof(u32),
 592                .align = sizeof(u32),
 593                .get = hw_break_get,
 594                .set = hw_break_set,
 595        },
 596        [REGSET_HW_WATCH] = {
 597                .core_note_type = NT_ARM_HW_WATCH,
 598                .n = sizeof(struct user_hwdebug_state) / sizeof(u32),
 599                .size = sizeof(u32),
 600                .align = sizeof(u32),
 601                .get = hw_break_get,
 602                .set = hw_break_set,
 603        },
 604#endif
 605};
 606
 607static const struct user_regset_view user_aarch64_view = {
 608        .name = "aarch64", .e_machine = EM_AARCH64,
 609        .regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets)
 610};
 611
 612#ifdef CONFIG_COMPAT
 613#include <linux/compat.h>
 614
 615enum compat_regset {
 616        REGSET_COMPAT_GPR,
 617        REGSET_COMPAT_VFP,
 618};
 619
 620static int compat_gpr_get(struct task_struct *target,
 621                          const struct user_regset *regset,
 622                          unsigned int pos, unsigned int count,
 623                          void *kbuf, void __user *ubuf)
 624{
 625        int ret = 0;
 626        unsigned int i, start, num_regs;
 627
 628        /* Calculate the number of AArch32 registers contained in count */
 629        num_regs = count / regset->size;
 630
 631        /* Convert pos into an register number */
 632        start = pos / regset->size;
 633
 634        if (start + num_regs > regset->n)
 635                return -EIO;
 636
 637        for (i = 0; i < num_regs; ++i) {
 638                unsigned int idx = start + i;
 639                void *reg;
 640
 641                switch (idx) {
 642                case 15:
 643                        reg = (void *)&task_pt_regs(target)->pc;
 644                        break;
 645                case 16:
 646                        reg = (void *)&task_pt_regs(target)->pstate;
 647                        break;
 648                case 17:
 649                        reg = (void *)&task_pt_regs(target)->orig_x0;
 650                        break;
 651                default:
 652                        reg = (void *)&task_pt_regs(target)->regs[idx];
 653                }
 654
 655                ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t));
 656
 657                if (ret)
 658                        break;
 659                else
 660                        ubuf += sizeof(compat_ulong_t);
 661        }
 662
 663        return ret;
 664}
 665
 666static int compat_gpr_set(struct task_struct *target,
 667                          const struct user_regset *regset,
 668                          unsigned int pos, unsigned int count,
 669                          const void *kbuf, const void __user *ubuf)
 670{
 671        struct pt_regs newregs;
 672        int ret = 0;
 673        unsigned int i, start, num_regs;
 674
 675        /* Calculate the number of AArch32 registers contained in count */
 676        num_regs = count / regset->size;
 677
 678        /* Convert pos into an register number */
 679        start = pos / regset->size;
 680
 681        if (start + num_regs > regset->n)
 682                return -EIO;
 683
 684        newregs = *task_pt_regs(target);
 685
 686        for (i = 0; i < num_regs; ++i) {
 687                unsigned int idx = start + i;
 688                void *reg;
 689
 690                switch (idx) {
 691                case 15:
 692                        reg = (void *)&newregs.pc;
 693                        break;
 694                case 16:
 695                        reg = (void *)&newregs.pstate;
 696                        break;
 697                case 17:
 698                        reg = (void *)&newregs.orig_x0;
 699                        break;
 700                default:
 701                        reg = (void *)&newregs.regs[idx];
 702                }
 703
 704                ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t));
 705
 706                if (ret)
 707                        goto out;
 708                else
 709                        ubuf += sizeof(compat_ulong_t);
 710        }
 711
 712        if (valid_user_regs(&newregs.user_regs))
 713                *task_pt_regs(target) = newregs;
 714        else
 715                ret = -EINVAL;
 716
 717out:
 718        return ret;
 719}
 720
 721static int compat_vfp_get(struct task_struct *target,
 722                          const struct user_regset *regset,
 723                          unsigned int pos, unsigned int count,
 724                          void *kbuf, void __user *ubuf)
 725{
 726        struct user_fpsimd_state *uregs;
 727        compat_ulong_t fpscr;
 728        int ret;
 729
 730        uregs = &target->thread.fpsimd_state.user_fpsimd;
 731
 732        /*
 733         * The VFP registers are packed into the fpsimd_state, so they all sit
 734         * nicely together for us. We just need to create the fpscr separately.
 735         */
 736        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
 737                                  VFP_STATE_SIZE - sizeof(compat_ulong_t));
 738
 739        if (count && !ret) {
 740                fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) |
 741                        (uregs->fpcr & VFP_FPSCR_CTRL_MASK);
 742                ret = put_user(fpscr, (compat_ulong_t *)ubuf);
 743        }
 744
 745        return ret;
 746}
 747
 748static int compat_vfp_set(struct task_struct *target,
 749                          const struct user_regset *regset,
 750                          unsigned int pos, unsigned int count,
 751                          const void *kbuf, const void __user *ubuf)
 752{
 753        struct user_fpsimd_state *uregs;
 754        compat_ulong_t fpscr;
 755        int ret;
 756
 757        if (pos + count > VFP_STATE_SIZE)
 758                return -EIO;
 759
 760        uregs = &target->thread.fpsimd_state.user_fpsimd;
 761
 762        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
 763                                 VFP_STATE_SIZE - sizeof(compat_ulong_t));
 764
 765        if (count && !ret) {
 766                ret = get_user(fpscr, (compat_ulong_t *)ubuf);
 767                uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK;
 768                uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
 769        }
 770
 771        return ret;
 772}
 773
 774static const struct user_regset aarch32_regsets[] = {
 775        [REGSET_COMPAT_GPR] = {
 776                .core_note_type = NT_PRSTATUS,
 777                .n = COMPAT_ELF_NGREG,
 778                .size = sizeof(compat_elf_greg_t),
 779                .align = sizeof(compat_elf_greg_t),
 780                .get = compat_gpr_get,
 781                .set = compat_gpr_set
 782        },
 783        [REGSET_COMPAT_VFP] = {
 784                .core_note_type = NT_ARM_VFP,
 785                .n = VFP_STATE_SIZE / sizeof(compat_ulong_t),
 786                .size = sizeof(compat_ulong_t),
 787                .align = sizeof(compat_ulong_t),
 788                .get = compat_vfp_get,
 789                .set = compat_vfp_set
 790        },
 791};
 792
 793static const struct user_regset_view user_aarch32_view = {
 794        .name = "aarch32", .e_machine = EM_ARM,
 795        .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
 796};
 797
 798static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
 799                                   compat_ulong_t __user *ret)
 800{
 801        compat_ulong_t tmp;
 802
 803        if (off & 3)
 804                return -EIO;
 805
 806        if (off == COMPAT_PT_TEXT_ADDR)
 807                tmp = tsk->mm->start_code;
 808        else if (off == COMPAT_PT_DATA_ADDR)
 809                tmp = tsk->mm->start_data;
 810        else if (off == COMPAT_PT_TEXT_END_ADDR)
 811                tmp = tsk->mm->end_code;
 812        else if (off < sizeof(compat_elf_gregset_t))
 813                return copy_regset_to_user(tsk, &user_aarch32_view,
 814                                           REGSET_COMPAT_GPR, off,
 815                                           sizeof(compat_ulong_t), ret);
 816        else if (off >= COMPAT_USER_SZ)
 817                return -EIO;
 818        else
 819                tmp = 0;
 820
 821        return put_user(tmp, ret);
 822}
 823
 824static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
 825                                    compat_ulong_t val)
 826{
 827        int ret;
 828
 829        if (off & 3 || off >= COMPAT_USER_SZ)
 830                return -EIO;
 831
 832        if (off >= sizeof(compat_elf_gregset_t))
 833                return 0;
 834
 835        ret = copy_regset_from_user(tsk, &user_aarch32_view,
 836                                    REGSET_COMPAT_GPR, off,
 837                                    sizeof(compat_ulong_t),
 838                                    &val);
 839        return ret;
 840}
 841
 842#ifdef CONFIG_HAVE_HW_BREAKPOINT
 843
 844/*
 845 * Convert a virtual register number into an index for a thread_info
 846 * breakpoint array. Breakpoints are identified using positive numbers
 847 * whilst watchpoints are negative. The registers are laid out as pairs
 848 * of (address, control), each pair mapping to a unique hw_breakpoint struct.
 849 * Register 0 is reserved for describing resource information.
 850 */
 851static int compat_ptrace_hbp_num_to_idx(compat_long_t num)
 852{
 853        return (abs(num) - 1) >> 1;
 854}
 855
 856static int compat_ptrace_hbp_get_resource_info(u32 *kdata)
 857{
 858        u8 num_brps, num_wrps, debug_arch, wp_len;
 859        u32 reg = 0;
 860
 861        num_brps        = hw_breakpoint_slots(TYPE_INST);
 862        num_wrps        = hw_breakpoint_slots(TYPE_DATA);
 863
 864        debug_arch      = debug_monitors_arch();
 865        wp_len          = 8;
 866        reg             |= debug_arch;
 867        reg             <<= 8;
 868        reg             |= wp_len;
 869        reg             <<= 8;
 870        reg             |= num_wrps;
 871        reg             <<= 8;
 872        reg             |= num_brps;
 873
 874        *kdata = reg;
 875        return 0;
 876}
 877
 878static int compat_ptrace_hbp_get(unsigned int note_type,
 879                                 struct task_struct *tsk,
 880                                 compat_long_t num,
 881                                 u32 *kdata)
 882{
 883        u64 addr = 0;
 884        u32 ctrl = 0;
 885
 886        int err, idx = compat_ptrace_hbp_num_to_idx(num);;
 887
 888        if (num & 1) {
 889                err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
 890                *kdata = (u32)addr;
 891        } else {
 892                err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl);
 893                *kdata = ctrl;
 894        }
 895
 896        return err;
 897}
 898
 899static int compat_ptrace_hbp_set(unsigned int note_type,
 900                                 struct task_struct *tsk,
 901                                 compat_long_t num,
 902                                 u32 *kdata)
 903{
 904        u64 addr;
 905        u32 ctrl;
 906
 907        int err, idx = compat_ptrace_hbp_num_to_idx(num);
 908
 909        if (num & 1) {
 910                addr = *kdata;
 911                err = ptrace_hbp_set_addr(note_type, tsk, idx, addr);
 912        } else {
 913                ctrl = *kdata;
 914                err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl);
 915        }
 916
 917        return err;
 918}
 919
 920static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num,
 921                                    compat_ulong_t __user *data)
 922{
 923        int ret;
 924        u32 kdata;
 925        mm_segment_t old_fs = get_fs();
 926
 927        set_fs(KERNEL_DS);
 928        /* Watchpoint */
 929        if (num < 0) {
 930                ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata);
 931        /* Resource info */
 932        } else if (num == 0) {
 933                ret = compat_ptrace_hbp_get_resource_info(&kdata);
 934        /* Breakpoint */
 935        } else {
 936                ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata);
 937        }
 938        set_fs(old_fs);
 939
 940        if (!ret)
 941                ret = put_user(kdata, data);
 942
 943        return ret;
 944}
 945
 946static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num,
 947                                    compat_ulong_t __user *data)
 948{
 949        int ret;
 950        u32 kdata = 0;
 951        mm_segment_t old_fs = get_fs();
 952
 953        if (num == 0)
 954                return 0;
 955
 956        ret = get_user(kdata, data);
 957        if (ret)
 958                return ret;
 959
 960        set_fs(KERNEL_DS);
 961        if (num < 0)
 962                ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata);
 963        else
 964                ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata);
 965        set_fs(old_fs);
 966
 967        return ret;
 968}
 969#endif  /* CONFIG_HAVE_HW_BREAKPOINT */
 970
 971long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 972                        compat_ulong_t caddr, compat_ulong_t cdata)
 973{
 974        unsigned long addr = caddr;
 975        unsigned long data = cdata;
 976        void __user *datap = compat_ptr(data);
 977        int ret;
 978
 979        switch (request) {
 980                case PTRACE_PEEKUSR:
 981                        ret = compat_ptrace_read_user(child, addr, datap);
 982                        break;
 983
 984                case PTRACE_POKEUSR:
 985                        ret = compat_ptrace_write_user(child, addr, data);
 986                        break;
 987
 988                case COMPAT_PTRACE_GETREGS:
 989                        ret = copy_regset_to_user(child,
 990                                                  &user_aarch32_view,
 991                                                  REGSET_COMPAT_GPR,
 992                                                  0, sizeof(compat_elf_gregset_t),
 993                                                  datap);
 994                        break;
 995
 996                case COMPAT_PTRACE_SETREGS:
 997                        ret = copy_regset_from_user(child,
 998                                                    &user_aarch32_view,
 999                                                    REGSET_COMPAT_GPR,
1000                                                    0, sizeof(compat_elf_gregset_t),
1001                                                    datap);
1002                        break;
1003
1004                case COMPAT_PTRACE_GET_THREAD_AREA:
1005                        ret = put_user((compat_ulong_t)child->thread.tp_value,
1006                                       (compat_ulong_t __user *)datap);
1007                        break;
1008
1009                case COMPAT_PTRACE_SET_SYSCALL:
1010                        task_pt_regs(child)->syscallno = data;
1011                        ret = 0;
1012                        break;
1013
1014                case COMPAT_PTRACE_GETVFPREGS:
1015                        ret = copy_regset_to_user(child,
1016                                                  &user_aarch32_view,
1017                                                  REGSET_COMPAT_VFP,
1018                                                  0, VFP_STATE_SIZE,
1019                                                  datap);
1020                        break;
1021
1022                case COMPAT_PTRACE_SETVFPREGS:
1023                        ret = copy_regset_from_user(child,
1024                                                    &user_aarch32_view,
1025                                                    REGSET_COMPAT_VFP,
1026                                                    0, VFP_STATE_SIZE,
1027                                                    datap);
1028                        break;
1029
1030#ifdef CONFIG_HAVE_HW_BREAKPOINT
1031                case COMPAT_PTRACE_GETHBPREGS:
1032                        ret = compat_ptrace_gethbpregs(child, addr, datap);
1033                        break;
1034
1035                case COMPAT_PTRACE_SETHBPREGS:
1036                        ret = compat_ptrace_sethbpregs(child, addr, datap);
1037                        break;
1038#endif
1039
1040                default:
1041                        ret = compat_ptrace_request(child, request, addr,
1042                                                    data);
1043                        break;
1044        }
1045
1046        return ret;
1047}
1048#endif /* CONFIG_COMPAT */
1049
1050const struct user_regset_view *task_user_regset_view(struct task_struct *task)
1051{
1052#ifdef CONFIG_COMPAT
1053        if (is_compat_thread(task_thread_info(task)))
1054                return &user_aarch32_view;
1055#endif
1056        return &user_aarch64_view;
1057}
1058
1059long arch_ptrace(struct task_struct *child, long request,
1060                 unsigned long addr, unsigned long data)
1061{
1062        return ptrace_request(child, request, addr, data);
1063}
1064
1065asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
1066{
1067        unsigned long saved_reg;
1068
1069        if (!test_thread_flag(TIF_SYSCALL_TRACE))
1070                return regs->syscallno;
1071
1072        if (is_compat_task()) {
1073                /* AArch32 uses ip (r12) for scratch */
1074                saved_reg = regs->regs[12];
1075                regs->regs[12] = dir;
1076        } else {
1077                /*
1078                 * Save X7. X7 is used to denote syscall entry/exit:
1079                 *   X7 = 0 -> entry, = 1 -> exit
1080                 */
1081                saved_reg = regs->regs[7];
1082                regs->regs[7] = dir;
1083        }
1084
1085        if (dir)
1086                tracehook_report_syscall_exit(regs, 0);
1087        else if (tracehook_report_syscall_entry(regs))
1088                regs->syscallno = ~0UL;
1089
1090        if (is_compat_task())
1091                regs->regs[12] = saved_reg;
1092        else
1093                regs->regs[7] = saved_reg;
1094
1095        return regs->syscallno;
1096}
1097