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