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