root/arch/unicore32/kernel/ptrace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_user_reg
  2. put_user_reg
  3. ptrace_disable
  4. ptrace_read_user
  5. ptrace_write_user
  6. arch_ptrace
  7. syscall_trace

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

/* [<][>][^][v][top][bottom][index][help] */