aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c144
1 files changed, 99 insertions, 45 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 228e743..92092ab 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -45,7 +45,6 @@
#include "language.h"
#include "solib.h"
#include "main.h"
-
#include "gdb_assert.h"
#include "mi/mi-common.h"
#include "event-top.h"
@@ -4387,14 +4386,20 @@ Further execution is probably impossible.\n"));
if (stop_stack_dummy)
{
- /* Pop the empty frame that contains the stack dummy. POP_FRAME
- ends with a setting of the current frame, so we can use that
- next. */
- frame_pop (get_current_frame ());
- /* Set stop_pc to what it was before we called the function.
- Can't rely on restore_inferior_status because that only gets
- called if we don't stop in the called function. */
- stop_pc = read_pc ();
+ /* Pop the empty frame that contains the stack dummy.
+ This also restores inferior state prior to the call
+ (struct inferior_thread_state). */
+ struct frame_info *frame = get_current_frame ();
+ gdb_assert (get_frame_type (frame) == DUMMY_FRAME);
+ frame_pop (frame);
+ /* frame_pop() calls reinit_frame_cache as the last thing it does
+ which means there's currently no selected frame. We don't need
+ to re-establish a selected frame if the dummy call returns normally,
+ that will be done by restore_inferior_status. However, we do have
+ to handle the case where the dummy call is returning after being
+ stopped (e.g. the dummy call previously hit a breakpoint). We
+ can't know which case we have so just always re-establish a
+ selected frame here. */
select_frame (get_current_frame ());
}
@@ -4792,10 +4797,85 @@ signals_info (char *signum_exp, int from_tty)
printf_filtered (_("\nUse the \"handle\" command to change these tables.\n"));
}
-struct inferior_status
+/* Inferior thread state.
+ These are details related to the inferior itself, and don't include
+ things like what frame the user had selected or what gdb was doing
+ with the target at the time.
+ For inferior function calls these are things we want to restore
+ regardless of whether the function call successfully completes
+ or the dummy frame has to be manually popped. */
+
+struct inferior_thread_state
{
enum target_signal stop_signal;
CORE_ADDR stop_pc;
+ struct regcache *registers;
+};
+
+struct inferior_thread_state *
+save_inferior_thread_state (void)
+{
+ struct inferior_thread_state *inf_state = XMALLOC (struct inferior_thread_state);
+ struct thread_info *tp = inferior_thread ();
+
+ inf_state->stop_signal = tp->stop_signal;
+ inf_state->stop_pc = stop_pc;
+
+ inf_state->registers = regcache_dup (get_current_regcache ());
+
+ return inf_state;
+}
+
+/* Restore inferior session state to INF_STATE. */
+
+void
+restore_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+ struct thread_info *tp = inferior_thread ();
+
+ tp->stop_signal = inf_state->stop_signal;
+ stop_pc = inf_state->stop_pc;
+
+ /* The inferior can be gone if the user types "print exit(0)"
+ (and perhaps other times). */
+ if (target_has_execution)
+ /* NB: The register write goes through to the target. */
+ regcache_cpy (get_current_regcache (), inf_state->registers);
+ regcache_xfree (inf_state->registers);
+ xfree (inf_state);
+}
+
+static void
+do_restore_inferior_thread_state_cleanup (void *state)
+{
+ restore_inferior_thread_state (state);
+}
+
+struct cleanup *
+make_cleanup_restore_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+ return make_cleanup (do_restore_inferior_thread_state_cleanup, inf_state);
+}
+
+void
+discard_inferior_thread_state (struct inferior_thread_state *inf_state)
+{
+ regcache_xfree (inf_state->registers);
+ xfree (inf_state);
+}
+
+struct regcache *
+get_inferior_thread_state_regcache (struct inferior_thread_state *inf_state)
+{
+ return inf_state->registers;
+}
+
+/* Session related state for inferior function calls.
+ These are the additional bits of state that need to be restored
+ when an inferior function call successfully completes. */
+
+struct inferior_status
+{
bpstat stop_bpstat;
int stop_step;
int stop_stack_dummy;
@@ -4809,32 +4889,23 @@ struct inferior_status
int stop_after_trap;
int stop_soon;
- /* These are here because if call_function_by_hand has written some
- registers and then decides to call error(), we better not have changed
- any registers. */
- struct regcache *registers;
-
- /* A frame unique identifier. */
+ /* ID if the selected frame when the inferior function call was made. */
struct frame_id selected_frame_id;
int breakpoint_proceeded;
- int restore_stack_info;
int proceed_to_finish;
};
/* Save all of the information associated with the inferior<==>gdb
- connection. INF_STATUS is a pointer to a "struct inferior_status"
- (defined in inferior.h). */
+ connection. */
struct inferior_status *
-save_inferior_status (int restore_stack_info)
+save_inferior_status (void)
{
struct inferior_status *inf_status = XMALLOC (struct inferior_status);
struct thread_info *tp = inferior_thread ();
struct inferior *inf = current_inferior ();
- inf_status->stop_signal = tp->stop_signal;
- inf_status->stop_pc = stop_pc;
inf_status->stop_step = tp->stop_step;
inf_status->stop_stack_dummy = stop_stack_dummy;
inf_status->stopped_by_random_signal = stopped_by_random_signal;
@@ -4852,12 +4923,10 @@ save_inferior_status (int restore_stack_info)
inf_status->stop_bpstat = tp->stop_bpstat;
tp->stop_bpstat = bpstat_copy (tp->stop_bpstat);
inf_status->breakpoint_proceeded = breakpoint_proceeded;
- inf_status->restore_stack_info = restore_stack_info;
inf_status->proceed_to_finish = tp->proceed_to_finish;
- inf_status->registers = regcache_dup (get_current_regcache ());
-
inf_status->selected_frame_id = get_frame_id (get_selected_frame (NULL));
+
return inf_status;
}
@@ -4882,14 +4951,14 @@ restore_selected_frame (void *args)
return (1);
}
+/* Restore inferior session state to INF_STATUS. */
+
void
restore_inferior_status (struct inferior_status *inf_status)
{
struct thread_info *tp = inferior_thread ();
struct inferior *inf = current_inferior ();
- tp->stop_signal = inf_status->stop_signal;
- stop_pc = inf_status->stop_pc;
tp->stop_step = inf_status->stop_step;
stop_stack_dummy = inf_status->stop_stack_dummy;
stopped_by_random_signal = inf_status->stopped_by_random_signal;
@@ -4902,24 +4971,11 @@ restore_inferior_status (struct inferior_status *inf_status)
inf->stop_soon = inf_status->stop_soon;
bpstat_clear (&tp->stop_bpstat);
tp->stop_bpstat = inf_status->stop_bpstat;
+ inf_status->stop_bpstat = NULL;
breakpoint_proceeded = inf_status->breakpoint_proceeded;
tp->proceed_to_finish = inf_status->proceed_to_finish;
- /* The inferior can be gone if the user types "print exit(0)"
- (and perhaps other times). */
- if (target_has_execution)
- /* NB: The register write goes through to the target. */
- regcache_cpy (get_current_regcache (), inf_status->registers);
- regcache_xfree (inf_status->registers);
-
- /* FIXME: If we are being called after stopping in a function which
- is called from gdb, we should not be trying to restore the
- selected frame; it just prints a spurious error message (The
- message is useful, however, in detecting bugs in gdb (like if gdb
- clobbers the stack)). In fact, should we be restoring the
- inferior status at all in that case? . */
-
- if (target_has_stack && inf_status->restore_stack_info)
+ if (target_has_stack)
{
/* The point of catch_errors is that if the stack is clobbered,
walking the stack might encounter a garbage pointer and
@@ -4931,7 +4987,6 @@ restore_inferior_status (struct inferior_status *inf_status)
/* Error in restoring the selected frame. Select the innermost
frame. */
select_frame (get_current_frame ());
-
}
xfree (inf_status);
@@ -4954,10 +5009,9 @@ discard_inferior_status (struct inferior_status *inf_status)
{
/* See save_inferior_status for info on stop_bpstat. */
bpstat_clear (&inf_status->stop_bpstat);
- regcache_xfree (inf_status->registers);
xfree (inf_status);
}
-
+
int
inferior_has_forked (ptid_t pid, ptid_t *child_pid)
{