long arch_ptrace(struct task_struct *child, long request,
		 unsigned long addr, unsigned long data)
{
	int rval;
	unsigned long val = 0;

	switch (request) {
	/* Read/write the word at location ADDR in the registers. */
	case PTRACE_PEEKUSR:
	case PTRACE_POKEUSR:
		pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
		rval = 0;
		if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
			/*
			 * Special requests that don't actually correspond
			 * to offsets in struct pt_regs.
			 */
			if (addr == PT_TEXT_ADDR) {
				val = child->mm->start_code;
			} else if (addr == PT_DATA_ADDR) {
				val = child->mm->start_data;
			} else if (addr == PT_TEXT_LEN) {
				val = child->mm->end_code
					- child->mm->start_code;
			} else {
				rval = -EIO;
			}
		} else if (addr < PT_SIZE && (addr & 0x3) == 0) {
			microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
			if (request == PTRACE_PEEKUSR)
				val = *reg_addr;
			else {
#if 1
				*reg_addr = data;
#else
				/* MS potential problem on WB system
				 * Be aware that reg_addr is virtual address
				 * virt_to_phys conversion is necessary.
				 * This could be sensible solution.
				 */
				u32 paddr = virt_to_phys((u32)reg_addr);
				invalidate_icache_range(paddr, paddr + 4);
				*reg_addr = data;
				flush_dcache_range(paddr, paddr + 4);
#endif
			}
		} else
			rval = -EIO;

		if (rval == 0 && request == PTRACE_PEEKUSR)
			rval = put_user(val, (unsigned long __user *)data);
		break;
	default:
		rval = ptrace_request(child, request, addr, data);
	}
	return rval;
}
示例#2
0
/* Try to set CHILD's single-step flag to VAL.  Returns true if successful.  */
static int set_single_step (struct task_struct *t, int val)
{
	microblaze_reg_t *sstep_addr = reg_save_addr(PT_SINGLESTEP, t);
	if (val) {
		/* Make sure single-stepping is enabled.  */
		if (! enable_single_stepping ())
			return 0;
		/* Set T's single-step flag.  */
		*sstep_addr = 1;
	} else
		*sstep_addr = 0;
	return 1;
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int rval;
	unsigned long val = 0;

	switch (request) {
	/* Read/write the word at location ADDR in the registers. */
	case PTRACE_PEEKUSR:
	case PTRACE_POKEUSR:
		pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
		rval = 0;
		if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
			/*
			 * Special requests that don't actually correspond
			 * to offsets in struct pt_regs.
			 */
			if (addr == PT_TEXT_ADDR) {
				val = child->mm->start_code;
			} else if (addr == PT_DATA_ADDR) {
				val = child->mm->start_data;
			} else if (addr == PT_TEXT_LEN) {
				val = child->mm->end_code
					- child->mm->start_code;
			} else {
				rval = -EIO;
			}
		} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
			microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
			if (request == PTRACE_PEEKUSR)
				val = *reg_addr;
			else
				*reg_addr = data;
		} else
			rval = -EIO;

		if (rval == 0 && request == PTRACE_PEEKUSR)
			rval = put_user(val, (unsigned long *)data);
		break;
	default:
		rval = ptrace_request(child, request, addr, data);
	}
	return rval;
}
示例#4
0
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int rval;

	lock_kernel();
	/* printk("sys_ptrace - PID:%u  ADDR:%08x  DATA:%08x\n",pid,addr,data); */

	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED) {
			rval = -EPERM;
			goto out;
		}
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		rval = 0;
		goto out;
	}
	rval = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);
	if (!child)
		goto out;

	rval = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out;

	if (request == PTRACE_ATTACH) {
		rval = ptrace_attach(child);
		goto out_tsk;
	}
	rval = -ESRCH;
	if (!(child->ptrace & PT_PTRACED))
		goto out_tsk;
	if (child->state != TASK_STOPPED) {
		if (request != PTRACE_KILL)
			goto out_tsk;
	}
	if (child->p_pptr != current)
		goto out_tsk;

	switch (request) {
		unsigned long val, copied;

	case PTRACE_PEEKTEXT: /* read word at location addr. */
	case PTRACE_PEEKDATA:
	/*	printk("PEEKTEXT/PEEKDATA at %08X\n",addr); */
		copied = access_process_vm(child, addr, &val, sizeof(val), 0);
		rval = -EIO;
		if (copied != sizeof(val))
			break;
		rval = put_user(val, (unsigned long *)data);
		goto out;

	case PTRACE_POKETEXT: /* write the word at location addr. */
	case PTRACE_POKEDATA:
		/* printk("POKETEXT/POKEDATA to %08X\n",addr); */
		rval = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
		    == sizeof(data))
			break;
		rval = -EIO;
		goto out;

	/* Read/write the word at location ADDR in the registers.  */
	case PTRACE_PEEKUSR:
	case PTRACE_POKEUSR:
		rval = 0;
		if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
			/* Special requests that don't actually correspond
			   to offsets in struct pt_regs.  */
			if (addr == PT_TEXT_ADDR)
			{
				val = child->mm->start_code;
			}
			else if (addr == PT_DATA_ADDR)
			{
				val = child->mm->start_data;
			}
			else if (addr == PT_TEXT_LEN)
			{
				val = child->mm->end_code
					- child->mm->start_code;
			}
			else if (addr == PT_DATA_LEN)
			{
				val = child->mm->end_data
					- child->mm->start_data;
			}
			else
			{
				rval = -EIO;
			}
		} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
			microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
			if (request == PTRACE_PEEKUSR)
			{
				val = *reg_addr;
			}
			else
			{
				*reg_addr = data;
			}
		} else
			rval = -EIO;

		if (rval == 0 && request == PTRACE_PEEKUSR)
		{
			rval = put_user (val, (unsigned long *)data);
		}
		goto out;

	/* Continue and stop at next (return from) syscall */
	case PTRACE_SYSCALL:
	/* Restart after a signal.  */
	case PTRACE_CONT:
		/* printk("PTRACE_CONT\n"); */
	/* Execute a single instruction. */
	case PTRACE_SINGLESTEP:
		/* printk("PTRACE_SINGLESTEP\n"); */
		rval = -EIO;
		if ((unsigned long) data > _NSIG)
			break;

		/* Turn CHILD's single-step flag on or off.  */
		/* printk("calling set_single_step\n"); */
		if (! set_single_step (child, request == PTRACE_SINGLESTEP))
			break;

		if (request == PTRACE_SYSCALL)
			child->ptrace |= PT_TRACESYS;
		else
			child->ptrace &= ~PT_TRACESYS;

		child->exit_code = data;
		/* printk("wakeup_process\n"); */
		wake_up_process(child);
		rval = 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:
		/* printk("PTRACE_KILL\n"); */
		rval = 0;
		if (child->state == TASK_ZOMBIE)	/* already dead */
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

	case PTRACE_DETACH: /* detach a process that was attached. */
		/* printk("PTRACE_DETACH\n"); */
		set_single_step (child, 0);  /* Clear single-step flag */
		rval = ptrace_detach(child, data);
		break;

	default:
		rval = -EIO;
		goto out;
	}

