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