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