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/mm.h>
  15#include <linux/smp.h>
  16#include <linux/smp_lock.h>
  17#include <linux/errno.h>
  18#include <linux/ptrace.h>
  19#include <linux/user.h>
  20#include <asm/uaccess.h>
  21#include <asm/pgtable.h>
  22#include <asm/system.h>
  23#include <asm/processor.h>
  24#include <asm/cacheflush.h>
  25#include <asm/fpu.h>
  26#include <asm/asm-offsets.h>
  27
  28/*
  29 * translate ptrace register IDs into struct pt_regs offsets
  30 */
  31static const u8 ptrace_regid_to_frame[] = {
  32        [PT_A3 << 2]            = REG_A3,
  33        [PT_A2 << 2]            = REG_A2,
  34        [PT_D3 << 2]            = REG_D3,
  35        [PT_D2 << 2]            = REG_D2,
  36        [PT_MCVF << 2]          = REG_MCVF,
  37        [PT_MCRL << 2]          = REG_MCRL,
  38        [PT_MCRH << 2]          = REG_MCRH,
  39        [PT_MDRQ << 2]          = REG_MDRQ,
  40        [PT_E1 << 2]            = REG_E1,
  41        [PT_E0 << 2]            = REG_E0,
  42        [PT_E7 << 2]            = REG_E7,
  43        [PT_E6 << 2]            = REG_E6,
  44        [PT_E5 << 2]            = REG_E5,
  45        [PT_E4 << 2]            = REG_E4,
  46        [PT_E3 << 2]            = REG_E3,
  47        [PT_E2 << 2]            = REG_E2,
  48        [PT_SP << 2]            = REG_SP,
  49        [PT_LAR << 2]           = REG_LAR,
  50        [PT_LIR << 2]           = REG_LIR,
  51        [PT_MDR << 2]           = REG_MDR,
  52        [PT_A1 << 2]            = REG_A1,
  53        [PT_A0 << 2]            = REG_A0,
  54        [PT_D1 << 2]            = REG_D1,
  55        [PT_D0 << 2]            = REG_D0,
  56        [PT_ORIG_D0 << 2]       = REG_ORIG_D0,
  57        [PT_EPSW << 2]          = REG_EPSW,
  58        [PT_PC << 2]            = REG_PC,
  59};
  60
  61static inline int get_stack_long(struct task_struct *task, int offset)
  62{
  63        return *(unsigned long *)
  64                ((unsigned long) task->thread.uregs + offset);
  65}
  66
  67/*
  68 * this routine will put a word on the processes privileged stack.
  69 * the offset is how far from the base addr as stored in the TSS.
  70 * this routine assumes that all the privileged stacks are in our
  71 * data space.
  72 */
  73static inline
  74int put_stack_long(struct task_struct *task, int offset, unsigned long data)
  75{
  76        unsigned long stack;
  77
  78        stack = (unsigned long) task->thread.uregs + offset;
  79        *(unsigned long *) stack = data;
  80        return 0;
  81}
  82
  83static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
  84                                       struct task_struct *tsk)
  85{
  86        return __copy_to_user(buf, &tsk->thread.fpu_state,
  87                              sizeof(struct fpu_state_struct));
  88}
  89
  90static inline unsigned long set_fpregs(struct task_struct *tsk,
  91                                       struct fpu_state_struct *buf)
  92{
  93        return __copy_from_user(&tsk->thread.fpu_state, buf,
  94                                sizeof(struct fpu_state_struct));
  95}
  96
  97static inline void fpsave_init(struct task_struct *task)
  98{
  99        memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
 100}
 101
 102/*
 103 * make sure the single step bit is not set
 104 */
 105void ptrace_disable(struct task_struct *child)
 106{
 107#ifndef CONFIG_MN10300_USING_JTAG
 108        struct user *dummy = NULL;
 109        long tmp;
 110
 111        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
 112        tmp &= ~EPSW_T;
 113        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 114#endif
 115}
 116
 117/*
 118 * set the single step bit
 119 */
 120void ptrace_enable(struct task_struct *child)
 121{
 122#ifndef CONFIG_MN10300_USING_JTAG
 123        struct user *dummy = NULL;
 124        long tmp;
 125
 126        tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
 127        tmp |= EPSW_T;
 128        put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
 129#endif
 130}
 131
 132/*
 133 * handle the arch-specific side of process tracing
 134 */
 135long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 136{
 137        struct fpu_state_struct fpu_state;
 138        int i, ret;
 139
 140        switch (request) {
 141        /* read the word at location addr. */
 142        case PTRACE_PEEKTEXT: {
 143                unsigned long tmp;
 144                int copied;
 145
 146                copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 147                ret = -EIO;
 148                if (copied != sizeof(tmp))
 149                        break;
 150                ret = put_user(tmp, (unsigned long *) data);
 151                break;
 152        }
 153
 154        /* read the word at location addr. */
 155        case PTRACE_PEEKDATA: {
 156                unsigned long tmp;
 157                int copied;
 158
 159                copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
 160                ret = -EIO;
 161                if (copied != sizeof(tmp))
 162                        break;
 163                ret = put_user(tmp, (unsigned long *) data);
 164                break;
 165        }
 166
 167        /* read the word at location addr in the USER area. */
 168        case PTRACE_PEEKUSR: {
 169                unsigned long tmp;
 170
 171                ret = -EIO;
 172                if ((addr & 3) || addr < 0 ||
 173                    addr > sizeof(struct user) - 3)
 174                        break;
 175
 176                tmp = 0;  /* Default return condition */
 177                if (addr < NR_PTREGS << 2)
 178                        tmp = get_stack_long(child,
 179                                             ptrace_regid_to_frame[addr]);
 180                ret = put_user(tmp, (unsigned long *) data);
 181                break;
 182        }
 183
 184        /* write the word at location addr. */
 185        case PTRACE_POKETEXT:
 186        case PTRACE_POKEDATA:
 187                if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
 188                    sizeof(data))
 189                        ret = 0;
 190                else
 191                        ret = -EIO;
 192                break;
 193
 194                /* write the word at location addr in the USER area */
 195        case PTRACE_POKEUSR:
 196                ret = -EIO;
 197                if ((addr & 3) || addr < 0 ||
 198                    addr > sizeof(struct user) - 3)
 199                        break;
 200
 201                ret = 0;
 202                if (addr < NR_PTREGS << 2)
 203                        ret = put_stack_long(child, ptrace_regid_to_frame[addr],
 204                                             data);
 205                break;
 206
 207                /* continue and stop at next (return from) syscall */
 208        case PTRACE_SYSCALL:
 209                /* restart after signal. */
 210        case PTRACE_CONT:
 211                ret = -EIO;
 212                if ((unsigned long) data > _NSIG)
 213                        break;
 214                if (request == PTRACE_SYSCALL)
 215                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 216                else
 217                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 218                child->exit_code = data;
 219                ptrace_disable(child);
 220                wake_up_process(child);
 221                ret = 0;
 222                break;
 223
 224                /*
 225                 * make the child exit
 226                 * - the best I can do is send it a sigkill
 227                 * - perhaps it should be put in the status that it wants to
 228                 *   exit
 229                 */
 230        case PTRACE_KILL:
 231                ret = 0;
 232                if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
 233                        break;
 234                child->exit_code = SIGKILL;
 235                clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 236                ptrace_disable(child);
 237                wake_up_process(child);
 238                break;
 239
 240        case PTRACE_SINGLESTEP: /* set the trap flag. */
 241#ifndef CONFIG_MN10300_USING_JTAG
 242                ret = -EIO;
 243                if ((unsigned long) data > _NSIG)
 244                        break;
 245                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 246                ptrace_enable(child);
 247                child->exit_code = data;
 248                wake_up_process(child);
 249                ret = 0;
 250#else
 251                ret = -EINVAL;
 252#endif
 253                break;
 254
 255        case PTRACE_DETACH:     /* detach a process that was attached. */
 256                ret = ptrace_detach(child, data);
 257                break;
 258
 259                /* Get all gp regs from the child. */
 260        case PTRACE_GETREGS: {
 261                unsigned long tmp;
 262
 263                if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
 264                        ret = -EIO;
 265                        break;
 266                }
 267
 268                for (i = 0; i < NR_PTREGS << 2; i += 4) {
 269                        tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
 270                        __put_user(tmp, (unsigned long *) data);
 271                        data += sizeof(tmp);
 272                }
 273                ret = 0;
 274                break;
 275        }
 276
 277        case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 278                unsigned long tmp;
 279
 280                if (!access_ok(VERIFY_READ, (unsigned long *)data,
 281                               sizeof(struct pt_regs))) {
 282                        ret = -EIO;
 283                        break;
 284                }
 285
 286                for (i = 0; i < NR_PTREGS << 2; i += 4) {
 287                        __get_user(tmp, (unsigned long *) data);
 288                        put_stack_long(child, ptrace_regid_to_frame[i], tmp);
 289                        data += sizeof(tmp);
 290                }
 291                ret = 0;
 292                break;
 293        }
 294
 295        case PTRACE_GETFPREGS: { /* Get the child FPU state. */
 296                if (is_using_fpu(child)) {
 297                        unlazy_fpu(child);
 298                        fpu_state = child->thread.fpu_state;
 299                } else {
 300                        memset(&fpu_state, 0, sizeof(fpu_state));
 301                }
 302
 303                ret = -EIO;
 304                if (copy_to_user((void *) data, &fpu_state,
 305                                 sizeof(fpu_state)) == 0)
 306                        ret = 0;
 307                break;
 308        }
 309
 310        case PTRACE_SETFPREGS: { /* Set the child FPU state. */
 311                ret = -EFAULT;
 312                if (copy_from_user(&fpu_state, (const void *) data,
 313                                   sizeof(fpu_state)) == 0) {
 314                        fpu_kill_state(child);
 315                        child->thread.fpu_state = fpu_state;
 316                        set_using_fpu(child);
 317                        ret = 0;
 318                }
 319                break;
 320        }
 321
 322        case PTRACE_SETOPTIONS: {
 323                if (data & PTRACE_O_TRACESYSGOOD)
 324                        child->ptrace |= PT_TRACESYSGOOD;
 325                else
 326                        child->ptrace &= ~PT_TRACESYSGOOD;
 327                ret = 0;
 328                break;
 329        }
 330
 331        default:
 332                ret = -EIO;
 333                break;
 334        }
 335
 336        return ret;
 337}
 338
 339/*
 340 * notification of system call entry/exit
 341 * - triggered by current->work.syscall_trace
 342 */
 343asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 344{
 345#if 0
 346        /* just in case... */
 347        printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
 348               current->pid,
 349               regs->orig_d0,
 350               regs->a0,
 351               regs->d1,
 352               regs->a3,
 353               regs->a2,
 354               regs->d0);
 355        return;
 356#endif
 357
 358        if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
 359            !test_thread_flag(TIF_SINGLESTEP))
 360                return;
 361        if (!(current->ptrace & PT_PTRACED))
 362                return;
 363
 364        /* the 0x80 provides a way for the tracing parent to distinguish
 365           between a syscall stop and SIGTRAP delivery */
 366        ptrace_notify(SIGTRAP |
 367                      ((current->ptrace & PT_TRACESYSGOOD) &&
 368                       !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
 369
 370        /*
 371         * this isn't the same as continuing with a signal, but it will do
 372         * for normal use.  strace only continues with a signal if the
 373         * stopping signal is not SIGTRAP.  -brl
 374         */
 375        if (current->exit_code) {
 376                send_sig(current->exit_code, current, 1);
 377                current->exit_code = 0;
 378        }
 379}
 380