PageRenderTime 45ms CodeModel.GetById 2ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/h8300/kernel/ptrace.c

https://bitbucket.org/evzijst/gittest
C | 277 lines | 214 code | 27 blank | 36 comment | 40 complexity | eb89d63d7d512e69c8e06a9790d12c82 MD5 | raw file
  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/smp_lock.h>
 23#include <linux/errno.h>
 24#include <linux/ptrace.h>
 25#include <linux/user.h>
 26#include <linux/config.h>
 27
 28#include <asm/uaccess.h>
 29#include <asm/page.h>
 30#include <asm/pgtable.h>
 31#include <asm/system.h>
 32#include <asm/processor.h>
 33#include <asm/signal.h>
 34
 35/* cpu depend functions */
 36extern long h8300_get_reg(struct task_struct *task, int regno);
 37extern int  h8300_put_reg(struct task_struct *task, int regno, unsigned long data);
 38extern void h8300_disable_trace(struct task_struct *child);
 39extern void h8300_enable_trace(struct task_struct *child);
 40
 41/*
 42 * does not yet catch signals sent when the child dies.
 43 * in exit.c or in signal.c.
 44 */
 45
 46inline
 47static int read_long(struct task_struct * tsk, unsigned long addr,
 48	unsigned long * result)
 49{
 50	*result = *(unsigned long *)addr;
 51	return 0;
 52}
 53
 54void ptrace_disable(struct task_struct *child)
 55{
 56	h8300_disable_trace(child);
 57}
 58
 59asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 60{
 61	struct task_struct *child;
 62	int ret;
 63
 64	lock_kernel();
 65	ret = -EPERM;
 66	if (request == PTRACE_TRACEME) {
 67		/* are we already being traced? */
 68		if (current->ptrace & PT_PTRACED)
 69			goto out;
 70		/* set the ptrace bit in the process flags. */
 71		current->ptrace |= PT_PTRACED;
 72		ret = 0;
 73		goto out;
 74	}
 75	ret = -ESRCH;
 76	read_lock(&tasklist_lock);
 77	child = find_task_by_pid(pid);
 78	if (child)
 79		get_task_struct(child);
 80	read_unlock(&tasklist_lock);
 81	if (!child)
 82		goto out;
 83
 84	ret = -EPERM;
 85	if (pid == 1)		/* you may not mess with init */
 86		goto out_tsk;
 87
 88	if (request == PTRACE_ATTACH) {
 89		ret = ptrace_attach(child);
 90		goto out_tsk;
 91	}
 92	ret = ptrace_check_attach(child, request == PTRACE_KILL);
 93	if (ret < 0)
 94		goto out_tsk;
 95
 96	switch (request) {
 97		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 98		case PTRACE_PEEKDATA: {
 99			unsigned long tmp;
100
101			ret = read_long(child, addr, &tmp);
102			if (ret < 0)
103				break ;
104			ret = put_user(tmp, (unsigned long *) data);
105			break ;
106		}
107
108	/* read the word at location addr in the USER area. */
109		case PTRACE_PEEKUSR: {
110			unsigned long tmp = 0;
111			
112			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
113				ret = -EIO;
114				break ;
115			}
116			
117		        ret = 0;  /* Default return condition */
118			addr = addr >> 2; /* temporary hack. */
119
120			if (addr < H8300_REGS_NO)
121				tmp = h8300_get_reg(child, addr);
122			else {
123				switch(addr) {
124				case 49:
125					tmp = child->mm->start_code;
126					break ;
127				case 50:
128					tmp = child->mm->start_data;
129					break ;
130				case 51:
131					tmp = child->mm->end_code;
132					break ;
133				case 52:
134					tmp = child->mm->end_data;
135					break ;
136				default:
137					ret = -EIO;
138				}
139			}
140			if (!ret)
141				ret = put_user(tmp,(unsigned long *) data);
142			break ;
143		}
144
145      /* when I and D space are separate, this will have to be fixed. */
146		case PTRACE_POKETEXT: /* write the word at location addr. */
147		case PTRACE_POKEDATA:
148			ret = 0;
149			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
150				break;
151			ret = -EIO;
152			break;
153
154		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
155			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
156				ret = -EIO;
157				break ;
158			}
159			addr = addr >> 2; /* temporary hack. */
160			    
161			if (addr == PT_ORIG_ER0) {
162				ret = -EIO;
163				break ;
164			}
165			if (addr < H8300_REGS_NO) {
166				ret = h8300_put_reg(child, addr, data);
167				break ;
168			}
169			ret = -EIO;
170			break ;
171		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
172		case PTRACE_CONT: { /* restart after signal. */
173			ret = -EIO;
174			if ((unsigned long) data >= _NSIG)
175				break ;
176			if (request == PTRACE_SYSCALL)
177				set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
178			else
179				clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
180			child->exit_code = data;
181			wake_up_process(child);
182			/* make sure the single step bit is not set. */
183			h8300_disable_trace(child);
184			ret = 0;
185		}
186
187/*
188 * make the child exit.  Best I can do is send it a sigkill. 
189 * perhaps it should be put in the status that it wants to 
190 * exit.
191 */
192		case PTRACE_KILL: {
193
194			ret = 0;
195			if (child->exit_state == EXIT_ZOMBIE) /* already dead */
196				break;
197			child->exit_code = SIGKILL;
198			h8300_disable_trace(child);
199			wake_up_process(child);
200			break;
201		}
202
203		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
204			ret = -EIO;
205			if ((unsigned long) data > _NSIG)
206				break;
207			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
208			child->exit_code = data;
209			h8300_enable_trace(child);
210			wake_up_process(child);
211			ret = 0;
212			break;
213		}
214
215		case PTRACE_DETACH:	/* detach a process that was attached. */
216			ret = ptrace_detach(child, data);
217			break;
218
219		case PTRACE_GETREGS: { /* Get all gp regs from the child. */
220		  	int i;
221			unsigned long tmp;
222			for (i = 0; i < H8300_REGS_NO; i++) {
223			    tmp = h8300_get_reg(child, i);
224			    if (put_user(tmp, (unsigned long *) data)) {
225				ret = -EFAULT;
226				break;
227			    }
228			    data += sizeof(long);
229			}
230			ret = 0;
231			break;
232		}
233
234		case PTRACE_SETREGS: { /* Set all gp regs in the child. */
235			int i;
236			unsigned long tmp;
237			for (i = 0; i < H8300_REGS_NO; i++) {
238			    if (get_user(tmp, (unsigned long *) data)) {
239				ret = -EFAULT;
240				break;
241			    }
242			    h8300_put_reg(child, i, tmp);
243			    data += sizeof(long);
244			}
245			ret = 0;
246			break;
247		}
248
249		default:
250			ret = -EIO;
251			break;
252	}
253out_tsk:
254	put_task_struct(child);
255out:
256	unlock_kernel();
257	return ret;
258}
259
260asmlinkage void syscall_trace(void)
261{
262	if (!test_thread_flag(TIF_SYSCALL_TRACE))
263		return;
264	if (!(current->ptrace & PT_PTRACED))
265		return;
266	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
267				 ? 0x80 : 0));
268	/*
269	 * this isn't the same as continuing with a signal, but it will do
270	 * for normal use.  strace only continues with a signal if the
271	 * stopping signal is not SIGTRAP.  -brl
272	 */
273	if (current->exit_code) {
274		send_sig(current->exit_code, current, 1);
275		current->exit_code = 0;
276	}
277}