root/arch/m68k/kernel/ptrace.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_reg
  2. put_reg
  3. singlestep_disable
  4. ptrace_disable
  5. user_enable_single_step
  6. user_enable_block_step
  7. user_disable_single_step
  8. arch_ptrace
  9. syscall_trace
  10. syscall_trace_enter
  11. syscall_trace_leave

   1 /*
   2  *  linux/arch/m68k/kernel/ptrace.c
   3  *
   4  *  Copyright (C) 1994 by Hamish Macdonald
   5  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
   6  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
   7  *
   8  * This file is subject to the terms and conditions of the GNU General
   9  * Public License.  See the file COPYING in the main directory of
  10  * this archive for more details.
  11  */
  12 
  13 #include <linux/kernel.h>
  14 #include <linux/sched.h>
  15 #include <linux/sched/task_stack.h>
  16 #include <linux/mm.h>
  17 #include <linux/smp.h>
  18 #include <linux/errno.h>
  19 #include <linux/ptrace.h>
  20 #include <linux/user.h>
  21 #include <linux/signal.h>
  22 #include <linux/tracehook.h>
  23 
  24 #include <linux/uaccess.h>
  25 #include <asm/page.h>
  26 #include <asm/pgtable.h>
  27 #include <asm/processor.h>
  28 
  29 /*
  30  * does not yet catch signals sent when the child dies.
  31  * in exit.c or in signal.c.
  32  */
  33 
  34 /* determines which bits in the SR the user has access to. */
  35 /* 1 = access 0 = no access */
  36 #define SR_MASK 0x001f
  37 
  38 /* sets the trace bits. */
  39 #define TRACE_BITS 0xC000
  40 #define T1_BIT 0x8000
  41 #define T0_BIT 0x4000
  42 
  43 /* Find the stack offset for a register, relative to thread.esp0. */
  44 #define PT_REG(reg)     ((long)&((struct pt_regs *)0)->reg)
  45 #define SW_REG(reg)     ((long)&((struct switch_stack *)0)->reg \
  46                          - sizeof(struct switch_stack))
  47 /* Mapping from PT_xxx to the stack offset at which the register is
  48    saved.  Notice that usp has no stack-slot and needs to be treated
  49    specially (see get_reg/put_reg below). */
  50 static const int regoff[] = {
  51         [0]     = PT_REG(d1),
  52         [1]     = PT_REG(d2),
  53         [2]     = PT_REG(d3),
  54         [3]     = PT_REG(d4),
  55         [4]     = PT_REG(d5),
  56         [5]     = SW_REG(d6),
  57         [6]     = SW_REG(d7),
  58         [7]     = PT_REG(a0),
  59         [8]     = PT_REG(a1),
  60         [9]     = PT_REG(a2),
  61         [10]    = SW_REG(a3),
  62         [11]    = SW_REG(a4),
  63         [12]    = SW_REG(a5),
  64         [13]    = SW_REG(a6),
  65         [14]    = PT_REG(d0),
  66         [15]    = -1,
  67         [16]    = PT_REG(orig_d0),
  68         [17]    = PT_REG(sr),
  69         [18]    = PT_REG(pc),
  70 };
  71 
  72 /*
  73  * Get contents of register REGNO in task TASK.
  74  */
  75 static inline long get_reg(struct task_struct *task, int regno)
  76 {
  77         unsigned long *addr;
  78 
  79         if (regno == PT_USP)
  80                 addr = &task->thread.usp;
  81         else if (regno < ARRAY_SIZE(regoff))
  82                 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
  83         else
  84                 return 0;
  85         /* Need to take stkadj into account. */
  86         if (regno == PT_SR || regno == PT_PC) {
  87                 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
  88                 addr = (unsigned long *) ((unsigned long)addr + stkadj);
  89                 /* The sr is actually a 16 bit register.  */
  90                 if (regno == PT_SR)
  91                         return *(unsigned short *)addr;
  92         }
  93         return *addr;
  94 }
  95 
  96 /*
  97  * Write contents of register REGNO in task TASK.
  98  */
  99 static inline int put_reg(struct task_struct *task, int regno,
 100                           unsigned long data)
 101 {
 102         unsigned long *addr;
 103 
 104         if (regno == PT_USP)
 105                 addr = &task->thread.usp;
 106         else if (regno < ARRAY_SIZE(regoff))
 107                 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
 108         else
 109                 return -1;
 110         /* Need to take stkadj into account. */
 111         if (regno == PT_SR || regno == PT_PC) {
 112                 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
 113                 addr = (unsigned long *) ((unsigned long)addr + stkadj);
 114                 /* The sr is actually a 16 bit register.  */
 115                 if (regno == PT_SR) {
 116                         *(unsigned short *)addr = data;
 117                         return 0;
 118                 }
 119         }
 120         *addr = data;
 121         return 0;
 122 }
 123 
 124 /*
 125  * Make sure the single step bit is not set.
 126  */
 127 static inline void singlestep_disable(struct task_struct *child)
 128 {
 129         unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
 130         put_reg(child, PT_SR, tmp);
 131         clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
 132 }
 133 
 134 /*
 135  * Called by kernel/ptrace.c when detaching..
 136  */
 137 void ptrace_disable(struct task_struct *child)
 138 {
 139         singlestep_disable(child);
 140 }
 141 
 142 void user_enable_single_step(struct task_struct *child)
 143 {
 144         unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
 145         put_reg(child, PT_SR, tmp | T1_BIT);
 146         set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
 147 }
 148 
 149 #ifdef CONFIG_MMU
 150 void user_enable_block_step(struct task_struct *child)
 151 {
 152         unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
 153         put_reg(child, PT_SR, tmp | T0_BIT);
 154 }
 155 #endif
 156 
 157 void user_disable_single_step(struct task_struct *child)
 158 {
 159         singlestep_disable(child);
 160 }
 161 
 162 long arch_ptrace(struct task_struct *child, long request,
 163                  unsigned long addr, unsigned long data)
 164 {
 165         unsigned long tmp;
 166         int i, ret = 0;
 167         int regno = addr >> 2; /* temporary hack. */
 168         unsigned long __user *datap = (unsigned long __user *) data;
 169 
 170         switch (request) {
 171         /* read the word at location addr in the USER area. */
 172         case PTRACE_PEEKUSR:
 173                 if (addr & 3)
 174                         goto out_eio;
 175 
 176                 if (regno >= 0 && regno < 19) {
 177                         tmp = get_reg(child, regno);
 178                 } else if (regno >= 21 && regno < 49) {
 179                         tmp = child->thread.fp[regno - 21];
 180                         /* Convert internal fpu reg representation
 181                          * into long double format
 182                          */
 183                         if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
 184                                 tmp = ((tmp & 0xffff0000) << 15) |
 185                                       ((tmp & 0x0000ffff) << 16);
 186 #ifndef CONFIG_MMU
 187                 } else if (regno == 49) {
 188                         tmp = child->mm->start_code;
 189                 } else if (regno == 50) {
 190                         tmp = child->mm->start_data;
 191                 } else if (regno == 51) {
 192                         tmp = child->mm->end_code;
 193 #endif
 194                 } else
 195                         goto out_eio;
 196                 ret = put_user(tmp, datap);
 197                 break;
 198 
 199         case PTRACE_POKEUSR:
 200         /* write the word at location addr in the USER area */
 201                 if (addr & 3)
 202                         goto out_eio;
 203 
 204                 if (regno == PT_SR) {
 205                         data &= SR_MASK;
 206                         data |= get_reg(child, PT_SR) & ~SR_MASK;
 207                 }
 208                 if (regno >= 0 && regno < 19) {
 209                         if (put_reg(child, regno, data))
 210                                 goto out_eio;
 211                 } else if (regno >= 21 && regno < 48) {
 212                         /* Convert long double format
 213                          * into internal fpu reg representation
 214                          */
 215                         if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
 216                                 data <<= 15;
 217                                 data = (data & 0xffff0000) |
 218                                        ((data & 0x0000ffff) >> 1);
 219                         }
 220                         child->thread.fp[regno - 21] = data;
 221                 } else
 222                         goto out_eio;
 223                 break;
 224 
 225         case PTRACE_GETREGS:    /* Get all gp regs from the child. */
 226                 for (i = 0; i < 19; i++) {
 227                         tmp = get_reg(child, i);
 228                         ret = put_user(tmp, datap);
 229                         if (ret)
 230                                 break;
 231                         datap++;
 232                 }
 233                 break;
 234 
 235         case PTRACE_SETREGS:    /* Set all gp regs in the child. */
 236                 for (i = 0; i < 19; i++) {
 237                         ret = get_user(tmp, datap);
 238                         if (ret)
 239                                 break;
 240                         if (i == PT_SR) {
 241                                 tmp &= SR_MASK;
 242                                 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
 243                         }
 244                         put_reg(child, i, tmp);
 245                         datap++;
 246                 }
 247                 break;
 248 
 249         case PTRACE_GETFPREGS:  /* Get the child FPU state. */
 250                 if (copy_to_user(datap, &child->thread.fp,
 251                                  sizeof(struct user_m68kfp_struct)))
 252                         ret = -EFAULT;
 253                 break;
 254 
 255         case PTRACE_SETFPREGS:  /* Set the child FPU state. */
 256                 if (copy_from_user(&child->thread.fp, datap,
 257                                    sizeof(struct user_m68kfp_struct)))
 258                         ret = -EFAULT;
 259                 break;
 260 
 261         case PTRACE_GET_THREAD_AREA:
 262                 ret = put_user(task_thread_info(child)->tp_value, datap);
 263                 break;
 264 
 265         default:
 266                 ret = ptrace_request(child, request, addr, data);
 267                 break;
 268         }
 269 
 270         return ret;
 271 out_eio:
 272         return -EIO;
 273 }
 274 
 275 asmlinkage void syscall_trace(void)
 276 {
 277         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 278                                  ? 0x80 : 0));
 279         /*
 280          * this isn't the same as continuing with a signal, but it will do
 281          * for normal use.  strace only continues with a signal if the
 282          * stopping signal is not SIGTRAP.  -brl
 283          */
 284         if (current->exit_code) {
 285                 send_sig(current->exit_code, current, 1);
 286                 current->exit_code = 0;
 287         }
 288 }
 289 
 290 #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU)
 291 asmlinkage int syscall_trace_enter(void)
 292 {
 293         int ret = 0;
 294 
 295         if (test_thread_flag(TIF_SYSCALL_TRACE))
 296                 ret = tracehook_report_syscall_entry(task_pt_regs(current));
 297         return ret;
 298 }
 299 
 300 asmlinkage void syscall_trace_leave(void)
 301 {
 302         if (test_thread_flag(TIF_SYSCALL_TRACE))
 303                 tracehook_report_syscall_exit(task_pt_regs(current), 0);
 304 }
 305 #endif /* CONFIG_COLDFIRE */

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