コード例 #1
0
static int ptrace_resume(struct task_struct *child, long request,
			 unsigned long data)
{
	if (!valid_signal(data))
		return -EIO;

	if (request == PTRACE_SYSCALL)
		set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
	else
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

#ifdef TIF_SYSCALL_EMU
	if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP)
		set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
	else
		clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
#endif

	if (is_singleblock(request)) {
		if (unlikely(!arch_has_block_step()))
			return -EIO;
		user_enable_block_step(child);
	} else if (is_singlestep(request) || is_sysemu_singlestep(request)) {
		if (unlikely(!arch_has_single_step()))
			return -EIO;
		user_enable_single_step(child);
	} else {
		user_disable_single_step(child);
	}

	child->exit_code = data;
	wake_up_state(child, __TASK_TRACED);

	return 0;
}
コード例 #2
0
static int ptrace_detach(struct task_struct *child, unsigned int data)
{
	bool dead = false;

	if (!valid_signal(data))
		return -EIO;

	/* Architecture-specific hardware disable .. */
	ptrace_disable(child);
	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

	write_lock_irq(&tasklist_lock);
	/*
	 * This child can be already killed. Make sure de_thread() or
	 * our sub-thread doing do_wait() didn't do release_task() yet.
	 */
	if (child->ptrace) {
		child->exit_code = data;
		dead = __ptrace_detach(current, child);
	}
	write_unlock_irq(&tasklist_lock);

	if (unlikely(dead))
		release_task(child);

	return 0;
}
コード例 #3
0
ファイル: ptrace.c プロジェクト: achristensen3/cm-kernel
int ptrace_detach(struct task_struct *child, unsigned int data)
{
	int dead = 0;

	if (!valid_signal(data))
		return -EIO;

	/* Architecture-specific hardware disable .. */
	ptrace_disable(child);
	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

	write_lock_irq(&tasklist_lock);
	/* protect against de_thread()->release_task() */
	if (child->ptrace) {
		child->exit_code = data;

		dead = __ptrace_detach(current, child);

		if (!child->exit_state)
			wake_up_process(child);
	}
	write_unlock_irq(&tasklist_lock);

	if (unlikely(dead))
		release_task(child);

	return 0;
}
コード例 #4
0
ファイル: ptrace.c プロジェクト: 3sOx/asuswrt-merlin
int ptrace_detach(struct task_struct *child, unsigned int data)
{
	if (!valid_signal(data))
		return -EIO;

	/* Architecture-specific hardware disable .. */
	ptrace_disable(child);

	write_lock_irq(&tasklist_lock);
	/* protect against de_thread()->release_task() */
	if (child->ptrace)
		__ptrace_detach(child, data);
	write_unlock_irq(&tasklist_lock);

	return 0;
}
コード例 #5
0
int ptrace_detach(struct task_struct *child, unsigned int data)
{
	if (!valid_signal(data))
		return	-EIO;

	/* Architecture-specific hardware disable .. */
	ptrace_disable(child);

	/* .. re-parent .. */
	child->exit_code = data;

	write_lock_irq(&tasklist_lock);
	__ptrace_unlink(child);
	/* .. and wake it up. */
	if (child->exit_state != EXIT_ZOMBIE)
		wake_up_process(child);
	write_unlock_irq(&tasklist_lock);

	return 0;
}
コード例 #6
0
ファイル: sigaction_calls.c プロジェクト: davenso/openonload
static int
efab_signal_do_sigaction(int sig, struct sigaction *act,
                         struct sigaction *oact,
                         struct mm_signal_data *tramp_data,
                         int *out_pass_to_kernel)
{
  int rc = 0;

  if( !valid_signal(sig) || sig < 1 || (act != NULL && sig_kernel_only(sig)) )
    return -EINVAL;


  if( oact != NULL ) {
    rc = efab_signal_report_sigaction(sig, oact, tramp_data);
    if( rc != 0 )
      return rc;
  }

  if( act != NULL ) {
    sigdelsetmask(&act->sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP));

  /* If the signal is ignored now, we should ignore all already-pending
   * signals.  Instead of doing it, pass this to OS. */
    if( act->sa_handler == SIG_IGN ||
        (act->sa_handler == SIG_DFL && sig_kernel_ignore(sig)) )
      *out_pass_to_kernel = 1;
    else if( act->sa_flags & SA_ONSTACK && !tramp_data->sa_onstack_intercept )
      *out_pass_to_kernel = 1;
    else
      rc = efab_signal_substitute(sig, act, tramp_data);
  }
  else
    efab_signal_recheck(sig, tramp_data);

  return rc;
}
コード例 #7
0
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret;
	int add = 0;

	lock_kernel();
	ret = -EPERM;
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -ESRCH;
	read_lock(&tasklist_lock);
	child = find_task_by_pid(pid);
	if (child)
		get_task_struct(child);
	read_unlock(&tasklist_lock);	/* FIXME!!! */
	if (!child)
		goto out;
	ret = -EPERM;
	if (pid == 1)		/* you may not mess with init */
		goto out_tsk;
	if (request == PTRACE_ATTACH) {

		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	switch (request) {
		/* when I and D space are separate, these will need to be fixed. */
	case PTRACE_PEEKDATA:
#ifdef DEBUG
		printk("PTRACE_PEEKDATA\n");
#endif
		add = MAX_SHARED_LIBS * 4;	/* space between text and data */
		/* fall through */
	case PTRACE_PEEKTEXT:	/* read word at location addr. */
		{
			unsigned long tmp = 0;
			int copied;

#ifdef DEBUG
			printk("PEEKTEXT at addr %x + add %d %d", addr, add,
			       sizeof(data));
#endif
			copied =
			    access_process_vm(child, addr + add, &tmp,
					      sizeof(tmp), 0);
#ifdef DEBUG
			printk(" bytes %x\n", data);
#endif
			ret = -EIO;
			if (copied != sizeof(tmp))
				goto out_tsk;
			ret = put_user(tmp, (unsigned long *)data);
			goto out_tsk;
		}

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR:
		{
			unsigned long tmp;
			ret = -EIO;
			tmp = 0;
			if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 8))) {
				printk
				    ("ptrace error : PEEKUSR : temporarily returning 0 - %x sizeof(pt_regs) is %lx\n",
				     (int)addr, sizeof(struct pt_regs));
				goto out_tsk;
			}
			if (addr == sizeof(struct pt_regs)) {
				tmp = child->mm->start_code + TEXT_OFFSET;
			} else if (addr == (sizeof(struct pt_regs) + 4)) {
				// should really just be start_data but the .gdb file has data starting
				// at an offset and gdb refuses to reduce the start value
				tmp =
				    child->mm->start_data -
				    (child->mm->end_code -
				     child->mm->start_code);
			} else if (addr == (sizeof(struct pt_regs) + 8)) {
				// should really just be end_data but the .gdb file has data starting
				// at an offset and gdb refuses to reduce the start value
				tmp =
				    child->mm->end_data - (child->mm->end_code -
							   child->mm->
							   start_code);
			} else {
				tmp = get_reg(child, addr);
			}
			ret = put_user(tmp, (unsigned long *)data);
			goto out_tsk;
		}

		/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKEDATA:
		printk("PTRACE_PEEKDATA\n");
		/* fall through */
	case PTRACE_POKETEXT:	/* write the word at location addr. */
		{
			ret = 0;
#ifdef DEBUG
			printk("POKETEXT at addr %x + add %d %d bytes %x\n",
			       addr, add, sizeof(data), data);
#endif
			if (access_process_vm(child, addr + add,
					      &data, sizeof(data),
					      1) == sizeof(data))
				goto out_tsk;
			ret = -EIO;
			goto out_tsk;
		}

	case PTRACE_POKEUSR:	/* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 8))) {
			printk
			    ("ptrace error : POKEUSR: temporarily returning 0\n");
			goto out_tsk;
		}

		if (addr == PT_SYSCFG) {
			data &= SYSCFG_MASK;
			data |= get_reg(child, PT_SYSCFG);
		}
		ret = put_reg(child, addr, data);
		goto out_tsk;

	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
	case PTRACE_CONT:
		{		/* restart after signal. */
			long tmp;
