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