linux/arch/unicore32/kernel/ptrace.c
<<
>>
Prefs
   1/*
   2 * linux/arch/unicore32/kernel/ptrace.c
   3 *
   4 * Code specific to PKUnity SoC and UniCore ISA
   5 *
   6 * Copyright (C) 2001-2010 GUAN Xue-tao
   7 *
   8 * By Ross Biro 1/23/92
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14#include <linux/kernel.h>
  15#include <linux/ptrace.h>
  16#include <linux/signal.h>
  17#include <linux/uaccess.h>
  18
  19/*
  20 * this routine will get a word off of the processes privileged stack.
  21 * the offset is how far from the base addr as stored in the THREAD.
  22 * this routine assumes that all the privileged stacks are in our
  23 * data space.
  24 */
  25static inline long get_user_reg(struct task_struct *task, int offset)
  26{
  27        return task_pt_regs(task)->uregs[offset];
  28}
  29
  30/*
  31 * this routine will put a word on the processes privileged stack.
  32 * the offset is how far from the base addr as stored in the THREAD.
  33 * this routine assumes that all the privileged stacks are in our
  34 * data space.
  35 */
  36static inline int
  37put_user_reg(struct task_struct *task, int offset, long data)
  38{
  39        struct pt_regs newregs, *regs = task_pt_regs(task);
  40        int ret = -EINVAL;
  41
  42        newregs = *regs;
  43        newregs.uregs[offset] = data;
  44
  45        if (valid_user_regs(&newregs)) {
  46                regs->uregs[offset] = data;
  47                ret = 0;
  48        }
  49
  50        return ret;
  51}
  52
  53/*
  54 * Called by kernel/ptrace.c when detaching..
  55 */
  56void ptrace_disable(struct task_struct *child)
  57{
  58}
  59
  60/*
  61 * We actually access the pt_regs stored on the kernel stack.
  62 */
  63static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
  64                            unsigned long __user *ret)
  65{
  66        unsigned long tmp;
  67
  68        tmp = 0;
  69        if (off < sizeof(struct pt_regs))
  70                tmp = get_user_reg(tsk, off >> 2);
  71
  72        return put_user(tmp, ret);
  73}
  74
  75/*
  76 * We actually access the pt_regs stored on the kernel stack.
  77 */
  78static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
  79                             unsigned long val)
  80{
  81        if (off >= sizeof(struct pt_regs))
  82                return 0;
  83
  84        return put_user_reg(tsk, off >> 2, val);
  85}
  86
  87long arch_ptrace(struct task_struct *child, long request,
  88                 unsigned long addr, unsigned long data)
  89{
  90        int ret;
  91        unsigned long __user *datap = (unsigned long __user *) data;
  92
  93        switch (request) {
  94        case PTRACE_PEEKUSR:
  95                ret = ptrace_read_user(child, addr, datap);
  96                break;
  97
  98        case PTRACE_POKEUSR:
  99                ret = ptrace_write_user(child, addr, data);
 100                break;
 101
 102        case PTRACE_GET_THREAD_AREA:
 103                ret = put_user(task_pt_regs(child)->UCreg_16,
 104                               datap);
 105                break;
 106
 107        default:
 108                ret = ptrace_request(child, request, addr, data);
 109                break;
 110        }
 111
 112        return ret;
 113}
 114
 115asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 116{
 117        unsigned long ip;
 118
 119        if (!test_thread_flag(TIF_SYSCALL_TRACE))
 120                return scno;
 121        if (!(current->ptrace & PT_PTRACED))
 122                return scno;
 123
 124        /*
 125         * Save IP.  IP is used to denote syscall entry/exit:
 126         *  IP = 0 -> entry, = 1 -> exit
 127         */
 128        ip = regs->UCreg_ip;
 129        regs->UCreg_ip = why;
 130
 131        current_thread_info()->syscall = scno;
 132
 133        /* the 0x80 provides a way for the tracing parent to distinguish
 134           between a syscall stop and SIGTRAP delivery */
 135        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 136                                 ? 0x80 : 0));
 137        /*
 138         * this isn't the same as continuing with a signal, but it will do
 139         * for normal use.  strace only continues with a signal if the
 140         * stopping signal is not SIGTRAP.  -brl
 141         */
 142        if (current->exit_code) {
 143                send_sig(current->exit_code, current, 1);
 144                current->exit_code = 0;
 145        }
 146        regs->UCreg_ip = ip;
 147
 148        return current_thread_info()->syscall;
 149}
 150