OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [or32/] [kernel/] [ptrace.c] - Rev 7

Compare with Previous | Blame | View Log

/*
 *  linux/arch/or32/kernel/ptrace.c
 *
 *  or32 version
 *    author(s): Matjaz Breskvar (phoenix@bsemi.com)
 *
 *  derived from cris, i386, m68k, ppc, sh ports.
 *
 *  changes:
 *  18. 11. 2003: Matjaz Breskvar (phoenix@bsemi.com)
 *    initial port to or32 architecture
 *  31. 12. 2005: Gyorgy Jeney (nog@bsemi.com)
 *    Added actual ptrace implementation except for single step traceing
 *    (Basically copy arch/i386/kernel/ptrace.c)
 *
 *  Based on:
 *
 *  linux/arch/m68k/kernel/ptrace
 *
 *  Copyright (C) 1994 by Hamish Macdonald
 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License.  See the file COPYING in the main directory of
 * this archive for more details.
 */
 
#include <stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
 
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/audit.h>
 
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/or32-hf.h>
 
/*
 * does not yet catch signals sent when the child dies.
 * in exit.c or in signal.c.
 */
 
 
/*
 * Get contents of register REGNO in task TASK.
 */
static inline long get_reg(struct task_struct *task, int regno)
{
	if(regno < sizeof(struct pt_regs))
		return *((unsigned long *)user_regs(task->stack) + (regno >> 2));
	switch(regno) {
	case offsetof(struct user, start_code):
		return task->mm->start_code;
	case offsetof(struct user, start_data):
		return task->mm->start_data;
	case offsetof(struct user, start_stack):
		return task->mm->start_stack;
	default:
		printk("Don't know how to get offset %i of struct user\n",
		       regno);
	}
	return 0;
}
 
/*
 * Write contents of register REGNO in task TASK.
 */
static inline int put_reg(struct task_struct *task, int regno,
			  unsigned long data)
{
	/* Whatever happens, don't let any process the the sr flags and elevate
	 * their privaleges to kernel mode. */
	if((regno < sizeof(struct pt_regs)) &&
	   (regno != offsetof(struct pt_regs, sr))) {
		*((unsigned long *)task->thread.regs + (regno >> 2)) = data;
		return 0;
	}
	return -EIO;
}
 
static void set_singlestep(struct task_struct *child)
{
	/* FIXME */
#if 0
	struct pt_regs *regs = get_child_regs(child);
 
	/*
	 * Always set TIF_SINGLESTEP - this guarantees that 
	 * we single-step system calls etc..  This will also
	 * cause us to set TF when returning to user mode.
	 */
	set_tsk_thread_flag(child, TIF_SINGLESTEP);
 
	/*
	 * If TF was already set, don't do anything else
	 */
	if (regs->eflags & TRAP_FLAG)
		return;
 
	/* Set TF on the kernel stack.. */
	regs->eflags |= TRAP_FLAG;
 
	child->ptrace |= PT_DTRACE;
#endif
}
 
 
static void clear_singlestep(struct task_struct *child)
{
	/* FIXME */
#if 0
	/* Always clear TIF_SINGLESTEP... */
	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 
	/* But touch TF only if it was set by us.. */
	if (child->ptrace & PT_DTRACE) {
		struct pt_regs *regs = get_child_regs(child);
		regs->eflags &= ~TRAP_FLAG;
		child->ptrace &= ~PT_DTRACE;
	}
#endif
}
 
/*
 * Called by kernel/ptrace.c when detaching..
 *
 * Make sure the single step bit is not set.
 */
void ptrace_disable(struct task_struct *child)
{
	printk("ptrace_disable(): TODO\n");
	clear_singlestep(child);
	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
 
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret;
	unsigned long __user *datap = (unsigned long __user *)data;
 
	switch (request) {
	/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
		unsigned long tmp;
		int copied;
 
		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		ret = -EIO;
		if (copied != sizeof(tmp))
			break;
		ret = put_user(tmp,(unsigned long *) datap);
		break;
	}
 
	/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR:
		ret = -EIO;
		if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
			break;
 
		ret = put_user(get_reg(child, addr), datap);
		break;
 
	/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
			break;
		ret = -EIO;
		break;
 
	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
			break;
 
		ret = put_reg(child, addr, data);	    
		break;
 
	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT: /* restart after signal. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		if (request == PTRACE_SYSCALL) {
			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		} else {
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		}
		child->exit_code = data;
		/* make sure the single step bit is not set. */
		clear_singlestep(child);
		wake_up_process(child);
		ret = 0;
		break;
 
/*
 * make the child exit.  Best I can do is send it a sigkill. 
 * perhaps it should be put in the status that it wants to 
 * exit.
 */
	case PTRACE_KILL:
		ret = 0;
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		/* make sure the single step bit is not set. */
		clear_singlestep(child);
		wake_up_process(child);
		break;
 
		/*case PTRACE_SYSEMU_SINGLESTEP:  Same as SYSEMU, but singlestep if not syscall RGD */
	case PTRACE_SINGLESTEP:  /* set the trap flag. */
		printk("SINGLESTEP: TODO\n");
		ret = -ENOSYS;
#if 0
		ret = -EIO;
		if (!valid_signal(data))
			break;
 
		if (request == PTRACE_SYSEMU_SINGLESTEP)
			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
		else
			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
 
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		set_singlestep(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
#endif
		break;
 
	case PTRACE_DETACH: /* detach a process that was attached. */
		ret = ptrace_detach(child, data);
		break;
 
	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
	return ret;
}
 
/* notification of system call entry/exit
 * - triggered by current->work.syscall_trace
 */
asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
{
 	if (unlikely(current->audit_context) && entryexit)
	  audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), regs->regs[2]);/*RGD current*/
 
	if (!test_thread_flag(TIF_SYSCALL_TRACE))
		goto out;
	if (!(current->ptrace & PT_PTRACED))
		goto out;
 
	/* The 0x80 provides a way for the tracing parent to distinguish
	   between a syscall stop and SIGTRAP delivery */
	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
	                         0x80 : 0));
 
	/*
	 * this isn't the same as continuing with a signal, but it will do
	 * for normal use.  strace only continues with a signal if the
	 * stopping signal is not SIGTRAP.  -brl
	 */
	if (current->exit_code) {
		send_sig(current->exit_code, current, 1);
		current->exit_code = 0;
	}
 out:
	if (unlikely(current->audit_context) && !entryexit)
		audit_syscall_entry(audit_arch(), regs->regs[2],
				    regs->regs[4], regs->regs[5],
				    regs->regs[6], regs->regs[7]);/*RGD*/
 
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.