linux/arch/mn10300/kernel/ptrace.c
<<
>>
Prefs
   1/* MN10300 Process tracing
   2 *
   3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
   4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   5 * Modified by David Howells (dhowells@redhat.com)
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public Licence
   9 * as published by the Free Software Foundation; either version
  10 * 2 of the Licence, or (at your option) any later version.
  11 */
  12#include <linux/kernel.h>
  13#include <linux/sched.h>
  14#include <linux/sched/task_stack.h>
  15#include <linux/mm.h>
  16#include <linux/smp.h>
  17#include <linux/errno.h>
  18#include <linux/ptrace.h>
  19#include <linux/user.h>
  20#include <linux/regset.h>
  21#include <linux/elf.h>
  22#include <linux/tracehook.h>
  23#include <linux/uaccess.h>
  24#include <asm/pgtable.h>
  25#include <asm/processor.h>
  26#include <asm/cacheflush.h>
  27#include <asm/fpu.h>
  28#include <asm/asm-offsets.h>
  29
  30/*
  31 * translate ptrace register IDs into struct pt_regs offsets
  32 */
  33static const u8 ptrace_regid_to_frame[] = {
  34        [PT_A3 << 2]            = REG_A3,
  35        [PT_A2 << 2]            = REG_A2,
  36        [PT_D3 << 2]            = REG_D3,
  37        [PT_D2 << 2]            = REG_D2,
  38        [PT_MCVF << 2]          = REG_MCVF,
  39        [PT_MCRL << 2]          = REG_MCRL,
  40        [PT_MCRH << 2]          = REG_MCRH,
  41        [PT_MDRQ << 2]          = REG_MDRQ,
  42        [PT_E1 << 2]            = REG_E1,
  43        [PT_E0 << 2]            = REG_E0,
  44        [PT_E7 << 2]            = REG_E7,
  45        [PT_E6 << 2]            = REG_E6,
  46        [PT_E5 << 2]            = REG_E5,
  47        [PT_E4 << 2]            = REG_E4,
  48        [PT_E3 << 2]            = REG_E3,
  49        [PT_E2 << 2]            = REG_E2,
  50        [PT_SP << 2]            = REG_SP,
  51        [PT_LAR << 2]           = REG_LAR,
  52        [PT_LIR << 2]           = REG_LIR,
  53        [PT_MDR << 2]           = REG_MDR,
  54        [PT_A1 << 2]            = REG_A1,
  55        [PT_A0 << 2]            = REG_A0,
  56        [PT_D1 << 2]            = REG_D1,
  57        [PT_D0 << 2]            = REG_D0,
  58        [PT_ORIG_D0 << 2]       = REG_ORIG_D0,
  59        [PT_EPSW << 2]          = REG_EPSW,
  60        [PT_PC << 2]            = REG_PC,
  61};
  62
  63static inline int get_stack_long(struct task_struct *task, int offset)
  64{
  65        return *(unsigned long *)
  66                ((unsigned long) task->thread.uregs + offset);
  67}
  68
  69static inline
  70int put_stack_long(struct task_struct *task, int offset, unsigned long data)
  71{
  72        unsigned long stack;
  73
  74        stack = (unsigned long) task->thread.uregs + offset;
  75        *(unsigned long *) stack = data;
  76        return 0;
  77}
  78
  79/*
  80 * retrieve the contents of MN10300 userspace general registers
  81 */
  82static int genregs_get(struct task_struct *target,
  83                       const struct user_regset *regset,
  84                       unsigned int pos, unsigned int count,
  85                       void *kbuf, void __user *ubuf)
  86{
  87        const struct pt_regs *regs = task_pt_regs(target);
  88        int ret;
  89
  90        /* we need to skip regs->next */
  91        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  92                                  regs, 0, PT_ORIG_D0 * sizeof(long));
  93        if (ret < 0)
  94                return ret;
  95
  96        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
  97                                  &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
  98                                  NR_PTREGS * sizeof(long));
  99        if (ret < 0)
 100                return ret;
 101
 102        return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 103                                        NR_PTREGS * sizeof(long), -1);
 104}
 105
 106/*
 107 * update the contents of the MN10300 userspace general registers
 108 */
 109static int genregs_set(struct task_struct *target,
 110                       const struct user_regset *regset,
 111                       unsigned int pos, unsigned int count,
 112                       const void *kbuf, const void __user *ubuf)
 113{
 114        struct pt_regs *regs = task_pt_regs(target);
 115        unsigned long tmp;
 116        int ret;
 117
 118        /* we need to skip regs->next */
 119        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 120                                 regs, 0, PT_ORIG_D0 * sizeof(long));
 121        if (ret < 0)
 122                return ret;
 123
 124        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 125                                 &regs->orig_d0, PT_ORIG_D0 * sizeof(long),
 126                                 PT_EPSW * sizeof(long));
 127        if (ret < 0)
 128                return ret;
 129
 130        /* we need to mask off changes to EPSW */
 131        tmp = regs->epsw;
 132        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 133                                 &tmp, PT_EPSW * sizeof(long),
 134                                 PT_PC * sizeof(long));
 135        tmp &= EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N | EPSW_FLAG_Z;
 136        tmp |= regs->epsw & ~(EPSW_FLAG_V | EPSW_FLAG_C | EPSW_FLAG_N |
 137                              EPSW_FLAG_Z);
 138        regs->epsw = tmp;
 139
 140        if (ret < 0)
 141                return ret;
 142
 143        /* and finally load the PC */
 144        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 145                                 &regs->pc, PT_PC * sizeof(long),
 146                                 NR_PTREGS * sizeof(long));
 147
 148        if (ret < 0)
 149                return ret;
 150
 151        return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 152                                         NR_PTREGS * sizeof(long), -1);
 153}
 154
 155/*
 156 * retrieve the contents of MN10300 userspace FPU registers
 157 */
 158static int fpuregs_get(struct task_struct *target,
 159                       const struct user_regset *regset,
 160                       unsigned int pos, unsigned int count,
 161                       void *kbuf, void __user *ubuf)
 162{
 163        const struct fpu_state_struct *fpregs = &target->thread.fpu_state;
 164        int ret;
 165
 166        unlazy_fpu(target);
 167
 168        ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
 169                                  fpregs, 0, sizeof(*fpregs));
 170        if (ret < 0)
 171                return ret;
 172
 173        return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
 174                                        sizeof(*fpregs), -1);
 175}
 176
 177/*
 178 * update the contents of the MN10300 userspace FPU registers
 179 */
 180static int fpuregs_set(struct task_struct *target,
 181                       const struct user_regset *regset,
 182                       unsigned int pos, unsigned int count,
 183                       const void *kbuf, const void __user *ubuf)
 184{
 185        struct fpu_state_struct fpu_state = target->thread.fpu_state;
 186        int ret;
 187
 188        ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
 189                                 &fpu_state, 0, sizeof(fpu_state));
 190        if (ret < 0)
 191                return ret;
 192
 193        fpu_kill_state(target);
 194        target->thread.fpu_state = fpu_state;
 195        set_using_fpu(target);
 196
 197        return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 198                                         sizeof(fpu_state), -1);
 199}
 200
 201/*
 202 * determine if the FPU registers have actually been used
 203 */
 204static int fpuregs_active(struct task_struct *target,
 205                          const struct user_regset *regset)
 206{
 207        return is_using_fpu(target) ? regset->n : 0;
 208}
 209
 210/*
 211 * Define the register sets available on the MN10300 under Linux
 212 */
 213enum mn10300_regset {
 214        REGSET_GENERAL,
 215        REGSET_FPU,
 216};
 217
 218static const struct user_regset mn10300_regsets[] = {
 219        /*
 220         * General register format is:
 221         *      A3, A2, D3, D2, MCVF, MCRL, MCRH, MDRQ
 222         *      E1, E0, E7...E2, SP, LAR, LIR, MDR
 223         *      A1, A0, D1, D0, ORIG_D0, EPSW, PC
 224         */
 225        [REGSET_GENERAL] = {
 226                .core_note_type = NT_PRSTATUS,
 227                .n              = ELF_NGREG,
 228                .size           = sizeof(long),
 229                .align          = sizeof(long),
 230                .get            = genregs_get,
 231                .set            = genregs_set,
 232        },
 233        /*
 234         * FPU register format is:
 235         *      FS0-31, FPCR
 236         */
 237        [REGSET_FPU] = {
 238                .core_note_type = NT_PRFPREG,
 239                .n              = sizeof(struct fpu_state_struct) / sizeof(long),
 240                .size           = sizeof(long),
 241                .align          = sizeof(long),
 242                .get            = fpuregs_get,
 243                .set            = fpuregs_set,
 244                .active         = fpuregs_active,
 245        },
 246};
 247
 248static const struct user_regset_view user_mn10300_native_view = {
 249        .name           = "mn10300",
 250        .e_machine      = EM_MN10300,
 251        .regsets        = mn10300_regsets,
 252        .n              = ARRAY_SIZE(mn10300_regsets),
 253};
 254
 255const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 256{
 257        return &user_mn10300_native_view;
 258}
 259
 260/*
 261 * set the single-step bit
 262 */
 263void user_enable_single_step(struct task_struct *child)
 264{
 265#ifndef CONFIG_MN10300_USING_JTAG
 266        struct user *dummy = NULL;
 267        long tmp;
 268
 269        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
 270        tmp |= EPSW_T;
 271        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 272#endif
 273}
 274
 275/*
 276 * make sure the single-step bit is not set
 277 */
 278void user_disable_single_step(struct task_struct *child)
 279{
 280#ifndef CONFIG_MN10300_USING_JTAG
 281        struct user *dummy = NULL;
 282        long tmp;
 283
 284        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
 285        tmp &= ~EPSW_T;
 286        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 287#endif
 288}
 289
 290void ptrace_disable(struct task_struct *child)
 291{
 292        user_disable_single_step(child);
 293}
 294
 295/*
 296 * handle the arch-specific side of process tracing
 297 */
 298long arch_ptrace(struct task_struct *child, long request,
 299                 unsigned long addr, unsigned long data)
 300{
 301        unsigned long tmp;
 302        int ret;
 303        unsigned long __user *datap = (unsigned long __user *) data;
 304
 305        switch (request) {
 306        /* read the word at location addr in the USER area. */
 307        case PTRACE_PEEKUSR:
 308                ret = -EIO;
 309                if ((addr & 3) || addr > sizeof(struct user) - 3)
 310                        break;
 311
 312                tmp = 0;  /* Default return condition */
 313                if (addr < NR_PTREGS << 2)
 314                        tmp = get_stack_long(child,
 315                                             ptrace_regid_to_frame[addr]);
 316                ret = put_user(tmp, datap);
 317                break;
 318
 319                /* write the word at location addr in the USER area */
 320        case PTRACE_POKEUSR:
 321                ret = -EIO;
 322                if ((addr & 3) || addr > sizeof(struct user) - 3)
 323                        break;
 324
 325                ret = 0;
 326                if (addr < NR_PTREGS << 2)
 327                        ret = put_stack_long(child, ptrace_regid_to_frame[addr],
 328                                             data);
 329                break;
 330
 331        case PTRACE_GETREGS:    /* Get all integer regs from the child. */
 332                return copy_regset_to_user(child, &user_mn10300_native_view,
 333                                           REGSET_GENERAL,
 334                                           0, NR_PTREGS * sizeof(long),
 335                                           datap);
 336
 337        case PTRACE_SETREGS:    /* Set all integer regs in the child. */
 338                return copy_regset_from_user(child, &user_mn10300_native_view,
 339                                             REGSET_GENERAL,
 340                                             0, NR_PTREGS * sizeof(long),
 341                                             datap);
 342
 343        case PTRACE_GETFPREGS:  /* Get the child FPU state. */
 344                return copy_regset_to_user(child, &user_mn10300_native_view,
 345                                           REGSET_FPU,
 346                                           0, sizeof(struct fpu_state_struct),
 347                                           datap);
 348
 349        case PTRACE_SETFPREGS:  /* Set the child FPU state. */
 350                return copy_regset_from_user(child, &user_mn10300_native_view,
 351                                             REGSET_FPU,
 352                                             0, sizeof(struct fpu_state_struct),
 353                                             datap);
 354
 355        default:
 356                ret = ptrace_request(child, request, addr, data);
 357                break;
 358        }
 359
 360        return ret;
 361}
 362
 363/*
 364 * handle tracing of system call entry
 365 * - return the revised system call number or ULONG_MAX to cause ENOSYS
 366 */
 367asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
 368{
 369        if (tracehook_report_syscall_entry(regs))
 370                /* tracing decided this syscall should not happen, so
 371                 * We'll return a bogus call number to get an ENOSYS
 372                 * error, but leave the original number in
 373                 * regs->orig_d0
 374                 */
 375                return ULONG_MAX;
 376
 377        return regs->orig_d0;
 378}
 379
 380/*
 381 * handle tracing of system call exit
 382 */
 383asmlinkage void syscall_trace_exit(struct pt_regs *regs)
 384{
 385        tracehook_report_syscall_exit(regs, 0);
 386}
 387