#ifdef DEBUG
			printk("ptrace_cont\n");
#endif

			ret = -EIO;
			if (!valid_signal(data))
				goto out_tsk;
			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. */
			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);
#ifdef DEBUG
			printk("before wake_up_process\n");
#endif
			wake_up_process(child);
			ret = 0;
			goto out_tsk;
		}

/*
 * 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:
		{
			long tmp;
			ret = 0;
			if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
				goto out_tsk;
			child->exit_code = SIGKILL;
			/* make sure the single step bit is not set. */
			tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);
			wake_up_process(child);
			goto out_tsk;
		}

	case PTRACE_SINGLESTEP:
		{		/* set the trap flag. */
			long tmp;
#ifdef DEBUG
			printk("single step\n");
#endif
			ret = -EIO;
			if (!valid_signal(data))
				goto out_tsk;
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
			put_reg(child, PT_SYSCFG, tmp);

			child->exit_code = data;
			/* give it a chance to run. */
			wake_up_process(child);
			ret = 0;
			goto out;
		}

	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. */
			ret = ptrace_getregs(child, (void __user *)data);
			goto out_tsk;
		}

	case PTRACE_SETREGS:
		{

			printk("SETREGS : **** NOT IMPLEMENTED ***\n");
			/* Set all gp regs in the child. */
			ret = 0;
			goto out_tsk;
		}

	default:
		printk("Ptrace :  *** Unhandled case **** %d\n", (int)request);
		ret = -EIO;
		goto out_tsk;
	}
      out_tsk:
	put_task_struct(child);
      out:
	unlock_kernel();
	return ret;
}
コード例 #8
0
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
    int i, ret;
    unsigned long __user *p = (void __user *)(unsigned long)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;

        ret = -EIO;
        copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
        if (copied != sizeof(tmp))
            break;
        ret = put_user(tmp, p);
        break;
    }

    /* read the word at location addr in the USER area. */
    case PTRACE_PEEKUSR:
        ret = peek_user(child, addr, data);
        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 = -EIO;
        if (access_process_vm(child, addr, &data, sizeof(data),
                              1) != sizeof(data))
            break;
        ret = 0;
        break;

    case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
        ret = poke_user(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;

        set_singlestepping(child, 0);
        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;
        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;

        set_singlestepping(child, 0);
        child->exit_code = SIGKILL;
        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_singlestepping(child, 1);
        child->exit_code = data;
        /* give it a chance to run. */
        wake_up_process(child);
        ret = 0;
        break;
    }

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

#ifdef PTRACE_GETREGS
    case PTRACE_GETREGS: { /* Get all gp regs from the child. */
        if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __put_user(getreg(child, i), p);
            p++;
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_SETREGS
    case PTRACE_SETREGS: { /* Set all gp regs in the child. */
        unsigned long tmp = 0;
        if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __get_user(tmp, p);
            putreg(child, i, tmp);
            p++;
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_GETFPREGS
    case PTRACE_GETFPREGS: /* Get the child FPU state. */
        ret = get_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPREGS
    case PTRACE_SETFPREGS: /* Set the child FPU state. */
        ret = set_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_GETFPXREGS
    case PTRACE_GETFPXREGS: /* Get the child FPU state. */
        ret = get_fpxregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPXREGS
    case PTRACE_SETFPXREGS: /* Set the child FPU state. */
        ret = set_fpxregs(data, child);
        break;
#endif
    case PTRACE_GET_THREAD_AREA:
        ret = ptrace_get_thread_area(child, addr,
                                     (struct user_desc __user *) data);
        break;

    case PTRACE_SET_THREAD_AREA:
        ret = ptrace_set_thread_area(child, addr,
                                     (struct user_desc __user *) data);
        break;

    case PTRACE_FAULTINFO: {
        /* Take the info from thread->arch->faultinfo,
         * but transfer max. sizeof(struct ptrace_faultinfo).
         * On i386, ptrace_faultinfo is smaller!
         */
        ret = copy_to_user(p, &child->thread.arch.faultinfo,
                           sizeof(struct ptrace_faultinfo));
        if(ret)
            break;
        break;
    }

#ifdef PTRACE_LDT
    case PTRACE_LDT: {
        struct ptrace_ldt ldt;

        if(copy_from_user(&ldt, p, sizeof(ldt))) {
            ret = -EIO;
            break;
        }

        /* This one is confusing, so just punt and return -EIO for
         * now
         */
        ret = -EIO;
        break;
    }
#endif
#ifdef CONFIG_PROC_MM
    case PTRACE_SWITCH_MM: {
        struct mm_struct *old = child->mm;
        struct mm_struct *new = proc_mm_get_mm(data);

        if(IS_ERR(new)) {
            ret = PTR_ERR(new);
            break;
        }

        atomic_inc(&new->mm_users);
        child->mm = new;
        child->active_mm = new;
        mmput(old);
        ret = 0;
        break;
    }
#endif
    default:
        ret = ptrace_request(child, request, addr, data);
        break;
    }

    return ret;
}
コード例 #9
0
ファイル: fcntl.c プロジェクト: nemumu/linux
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
                     struct file *filp)
{
    long err = -EINVAL;

