linux/arch/tile/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 *
  14 * Copied from i386: Ross Biro 1/23/92
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/ptrace.h>
  19#include <linux/kprobes.h>
  20#include <linux/compat.h>
  21#include <linux/uaccess.h>
  22#include <linux/regset.h>
  23#include <linux/elf.h>
  24#include <linux/tracehook.h>
  25#include <linux/context_tracking.h>
  26#include <linux/sched/task_stack.h>
  27
  28#include <asm/traps.h>
  29#include <arch/chip.h>
  30
  31#define CREATE_TRACE_POINTS
  32#include <trace/events/syscalls.h>
  33
  34void user_enable_single_step(struct task_struct *child)
  35{
  36        set_tsk_thread_flag(child, TIF_SINGLESTEP);
  37}
  38
  39void user_disable_single_step(struct task_struct *child)
  40{
  41        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
  42}
  43
  44/*
  45 * Called by kernel/ptrace.c when detaching..
  46 */
  47void ptrace_disable(struct task_struct *child)
  48{
  49        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
  50
  51        /*
  52         * These two are currently unused, but will be set by arch_ptrace()
  53         * and used in the syscall assembly when we do support them.
  54         */
  55        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  56}
  57
  58/*
  59 * Get registers from task and ready the result for userspace.
  60 * Note that we localize the API issues to getregs() and putregs() at
  61 * some cost in performance, e.g. we need a full pt_regs copy for
  62 * PEEKUSR, and two copies for POKEUSR.  But in general we expect
  63 * GETREGS/PUTREGS to be the API of choice anyway.
  64 */
  65static char *getregs(struct task_struct *child, struct pt_regs *uregs)
  66{
  67        *uregs = *task_pt_regs(child);
  68
  69        /* Set up flags ABI bits. */
  70        uregs->flags = 0;
  71#ifdef CONFIG_COMPAT
  72        if (task_thread_info(child)->status & TS_COMPAT)
  73                uregs->flags |= PT_FLAGS_COMPAT;
  74#endif
  75
  76        return (char *)uregs;
  77}
  78
  79/* Put registers back to task. */
  80static void putregs(struct task_struct *child, struct pt_regs *uregs)
  81{
  82        struct pt_regs *regs = task_pt_regs(child);
  83
  84        /* Don't allow overwriting the kernel-internal flags word. */
  85        uregs->flags = regs->flags;
  86
  87        /* Only allow setting the ICS bit in the ex1 word. */
  88        uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));
  89
  90        *regs = *uregs;
  91}
  92
  93enum tile_regset {
  94        REGSET_GPR,
  95};
  96
  97static int tile_gpr_get(struct task_struct *target,
  98                          const struct user_regset *regset,
  99                          unsigned int pos, unsigned int count,
 100                          void *kbuf, void __user *ubuf)
 101{
 102        struct pt_regs regs;
 103
 104        getregs(target, &regs);
 105
 106        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs, 0,
 107                                   sizeof(regs));
 108}
 109
 110static int tile_gpr_set(struct task_struct *target,
 111                          const struct user_regset *regset,
 112                          unsigned int pos, unsigned int count,
 113                          const void *kbuf, const void __user *ubuf)
 114{
 115        int ret;
 116        struct pt_regs regs = *task_pt_regs(target);
 117
 118        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
 119                                 sizeof(regs));
 120        if (ret)
 121                return ret;
 122
 123        putregs(target, &regs);
 124
 125        return 0;
 126}
 127
 128static const struct user_regset tile_user_regset[] = {
 129        [REGSET_GPR] = {
 130                .core_note_type = NT_PRSTATUS,
 131                .n = ELF_NGREG,
 132                .size = sizeof(elf_greg_t),
 133                .align = sizeof(elf_greg_t),
 134                .get = tile_gpr_get,
 135                .set = tile_gpr_set,
 136        },
 137};
 138
 139static const struct user_regset_view tile_user_regset_view = {
 140        .name = CHIP_ARCH_NAME,
 141        .e_machine = ELF_ARCH,
 142        .ei_osabi = ELF_OSABI,
 143        .regsets = tile_user_regset,
 144        .n = ARRAY_SIZE(tile_user_regset),
 145};
 146
 147const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 148{
 149        return &tile_user_regset_view;
 150}
 151
 152long arch_ptrace(struct task_struct *child, long request,
 153                 unsigned long addr, unsigned long data)
 154{
 155        unsigned long __user *datap = (long __user __force *)data;
 156        unsigned long tmp;
 157        long ret = -EIO;
 158        char *childreg;
 159        struct pt_regs copyregs;
 160
 161        switch (request) {
 162
 163        case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
 164                if (addr >= PTREGS_SIZE)
 165                        break;
 166                childreg = getregs(child, &copyregs) + addr;
 167#ifdef CONFIG_COMPAT
 168                if (is_compat_task()) {
 169                        if (addr & (sizeof(compat_long_t)-1))
 170                                break;
 171                        ret = put_user(*(compat_long_t *)childreg,
 172                                       (compat_long_t __user *)datap);
 173                } else
 174#endif
 175                {
 176                        if (addr & (sizeof(long)-1))
 177                                break;
 178                        ret = put_user(*(long *)childreg, datap);
 179                }
 180                break;
 181
 182        case PTRACE_POKEUSR:  /* Write register in pt_regs. */
 183                if (addr >= PTREGS_SIZE)
 184                        break;
 185                childreg = getregs(child, &copyregs) + addr;
 186#ifdef CONFIG_COMPAT
 187                if (is_compat_task()) {
 188                        if (addr & (sizeof(compat_long_t)-1))
 189                                break;
 190                        *(compat_long_t *)childreg = data;
 191                } else
 192#endif
 193                {
 194                        if (addr & (sizeof(long)-1))
 195                                break;
 196                        *(long *)childreg = data;
 197                }
 198                putregs(child, &copyregs);
 199                ret = 0;
 200                break;
 201
 202        case PTRACE_GETREGS:  /* Get all registers from the child. */
 203                ret = copy_regset_to_user(child, &tile_user_regset_view,
 204                                          REGSET_GPR, 0,
 205                                          sizeof(struct pt_regs), datap);
 206                break;
 207
 208        case PTRACE_SETREGS:  /* Set all registers in the child. */
 209                ret = copy_regset_from_user(child, &tile_user_regset_view,
 210                                            REGSET_GPR, 0,
 211                                            sizeof(struct pt_regs), datap);
 212                break;
 213
 214        case PTRACE_GETFPREGS:  /* Get the child FPU state. */
 215        case PTRACE_SETFPREGS:  /* Set the child FPU state. */
 216                break;
 217
 218        case PTRACE_SETOPTIONS:
 219                /* Support TILE-specific ptrace options. */
 220                BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK);
 221                tmp = data & PTRACE_O_MASK_TILE;
 222                data &= ~PTRACE_O_MASK_TILE;
 223                ret = ptrace_request(child, request, addr, data);
 224                if (ret == 0) {
 225                        unsigned int flags = child->ptrace;
 226                        flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT);
 227                        flags |= (tmp << PT_OPT_FLAG_SHIFT);
 228                        child->ptrace = flags;
 229                }
 230                break;
 231
 232        default:
 233#ifdef CONFIG_COMPAT
 234                if (task_thread_info(current)->status & TS_COMPAT) {
 235                        ret = compat_ptrace_request(child, request,
 236                                                    addr, data);
 237                        break;
 238                }
 239#endif
 240                ret = ptrace_request(child, request, addr, data);
 241                break;
 242        }
 243
 244        return ret;
 245}
 246
 247#ifdef CONFIG_COMPAT
 248/* Not used; we handle compat issues in arch_ptrace() directly. */
 249long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 250                               compat_ulong_t addr, compat_ulong_t data)
 251{
 252        BUG();
 253}
 254#endif
 255
 256int do_syscall_trace_enter(struct pt_regs *regs)
 257{
 258        u32 work = ACCESS_ONCE(current_thread_info()->flags);
 259
 260        if ((work & _TIF_SYSCALL_TRACE) &&
 261            tracehook_report_syscall_entry(regs)) {
 262                regs->regs[TREG_SYSCALL_NR] = -1;
 263                return -1;
 264        }
 265
 266        if (secure_computing(NULL) == -1)
 267                return -1;
 268
 269        if (work & _TIF_SYSCALL_TRACEPOINT)
 270                trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]);
 271
 272        return regs->regs[TREG_SYSCALL_NR];
 273}
 274
 275void do_syscall_trace_exit(struct pt_regs *regs)
 276{
 277        long errno;
 278
 279        /*
 280         * The standard tile calling convention returns the value (or negative
 281         * errno) in r0, and zero (or positive errno) in r1.
 282         * It saves a couple of cycles on the hot path to do this work in
 283         * registers only as we return, rather than updating the in-memory
 284         * struct ptregs.
 285         */
 286        errno = (long) regs->regs[0];
 287        if (errno < 0 && errno > -4096)
 288                regs->regs[1] = -errno;
 289        else
 290                regs->regs[1] = 0;
 291
 292        if (test_thread_flag(TIF_SYSCALL_TRACE))
 293                tracehook_report_syscall_exit(regs, 0);
 294
 295        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 296                trace_sys_exit(regs, regs->regs[0]);
 297}
 298
 299void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs)
 300{
 301        struct siginfo info;
 302
 303        memset(&info, 0, sizeof(info));
 304        info.si_signo = SIGTRAP;
 305        info.si_code  = TRAP_BRKPT;
 306        info.si_addr  = (void __user *) regs->pc;
 307
 308        /* Send us the fakey SIGTRAP */
 309        force_sig_info(SIGTRAP, &info, tsk);
 310}
 311
 312/* Handle synthetic interrupt delivered only by the simulator. */
 313void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
 314{
 315        send_sigtrap(current, regs);
 316}
 317