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