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]

PR11321: Inferior crashes if user detaches while displaced stepping is in progress


I've applied this patch below to fix PR11321 for hardware
single-step architectures.

It makes sure all in-process displaced stepping operations
are finished before actually detaching.

target_detach used to do:

 1. - remove breakpoints
 2. - actually detach

now does:

 1. - remove breakpoints
 2. - finish in-process displaced steppings
 3. - actually detach

For software single-step architectures (like ARM) this
will need further fixing, because step #1 also removes
the software-single-step-like breakpoints set in the
scratch pad...

-- 
Pedro Alves

2010-02-24  Pedro Alves  <pedro@codesourcery.com>

	PR gdb/11321

	* inferior.h (prepare_for_detach): Declare.
	(struct inferior) <detaching>: New field.
	* infrun.c (prepare_for_detach): New.
	(handle_inferior_event) <random signal>: Don't stop if detaching.
	* target.c (target_detach): Call prepare_for_detach.

---
 gdb/inferior.h |    5 +++
 gdb/infrun.c   |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/target.c   |    2 +
 3 files changed, 88 insertions(+), 1 deletion(-)

Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h	2010-02-24 20:44:49.000000000 +0000
+++ src/gdb/inferior.h	2010-02-24 20:47:42.000000000 +0000
@@ -185,6 +185,8 @@ extern void address_to_signed_pointer (s
 
 extern void wait_for_inferior (int treat_exec_as_sigtrap);
 
+extern void prepare_for_detach (void);
+
 extern void fetch_inferior_event (void *);
 
 extern void init_wait_for_inferior (void);
@@ -478,6 +480,9 @@ struct inferior
      either by exiting or execing.  */
   int waiting_for_vfork_done;
 
+  /* True if we're in the process of detaching from this inferior.  */
+  int detaching;
+
   /* What is left to do for an execution command after any thread of
      this inferior stops.  For continuations associated with a
      specific thread, see `struct thread_info'.  */
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2010-02-24 20:44:49.000000000 +0000
+++ src/gdb/infrun.c	2010-02-24 20:47:42.000000000 +0000
@@ -2331,6 +2331,84 @@ print_target_wait_results (ptid_t waiton
   ui_file_delete (tmp_stream);
 }
 
+/* Prepare and stabilize the inferior for detaching it.  E.g.,
+   detaching while a thread is displaced stepping is a recipe for
+   crashing it, as nothing would readjust the PC out of the scratch
+   pad.  */
+
+void
+prepare_for_detach (void)
+{
+  struct inferior *inf = current_inferior ();
+  ptid_t pid_ptid = pid_to_ptid (inf->pid);
+  struct cleanup *old_chain_1;
+  struct displaced_step_inferior_state *displaced;
+
+  displaced = get_displaced_stepping_state (inf->pid);
+
+  /* Is any thread of this process displaced stepping?  If not,
+     there's nothing else to do.  */
+  if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid))
+    return;
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+			"displaced-stepping in-process while detaching");
+
+  old_chain_1 = make_cleanup_restore_integer (&inf->detaching);
+  inf->detaching = 1;
+
+  while (!ptid_equal (displaced->step_ptid, null_ptid))
+    {
+      struct cleanup *old_chain_2;
+      struct execution_control_state ecss;
+      struct execution_control_state *ecs;
+
+      ecs = &ecss;
+      memset (ecs, 0, sizeof (*ecs));
+
+      overlay_cache_invalid = 1;
+
+      /* We have to invalidate the registers BEFORE calling
+	 target_wait because they can be loaded from the target while
+	 in target_wait.  This makes remote debugging a bit more
+	 efficient for those targets that provide critical registers
+	 as part of their normal status mechanism. */
+
+      registers_changed ();
+
+      if (deprecated_target_wait_hook)
+	ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0);
+      else
+	ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0);
+
+      if (debug_infrun)
+	print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws);
+
+      /* If an error happens while handling the event, propagate GDB's
+	 knowledge of the executing state to the frontend/user running
+	 state.  */
+      old_chain_2 = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
+      /* Now figure out what to do with the result of the result.  */
+      handle_inferior_event (ecs);
+
+      /* No error, don't finish the state yet.  */
+      discard_cleanups (old_chain_2);
+
+      /* Breakpoints and watchpoints are not installed on the target
+	 at this point, and signals are passed directly to the
+	 inferior, so this must mean the process is gone.  */
+      if (!ecs->wait_some_more)
+	{
+	  discard_cleanups (old_chain_1);
+	  error (_("Program exited while detaching"));
+	}
+    }
+
+  discard_cleanups (old_chain_1);
+}
+
 /* Wait for control to return from inferior to debugger.
 
    If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
@@ -3787,6 +3865,7 @@ process_event_stop_test:
     {
       /* Signal not for debugging purposes.  */
       int printed = 0;
+      struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
 
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n",
@@ -3805,7 +3884,8 @@ process_event_stop_test:
 	 to remain stopped.  */
       if (stop_soon != NO_STOP_QUIETLY
 	  || ecs->event_thread->stop_requested
-	  || signal_stop_state (ecs->event_thread->stop_signal))
+	  || (!inf->detaching
+	      && signal_stop_state (ecs->event_thread->stop_signal)))
 	{
 	  stop_stepping (ecs);
 	  return;
Index: src/gdb/target.c
===================================================================
--- src.orig/gdb/target.c	2010-02-24 20:44:49.000000000 +0000
+++ src/gdb/target.c	2010-02-24 20:47:42.000000000 +0000
@@ -2077,6 +2077,8 @@ target_detach (char *args, int from_tty)
        them before detaching.  */
     remove_breakpoints_pid (PIDGET (inferior_ptid));
 
+  prepare_for_detach ();
+
   for (t = current_target.beneath; t != NULL; t = t->beneath)
     {
       if (t->to_detach != NULL)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]