    switch (cmd) {
    case F_DUPFD:
        err = f_dupfd(arg, filp, 0);
        break;
    case F_DUPFD_CLOEXEC:
        err = f_dupfd(arg, filp, O_CLOEXEC);
        break;
    case F_GETFD:
        err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
        break;
    case F_SETFD:
        err = 0;
        set_close_on_exec(fd, arg & FD_CLOEXEC);
        break;
    case F_GETFL:
        err = filp->f_flags;
        break;
    case F_SETFL:
        err = setfl(fd, filp, arg);
        break;
#if BITS_PER_LONG != 32
    /* 32-bit arches must use fcntl64() */
    case F_OFD_GETLK:
#endif
    case F_GETLK:
        err = fcntl_getlk(filp, cmd, (struct flock __user *) arg);
        break;
#if BITS_PER_LONG != 32
    /* 32-bit arches must use fcntl64() */
    case F_OFD_SETLK:
    case F_OFD_SETLKW:
#endif
    /* Fallthrough */
    case F_SETLK:
    case F_SETLKW:
        err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg);
        break;
    case F_GETOWN:
        /*
         * XXX If f_owner is a process group, the
         * negative return value will get converted
         * into an error.  Oops.  If we keep the
         * current syscall conventions, the only way
         * to fix this will be in libc.
         */
        err = f_getown(filp);
        force_successful_syscall_return();
        break;
    case F_SETOWN:
        err = f_setown(filp, arg, 1);
        break;
    case F_GETOWN_EX:
        err = f_getown_ex(filp, arg);
        break;
    case F_SETOWN_EX:
        err = f_setown_ex(filp, arg);
        break;
    case F_GETOWNER_UIDS:
        err = f_getowner_uids(filp, arg);
        break;
    case F_GETSIG:
        err = filp->f_owner.signum;
        break;
    case F_SETSIG:
        /* arg == 0 restores default behaviour. */
        if (!valid_signal(arg)) {
            break;
        }
        err = 0;
        filp->f_owner.signum = arg;
        break;
    case F_GETLEASE:
        err = fcntl_getlease(filp);
        break;
    case F_SETLEASE:
        err = fcntl_setlease(fd, filp, arg);
        break;
    case F_NOTIFY:
        err = fcntl_dirnotify(fd, filp, arg);
        break;
    case F_SETPIPE_SZ:
    case F_GETPIPE_SZ:
        err = pipe_fcntl(filp, cmd, arg);
        break;
    case F_ADD_SEALS:
    case F_GET_SEALS:
        err = shmem_fcntl(filp, cmd, arg);
        break;
    default:
        break;
    }
    return err;
}
コード例 #10
0
ファイル: ptrace.c プロジェクト: ysei/linux-2.6.x
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_PEEKDATA:
		pr_debug("ptrace: PEEKDATA\n");
		/* fall through */
	case PTRACE_PEEKTEXT:	/* read word at location addr. */
		{
			unsigned long tmp = 0;
			int copied;

			ret = -EIO;
			pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data));
			if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
				break;
			pr_debug("ptrace: user address is valid\n");

			if (L1_CODE_LENGTH != 0 && addr >= get_l1_code_start()
			    && addr + sizeof(tmp) <= get_l1_code_start() + L1_CODE_LENGTH) {
				safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
				copied = sizeof(tmp);

			} else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
			    && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
				memcpy(&tmp, (const void *)(addr), sizeof(tmp));
				copied = sizeof(tmp);

			} else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
			    && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
				memcpy(&tmp, (const void *)(addr), sizeof(tmp));
				copied = sizeof(tmp);

			} else if (addr >= FIXED_CODE_START
			    && addr + sizeof(tmp) <= FIXED_CODE_END) {
				copy_from_user_page(0, 0, 0, &tmp, (const void *)(addr), sizeof(tmp));
				copied = sizeof(tmp);

			} else
				copied = access_process_vm(child, addr, &tmp,
							   sizeof(tmp), 0);

			pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
			if (copied != sizeof(tmp))
				break;
			ret = put_user(tmp, datap);
			break;
		}

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR:
		{
			unsigned long tmp;
			ret = -EIO;
			tmp = 0;
			if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
				printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
				                    "0 - %x sizeof(pt_regs) is %lx\n",
				     (int)addr, sizeof(struct pt_regs));
				break;
			}
			if (addr == sizeof(struct pt_regs)) {
				/* PT_TEXT_ADDR */
				tmp = child->mm->start_code + TEXT_OFFSET;
			} else if (addr == (sizeof(struct pt_regs) + 4)) {
				/* PT_TEXT_END_ADDR */
				tmp = child->mm->end_code;
			} else if (addr == (sizeof(struct pt_regs) + 8)) {
				/* PT_DATA_ADDR */
				tmp = child->mm->start_data;
#ifdef CONFIG_BINFMT_ELF_FDPIC
			} else if (addr == (sizeof(struct pt_regs) + 12)) {
				tmp = child->mm->context.exec_fdpic_loadmap;
			} else if (addr == (sizeof(struct pt_regs) + 16)) {
				tmp = child->mm->context.interp_fdpic_loadmap;
#endif
			} else {
				tmp = get_reg(child, addr);
			}
			ret = put_user(tmp, datap);
			break;
		}

		/* when I and D space are separate, this will have to be fixed. */
	case PTRACE_POKEDATA:
		pr_debug("ptrace: PTRACE_PEEKDATA\n");
		/* fall through */
	case PTRACE_POKETEXT:	/* write the word at location addr. */
		{
			int copied;

			ret = -EIO;
			pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n",
			         addr, sizeof(data), data);
			if (is_user_addr_valid(child, addr, sizeof(data)) < 0)
				break;
			pr_debug("ptrace: user address is valid\n");

			if (L1_CODE_LENGTH != 0 && addr >= get_l1_code_start()
			    && addr + sizeof(data) <= get_l1_code_start() + L1_CODE_LENGTH) {
				safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
				copied = sizeof(data);

			} else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
			    && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
				memcpy((void *)(addr), &data, sizeof(data));
				copied = sizeof(data);

			} else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
			    && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
				memcpy((void *)(addr), &data, sizeof(data));
				copied = sizeof(data);

			} else if (addr >= FIXED_CODE_START
			    && addr + sizeof(data) <= FIXED_CODE_END) {
				copy_to_user_page(0, 0, 0, (void *)(addr), &data, sizeof(data));
				copied = sizeof(data);

			} else
				copied = access_process_vm(child, addr, &data,
							   sizeof(data), 1);

			pr_debug("ptrace: copied size %d\n", copied);
			if (copied != sizeof(data))
				break;
			ret = 0;
			break;
		}

	case PTRACE_POKEUSR:	/* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
			printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
			break;
		}

		if (addr >= (sizeof(struct pt_regs))) {
			ret = 0;
			break;
		}
		if (addr == PT_SYSCFG) {
			data &= SYSCFG_MASK;
			data |= get_reg(child, PT_SYSCFG);
		}
		ret = put_reg(child, addr, data);
		break;

	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
	case PTRACE_CONT:	/* restart after signal. */
		pr_debug("ptrace: syscall/cont\n");

		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;
		ptrace_disable(child);
		pr_debug("ptrace: before wake_up_process\n");
		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;
		ptrace_disable(child);
		wake_up_process(child);
		break;

	case PTRACE_SINGLESTEP:	/* set the trap flag. */
		pr_debug("ptrace: single step\n");
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		ptrace_enable(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

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

	case PTRACE_SETREGS:
		printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
		/* Set all gp regs in the child. */
		ret = 0;
		break;

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

	return ret;
}
コード例 #11
0
ファイル: ptrace.c プロジェクト: 420GrayFox/dsl-n55u-bender
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	unsigned long tmp;
	int ret;

	pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
		 request, child->pid, addr, data);

	pr_debug("ptrace: Enabling monitor mode...\n");
	__mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);

	switch (request) {
	/* Read the word at location addr in the child process */
	case PTRACE_PEEKTEXT:
	case PTRACE_PEEKDATA:
		ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		if (ret == sizeof(tmp))
			ret = put_user(tmp, (unsigned long __user *)data);
		else
			ret = -EIO;
		break;

	case PTRACE_PEEKUSR:
		ret = ptrace_read_user(child, addr,
				       (unsigned long __user *)data);
		break;

	/* Write the word in data at location addr */
	case PTRACE_POKETEXT:
	case PTRACE_POKEDATA:
		ret = access_process_vm(child, addr, &data, sizeof(data), 1);
		if (ret == sizeof(data))
			ret = 0;
		else
			ret = -EIO;
		break;

	case PTRACE_POKEUSR:
		ret = ptrace_write_user(child, addr, data);
		break;

	/* continue and stop at next (return from) syscall */
	case PTRACE_SYSCALL:
	/* restart after signal */
	case PTRACE_CONT:
		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;
		/* XXX: Are we sure no breakpoints are active here? */
		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)
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

	/*
	 * execute single instruction.
	 */
	case PTRACE_SINGLESTEP:
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		ptrace_single_step(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

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

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, (void __user *)data);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, (const void __user *)data);
		break;

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

	pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
	return ret;
}
コード例 #12
0
ファイル: ptrace.c プロジェクト: PennPanda/linux-repo
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;
}
コード例 #13
0
ファイル: ptrace.c プロジェクト: 420GrayFox/dsl-n55u-bender
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	unsigned long tmp;
	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: {
		int copied;

		ret = -EIO;
		if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
			break;

		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
		if (copied != sizeof(tmp))
			break;

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

		/* read the word at location addr in the USER area. */
	case PTRACE_PEEKUSR: {
		tmp = 0;
		ret = -EIO;
		if ((addr & 3) || addr < 0)
			break;

		ret = 0;
		switch (addr >> 2) {
		case 0 ... PT__END - 1:
			tmp = get_reg(child, addr >> 2);
			break;

		case PT__END + 0:
			tmp = child->mm->end_code - child->mm->start_code;
			break;

		case PT__END + 1:
			tmp = child->mm->end_data - child->mm->start_data;
			break;

		case PT__END + 2:
			tmp = child->mm->start_stack - child->mm->start_brk;
			break;

		case PT__END + 3:
			tmp = child->mm->start_code;
			break;

		case PT__END + 4:
			tmp = child->mm->start_stack;
			break;

		default:
			ret = -EIO;
			break;
		}

		if (ret == 0)
			ret = put_user(tmp, (unsigned long *) data);
		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 = -EIO;
		if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
			break;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
			break;
		ret = 0;
		break;

	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
		ret = -EIO;
		if ((addr & 3) || addr < 0)
			break;

		ret = 0;
		switch (addr >> 2) {
		case 0 ... PT__END-1:
			ret = put_reg(child, addr >> 2, data);
			break;

		default:
			ret = -EIO;
			break;
		}
		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;
		ptrace_disable(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;
		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
		ptrace_disable(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);
		ptrace_enable(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

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

	case PTRACE_GETREGS: { /* Get all integer regs from the child. */
		int i;
		for (i = 0; i < PT__GPEND; i++) {
			tmp = get_reg(child, i);
			if (put_user(tmp, (unsigned long *) data)) {
				ret = -EFAULT;
				break;
			}
			data += sizeof(long);
		}
		ret = 0;
		break;
	}

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

	case PTRACE_GETFPREGS: { /* Get the child FP/Media state. */
		ret = 0;
		if (copy_to_user((void *) data,
				 &child->thread.user->f,
				 sizeof(child->thread.user->f)))
			ret = -EFAULT;
		break;
	}

	case PTRACE_SETFPREGS: { /* Set the child FP/Media state. */
		ret = 0;
		if (copy_from_user(&child->thread.user->f,
				   (void *) data,
				   sizeof(child->thread.user->f)))
			ret = -EFAULT;
		break;
	}

	case PTRACE_GETFDPIC:
		tmp = 0;
		switch (addr) {
		case PTRACE_GETFDPIC_EXEC:
			tmp = child->mm->context.exec_fdpic_loadmap;
			break;
		case PTRACE_GETFDPIC_INTERP:
			tmp = child->mm->context.interp_fdpic_loadmap;
			break;
		default:
			break;
		}

		ret = 0;
		if (put_user(tmp, (unsigned long *) data)) {
			ret = -EFAULT;
			break;
		}
		break;

	default:
		ret = -EIO;
		break;
	}
	return ret;
}
コード例 #14
0
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: {
		struct pt_regs *regs;
		unsigned long tmp = 0;

		regs = task_pt_regs(child);
		ret = 0;  /* Default return value. */

		switch (addr) {
		case 0 ... 31:
			tmp = regs->regs[addr];
			break;
		case PC:
			tmp = regs->cp0_epc;
			break;
		case CAUSE:
			tmp = regs->cp0_cause;
			break;
		case BADVADDR:
			tmp = regs->cp0_badvaddr;
			break;
		case MMHI:
			tmp = regs->hi;
			break;
		case MMLO:
			tmp = regs->lo;
			break;
		default:
			tmp = 0;
			ret = -EIO;
			goto out;
		}
		ret = put_user(tmp, (unsigned long __user *) data);
		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 = generic_ptrace_pokedata(child, addr, data);
		break;

	case PTRACE_POKEUSR: {
		struct pt_regs *regs;
		ret = 0;
		regs = task_pt_regs(child);

		switch (addr) {
		case 0 ... 31:
			regs->regs[addr] = data;
			break;
		case PC:
			regs->cp0_epc = data;
			break;
		case MMHI:
			regs->hi = data;
			break;
		case MMLO:
			regs->lo = data;
			break;
		default:
			/* The rest are not allowed. */
			ret = -EIO;
			break;
		}
		break;
		}

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, (__s64 __user *) data);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, (__s64 __user *) 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;
		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;
		wake_up_process(child);
		break;

	case PTRACE_GET_THREAD_AREA:
		ret = put_user(task_thread_info(child)->tp_value,
				(unsigned long __user *) data);
		break;

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
 out:
	return ret;
}
コード例 #15
0
ファイル: sys.c プロジェクト: BackupTheBerlios/tew632-brp-svn
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5)
{
    long error;

    error = security_task_prctl(option, arg2, arg3, arg4, arg5);
    if (error)
        return error;

    switch (option) {
    case PR_SET_PDEATHSIG:
        if (!valid_signal(arg2)) {
            error = -EINVAL;
            break;
        }
        current->pdeath_signal = arg2;
        break;
    case PR_GET_PDEATHSIG:
        error = put_user(current->pdeath_signal, (int __user *)arg2);
        break;
    case PR_GET_DUMPABLE:
        error = current->mm->dumpable;
        break;
    case PR_SET_DUMPABLE:
        if (arg2 < 0 || arg2 > 2) {
            error = -EINVAL;
            break;
        }
        current->mm->dumpable = arg2;
        break;

    case PR_SET_UNALIGN:
        error = SET_UNALIGN_CTL(current, arg2);
        break;
    case PR_GET_UNALIGN:
        error = GET_UNALIGN_CTL(current, arg2);
        break;
    case PR_SET_FPEMU:
        error = SET_FPEMU_CTL(current, arg2);
        break;
    case PR_GET_FPEMU:
        error = GET_FPEMU_CTL(current, arg2);
        break;
    case PR_SET_FPEXC:
        error = SET_FPEXC_CTL(current, arg2);
        break;
    case PR_GET_FPEXC:
        error = GET_FPEXC_CTL(current, arg2);
        break;
    case PR_GET_TIMING:
        error = PR_TIMING_STATISTICAL;
        break;
    case PR_SET_TIMING:
        if (arg2 == PR_TIMING_STATISTICAL)
            error = 0;
        else
            error = -EINVAL;
        break;

    case PR_GET_KEEPCAPS:
        if (current->keep_capabilities)
            error = 1;
        break;
    case PR_SET_KEEPCAPS:
        if (arg2 != 0 && arg2 != 1) {
            error = -EINVAL;
            break;
        }
        current->keep_capabilities = arg2;
        break;
    case PR_SET_NAME: {
        struct task_struct *me = current;
        unsigned char ncomm[sizeof(me->comm)];

        ncomm[sizeof(me->comm)-1] = 0;
        if (strncpy_from_user(ncomm, (char __user *)arg2,
                              sizeof(me->comm)-1) < 0)
            return -EFAULT;
        set_task_comm(me, ncomm);
        return 0;
    }
    case PR_GET_NAME: {
        struct task_struct *me = current;
        unsigned char tcomm[sizeof(me->comm)];

        get_task_comm(tcomm, me);
        if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
            return -EFAULT;
        return 0;
    }
    default:
        error = -EINVAL;
        break;
    }
    return error;
}
コード例 #16
0
ファイル: ptrace.c プロジェクト: PennPanda/linux-repo
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	int ret;

	pr_debug("ptrace: Enabling monitor mode...\n");
	ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
			| (1 << OCD_DC_DBE_BIT));

	switch (request) {
	/* Read the word at location addr in the child process */
	case PTRACE_PEEKTEXT:
	case PTRACE_PEEKDATA:
		ret = generic_ptrace_peekdata(child, addr, data);
		break;

	case PTRACE_PEEKUSR:
		ret = ptrace_read_user(child, addr,
				       (unsigned long __user *)data);
		break;

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

	case PTRACE_POKEUSR:
		ret = ptrace_write_user(child, addr, data);
		break;

	/* continue and stop at next (return from) syscall */
	case PTRACE_SYSCALL:
	/* restart after signal */
	case PTRACE_CONT:
		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;
		/* XXX: Are we sure no breakpoints are active here? */
		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)
			break;
		child->exit_code = SIGKILL;
		wake_up_process(child);
		break;

	/*
	 * execute single instruction.
	 */
	case PTRACE_SINGLESTEP:
		ret = -EIO;
		if (!valid_signal(data))
			break;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		ptrace_single_step(child);
		child->exit_code = data;
		wake_up_process(child);
		ret = 0;
		break;

	case PTRACE_GETREGS:
		ret = ptrace_getregs(child, (void __user *)data);
		break;

	case PTRACE_SETREGS:
		ret = ptrace_setregs(child, (const void __user *)data);
		break;

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

	return ret;
}
コード例 #17
0
ファイル: ptrace.c プロジェクト: ivucica/linux
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: {
		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 __user *) 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;

