linux/arch/cris/arch-v10/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2000-2003, Axis Communications AB.
   3 */
   4
   5#include <linux/kernel.h>
   6#include <linux/sched.h>
   7#include <linux/mm.h>
   8#include <linux/smp.h>
   9#include <linux/errno.h>
  10#include <linux/ptrace.h>
  11#include <linux/user.h>
  12#include <linux/signal.h>
  13#include <linux/security.h>
  14
  15#include <asm/uaccess.h>
  16#include <asm/page.h>
  17#include <asm/pgtable.h>
  18#include <asm/processor.h>
  19
  20/* 
  21 * Determines which bits in DCCR the user has access to.
  22 * 1 = access, 0 = no access.
  23 */
  24#define DCCR_MASK 0x0000001f     /* XNZVC */
  25
  26/*
  27 * Get contents of register REGNO in task TASK.
  28 */
  29inline long get_reg(struct task_struct *task, unsigned int regno)
  30{
  31        /* USP is a special case, it's not in the pt_regs struct but
  32         * in the tasks thread struct
  33         */
  34
  35        if (regno == PT_USP)
  36                return task->thread.usp;
  37        else if (regno < PT_MAX)
  38                return ((unsigned long *)task_pt_regs(task))[regno];
  39        else
  40                return 0;
  41}
  42
  43/*
  44 * Write contents of register REGNO in task TASK.
  45 */
  46inline int put_reg(struct task_struct *task, unsigned int regno,
  47                          unsigned long data)
  48{
  49        if (regno == PT_USP)
  50                task->thread.usp = data;
  51        else if (regno < PT_MAX)
  52                ((unsigned long *)task_pt_regs(task))[regno] = data;
  53        else
  54                return -1;
  55        return 0;
  56}
  57
  58/*
  59 * Called by kernel/ptrace.c when detaching.
  60 *
  61 * Make sure the single step bit is not set.
  62 */
  63void 
  64ptrace_disable(struct task_struct *child)
  65{
  66       /* Todo - pending singlesteps? */
  67       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
  68}
  69
  70/* 
  71 * Note that this implementation of ptrace behaves differently from vanilla
  72 * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
  73 * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
  74 * ignored.  Instead, the data variable is expected to point at a location
  75 * (in user space) where the result of the ptrace call is written (instead of
  76 * being returned).
  77 */
  78long arch_ptrace(struct task_struct *child, long request,
  79                 unsigned long addr, unsigned long data)
  80{
  81        int ret;
  82        unsigned int regno = addr >> 2;
  83        unsigned long __user *datap = (unsigned long __user *)data;
  84
  85        switch (request) {
  86                /* Read word at location address. */ 
  87                case PTRACE_PEEKTEXT:
  88                case PTRACE_PEEKDATA:
  89                        ret = generic_ptrace_peekdata(child, addr, data);
  90                        break;
  91
  92                /* Read the word at location address in the USER area. */
  93                case PTRACE_PEEKUSR: {
  94                        unsigned long tmp;
  95
  96                        ret = -EIO;
  97                        if ((addr & 3) || regno > PT_MAX)
  98                                break;
  99
 100                        tmp = get_reg(child, regno);
 101                        ret = put_user(tmp, datap);
 102                        break;
 103                }
 104                
 105                /* Write the word at location address. */
 106                case PTRACE_POKETEXT:
 107                case PTRACE_POKEDATA:
 108                        ret = generic_ptrace_pokedata(child, addr, data);
 109                        break;
 110 
 111                /* Write the word at location address in the USER area. */
 112                case PTRACE_POKEUSR:
 113                        ret = -EIO;
 114                        if ((addr & 3) || regno > PT_MAX)
 115                                break;
 116
 117                        if (regno == PT_DCCR) {
 118                                /* don't allow the tracing process to change stuff like
 119                                 * interrupt enable, kernel/user bit, dma enables etc.
 120                                 */
 121                                data &= DCCR_MASK;
 122                                data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
 123                        }
 124                        if (put_reg(child, regno, data))
 125                                break;
 126                        ret = 0;
 127                        break;
 128
 129                /* Get all GP registers from the child. */
 130                case PTRACE_GETREGS: {
 131                        int i;
 132                        unsigned long tmp;
 133                        
 134                        ret = 0;
 135                        for (i = 0; i <= PT_MAX; i++) {
 136                                tmp = get_reg(child, i);
 137                                
 138                                if (put_user(tmp, datap)) {
 139                                        ret = -EFAULT;
 140                                        break;
 141                                }
 142                                
 143                                datap++;
 144                        }
 145
 146                        break;
 147                }
 148
 149                /* Set all GP registers in the child. */
 150                case PTRACE_SETREGS: {
 151                        int i;
 152                        unsigned long tmp;
 153                        
 154                        ret = 0;
 155                        for (i = 0; i <= PT_MAX; i++) {
 156                                if (get_user(tmp, datap)) {
 157                                        ret = -EFAULT;
 158                                        break;
 159                                }
 160                                
 161                                if (i == PT_DCCR) {
 162                                        tmp &= DCCR_MASK;
 163                                        tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
 164                                }
 165                                
 166                                put_reg(child, i, tmp);
 167                                datap++;
 168                        }
 169                        
 170                        break;
 171                }
 172
 173                default:
 174                        ret = ptrace_request(child, request, addr, data);
 175                        break;
 176        }
 177
 178        return ret;
 179}
 180
 181void do_syscall_trace(void)
 182{
 183        if (!test_thread_flag(TIF_SYSCALL_TRACE))
 184                return;
 185        
 186        if (!(current->ptrace & PT_PTRACED))
 187                return;
 188        
 189        /* the 0x80 provides a way for the tracing parent to distinguish
 190           between a syscall stop and SIGTRAP delivery */
 191        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 192                                 ? 0x80 : 0));
 193        
 194        /*
 195         * This isn't the same as continuing with a signal, but it will do for
 196         * normal use.
 197         */
 198        if (current->exit_code) {
 199                send_sig(current->exit_code, current, 1);
 200                current->exit_code = 0;
 201        }
 202}
 203