v2.4.2.7 -> v2.4.2.8
[linux-flexiantxendom0-3.2.10.git] / arch / sparc64 / kernel / ptrace.c
1 /* ptrace.c: Sparc process tracing support.
2  *
3  * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
4  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5  *
6  * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
7  * and David Mosberger.
8  *
9  * Added Linux support -miguel (weird, eh?, the orignal code was meant
10  * to emulate SunOS).
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/mm.h>
16 #include <linux/errno.h>
17 #include <linux/ptrace.h>
18 #include <linux/user.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21
22 #include <asm/asi.h>
23 #include <asm/pgtable.h>
24 #include <asm/system.h>
25 #include <asm/uaccess.h>
26 #include <asm/psrcompat.h>
27 #include <asm/visasm.h>
28
29 #define MAGIC_CONSTANT 0x80000000
30
31 /* Returning from ptrace is a bit tricky because the syscall return
32  * low level code assumes any value returned which is negative and
33  * is a valid errno will mean setting the condition codes to indicate
34  * an error return.  This doesn't work, so we have this hook.
35  */
36 static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
37 {
38         regs->u_regs[UREG_I0] = error;
39         regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY);
40         regs->tpc = regs->tnpc;
41         regs->tnpc += 4;
42 }
43
44 static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
45 {
46         regs->u_regs[UREG_I0] = value;
47         regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
48         regs->tpc = regs->tnpc;
49         regs->tnpc += 4;
50 }
51
52 static inline void
53 pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr)
54 {
55         if (current->thread.flags & SPARC_FLAG_32BIT) {
56                 if (put_user(value, (unsigned int *)addr))
57                         return pt_error_return(regs, EFAULT);
58         } else {
59                 if (put_user(value, addr))
60                         return pt_error_return(regs, EFAULT);
61         }
62         regs->u_regs[UREG_I0] = 0;
63         regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY);
64         regs->tpc = regs->tnpc;
65         regs->tnpc += 4;
66 }
67
68 static void
69 pt_os_succ_return (struct pt_regs *regs, unsigned long val, long *addr)
70 {
71         if (current->personality == PER_SUNOS)
72                 pt_succ_return (regs, val);
73         else
74                 pt_succ_return_linux (regs, val, addr);
75 }
76
77 /* #define ALLOW_INIT_TRACING */
78 /* #define DEBUG_PTRACE */
79
80 #ifdef DEBUG_PTRACE
81 char *pt_rq [] = {
82 "TRACEME",
83 "PEEKTEXT",
84 "PEEKDATA",
85 "PEEKUSR",
86 "POKETEXT",
87 "POKEDATA",
88 "POKEUSR",
89 "CONT",
90 "KILL",
91 "SINGLESTEP",
92 "SUNATTACH",
93 "SUNDETACH",
94 "GETREGS",
95 "SETREGS",
96 "GETFPREGS",
97 "SETFPREGS",
98 "READDATA",
99 "WRITEDATA",
100 "READTEXT",
101 "WRITETEXT",
102 "GETFPAREGS",
103 "SETFPAREGS",
104 ""
105 };
106 #endif
107
108 asmlinkage void do_ptrace(struct pt_regs *regs)
109 {
110         int request = regs->u_regs[UREG_I0];
111         pid_t pid = regs->u_regs[UREG_I1];
112         unsigned long addr = regs->u_regs[UREG_I2];
113         unsigned long data = regs->u_regs[UREG_I3];
114         unsigned long addr2 = regs->u_regs[UREG_I4];
115         struct task_struct *child;
116
117         if (current->thread.flags & SPARC_FLAG_32BIT) {
118                 addr &= 0xffffffffUL;
119                 data &= 0xffffffffUL;
120                 addr2 &= 0xffffffffUL;
121         }
122         lock_kernel();
123 #ifdef DEBUG_PTRACE
124         {
125                 char *s;
126
127                 if ((request > 0) && (request < 21))
128                         s = pt_rq [request];
129                 else
130                         s = "unknown";
131
132                 if (request == PTRACE_POKEDATA && data == 0x91d02001){
133                         printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n",
134                                 pid, addr, addr2);
135                 } else 
136                         printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n",
137                                s, request, pid, addr, data, addr2);
138         }
139 #endif
140         if (request == PTRACE_TRACEME) {
141                 /* are we already being traced? */
142                 if (current->ptrace & PT_PTRACED) {
143                         pt_error_return(regs, EPERM);
144                         goto out;
145                 }
146                 /* set the ptrace bit in the process flags. */
147                 current->ptrace |= PT_PTRACED;
148                 pt_succ_return(regs, 0);
149                 goto out;
150         }
151 #ifndef ALLOW_INIT_TRACING
152         if (pid == 1) {
153                 /* Can't dork with init. */
154                 pt_error_return(regs, EPERM);
155                 goto out;
156         }
157 #endif
158         read_lock(&tasklist_lock);
159         child = find_task_by_pid(pid);
160         if (child)
161                 get_task_struct(child);
162         read_unlock(&tasklist_lock);
163
164         if (!child) {
165                 pt_error_return(regs, ESRCH);
166                 goto out;
167         }
168
169         if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
170             || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
171                 unsigned long flags;
172
173                 if (child == current) {
174                         /* Try this under SunOS/Solaris, bwa haha
175                          * You'll never be able to kill the process. ;-)
176                          */
177                         pt_error_return(regs, EPERM);
178                         goto out_tsk;
179                 }
180                 if ((!child->dumpable ||
181                      (current->uid != child->euid) ||
182                      (current->uid != child->uid) ||
183                      (current->uid != child->suid) ||
184                      (current->gid != child->egid) ||
185                      (current->gid != child->sgid) ||
186                      (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
187                      (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) {
188                         pt_error_return(regs, EPERM);
189                         goto out_tsk;
190                 }
191                 /* the same process cannot be attached many times */
192                 if (child->ptrace & PT_PTRACED) {
193                         pt_error_return(regs, EPERM);
194                         goto out_tsk;
195                 }
196                 child->ptrace |= PT_PTRACED;
197                 write_lock_irqsave(&tasklist_lock, flags);
198                 if (child->p_pptr != current) {
199                         REMOVE_LINKS(child);
200                         child->p_pptr = current;
201                         SET_LINKS(child);
202                 }
203                 write_unlock_irqrestore(&tasklist_lock, flags);
204                 send_sig(SIGSTOP, child, 1);
205                 pt_succ_return(regs, 0);
206                 goto out_tsk;
207         }
208         if (!(child->ptrace & PT_PTRACED)) {
209                 pt_error_return(regs, ESRCH);
210                 goto out_tsk;
211         }
212         if (child->state != TASK_STOPPED) {
213                 if (request != PTRACE_KILL) {
214                         pt_error_return(regs, ESRCH);
215                         goto out_tsk;
216                 }
217         }
218         if (child->p_pptr != current) {
219                 pt_error_return(regs, ESRCH);
220                 goto out_tsk;
221         }
222
223         if (!(child->thread.flags & SPARC_FLAG_32BIT)   &&
224             ((request == PTRACE_READDATA64)             ||
225              (request == PTRACE_WRITEDATA64)            ||
226              (request == PTRACE_READTEXT64)             ||
227              (request == PTRACE_WRITETEXT64)            ||
228              (request == PTRACE_PEEKTEXT64)             ||
229              (request == PTRACE_POKETEXT64)             ||
230              (request == PTRACE_PEEKDATA64)             ||
231              (request == PTRACE_POKEDATA64))) {
232                 addr = regs->u_regs[UREG_G2];
233                 addr2 = regs->u_regs[UREG_G3];
234                 request -= 30; /* wheee... */
235         }
236
237         switch(request) {
238         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
239         case PTRACE_PEEKDATA: {
240                 unsigned long tmp64;
241                 unsigned int tmp32;
242                 int res, copied;
243
244                 res = -EIO;
245                 if (current->thread.flags & SPARC_FLAG_32BIT) {
246                         copied = access_process_vm(child, addr,
247                                                    &tmp32, sizeof(tmp32), 0);
248                         tmp64 = (unsigned long) tmp32;
249                         if (copied == sizeof(tmp32))
250                                 res = 0;
251                 } else {
252                         copied = access_process_vm(child, addr,
253                                                    &tmp64, sizeof(tmp64), 0);
254                         if (copied == sizeof(tmp64))
255                                 res = 0;
256                 }
257                 if (res < 0)
258                         pt_error_return(regs, -res);
259                 else
260                         pt_os_succ_return(regs, tmp64, (long *) data);
261                 goto flush_and_out;
262         }
263
264         case PTRACE_POKETEXT: /* write the word at location addr. */
265         case PTRACE_POKEDATA: {
266                 unsigned long tmp64;
267                 unsigned int tmp32;
268                 int copied, res = -EIO;
269
270                 if (current->thread.flags & SPARC_FLAG_32BIT) {
271                         tmp32 = data;
272                         copied = access_process_vm(child, addr,
273                                                    &tmp32, sizeof(tmp32), 1);
274                         if (copied == sizeof(tmp32))
275                                 res = 0;
276                 } else {
277                         tmp64 = data;
278                         copied = access_process_vm(child, addr,
279                                                    &tmp64, sizeof(tmp64), 1);
280                         if (copied == sizeof(tmp64))
281                                 res = 0;
282                 }
283                 if (res < 0)
284                         pt_error_return(regs, -res);
285                 else
286                         pt_succ_return(regs, res);
287                 goto flush_and_out;
288         }
289
290         case PTRACE_GETREGS: {
291                 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
292                 struct pt_regs *cregs = child->thread.kregs;
293                 int rval;
294
295                 if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) ||
296                     __put_user(cregs->tpc, (&pregs->pc)) ||
297                     __put_user(cregs->tnpc, (&pregs->npc)) ||
298                     __put_user(cregs->y, (&pregs->y))) {
299                         pt_error_return(regs, EFAULT);
300                         goto out_tsk;
301                 }
302                 for (rval = 1; rval < 16; rval++)
303                         if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
304                                 pt_error_return(regs, EFAULT);
305                                 goto out_tsk;
306                         }
307                 pt_succ_return(regs, 0);
308 #ifdef DEBUG_PTRACE
309                 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
310 #endif
311                 goto out_tsk;
312         }
313
314         case PTRACE_GETREGS64: {
315                 struct pt_regs *pregs = (struct pt_regs *) addr;
316                 struct pt_regs *cregs = child->thread.kregs;
317                 unsigned long tpc = cregs->tpc;
318                 int rval;
319
320                 if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
321                         tpc &= 0xffffffff;
322                 if (__put_user(cregs->tstate, (&pregs->tstate)) ||
323                     __put_user(tpc, (&pregs->tpc)) ||
324                     __put_user(cregs->tnpc, (&pregs->tnpc)) ||
325                     __put_user(cregs->y, (&pregs->y))) {
326                         pt_error_return(regs, EFAULT);
327                         goto out_tsk;
328                 }
329                 for (rval = 1; rval < 16; rval++)
330                         if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) {
331                                 pt_error_return(regs, EFAULT);
332                                 goto out_tsk;
333                         }
334                 pt_succ_return(regs, 0);
335 #ifdef DEBUG_PTRACE
336                 printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]);
337 #endif
338                 goto out_tsk;
339         }
340
341         case PTRACE_SETREGS: {
342                 struct pt_regs32 *pregs = (struct pt_regs32 *) addr;
343                 struct pt_regs *cregs = child->thread.kregs;
344                 unsigned int psr, pc, npc, y;
345                 int i;
346
347                 /* Must be careful, tracing process can only set certain
348                  * bits in the psr.
349                  */
350                 if (__get_user(psr, (&pregs->psr)) ||
351                     __get_user(pc, (&pregs->pc)) ||
352                     __get_user(npc, (&pregs->npc)) ||
353                     __get_user(y, (&pregs->y))) {
354                         pt_error_return(regs, EFAULT);
355                         goto out_tsk;
356                 }
357                 cregs->tstate &= ~(TSTATE_ICC);
358                 cregs->tstate |= psr_to_tstate_icc(psr);
359                 if (!((pc | npc) & 3)) {
360                         cregs->tpc = pc;
361                         cregs->tnpc = npc;
362                 }
363                 cregs->y = y;
364                 for (i = 1; i < 16; i++) {
365                         if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
366                                 pt_error_return(regs, EFAULT);
367                                 goto out_tsk;
368                         }
369                 }
370                 pt_succ_return(regs, 0);
371                 goto out_tsk;
372         }
373
374         case PTRACE_SETREGS64: {
375                 struct pt_regs *pregs = (struct pt_regs *) addr;
376                 struct pt_regs *cregs = child->thread.kregs;
377                 unsigned long tstate, tpc, tnpc, y;
378                 int i;
379
380                 /* Must be careful, tracing process can only set certain
381                  * bits in the psr.
382                  */
383                 if (__get_user(tstate, (&pregs->tstate)) ||
384                     __get_user(tpc, (&pregs->tpc)) ||
385                     __get_user(tnpc, (&pregs->tnpc)) ||
386                     __get_user(y, (&pregs->y))) {
387                         pt_error_return(regs, EFAULT);
388                         goto out_tsk;
389                 }
390                 if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) {
391                         tpc &= 0xffffffff;
392                         tnpc &= 0xffffffff;
393                 }
394                 tstate &= (TSTATE_ICC | TSTATE_XCC);
395                 cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
396                 cregs->tstate |= tstate;
397                 if (!((tpc | tnpc) & 3)) {
398                         cregs->tpc = tpc;
399                         cregs->tnpc = tnpc;
400                 }
401                 cregs->y = y;
402                 for (i = 1; i < 16; i++) {
403                         if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) {
404                                 pt_error_return(regs, EFAULT);
405                                 goto out_tsk;
406                         }
407                 }
408                 pt_succ_return(regs, 0);
409                 goto out_tsk;
410         }
411
412         case PTRACE_GETFPREGS: {
413                 struct fps {
414                         unsigned int regs[32];
415                         unsigned int fsr;
416                         unsigned int flags;
417                         unsigned int extra;
418                         unsigned int fpqd;
419                         struct fq {
420                                 unsigned int insnaddr;
421                                 unsigned int insn;
422                         } fpq[16];
423                 } *fps = (struct fps *) addr;
424                 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
425
426                 if (copy_to_user(&fps->regs[0], fpregs,
427                                  (32 * sizeof(unsigned int))) ||
428                     __put_user(child->thread.xfsr[0], (&fps->fsr)) ||
429                     __put_user(0, (&fps->fpqd)) ||
430                     __put_user(0, (&fps->flags)) ||
431                     __put_user(0, (&fps->extra)) ||
432                     clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) {
433                         pt_error_return(regs, EFAULT);
434                         goto out_tsk;
435                 }
436                 pt_succ_return(regs, 0);
437                 goto out_tsk;
438         }
439
440         case PTRACE_GETFPREGS64: {
441                 struct fps {
442                         unsigned int regs[64];
443                         unsigned long fsr;
444                 } *fps = (struct fps *) addr;
445                 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
446
447                 if (copy_to_user(&fps->regs[0], fpregs,
448                                  (64 * sizeof(unsigned int))) ||
449                     __put_user(child->thread.xfsr[0], (&fps->fsr))) {
450                         pt_error_return(regs, EFAULT);
451                         goto out_tsk;
452                 }
453                 pt_succ_return(regs, 0);
454                 goto out_tsk;
455         }
456
457         case PTRACE_SETFPREGS: {
458                 struct fps {
459                         unsigned int regs[32];
460                         unsigned int fsr;
461                         unsigned int flags;
462                         unsigned int extra;
463                         unsigned int fpqd;
464                         struct fq {
465                                 unsigned int insnaddr;
466                                 unsigned int insn;
467                         } fpq[16];
468                 } *fps = (struct fps *) addr;
469                 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
470                 unsigned fsr;
471
472                 if (copy_from_user(fpregs, &fps->regs[0],
473                                    (32 * sizeof(unsigned int))) ||
474                     __get_user(fsr, (&fps->fsr))) {
475                         pt_error_return(regs, EFAULT);
476                         goto out_tsk;
477                 }
478                 child->thread.xfsr[0] &= 0xffffffff00000000UL;
479                 child->thread.xfsr[0] |= fsr;
480                 if (!(child->thread.fpsaved[0] & FPRS_FEF))
481                         child->thread.gsr[0] = 0;
482                 child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL);
483                 pt_succ_return(regs, 0);
484                 goto out_tsk;
485         }
486
487         case PTRACE_SETFPREGS64: {
488                 struct fps {
489                         unsigned int regs[64];
490                         unsigned long fsr;
491                 } *fps = (struct fps *) addr;
492                 unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs);
493
494                 if (copy_from_user(fpregs, &fps->regs[0],
495                                    (64 * sizeof(unsigned int))) ||
496                     __get_user(child->thread.xfsr[0], (&fps->fsr))) {
497                         pt_error_return(regs, EFAULT);
498                         goto out_tsk;
499                 }
500                 if (!(child->thread.fpsaved[0] & FPRS_FEF))
501                         child->thread.gsr[0] = 0;
502                 child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU);
503                 pt_succ_return(regs, 0);
504                 goto out_tsk;
505         }
506
507         case PTRACE_READTEXT:
508         case PTRACE_READDATA: {
509                 int res = ptrace_readdata(child, addr,
510                                           (void *)addr2, data);
511                 if (res == data) {
512                         pt_succ_return(regs, 0);
513                         goto flush_and_out;
514                 }
515                 if (res >= 0)
516                         res = -EIO;
517                 pt_error_return(regs, -res);
518                 goto flush_and_out;
519         }
520
521         case PTRACE_WRITETEXT:
522         case PTRACE_WRITEDATA: {
523                 int res = ptrace_writedata(child, (void *) addr2,
524                                            addr, data);
525                 if (res == data) {
526                         pt_succ_return(regs, 0);
527                         goto flush_and_out;
528                 }
529                 if (res >= 0)
530                         res = -EIO;
531                 pt_error_return(regs, -res);
532                 goto flush_and_out;
533         }
534         case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
535                 addr = 1;
536
537         case PTRACE_CONT: { /* restart after signal. */
538                 if (data > _NSIG) {
539                         pt_error_return(regs, EIO);
540                         goto out_tsk;
541                 }
542                 if (addr != 1) {
543                         unsigned long pc_mask = ~0UL;
544
545                         if ((child->thread.flags & SPARC_FLAG_32BIT) != 0)
546                                 pc_mask = 0xffffffff;
547
548                         if (addr & 3) {
549                                 pt_error_return(regs, EINVAL);
550                                 goto out_tsk;
551                         }
552 #ifdef DEBUG_PTRACE
553                         printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc);
554                         printk ("Continuing with %016lx %016lx\n", addr, addr+4);
555 #endif
556                         child->thread.kregs->tpc = (addr & pc_mask);
557                         child->thread.kregs->tnpc = ((addr + 4) & pc_mask);
558                 }
559
560                 if (request == PTRACE_SYSCALL)
561                         child->ptrace |= PT_TRACESYS;
562                 else
563                         child->ptrace &= ~PT_TRACESYS;
564
565                 child->exit_code = data;
566 #ifdef DEBUG_PTRACE
567                 printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm,
568                         child->pid, child->exit_code,
569                         child->thread.kregs->tpc,
570                         child->thread.kregs->tnpc);
571                        
572 #endif
573                 wake_up_process(child);
574                 pt_succ_return(regs, 0);
575                 goto out_tsk;
576         }
577
578 /*
579  * make the child exit.  Best I can do is send it a sigkill. 
580  * perhaps it should be put in the status that it wants to 
581  * exit.
582  */
583         case PTRACE_KILL: {
584                 if (child->state == TASK_ZOMBIE) {      /* already dead */
585                         pt_succ_return(regs, 0);
586                         goto out_tsk;
587                 }
588                 child->exit_code = SIGKILL;
589                 wake_up_process(child);
590                 pt_succ_return(regs, 0);
591                 goto out_tsk;
592         }
593
594         case PTRACE_SUNDETACH: { /* detach a process that was attached. */
595                 unsigned long flags;
596
597                 if ((unsigned long) data > _NSIG) {
598                         pt_error_return(regs, EIO);
599                         goto out_tsk;
600                 }
601                 child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
602                 child->exit_code = data;
603
604                 write_lock_irqsave(&tasklist_lock, flags);
605                 REMOVE_LINKS(child);
606                 child->p_pptr = child->p_opptr;
607                 SET_LINKS(child);
608                 write_unlock_irqrestore(&tasklist_lock, flags);
609
610                 wake_up_process(child);
611                 pt_succ_return(regs, 0);
612                 goto out_tsk;
613         }
614
615         /* PTRACE_DUMPCORE unsupported... */
616
617         default:
618                 pt_error_return(regs, EIO);
619                 goto out_tsk;
620         }
621 flush_and_out:
622         {
623                 unsigned long va;
624
625                 if (tlb_type == cheetah) {
626                         for (va = 0; va < (1 << 16); va += (1 << 5))
627                                 spitfire_put_dcache_tag(va, 0x0);
628                         /* No need to mess with I-cache on Cheetah. */
629                 } else {
630                         for (va =  0; va < (PAGE_SIZE << 1); va += 32)
631                                 spitfire_put_dcache_tag(va, 0x0);
632                         if (request == PTRACE_PEEKTEXT ||
633                             request == PTRACE_POKETEXT ||
634                             request == PTRACE_READTEXT ||
635                             request == PTRACE_WRITETEXT) {
636                                 for (va =  0; va < (PAGE_SIZE << 1); va += 32)
637                                         spitfire_put_icache_tag(va, 0x0);
638                                 __asm__ __volatile__("flush %g6");
639                         }
640                 }
641         }
642 out_tsk:
643         if (child)
644                 free_task_struct(child);
645 out:
646         unlock_kernel();
647 }
648
649 asmlinkage void syscall_trace(void)
650 {
651 #ifdef DEBUG_PTRACE
652         printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
653 #endif
654         if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
655             != (PT_PTRACED|PT_TRACESYS))
656                 return;
657         current->exit_code = SIGTRAP;
658         current->state = TASK_STOPPED;
659         current->thread.flags ^= MAGIC_CONSTANT;
660         notify_parent(current, SIGCHLD);
661         schedule();
662         /*
663          * this isn't the same as continuing with a signal, but it will do
664          * for normal use.  strace only continues with a signal if the
665          * stopping signal is not SIGTRAP.  -brl
666          */
667 #ifdef DEBUG_PTRACE
668         printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
669                 current->pid, current->exit_code);
670 #endif
671         if (current->exit_code) {
672                 send_sig (current->exit_code, current, 1);
673                 current->exit_code = 0;
674         }
675 }