#ifdef CONFIG_PPC32
		CHECK_FULL_REGS(child->thread.regs);
#endif
		if (index < PT_FPR0) {
			tmp = 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 = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
				== sizeof(data))
			break;
		ret = -EIO;
		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;

#ifdef CONFIG_PPC32
		CHECK_FULL_REGS(child->thread.regs);
#endif
		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = 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;
	}

#ifdef CONFIG_PPC64
	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;
#endif

	case PTRACE_DETACH:
		ret = ptrace_detach(child, data);
		break;

	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		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. */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(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 */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(child);
		ret = set_evrregs(child, (unsigned long __user *)data);
		break;
#endif

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

	return ret;
}
コード例 #18
0
ファイル: ptrace.c プロジェクト: chunyenho/RTS-hw2
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;
}
コード例 #19
0
ファイル: ptrace.c プロジェクト: kzlin129/tt-gpl
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -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;

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

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	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 __user *) data);
		break;
	}

	/* read the word at location addr in the USER area. */
	/* XXX this will need fixing for 64-bit */
	case PTRACE_PEEKUSR: {
		unsigned long index, tmp;

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

		CHECK_FULL_REGS(child->thread.regs);
		if (index < PT_FPR0) {
			tmp = get_reg(child, (int) index);
		} else {
			preempt_disable();
			if (child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			preempt_enable();
			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 = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
			break;
		ret = -EIO;
		break;

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

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

		CHECK_FULL_REGS(child->thread.regs);
		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = put_reg(child, index, data);
		} else {
			preempt_disable();
			if (child->thread.regs->msr & MSR_FP)
				giveup_fpu(child);
			preempt_enable();
			((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_DETACH:
		ret = ptrace_detach(child, data);
		break;

#ifdef CONFIG_ALTIVEC
	case PTRACE_GETVRREGS:
		/* Get the child altivec register state. */
		preempt_disable();
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		preempt_enable();
		ret = get_vrregs((unsigned long __user *)data, child);
		break;

	case PTRACE_SETVRREGS:
		/* Set the child altivec register state. */
		/* this is to clear the MSR_VEC bit to force a reload
		 * of register state from memory */
		preempt_disable();
		if (child->thread.regs->msr & MSR_VEC)
			giveup_altivec(child);
		preempt_enable();
		ret = set_vrregs(child, (unsigned long __user *)data);
		break;
#endif
#ifdef CONFIG_SPE
	case PTRACE_GETEVRREGS:
		/* Get the child spe register state. */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(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 */
		if (child->thread.regs->msr & MSR_SPE)
			giveup_spe(child);
		ret = set_evrregs(child, (unsigned long __user *)data);
		break;
#endif

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
コード例 #20
0
ファイル: ptrace.c プロジェクト: 1x23/unifi-gpl
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) {
		/* Read word at location address. */
		case PTRACE_PEEKTEXT:
		case PTRACE_PEEKDATA: {
			unsigned long tmp;
			int copied;

			ret = -EIO;

			/* The signal trampoline page is outside the normal user-addressable
			 * space but still accessible. This is hack to make it possible to
			 * access the signal handler code in GDB.
			 */
			if ((addr & PAGE_MASK) == cris_signal_return_page) {
				/* The trampoline page is globally mapped, no page table to traverse.*/
				tmp = *(unsigned long*)addr;
			} else {
				copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);

				if (copied != sizeof(tmp))
					break;
			}

			ret = put_user(tmp,datap);
			break;
		}

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

			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			tmp = get_reg(child, addr >> 2);
			ret = put_user(tmp, datap);
			break;
		}

		/* Write the word at location address. */
		case PTRACE_POKETEXT:
		case PTRACE_POKEDATA:
			ret = 0;

			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;

			ret = -EIO;
			break;

 		/* Write the word at location address in the USER area. */
		case PTRACE_POKEUSR:
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			addr >>= 2;

			if (addr == PT_CCS) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
				data &= CCS_MASK;
				data |= get_reg(child, PT_CCS) & ~CCS_MASK;
			}
			if (put_reg(child, addr, data))
				break;
			ret = 0;
			break;

		case PTRACE_SYSCALL:
		case PTRACE_CONT:
			ret = -EIO;

			if (!valid_signal(data))
				break;

			/* Continue means no single-step. */
			put_reg(child, PT_SPC, 0);

			if (!get_debugreg(child->pid, PT_BP_CTRL)) {
				unsigned long tmp;
				/* If no h/w bp configured, disable S bit. */
				tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
				put_reg(child, PT_CCS, tmp);
			}

			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;

			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			ret = 0;

			break;

 		/* Make the child exit by sending it a sigkill. */
		case PTRACE_KILL:
			ret = 0;

			if (child->exit_state == EXIT_ZOMBIE)
				break;

			child->exit_code = SIGKILL;

			/* Deconfigure single-step and h/w bp. */
			ptrace_disable(child);

			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			break;

		/* Set the trap flag. */
		case PTRACE_SINGLESTEP:	{
			unsigned long tmp;
			ret = -EIO;

			/* Set up SPC if not set already (in which case we have
			   no other choice but to trust it). */
			if (!get_reg(child, PT_SPC)) {
				/* In case we're stopped in a delay slot. */
				tmp = get_reg(child, PT_ERP) & ~1;
				put_reg(child, PT_SPC, tmp);
			}
			tmp = get_reg(child, PT_CCS) | SBIT_USER;
			put_reg(child, PT_CCS, tmp);

			if (!valid_signal(data))
				break;

			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			/* TODO: set some clever breakpoint mechanism... */

			child->exit_code = data;
			wake_up_process(child);
			ret = 0;
			break;

		}
		case PTRACE_DETACH:
			ret = ptrace_detach(child, data);
			break;

		/* Get all GP registers from the child. */
		case PTRACE_GETREGS: {
		  	int i;
			unsigned long tmp;

			for (i = 0; i <= PT_MAX; i++) {
				tmp = get_reg(child, i);

				if (put_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}

				datap++;
			}

			ret = 0;
			break;
		}

		/* Set all GP registers in the child. */
		case PTRACE_SETREGS: {
			int i;
			unsigned long tmp;

			for (i = 0; i <= PT_MAX; i++) {
				if (get_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}

				if (i == PT_CCS) {
					tmp &= CCS_MASK;
					tmp |= get_reg(child, PT_CCS) & ~CCS_MASK;
				}

				put_reg(child, i, tmp);
				datap++;
			}

			ret = 0;
			break;
		}

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

	return ret;
}
コード例 #21
0
ファイル: ptrace.c プロジェクト: 7LK/McWRT
/*
 * 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;
}
コード例 #22
0
ファイル: ptrace.c プロジェクト: ForayJones/iods
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
	long ret;
#ifdef DEBUG_PTRACE
	long oaddr=addr, odata=data;
#endif

	switch (request) {
	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
	case PTRACE_PEEKDATA: {
#ifdef CONFIG_64BIT
		if (__is_compat_task(child)) {
			int copied;
			unsigned int tmp;

			addr &= 0xffffffffL;
			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
			ret = -EIO;
			if (copied != sizeof(tmp))
				goto out_tsk;
			ret = put_user(tmp,(unsigned int *) data);
			DBG("sys_ptrace(PEEK%s, %d, %lx, %lx) returning %ld, data %x\n",
				request == PTRACE_PEEKTEXT ? "TEXT" : "DATA",
				pid, oaddr, odata, ret, tmp);
		}
		else
#endif
			ret = generic_ptrace_peekdata(child, addr, data);
		goto out_tsk;
	}

	/* 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;
#ifdef CONFIG_64BIT
		if (__is_compat_task(child)) {
			unsigned int tmp = (unsigned int)data;
			DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
				request == PTRACE_POKETEXT ? "TEXT" : "DATA",
				pid, oaddr, odata);
			addr &= 0xffffffffL;
			if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) == sizeof(tmp))
				goto out_tsk;
		}
		else
#endif
		{
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				goto out_tsk;
		}
		ret = -EIO;
		goto out_tsk;

	/* Read the word at location addr in the USER area.  For ptraced
	   processes, the kernel saves all regs on a syscall. */
	case PTRACE_PEEKUSR: {
		ret = -EIO;
#ifdef CONFIG_64BIT
		if (__is_compat_task(child)) {
			unsigned int tmp;

			if (addr & (sizeof(int)-1))
				goto out_tsk;
			if ((addr = translate_usr_offset(addr)) < 0)
				goto out_tsk;

			tmp = *(unsigned int *) ((char *) task_regs(child) + addr);
			ret = put_user(tmp, (unsigned int *) data);
			DBG("sys_ptrace(PEEKUSR, %d, %lx, %lx) returning %ld, addr %lx, data %x\n",
				pid, oaddr, odata, ret, addr, tmp);
		}
		else
#endif
		{
			unsigned long tmp;

			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
				goto out_tsk;
			tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
			ret = put_user(tmp, (unsigned long *) data);
		}
		goto out_tsk;
	}

	/* Write the word at location addr in the USER area.  This will need
	   to change when the kernel no longer saves all regs on a syscall.
	   FIXME.  There is a problem at the moment in that r3-r18 are only
	   saved if the process is ptraced on syscall entry, and even then
	   those values are overwritten by actual register values on syscall
	   exit. */
	case PTRACE_POKEUSR:
		ret = -EIO;
		/* Some register values written here may be ignored in
		 * entry.S:syscall_restore_rfi; e.g. iaoq is written with
		 * r31/r31+4, and not with the values in pt_regs.
		 */
		 /* PT_PSW=0, so this is valid for 32 bit processes under 64
		 * bit kernels.
		 */
		if (addr == PT_PSW) {
			/* PT_PSW=0, so this is valid for 32 bit processes
			 * under 64 bit kernels.
			 *
			 * Allow writing to Nullify, Divide-step-correction,
			 * and carry/borrow bits.
			 * BEWARE, if you set N, and then single step, it won't
			 * stop on the nullified instruction.
			 */
			DBG("sys_ptrace(POKEUSR, %d, %lx, %lx)\n",
				pid, oaddr, odata);
			data &= USER_PSW_BITS;
			task_regs(child)->gr[0] &= ~USER_PSW_BITS;
			task_regs(child)->gr[0] |= data;
			ret = 0;
			goto out_tsk;
		}
#ifdef CONFIG_64BIT
		if (__is_compat_task(child)) {
			if (addr & (sizeof(int)-1))
				goto out_tsk;
			if ((addr = translate_usr_offset(addr)) < 0)
				goto out_tsk;
			DBG("sys_ptrace(POKEUSR, %d, %lx, %lx) addr %lx\n",
				pid, oaddr, odata, addr);
			if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
				/* Special case, fp regs are 64 bits anyway */
				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
					addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
					addr == PT_SAR+4) {
				/* Zero the top 32 bits */
				*(unsigned int *) ((char *) task_regs(child) + addr - 4) = 0;
				*(unsigned int *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			goto out_tsk;
		}
		else
#endif
		{
			if ((addr & (sizeof(long)-1)) || (unsigned long) addr >= sizeof(struct pt_regs))
				goto out_tsk;
			if ((addr >= PT_GR1 && addr <= PT_GR31) ||
					addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
					(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
					addr == PT_SAR) {
				*(unsigned long *) ((char *) task_regs(child) + addr) = data;
				ret = 0;
			}
			goto out_tsk;
		}

	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
	case PTRACE_CONT:
		ret = -EIO;
		DBG("sys_ptrace(%s)\n",
			request == PTRACE_SYSCALL ? "SYSCALL" : "CONT");
		if (!valid_signal(data))
			goto out_tsk;
		child->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
		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;
		goto out_wake_notrap;

	case PTRACE_KILL:
		/*
		 * 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.
		 */
		ret = 0;
		DBG("sys_ptrace(KILL)\n");
		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
			goto out_tsk;
		child->exit_code = SIGKILL;
		goto out_wake_notrap;

	case PTRACE_SINGLEBLOCK:
		DBG("sys_ptrace(SINGLEBLOCK)\n");
		ret = -EIO;
		if (!valid_signal(data))
			goto out_tsk;
		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->ptrace &= ~PT_SINGLESTEP;
		child->ptrace |= PT_BLOCKSTEP;
		child->exit_code = data;

		/* Enable taken branch trap. */
		pa_psw(child)->r = 0;
		pa_psw(child)->t = 1;
		pa_psw(child)->h = 0;
		pa_psw(child)->l = 0;
		goto out_wake;

	case PTRACE_SINGLESTEP:
		DBG("sys_ptrace(SINGLESTEP)\n");
		ret = -EIO;
		if (!valid_signal(data))
			goto out_tsk;

		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
		child->ptrace &= ~PT_BLOCKSTEP;
		child->ptrace |= PT_SINGLESTEP;
		child->exit_code = data;

		if (pa_psw(child)->n) {
			struct siginfo si;

			/* Nullified, just crank over the queue. */
			task_regs(child)->iaoq[0] = task_regs(child)->iaoq[1];
			task_regs(child)->iasq[0] = task_regs(child)->iasq[1];
			task_regs(child)->iaoq[1] = task_regs(child)->iaoq[0] + 4;
			pa_psw(child)->n = 0;
			pa_psw(child)->x = 0;
			pa_psw(child)->y = 0;
			pa_psw(child)->z = 0;
			pa_psw(child)->b = 0;
			ptrace_disable(child);
			/* Don't wake up the child, but let the
			   parent know something happened. */
			si.si_code = TRAP_TRACE;
			si.si_addr = (void __user *) (task_regs(child)->iaoq[0] & ~3);
			si.si_signo = SIGTRAP;
			si.si_errno = 0;
			force_sig_info(SIGTRAP, &si, child);
			//notify_parent(child, SIGCHLD);
			//ret = 0;
			goto out_wake;
		}

		/* Enable recovery counter traps.  The recovery counter
		 * itself will be set to zero on a task switch.  If the
		 * task is suspended on a syscall then the syscall return
		 * path will overwrite the recovery counter with a suitable
		 * value such that it traps once back in user space.  We
		 * disable interrupts in the childs PSW here also, to avoid
		 * interrupts while the recovery counter is decrementing.
		 */
		pa_psw(child)->r = 1;
		pa_psw(child)->t = 0;
		pa_psw(child)->h = 0;
		pa_psw(child)->l = 0;
		/* give it a chance to run. */
		goto out_wake;

	case PTRACE_GETEVENTMSG:
                ret = put_user(child->ptrace_message, (unsigned int __user *) data);
		goto out_tsk;

	default:
		ret = ptrace_request(child, request, addr, data);
		goto out_tsk;
	}

out_wake_notrap:
	ptrace_disable(child);
out_wake:
	wake_up_process(child);
	ret = 0;
out_tsk:
	DBG("arch_ptrace(%ld, %d, %lx, %lx) returning %ld\n",
		request, pid, oaddr, odata, ret);
	return ret;
}
コード例 #23
0
ファイル: sys.c プロジェクト: maraz/linux-2.6
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
			  unsigned long arg4, unsigned long arg5)
{
	long error = 0;

	if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
		return error;

	switch (option) {
		case PR_SET_PDEATHSIG:
			if (!valid_signal(arg2)) {
				error = -EINVAL;
				break;
			}
			current->pdeath_signal = arg2;
			break;
		case PR_GET_PDEATHSIG:
			error = put_user(current->pdeath_signal, (int __user *)arg2);
			break;
		case PR_GET_DUMPABLE:
			error = get_dumpable(current->mm);
			break;
		case PR_SET_DUMPABLE:
			if (arg2 < 0 || arg2 > 1) {
				error = -EINVAL;
				break;
			}
			set_dumpable(current->mm, arg2);
			break;

		case PR_SET_UNALIGN:
			error = SET_UNALIGN_CTL(current, arg2);
			break;
		case PR_GET_UNALIGN:
			error = GET_UNALIGN_CTL(current, arg2);
			break;
		case PR_SET_FPEMU:
			error = SET_FPEMU_CTL(current, arg2);
			break;
		case PR_GET_FPEMU:
			error = GET_FPEMU_CTL(current, arg2);
			break;
		case PR_SET_FPEXC:
			error = SET_FPEXC_CTL(current, arg2);
			break;
		case PR_GET_FPEXC:
			error = GET_FPEXC_CTL(current, arg2);
			break;
		case PR_GET_TIMING:
			error = PR_TIMING_STATISTICAL;
			break;
		case PR_SET_TIMING:
			if (arg2 != PR_TIMING_STATISTICAL)
				error = -EINVAL;
			break;

		case PR_SET_NAME: {
			struct task_struct *me = current;
			unsigned char ncomm[sizeof(me->comm)];

			ncomm[sizeof(me->comm)-1] = 0;
			if (strncpy_from_user(ncomm, (char __user *)arg2,
						sizeof(me->comm)-1) < 0)
				return -EFAULT;
			set_task_comm(me, ncomm);
			return 0;
		}
		case PR_GET_NAME: {
			struct task_struct *me = current;
			unsigned char tcomm[sizeof(me->comm)];

			get_task_comm(tcomm, me);
			if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
				return -EFAULT;
			return 0;
		}
		case PR_GET_ENDIAN:
			error = GET_ENDIAN(current, arg2);
			break;
		case PR_SET_ENDIAN:
			error = SET_ENDIAN(current, arg2);
			break;

		case PR_GET_SECCOMP:
			error = prctl_get_seccomp();
			break;
		case PR_SET_SECCOMP:
			error = prctl_set_seccomp(arg2);
			break;
		case PR_GET_TSC:
			error = GET_TSC_CTL(arg2);
			break;
		case PR_SET_TSC:
			error = SET_TSC_CTL(arg2);
			break;
		default:
			error = -EINVAL;
			break;
	}
	return error;
}
コード例 #24
0
ファイル: ptrace.c プロジェクト: kzlin129/tt-gpl
int sys_ptrace(long request, long pid, long addr, long data)
{
	struct task_struct *child;
	int ret = -EPERM;

	lock_kernel();
	if (request == PTRACE_TRACEME) {
		/* are we already being traced? */
		if (current->ptrace & PT_PTRACED)
			goto out;
		ret = security_ptrace(current->parent, current);
		if (ret)
			goto out;
		/* set the ptrace bit in the process flags. */
		current->ptrace |= PT_PTRACED;
		ret = 0;
		goto out;
	}
	ret = -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;

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

	if (request == PTRACE_ATTACH) {
		ret = ptrace_attach(child);
		goto out_tsk;
	}

	ret = ptrace_check_attach(child, request == PTRACE_KILL);
	if (ret < 0)
		goto out_tsk;

	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 __user *) data);
		break;
	}

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

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index < PT_FPR0) {
			tmp = 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 = 0;
		if (access_process_vm(child, addr, &data, sizeof(data), 1)
				== sizeof(data))
			break;
		ret = -EIO;
		break;

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

		ret = -EIO;
		/* convert to index and check */
		index = (unsigned long) addr >> 3;
		if ((addr & 7) || (index > PT_FPSCR))
			break;

		if (index == PT_ORIG_R3)
			break;
		if (index < PT_FPR0) {
			ret = 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_DETACH:
		ret = ptrace_detach(child, data);
		break;

	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = put_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
		int i;
		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
		unsigned long __user *tmp = (unsigned long __user *)addr;

		flush_fp_to_thread(child);

		for (i = 0; i < 32; i++) {
			ret = get_user(*reg, tmp);
			if (ret)
				break;
			reg++;
			tmp++;
		}
		break;
	}

	default:
		ret = ptrace_request(child, request, addr, data);
		break;
	}
