root/arch/arc/kernel/ptrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. task_callee_regs
  2. genregs_get
  3. genregs_set
  4. arcv2regs_get
  5. arcv2regs_set
  6. task_user_regset_view
  7. ptrace_disable
  8. arch_ptrace
  9. syscall_trace_entry
  10. syscall_trace_exit

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

/* [<][>][^][v][top][bottom][index][help] */