Exemple #1
0
/*
 * arch_ptrace()
 *	architecture specific ptrace routine.
 */
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret;
	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:
		ret = generic_ptrace_peekdata(child, addr, data);
		break;

	/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		unsigned long tmp;

		ret = -EIO;
		if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
		    || (addr & 3))
			break;

		tmp = 0;  /* Default return condition */

		ret = -EIO;
		if (addr < sizeof(struct pt_regs)) {
			tmp = ptrace_get_reg(child, addr);
		} else if (addr == PT_TEXT_ADDR) {
			tmp = child->mm->start_code;
		} else if (addr == PT_TEXT_END_ADDR) {
			tmp = child->mm->end_code;
		} else if (addr == PT_DATA_ADDR) {
			tmp = child->mm->start_data;
		} else if (addr == PT_EXEC_FDPIC_LOADMAP) {
#ifdef CONFIG_BINFMT_ELF_FDPIC
			tmp = child->mm->context.exec_fdpic_loadmap;
#endif
		} else if (addr == PT_INTERP_FDPIC_LOADMAP) {
#ifdef CONFIG_BINFMT_ELF_FDPIC
			tmp = child->mm->context.interp_fdpic_loadmap;
#endif
		} else {
			break;
		}

		ret = put_user(tmp, (unsigned long *)data);
		break;
	}

	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		ret = generic_ptrace_pokedata(child, addr, data);

		/*
		 * If we just changed some code so we need to
		 * correct the caches
		 */
		if (request == PTRACE_POKETEXT && ret == 0) {
			flush_icache_range(addr, addr + 4);
		}
		break;

	case PTRACE_POKEUSR: /* write the word at location addr
			      * in the USER area */
		ret = -EIO;

		if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
			break;

		if (addr < sizeof(struct pt_regs)) {
			ret = ptrace_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. */
		ptrace_disable_single_step(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. */
		ptrace_disable_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_DETACH:	/* detach a process that was attached. */
		ret = ptrace_detach(child, data);
		break;

	case PTRACE_GETREGS:    /* Get all gp regs from the child. */
		ptrace_getregs(child, (unsigned long *)data);
		ret = 0;
		break;

	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
		int i;
		unsigned long tmp;
		int count = sizeof(struct pt_regs) / sizeof(unsigned long);
		for (i = 0; i < count; i++) {
			if (get_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			}
			ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
			data += sizeof(long);
		}
		ret = 0;
		break;
	}

	default:
		return ptrace_request(child, request, addr, data);
		break;
	}
	return ret;
}
Exemple #2
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret = -EPERM;

	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:
		ret = generic_ptrace_peekdata(child, addr, data);
		break;

	/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		unsigned long index, tmp;

		ret = -EIO;
		/* convert to index and check */
#ifdef CONFIG_PPC32
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || (index > PT_FPSCR)
		    || (child->thread.regs == NULL))
#else
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
#endif
			break;

		CHECK_FULL_REGS(child->thread.regs);
		if (index < PT_FPR0) {
			tmp = ptrace_get_reg(child, (int) index);
		} else {
			flush_fp_to_thread(child);
			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
		}
		ret = put_user(tmp,(unsigned long __user *) data);
		break;
	}

	/* If 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 = generic_ptrace_pokedata(child, addr, data);
		break;

	/* write the word at location addr in the USER area */
	case PTRACE_POKEUSR: {
		unsigned long index;

		ret = -EIO;
		/* convert to index and check */
#ifdef CONFIG_PPC32
		index = (unsigned long) addr >> 2;
		if ((addr & 3) || (index > PT_FPSCR)
		    || (child->thread.regs == NULL))
#else
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
#endif
			break;

		CHECK_FULL_REGS(child->thread.regs);
		if (index < PT_FPR0) {
			ret = ptrace_put_reg(child, index, data);
		} else {
			flush_fp_to_thread(child);
			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
			ret = 0;
		}
		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_single_step(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_single_step(child);
		wake_up_process(child);
		break;
	}

	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		set_single_step(child);
		child->exit_code = data;
		/* give it a chance to run. */
		wake_up_process(child);
		ret = 0;
		break;
	}

	case PTRACE_GET_DEBUGREG: {
		ret = -EINVAL;
		/* We only support one DABR and no IABRS at the moment */
		if (addr > 0)
			break;
		ret = put_user(child->thread.dabr,
			       (unsigned long __user *)data);
		break;
	}

	case PTRACE_SET_DEBUGREG:
		ret = ptrace_set_debugreg(child, addr, data);
		break;

#ifdef CONFIG_PPC64
	case PTRACE_GETREGS64:
#endif
	case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
		int ui;
	  	if (!access_ok(VERIFY_WRITE, (void __user *)data,
			       sizeof(struct pt_regs))) {
			ret = -EIO;
			break;
		}
		CHECK_FULL_REGS(child->thread.regs);
		ret = 0;
		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
			ret |= __put_user(ptrace_get_reg(child, ui),
					  (unsigned long __user *) data);
			data += sizeof(long);
		}
		break;
	}

#ifdef CONFIG_PPC64
	case PTRACE_SETREGS64:
#endif
	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
		unsigned long tmp;
		int ui;
	  	if (!access_ok(VERIFY_READ, (void __user *)data,
			       sizeof(struct pt_regs))) {
			ret = -EIO;
			break;
		}
		CHECK_FULL_REGS(child->thread.regs);
		ret = 0;
		for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
			ret = __get_user(tmp, (unsigned long __user *) data);
			if (ret)
				break;
			ptrace_put_reg(child, ui, tmp);
			data += sizeof(long);
		}
		break;
	}

	case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
		flush_fp_to_thread(child);
		ret = get_fpregs((void __user *)data, child, 1);
		break;
	}

	case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
		flush_fp_to_thread(child);
		ret = set_fpregs((void __user *)data, child, 1);
		break;
	}

#ifdef CONFIG_ALTIVEC
	case PTRACE_GETVRREGS:
		/* Get the child altivec register state. */
		flush_altivec_to_thread(child);
		ret = get_vrregs((unsigned long __user *)data, child);
		break;

	case PTRACE_SETVRREGS:
		/* Set the child altivec register state. */
		flush_altivec_to_thread(child);
		ret = set_vrregs(child, (unsigned long __user *)data);
		break;
#endif
#ifdef CONFIG_SPE
	case PTRACE_GETEVRREGS:
		/* Get the child spe register state. */
		flush_spe_to_thread(child);
		ret = get_evrregs((unsigned long __user *)data, child);
		break;

	case PTRACE_SETEVRREGS:
		/* Set the child spe register state. */
		/* this is to clear the MSR_SPE bit to force a reload
		 * of register state from memory */
		flush_spe_to_thread(child);
		ret = set_evrregs(child, (unsigned long __user *)data);
		break;
#endif

	/* Old reverse args ptrace callss */
	case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
	case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
	case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
	case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
		ret = arch_ptrace_old(child, request, addr, data);
		break;

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
	return ret;
}