out_tsk:
	free_task_struct(child);
out:
	unlock_kernel();
	return rval;
}
示例#5
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
    int rval;
    unsigned long val = 0;
    unsigned long copied;

    switch (request) {
    case PTRACE_PEEKTEXT: /* read word at location addr. */
    case PTRACE_PEEKDATA:
        pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
        copied = access_process_vm(child, addr, &val, sizeof(val), 0);
        rval = -EIO;
        if (copied != sizeof(val))
            break;
        rval = put_user(val, (unsigned long *)data);
        break;

    case PTRACE_POKETEXT: /* write the word at location addr. */
    case PTRACE_POKEDATA:
        pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
        rval = 0;
        if (access_process_vm(child, addr, &data, sizeof(data), 1)
                == sizeof(data))
            break;
        rval = -EIO;
        break;

    /* Read/write the word at location ADDR in the registers. */
    case PTRACE_PEEKUSR:
    case PTRACE_POKEUSR:
        pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
        rval = 0;
        if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
            /*
             * Special requests that don't actually correspond
             * to offsets in struct pt_regs.
             */
            if (addr == PT_TEXT_ADDR) {
                val = child->mm->start_code;
            } else if (addr == PT_DATA_ADDR) {
                val = child->mm->start_data;
            } else if (addr == PT_TEXT_LEN) {
                val = child->mm->end_code
                      - child->mm->start_code;
            } else {
                rval = -EIO;
            }
        } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
            microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
            if (request == PTRACE_PEEKUSR)
                val = *reg_addr;
            else
                *reg_addr = data;
        } else
            rval = -EIO;

        if (rval == 0 && request == PTRACE_PEEKUSR)
            rval = put_user(val, (unsigned long *)data);
        break;
    /* Continue and stop at next (return from) syscall */
    case PTRACE_SYSCALL:
        pr_debug("PTRACE_SYSCALL\n");
    case PTRACE_SINGLESTEP:
        pr_debug("PTRACE_SINGLESTEP\n");
    /* Restart after a signal.  */
    case PTRACE_CONT:
        pr_debug("PTRACE_CONT\n");
        rval = -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;
        pr_debug("wakeup_process\n");
        wake_up_process(child);
        rval = 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:
        pr_debug("PTRACE_KILL\n");
        rval = 0;
        if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
            break;
        child->exit_code = SIGKILL;
        wake_up_process(child);
        break;

    case PTRACE_DETACH: /* detach a process that was attached. */
        pr_debug("PTRACE_DETACH\n");
        rval = ptrace_detach(child, data);
        break;
    default:
        /* rval = ptrace_request(child, request, addr, data); noMMU */
        rval = -EIO;
    }
    return rval;
}