This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Handle fork exit more gracefully in linux-fork.c
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Cc: Michael Snyder <msnyder at redhat dot com>
- Date: Mon, 27 Feb 2006 11:43:48 -0500
- Subject: Handle fork exit more gracefully in linux-fork.c
A cleanup I made while working on my next patch. I was debugging
some checkpoint.exp failures by hand, and the most obvious thing for
me to do was to create a checkpoint, let the current one exit, and
then continue the previous checkpoint - but as soon as I did this
it crashed with corrupted register state.
We weren't restoring the saved registers in linux_fork_mourn_inferior.
And we were somehow clobbering the previous registers. Moving
some bits from the explicit context-switch code into the restore-a-fork
routine fixed all that.
Look OK?
--
Daniel Jacobowitz
CodeSourcery
2006-02-27 Daniel Jacobowitz <dan@codesourcery.com>
* linux-fork.c: Include "gdb_assert.h".
(fork_load_infrun_state): Set inferior_ptid and stop_pc here.
Update the register cache and selected frame also.
(linux_fork_mourn_inferior): Use fork_load_infrun_state. Return
to single fork mode if necessary.
(linux_fork_context): Remove bits handled by fork_load_infrun_state.
* Makefile.in (linux_fork_h): New.
(linux-fork.o, linux-nat.o): Update.
Index: src/gdb/linux-fork.c
===================================================================
--- src.orig/gdb/linux-fork.c 2006-02-27 10:59:47.000000000 -0500
+++ src/gdb/linux-fork.c 2006-02-27 11:10:45.000000000 -0500
@@ -24,6 +24,7 @@
#include "regcache.h"
#include "gdbcmd.h"
#include "infcall.h"
+#include "gdb_assert.h"
#include "gdb_string.h"
#include "linux-fork.h"
@@ -239,9 +240,19 @@ fork_load_infrun_state (struct fork_info
extern void nullify_last_target_wait_ptid ();
int i;
+ inferior_ptid = fp->ptid;
+
if (fp->savedregs && fp->clobber_regs)
regcache_cpy (current_regcache, fp->savedregs);
+ registers_changed ();
+ reinit_frame_cache ();
+
+ /* We must select a new frame before making any inferior calls to
+ avoid warnings. */
+ select_frame (get_current_frame ());
+
+ stop_pc = read_pc ();
nullify_last_target_wait_ptid ();
/* Now restore the file positions of open file descriptors. */
@@ -354,12 +365,19 @@ linux_fork_mourn_inferior (void)
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));
- }
+
+ /* There should still be a fork - if there's only one left,
+ delete_fork won't remove it, because we haven't updated
+ inferior_ptid yet. */
+ gdb_assert (fork_list);
+
+ fork_load_infrun_state (fork_list);
+ printf_filtered (_("[Switching to %s]\n"),
+ target_pid_to_str (inferior_ptid));
+
+ /* If there's only one fork, switch back to non-fork mode. */
+ if (fork_list->next == NULL)
+ delete_fork (inferior_ptid);
}
/* Fork list <-> user interface. */
@@ -555,17 +573,10 @@ linux_fork_context (struct fork_info *ne
error (_("No such fork/process"));
if (!oldfp)
- {
- oldfp = add_fork (ptid_get_pid (inferior_ptid));
- }
+ 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));
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2006-02-27 10:59:48.000000000 -0500
+++ src/gdb/Makefile.in 2006-02-27 11:12:35.000000000 -0500
@@ -726,6 +726,7 @@ kod_h = kod.h
language_h = language.h
libunwind_frame_h = libunwind-frame.h $(libunwind_h)
linespec_h = linespec.h
+linux_fork_h = linux-fork.h
linux_nat_h = linux-nat.h $(target_h)
m2_lang_h = m2-lang.h
m32r_tdep_h = m32r-tdep.h
@@ -2186,12 +2187,13 @@ linespec.o: linespec.c $(defs_h) $(symta
$(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-fork.o: linux-fork.c $(defs_h) $(inferior_h) $(regcache_h) $(gdbcmd_h) \
+ $(infcall_h) $(gdb_assert_h) $(gdb_string_h) $(linux_fork_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
+ $(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) \