aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2010-02-24 20:49:50 +0000
committerPedro Alves <palves@redhat.com>2010-02-24 20:49:50 +0000
commit24291992dac3f63bef7ee031d4d5f2f96920e070 (patch)
tree31ecffb25c822e47a6607a984cdcee46ff3b91fa
parentfc1cf338c43f4f84624cd0f9026e1be8561b2c42 (diff)
downloadfsf-binutils-gdb-24291992dac3f63bef7ee031d4d5f2f96920e070.zip
fsf-binutils-gdb-24291992dac3f63bef7ee031d4d5f2f96920e070.tar.gz
fsf-binutils-gdb-24291992dac3f63bef7ee031d4d5f2f96920e070.tar.bz2
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.
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/inferior.h5
-rw-r--r--gdb/infrun.c82
-rw-r--r--gdb/target.c2
4 files changed, 98 insertions, 1 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 44c7653..962a3c9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,15 @@
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.
+
+2010-02-24 Pedro Alves <pedro@codesourcery.com>
+
Per-process displaced stepping queue.
* infrun.c (displaced_step_ptid, displaced_step_request_queue)
diff --git a/gdb/inferior.h b/gdb/inferior.h
index bd6f1c8..dc87a9e 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -185,6 +185,8 @@ extern void address_to_signed_pointer (struct gdbarch *gdbarch,
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'. */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 7379107..83cfe3c 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2331,6 +2331,84 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
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;
diff --git a/gdb/target.c b/gdb/target.c
index e6659c9..1f90171 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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)