linux/arch/h8300/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/h8300/kernel/ptrace.c
   3 *
   4 *  Yoshinori Sato <ysato@users.sourceforge.jp>
   5 *
   6 *  Based on:
   7 *  linux/arch/m68k/kernel/ptrace.c
   8 *
   9 *  Copyright (C) 1994 by Hamish Macdonald
  10 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
  11 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
  12 *
  13 * This file is subject to the terms and conditions of the GNU General
  14 * Public License.  See the file COPYING in the main directory of
  15 * this archive for more details.
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/sched.h>
  20#include <linux/mm.h>
  21#include <linux/smp.h>
  22#include <linux/errno.h>
  23#include <linux/ptrace.h>
  24#include <linux/user.h>
  25#include <linux/signal.h>
  26
  27#include <asm/uaccess.h>
  28#include <asm/page.h>
  29#include <asm/pgtable.h>
  30#include <asm/system.h>
  31#include <asm/processor.h>
  32#include <asm/signal.h>
  33
  34/* cpu depend functions */
  35extern long h8300_get_reg(struct task_struct *task, int regno);
  36extern int  h8300_put_reg(struct task_struct *task, int regno, unsigned long data);
  37extern void h8300_disable_trace(struct task_struct *child);
  38extern void h8300_enable_trace(struct task_struct *child);
  39
  40/*
  41 * does not yet catch signals sent when the child dies.
  42 * in exit.c or in signal.c.
  43 */
  44
  45inline
  46static int read_long(struct task_struct * tsk, unsigned long addr,
  47        unsigned long * result)
  48{
  49        *result = *(unsigned long *)addr;
  50        return 0;
  51}
  52
  53void ptrace_disable(struct task_struct *child)
  54{
  55        h8300_disable_trace(child);
  56}
  57
  58long arch_ptrace(struct task_struct *child, long request, long addr, long data)
  59{
  60        int ret;
  61
  62        switch (request) {
  63                case PTRACE_PEEKTEXT: /* read word at location addr. */ 
  64                case PTRACE_PEEKDATA: {
  65                        unsigned long tmp;
  66
  67                        ret = read_long(child, addr, &tmp);
  68                        if (ret < 0)
  69                                break ;
  70                        ret = put_user(tmp, (unsigned long *) data);
  71                        break ;
  72                }
  73
  74        /* read the word at location addr in the USER area. */
  75                case PTRACE_PEEKUSR: {
  76                        unsigned long tmp = 0;
  77                        
  78                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
  79                                ret = -EIO;
  80                                break ;
  81                        }
  82                        
  83                        ret = 0;  /* Default return condition */
  84                        addr = addr >> 2; /* temporary hack. */
  85
  86                        if (addr < H8300_REGS_NO)
  87                                tmp = h8300_get_reg(child, addr);
  88                        else {
  89                                switch(addr) {
  90                                case 49:
  91                                        tmp = child->mm->start_code;
  92                                        break ;
  93                                case 50:
  94                                        tmp = child->mm->start_data;
  95                                        break ;
  96                                case 51:
  97                                        tmp = child->mm->end_code;
  98                                        break ;
  99                                case 52:
 100                                        tmp = child->mm->end_data;
 101                                        break ;
 102                                default:
 103                                        ret = -EIO;
 104                                }
 105                        }
 106                        if (!ret)
 107                                ret = put_user(tmp,(unsigned long *) data);
 108                        break ;
 109                }
 110
 111      /* when I and D space are separate, this will have to be fixed. */
 112                case PTRACE_POKETEXT: /* write the word at location addr. */
 113                case PTRACE_POKEDATA:
 114                        ret = generic_ptrace_pokedata(child, addr, data);
 115                        break;
 116
 117                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 118                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
 119                                ret = -EIO;
 120                                break ;
 121                        }
 122                        addr = addr >> 2; /* temporary hack. */
 123                            
 124                        if (addr == PT_ORIG_ER0) {
 125                                ret = -EIO;
 126                                break ;
 127                        }
 128                        if (addr < H8300_REGS_NO) {
 129                                ret = h8300_put_reg(child, addr, data);
 130                                break ;
 131                        }
 132                        ret = -EIO;
 133                        break ;
 134                case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
 135                case PTRACE_CONT: { /* restart after signal. */
 136                        ret = -EIO;
 137                        if (!valid_signal(data))
 138                                break ;
 139                        if (request == PTRACE_SYSCALL)
 140                                set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 141                        else
 142                                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 143                        child->exit_code = data;
 144                        wake_up_process(child);
 145                        /* make sure the single step bit is not set. */
 146                        h8300_disable_trace(child);
 147                        ret = 0;
 148                }
 149
 150/*
 151 * make the child exit.  Best I can do is send it a sigkill. 
 152 * perhaps it should be put in the status that it wants to 
 153 * exit.
 154 */
 155                case PTRACE_KILL: {
 156
 157                        ret = 0;
 158                        if (child->exit_state == EXIT_ZOMBIE) /* already dead */
 159                                break;
 160                        child->exit_code = SIGKILL;
 161                        h8300_disable_trace(child);
 162                        wake_up_process(child);
 163                        break;
 164                }
 165
 166                case PTRACE_SINGLESTEP: {  /* set the trap flag. */
 167                        ret = -EIO;
 168                        if (!valid_signal(data))
 169                                break;
 170                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 171                        child->exit_code = data;
 172                        h8300_enable_trace(child);
 173                        wake_up_process(child);
 174                        ret = 0;
 175                        break;
 176                }
 177
 178                case PTRACE_DETACH:     /* detach a process that was attached. */
 179                        ret = ptrace_detach(child, data);
 180                        break;
 181
 182                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
 183                        int i;
 184                        unsigned long tmp;
 185                        for (i = 0; i < H8300_REGS_NO; i++) {
 186                            tmp = h8300_get_reg(child, i);
 187                            if (put_user(tmp, (unsigned long *) data)) {
 188                                ret = -EFAULT;
 189                                break;
 190                            }
 191                            data += sizeof(long);
 192                        }
 193                        ret = 0;
 194                        break;
 195                }
 196
 197                case PTRACE_SETREGS: { /* Set all gp regs in the child. */
 198                        int i;
 199                        unsigned long tmp;
 200                        for (i = 0; i < H8300_REGS_NO; i++) {
 201                            if (get_user(tmp, (unsigned long *) data)) {
 202                                ret = -EFAULT;
 203                                break;
 204                            }
 205                            h8300_put_reg(child, i, tmp);
 206                            data += sizeof(long);
 207                        }
 208                        ret = 0;
 209                        break;
 210                }
 211
 212                default:
 213                        ret = -EIO;
 214                        break;
 215        }
 216        return ret;
 217}
 218
 219asmlinkage void do_syscall_trace(void)
 220{
 221        if (!test_thread_flag(TIF_SYSCALL_TRACE))
 222                return;
 223        if (!(current->ptrace & PT_PTRACED))
 224                return;
 225        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 226                                 ? 0x80 : 0));
 227        /*
 228         * this isn't the same as continuing with a signal, but it will do
 229         * for normal use.  strace only continues with a signal if the
 230         * stopping signal is not SIGTRAP.  -brl
 231         */
 232        if (current->exit_code) {
 233                send_sig(current->exit_code, current, 1);
 234                current->exit_code = 0;
 235        }
 236}
 237