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 = 0; 115 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) 116 break; 117 ret = -EIO; 118 break; 119 120 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 121 if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) { 122 ret = -EIO; 123 break ; 124 } 125 addr = addr >> 2; /* temporary hack. */ 126 127 if (addr == PT_ORIG_ER0) { 128 ret = -EIO; 129 break ; 130 } 131 if (addr < H8300_REGS_NO) { 132 ret = h8300_put_reg(child, addr, data); 133 break ; 134 } 135 ret = -EIO; 136 break ; 137 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 138 case PTRACE_CONT: { /* restart after signal. */ 139 ret = -EIO; 140 if (!valid_signal(data)) 141 break ; 142 if (request == PTRACE_SYSCALL) 143 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 144 else 145 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 146 child->exit_code = data; 147 wake_up_process(child); 148 /* make sure the single step bit is not set. */ 149 h8300_disable_trace(child); 150 ret = 0; 151 } 152 153/* 154 * make the child exit. Best I can do is send it a sigkill. 155 * perhaps it should be put in the status that it wants to 156 * exit. 157 */ 158 case PTRACE_KILL: { 159 160 ret = 0; 161 if (child->exit_state == EXIT_ZOMBIE) /* already dead */ 162 break; 163 child->exit_code = SIGKILL; 164 h8300_disable_trace(child); 165 wake_up_process(child); 166 break; 167 } 168 169 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 170 ret = -EIO; 171 if (!valid_signal(data)) 172 break; 173 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 174 child->exit_code = data; 175 h8300_enable_trace(child); 176 wake_up_process(child); 177 ret = 0; 178 break; 179 } 180 181 case PTRACE_DETACH: /* detach a process that was attached. */ 182 ret = ptrace_detach(child, data); 183 break; 184 185 case PTRACE_GETREGS: { /* Get all gp regs from the child. */ 186 int i; 187 unsigned long tmp; 188 for (i = 0; i < H8300_REGS_NO; i++) { 189 tmp = h8300_get_reg(child, i); 190 if (put_user(tmp, (unsigned long *) data)) { 191 ret = -EFAULT; 192 break; 193 } 194 data += sizeof(long); 195 } 196 ret = 0; 197 break; 198 } 199 200 case PTRACE_SETREGS: { /* Set all gp regs in the child. */ 201 int i; 202 unsigned long tmp; 203 for (i = 0; i < H8300_REGS_NO; i++) { 204 if (get_user(tmp, (unsigned long *) data)) { 205 ret = -EFAULT; 206 break; 207 } 208 h8300_put_reg(child, i, tmp); 209 data += sizeof(long); 210 } 211 ret = 0; 212 break; 213 } 214 215 default: 216 ret = -EIO; 217 break; 218 } 219 return ret; 220} 221 222asmlinkage void syscall_trace(void) 223{ 224 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 225 return; 226 if (!(current->ptrace & PT_PTRACED)) 227 return; 228 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 229 ? 0x80 : 0)); 230 /* 231 * this isn't the same as continuing with a signal, but it will do 232 * for normal use. strace only continues with a signal if the 233 * stopping signal is not SIGTRAP. -brl 234 */ 235 if (current->exit_code) { 236 send_sig(current->exit_code, current, 1); 237 current->exit_code = 0; 238 } 239} 240