out_tsk:
	put_task_struct(child);
out:
	unlock_kernel();
	return ret;
}
コード例 #25
0
ファイル: ptrace.c プロジェクト: 1x23/unifi-gpl
/* 
 * Note that this implementation of ptrace behaves differently from vanilla
 * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
 * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
 * ignored.  Instead, the data variable is expected to point at a location
 * (in user space) where the result of the ptrace call is written (instead of
 * being returned).
 */
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) {
		/* Read word at location address. */ 
		case PTRACE_PEEKTEXT:
		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,datap);
			break;
		}

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

			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			tmp = get_reg(child, addr >> 2);
			ret = put_user(tmp, datap);
			break;
		}
		
		/* Write the word at location address. */
		case PTRACE_POKETEXT:
		case PTRACE_POKEDATA:
			ret = 0;
			
			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
				break;
			
			ret = -EIO;
			break;
 
 		/* Write the word at location address in the USER area. */
		case PTRACE_POKEUSR:
			ret = -EIO;
			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
				break;

			addr >>= 2;

			if (addr == PT_DCCR) {
				/* don't allow the tracing process to change stuff like
				 * interrupt enable, kernel/user bit, dma enables etc.
				 */
				data &= DCCR_MASK;
				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
			}
			if (put_reg(child, addr, data))
				break;
			ret = 0;
			break;

		case PTRACE_SYSCALL:
		case PTRACE_CONT:
			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;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			ret = 0;
			
			break;
		
 		/* Make the child exit by sending it a sigkill. */
		case PTRACE_KILL:
			ret = 0;
			
			if (child->exit_state == EXIT_ZOMBIE)
				break;
			
			child->exit_code = SIGKILL;
			
			/* TODO: make sure any pending breakpoint is killed */
			wake_up_process(child);
			break;

		/* Set the trap flag. */
		case PTRACE_SINGLESTEP:
			ret = -EIO;
			
			if (!valid_signal(data))
				break;
			
			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);

			/* TODO: set some clever breakpoint mechanism... */

			child->exit_code = data;
			wake_up_process(child);
			ret = 0;
			break;

		case PTRACE_DETACH:
			ret = ptrace_detach(child, data);
			break;

		/* Get all GP registers from the child. */
		case PTRACE_GETREGS: {
		  	int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				tmp = get_reg(child, i);
				
				if (put_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				data += sizeof(long);
			}

			ret = 0;
			break;
		}

		/* Set all GP registers in the child. */
		case PTRACE_SETREGS: {
			int i;
			unsigned long tmp;
			
			for (i = 0; i <= PT_MAX; i++) {
				if (get_user(tmp, datap)) {
					ret = -EFAULT;
					goto out_tsk;
				}
				
				if (i == PT_DCCR) {
					tmp &= DCCR_MASK;
					tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
				}
				
				put_reg(child, i, tmp);
				data += sizeof(long);
			}
			
			ret = 0;
			break;
		}

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

	return ret;
}
コード例 #26
0
long sys_ptrace(long request, long pid, long addr, long data)
{
    struct task_struct *child;
    int i, ret;

    lock_kernel();
    ret = -EPERM;
    if (request == PTRACE_TRACEME) {
        /* are we already being traced? */
        if (current->ptrace & PT_PTRACED)
            goto out;

        ret = security_ptrace(current->parent, current);
        if (ret)
            goto out;

        /* set the ptrace bit in the process flags. */
        current->ptrace |= PT_PTRACED;
        ret = 0;
        goto out;
    }
    ret = -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;

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

    if (request == PTRACE_ATTACH) {
        ret = ptrace_attach(child);
        goto out_tsk;
    }

#ifdef SUBACH_PTRACE_SPECIAL
    SUBARCH_PTRACE_SPECIAL(child,request,addr,data);
#endif

    ret = ptrace_check_attach(child, request == PTRACE_KILL);
    if (ret < 0)
        goto out_tsk;

    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;

        ret = -EIO;
        copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
        if (copied != sizeof(tmp))
            break;
        ret = put_user(tmp, (unsigned long __user *) data);
        break;
    }

    /* read the word at location addr in the USER area. */
    case PTRACE_PEEKUSR:
        ret = peek_user(child, addr, data);
        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 = -EIO;
        if (access_process_vm(child, addr, &data, sizeof(data),
                              1) != sizeof(data))
            break;
        ret = 0;
        break;

    case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
        ret = poke_user(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;

        set_singlestepping(child, 0);
        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;
        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;

        set_singlestepping(child, 0);
        child->exit_code = SIGKILL;
        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_singlestepping(child, 1);
        child->exit_code = data;
        /* give it a chance to run. */
        wake_up_process(child);
        ret = 0;
        break;
    }

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

