linux/arch/arc/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/ptrace.h>
  10#include <linux/tracehook.h>
  11#include <linux/sched/task_stack.h>
  12#include <linux/regset.h>
  13#include <linux/unistd.h>
  14#include <linux/elf.h>
  15
  16static struct callee_regs *task_callee_regs(struct task_struct *tsk)
  17{
  18        struct callee_regs *tmp = (struct callee_regs *)tsk->thread.callee_reg;
  19        return tmp;
  20}
  21
  22static int genregs_get(struct task_struct *target,
  23                       const struct user_regset *regset,
  24                       unsigned int pos, unsigned int count,
  25                       void *kbuf, void __user *ubuf)
  26{
  27        const struct pt_regs *ptregs = task_pt_regs(target);
  28        const struct callee_regs *cregs = task_callee_regs(target);
  29        int ret = 0;
  30        unsigned int stop_pc_val;
  31
  32#define REG_O_CHUNK(START, END, PTR)    \
  33        if (!ret)       \
  34                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
  35                        offsetof(struct user_regs_struct, START), \
  36                        offsetof(struct user_regs_struct, END));
  37
  38#define REG_O_ONE(LOC, PTR)     \
  39        if (!ret)               \
  40                ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
  41                        offsetof(struct user_regs_struct, LOC), \
  42                        offsetof(struct user_regs_struct, LOC) + 4);
  43
  44#define REG_O_ZERO(LOC)         \
  45        if (!ret)               \
  46                ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
  47                        offsetof(struct user_regs_struct, LOC), \
  48                        offsetof(struct user_regs_struct, LOC) + 4);
  49
  50        REG_O_ZERO(pad);
  51        REG_O_ONE(scratch.bta, &ptregs->bta);
  52        REG_O_ONE(scratch.lp_start, &ptregs->lp_start);
  53        REG_O_ONE(scratch.lp_end, &ptregs->lp_end);
  54        REG_O_ONE(scratch.lp_count, &ptregs->lp_count);
  55        REG_O_ONE(scratch.status32, &ptregs->status32);
  56        REG_O_ONE(scratch.ret, &ptregs->ret);
  57        REG_O_ONE(scratch.blink, &ptregs->blink);
  58        REG_O_ONE(scratch.fp, &ptregs->fp);
  59        REG_O_ONE(scratch.gp, &ptregs->r26);
  60        REG_O_ONE(scratch.r12, &ptregs->r12);
  61        REG_O_ONE(scratch.r11, &ptregs->r11);
  62        REG_O_ONE(scratch.r10, &ptregs->r10);
  63        REG_O_ONE(scratch.r9, &ptregs->r9);
  64        REG_O_ONE(scratch.r8, &ptregs->r8);
  65        REG_O_ONE(scratch.r7, &ptregs->r7);
  66        REG_O_ONE(scratch.r6, &ptregs->r6);
  67        REG_O_ONE(scratch.r5, &ptregs->r5);
  68        REG_O_ONE(scratch.r4, &ptregs->r4);
  69        REG_O_ONE(scratch.r3, &ptregs->r3);
  70        REG_O_ONE(scratch.r2, &ptregs->r2);
  71        REG_O_ONE(scratch.r1, &ptregs->r1);
  72        REG_O_ONE(scratch.r0, &ptregs->r0);
  73        REG_O_ONE(scratch.sp, &ptregs->sp);
  74
  75        REG_O_ZERO(pad2);
  76
  77        REG_O_ONE(callee.r25, &cregs->r25);
  78        REG_O_ONE(callee.r24, &cregs->r24);
  79        REG_O_ONE(callee.r23, &cregs->r23);
  80        REG_O_ONE(callee.r22, &cregs->r22);
  81        REG_O_ONE(callee.r21, &cregs->r21);
  82        REG_O_ONE(callee.r20, &cregs->r20);
  83        REG_O_ONE(callee.r19, &cregs->r19);
  84        REG_O_ONE(callee.r18, &cregs->r18);
  85        REG_O_ONE(callee.r17, &cregs->r17);
  86        REG_O_ONE(callee.r16, &cregs->r16);
  87        REG_O_ONE(callee.r15, &cregs->r15);
  88        REG_O_ONE(callee.r14, &cregs->r14);
  89        REG_O_ONE(callee.r13, &cregs->r13);
  90
  91        REG_O_ONE(efa, &target->thread.fault_address);
  92
  93        if (!ret) {
  94                if (in_brkpt_trap(ptregs)) {
  95                        stop_pc_val = target->thread.fault_address;
  96                        pr_debug("\t\tstop_pc (brk-pt)\n");
  97                } else {
  98                        stop_pc_val = ptregs->ret;
  99                        pr_debug("\t\tstop_pc (others)\n");
 100                }
 101
 102                REG_O_ONE(stop_pc, &stop_pc_val);
 103        }
 104
 105        return ret;
 106}
 107
 108static int genregs_set(struct task_struct *target,
 109                       const struct user_regset *regset,
 110                       unsigned int pos, unsigned int count,
 111                       const void *kbuf, const void __user *ubuf)
 112{
 113        const struct pt_regs *ptregs = task_pt_regs(target);
 114        const struct callee_regs *cregs = task_callee_regs(target);
 115        int ret = 0;
 116
 117#define REG_IN_CHUNK(FIRST, NEXT, PTR)  \
 118        if (!ret)                       \
 119                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
 120                        (void *)(PTR), \
 121                        offsetof(struct user_regs_struct, FIRST), \
 122                        offsetof(struct user_regs_struct, NEXT));
 123
 124#define REG_IN_ONE(LOC, PTR)            \
 125        if (!ret)                       \
 126                ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
 127                        (void *)(PTR), \
 128                        offsetof(struct user_regs_struct, LOC), \
 129                        offsetof(struct user_regs_struct, LOC) + 4);
 130
 131#define REG_IGNORE_ONE(LOC)             \
 132        if (!ret)                       \
 133                ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
 134                        offsetof(struct user_regs_struct, LOC), \
 135                        offsetof(struct user_regs_struct, LOC) + 4);
 136
 137        REG_IGNORE_ONE(pad);
 138
 139        REG_IN_ONE(scratch.bta, &ptregs->bta);
 140        REG_IN_ONE(scratch.lp_start, &ptregs->lp_start);
 141        REG_IN_ONE(scratch.lp_end, &ptregs->lp_end);
 142        REG_IN_ONE(scratch.lp_count, &ptregs->lp_count);
 143
 144        REG_IGNORE_ONE(scratch.status32);
 145
 146        REG_IN_ONE(scratch.ret, &ptregs->ret);
 147        REG_IN_ONE(scratch.blink, &ptregs->blink);
 148        REG_IN_ONE(scratch.fp, &ptregs->fp);
 149        REG_IN_ONE(scratch.gp, &ptregs->r26);
 150        REG_IN_ONE(scratch.r12, &ptregs->r12);
 151        REG_IN_ONE(scratch.r11, &ptregs->r11);
 152        REG_IN_ONE(scratch.r10, &ptregs->r10);
 153        REG_IN_ONE(scratch.r9, &ptregs->r9);
 154        REG_IN_ONE(scratch.r8, &ptregs->r8);
 155        REG_IN_ONE(scratch.r7, &ptregs->r7);
 156        REG_IN_ONE(scratch.r6, &ptregs->r6);
 157        REG_IN_ONE(scratch.r5, &ptregs->r5);
 158        REG_IN_ONE(scratch.r4, &ptregs->r4);
 159        REG_IN_ONE(scratch.r3, &ptregs->r3);
 160        REG_IN_ONE(scratch.r2, &ptregs->r2);
 161        REG_IN_ONE(scratch.r1, &ptregs->r1);
 162        REG_IN_ONE(scratch.r0, &ptregs->r0);
 163        REG_IN_ONE(scratch.sp, &ptregs->sp);
 164
 165        REG_IGNORE_ONE(pad2);
 166
 167        REG_IN_ONE(callee.r25, &cregs->r25);
 168        REG_IN_ONE(callee.r24, &cregs->r24);
 169        REG_IN_ONE(callee.r23, &cregs->r23);
 170        REG_IN_ONE(callee.r22, &cregs->r22);
 171        REG_IN_ONE(callee.r21, &cregs->r21);
 172        REG_IN_ONE(callee.r20, &cregs->r20);
 173        REG_IN_ONE(callee.r19, &cregs->r19);
 174        REG_IN_ONE(callee.r18, &cregs->r18);
 175        REG_IN_ONE(callee.r17, &cregs->r17);
 176        REG_IN_ONE(callee.r16, &cregs->r16);
 177        REG_IN_ONE(callee.r15, &cregs->r15);
 178        REG_IN_ONE(callee.r14, &cregs->r14);
 179        REG_IN_ONE(callee.r13, &cregs->r13);
 180
 181        REG_IGNORE_ONE(efa);                    /* efa update invalid */
 182        REG_IGNORE_ONE(stop_pc);                /* PC updated via @ret */
 183
 184        return ret;
 185}
 186
 187#ifdef CONFIG_ISA_ARCV2
 188static int arcv2regs_get(struct task_struct *target,
 189                       const struct user_regset *regset,
 190                       unsigned int pos, unsigned int count,
 191                       void *kbuf, void __user *ubuf)
 192{
 193        const struct pt_regs *regs = task_pt_regs(target);
 194        int ret, copy_sz;
 195
 196        if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS))
 197                copy_sz = sizeof(struct user_regs_arcv2);
 198        else
 199                copy_sz = 4;    /* r30 only */
 200
 201        /*
 202         * itemized copy not needed like above as layout of regs (r30,r58,r59)
 203         * is exactly same in kernel (pt_regs) and userspace (user_regs_arcv2)
 204         */
 205        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs->r30,
 206                                  0, copy_sz);
 207
 208        return ret;
 209}
 210
 211static int arcv2regs_set(struct task_struct *target,
 212                       const struct user_regset *regset,
 213                       unsigned int pos, unsigned int count,
 214                       const void *kbuf, const void __user *ubuf)
 215{
 216        const struct pt_regs *regs = task_pt_regs(target);
 217        int ret, copy_sz;
 218
 219        if (IS_ENABLED(CONFIG_ARC_HAS_ACCL_REGS))
 220                copy_sz = sizeof(struct user_regs_arcv2);
 221        else
 222                copy_sz = 4;    /* r30 only */
 223
 224        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, (void *)&regs->r30,
 225                                  0, copy_sz);
 226
 227        return ret;
 228}
 229
 230#endif
 231
 232enum arc_getset {
 233        REGSET_CMN,
 234        REGSET_ARCV2,
 235};
 236
 237static const struct user_regset arc_regsets[] = {
 238        [REGSET_CMN] = {
 239               .core_note_type = NT_PRSTATUS,
 240               .n = ELF_NGREG,
 241               .size = sizeof(unsigned long),
 242               .align = sizeof(unsigned long),
 243               .get = genregs_get,
 244               .set = genregs_set,
 245        },
 246#ifdef CONFIG_ISA_ARCV2
 247        [REGSET_ARCV2] = {
 248               .core_note_type = NT_ARC_V2,
 249               .n = ELF_ARCV2REG,
 250               .size = sizeof(unsigned long),
 251               .align = sizeof(unsigned long),
 252               .get = arcv2regs_get,
 253               .set = arcv2regs_set,
 254        },
 255#endif
 256};
 257
 258static const struct user_regset_view user_arc_view = {
 259        .name           = UTS_MACHINE,
 260        .e_machine      = EM_ARC_INUSE,
 261        .regsets        = arc_regsets,
 262        .n              = ARRAY_SIZE(arc_regsets)
 263};
 264
 265const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 266{
 267        return &user_arc_view;
 268}
 269
 270void ptrace_disable(struct task_struct *child)
 271{
 272}
 273
 274long arch_ptrace(struct task_struct *child, long request,
 275                 unsigned long addr, unsigned long data)
 276{
 277        int ret = -EIO;
 278
 279        pr_debug("REQ=%ld: ADDR =0x%lx, DATA=0x%lx)\n", request, addr, data);
 280
 281        switch (request) {
 282        case PTRACE_GET_THREAD_AREA:
 283                ret = put_user(task_thread_info(child)->thr_ptr,
 284                               (unsigned long __user *)data);
 285                break;
 286        default:
 287                ret = ptrace_request(child, request, addr, data);
 288                break;
 289        }
 290
 291        return ret;
 292}
 293
 294asmlinkage int syscall_trace_entry(struct pt_regs *regs)
 295{
 296        if (tracehook_report_syscall_entry(regs))
 297                return ULONG_MAX;
 298
 299        return regs->r8;
 300}
 301
 302asmlinkage void syscall_trace_exit(struct pt_regs *regs)
 303{
 304        tracehook_report_syscall_exit(regs, 0);
 305}
 306