~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/ppc/kernel/ptrace.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.12 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.55 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.136 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.191 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  arch/ppc/kernel/ptrace.c
  3  *
  4  *  PowerPC version
  5  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  6  *
  7  *  Derived from "arch/m68k/kernel/ptrace.c"
  8  *  Copyright (C) 1994 by Hamish Macdonald
  9  *  Taken from linux/kernel/ptrace.c and modified for M680x0.
 10  *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
 11  *
 12  * Modified by Cort Dougan (cort@hq.fsmlabs.com)
 13  * and Paul Mackerras (paulus@linuxcare.com.au).
 14  *
 15  * This file is subject to the terms and conditions of the GNU General
 16  * Public License.  See the file README.legal in the main directory of
 17  * this archive for more details.
 18  */
 19 
 20 #include <linux/kernel.h>
 21 #include <linux/sched.h>
 22 #include <linux/mm.h>
 23 #include <linux/smp.h>
 24 #include <linux/smp_lock.h>
 25 #include <linux/errno.h>
 26 #include <linux/ptrace.h>
 27 #include <linux/user.h>
 28 #include <linux/security.h>
 29 
 30 #include <asm/uaccess.h>
 31 #include <asm/page.h>
 32 #include <asm/pgtable.h>
 33 #include <asm/system.h>
 34 
 35 /*
 36  * Set of msr bits that gdb can change on behalf of a process.
 37  */
 38 #ifdef CONFIG_4xx
 39 #define MSR_DEBUGCHANGE 0
 40 #else
 41 #define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
 42 #endif
 43 
 44 /*
 45  * does not yet catch signals sent when the child dies.
 46  * in exit.c or in signal.c.
 47  */
 48 
 49 /*
 50  * Get contents of register REGNO in task TASK.
 51  */
 52 static inline unsigned long get_reg(struct task_struct *task, int regno)
 53 {
 54         if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
 55             && task->thread.regs != NULL)
 56                 return ((unsigned long *)task->thread.regs)[regno];
 57         return (0);
 58 }
 59 
 60 /*
 61  * Write contents of register REGNO in task TASK.
 62  */
 63 static inline int put_reg(struct task_struct *task, int regno,
 64                           unsigned long data)
 65 {
 66         if (regno <= PT_MQ && task->thread.regs != NULL) {
 67                 if (regno == PT_MSR)
 68                         data = (data & MSR_DEBUGCHANGE)
 69                                 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
 70                 ((unsigned long *)task->thread.regs)[regno] = data;
 71                 return 0;
 72         }
 73         return -EIO;
 74 }
 75 
 76 #ifdef CONFIG_ALTIVEC
 77 /*
 78  * Get contents of AltiVec register state in task TASK
 79  */
 80 static inline int get_vrregs(unsigned long *data, struct task_struct *task)
 81 {
 82         int i, j;
 83 
 84         if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
 85                 return -EFAULT;
 86 
 87         /* copy AltiVec registers VR[0] .. VR[31] */
 88         for (i = 0; i < 32; i++)
 89                 for (j = 0; j < 4; j++, data++)
 90                         if (__put_user(task->thread.vr[i].u[j], data))
 91                                 return -EFAULT;
 92 
 93         /* copy VSCR */
 94         for (i = 0; i < 4; i++, data++)
 95                 if (__put_user(task->thread.vscr.u[i], data))
 96                         return -EFAULT;
 97 
 98         /* copy VRSAVE */
 99         if (__put_user(task->thread.vrsave, data))
100                 return -EFAULT;
101 
102         return 0;
103 }
104 
105 /*
106  * Write contents of AltiVec register state into task TASK.
107  */
108 static inline int set_vrregs(struct task_struct *task, unsigned long *data)
109 {
110         int i, j;
111 
112         if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
113                 return -EFAULT;
114 
115         /* copy AltiVec registers VR[0] .. VR[31] */
116         for (i = 0; i < 32; i++)
117                 for (j = 0; j < 4; j++, data++)
118                         if (__get_user(task->thread.vr[i].u[j], data))
119                                 return -EFAULT;
120 
121         /* copy VSCR */
122         for (i = 0; i < 4; i++, data++)
123                 if (__get_user(task->thread.vscr.u[i], data))
124                         return -EFAULT;
125 
126         /* copy VRSAVE */
127         if (__get_user(task->thread.vrsave, data))
128                 return -EFAULT;
129 
130         return 0;
131 }
132 #endif
133 
134 static inline void
135 set_single_step(struct task_struct *task)
136 {
137         struct pt_regs *regs = task->thread.regs;
138 
139         if (regs != NULL) {
140 #ifdef CONFIG_4xx
141                 task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
142                 /* MSR.DE should already be set */
143 #else
144                 regs->msr |= MSR_SE;
145 #endif
146         }
147 }
148 
149 static inline void
150 clear_single_step(struct task_struct *task)
151 {
152         struct pt_regs *regs = task->thread.regs;
153 
154         if (regs != NULL) {
155 #ifdef CONFIG_4xx
156                 task->thread.dbcr0 = 0;
157 #else
158                 regs->msr &= ~MSR_SE;
159 #endif
160         }
161 }
162 
163 /*
164  * Called by kernel/ptrace.c when detaching..
165  *
166  * Make sure single step bits etc are not set.
167  */
168 void ptrace_disable(struct task_struct *child)
169 {
170         /* make sure the single step bit is not set. */
171         clear_single_step(child);
172 }
173 
174 int sys_ptrace(long request, long pid, long addr, long data)
175 {
176         struct task_struct *child;
177         int ret = -EPERM;
178 
179         lock_kernel();
180         if (request == PTRACE_TRACEME) {
181                 /* are we already being traced? */
182                 if (current->ptrace & PT_PTRACED)
183                         goto out;
184                 ret = security_ptrace(current->parent, current);
185                 if (ret)
186                         goto out;
187                 /* set the ptrace bit in the process flags. */
188                 current->ptrace |= PT_PTRACED;
189                 ret = 0;
190                 goto out;
191         }
192         ret = -ESRCH;
193         read_lock(&tasklist_lock);
194         child = find_task_by_pid(pid);
195         if (child)
196                 get_task_struct(child);
197         read_unlock(&tasklist_lock);
198         if (!child)
199                 goto out;
200 
201         ret = -EPERM;
202         if (pid == 1)           /* you may not mess with init */
203                 goto out_tsk;
204 
205         if (request == PTRACE_ATTACH) {
206                 ret = ptrace_attach(child);
207                 goto out_tsk;
208         }
209 
210         ret = ptrace_check_attach(child, request == PTRACE_KILL);
211         if (ret < 0)
212                 goto out_tsk;
213 
214         switch (request) {
215         /* when I and D space are separate, these will need to be fixed. */
216         case PTRACE_PEEKTEXT: /* read word at location addr. */
217         case PTRACE_PEEKDATA: {
218                 unsigned long tmp;
219                 int copied;
220 
221                 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
222                 ret = -EIO;
223                 if (copied != sizeof(tmp))
224                         break;
225                 ret = put_user(tmp,(unsigned long *) data);
226                 break;
227         }
228 
229         /* read the word at location addr in the USER area. */
230         /* XXX this will need fixing for 64-bit */
231         case PTRACE_PEEKUSR: {
232                 unsigned long index, tmp;
233 
234                 ret = -EIO;
235                 /* convert to index and check */
236                 index = (unsigned long) addr >> 2;
237                 if ((addr & 3) || index > PT_FPSCR
238                     || child->thread.regs == NULL)
239                         break;
240 
241                 CHECK_FULL_REGS(child->thread.regs);
242                 if (index < PT_FPR0) {
243                         tmp = get_reg(child, (int) index);
244                 } else {
245                         if (child->thread.regs->msr & MSR_FP)
246                                 giveup_fpu(child);
247                         tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
248                 }
249                 ret = put_user(tmp,(unsigned long *) data);
250                 break;
251         }
252 
253         /* If I and D space are separate, this will have to be fixed. */
254         case PTRACE_POKETEXT: /* write the word at location addr. */
255         case PTRACE_POKEDATA:
256                 ret = 0;
257                 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
258                         break;
259                 ret = -EIO;
260                 break;
261 
262         /* write the word at location addr in the USER area */
263         case PTRACE_POKEUSR: {
264                 unsigned long index;
265 
266                 ret = -EIO;
267                 /* convert to index and check */
268                 index = (unsigned long) addr >> 2;
269                 if ((addr & 3) || index > PT_FPSCR
270                     || child->thread.regs == NULL)
271                         break;
272 
273                 CHECK_FULL_REGS(child->thread.regs);
274                 if (index == PT_ORIG_R3)
275                         break;
276                 if (index < PT_FPR0) {
277                         ret = put_reg(child, index, data);
278                 } else {
279                         if (child->thread.regs->msr & MSR_FP)
280                                 giveup_fpu(child);
281                         ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
282                         ret = 0;
283                 }
284                 break;
285         }
286 
287         case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
288         case PTRACE_CONT: { /* restart after signal. */
289                 ret = -EIO;
290                 if ((unsigned long) data > _NSIG)
291                         break;
292                 if (request == PTRACE_SYSCALL) {
293                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
294                 } else {
295                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
296                 }
297                 child->exit_code = data;
298                 /* make sure the single step bit is not set. */
299                 clear_single_step(child);
300                 wake_up_process(child);
301                 ret = 0;
302                 break;
303         }
304 
305 /*
306  * make the child exit.  Best I can do is send it a sigkill.
307  * perhaps it should be put in the status that it wants to
308  * exit.
309  */
310         case PTRACE_KILL: {
311                 ret = 0;
312                 if (child->state == TASK_ZOMBIE)        /* already dead */
313                         break;
314                 child->exit_code = SIGKILL;
315                 /* make sure the single step bit is not set. */
316                 clear_single_step(child);
317                 wake_up_process(child);
318                 break;
319         }
320 
321         case PTRACE_SINGLESTEP: {  /* set the trap flag. */
322                 ret = -EIO;
323                 if ((unsigned long) data > _NSIG)
324                         break;
325                 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
326                 set_single_step(child);
327                 child->exit_code = data;
328                 /* give it a chance to run. */
329                 wake_up_process(child);
330                 ret = 0;
331                 break;
332         }
333 
334         case PTRACE_DETACH:
335                 ret = ptrace_detach(child, data);
336                 break;
337 
338 #ifdef CONFIG_ALTIVEC
339         case PTRACE_GETVRREGS:
340                 /* Get the child altivec register state. */
341                 if (child->thread.regs->msr & MSR_VEC)
342                         giveup_altivec(child);
343                 ret = get_vrregs((unsigned long *)data, child);
344                 break;
345 
346         case PTRACE_SETVRREGS:
347                 /* Set the child altivec register state. */
348                 /* this is to clear the MSR_VEC bit to force a reload
349                  * of register state from memory */
350                 if (child->thread.regs->msr & MSR_VEC)
351                         giveup_altivec(child);
352                 ret = set_vrregs(child, (unsigned long *)data);
353                 break;
354 #endif
355 
356         default:
357                 ret = ptrace_request(child, request, addr, data);
358                 break;
359         }
360 out_tsk:
361         put_task_struct(child);
362 out:
363         unlock_kernel();
364         return ret;
365 }
366 
367 void do_syscall_trace(void)
368 {
369         if (!test_thread_flag(TIF_SYSCALL_TRACE)
370             || !(current->ptrace & PT_PTRACED))
371                 return;
372         ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
373                                  ? 0x80 : 0));
374 
375         /*
376          * this isn't the same as continuing with a signal, but it will do
377          * for normal use.  strace only continues with a signal if the
378          * stopping signal is not SIGTRAP.  -brl
379          */
380         if (current->exit_code) {
381                 send_sig(current->exit_code, current, 1);
382                 current->exit_code = 0;
383         }
384 }
385 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp