This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] | |
Fixups per Daniel and Eli. Daniel, 1) Regarding register_raw_read, I just sidestepped the issue and added a PC field to my saved context. 2) Regarding threads, I could make checkpoint_command refuse if there are threads -- what's the best way to check that? I could look at to_shortname, or better, I could add an access method for the static variable "threaded" in linux-nat.
Checkpoint/Restart for Linux. * linux-nat.c: Add support for debugging multiple forks. Add #include for linux-fork.h (interface spec). (super_mourn_inferior): New function pointer. (child_mourn_inferior): New function / target method. (linux_target): Claim to_mourn_inferior method pointer. (child_follow_fork): Call interface to linux-fork, conditionally add new fork processes to list of debugged processes. (kill_inferior): Use interface to linux-fork to kill multiple processes.
* linux-fork.h: New file. * linux-fork.c: New file. Support for debugging multiple forks of the same program. Support for checkpoint and restart commands.
* Makefile.in: Add linux-fork. * config/i386/linux.mh: Add linux-fork. * doc/gdb.texinfo: Add documentation for linux-fork. * doc/gdbint.texinfo: Add internal documentation for checkpoints. * NEWS: Mention new functionality.
Add testing for checkpoint/restart and multiple fork debugging. * gdb.base/checkpoint.c: New file. * gdb.base/checkpoint.exp: New file. * gdb.base/multi-fork.c: New file. * gdb.base/multi-fork.exp: New file. * gdb.base/pi.txt: New file (data for checkpoint.c test).
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.766
diff -p -r1.766 Makefile.in
*** Makefile.in 22 Dec 2005 17:06:24 -0000 1.766
--- Makefile.in 23 Dec 2005 22:05:25 -0000
*************** MAKEOVERRIDES=
*** 1376,1382 ****
ALLDEPFILES = \
aix-thread.c \
! alpha-nat.c alphabsd-nat.c alpha-linux-nat.c \
alpha-tdep.c alpha-linux-tdep.c alphabsd-tdep.c alphanbsd-tdep.c \
alpha-osf1-tdep.c alphafbsd-tdep.c alpha-mdebug-tdep.c \
amd64-nat.c amd64-tdep.c \
--- 1376,1382 ----
ALLDEPFILES = \
aix-thread.c \
! alpha-nat.c alphabsd-nat.c alpha-linux-nat.c linux-fork.c \
alpha-tdep.c alpha-linux-tdep.c alphabsd-tdep.c alphanbsd-tdep.c \
alpha-osf1-tdep.c alphafbsd-tdep.c alpha-mdebug-tdep.c \
amd64-nat.c amd64-tdep.c \
*************** linespec.o: linespec.c $(defs_h) $(symta
*** 2179,2188 ****
$(symfile_h) $(objfiles_h) $(source_h) $(demangle_h) $(value_h) \
$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
$(objc_lang_h) $(linespec_h) $(exceptions_h)
linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
$(gdbcmd_h) $(regcache_h) $(inf_ptrace.h) $(auxv.h) $(elf_bfd_h) \
! $(gregset_h) $(gdbcore_h) $(gdbthread_h) $(gdb_stat_h)
linux-thread-db.o: linux-thread-db.c $(defs_h) $(gdb_assert_h) \
$(gdb_proc_service_h) $(gdb_thread_db_h) $(bfd_h) $(exceptions_h) \
$(gdbthread_h) $(inferior_h) $(symfile_h) $(objfiles_h) $(target_h) \
--- 2179,2190 ----
$(symfile_h) $(objfiles_h) $(source_h) $(demangle_h) $(value_h) \
$(completer_h) $(cp_abi_h) $(parser_defs_h) $(block_h) \
$(objc_lang_h) $(linespec_h) $(exceptions_h)
+ linux-fork.o: linux-fork.c linux-fork.h $(defs_h) $(inferior_h) \
+ $(regcache_h) $(gdbcmd_h) $(infcall_h)
linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
$(gdbcmd_h) $(regcache_h) $(inf_ptrace.h) $(auxv.h) $(elf_bfd_h) \
! $(gregset_h) $(gdbcore_h) $(gdbthread_h) $(gdb_stat_h) linux-fork.h
linux-thread-db.o: linux-thread-db.c $(defs_h) $(gdb_assert_h) \
$(gdb_proc_service_h) $(gdb_thread_db_h) $(bfd_h) $(exceptions_h) \
$(gdbthread_h) $(inferior_h) $(symfile_h) $(objfiles_h) $(target_h) \
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.181
diff -p -r1.181 NEWS
*** NEWS 8 Dec 2005 19:13:00 -0000 1.181
--- NEWS 23 Dec 2005 22:05:25 -0000
***************
*** 8,13 ****
--- 8,42 ----
init-if-undefined Initialize a convenience variable, but
only if it doesn't already have a value.
+ The following commands are presently only implemented for native GNU/Linux:
+
+ checkpoint Save a snapshot of the program state.
+
+ restart <n> Return the program state to a
+ previously saved state.
+
+ info checkpoints List currently saved checkpoints.
+
+ delete-checkpoint <n> Delete a previously saved checkpoint.
+
+ set|show detach-on-fork Tell gdb whether to detach from a newly
+ forked process, or to keep debugging it.
+
+ info forks List forks of the user program that
+ are available to be debugged.
+
+ fork <n> Switch to debugging one of several
+ forks of the user program that are
+ available to be debugged.
+
+ delete-fork <n> Delete a fork from the list of forks
+ that are available to be debugged (and
+ kill the forked process).
+
+ detach-fork <n> Delete a fork from the list of forks
+ that are available to be debugged (and
+ allow the process to continue).
+
* New architecture
Morpho Technologies ms2 ms1-elf
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.208
diff -p -r1.208 infrun.c
*** infrun.c 17 Dec 2005 22:34:01 -0000 1.208
--- infrun.c 23 Dec 2005 22:05:28 -0000
*************** get_last_target_status (ptid_t *ptidp, s
*** 1102,1107 ****
--- 1102,1113 ----
*status = target_last_waitstatus;
}
+ void
+ nullify_last_target_wait_ptid (void)
+ {
+ target_last_wait_ptid = minus_one_ptid;
+ }
+
/* Switch thread contexts, maintaining "infrun state". */
static void
Index: linux-fork.c
===================================================================
RCS file: linux-fork.c
diff -N linux-fork.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- linux-fork.c 23 Dec 2005 22:05:28 -0000
***************
*** 0 ****
--- 1,680 ----
+ /* GNU/Linux native-dependent code for debugging multiple forks.
+
+ Copyright 2005 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ #include "defs.h" /* Standard includes */
+ #include "inferior.h"
+ #include "regcache.h" /* For regcache copy/restore */
+ #include "gdbcmd.h"
+ #include "infcall.h" /* For call_function_by_hand */
+ #include "gdb_string.h"
+ #include "linux-fork.h" /* External interface */
+
+ #include <sys/ptrace.h>
+ #include <sys/wait.h>
+ #include <sys/param.h> /* For MAXPATHLEN */
+ #include <dirent.h>
+ #include <ctype.h>
+
+ struct fork_info *fork_list;
+ static int highest_fork_num;
+
+ int detach_fork = 1; /* Default behavior is to detach
+ newly forked processes (legacy). */
+
+ /* Fork list data structure: */
+ struct fork_info
+ {
+ struct fork_info *next;
+ ptid_t ptid;
+ int num; /* Convenient handle (GDB fork id) */
+ struct regcache *savedregs; /* Convenient for info fork, saves
+ having to actually switch contexts. */
+ int clobber_regs; /* True if we should restore saved regs. */
+ ULONGEST pc; /* PC for info fork. */
+ off_t *filepos; /* Set of open file descriptors' offsets. */
+ int maxfd;
+ };
+
+ /* Fork list methods: */
+
+ /* Add a fork to internal fork list.
+ Called from linux child_follow_fork. */
+
+ extern struct fork_info *
+ add_fork (pid_t pid)
+ {
+ struct fork_info *fp;
+
+ if (fork_list == NULL &&
+ pid != PIDGET (inferior_ptid))
+ {
+ /* Special case -- if this is the first fork in the list
+ (the list is hitherto empty), and if this new fork is
+ NOT the current inferior_ptid, then add inferior_ptid
+ first, as a special zeroeth fork id. */
+ highest_fork_num = -1;
+ add_fork (PIDGET (inferior_ptid)); /* safe recursion */
+ }
+
+ fp = XZALLOC (struct fork_info);
+ fp->ptid = pid_to_ptid (pid);
+ fp->num = ++highest_fork_num;
+ fp->next = fork_list;
+ fork_list = fp;
+ return fp;
+ }
+
+ static void
+ free_fork (struct fork_info *fp)
+ {
+ /* Notes on step-resume breakpoints: since this is a concern for
+ threads, let's convince ourselves that it's not a concern for
+ forks. There are two ways for a fork_info to be created. First,
+ by the checkpoint command, in which case we're at a gdb prompt
+ and there can't be any step-resume breakpoint. Second, by a fork
+ in the user program, in which case we *may* have stepped into the
+ fork call, but regardless of whether we follow the parent or the
+ child, we will return to the same place and the step-resume
+ breakpoint, if any, will take care of itself as usual. And
+ unlike threads, we do not save a private copy of the step-resume
+ breakpoint -- so we're OK. */
+
+ if (fp)
+ {
+ if (fp->savedregs)
+ regcache_xfree (fp->savedregs);
+ if (fp->filepos)
+ xfree (fp->filepos);
+ xfree (fp);
+ }
+ }
+
+ static void
+ delete_fork (ptid_t ptid)
+ {
+ struct fork_info *fp, *fpprev;
+
+ fpprev = NULL;
+
+ for (fp = fork_list; fp; fpprev = fp, fp = fp->next)
+ if (ptid_equal (fp->ptid, ptid))
+ break;
+
+ if (!fp)
+ return;
+
+ if (fpprev)
+ fpprev->next = fp->next;
+ else
+ fork_list = fp->next;
+
+ free_fork (fp);
+
+ /* Special case: if there is now only one process in the list,
+ and if it is (hopefully!) the current inferior_ptid, then
+ remove it, leaving the list empty -- we're now down to the
+ default case of debugging a single process. */
+ if (fork_list != NULL && fork_list->next == NULL &&
+ ptid_equal (fork_list->ptid, inferior_ptid))
+ {
+ /* Last fork -- delete from list and handle as solo process
+ (should be a safe recursion). */
+ delete_fork (inferior_ptid);
+ }
+ }
+
+ /* Find a fork_info by matching PTID. */
+ static struct fork_info *
+ find_fork_ptid (ptid_t ptid)
+ {
+ struct fork_info *fp;
+
+ for (fp = fork_list; fp; fp = fp->next)
+ if (ptid_equal (fp->ptid, ptid))
+ return fp;
+
+ return NULL;
+ }
+
+ /* Find a fork_info by matching ID. */
+ static struct fork_info *
+ find_fork_id (int num)
+ {
+ struct fork_info *fp;
+
+ for (fp = fork_list; fp; fp = fp->next)
+ if (fp->num == num)
+ return fp;
+
+ return NULL;
+ }
+
+ /* Find a fork_info by matching pid. */
+ extern struct fork_info *
+ find_fork_pid (pid_t pid)
+ {
+ struct fork_info *fp;
+
+ for (fp = fork_list; fp; fp = fp->next)
+ if (pid == ptid_get_pid (fp->ptid))
+ return fp;
+
+ return NULL;
+ }
+
+ static ptid_t
+ fork_id_to_ptid (int num)
+ {
+ struct fork_info *fork = find_fork_id (num);
+ if (fork)
+ return fork->ptid;
+ else
+ return pid_to_ptid (-1);
+ }
+
+ static void
+ init_fork_list (void)
+ {
+ struct fork_info *fp, *fpnext;
+
+ if (!fork_list)
+ return;
+
+ for (fp = fork_list; fp; fp = fpnext)
+ {
+ fpnext = fp->next;
+ free_fork (fp);
+ }
+
+ fork_list = NULL;
+ }
+
+ /* Fork list <-> gdb interface. */
+
+ /* call_lseek -- utility function for fork_load/fork_save.
+ Calls lseek in the (current) inferior process. */
+ static off_t
+ call_lseek (int fd, off_t offset, int whence)
+ {
+ char exp[80];
+
+ snprintf (&exp[0], sizeof (exp), "lseek (%d, %ld, %d)",
+ fd, (long) offset, whence);
+ return (off_t) parse_and_eval_long (&exp[0]);
+ }
+
+ /* Load infrun state for the fork PTID. */
+
+ static void
+ fork_load_infrun_state (struct fork_info *fp)
+ {
+ extern void nullify_last_target_wait_ptid ();
+ int i;
+
+ if (fp->savedregs && fp->clobber_regs)
+ regcache_cpy (current_regcache, fp->savedregs);
+
+ nullify_last_target_wait_ptid ();
+
+ /* Now restore the file positions of open file descriptors. */
+ if (fp->filepos)
+ {
+ for (i = 0; i <= fp->maxfd; i++)
+ if (fp->filepos[i] != (off_t) -1)
+ call_lseek (i, fp->filepos[i], SEEK_SET);
+ /* NOTE: I can get away with using SEEK_SET and SEEK_CUR because
+ this is native-only. If it ever has to be cross, we'll have
+ to rethink this. */
+ }
+ }
+
+ /* Save infrun state for the fork PTID.
+ Exported for use by linux child_follow_fork. */
+
+ extern void
+ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
+ {
+ char path[MAXPATHLEN];
+ struct dirent *de;
+ DIR *d;
+
+ if (fp->savedregs)
+ regcache_xfree (fp->savedregs);
+
+ fp->savedregs = regcache_dup (current_regcache);
+ fp->clobber_regs = clobber_regs;
+ fp->pc = read_pc ();
+
+ if (clobber_regs)
+ {
+ /* Now save the 'state' (file position) of all open file descriptors.
+ Unfortunately fork does not take care of that for us... */
+ snprintf (path, MAXPATHLEN, "/proc/%ld/fd", (long) PIDGET (fp->ptid));
+ if ((d = opendir (path)) != NULL)
+ {
+ long tmp;
+
+ fp->maxfd = 0;
+ while ((de = readdir (d)) != NULL)
+ {
+ /* Count open file descriptors (actually find highest
+ numbered). */
+ tmp = strtol (&de->d_name[0], NULL, 10);
+ if (fp->maxfd < tmp)
+ fp->maxfd = tmp;
+ }
+ /* Allocate array of file positions. */
+ fp->filepos = xrealloc (fp->filepos,
+ (fp->maxfd + 1) * sizeof (*fp->filepos));
+
+ /* Initialize to -1 (invalid). */
+ for (tmp = 0; tmp <= fp->maxfd; tmp++)
+ fp->filepos[tmp] = -1;
+
+ /* Now find actual file positions. */
+ rewinddir (d);
+ while ((de = readdir (d)) != NULL)
+ if (isdigit (de->d_name[0]))
+ {
+ tmp = strtol (&de->d_name[0], NULL, 10);
+ fp->filepos[tmp] = call_lseek (tmp, 0, SEEK_CUR);
+ }
+ closedir (d);
+ }
+ }
+ }
+
+ /* linux_fork_killall. Let God sort 'em out... */
+
+ extern void
+ linux_fork_killall (void)
+ {
+ /* Walk list and kill every pid. No need to treat the
+ current inferior_ptid as special (we do not return a
+ status for it) -- however any process may be a child
+ or a parent, so may get a SIGCHLD from a previously
+ killed child. Wait them all out. */
+ pid_t pid, ret;
+ int status;
+
+ do {
+ pid = PIDGET (fork_list->ptid);
+ do {
+ ptrace (PT_KILL, pid, 0, 0);
+ ret = waitpid (pid, &status, 0);
+ } while (ret == pid && WIFSTOPPED (status));
+ delete_fork (fork_list->ptid);
+ } while (fork_list != NULL);
+ }
+
+ /* linux_fork_mourn_inferior. The current inferior_ptid has exited,
+ but there are other viable forks to debug. Delete the exiting one
+ and context-switch to the first available. */
+
+ extern void
+ linux_fork_mourn_inferior (void)
+ {
+ /* Wait just one more time to collect the inferior's exit status.
+ Do not check whether this succeeds though, since we may be
+ dealing with a process that we attached to. Such a process will
+ only report its exit status to its original parent. */
+ int status;
+
+ waitpid (ptid_get_pid (inferior_ptid), &status, 0);
+
+ /* OK, presumably inferior_ptid is the one who has exited.
+ We need to delete that one from the fork_list, and switch
+ to the next available fork. */
+ delete_fork (inferior_ptid);
+ if (fork_list) /* Paranoia, shouldn't happen. */
+ {
+ inferior_ptid = fork_list[0].ptid;
+ printf_filtered (_("[Switching to %s]\n"),
+ target_pid_to_str (inferior_ptid));
+ }
+ }
+
+ /* Fork list <-> user interface. */
+
+ static void
+ delete_fork_command (char *args, int from_tty)
+ {
+ ptid_t ptid;
+
+ if (!args || !*args)
+ error (_("Requires argument (fork/checkpoint id to delete)"));
+
+ ptid = fork_id_to_ptid (parse_and_eval_long (args));
+ if (ptid_equal (ptid, minus_one_ptid))
+ error (_("No such fork/checkpoint id, %s"), args);
+
+ if (ptid_equal (ptid, inferior_ptid))
+ error (_("Please switch to another fork/checkpoint before deleting the current one"));
+
+ if (ptrace (PTRACE_KILL, ptid, 0, 0))
+ error (_("Unable to kill pid %s"), target_tid_to_str (ptid));
+
+ if (from_tty)
+ printf_filtered (_("Killed %s\n"), target_pid_to_str (ptid));
+
+ delete_fork (ptid);
+ }
+
+ static void
+ detach_fork_command (char *args, int from_tty)
+ {
+ ptid_t ptid;
+
+ if (!args || !*args)
+ error (_("Requires argument (fork id to detach)"));
+
+ ptid = fork_id_to_ptid (parse_and_eval_long (args));
+ if (ptid_equal (ptid, minus_one_ptid))
+ error (_("No such fork id, %s"), args);
+
+ if (ptid_equal (ptid, inferior_ptid))
+ error (_("Please switch to another fork before detaching the current one"));
+
+ if (ptrace (PTRACE_DETACH, ptid, 0, 0))
+ error (_("Unable to detach %s"), target_pid_to_str (ptid));
+
+ if (from_tty)
+ printf_filtered (_("Detached %s\n"), target_pid_to_str (ptid));
+
+ delete_fork (ptid);
+ }
+
+ /* Print information about currently known forks. */
+
+ static void
+ info_forks_command (char *arg, int from_tty)
+ {
+ struct frame_info *cur_frame;
+ struct symtab_and_line sal;
+ struct symtab *cur_symtab;
+ struct fork_info *fp;
+ int cur_line;
+ ULONGEST pc;
+
+ for (fp = fork_list; fp; fp = fp->next)
+ {
+ if (ptid_equal (fp->ptid, inferior_ptid))
+ {
+ printf_filtered ("* ");
+ pc = read_pc ();
+ }
+ else
+ {
+ printf_filtered (" ");
+ pc = fp->pc;
+ }
+ printf_filtered ("%d %s", fp->num, target_pid_to_str (fp->ptid));
+ if (fp->num == 0)
+ printf_filtered (_(" (main process)"));
+ printf_filtered (_(" at "));
+ deprecated_print_address_numeric (pc, 1, gdb_stdout);
+
+ sal = find_pc_line (pc, 0);
+ if (sal.symtab)
+ {
+ char *tmp = strrchr (sal.symtab->filename, '/');
+
+ if (tmp)
+ printf_filtered (_(", file %s"), tmp + 1);
+ else
+ printf_filtered (_(", file %s"), sal.symtab->filename);
+ }
+ if (sal.line)
+ printf_filtered (_(", line %d"), sal.line);
+ if (!sal.symtab && !sal.line)
+ {
+ struct minimal_symbol *msym;
+
+ msym = lookup_minimal_symbol_by_pc (pc);
+ if (msym)
+ printf_filtered (", <%s>", SYMBOL_LINKAGE_NAME (msym));
+ }
+
+ putchar_filtered ('\n');
+ }
+ }
+
+ /* Save/restore mode variable 'detach_fork':
+ We need to temporarily take over this mode variable, while
+ preserving the user-specified state, and make sure that it
+ gets restored in case of error.
+
+ The int pointer that we use comes from the caller, so we can
+ be called more than once (even though currently we don't need to). */
+
+ static void
+ restore_detach_fork (void *arg)
+ {
+ detach_fork = *(int *) arg;
+ }
+
+ static struct cleanup *
+ save_detach_fork (int *saved_val)
+ {
+ *saved_val = detach_fork;
+ return make_cleanup (restore_detach_fork, (void *) saved_val);
+ }
+
+ static void
+ checkpoint_command (char *args, int from_tty)
+ {
+ struct target_waitstatus last_target_waitstatus;
+ ptid_t last_target_ptid;
+ struct value *fork_fn = NULL, *ret;
+ struct fork_info *fp;
+ pid_t retpid;
+ struct cleanup *old_chain;
+ long i;
+ /* Make this temp var static, 'cause it's used in the error context. */
+ static int temp_detach_fork;
+
+ /* Make the inferior fork, record its (and gdb's) state. */
+
+ if (lookup_minimal_symbol ("fork", NULL, NULL) != NULL)
+ fork_fn = find_function_in_inferior ("fork");
+ if (!fork_fn)
+ if (lookup_minimal_symbol ("_fork", NULL, NULL) != NULL)
+ fork_fn = find_function_in_inferior ("fork");
+ if (!fork_fn)
+ error (_("checkpoint: can't find fork function in inferior."));
+
+ ret = value_from_longest (builtin_type_int, 0);
+ old_chain = save_detach_fork (&temp_detach_fork);
+ detach_fork = 0;
+ ret = call_function_by_hand (fork_fn, 0, &ret);
+ do_cleanups (old_chain);
+ if (!ret) /* Probably can't happen. */
+ error (_("checkpoint: call_function_by_hand returned null."));
+
+ retpid = value_as_long (ret);
+ get_last_target_status (&last_target_ptid, &last_target_waitstatus);
+ if (from_tty)
+ {
+ int parent_pid;
+
+ printf_filtered (_("checkpoint: fork returned pid %ld.\n"),
+ (long) retpid);
+ if (info_verbose)
+ {
+ parent_pid = ptid_get_lwp (last_target_ptid);
+ if (parent_pid == 0)
+ parent_pid = ptid_get_pid (last_target_ptid);
+ printf_filtered (_(" gdb says parent = %ld.\n"),
+ (long) parent_pid);
+ }
+ }
+
+ fp = find_fork_pid (retpid);
+ if (!fp)
+ error (_("Failed to find new fork"));
+ fork_save_infrun_state (fp, 1);
+ }
+
+ static void
+ linux_fork_context (struct fork_info *newfp, int from_tty)
+ {
+ /* Now we attempt to switch processes. */
+ struct fork_info *oldfp = find_fork_ptid (inferior_ptid);
+ ptid_t ptid;
+ int id, i;
+
+ if (!newfp)
+ error (_("No such fork/process"));
+
+ if (!oldfp)
+ {
+ oldfp = add_fork (ptid_get_pid (inferior_ptid));
+ }
+
+ fork_save_infrun_state (oldfp, 1);
+ inferior_ptid = newfp->ptid;
+ fork_load_infrun_state (newfp);
+ registers_changed ();
+ reinit_frame_cache ();
+ stop_pc = read_pc ();
+ select_frame (get_current_frame ());
+
+ printf_filtered (_("Switching to %s\n"),
+ target_pid_to_str (inferior_ptid));
+
+ print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
+ }
+
+ /* Switch inferior process (fork) context, by process id. */
+ static void
+ process_command (char *args, int from_tty)
+ {
+ struct fork_info *fp;
+
+ if (!args || !*args)
+ error (_("Requires argument (process id to switch to)"));
+
+ if ((fp = find_fork_pid (parse_and_eval_long (args))) == NULL)
+ error (_("Not found: process id %s"), args);
+
+ linux_fork_context (fp, from_tty);
+ }
+
+ /* Switch inferior process (fork) context, by fork id. */
+ static void
+ fork_command (char *args, int from_tty)
+ {
+ struct fork_info *fp;
+
+ if (!args || !*args)
+ error (_("Requires argument (fork id to switch to)"));
+
+ if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
+ error (_("Not found: fork id %s"), args);
+
+ linux_fork_context (fp, from_tty);
+ }
+
+ /* Switch inferior process (fork) context, by checkpoint id. */
+ static void
+ restart_command (char *args, int from_tty)
+ {
+ struct fork_info *fp;
+
+ if (!args || !*args)
+ error (_("Requires argument (checkpoint id to restart)"));
+
+ if ((fp = find_fork_id (parse_and_eval_long (args))) == NULL)
+ error (_("Not found: checkpoint id %s"), args);
+
+ linux_fork_context (fp, from_tty);
+ }
+
+ /* Extern because called from core gdb. */
+ extern void
+ _initialize_linux_fork (void)
+ {
+ init_fork_list ();
+
+ /* Set/show detach-on-fork: user-settable mode. */
+
+ add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
+ Set whether gdb will detach the child of a fork."), _("\
+ Show whether gdb will detach the child of a fork."), _("\
+ Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
+ /* Set/show restart-auto-finish: user-settable count. Causes the
+ first "restart" of a fork to do some number of "finish" commands
+ before returning to user.
+
+ Useful because otherwise the virgin fork process will be stopped
+ somewhere in the un-interesting fork system call. */
+
+ /* Checkpoint command: create a fork of the inferior process
+ and set it aside for later debugging. */
+
+ add_com ("checkpoint", class_obscure, checkpoint_command, _("\
+ Fork a duplicate process (experimental)."));
+
+ /* Restart command: restore the context of a specified fork
+ process. May be used for "program forks" as well as for
+ "debugger forks" (checkpoints). */
+
+ add_com ("restart", class_obscure, restart_command, _("\
+ restart <n>: restore program context from a checkpoint.\n\
+ Argument 'n' is checkpoint ID, as displayed by 'info checkpoints'."));
+
+ /* Delete-checkpoint command: kill the process and remove it from
+ fork list. */
+
+ add_com ("delete-checkpoint", class_obscure, delete_fork_command, _("\
+ Delete a fork/checkpoint (experimental)."));
+
+ /* Detach-checkpoint command: release the process to run independantly,
+ and remove it from the fork list. */
+
+ add_com ("detach-checkpoint", class_obscure, detach_fork_command, _("\
+ Detach from a fork/checkpoint (experimental)."));
+
+ /* Info checkpoints command: list all forks/checkpoints
+ currently under gdb's control. */
+
+ add_info ("checkpoints", info_forks_command,
+ _("IDs of currently known forks/checkpoints."));
+
+ /* Command aliases (let "fork" and "checkpoint" be used
+ interchangeably). */
+
+ add_com_alias ("delete-fork", "delete-checkpoint", class_obscure, 1);
+ add_com_alias ("detach-fork", "detach-checkpoint", class_obscure, 1);
+ add_info_alias ("forks", "checkpoints", 0);
+
+ /* "fork <n>" (by analogy to "thread <n>"). */
+ add_com ("fork", class_obscure, fork_command, _("\
+ fork <n>: Switch between forked processes.\n\
+ Argument 'n' is fork ID, as displayed by 'info forks'."));
+
+ /* "process <proc id>" as opposed to "fork <fork id>". */
+ add_com ("process", class_obscure, process_command, _("\
+ process <pid>: Switch between forked processes.\n\
+ Argument 'pid' is process ID, as displayed by 'info forks' or 'shell ps'."));
+ }
Index: linux-fork.h
===================================================================
RCS file: linux-fork.h
diff -N linux-fork.h
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- linux-fork.h 23 Dec 2005 22:05:28 -0000
***************
*** 0 ****
--- 1,33 ----
+ /* GNU/Linux native-dependent code for debugging multiple forks.
+
+ Copyright 2005 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ struct fork_info;
+ extern struct fork_info *add_fork (pid_t);
+ extern struct fork_info *find_fork_pid (pid_t);
+ extern void fork_save_infrun_state (struct fork_info *, int);
+ extern void linux_fork_killall (void);
+ extern void linux_fork_mourn_inferior (void);
+
+ struct fork_info *fork_list;
+ #define FORKS_EXIST() (fork_list != NULL)
+
+ extern int detach_fork;
+
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.35
diff -p -r1.35 linux-nat.c
*** linux-nat.c 17 Dec 2005 22:34:01 -0000 1.35
--- linux-nat.c 23 Dec 2005 22:05:29 -0000
***************
*** 31,36 ****
--- 31,37 ----
#endif
#include <sys/ptrace.h>
#include "linux-nat.h"
+ #include "linux-fork.h"
#include "gdbthread.h"
#include "gdbcmd.h"
#include "regcache.h"
***************
*** 87,98 ****
the use of the multi-threaded target. */
static struct target_ops *linux_ops;
! /* The saved to_xfer_partial method, inherited from inf-ptrace.c. Called
! by our to_xfer_partial. */
! static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
! const char *, gdb_byte *, const gdb_byte *,
ULONGEST, LONGEST);
static int debug_linux_nat;
static void
show_debug_linux_nat (struct ui_file *file, int from_tty,
--- 88,105 ----
the use of the multi-threaded target. */
static struct target_ops *linux_ops;
! /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
! Called by our to_xfer_partial. */
! static LONGEST (*super_xfer_partial) (struct target_ops *,
! enum target_object,
! const char *, gdb_byte *,
! const gdb_byte *,
ULONGEST, LONGEST);
+ /* The saved to_mourn_inferior method, inherited from inf-ptrace.c.
+ Called by our to_mourn_inferior. */
+ static void (*super_mourn_inferior) (void);
+
static int debug_linux_nat;
static void
show_debug_linux_nat (struct ui_file *file, int from_tty,
*************** child_follow_fork (struct target_ops *op
*** 363,377 ****
also, but they'll be reinserted below. */
detach_breakpoints (child_pid);
! if (debug_linux_nat)
{
! target_terminal_ours ();
! fprintf_unfiltered (gdb_stdlog,
! "Detaching after fork from child process %d.\n",
! child_pid);
! }
! ptrace (PTRACE_DETACH, child_pid, 0, 0);
if (has_vforked)
{
--- 370,397 ----
also, but they'll be reinserted below. */
detach_breakpoints (child_pid);
! /* Detach new forked process? */
! if (detach_fork)
{
! if (debug_linux_nat)
! {
! target_terminal_ours ();
! fprintf_filtered (gdb_stdlog,
! "Detaching after fork from child process %d.\n",
! child_pid);
! }
! ptrace (PTRACE_DETACH, child_pid, 0, 0);
! }
! else
! {
! struct fork_info *fp;
! /* Retain child fork in ptrace (stopped) state. */
! fp = find_fork_pid (child_pid);
! if (!fp)
! fp = add_fork (child_pid);
! fork_save_infrun_state (fp, 0);
! }
if (has_vforked)
{
*************** child_follow_fork (struct target_ops *op
*** 441,449 ****
if (debug_linux_nat)
{
target_terminal_ours ();
! fprintf_unfiltered (gdb_stdlog,
! "Attaching after fork to child process %d.\n",
! child_pid);
}
/* If we're vforking, we may want to hold on to the parent until
--- 461,469 ----
if (debug_linux_nat)
{
target_terminal_ours ();
! fprintf_filtered (gdb_stdlog,
! "Attaching after fork to child process %d.\n",
! child_pid);
}
/* If we're vforking, we may want to hold on to the parent until
*************** child_follow_fork (struct target_ops *op
*** 466,478 ****
if (has_vforked)
linux_parent_pid = parent_pid;
else
! target_detach (NULL, 0);
inferior_ptid = pid_to_ptid (child_pid);
/* Reinstall ourselves, since we might have been removed in
target_detach (which does other necessary cleanup). */
push_target (ops);
/* Reset breakpoints in the child as appropriate. */
--- 486,510 ----
if (has_vforked)
linux_parent_pid = parent_pid;
+ else if (!detach_fork)
+ {
+ struct fork_info *fp;
+ /* Retain parent fork in ptrace (stopped) state. */
+ fp = find_fork_pid (parent_pid);
+ if (!fp)
+ fp = add_fork (parent_pid);
+ fork_save_infrun_state (fp, 0);
+ }
else
! {
! target_detach (NULL, 0);
! }
inferior_ptid = pid_to_ptid (child_pid);
/* Reinstall ourselves, since we might have been removed in
target_detach (which does other necessary cleanup). */
+
push_target (ops);
/* Reset breakpoints in the child as appropriate. */
*************** kill_inferior (void)
*** 579,611 ****
if (pid == 0)
return;
! /* If we're stopped while forking and we haven't followed yet, kill the
! other task. We need to do this first because the parent will be
! sleeping if this is a vfork. */
!
! get_last_target_status (&last_ptid, &last);
!
! if (last.kind == TARGET_WAITKIND_FORKED
! || last.kind == TARGET_WAITKIND_VFORKED)
{
! ptrace (PT_KILL, last.value.related_pid, 0, 0);
! wait (&status);
}
! /* Kill the current process. */
! ptrace (PT_KILL, pid, 0, 0);
! ret = wait (&status);
! /* We might get a SIGCHLD instead of an exit status. This is
! aggravated by the first kill above - a child has just died. */
! while (ret == pid && WIFSTOPPED (status))
! {
ptrace (PT_KILL, pid, 0, 0);
ret = wait (&status);
- }
! target_mourn_inferior ();
}
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
--- 611,652 ----
if (pid == 0)
return;
! /* First cut -- let's crudely do everything inline. */
! if (FORKS_EXIST ())
{
! linux_fork_killall ();
! pop_target ();
! generic_mourn_inferior ();
}
+ else
+ {
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the other task. We need to do this first because the
+ parent will be sleeping if this is a vfork. */
! get_last_target_status (&last_ptid, &last);
! if (last.kind == TARGET_WAITKIND_FORKED
! || last.kind == TARGET_WAITKIND_VFORKED)
! {
! ptrace (PT_KILL, last.value.related_pid, 0, 0);
! wait (&status);
! }
! /* Kill the current process. */
ptrace (PT_KILL, pid, 0, 0);
ret = wait (&status);
! /* We might get a SIGCHLD instead of an exit status. This is
! aggravated by the first kill above - a child has just died. */
!
! while (ret == pid && WIFSTOPPED (status))
! {
! ptrace (PT_KILL, pid, 0, 0);
! ret = wait (&status);
! }
! target_mourn_inferior ();
! }
}
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
*************** select_event_lwp (struct lwp_info **orig
*** 1677,1683 ****
int random_selector;
struct lwp_info *event_lp;
! /* Record the wait status for the origional LWP. */
(*orig_lp)->status = *status;
/* Give preference to any LWP that is being single-stepped. */
--- 1718,1724 ----
int random_selector;
struct lwp_info *event_lp;
! /* Record the wait status for the original LWP. */
(*orig_lp)->status = *status;
/* Give preference to any LWP that is being single-stepped. */
*************** resumed_callback (struct lwp_info *lp, v
*** 1729,1734 ****
--- 1770,1799 ----
return lp->resumed;
}
+ /* Local mourn_inferior -- we need to override mourn_inferior
+ so that we can do something clever if one of several forks
+ has exited. */
+
+ static void
+ child_mourn_inferior (void)
+ {
+ int status;
+
+ if (! FORKS_EXIST ())
+ {
+ /* Normal case, no other forks available. */
+ super_mourn_inferior ();
+ return;
+ }
+ else
+ {
+ /* Multi-fork case. The current inferior_ptid has exited, but
+ there are other viable forks to debug. Delete the exiting
+ one and context-switch to the first available. */
+ linux_fork_mourn_inferior ();
+ }
+ }
+
/* We need to override child_wait to support attaching to cloned
processes, since a normal wait (as done by the default version)
ignores those processes. */
*************** linux_target (void)
*** 3201,3206 ****
--- 3266,3274 ----
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
+ super_mourn_inferior = t->to_mourn_inferior;
+ t->to_mourn_inferior = child_mourn_inferior;
+
linux_ops = t;
return t;
}
*************** lin_thread_get_thread_signals (sigset_t
*** 3312,3314 ****
--- 3380,3383 ----
/* ... except during a sigsuspend. */
sigdelset (&suspend_mask, cancel);
}
+
Index: config/alpha/alpha-linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/alpha/alpha-linux.mh,v
retrieving revision 1.18
diff -p -r1.18 alpha-linux.mh
*** config/alpha/alpha-linux.mh 10 Sep 2005 18:11:07 -0000 1.18
--- config/alpha/alpha-linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 2,8 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o corelow.o alpha-nat.o alpha-linux-nat.o \
fork-child.o proc-service.o linux-thread-db.o gcore.o \
! linux-nat.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
--- 2,8 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o corelow.o alpha-nat.o alpha-linux-nat.o \
fork-child.o proc-service.o linux-thread-db.o gcore.o \
! linux-nat.o linux-fork.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
Index: config/arm/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/arm/linux.mh,v
retrieving revision 1.16
diff -p -r1.16 linux.mh
*** config/arm/linux.mh 10 Sep 2005 18:11:09 -0000 1.16
--- config/arm/linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 3,9 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
core-regset.o arm-linux-nat.o gcore.o \
! proc-service.o linux-thread-db.o linux-nat.o
LOADLIBES= -ldl -rdynamic
--- 3,9 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
core-regset.o arm-linux-nat.o gcore.o \
! proc-service.o linux-thread-db.o linux-nat.o linux-fork.o
LOADLIBES= -ldl -rdynamic
Index: config/i386/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mh,v
retrieving revision 1.18
diff -p -r1.18 linux.mh
*** config/i386/linux.mh 10 Sep 2005 18:11:10 -0000 1.18
--- config/i386/linux.mh 23 Dec 2005 22:05:31 -0000
*************** NAT_FILE= nm-linux.h
*** 4,10 ****
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
core-aout.o i386-nat.o i386-linux-nat.o \
proc-service.o linux-thread-db.o gcore.o \
! linux-nat.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
--- 4,10 ----
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
core-aout.o i386-nat.o i386-linux-nat.o \
proc-service.o linux-thread-db.o gcore.o \
! linux-nat.o linux-fork.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
Index: config/i386/linux64.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux64.mh,v
retrieving revision 1.6
diff -p -r1.6 linux64.mh
*** config/i386/linux64.mh 10 Sep 2005 18:11:10 -0000 1.6
--- config/i386/linux64.mh 23 Dec 2005 22:05:31 -0000
***************
*** 1,7 ****
# Host: GNU/Linux x86-64
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o amd64-nat.o amd64-linux-nat.o linux-nat.o \
! proc-service.o linux-thread-db.o gcore.o
NAT_FILE= nm-linux64.h
# The dynamically loaded libthread_db needs access to symbols in the
--- 1,7 ----
# Host: GNU/Linux x86-64
NATDEPFILES= inf-ptrace.o fork-child.o \
i386-nat.o amd64-nat.o amd64-linux-nat.o linux-nat.o \
! proc-service.o linux-thread-db.o gcore.o linux-fork.o
NAT_FILE= nm-linux64.h
# The dynamically loaded libthread_db needs access to symbols in the
Index: config/ia64/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/linux.mh,v
retrieving revision 1.19
diff -p -r1.19 linux.mh
*** config/ia64/linux.mh 10 Sep 2005 18:11:11 -0000 1.19
--- config/ia64/linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 3,8 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o gcore.o \
core-aout.o core-regset.o ia64-linux-nat.o \
! proc-service.o linux-thread-db.o linux-nat.o
LOADLIBES = -ldl -rdynamic
--- 3,8 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o gcore.o \
core-aout.o core-regset.o ia64-linux-nat.o \
! proc-service.o linux-thread-db.o linux-nat.o linux-fork.o
LOADLIBES = -ldl -rdynamic
Index: config/m32r/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/m32r/linux.mh,v
retrieving revision 1.3
diff -p -r1.3 linux.mh
*** config/m32r/linux.mh 10 Sep 2005 18:11:11 -0000 1.3
--- config/m32r/linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 3,8 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
m32r-linux-nat.o gcore.o proc-service.o linux-thread-db.o \
! linux-nat.o
LOADLIBES= -ldl -rdynamic
--- 3,8 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o \
m32r-linux-nat.o gcore.o proc-service.o linux-thread-db.o \
! linux-nat.o linux-fork.o
LOADLIBES= -ldl -rdynamic
Index: config/m68k/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/m68k/linux.mh,v
retrieving revision 1.17
diff -p -r1.17 linux.mh
*** config/m68k/linux.mh 10 Sep 2005 18:11:12 -0000 1.17
--- config/m68k/linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 3,9 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
corelow.o core-aout.o m68klinux-nat.o gcore.o \
! proc-service.o linux-thread-db.o linux-nat.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
--- 3,9 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
corelow.o core-aout.o m68klinux-nat.o gcore.o \
! proc-service.o linux-thread-db.o linux-nat.o linux-fork.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
Index: config/mips/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/mips/linux.mh,v
retrieving revision 1.10
diff -p -r1.10 linux.mh
*** config/mips/linux.mh 10 Sep 2005 18:11:12 -0000 1.10
--- config/mips/linux.mh 23 Dec 2005 22:05:31 -0000
***************
*** 2,7 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
linux-thread-db.o proc-service.o gcore.o \
! linux-nat.o
LOADLIBES = -ldl -rdynamic
--- 2,7 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
linux-thread-db.o proc-service.o gcore.o \
! linux-nat.o linux-fork.o
LOADLIBES = -ldl -rdynamic
Index: config/pa/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/pa/linux.mh,v
retrieving revision 1.6
diff -p -r1.6 linux.mh
*** config/pa/linux.mh 10 Sep 2005 18:11:12 -0000 1.6
--- config/pa/linux.mh 23 Dec 2005 22:05:31 -0000
*************** XDEPFILES=
*** 3,8 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o gcore.o \
core-regset.o hppa-linux-nat.o \
! proc-service.o linux-thread-db.o linux-nat.o
LOADLIBES = -ldl -rdynamic
--- 3,8 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o corelow.o gcore.o \
core-regset.o hppa-linux-nat.o \
! proc-service.o linux-thread-db.o linux-nat.o linux-fork.o
LOADLIBES = -ldl -rdynamic
Index: config/powerpc/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/powerpc/linux.mh,v
retrieving revision 1.19
diff -p -r1.19 linux.mh
*** config/powerpc/linux.mh 10 Sep 2005 18:11:13 -0000 1.19
--- config/powerpc/linux.mh 23 Dec 2005 22:05:31 -0000
*************** XM_CLIBS=
*** 5,10 ****
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
ppc-linux-nat.o proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o
LOADLIBES = -ldl -rdynamic
--- 5,10 ----
NAT_FILE= nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
ppc-linux-nat.o proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o linux-fork.o
LOADLIBES = -ldl -rdynamic
Index: config/powerpc/ppc64-linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/powerpc/ppc64-linux.mh,v
retrieving revision 1.8
diff -p -r1.8 ppc64-linux.mh
*** config/powerpc/ppc64-linux.mh 10 Sep 2005 18:11:13 -0000 1.8
--- config/powerpc/ppc64-linux.mh 23 Dec 2005 22:05:31 -0000
*************** XM_CLIBS=
*** 5,11 ****
NAT_FILE= nm-ppc64-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
ppc-linux-nat.o proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o
# The PowerPC has severe limitations on TOC size, and uses them even
# for non-PIC code. GDB overflows those tables when compiling with
--- 5,11 ----
NAT_FILE= nm-ppc64-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o \
ppc-linux-nat.o proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o linux-fork.o
# The PowerPC has severe limitations on TOC size, and uses them even
# for non-PIC code. GDB overflows those tables when compiling with
Index: config/sparc/linux.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/linux.mh,v
retrieving revision 1.16
diff -p -r1.16 linux.mh
*** config/sparc/linux.mh 10 Sep 2005 18:11:13 -0000 1.16
--- config/sparc/linux.mh 23 Dec 2005 22:05:31 -0000
*************** NAT_FILE= nm-linux.h
*** 3,9 ****
NATDEPFILES= sparc-nat.o sparc-sol2-nat.o sparc-linux-nat.o \
corelow.o core-regset.o fork-child.o inf-ptrace.o \
proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
--- 3,9 ----
NATDEPFILES= sparc-nat.o sparc-sol2-nat.o sparc-linux-nat.o \
corelow.o core-regset.o fork-child.o inf-ptrace.o \
proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o linux-fork.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
Index: config/sparc/linux64.mh
===================================================================
RCS file: /cvs/src/src/gdb/config/sparc/linux64.mh,v
retrieving revision 1.7
diff -p -r1.7 linux64.mh
*** config/sparc/linux64.mh 10 Sep 2005 18:11:14 -0000 1.7
--- config/sparc/linux64.mh 23 Dec 2005 22:05:31 -0000
*************** NATDEPFILES= sparc-nat.o sparc64-nat.o s
*** 4,10 ****
corelow.o core-regset.o \
fork-child.o inf-ptrace.o \
proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
--- 4,10 ----
corelow.o core-regset.o \
fork-child.o inf-ptrace.o \
proc-service.o linux-thread-db.o \
! gcore.o linux-nat.o linux-fork.o
# The dynamically loaded libthread_db needs access to symbols in the
# gdb executable.
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.300
diff -p -r1.300 gdb.texinfo
*** doc/gdb.texinfo 23 Dec 2005 19:26:16 -0000 1.300
--- doc/gdb.texinfo 23 Dec 2005 22:05:36 -0000
*************** kill a child process.
*** 1740,1745 ****
--- 1740,1746 ----
* Threads:: Debugging programs with multiple threads
* Processes:: Debugging programs with multiple processes
+ * Checkpoint/Restart:: Setting a @emph{bookmark} to return to later
@end menu
@node Compilation
*************** unimpeded.
*** 2507,2512 ****
--- 2508,2583 ----
Display the current debugger response to a @code{fork} or @code{vfork} call.
@end table
+ @cindex debugging multiple processes
+ On Linux, if you want to debug both the parent and child processes, use the
+ command @w{@code{set detach-on-fork}}.
+
+ @table @code
+ @kindex set detach-on-fork
+ @item set detach-on-fork @var{mode}
+ Tells gdb whether to detach one of the processes after a fork, or
+ retain debugger control over them both.
+
+ @table @code
+ @item on
+ The child process (or parent process, depending on the value of
+ @code{follow-fork-mode}) will be detached and allowed to run
+ independently. This is the default.
+
+ @item off
+ Both processes will be held under the control of @value{GDBN}.
+ One process (child or parent, depending on the value of
+ @code{follow-fork-mode}) is debugged as usual, while the other
+ is held suspended.
+
+ @end table
+
+ @kindex show detach-on-follow
+ @item show detach-on-follow
+ Show whether detach-on-follow mode is on/off.
+ @end table
+
+ If you choose to set @var{detach-on-follow} mode off, then
+ @value{GDBN} will retain control of all forked processes (including
+ nested forks). You can list the forked processes under the control of
+ @value{GDBN} by using the @w{@code{info forks}} command, and switch
+ from one fork to another by using the @w{@code{fork}} command.
+
+ @table @code
+ @kindex info forks
+ @item info forks
+ Print a list of all forked processes under the control of @value{GDBN}.
+ The listing will include a fork id, a process id, and the current
+ position (program counter) of the process.
+
+
+ @kindex fork @var{fork-id}
+ @item fork @var{fork-id}
+ Make fork number @var{fork-id} the current process. The argument
+ @var{fork-id} is the internal fork number assigned by @value{GDBN},
+ as shown in the first field of the @samp{info forks} display.
+
+ @end table
+
+ To quit debugging one of the forked processes, you can either detach
+ from it by using the @w{@code{detach-fork}} command (allowing it to
+ run independently), or delete (and kill) it using the
+ @w{@code{delete-fork}} command.
+
+ @table @code
+ @kindex detach-fork @var{fork-id}
+ @item detach-fork @var{fork-id}
+ Detach from the process identified by @value{GDBN} fork number
+ @var{fork-id}, and remove it from the fork list. The process will be
+ allowed to run independently.
+
+ @kindex delete-fork @var{fork-id}
+ @item delete-fork @var{fork-id}
+ Kill the process identified by @value{GDBN} fork number @var{fork-id},
+ and remove it from the fork list.
+
+ @end table
+
If you ask to debug a child process and a @code{vfork} is followed by an
@code{exec}, @value{GDBN} executes the new target up to the first
breakpoint in the new target. If you have a breakpoint set on
*************** You can use the @code{catch} command to
*** 2525,2530 ****
--- 2596,2715 ----
a @code{fork}, @code{vfork}, or @code{exec} call is made. @xref{Set
Catchpoints, ,Setting catchpoints}.
+ @node Checkpoint/Restart
+ @section Setting a @emph{bookmark} to return to later
+
+ @cindex checkpoint
+ @cindex restart
+ @cindex bookmark
+ @cindex snapshot of a process
+ @cindex rewind program state
+
+ On certain operating systems@footnote{Currently, only
+ @sc{gnu}/Linux.}, @value{GDBN} is able to save a @dfn{snapshot} of a
+ program's state, called a @dfn{checkpoint}, and come back to it
+ later.
+
+ Returning to a checkpoint effectively undoes everything that has
+ happened in the program since the @code{checkpoint} was saved. This
+ includes changes in memory, registers, and even (within some limits)
+ system state. Effectively, it is like going back in time to the
+ moment when the checkpoint was saved.
+
+ Thus, if you're stepping thru a program and you think you're
+ getting close to the point where things go wrong, you can save
+ a checkpoint. Then, if you accidentally go too far and miss
+ the critical statement, instead of having to restart your program
+ from the beginning, you can just go back to the checkpoint and
+ start again from there.
+
+ This can be especially useful if it takes a lot of time or
+ steps to reach the point where you think the bug occurs.
+
+ To use the @code{checkpoint}/@code{restart} method of debugging:
+
+ @table @code
+ @kindex checkpoint
+ @item checkpoint
+ Save a snapshot of the debugged program's current execution state.
+ The @code{checkpoint} command takes no arguments, but each checkpoint
+ is assigned a small integer id, similar to a breakpoint id.
+
+ @kindex info checkpoints
+ @item info checkpoints
+ List the checkpoints that have been saved in the current debugging
+ session. For each checkpoint, the following information will be
+ listed:
+
+ @table @code
+ @item Checkpoint ID
+ @item Process ID
+ @item Code Address
+ @item Source line, or label
+ @end table
+
+ @kindex restart @var{checkpoint-id}
+ @item restart @var{checkpoint-id}
+ Restore the program state that was saved as checkpoint number
+ @var{checkpoint-id}. All program variables, registers, stack frames
+ etc.@: will be returned to the values that they had when the checkpoint
+ was saved. In essence, gdb will ``wind back the clock'' to the point
+ in time when the checkpoint was saved.
+
+ Note that breakpoints, @value{GDBN} variables, command history etc.
+ are not affected by restoring a checkpoint. In general, a checkpoint
+ only restores things that reside in the program being debugged, not in
+ the debugger.
+
+ @kindex delete-checkpoint @var{checkpoint-id}
+ @item delete-checkpoint @var{checkpoint-id}
+ Delete the previously-saved checkpoint identified by @var{checkpoint-id}.
+
+ @end table
+
+ Returning to a previously saved checkpoint will restore the user state
+ of the program being debugged, plus a significant subset of the system
+ (OS) state, including file pointers. It won't ``un-write'' data from
+ a file, but it will rewind the file pointer to the previous location,
+ so that the previously written data can be overwritten. For files
+ opened in read mode, the pointer will also be restored so that the
+ previously read data can be read again.
+
+ Of course, characters that have been sent to a printer (or other
+ external device) cannot be ``snatched back'', and characters received
+ from eg.@: a serial device can be removed from internal program buffers,
+ but they cannot be ``pushed back'' into the serial pipeline, ready to
+ be received again. Similarly, the actual contents of files that have
+ been changed cannot be restored (at this time).
+
+ However, within those constraints, you actually can ``rewind'' your
+ program to a previously saved point in time, and begin debugging it
+ again --- and you can change the course of events so as to debug a
+ different execution path this time.
+
+ @cindex checkpoints and process id
+ Finally, there is one bit of internal program state that will be
+ different when you return to a checkpoint --- the program's process
+ id. Each checkpoint will have a unique process id (or @var{pid}),
+ and each will be different from the program's original @var{pid}.
+ If your program has saved a local copy of its process id, this could
+ potentially pose a problem.
+
+ @subsection A non-obvious benefit of using checkpoints
+
+ On some systems such as @sc{gnu}/Linux, address space randomization
+ is performed on new processes for security reasons. This makes it
+ difficult or impossible to set a breakpoint, or watchpoint, on an
+ absolute address if you have to restart the program, since the
+ absolute location of a symbol will change from one execution to the
+ next.
+
+ A checkpoint, however, is an @emph{identical} copy of a process.
+ Therefore if you create a checkpoint at (eg.@:) the start of main,
+ and simply return to that checkpoint instead of restarting the
+ process, you can avoid the effects of address randomization and
+ your symbols will all stay in the same place.
+
@node Stopping
@chapter Stopping and Continuing
Index: doc/gdbint.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdbint.texinfo,v
retrieving revision 1.232
diff -p -r1.232 gdbint.texinfo
*** doc/gdbint.texinfo 23 Dec 2005 19:26:16 -0000 1.232
--- doc/gdbint.texinfo 23 Dec 2005 22:05:37 -0000
*************** watchpoints might interfere with the und
*** 712,717 ****
--- 712,749 ----
unavailable in many platforms.
@end enumerate
+ @section Checkpoints
+ @cindex checkpoints
+ @cindex restart
+ In the abstract, a checkpoint is a point in the execution history of
+ the program, which the user may wish to return to at some later time.
+
+ Internally, a checkpoint is a saved copy of the program state, including
+ whatever information is required in order to restore the program to that
+ state at a later time. This can be expected to include the state of
+ registers and memory, and may include external state such as the state
+ of open files and devices.
+
+ There are a number of ways in which checkpoints may be implemented
+ in gdb, eg. as corefiles, as forked processes, and as some opaque
+ method implemented on the target side.
+
+ A corefile can be used to save an image of target memory and register
+ state, which can in principle be restored later --- but corefiles do
+ not typically include information about external entities such as
+ open files. Currently this method is not implemented in gdb.
+
+ A forked process can save the state of user memory and registers,
+ as well as some subset of external (kernel) state. This method
+ is used to implement checkpoints on Linux, and in principle might
+ be used on other systems.
+
+ Some targets, eg.@: simulators, might have their own built-in
+ method for saving checkpoints, and gdb might be able to take
+ advantage of that capability without necessarily knowing any
+ details of how it is done.
+
+
@section Observing changes in @value{GDBN} internals
@cindex observer pattern interface
@cindex notifications about changes in internals
Index: testsuite/gdb.base/checkpoint.c
===================================================================
RCS file: testsuite/gdb.base/checkpoint.c
diff -N testsuite/gdb.base/checkpoint.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/checkpoint.c 23 Dec 2005 22:05:38 -0000
***************
*** 0 ****
--- 1,62 ----
+ /* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Please email any bugs, comments, and/or additions to this file to:
+ bug-gdb@prep.ai.mit.edu */
+
+ #include <stdio.h>
+
+ long lines = 0;
+
+ main()
+ {
+ char linebuf[128];
+ FILE *in, *out;
+ char *tmp = &linebuf[0];
+ long i;
+ int c = 0;
+
+ in = fopen ("pi.txt", "r");
+ out = fopen ("copy1.txt", "w");
+
+ if (!in || !out)
+ {
+ fprintf (stderr, "File open failed\n");
+ exit (1);
+ }
+
+ for (i = 0; ; i++)
+ {
+ if (ftell (in) != i)
+ fprintf (stderr, "Input error at %d\n", i);
+ if (ftell (out) != i)
+ fprintf (stderr, "Output error at %d\n", i);
+ c = fgetc (in);
+ if (c == '\n')
+ lines++; /* breakpoint 1 */
+ if (c == EOF)
+ break;
+ fputc (c, out);
+ }
+ printf ("Copy complete.\n"); /* breakpoint 2 */
+ fclose (in);
+ fclose (out);
+ printf ("Deleting copy.\n"); /* breakpoint 3 */
+ unlink ("copy1.txt");
+ exit (0); /* breakpoint 4 */
+ }
Index: testsuite/gdb.base/checkpoint.exp
===================================================================
RCS file: testsuite/gdb.base/checkpoint.exp
diff -N testsuite/gdb.base/checkpoint.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/checkpoint.exp 23 Dec 2005 22:05:38 -0000
***************
*** 0 ****
--- 1,375 ----
+ # Copyright 2005 Free Software Foundation, Inc.
+
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+ # Please email any bugs, comments, and/or additions to this file to:
+ # bug-gdb@prep.ai.mit.edu
+
+ if $tracelevel then {
+ strace $tracelevel
+ }
+
+ if { ![isnative] } then {
+ continue
+ }
+
+ # Until "set follow-fork-mode" and "catch fork" are implemented on
+ # other targets...
+ #
+ if {![istarget "*-*-linux*"]} then {
+ continue
+ }
+
+ set prms_id 0
+ set bug_id 0
+
+ set testfile "checkpoint"
+ set srcfile ${testfile}.c
+ set binfile ${objdir}/${subdir}/${testfile}
+
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+ }
+
+ # Start with a fresh gdb
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ global gdb_prompt
+
+ #
+ # This tests gdb checkpoint and restart.
+ #
+
+ remote_download host ${srcdir}/${subdir}/pi.txt pi.txt
+
+ runto_main
+ set break1_loc [gdb_get_line_number "breakpoint 1"]
+ set break2_loc [gdb_get_line_number "breakpoint 2"]
+ set break3_loc [gdb_get_line_number "breakpoint 3"]
+ set break4_loc [gdb_get_line_number "breakpoint 4"]
+
+ gdb_breakpoint $break1_loc
+ gdb_test "continue" "breakpoint 1.*" "break1 start"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 two"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 three"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 four"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 five"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 six"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 seven"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 eight"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 nine"
+
+ gdb_test "checkpoint" "" ""
+ gdb_test "continue 10" "breakpoint 1.*" "break1 ten"
+
+ gdb_test "checkpoint" "" ""
+
+ gdb_test "info checkpoints" \
+ " 10 .* 9 .* 8 .* 7 .* 6 .* 5 .* 4 .* 3 .* 2 .* 1 .*" \
+ "info checkpoints one"
+
+ delete_breakpoints
+ gdb_breakpoint $break2_loc
+ gdb_test "continue" "breakpoint 2.*" "break2 one"
+
+ gdb_test "restart 1" "Switching to .*breakpoint 1.*" "restart 1 one"
+ gdb_test "print i" " = 78" "verify i 1 one"
+ gdb_test "step" "if .c == EOF.*" "step in 1 one"
+ gdb_test "print lines" " = 1.*" "verify lines 1 one"
+
+ gdb_test "restart 2" "Switching to .*breakpoint 1.*" "restart 2 one"
+ gdb_test "step" "if .c == EOF.*" "step in 2 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 2 one"
+ gdb_test "print lines" " = 11.*" "verify lines 2 one"
+
+ gdb_test "restart 3" "Switching to .*breakpoint 1.*" "restart 3 one"
+ gdb_test "step" "if .c == EOF.*" "step in 3 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 3 one"
+ gdb_test "print lines" " = 21.*" "verify lines 3 one"
+
+ gdb_test "restart 4" "Switching to .*breakpoint 1.*" "restart 4 one"
+ gdb_test "step" "if .c == EOF.*" "step in 4 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 4 one"
+ gdb_test "print lines" " = 31.*" "verify lines 4 one"
+
+ gdb_test "restart 5" "Switching to .*breakpoint 1.*" "restart 5 one"
+ gdb_test "step" "if .c == EOF.*" "step in 5 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 5 one"
+ gdb_test "print lines" " = 41.*" "verify lines 5 one"
+
+ gdb_test "restart 6" "Switching to .*breakpoint 1.*" "restart 6 one"
+ gdb_test "step" "if .c == EOF.*" "step in 6 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 6 one"
+ gdb_test "print lines" " = 51.*" "verify lines 6 one"
+
+ gdb_test "restart 7" "Switching to .*breakpoint 1.*" "restart 7 one"
+ gdb_test "step" "if .c == EOF.*" "step in 7 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 7 one"
+ gdb_test "print lines" " = 61.*" "verify lines 7 one"
+
+ gdb_test "restart 8" "Switching to .*breakpoint 1.*" "restart 8 one"
+ gdb_test "step" "if .c == EOF.*" "step in 8 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 8 one"
+ gdb_test "print lines" " = 71.*" "verify lines 8 one"
+
+ gdb_test "restart 9" "Switching to .*breakpoint 1.*" "restart 9 one"
+ gdb_test "step" "if .c == EOF.*" "step in 9 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 9 one"
+ gdb_test "print lines" " = 81.*" "verify lines 9 one"
+
+ gdb_test "restart 10" "Switching to .*breakpoint 1.*" "restart 10 one"
+ gdb_test "step" "if .c == EOF.*" "step in 10 one"
+ gdb_test "print i + 1 == lines * 79" " = 1" "verify i 10 one"
+ gdb_test "print lines" " = 91.*" "verify lines 10 one"
+
+ #
+ # Now let the files be closed by the original process,
+ # and diff them.
+
+ gdb_test "restart 0" "Switching to .*breakpoint 2.*" "restart 0 one"
+ gdb_breakpoint $break3_loc
+ gdb_test "continue" "breakpoint 3.*" "break3 one"
+
+ gdb_test "shell diff -s pi.txt copy1.txt" \
+ "Files pi.txt and copy1.txt are identical.*" \
+ "Diff input and output one"
+
+ #
+ # And now run from various checkpoints, allowing
+ # various amounts of input and output.
+ #
+
+ gdb_breakpoint $break1_loc
+
+ gdb_test "restart 1" "Switching to .*c == EOF.*" "restart 1 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 100" "breakpoint 1.*" "breakpoint 1 1 one"
+ gdb_test "step" "if .c == EOF.*" "step in 1 two"
+ gdb_test "print lines" " = 102.*" "verify lines 1 two"
+
+ gdb_test "restart 2" "Switching to .*c == EOF.*" "restart 2 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 100" "breakpoint 1.*" "breakpoint 1 2 one"
+ gdb_test "step" "if .c == EOF.*" "step in 2 two"
+ gdb_test "print lines" " = 112.*" "verify lines 2 two"
+
+ gdb_test "restart 3" "Switching to .*c == EOF.*" "restart 3 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 500" "breakpoint 1.*" "breakpoint 1 3 one"
+ gdb_test "step" "if .c == EOF.*" "step in 3 two"
+ gdb_test "print lines" " = 522.*" "verify lines 3 two"
+
+ gdb_test "restart 4" "Switching to .*c == EOF.*" "restart 4 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 500" "breakpoint 1.*" "breakpoint 1 4 one"
+ gdb_test "step" "if .c == EOF.*" "step in 4 two"
+ gdb_test "print lines" " = 532.*" "verify lines 4 two"
+
+ gdb_test "restart 5" "Switching to .*c == EOF.*" "restart 5 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 1000" "breakpoint 1.*" "breakpoint 1 5 one"
+ gdb_test "step" "if .c == EOF.*" "step in 5 two"
+ gdb_test "print lines" " = 1042.*" "verify lines 5 two"
+
+ gdb_test "restart 6" "Switching to .*c == EOF.*" "restart 6 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 1000" "breakpoint 1.*" "breakpoint 1 6 one"
+ gdb_test "step" "if .c == EOF.*" "step in 6 two"
+ gdb_test "print lines" " = 1052.*" "verify lines 5 two"
+
+ gdb_test "restart 7" "Switching to .*c == EOF.*" "restart 7 two"
+ gdb_test "continue" "" ""
+ gdb_test "continue 1100" "breakpoint 1.*" "breakpoint 1 7 one"
+ gdb_test "step" "if .c == EOF.*" "step in 7 two"
+ gdb_test "print lines" " = 1162.*" "verify lines 7 two"
+
+ gdb_test "shell diff -s pi.txt copy1.txt" \
+ "Files pi.txt and copy1.txt are identical.*" \
+ "Diff input and output two"
+
+ #
+ # OK, now allow the original program to delete the output file,
+ # and verify that the checkpoints can still write to it.
+ #
+
+ gdb_test "restart 0" "Switching to .*breakpoint 3.*" "restart 0 one"
+ gdb_breakpoint $break4_loc
+ gdb_test "continue" "breakpoint 4.*" "break4 one"
+
+ gdb_test "shell diff pi.txt copy1.txt" \
+ "diff: copy1.txt: No such file or directory" \
+ "delete copy1"
+
+ delete_breakpoints
+ gdb_breakpoint $break2_loc
+
+ gdb_test "restart 1" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 1 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 1"
+
+ gdb_test "restart 2" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 2 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 2"
+
+ gdb_test "restart 3" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 3 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 3"
+
+ gdb_test "restart 4" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 4 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 4"
+
+ gdb_test "restart 5" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 5 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 5"
+
+ gdb_test "restart 6" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 6 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 6"
+
+ gdb_test "restart 7" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 7 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 7"
+
+ gdb_test "restart 8" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 8 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 8"
+
+ gdb_test "restart 9" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 9 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 9"
+
+ gdb_test "restart 10" "if .c == EOF.*" "restart 1 three"
+ gdb_test "continue" "breakpoint 2.*" "break2 10 one"
+ gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 10"
+
+ #
+ # Now confirm that if one fork exits, we automatically switch to another one.
+ #
+
+ delete_breakpoints
+ gdb_test "continue" \
+ "Deleting copy.*Program exited normally.*Switching to.*" \
+ "Exit, dropped into next fork one"
+
+ gdb_test "continue" \
+ "Deleting copy.*Program exited normally.*Switching to.*" \
+ "Exit, dropped into next fork two"
+
+ gdb_test "continue" \
+ "Deleting copy.*Program exited normally.*Switching to.*" \
+ "Exit, dropped into next fork three"
+
+ gdb_test "continue" \
+ "Deleting copy.*Program exited normally.*Switching to.*" \
+ "Exit, dropped into next fork four"
+
+ gdb_test "continue" \
+ "Deleting copy.*Program exited normally.*Switching to.*" \
+ "Exit, dropped into next fork five"
+
+ #
+ # There should be still at least five forks left
+ #
+
+ gdb_test "info checkpoints" " 5 .* 4 .* 3 .* 2 .* 1 .*" \
+ "info checkpoints two"
+
+ #
+ # Kill should now terminate all of them.
+ #
+
+ gdb_test "kill" "" "kill all one" \
+ "Kill the program being debugged.*y or n. $" "y"
+
+ #
+ # and confirm that all are gone
+ #
+
+ gdb_test "restart 0" "Not found.*" "no more checkpoint 0"
+ gdb_test "restart 1" "Not found.*" "no more checkpoint 1"
+ gdb_test "restart 2" "Not found.*" "no more checkpoint 2"
+ gdb_test "restart 3" "Not found.*" "no more checkpoint 3"
+ gdb_test "restart 4" "Not found.*" "no more checkpoint 4"
+ gdb_test "restart 5" "Not found.*" "no more checkpoint 5"
+ gdb_test "restart 6" "Not found.*" "no more checkpoint 6"
+ gdb_test "restart 7" "Not found.*" "no more checkpoint 7"
+ gdb_test "restart 8" "Not found.*" "no more checkpoint 8"
+ gdb_test "restart 9" "Not found.*" "no more checkpoint 9"
+ gdb_test "restart 10" "Not found.*" "no more checkpoint 10"
+
+ #
+ # Now let's try setting a large number of checkpoints (>1000)
+ #
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ runto_main
+ gdb_breakpoint $break1_loc
+
+ send_gdb "commands\n"
+ send_gdb " silent\n"
+ send_gdb " if (lines % 2)\n"
+ send_gdb " checkpoint\n"
+ send_gdb " end\n"
+ send_gdb " continue\n"
+ send_gdb "end\n"
+
+ gdb_expect {
+ -re ".*$gdb_prompt $" { pass "set checkpoint breakpoint" }
+ timeout { fail "(timeout) set checkpoint breakpoint" }
+ }
+
+ gdb_breakpoint $break2_loc
+ gdb_test "continue" "breakpoint 2.*" "break2 with many checkpoints"
+
+ gdb_test "info checkpoints" " 600 .* 0 .*" \
+ "info checkpoints with at least 600 checkpoints"
+
+ #
+ # OK, kill 'em all...
+ #
+
+ gdb_test "kill" "" "kill all one" \
+ "Kill the program being debugged.*y or n. $" "y"
+
+ #
+ # Finished: cleanup
+ #
+
+ remote_exec build "rm -f pi.txt"
Index: testsuite/gdb.base/multi-forks.c
===================================================================
RCS file: testsuite/gdb.base/multi-forks.c
diff -N testsuite/gdb.base/multi-forks.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/multi-forks.c 23 Dec 2005 22:05:38 -0000
***************
*** 0 ****
--- 1,18 ----
+ #include <stdio.h>
+ #include <sys/types.h>
+ #include <unistd.h>
+
+ pid_t pids[4];
+
+ main()
+ {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ pids [i] = fork ();
+
+ printf ("%d ready\n", getpid ());
+ sleep (2);
+ printf ("%d done\n", getpid ());
+ exit (0); /* Set exit breakpoint here. */
+ }
Index: testsuite/gdb.base/multi-forks.exp
===================================================================
RCS file: testsuite/gdb.base/multi-forks.exp
diff -N testsuite/gdb.base/multi-forks.exp
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/multi-forks.exp 23 Dec 2005 22:13:25 -0000
***************
*** 0 ****
--- 1,214 ----
+ # Copyright 2005 Free Software Foundation, Inc.
+
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 2 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+ # Please email any bugs, comments, and/or additions to this file to:
+ # bug-gdb@prep.ai.mit.edu
+
+ if $tracelevel then {
+ strace $tracelevel
+ }
+
+ if { ![isnative] } then {
+ continue
+ }
+
+ # Until "set follow-fork-mode" and "catch fork" are implemented on
+ # other targets...
+ #
+ if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-*-linux*"]} then {
+ continue
+ }
+
+ set prms_id 0
+ set bug_id 0
+
+ set testfile "multi-forks"
+ set srcfile ${testfile}.c
+ set binfile ${objdir}/${subdir}/${testfile}
+
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+ }
+
+ # Start with a fresh gdb
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ global gdb_prompt
+
+ # This is a test of gdb's ability to follow the parent, child or both
+ # parent and child of multiple Unix fork() system calls.
+ #
+
+ # Inferior program calls fork 4 times. Since each fork
+ # calls fork 4 times, there will be 16 forks. Each fork
+ # saves the return values of its own 4 fork calls.
+
+ # First set gdb to follow the child.
+ # The result should be that each of the 4 forks returns zero.
+
+ runto_main
+ set exit_bp_loc [gdb_get_line_number "Set exit breakpoint here."]
+ gdb_test "break $exit_bp_loc" "Breakpoint.* at .*" "Break at exit"
+ gdb_test "set follow child" "" ""
+
+ send_gdb "continue\n"
+ gdb_expect {
+ -re ".*Break.* main .*$gdb_prompt $" {}
+ -re ".*$gdb_prompt $" {fail "run to exit 1"}
+ default {fail "run to exit 1 (timeout)"}
+ }
+
+ gdb_test "print pids" "\\$.* = \\{0, 0, 0, 0\\}.*" "follow child, print pids"
+
+ # Now set gdb to follow the parent.
+ # Result should be that none of the 4 forks returns zero.
+
+ delete_breakpoints
+ runto_main
+ gdb_test "break $exit_bp_loc" "Breakpoint.* at .*" "Break at exit"
+ gdb_test "set follow parent" "" ""
+
+ send_gdb "continue\n"
+ gdb_expect {
+ -re ".*Break.* main .*$gdb_prompt $" {}
+ -re ".*$gdb_prompt $" {fail "run to exit 2"}
+ default {fail "run to exit 2 (timeout)"}
+ }
+
+ gdb_test "print pids\[0\]==0 || pids\[1\]==0 || pids\[2\]==0 || pids\[3\]==0" \
+ " = 0" "follow parent, print pids"
+
+ #
+ # Now test with detach-on-fork off.
+ #
+
+ runto_main
+ gdb_test "break $exit_bp_loc" "Breakpoint.* at .*" ""
+
+ gdb_test "help set detach-on-fork" "whether gdb will detach the child.*" \
+ "help set detach"
+
+ gdb_test "show detach-on-fork" "on." "show detach default on"
+
+ gdb_test "set detach off" "" "set detach off"
+
+ #
+ # We will now run every fork up to the exit bp,
+ # eventually winding up with 16 forks.
+ #
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 1"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 1"
+ gdb_test "restart 1" "_dl_sysinfo_int80.*" "restart 1"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 2"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 2"
+ gdb_test "restart 2" "_dl_sysinfo_int80.*" "restart 2"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 3"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 3"
+ gdb_test "restart 3" "_dl_sysinfo_int80.*" "restart 3"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 4"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 4"
+ gdb_test "restart 4" "_dl_sysinfo_int80.*" "restart 4"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 5"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 5"
+ gdb_test "restart 5" "_dl_sysinfo_int80.*" "restart 5"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 6"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 6"
+ gdb_test "restart 6" "_dl_sysinfo_int80.*" "restart 6"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 7"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 7"
+ gdb_test "restart 7" "_dl_sysinfo_int80.*" "restart 7"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 8"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 8"
+ gdb_test "restart 8" "_dl_sysinfo_int80.*" "restart 8"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 9"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 9"
+ gdb_test "restart 9" "_dl_sysinfo_int80.*" "restart 9"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 10"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 10"
+ gdb_test "restart 10" "_dl_sysinfo_int80.*" "restart 10"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 11"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 11"
+ gdb_test "restart 11" "_dl_sysinfo_int80.*" "restart 11"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 12"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 12"
+ gdb_test "restart 12" "_dl_sysinfo_int80.*" "restart 12"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 13"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 13"
+ gdb_test "restart 13" "_dl_sysinfo_int80.*" "restart 13"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 14"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 14"
+ gdb_test "restart 14" "_dl_sysinfo_int80.*" "restart 14"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 15"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 15"
+ gdb_test "restart 15" "_dl_sysinfo_int80.*" "restart 15"
+
+ gdb_test "continue" "Breakpoint .* main .*exit.*" "Run to exit 16"
+ gdb_test "info fork" " 4 .* 3 .* 2 .* 1 .*" "info fork 16"
+ gdb_test "restart 0" " main .*" "restart final"
+
+ #
+ # Now we should examine all the pids.
+ #
+
+ #
+ # Test detach-fork
+ #
+
+ # [assumes we're at #0]
+ gdb_test "detach-fork 1" "Detached .*" "Detach 1"
+ gdb_test "detach-fork 2" "Detached .*" "Detach 2"
+ gdb_test "detach-fork 3" "Detached .*" "Detach 3"
+ gdb_test "detach-fork 4" "Detached .*" "Detach 4"
+
+ #
+ # Test delete-fork
+ #
+
+ gdb_test "delete-fork 5" "" "Delete 5"
+ gdb_test "delete-fork 6" "" "Delete 6"
+ gdb_test "delete-fork 7" "" "Delete 7"
+ gdb_test "delete-fork 8" "" "Delete 8"
+ gdb_test "delete-fork 9" "" "Delete 9"
+ gdb_test "delete-fork 10" "" "Delete 10"
+ gdb_test "delete-fork 11" "" "Delete 11"
+ gdb_test "delete-fork 12" "" "Delete 12"
+ gdb_test "delete-fork 13" "" "Delete 13"
+ gdb_test "delete-fork 14" "" "Delete 14"
+ gdb_test "delete-fork 15" "" "Delete 15"
+
+
+
+ return 0
+
Index: testsuite/gdb.base/pi.txt
===================================================================
RCS file: testsuite/gdb.base/pi.txt
diff -N testsuite/gdb.base/pi.txt
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gdb.base/pi.txt 23 Dec 2005 22:05:38 -0000
***************
*** 0 ****
--- 1,1283 ----
+ 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+ 208998628034825342117067982148086513282306647093844609550582231725359408128481
+ 117450284102701938521105559644622948954930381964428810975665933446128475648233
+ 786783165271201909145648566923460348610454326648213393607260249141273724587006
+ 606315588174881520920962829254091715364367892590360011330530548820466521384146
+ 951941511609433057270365759591953092186117381932611793105118548074462379962749
+ 567351885752724891227938183011949129833673362440656643086021394946395224737190
+ 702179860943702770539217176293176752384674818467669405132000568127145263560827
+ 785771342757789609173637178721468440901224953430146549585371050792279689258923
+ 542019956112129021960864034418159813629774771309960518707211349999998372978049
+ 951059731732816096318595024459455346908302642522308253344685035261931188171010
+ 003137838752886587533208381420617177669147303598253490428755468731159562863882
+ 353787593751957781857780532171226806613001927876611195909216420198938095257201
+ 065485863278865936153381827968230301952035301852968995773622599413891249721775
+ 283479131515574857242454150695950829533116861727855889075098381754637464939319
+ 255060400927701671139009848824012858361603563707660104710181942955596198946767
+ 837449448255379774726847104047534646208046684259069491293313677028989152104752
+ 162056966024058038150193511253382430035587640247496473263914199272604269922796
+ 782354781636009341721641219924586315030286182974555706749838505494588586926995
+ 690927210797509302955321165344987202755960236480665499119881834797753566369807
+ 426542527862551818417574672890977772793800081647060016145249192173217214772350
+ 141441973568548161361157352552133475741849468438523323907394143334547762416862
+ 518983569485562099219222184272550254256887671790494601653466804988627232791786
+ 085784383827967976681454100953883786360950680064225125205117392984896084128488
+ 626945604241965285022210661186306744278622039194945047123713786960956364371917
+ 287467764657573962413890865832645995813390478027590099465764078951269468398352
+ 595709825822620522489407726719478268482601476990902640136394437455305068203496
+ 252451749399651431429809190659250937221696461515709858387410597885959772975498
+ 930161753928468138268683868942774155991855925245953959431049972524680845987273
+ 644695848653836736222626099124608051243884390451244136549762780797715691435997
+ 700129616089441694868555848406353422072225828488648158456028506016842739452267
+ 467678895252138522549954666727823986456596116354886230577456498035593634568174
+ 324112515076069479451096596094025228879710893145669136867228748940560101503308
+ 617928680920874760917824938589009714909675985261365549781893129784821682998948
+ 722658804857564014270477555132379641451523746234364542858444795265867821051141
+ 354735739523113427166102135969536231442952484937187110145765403590279934403742
+ 007310578539062198387447808478489683321445713868751943506430218453191048481005
+ 370614680674919278191197939952061419663428754440643745123718192179998391015919
+ 561814675142691239748940907186494231961567945208095146550225231603881930142093
+ 762137855956638937787083039069792077346722182562599661501421503068038447734549
+ 202605414665925201497442850732518666002132434088190710486331734649651453905796
+ 268561005508106658796998163574736384052571459102897064140110971206280439039759
+ 515677157700420337869936007230558763176359421873125147120532928191826186125867
+ 321579198414848829164470609575270695722091756711672291098169091528017350671274
+ 858322287183520935396572512108357915136988209144421006751033467110314126711136
+ 990865851639831501970165151168517143765761835155650884909989859982387345528331
+ 635507647918535893226185489632132933089857064204675259070915481416549859461637
+ 180270981994309924488957571282890592323326097299712084433573265489382391193259
+ 746366730583604142813883032038249037589852437441702913276561809377344403070746
+ 921120191302033038019762110110044929321516084244485963766983895228684783123552
+ 658213144957685726243344189303968642624341077322697802807318915441101044682325
+ 271620105265227211166039666557309254711055785376346682065310989652691862056476
+ 931257058635662018558100729360659876486117910453348850346113657686753249441668
+ 039626579787718556084552965412665408530614344431858676975145661406800700237877
+ 659134401712749470420562230538994561314071127000407854733269939081454664645880
+ 797270826683063432858785698305235808933065757406795457163775254202114955761581
+ 400250126228594130216471550979259230990796547376125517656751357517829666454779
+ 174501129961489030463994713296210734043751895735961458901938971311179042978285
+ 647503203198691514028708085990480109412147221317947647772622414254854540332157
+ 185306142288137585043063321751829798662237172159160771669254748738986654949450
+ 114654062843366393790039769265672146385306736096571209180763832716641627488880
+ 078692560290228472104031721186082041900042296617119637792133757511495950156604
+ 963186294726547364252308177036751590673502350728354056704038674351362222477158
+ 915049530984448933309634087807693259939780541934144737744184263129860809988868
+ 741326047215695162396586457302163159819319516735381297416772947867242292465436
+ 680098067692823828068996400482435403701416314965897940924323789690706977942236
+ 250822168895738379862300159377647165122893578601588161755782973523344604281512
+ 627203734314653197777416031990665541876397929334419521541341899485444734567383
+ 162499341913181480927777103863877343177207545654532207770921201905166096280490
+ 926360197598828161332316663652861932668633606273567630354477628035045077723554
+ 710585954870279081435624014517180624643626794561275318134078330336254232783944
+ 975382437205835311477119926063813346776879695970309833913077109870408591337464
+ 144282277263465947047458784778720192771528073176790770715721344473060570073349
+ 243693113835049316312840425121925651798069411352801314701304781643788518529092
+ 854520116583934196562134914341595625865865570552690496520985803385072242648293
+ 972858478316305777756068887644624824685792603953527734803048029005876075825104
+ 747091643961362676044925627420420832085661190625454337213153595845068772460290
+ 161876679524061634252257719542916299193064553779914037340432875262888963995879
+ 475729174642635745525407909145135711136941091193932519107602082520261879853188
+ 770584297259167781314969900901921169717372784768472686084900337702424291651300
+ 500516832336435038951702989392233451722013812806965011784408745196012122859937
+ 162313017114448464090389064495444006198690754851602632750529834918740786680881
+ 833851022833450850486082503930213321971551843063545500766828294930413776552793
+ 975175461395398468339363830474611996653858153842056853386218672523340283087112
+ 328278921250771262946322956398989893582116745627010218356462201349671518819097
+ 303811980049734072396103685406643193950979019069963955245300545058068550195673
+ 022921913933918568034490398205955100226353536192041994745538593810234395544959
+ 778377902374216172711172364343543947822181852862408514006660443325888569867054
+ 315470696574745855033232334210730154594051655379068662733379958511562578432298
+ 827372319898757141595781119635833005940873068121602876496286744604774649159950
+ 549737425626901049037781986835938146574126804925648798556145372347867330390468
+ 838343634655379498641927056387293174872332083760112302991136793862708943879936
+ 201629515413371424892830722012690147546684765357616477379467520049075715552781
+ 965362132392640616013635815590742202020318727760527721900556148425551879253034
+ 351398442532234157623361064250639049750086562710953591946589751413103482276930
+ 624743536325691607815478181152843667957061108615331504452127473924544945423682
+ 886061340841486377670096120715124914043027253860764823634143346235189757664521
+ 641376796903149501910857598442391986291642193994907236234646844117394032659184
+ 044378051333894525742399508296591228508555821572503107125701266830240292952522
+ 011872676756220415420516184163484756516999811614101002996078386909291603028840
+ 026910414079288621507842451670908700069928212066041837180653556725253256753286
+ 129104248776182582976515795984703562226293486003415872298053498965022629174878
+ 820273420922224533985626476691490556284250391275771028402799806636582548892648
+ 802545661017296702664076559042909945681506526530537182941270336931378517860904
+ 070866711496558343434769338578171138645587367812301458768712660348913909562009
+ 939361031029161615288138437909904231747336394804575931493140529763475748119356
+ 709110137751721008031559024853090669203767192203322909433467685142214477379393
+ 751703443661991040337511173547191855046449026365512816228824462575916333039107
+ 225383742182140883508657391771509682887478265699599574490661758344137522397096
+ 834080053559849175417381883999446974867626551658276584835884531427756879002909
+ 517028352971634456212964043523117600665101241200659755851276178583829204197484
+ 423608007193045761893234922927965019875187212726750798125547095890455635792122
+ 103334669749923563025494780249011419521238281530911407907386025152274299581807
+ 247162591668545133312394804947079119153267343028244186041426363954800044800267
+ 049624820179289647669758318327131425170296923488962766844032326092752496035799
+ 646925650493681836090032380929345958897069536534940603402166544375589004563288
+ 225054525564056448246515187547119621844396582533754388569094113031509526179378
+ 002974120766514793942590298969594699556576121865619673378623625612521632086286
+ 922210327488921865436480229678070576561514463204692790682120738837781423356282
+ 360896320806822246801224826117718589638140918390367367222088832151375560037279
+ 839400415297002878307667094447456013455641725437090697939612257142989467154357
+ 846878861444581231459357198492252847160504922124247014121478057345510500801908
+ 699603302763478708108175450119307141223390866393833952942578690507643100638351
+ 983438934159613185434754649556978103829309716465143840700707360411237359984345
+ 225161050702705623526601276484830840761183013052793205427462865403603674532865
+ 105706587488225698157936789766974220575059683440869735020141020672358502007245
+ 225632651341055924019027421624843914035998953539459094407046912091409387001264
+ 560016237428802109276457931065792295524988727584610126483699989225695968815920
+ 560010165525637567856672279661988578279484885583439751874454551296563443480396
+ 642055798293680435220277098429423253302257634180703947699415979159453006975214
+ 829336655566156787364005366656416547321704390352132954352916941459904160875320
+ 186837937023488868947915107163785290234529244077365949563051007421087142613497
+ 459561513849871375704710178795731042296906667021449863746459528082436944578977
+ 233004876476524133907592043401963403911473202338071509522201068256342747164602
+ 433544005152126693249341967397704159568375355516673027390074972973635496453328
+ 886984406119649616277344951827369558822075735517665158985519098666539354948106
+ 887320685990754079234240230092590070173196036225475647894064754834664776041146
+ 323390565134330684495397907090302346046147096169688688501408347040546074295869
+ 913829668246818571031887906528703665083243197440477185567893482308943106828702
+ 722809736248093996270607472645539925399442808113736943388729406307926159599546
+ 262462970706259484556903471197299640908941805953439325123623550813494900436427
+ 852713831591256898929519642728757394691427253436694153236100453730488198551706
+ 594121735246258954873016760029886592578662856124966552353382942878542534048308
+ 330701653722856355915253478445981831341129001999205981352205117336585640782648
+ 494276441137639386692480311836445369858917544264739988228462184490087776977631
+ 279572267265556259628254276531830013407092233436577916012809317940171859859993
+ 384923549564005709955856113498025249906698423301735035804408116855265311709957
+ 089942732870925848789443646005041089226691783525870785951298344172953519537885
+ 534573742608590290817651557803905946408735061232261120093731080485485263572282
+ 576820341605048466277504500312620080079980492548534694146977516493270950493463
+ 938243222718851597405470214828971117779237612257887347718819682546298126868581
+ 705074027255026332904497627789442362167411918626943965067151577958675648239939
+ 176042601763387045499017614364120469218237076488783419689686118155815873606293
+ 860381017121585527266830082383404656475880405138080163363887421637140643549556
+ 186896411228214075330265510042410489678352858829024367090488711819090949453314
+ 421828766181031007354770549815968077200947469613436092861484941785017180779306
+ 810854690009445899527942439813921350558642219648349151263901280383200109773868
+ 066287792397180146134324457264009737425700735921003154150893679300816998053652
+ 027600727749674584002836240534603726341655425902760183484030681138185510597970
+ 566400750942608788573579603732451414678670368809880609716425849759513806930944
+ 940151542222194329130217391253835591503100333032511174915696917450271494331515
+ 588540392216409722910112903552181576282328318234254832611191280092825256190205
+ 263016391147724733148573910777587442538761174657867116941477642144111126358355
+ 387136101102326798775641024682403226483464176636980663785768134920453022408197
+ 278564719839630878154322116691224641591177673225326433568614618654522268126887
+ 268445968442416107854016768142080885028005414361314623082102594173756238994207
+ 571362751674573189189456283525704413354375857534269869947254703165661399199968
+ 262824727064133622217892390317608542894373393561889165125042440400895271983787
+ 386480584726895462438823437517885201439560057104811949884239060613695734231559
+ 079670346149143447886360410318235073650277859089757827273130504889398900992391
+ 350337325085598265586708924261242947367019390772713070686917092646254842324074
+ 855036608013604668951184009366860954632500214585293095000090715105823626729326
+ 453738210493872499669933942468551648326113414611068026744663733437534076429402
+ 668297386522093570162638464852851490362932019919968828517183953669134522244470
+ 804592396602817156551565666111359823112250628905854914509715755390024393153519
+ 090210711945730024388017661503527086260253788179751947806101371500448991721002
+ 220133501310601639154158957803711779277522597874289191791552241718958536168059
+ 474123419339842021874564925644346239253195313510331147639491199507285843065836
+ 193536932969928983791494193940608572486396883690326556436421664425760791471086
+ 998431573374964883529276932822076294728238153740996154559879825989109371712621
+ 828302584811238901196822142945766758071865380650648702613389282299497257453033
+ 283896381843944770779402284359883410035838542389735424395647555684095224844554
+ 139239410001620769363684677641301781965937997155746854194633489374843912974239
+ 143365936041003523437770658886778113949861647874714079326385873862473288964564
+ 359877466763847946650407411182565837887845485814896296127399841344272608606187
+ 245545236064315371011274680977870446409475828034876975894832824123929296058294
+ 861919667091895808983320121031843034012849511620353428014412761728583024355983
+ 003204202451207287253558119584014918096925339507577840006746552603144616705082
+ 768277222353419110263416315714740612385042584598841990761128725805911393568960
+ 143166828317632356732541707342081733223046298799280490851409479036887868789493
+ 054695570307261900950207643349335910602454508645362893545686295853131533718386
+ 826561786227363716975774183023986006591481616404944965011732131389574706208847
+ 480236537103115089842799275442685327797431139514357417221975979935968525228574
+ 526379628961269157235798662057340837576687388426640599099350500081337543245463
+ 596750484423528487470144354541957625847356421619813407346854111766883118654489
+ 377697956651727966232671481033864391375186594673002443450054499539974237232871
+ 249483470604406347160632583064982979551010954183623503030945309733583446283947
+ 630477564501500850757894954893139394489921612552559770143685894358587752637962
+ 559708167764380012543650237141278346792610199558522471722017772370041780841942
+ 394872540680155603599839054898572354674564239058585021671903139526294455439131
+ 663134530893906204678438778505423939052473136201294769187497519101147231528932
+ 677253391814660730008902776896311481090220972452075916729700785058071718638105
+ 496797310016787085069420709223290807038326345345203802786099055690013413718236
+ 837099194951648960075504934126787643674638490206396401976668559233565463913836
+ 318574569814719621084108096188460545603903845534372914144651347494078488442377
+ 217515433426030669883176833100113310869042193903108014378433415137092435301367
+ 763108491351615642269847507430329716746964066653152703532546711266752246055119
+ 958183196376370761799191920357958200759560530234626775794393630746305690108011
+ 494271410093913691381072581378135789400559950018354251184172136055727522103526
+ 803735726527922417373605751127887218190844900617801388971077082293100279766593
+ 583875890939568814856026322439372656247277603789081445883785501970284377936240
+ 782505270487581647032458129087839523245323789602984166922548964971560698119218
+ 658492677040395648127810217991321741630581055459880130048456299765112124153637
+ 451500563507012781592671424134210330156616535602473380784302865525722275304999
+ 883701534879300806260180962381516136690334111138653851091936739383522934588832
+ 255088706450753947395204396807906708680644509698654880168287434378612645381583
+ 428075306184548590379821799459968115441974253634439960290251001588827216474500
+ 682070419376158454712318346007262933955054823955713725684023226821301247679452
+ 264482091023564775272308208106351889915269288910845557112660396503439789627825
+ 001611015323516051965590421184494990778999200732947690586857787872098290135295
+ 661397888486050978608595701773129815531495168146717695976099421003618355913877
+ 781769845875810446628399880600616229848616935337386578773598336161338413385368
+ 421197893890018529569196780455448285848370117096721253533875862158231013310387
+ 766827211572694951817958975469399264219791552338576623167627547570354699414892
+ 904130186386119439196283887054367774322427680913236544948536676800000106526248
+ 547305586159899914017076983854831887501429389089950685453076511680333732226517
+ 566220752695179144225280816517166776672793035485154204023817460892328391703275
+ 425750867655117859395002793389592057668278967764453184040418554010435134838953
+ 120132637836928358082719378312654961745997056745071833206503455664403449045362
+ 756001125018433560736122276594927839370647842645676338818807565612168960504161
+ 139039063960162022153684941092605387688714837989559999112099164646441191856827
+ 700457424343402167227644558933012778158686952506949936461017568506016714535431
+ 581480105458860564550133203758645485840324029871709348091055621167154684847780
+ 394475697980426318099175642280987399876697323769573701580806822904599212366168
+ 902596273043067931653114940176473769387351409336183321614280214976339918983548
+ 487562529875242387307755955595546519639440182184099841248982623673771467226061
+ 633643296406335728107078875816404381485018841143188598827694490119321296827158
+ 884133869434682859006664080631407775772570563072940049294030242049841656547973
+ 670548558044586572022763784046682337985282710578431975354179501134727362577408
+ 021347682604502285157979579764746702284099956160156910890384582450267926594205
+ 550395879229818526480070683765041836562094555434613513415257006597488191634135
+ 955671964965403218727160264859304903978748958906612725079482827693895352175362
+ 185079629778514618843271922322381015874445052866523802253284389137527384589238
+ 442253547265309817157844783421582232702069028723233005386216347988509469547200
+ 479523112015043293226628272763217790884008786148022147537657810581970222630971
+ 749507212724847947816957296142365859578209083073323356034846531873029302665964
+ 501371837542889755797144992465403868179921389346924474198509733462679332107268
+ 687076806263991936196504409954216762784091466985692571507431574079380532392523
+ 947755744159184582156251819215523370960748332923492103451462643744980559610330
+ 799414534778457469999212859999939961228161521931488876938802228108300198601654
+ 941654261696858678837260958774567618250727599295089318052187292461086763995891
+ 614585505839727420980909781729323930106766386824040111304024700735085782872462
+ 713494636853181546969046696869392547251941399291465242385776255004748529547681
+ 479546700705034799958886769501612497228204030399546327883069597624936151010243
+ 655535223069061294938859901573466102371223547891129254769617600504797492806072
+ 126803922691102777226102544149221576504508120677173571202718024296810620377657
+ 883716690910941807448781404907551782038565390991047759414132154328440625030180
+ 275716965082096427348414695726397884256008453121406593580904127113592004197598
+ 513625479616063228873618136737324450607924411763997597461938358457491598809766
+ 744709300654634242346063423747466608043170126005205592849369594143408146852981
+ 505394717890045183575515412522359059068726487863575254191128887737176637486027
+ 660634960353679470269232297186832771739323619200777452212624751869833495151019
+ 864269887847171939664976907082521742336566272592844062043021411371992278526998
+ 469884770232382384005565551788908766136013047709843861168705231055314916251728
+ 373272867600724817298763756981633541507460883866364069347043720668865127568826
+ 614973078865701568501691864748854167915459650723428773069985371390430026653078
+ 398776385032381821553559732353068604301067576083890862704984188859513809103042
+ 359578249514398859011318583584066747237029714978508414585308578133915627076035
+ 639076394731145549583226694570249413983163433237897595568085683629725386791327
+ 505554252449194358912840504522695381217913191451350099384631177401797151228378
+ 546011603595540286440590249646693070776905548102885020808580087811577381719174
+ 177601733073855475800605601433774329901272867725304318251975791679296996504146
+ 070664571258883469797964293162296552016879730003564630457930884032748077181155
+ 533090988702550520768046303460865816539487695196004408482065967379473168086415
+ 645650530049881616490578831154345485052660069823093157776500378070466126470602
+ 145750579327096204782561524714591896522360839664562410519551052235723973951288
+ 181640597859142791481654263289200428160913693777372229998332708208296995573772
+ 737566761552711392258805520189887620114168005468736558063347160373429170390798
+ 639652296131280178267971728982293607028806908776866059325274637840539769184808
+ 204102194471971386925608416245112398062011318454124478205011079876071715568315
+ 407886543904121087303240201068534194723047666672174986986854707678120512473679
+ 247919315085644477537985379973223445612278584329684664751333657369238720146472
+ 367942787004250325558992688434959287612400755875694641370562514001179713316620
+ 715371543600687647731867558714878398908107429530941060596944315847753970094398
+ 839491443235366853920994687964506653398573888786614762944341401049888993160051
+ 207678103588611660202961193639682134960750111649832785635316145168457695687109
+ 002999769841263266502347716728657378579085746646077228341540311441529418804782
+ 543876177079043000156698677679576090996693607559496515273634981189641304331166
+ 277471233881740603731743970540670310967676574869535878967003192586625941051053
+ 358438465602339179674926784476370847497833365557900738419147319886271352595462
+ 518160434225372996286326749682405806029642114638643686422472488728343417044157
+ 348248183330164056695966886676956349141632842641497453334999948000266998758881
+ 593507357815195889900539512085351035726137364034367534714104836017546488300407
+ 846416745216737190483109676711344349481926268111073994825060739495073503169019
+ 731852119552635632584339099822498624067031076831844660729124874754031617969941
+ 139738776589986855417031884778867592902607004321266617919223520938227878880988
+ 633599116081923535557046463491132085918979613279131975649097600013996234445535
+ 014346426860464495862476909434704829329414041114654092398834443515913320107739
+ 441118407410768498106634724104823935827401944935665161088463125678529776973468
+ 430306146241803585293315973458303845541033701091676776374276210213701354854450
+ 926307190114731848574923318167207213727935567952844392548156091372812840633303
+ 937356242001604566455741458816605216660873874804724339121295587776390696903707
+ 882852775389405246075849623157436917113176134783882719416860662572103685132156
+ 647800147675231039357860689611125996028183930954870905907386135191459181951029
+ 732787557104972901148717189718004696169777001791391961379141716270701895846921
+ 434369676292745910994006008498356842520191559370370101104974733949387788598941
+ 743303178534870760322198297057975119144051099423588303454635349234982688362404
+ 332726741554030161950568065418093940998202060999414021689090070821330723089662
+ 119775530665918814119157783627292746156185710372172471009521423696483086410259
+ 288745799932237495519122195190342445230753513380685680735446499512720317448719
+ 540397610730806026990625807602029273145525207807991418429063884437349968145827
+ 337207266391767020118300464819000241308350884658415214899127610651374153943565
+ 721139032857491876909441370209051703148777346165287984823533829726013611098451
+ 484182380812054099612527458088109948697221612852489742555551607637167505489617
+ 301680961380381191436114399210638005083214098760459930932485102516829446726066
+ 613815174571255975495358023998314698220361338082849935670557552471290274539776
+ 214049318201465800802156653606776550878380430413431059180460680083459113664083
+ 488740800574127258670479225831912741573908091438313845642415094084913391809684
+ 025116399193685322555733896695374902662092326131885589158083245557194845387562
+ 878612885900410600607374650140262782402734696252821717494158233174923968353013
+ 617865367376064216677813773995100658952887742766263684183068019080460984980946
+ 976366733566228291513235278880615776827815958866918023894033307644191240341202
+ 231636857786035727694154177882643523813190502808701857504704631293335375728538
+ 660588890458311145077394293520199432197117164223500564404297989208159430716701
+ 985746927384865383343614579463417592257389858800169801475742054299580124295810
+ 545651083104629728293758416116253256251657249807849209989799062003593650993472
+ 158296517413579849104711166079158743698654122234834188772292944633517865385673
+ 196255985202607294767407261676714557364981210567771689348491766077170527718760
+ 119990814411305864557791052568430481144026193840232247093924980293355073184589
+ 035539713308844617410795916251171486487446861124760542867343670904667846867027
+ 409188101424971114965781772427934707021668829561087779440504843752844337510882
+ 826477197854000650970403302186255614733211777117441335028160884035178145254196
+ 432030957601869464908868154528562134698835544456024955666843660292219512483091
+ 060537720198021831010327041783866544718126039719068846237085751808003532704718
+ 565949947612424811099928867915896904956394762460842406593094862150769031498702
+ 067353384834955083636601784877106080980426924713241000946401437360326564518456
+ 679245666955100150229833079849607994988249706172367449361226222961790814311414
+ 660941234159359309585407913908720832273354957208075716517187659944985693795623
+ 875551617575438091780528029464200447215396280746360211329425591600257073562812
+ 638733106005891065245708024474937543184149401482119996276453106800663118382376
+ 163966318093144467129861552759820145141027560068929750246304017351489194576360
+ 789352855505317331416457050499644389093630843874484783961684051845273288403234
+ 520247056851646571647713932377551729479512613239822960239454857975458651745878
+ 771331813875295980941217422730035229650808917770506825924882232215493804837145
+ 478164721397682096332050830564792048208592047549985732038887639160199524091893
+ 894557676874973085695595801065952650303626615975066222508406742889826590751063
+ 756356996821151094966974458054728869363102036782325018232370845979011154847208
+ 761821247781326633041207621658731297081123075815982124863980721240786887811450
+ 165582513617890307086087019897588980745664395515741536319319198107057533663373
+ 803827215279884935039748001589051942087971130805123393322190346624991716915094
+ 854140187106035460379464337900589095772118080446574396280618671786101715674096
+ 766208029576657705129120990794430463289294730615951043090222143937184956063405
+ 618934251305726829146578329334052463502892917547087256484260034962961165413823
+ 007731332729830500160256724014185152041890701154288579920812198449315699905918
+ 201181973350012618772803681248199587707020753240636125931343859554254778196114
+ 293516356122349666152261473539967405158499860355295332924575238881013620234762
+ 466905581643896786309762736550472434864307121849437348530060638764456627218666
+ 170123812771562137974614986132874411771455244470899714452288566294244023018479
+ 120547849857452163469644897389206240194351831008828348024924908540307786387516
+ 591130287395878709810077271827187452901397283661484214287170553179654307650453
+ 432460053636147261818096997693348626407743519992868632383508875668359509726557
+ 481543194019557685043724800102041374983187225967738715495839971844490727914196
+ 584593008394263702087563539821696205532480321226749891140267852859967340524203
+ 109179789990571882194939132075343170798002373659098537552023891164346718558290
+ 685371189795262623449248339249634244971465684659124891855662958932990903523923
+ 333364743520370770101084388003290759834217018554228386161721041760301164591878
+ 053936744747205998502358289183369292233732399948043710841965947316265482574809
+ 948250999183300697656936715968936449334886474421350084070066088359723503953234
+ 017958255703601693699098867113210979889707051728075585519126993067309925070407
+ 024556850778679069476612629808225163313639952117098452809263037592242674257559
+ 989289278370474445218936320348941552104459726188380030067761793138139916205806
+ 270165102445886924764924689192461212531027573139084047000714356136231699237169
+ 484813255420091453041037135453296620639210547982439212517254013231490274058589
+ 206321758949434548906846399313757091034633271415316223280552297297953801880162
+ 859073572955416278867649827418616421878988574107164906919185116281528548679417
+ 363890665388576422915834250067361245384916067413734017357277995634104332688356
+ 950781493137800736235418007061918026732855119194267609122103598746924117283749
+ 312616339500123959924050845437569850795704622266461900010350049018303415354584
+ 283376437811198855631877779253720116671853954183598443830520376281944076159410
+ 682071697030228515225057312609304689842343315273213136121658280807521263154773
+ 060442377475350595228717440266638914881717308643611138906942027908814311944879
+ 941715404210341219084709408025402393294294549387864023051292711909751353600092
+ 197110541209668311151632870542302847007312065803262641711616595761327235156666
+ 253667271899853419989523688483099930275741991646384142707798870887422927705389
+ 122717248632202889842512528721782603050099451082478357290569198855546788607946
+ 280537122704246654319214528176074148240382783582971930101788834567416781139895
+ 475044833931468963076339665722672704339321674542182455706252479721997866854279
+ 897799233957905758189062252547358220523642485078340711014498047872669199018643
+ 882293230538231855973286978092225352959101734140733488476100556401824239219269
+ 506208318381454698392366461363989101210217709597670490830508185470419466437131
+ 229969235889538493013635657618610606222870559942337163102127845744646398973818
+ 856674626087948201864748767272722206267646533809980196688368099415907577685263
+ 986514625333631245053640261056960551318381317426118442018908885319635698696279
+ 503673842431301133175330532980201668881748134298868158557781034323175306478498
+ 321062971842518438553442762012823457071698853051832617964117857960888815032960
+ 229070561447622091509473903594664691623539680920139457817589108893199211226007
+ 392814916948161527384273626429809823406320024402449589445612916704950823581248
+ 739179964864113348032475777521970893277226234948601504665268143987705161531702
+ 669692970492831628550421289814670619533197026950721437823047687528028735412616
+ 639170824592517001071418085480063692325946201900227808740985977192180515853214
+ 739265325155903541020928466592529991435379182531454529059841581763705892790690
+ 989691116438118780943537152133226144362531449012745477269573939348154691631162
+ 492887357471882407150399500944673195431619385548520766573882513963916357672315
+ 100555603726339486720820780865373494244011579966750736071115935133195919712094
+ 896471755302453136477094209463569698222667377520994516845064362382421185353488
+ 798939567318780660610788544000550827657030558744854180577889171920788142335113
+ 866292966717964346876007704799953788338787034871802184243734211227394025571769
+ 081960309201824018842705704609262256417837526526335832424066125331152942345796
+ 556950250681001831090041124537901533296615697052237921032570693705109083078947
+ 999900499939532215362274847660361367769797856738658467093667958858378879562594
+ 646489137665219958828693380183601193236857855855819555604215625088365020332202
+ 451376215820461810670519533065306060650105488716724537794283133887163139559690
+ 583208341689847606560711834713621812324622725884199028614208728495687963932546
+ 428534307530110528571382964370999035694888528519040295604734613113826387889755
+ 178856042499874831638280404684861893818959054203988987265069762020199554841265
+ 000539442820393012748163815853039643992547020167275932857436666164411096256633
+ 730540921951967514832873480895747777527834422109107311135182804603634719818565
+ 557295714474768255285786334934285842311874944000322969069775831590385803935352
+ 135886007960034209754739229673331064939560181223781285458431760556173386112673
+ 478074585067606304822940965304111830667108189303110887172816751957967534718853
+ 722930961614320400638132246584111115775835858113501856904781536893813771847281
+ 475199835050478129771859908470762197460588742325699582889253504193795826061621
+ 184236876851141831606831586799460165205774052942305360178031335726326705479033
+ 840125730591233960188013782542192709476733719198728738524805742124892118347087
+ 662966720727232565056512933312605950577772754247124164831283298207236175057467
+ 387012820957554430596839555568686118839713552208445285264008125202766555767749
+ 596962661260456524568408613923826576858338469849977872670655519185446869846947
+ 849573462260629421962455708537127277652309895545019303773216664918257815467729
+ 200521266714346320963789185232321501897612603437368406719419303774688099929687
+ 758244104787812326625318184596045385354383911449677531286426092521153767325886
+ 672260404252349108702695809964759580579466397341906401003636190404203311357933
+ 654242630356145700901124480089002080147805660371015412232889146572239314507607
+ 167064355682743774396578906797268743847307634645167756210309860409271709095128
+ 086309029738504452718289274968921210667008164858339553773591913695015316201890
+ 888748421079870689911480466927065094076204650277252865072890532854856143316081
+ 269300569378541786109696920253886503457718317668688592368148847527649846882194
+ 973972970773718718840041432312763650481453112285099002074240925585925292610302
+ 106736815434701525234878635164397623586041919412969769040526483234700991115424
+ 260127343802208933109668636789869497799400126016422760926082349304118064382913
+ 834735467972539926233879158299848645927173405922562074910530853153718291168163
+ 721939518870095778818158685046450769934394098743351443162633031724774748689791
+ 820923948083314397084067308407958935810896656477585990556376952523265361442478
+ 023082681183103773588708924061303133647737101162821461466167940409051861526036
+ 009252194721889091810733587196414214447865489952858234394705007983038853886083
+ 103571930600277119455802191194289992272235345870756624692617766317885514435021
+ 828702668561066500353105021631820601760921798468493686316129372795187307897263
+ 735371715025637873357977180818487845886650433582437700414771041493492743845758
+ 710715973155943942641257027096512510811554824793940359768118811728247215825010
+ 949609662539339538092219559191818855267806214992317276316321833989693807561685
+ 591175299845013206712939240414459386239880938124045219148483164621014738918251
+ 010909677386906640415897361047643650006807710565671848628149637111883219244566
+ 394581449148616550049567698269030891118568798692947051352481609174324301538368
+ 470729289898284602223730145265567989862776796809146979837826876431159883210904
+ 371561129976652153963546442086919756737000573876497843768628768179249746943842
+ 746525631632300555130417422734164645512781278457777245752038654375428282567141
+ 288583