ptrace.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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