]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/linux-fork.c
* defs.h (strlen_paddr, paddr, paddr_nz): Remove.
[thirdparty/binutils-gdb.git] / gdb / linux-fork.c
1 /* GNU/Linux native-dependent code for debugging multiple forks.
2
3 Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "defs.h"
21 #include "arch-utils.h"
22 #include "inferior.h"
23 #include "regcache.h"
24 #include "gdbcmd.h"
25 #include "infcall.h"
26 #include "objfiles.h"
27 #include "gdb_assert.h"
28 #include "gdb_string.h"
29 #include "linux-fork.h"
30 #include "linux-nat.h"
31
32 #include <sys/ptrace.h>
33 #include "gdb_wait.h"
34 #include <sys/param.h>
35 #include "gdb_dirent.h"
36 #include <ctype.h>
37
38 struct fork_info *fork_list;
39 static int highest_fork_num;
40
41 /* Prevent warning from -Wmissing-prototypes. */
42 extern void _initialize_linux_fork (void);
43
44 int detach_fork = 1; /* Default behavior is to detach
45 newly forked processes (legacy). */
46
47 /* Fork list data structure: */
48 struct fork_info
49 {
50 struct fork_info *next;
51 ptid_t ptid;
52 int num; /* Convenient handle (GDB fork id) */
53 struct regcache *savedregs; /* Convenient for info fork, saves
54 having to actually switch contexts. */
55 int clobber_regs; /* True if we should restore saved regs. */
56 ULONGEST pc; /* PC for info fork. */
57 off_t *filepos; /* Set of open file descriptors' offsets. */
58 int maxfd;
59 };
60
61 /* Fork list methods: */
62
63 extern int
64 forks_exist_p (void)
65 {
66 return (fork_list != NULL);
67 }
68
69 /* Add a fork to internal fork list.
70 Called from linux child_follow_fork. */
71
72 extern struct fork_info *
73 add_fork (pid_t pid)
74 {
75 struct fork_info *fp;
76
77 if (fork_list == NULL && pid != PIDGET (inferior_ptid))
78 {
79 /* Special case -- if this is the first fork in the list
80 (the list is hitherto empty), and if this new fork is
81 NOT the current inferior_ptid, then add inferior_ptid
82 first, as a special zeroeth fork id. */
83 highest_fork_num = -1;
84 add_fork (PIDGET (inferior_ptid)); /* safe recursion */
85 }
86
87 fp = XZALLOC (struct fork_info);
88 fp->ptid = ptid_build (pid, pid, 0);
89 fp->num = ++highest_fork_num;
90 fp->next = fork_list;
91 fork_list = fp;
92 return fp;
93 }
94
95 static void
96 free_fork (struct fork_info *fp)
97 {
98 /* Notes on step-resume breakpoints: since this is a concern for
99 threads, let's convince ourselves that it's not a concern for
100 forks. There are two ways for a fork_info to be created. First,
101 by the checkpoint command, in which case we're at a gdb prompt
102 and there can't be any step-resume breakpoint. Second, by a fork
103 in the user program, in which case we *may* have stepped into the
104 fork call, but regardless of whether we follow the parent or the
105 child, we will return to the same place and the step-resume
106 breakpoint, if any, will take care of itself as usual. And
107 unlike threads, we do not save a private copy of the step-resume
108 breakpoint -- so we're OK. */
109
110 if (fp)
111 {
112 if (fp->savedregs)
113 regcache_xfree (fp->savedregs);
114 if (fp->filepos)
115 xfree (fp->filepos);
116 xfree (fp);
117 }
118 }
119
120 static void
121 delete_fork (ptid_t ptid)
122 {
123 struct fork_info *fp, *fpprev;
124
125 fpprev = NULL;
126
127 for (fp = fork_list; fp; fpprev = fp, fp = fp->next)
128 if (ptid_equal (fp->ptid, ptid))
129 break;
130
131 if (!fp)
132 return;
133
134 if (fpprev)
135 fpprev->next = fp->next;
136 else
137 fork_list = fp->next;
138
139 free_fork (fp);
140
141 /* Special case: if there is now only one process in the list,
142 and if it is (hopefully!) the current inferior_ptid, then
143 remove it, leaving the list empty -- we're now down to the
144 default case of debugging a single process. */
145 if (fork_list != NULL && fork_list->next == NULL &&
146 ptid_equal (fork_list->ptid, inferior_ptid))
147 {
148 /* Last fork -- delete from list and handle as solo process
149 (should be a safe recursion). */
150 delete_fork (inferior_ptid);
151 }
152 }
153
154 /* Find a fork_info by matching PTID. */
155 static struct fork_info *
156 find_fork_ptid (ptid_t ptid)
157 {
158 struct fork_info *fp;
159
160 for (fp = fork_list; fp; fp = fp->next)
161 if (ptid_equal (fp->ptid, ptid))
162 return fp;
163
164 return NULL;
165 }
166
167 /* Find a fork_info by matching ID. */
168 static struct fork_info *
169 find_fork_id (int num)
170 {
171 struct fork_info *fp;
172
173 for (fp = fork_list; fp; fp = fp->next)
174 if (fp->num == num)
175 return fp;
176
177 return NULL;
178 }
179
180 /* Find a fork_info by matching pid. */
181 extern struct fork_info *
182 find_fork_pid (pid_t pid)
183 {
184 struct fork_info *fp;
185
186 for (fp = fork_list; fp; fp = fp->next)
187 if (pid == ptid_get_pid (fp->ptid))
188 return fp;
189
190 return NULL;
191 }
192
193 static ptid_t
194 fork_id_to_ptid (int num)
195 {
196 struct fork_info *fork = find_fork_id (num);
197 if (fork)
198 return fork->ptid;
199 else
200 return pid_to_ptid (-1);
201 }
202
203 static void
204 init_fork_list (void)
205 {
206 struct fork_info *fp, *fpnext;
207
208 if (!fork_list)
209 return;
210
211 for (fp = fork_list; fp; fp = fpnext)
212 {
213 fpnext = fp->next;
214 delete_inferior (ptid_get_pid (fp->ptid));
215 free_fork (fp);
216 }
217
218 fork_list = NULL;
219 }
220
221 /* Fork list <-> gdb interface. */
222
223 /* Utility function for fork_load/fork_save.
224 Calls lseek in the (current) inferior process. */
225
226 static off_t
227 call_lseek (int fd, off_t offset, int whence)
228 {
229 char exp[80];
230
231 snprintf (&exp[0], sizeof (exp), "lseek (%d, %ld, %d)",
232 fd, (long) offset, whence);
233 return (off_t) parse_and_eval_long (&exp[0]);
234 }
235
236 /* Load infrun state for the fork PTID. */
237
238 static void
239 fork_load_infrun_state (struct fork_info *fp)
240 {
241 extern void nullify_last_target_wait_ptid ();
242 int i;
243
244 inferior_ptid = fp->ptid;
245
246 linux_nat_switch_fork (inferior_ptid);
247
248 if (fp->savedregs && fp->clobber_regs)
249 regcache_cpy (get_current_regcache (), fp->savedregs);
250
251 registers_changed ();
252 reinit_frame_cache ();
253
254 stop_pc = regcache_read_pc (get_current_regcache ());
255 nullify_last_target_wait_ptid ();
256
257 /* Now restore the file positions of open file descriptors. */
258 if (fp->filepos)
259 {
260 for (i = 0; i <= fp->maxfd; i++)
261 if (fp->filepos[i] != (off_t) -1)
262 call_lseek (i, fp->filepos[i], SEEK_SET);
263 /* NOTE: I can get away with using SEEK_SET and SEEK_CUR because
264 this is native-only. If it ever has to be cross, we'll have
265 to rethink this. */
266 }
267 }
268
269 /* Save infrun state for the fork PTID.
270 Exported for use by linux child_follow_fork. */
271
272 extern void
273 fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
274 {
275 char path[MAXPATHLEN];
276 struct dirent *de;
277 DIR *d;
278
279 if (fp->savedregs)
280 regcache_xfree (fp->savedregs);
281
282 fp->savedregs = regcache_dup (get_current_regcache ());
283 fp->clobber_regs = clobber_regs;
284 fp->pc = regcache_read_pc (get_current_regcache ());
285
286 if (clobber_regs)
287 {
288 /* Now save the 'state' (file position) of all open file descriptors.
289 Unfortunately fork does not take care of that for us... */
290 snprintf (path, MAXPATHLEN, "/proc/%ld/fd", (long) PIDGET (fp->ptid));
291 if ((d = opendir (path)) != NULL)
292 {
293 long tmp;
294
295 fp->maxfd = 0;
296 while ((de = readdir (d)) != NULL)
297 {
298 /* Count open file descriptors (actually find highest
299 numbered). */
300 tmp = strtol (&de->d_name[0], NULL, 10);
301 if (fp->maxfd < tmp)
302 fp->maxfd = tmp;
303 }
304 /* Allocate array of file positions. */
305 fp->filepos = xrealloc (fp->filepos,
306 (fp->maxfd + 1) * sizeof (*fp->filepos));
307
308 /* Initialize to -1 (invalid). */
309 for (tmp = 0; tmp <= fp->maxfd; tmp++)
310 fp->filepos[tmp] = -1;
311
312 /* Now find actual file positions. */
313 rewinddir (d);
314 while ((de = readdir (d)) != NULL)
315 if (isdigit (de->d_name[0]))
316 {
317 tmp = strtol (&de->d_name[0], NULL, 10);
318 fp->filepos[tmp] = call_lseek (tmp, 0, SEEK_CUR);
319 }
320 closedir (d);
321 }
322 }
323 }
324
325 /* Kill 'em all, let God sort 'em out... */
326
327 extern void
328 linux_fork_killall (void)
329 {
330 /* Walk list and kill every pid. No need to treat the
331 current inferior_ptid as special (we do not return a
332 status for it) -- however any process may be a child
333 or a parent, so may get a SIGCHLD from a previously
334 killed child. Wait them all out. */
335 struct fork_info *fp;
336 pid_t pid, ret;
337 int status;
338
339 for (fp = fork_list; fp; fp = fp->next)
340 {
341 pid = PIDGET (fp->ptid);
342 do {
343 /* Use SIGKILL instead of PTRACE_KILL because the former works even
344 if the thread is running, while the later doesn't. */
345 kill (pid, SIGKILL);
346 ret = waitpid (pid, &status, 0);
347 /* We might get a SIGCHLD instead of an exit status. This is
348 aggravated by the first kill above - a child has just
349 died. MVS comment cut-and-pasted from linux-nat. */
350 } while (ret == pid && WIFSTOPPED (status));
351 }
352 init_fork_list (); /* Clear list, prepare to start fresh. */
353 }
354
355 /* The current inferior_ptid has exited, but there are other viable
356 forks to debug. Delete the exiting one and context-switch to the
357 first available. */
358
359 extern void
360 linux_fork_mourn_inferior (void)
361 {
362 /* Wait just one more time to collect the inferior's exit status.
363 Do not check whether this succeeds though, since we may be
364 dealing with a process that we attached to. Such a process will
365 only report its exit status to its original parent. */
366 int status;
367
368 waitpid (ptid_get_pid (inferior_ptid), &status, 0);
369
370 /* OK, presumably inferior_ptid is the one who has exited.
371 We need to delete that one from the fork_list, and switch
372 to the next available fork. */
373 delete_fork (inferior_ptid);
374 /* Delete process from GDB's inferior list. */
375 delete_inferior (ptid_get_pid (inferior_ptid));
376
377 /* There should still be a fork - if there's only one left,
378 delete_fork won't remove it, because we haven't updated
379 inferior_ptid yet. */
380 gdb_assert (fork_list);
381
382 fork_load_infrun_state (fork_list);
383 printf_filtered (_("[Switching to %s]\n"),
384 target_pid_to_str (inferior_ptid));
385
386 /* If there's only one fork, switch back to non-fork mode. */
387 if (fork_list->next == NULL)
388 delete_fork (inferior_ptid);
389 }
390
391 /* The current inferior_ptid is being detached, but there are other
392 viable forks to debug. Detach and delete it and context-switch to
393 the first available. */
394
395 extern void
396 linux_fork_detach (char *args, int from_tty)
397 {
398 /* OK, inferior_ptid is the one we are detaching from. We need to
399 delete it from the fork_list, and switch to the next available
400 fork. */
401
402 if (ptrace (PTRACE_DETACH, PIDGET (inferior_ptid), 0, 0))
403 error (_("Unable to detach %s"), target_pid_to_str (inferior_ptid));
404
405 delete_fork (inferior_ptid);
406 /* Delete process from GDB's inferior list. */
407 delete_inferior (ptid_get_pid (inferior_ptid));
408
409 /* There should still be a fork - if there's only one left,
410 delete_fork won't remove it, because we haven't updated
411 inferior_ptid yet. */
412 gdb_assert (fork_list);
413
414 fork_load_infrun_state (fork_list);
415
416 if (from_tty)
417 printf_filtered (_("[Switching to %s]\n"),
418 target_pid_to_str (inferior_ptid));
419
420 /* If there's only one fork, switch back to non-fork mode. */
421 if (fork_list->next == NULL)
422 delete_fork (inferior_ptid);
423 }
424
425 /* Fork list <-> user interface. */
426
427 static void
428 delete_fork_command (char *args, int from_tty)
429 {
430 ptid_t ptid;
431
432 if (!args || !*args)
433 error (_("Requires argument (fork/checkpoint id to delete)"));
434
435 ptid = fork_id_to_ptid (parse_and_eval_long (args));
436 if (ptid_equal (ptid, minus_one_ptid))
437 error (_("No such fork/checkpoint id, %s"), args);
438
439 if (ptid_equal (ptid, inferior_ptid))
440 error (_("Please switch to another fork/checkpoint before deleting the current one"));
441
442 if (ptrace (PTRACE_KILL, PIDGET (ptid), 0, 0))
443 error (_("Unable to kill pid %s"), target_pid_to_str (ptid));
444
445 if (from_tty)
446 printf_filtered (_("Killed %s\n"), target_pid_to_str (ptid));
447
448 delete_fork (ptid);
449 /* Delete process from GDB's inferior list. */
450 delete_inferior (ptid_get_pid (ptid));
451 }
452
453 static void
454 detach_fork_command (char *args, int from_tty)
455 {
456 ptid_t ptid;
457
458 if (!args || !*args)
459 error (_("Requires argument (fork id to detach)"));
460
461 ptid = fork_id_to_ptid (parse_and_eval_long (args));
462 if (ptid_equal (ptid, minus_one_ptid))
463 error (_("No such fork id, %s"), args);
464
465 if (ptid_equal (ptid, inferior_ptid))
466 error (_("Please switch to another fork before detaching the current one"));
467
468 if (ptrace (PTRACE_DETACH, PIDGET (ptid), 0, 0))
469 error (_("Unable to detach %s"), target_pid_to_str (ptid));
470
471 if (from_tty)
472 printf_filtered (_("Detached %s\n"), target_pid_to_str (ptid));
473
474 delete_fork (ptid);
475 /* Delete process from GDB's process table. */
476 detach_inferior (ptid_get_pid (ptid));
477 }
478
479 /* Print information about currently known forks. */
480
481 static void
482 info_forks_command (char *arg, int from_tty)
483 {
484 struct gdbarch *gdbarch = get_current_arch ();
485 struct frame_info *cur_frame;
486 struct symtab_and_line sal;
487 struct symtab *cur_symtab;
488 struct fork_info *fp;
489 int cur_line;
490 ULONGEST pc;
491 int requested = -1;
492 struct fork_info *printed = NULL;
493
494 if (arg && *arg)
495 requested = (int) parse_and_eval_long (arg);
496
497 for (fp = fork_list; fp; fp = fp->next)
498 {
499 if (requested > 0 && fp->num != requested)
500 continue;
501
502 printed = fp;
503 if (ptid_equal (fp->ptid, inferior_ptid))
504 {
505 printf_filtered ("* ");
506 pc = regcache_read_pc (get_current_regcache ());
507 }
508 else
509 {
510 printf_filtered (" ");
511 pc = fp->pc;
512 }
513 printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
514 if (fp->num == 0)
515 printf_filtered (_(" (main process)"));
516 printf_filtered (_(" at "));
517 fputs_filtered (paddress (gdbarch, pc), gdb_stdout);
518
519 sal = find_pc_line (pc, 0);
520 if (sal.symtab)
521 {
522 char *tmp = strrchr (sal.symtab->filename, '/');
523
524 if (tmp)
525 printf_filtered (_(", file %s"), tmp + 1);
526 else
527 printf_filtered (_(", file %s"), sal.symtab->filename);
528 }
529 if (sal.line)
530 printf_filtered (_(", line %d"), sal.line);
531 if (!sal.symtab && !sal.line)
532 {
533 struct minimal_symbol *msym;
534
535 msym = lookup_minimal_symbol_by_pc (pc);
536 if (msym)
537 printf_filtered (", <%s>", SYMBOL_LINKAGE_NAME (msym));
538 }
539
540 putchar_filtered ('\n');
541 }
542 if (printed == NULL)
543 {
544 if (requested > 0)
545 printf_filtered (_("No fork number %d.\n"), requested);
546 else
547 printf_filtered (_("No forks.\n"));
548 }
549 }
550
551 /* Save/restore mode variable 'detach_fork':
552 We need to temporarily take over this mode variable, while
553 preserving the user-specified state, and make sure that it
554 gets restored in case of error.
555
556 The int pointer that we use comes from the caller, so we can
557 be called more than once (even though currently we don't need to). */
558
559 static void
560 restore_detach_fork (void *arg)
561 {
562 detach_fork = *(int *) arg;
563 }
564
565 static struct cleanup *
566 save_detach_fork (int *saved_val)
567 {
568 *saved_val = detach_fork;
569 return make_cleanup (restore_detach_fork, (void *) saved_val);
570 }
571
572 static void
573 checkpoint_command (char *args, int from_tty)
574 {
575 struct objfile *fork_objf;
576 struct gdbarch *gdbarch;
577 struct target_waitstatus last_target_waitstatus;
578 ptid_t last_target_ptid;
579 struct value *fork_fn = NULL, *ret;
580 struct fork_info *fp;
581 pid_t retpid;
582 struct cleanup *old_chain;
583 long i;
584 /* Make this temp var static, 'cause it's used in the error context. */
585 static int temp_detach_fork;
586
587 /* Remove breakpoints, so that they are not inserted
588 in the forked process. */
589 remove_breakpoints ();
590
591 /* Make the inferior fork, record its (and gdb's) state. */
592
593 if (lookup_minimal_symbol ("fork", NULL, NULL) != NULL)
594 fork_fn = find_function_in_inferior ("fork", &fork_objf);
595 if (!fork_fn)
596 if (lookup_minimal_symbol ("_fork", NULL, NULL) != NULL)
597 fork_fn = find_function_in_inferior ("fork", &fork_objf);
598 if (!fork_fn)
599 error (_("checkpoint: can't find fork function in inferior."));
600
601 gdbarch = get_objfile_arch (fork_objf);
602 ret = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
603 old_chain = save_detach_fork (&temp_detach_fork);
604 detach_fork = 0;
605 ret = call_function_by_hand (fork_fn, 0, &ret);
606 do_cleanups (old_chain);
607 if (!ret) /* Probably can't happen. */
608 error (_("checkpoint: call_function_by_hand returned null."));
609
610 retpid = value_as_long (ret);
611 get_last_target_status (&last_target_ptid, &last_target_waitstatus);
612 if (from_tty)
613 {
614 int parent_pid;
615
616 printf_filtered (_("checkpoint: fork returned pid %ld.\n"),
617 (long) retpid);
618 if (info_verbose)
619 {
620 parent_pid = ptid_get_lwp (last_target_ptid);
621 if (parent_pid == 0)
622 parent_pid = ptid_get_pid (last_target_ptid);
623 printf_filtered (_(" gdb says parent = %ld.\n"),
624 (long) parent_pid);
625 }
626 }
627
628 fp = find_fork_pid (retpid);
629 if (!fp)
630 error (_("Failed to find new fork"));
631 fork_save_infrun_state (fp, 1);
632 insert_breakpoints ();
633 }
634
635 static void
636 linux_fork_context (struct fork_info *newfp, int from_tty)
637 {
638 /* Now we attempt to switch processes. */
639 struct fork_info *oldfp;
640 ptid_t ptid;
641 int id, i;
642
643 gdb_assert (newfp != NULL);
644
645 oldfp = find_fork_ptid (inferior_ptid);
646 gdb_assert (oldfp != NULL);
647
648 fork_save_infrun_state (oldfp, 1);
649 remove_breakpoints ();
650 fork_load_infrun_state (newfp);
651 insert_breakpoints ();
652
653 printf_filtered (_("Switching to %s\n"),
654 target_pid_to_str (inferior_ptid));
655
656 print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
657 }
658
659 /* Switch inferior process (fork) context, by process id. */
660 static void
661 process_command (char *args, int from_tty)
662 {
663 struct fork_info *fp;
664
665 if (!args || !*args)
666 error (_("Requires argument (process id to switch to)"));
667
668 if ((fp = find_fork_pid (parse_and_eval_long (args))) == NULL)
669 error (_("Not found: process id %s"), args);
670
671 linux_fork_context (fp, from_tty);
672 }
673
674 /* Switch inferior process (fork) context, by fork id. */
675 static void
676 fork_command (char *args, int from_tty)
677 {
678 struct fork_info *fp;
679
680 if (!args || !*args)
681 error (_("Requires argument (fork id to switch to)"));
682
683 if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
684 error (_("Not found: fork id %s"), args);
685
686 linux_fork_context (fp, from_tty);
687 }
688
689 /* Switch inferior process (fork) context, by checkpoint id. */
690 static void
691 restart_command (char *args, int from_tty)
692 {
693 struct fork_info *fp;
694
695 if (!args || !*args)
696 error (_("Requires argument (checkpoint id to restart)"));
697
698 if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
699 error (_("Not found: checkpoint id %s"), args);
700
701 linux_fork_context (fp, from_tty);
702 }
703
704 void
705 _initialize_linux_fork (void)
706 {
707 init_fork_list ();
708
709 /* Set/show detach-on-fork: user-settable mode. */
710
711 add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
712 Set whether gdb will detach the child of a fork."), _("\
713 Show whether gdb will detach the child of a fork."), _("\
714 Tells gdb whether to detach the child of a fork."),
715 NULL, NULL, &setlist, &showlist);
716
717 /* Set/show restart-auto-finish: user-settable count. Causes the
718 first "restart" of a fork to do some number of "finish" commands
719 before returning to user.
720
721 Useful because otherwise the virgin fork process will be stopped
722 somewhere in the un-interesting fork system call. */
723
724 /* Checkpoint command: create a fork of the inferior process
725 and set it aside for later debugging. */
726
727 add_com ("checkpoint", class_obscure, checkpoint_command, _("\
728 Fork a duplicate process (experimental)."));
729
730 /* Restart command: restore the context of a specified fork
731 process. May be used for "program forks" as well as for
732 "debugger forks" (checkpoints). */
733
734 add_com ("restart", class_obscure, restart_command, _("\
735 restart <n>: restore program context from a checkpoint.\n\
736 Argument 'n' is checkpoint ID, as displayed by 'info checkpoints'."));
737
738 /* Delete checkpoint command: kill the process and remove it from
739 fork list. */
740
741 add_cmd ("checkpoint", class_obscure, delete_fork_command, _("\
742 Delete a fork/checkpoint (experimental)."),
743 &deletelist);
744
745 /* Detach checkpoint command: release the process to run independently,
746 and remove it from the fork list. */
747
748 add_cmd ("checkpoint", class_obscure, detach_fork_command, _("\
749 Detach from a fork/checkpoint (experimental)."),
750 &detachlist);
751
752 /* Info checkpoints command: list all forks/checkpoints
753 currently under gdb's control. */
754
755 add_info ("checkpoints", info_forks_command,
756 _("IDs of currently known forks/checkpoints."));
757
758 /* Command aliases (let "fork" and "checkpoint" be used
759 interchangeably). */
760
761 add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &deletelist);
762 add_alias_cmd ("fork", "checkpoint", class_obscure, 1, &detachlist);
763 add_info_alias ("forks", "checkpoints", 0);
764
765 /* "fork <n>" (by analogy to "thread <n>"). */
766 add_com ("fork", class_obscure, fork_command, _("\
767 fork <n>: Switch between forked processes.\n\
768 Argument 'n' is fork ID, as displayed by 'info forks'."));
769
770 /* "process <proc id>" as opposed to "fork <fork id>". */
771 add_com ("process", class_obscure, process_command, _("\
772 process <pid>: Switch between forked processes.\n\
773 Argument 'pid' is process ID, as displayed by 'info forks' or 'shell ps'."));
774 }