#ifdef PTRACE_GETREGS
    case PTRACE_GETREGS: { /* Get all gp regs from the child. */
        if (!access_ok(VERIFY_WRITE, (unsigned long *)data,
                       MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __put_user(getreg(child, i),
                       (unsigned long __user *) data);
            data += sizeof(long);
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_SETREGS
    case PTRACE_SETREGS: { /* Set all gp regs in the child. */
        unsigned long tmp = 0;
        if (!access_ok(VERIFY_READ, (unsigned *)data,
                       MAX_REG_OFFSET)) {
            ret = -EIO;
            break;
        }
        for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
            __get_user(tmp, (unsigned long __user *) data);
            putreg(child, i, tmp);
            data += sizeof(long);
        }
        ret = 0;
        break;
    }
#endif
#ifdef PTRACE_GETFPREGS
    case PTRACE_GETFPREGS: /* Get the child FPU state. */
        ret = get_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPREGS
    case PTRACE_SETFPREGS: /* Set the child FPU state. */
        ret = set_fpregs(data, child);
        break;
#endif
#ifdef PTRACE_GETFPXREGS
    case PTRACE_GETFPXREGS: /* Get the child FPU state. */
        ret = get_fpxregs(data, child);
        break;
#endif
#ifdef PTRACE_SETFPXREGS
    case PTRACE_SETFPXREGS: /* Set the child FPU state. */
        ret = set_fpxregs(data, child);
        break;
#endif
    case PTRACE_FAULTINFO: {
        /* Take the info from thread->arch->faultinfo,
         * but transfer max. sizeof(struct ptrace_faultinfo).
         * On i386, ptrace_faultinfo is smaller!
         */
        ret = copy_to_user((unsigned long __user *) data,
                           &child->thread.arch.faultinfo,
                           sizeof(struct ptrace_faultinfo));
        if(ret)
            break;
        break;
    }

#ifdef PTRACE_LDT
    case PTRACE_LDT: {
        struct ptrace_ldt ldt;

        if(copy_from_user(&ldt, (unsigned long __user *) data,
                          sizeof(ldt))) {
            ret = -EIO;
            break;
        }

        /* This one is confusing, so just punt and return -EIO for
         * now
         */
        ret = -EIO;
        break;
    }
#endif
#ifdef CONFIG_PROC_MM
    case PTRACE_SWITCH_MM: {
        struct mm_struct *old = child->mm;
        struct mm_struct *new = proc_mm_get_mm(data);

        if(IS_ERR(new)) {
            ret = PTR_ERR(new);
            break;
        }

        atomic_inc(&new->mm_users);
        child->mm = new;
        child->active_mm = new;
        mmput(old);
        ret = 0;
        break;
    }
#endif
    default:
        ret = ptrace_request(child, request, addr, data);
        break;
    }
out_tsk:
    put_task_struct(child);
out:
    unlock_kernel();
    return ret;
}