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