forked from Imagelibrary/binutils-gdb
* dummy-frame.c (dummy_frame): Replace regcache member with
caller_state. (dummy_frame_push): Replace caller_regcache arg with caller_state. All callers updated. (remove_dummy_frame,pop_dummy_frame,lookup_dummy_frame): New fns. (dummy_frame_pop): Rewrite. Verify requested frame is in the dummy frame stack. Restore program state. (cleanup_dummy_frames): Rewrite. (dummy_frame_sniffer): Update. Make static. * dummy-frame.h (regcache,frame_info): Delete forward decls. (inferior_thread_state): New forward decl. (dummy_frame_push): Update prototype. * frame.c (frame_pop): dummy_frame_pop now does all the work for DUMMY_FRAMEs. * infcall.c (breakpoint_auto_delete_contents): Delete. (get_function_name,run_inferior_call): New fns. (call_function_by_hand): Simplify by moving some code to get_function_name, run_inferior_call. Inferior function call wrapped in TRY_CATCH so there's less need for cleanups and all exits from proceed are handled similarily. Detect program exit. Detect program stopping in a different thread. Make error messages more consistent. * inferior.h (inferior_thread_state): Declare (opaque type). (save_inferior_thread_state,restore_inferior_thread_state, make_cleanup_restore_inferior_thread_state, discard_inferior_thread_state, get_inferior_thread_state_regcache): Declare. (save_inferior_status): Update prototype. * infrun.c: (normal_stop): When stopped for the completion of an inferior function call, verify the expected stack frame kind. (inferior_thread_state): New struct. (save_inferior_thread_state,restore_inferior_thread_state, do_restore_inferior_thread_state_cleanup, make_cleanup_restore_inferior_thread_state, discard_inferior_thread_state, get_inferior_thread_state_regcache): New functions. (inferior_status): Move stop_signal, stop_pc, registers to inferior_thread_state. Remove restore_stack_info. (save_inferior_status): Remove arg restore_stack_info. All callers updated. Remove saving of state now saved by save_inferior_thread_state. (restore_inferior_status): Remove restoration of state now done by restore_inferior_thread_state. (discard_inferior_status): Remove freeing of registers, now done by discard_inferior_thread_state. * gdb.base/break.exp: Update expected gdb output. * gdb.base/sepdebug.exp: Ditto. * gdb.mi/mi-syn-frame.exp: Ditto. * gdb.mi/mi2-syn-frame.exp: Ditto. * gdb.base/call-signal-resume.exp: New file. * gdb.base/call-signals.c: New file. * gdb.base/unwindonsignal.exp: New file. * gdb.base/unwindonsignal.c: New file. * gdb.threads/interrupted-hand-call.exp: New file. * gdb.threads/interrupted-hand-call.c: New file. * gdb.threads/thread-unwindonsignal.exp: New file.
This commit is contained in:
144
gdb/infrun.c
144
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user