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