summaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c1693
1 files changed, 937 insertions, 756 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 09939cae005..95022a28daf 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -52,12 +52,6 @@
#include "record.h"
-/* When the record function want inferior step before call function
- "keep_going", "reverse_resume_need_step" will be set to 1. It will be set
- back to 0 in the begin of function "handle_inferior_event" because it just
- be accessed by the sub-functions of "handle_inferior_event". */
-static int reverse_resume_need_step = 0;
-
/* Prototypes for local functions */
static void signals_info (char *, int);
@@ -81,9 +75,9 @@ static int follow_fork (void);
static void set_schedlock_func (char *args, int from_tty,
struct cmd_list_element *c);
-struct thread_stepping_state;
+static int currently_stepping (struct thread_info *tp);
-static int currently_stepping (struct thread_stepping_state *tss);
+static int currently_stepping_callback (struct thread_info *tp, void *data);
static void xdb_handle_command (char *args, int from_tty);
@@ -148,13 +142,13 @@ show_debug_infrun (struct ui_file *file, int from_tty,
past the dynamic linker, as if we were using "next" to step over a
function call.
- IN_SOLIB_DYNSYM_RESOLVE_CODE says whether we're in the dynamic
+ in_solib_dynsym_resolve_code() says whether we're in the dynamic
linker code or not. Normally, this means we single-step. However,
if SKIP_SOLIB_RESOLVER then returns non-zero, then its value is an
address where we can place a step-resume breakpoint to get past the
linker's symbol resolution function.
- IN_SOLIB_DYNSYM_RESOLVE_CODE can generally be implemented in a
+ in_solib_dynsym_resolve_code() can generally be implemented in a
pretty portable way, by comparing the PC against the address ranges
of the dynamic linker's sections.
@@ -224,31 +218,6 @@ static struct cmd_list_element *stop_command;
static struct symbol *step_start_function;
-/* Nonzero if we are presently stepping over a breakpoint.
-
- If we hit a breakpoint or watchpoint, and then continue,
- we need to single step the current thread with breakpoints
- disabled, to avoid hitting the same breakpoint or
- watchpoint again. And we should step just a single
- thread and keep other threads stopped, so that
- other threads don't miss breakpoints while they are removed.
-
- So, this variable simultaneously means that we need to single
- step the current thread, keep other threads stopped, and that
- breakpoints should be removed while we step.
-
- This variable is set either:
- - in proceed, when we resume inferior on user's explicit request
- - in keep_going, if handle_inferior_event decides we need to
- step over breakpoint.
-
- The variable is cleared in clear_proceed_status, called every
- time before we call proceed. The proceed calls wait_for_inferior,
- which calls handle_inferior_event in a loop, and until
- wait_for_inferior exits, this variable is changed only by keep_going. */
-
-static int stepping_over_breakpoint;
-
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
static int stop_on_solib_events;
@@ -265,20 +234,8 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty,
int stop_after_trap;
-/* Nonzero means expecting a trap and caller will handle it themselves.
- It is used after attach, due to attaching to a process;
- when running in the shell before the child program has been exec'd;
- and when running some kinds of remote stuff (FIXME?). */
-
-enum stop_kind stop_soon;
-
-/* Nonzero if proceed is being used for a "finish" command or a similar
- situation when stop_registers should be saved. */
-
-int proceed_to_finish;
-
-/* Save register contents here when about to pop a stack dummy frame,
- if-and-only-if proceed_to_finish is set.
+/* Save register contents here when executing a "finish" command or are
+ about to pop a stack dummy frame, if-and-only-if proceed_to_finish is set.
Thus this contains the return value from the called function (assuming
values are returned in a register). */
@@ -288,34 +245,15 @@ struct regcache *stop_registers;
static int stop_print_frame;
-/* Step-resume or longjmp-resume breakpoint. */
-static struct breakpoint *step_resume_breakpoint = NULL;
-
/* This is a cached copy of the pid/waitstatus of the last event
returned by target_wait()/deprecated_target_wait_hook(). This
information is returned by get_last_target_status(). */
static ptid_t target_last_wait_ptid;
static struct target_waitstatus target_last_waitstatus;
-/* Context-switchable data. */
-struct thread_stepping_state
-{
- /* Should we step over breakpoint next time keep_going
- is called? */
- int stepping_over_breakpoint;
- int current_line;
- struct symtab *current_symtab;
- int step_after_step_resume_breakpoint;
- int stepping_through_solib_after_catch;
- bpstat stepping_through_solib_catchpoints;
-};
-
-struct thread_stepping_state gtss;
-struct thread_stepping_state *tss = &gtss;
-
static void context_switch (ptid_t ptid);
-void init_thread_stepping_state (struct thread_stepping_state *tss);
+void init_thread_stepping_state (struct thread_info *tss);
void init_infwait_state (void);
@@ -367,6 +305,8 @@ follow_fork (void)
void
follow_inferior_reset_breakpoints (void)
{
+ struct thread_info *tp = inferior_thread ();
+
/* Was there a step_resume breakpoint? (There was if the user
did a "next" at the fork() call.) If so, explicitly reset its
thread number.
@@ -378,8 +318,8 @@ follow_inferior_reset_breakpoints (void)
"threads". We must update the bp's notion of which thread
it is for, or it'll be ignored when it triggers. */
- if (step_resume_breakpoint)
- breakpoint_re_set_thread (step_resume_breakpoint);
+ if (tp->step_resume_breakpoint)
+ breakpoint_re_set_thread (tp->step_resume_breakpoint);
/* Reinsert all breakpoints in the child. The user may have set
breakpoints after catching the fork, in which case those
@@ -395,8 +335,8 @@ follow_inferior_reset_breakpoints (void)
static void
follow_exec (ptid_t pid, char *execd_pathname)
{
- ptid_t saved_pid = pid;
struct target_ops *tgt;
+ struct thread_info *th = inferior_thread ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
@@ -422,9 +362,9 @@ follow_exec (ptid_t pid, char *execd_pathname)
/* If there was one, it's gone now. We cannot truly step-to-next
statement through an exec(). */
- step_resume_breakpoint = NULL;
- step_range_start = 0;
- step_range_end = 0;
+ th->step_resume_breakpoint = NULL;
+ th->step_range_start = 0;
+ th->step_range_end = 0;
/* What is this a.out's name? */
printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
@@ -433,9 +373,8 @@ follow_exec (ptid_t pid, char *execd_pathname)
inferior has essentially been killed & reborn. */
gdb_flush (gdb_stdout);
- generic_mourn_inferior ();
- /* Because mourn_inferior resets inferior_ptid. */
- inferior_ptid = saved_pid;
+
+ breakpoint_init_inferior (inf_execd);
if (gdb_sysroot && *gdb_sysroot)
{
@@ -618,28 +557,55 @@ static CORE_ADDR displaced_step_original, displaced_step_copy;
/* Saved contents of copy area. */
static gdb_byte *displaced_step_saved_copy;
-/* When this is non-zero, we are allowed to use displaced stepping, if
- the architecture supports it. When this is zero, we use
- traditional the hold-and-step approach. */
-int can_use_displaced_stepping = 1;
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char can_use_displaced_stepping_auto[] = "auto";
+static const char can_use_displaced_stepping_on[] = "on";
+static const char can_use_displaced_stepping_off[] = "off";
+static const char *can_use_displaced_stepping_enum[] =
+{
+ can_use_displaced_stepping_auto,
+ can_use_displaced_stepping_on,
+ can_use_displaced_stepping_off,
+ NULL,
+};
+
+/* If ON, and the architecture supports it, GDB will use displaced
+ stepping to step over breakpoints. If OFF, or if the architecture
+ doesn't support it, GDB will instead use the traditional
+ hold-and-step approach. If AUTO (which is the default), GDB will
+ decide which technique to use to step over breakpoints depending on
+ which of all-stop or non-stop mode is active --- displaced stepping
+ in non-stop mode; hold-and-step in all-stop mode. */
+
+static const char *can_use_displaced_stepping =
+ can_use_displaced_stepping_auto;
+
static void
show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
- fprintf_filtered (file, _("\
-Debugger's willingness to use displaced stepping to step over "
-"breakpoints is %s.\n"), value);
+ if (can_use_displaced_stepping == can_use_displaced_stepping_auto)
+ fprintf_filtered (file, _("\
+Debugger's willingness to use displaced stepping to step over \
+breakpoints is %s (currently %s).\n"),
+ value, non_stop ? "on" : "off");
+ else
+ fprintf_filtered (file, _("\
+Debugger's willingness to use displaced stepping to step over \
+breakpoints is %s.\n"), value);
}
-/* Return non-zero if displaced stepping is enabled, and can be used
- with GDBARCH. */
-/* When GDB is working in record replay mode, it doesn't need use desplaced
- step. */
+/* Return non-zero if displaced stepping can/should be used to step
+ over breakpoints. */
+
static int
use_displaced_stepping (struct gdbarch *gdbarch)
{
- return (can_use_displaced_stepping
+ return (((can_use_displaced_stepping == can_use_displaced_stepping_auto
+ && non_stop)
+ || can_use_displaced_stepping == can_use_displaced_stepping_on)
&& gdbarch_displaced_step_copy_insn_p (gdbarch)
&& !RECORD_IS_USED);
}
@@ -697,7 +663,7 @@ displaced_step_dump_bytes (struct ui_file *file,
static int
displaced_step_prepare (ptid_t ptid)
{
- struct cleanup *old_cleanups;
+ struct cleanup *old_cleanups, *ignore_cleanups;
struct regcache *regcache = get_thread_regcache (ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR original, copy;
@@ -749,6 +715,9 @@ displaced_step_prepare (ptid_t ptid)
displaced_step_clear ();
+ old_cleanups = save_inferior_ptid ();
+ inferior_ptid = ptid;
+
original = regcache_read_pc (regcache);
copy = gdbarch_displaced_step_location (gdbarch);
@@ -756,8 +725,8 @@ displaced_step_prepare (ptid_t ptid)
/* Save the original contents of the copy area. */
displaced_step_saved_copy = xmalloc (len);
- old_cleanups = make_cleanup (free_current_contents,
- &displaced_step_saved_copy);
+ ignore_cleanups = make_cleanup (free_current_contents,
+ &displaced_step_saved_copy);
read_memory (copy, displaced_step_saved_copy, len);
if (debug_displaced)
{
@@ -767,7 +736,7 @@ displaced_step_prepare (ptid_t ptid)
};
closure = gdbarch_displaced_step_copy_insn (gdbarch,
- original, copy, regcache);
+ original, copy, regcache);
/* We don't support the fully-simulated case at present. */
gdb_assert (closure);
@@ -777,11 +746,13 @@ displaced_step_prepare (ptid_t ptid)
/* Resume execution at the copy. */
regcache_write_pc (regcache, copy);
- discard_cleanups (old_cleanups);
+ discard_cleanups (ignore_cleanups);
+
+ do_cleanups (old_cleanups);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n",
- paddr_nz (copy));
+ paddr_nz (copy));
/* Save the information we need to fix things up if the step
succeeds. */
@@ -808,7 +779,7 @@ write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int l
do_cleanups (ptid_cleanup);
}
-void
+static void
displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
{
struct cleanup *old_cleanups;
@@ -852,30 +823,98 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
do_cleanups (old_cleanups);
+ displaced_step_ptid = null_ptid;
+
/* Are there any pending displaced stepping requests? If so, run
one now. */
- if (displaced_step_request_queue)
+ while (displaced_step_request_queue)
{
struct displaced_step_request *head;
ptid_t ptid;
+ CORE_ADDR actual_pc;
head = displaced_step_request_queue;
ptid = head->ptid;
displaced_step_request_queue = head->next;
xfree (head);
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog,
- "displaced: stepping queued %s now\n",
- target_pid_to_str (ptid));
+ context_switch (ptid);
+
+ actual_pc = read_pc ();
+
+ if (breakpoint_here_p (actual_pc))
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: stepping queued %s now\n",
+ target_pid_to_str (ptid));
+
+ displaced_step_prepare (ptid);
+
+ if (debug_displaced)
+ {
+ gdb_byte buf[4];
+
+ fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
+ paddr_nz (actual_pc));
+ read_memory (actual_pc, buf, sizeof (buf));
+ displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
+ }
+
+ target_resume (ptid, 1, TARGET_SIGNAL_0);
+
+ /* Done, we're stepping a thread. */
+ break;
+ }
+ else
+ {
+ int step;
+ struct thread_info *tp = inferior_thread ();
+
+ /* The breakpoint we were sitting under has since been
+ removed. */
+ tp->trap_expected = 0;
+
+ /* Go back to what we were trying to do. */
+ step = currently_stepping (tp);
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "breakpoint is gone %s: step(%d)\n",
+ target_pid_to_str (tp->ptid), step);
- displaced_step_ptid = null_ptid;
- displaced_step_prepare (ptid);
- target_resume (ptid, 1, TARGET_SIGNAL_0);
+ target_resume (ptid, step, TARGET_SIGNAL_0);
+ tp->stop_signal = TARGET_SIGNAL_0;
+
+ /* This request was discarded. See if there's any other
+ thread waiting for its turn. */
+ }
}
}
+/* Update global variables holding ptids to hold NEW_PTID if they were
+ holding OLD_PTID. */
+static void
+infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
+{
+ struct displaced_step_request *it;
+
+ if (ptid_equal (inferior_ptid, old_ptid))
+ inferior_ptid = new_ptid;
+
+ if (ptid_equal (singlestep_ptid, old_ptid))
+ singlestep_ptid = new_ptid;
+
+ if (ptid_equal (displaced_step_ptid, old_ptid))
+ displaced_step_ptid = new_ptid;
+
+ if (ptid_equal (deferred_step_ptid, old_ptid))
+ deferred_step_ptid = new_ptid;
+
+ for (it = displaced_step_request_queue; it; it = it->next)
+ if (ptid_equal (it->ptid, old_ptid))
+ it->ptid = new_ptid;
+}
+
/* Resuming. */
@@ -929,16 +968,20 @@ resume (int step, enum target_signal sig)
{
int should_resume = 1;
struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
+
+ /* Note that these must be reset if we follow a fork below. */
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
+
QUIT;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: resume (step=%d, signal=%d), "
- "stepping_over_breakpoint=%d\n",
- step, sig, stepping_over_breakpoint);
+ "trap_expected=%d\n",
+ step, sig, tp->trap_expected);
/* Some targets (e.g. Solaris x86) have a kernel bug when stepping
over an instruction that causes a page fault without triggering
@@ -975,14 +1018,18 @@ a command like `return' or `jump' to continue execution."));
comments in the handle_inferior event for dealing with 'random
signals' explain what we do instead. */
if (use_displaced_stepping (gdbarch)
- && stepping_over_breakpoint
+ && tp->trap_expected
&& sig == TARGET_SIGNAL_0)
{
if (!displaced_step_prepare (inferior_ptid))
{
/* Got placed in displaced stepping queue. Will be resumed
later when all the currently queued displaced stepping
- requests finish. */
+ requests finish. The thread is not executing at this point,
+ and the call to set_executing will be made later. But we
+ need to call set_running here, since from frontend point of view,
+ the thread is running. */
+ set_running (inferior_ptid, 1);
discard_cleanups (old_cleanups);
return;
}
@@ -1012,6 +1059,13 @@ a command like `return' or `jump' to continue execution."));
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
if (follow_fork ())
should_resume = 0;
+
+ /* Following a child fork will change our notion of current
+ thread. */
+ tp = inferior_thread ();
+ regcache = get_current_regcache ();
+ gdbarch = get_regcache_arch (regcache);
+ pc = regcache_read_pc (regcache);
break;
case TARGET_WAITKIND_EXECD:
@@ -1055,7 +1109,7 @@ a command like `return' or `jump' to continue execution."));
}
if ((step || singlestep_breakpoints_inserted_p)
- && stepping_over_breakpoint)
+ && tp->trap_expected)
{
/* We're allowing a thread to run past a breakpoint it has
hit, by single-stepping the thread with the breakpoint
@@ -1095,7 +1149,7 @@ a command like `return' or `jump' to continue execution."));
if (debug_displaced
&& use_displaced_stepping (gdbarch)
- && stepping_over_breakpoint)
+ && tp->trap_expected)
{
struct regcache *resume_regcache = get_thread_regcache (resume_ptid);
CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
@@ -1107,6 +1161,10 @@ a command like `return' or `jump' to continue execution."));
displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
}
+ /* Avoid confusing the next resume, if the next stop/resume
+ happens to apply to another thread. */
+ tp->stop_signal = TARGET_SIGNAL_0;
+
target_resume (resume_ptid, step, sig);
}
@@ -1118,17 +1176,64 @@ a command like `return' or `jump' to continue execution."));
/* Clear out all variables saying what to do when inferior is continued.
First do this, then set the ones you want, then call `proceed'. */
+static void
+clear_proceed_status_thread (struct thread_info *tp)
+{
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: clear_proceed_status_thread (%s)\n",
+ target_pid_to_str (tp->ptid));
+
+ tp->trap_expected = 0;
+ tp->step_range_start = 0;
+ tp->step_range_end = 0;
+ tp->step_frame_id = null_frame_id;
+ tp->step_over_calls = STEP_OVER_UNDEBUGGABLE;
+ tp->stop_requested = 0;
+
+ tp->stop_step = 0;
+
+ tp->proceed_to_finish = 0;
+
+ /* Discard any remaining commands or status from previous stop. */
+ bpstat_clear (&tp->stop_bpstat);
+}
+
+static int
+clear_proceed_status_callback (struct thread_info *tp, void *data)
+{
+ if (is_exited (tp->ptid))
+ return 0;
+
+ clear_proceed_status_thread (tp);
+ return 0;
+}
+
void
clear_proceed_status (void)
{
- stepping_over_breakpoint = 0;
- step_range_start = 0;
- step_range_end = 0;
- step_frame_id = null_frame_id;
- step_over_calls = STEP_OVER_UNDEBUGGABLE;
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ {
+ struct inferior *inferior;
+
+ if (non_stop)
+ {
+ /* If in non-stop mode, only delete the per-thread status
+ of the current thread. */
+ clear_proceed_status_thread (inferior_thread ());
+ }
+ else
+ {
+ /* In all-stop mode, delete the per-thread status of
+ *all* threads. */
+ iterate_over_threads (clear_proceed_status_callback, NULL);
+ }
+
+ inferior = current_inferior ();
+ inferior->stop_soon = NO_STOP_QUIETLY;
+ }
+
stop_after_trap = 0;
- stop_soon = NO_STOP_QUIETLY;
- proceed_to_finish = 0;
breakpoint_proceeded = 1; /* We're about to proceed... */
if (stop_registers)
@@ -1136,9 +1241,6 @@ clear_proceed_status (void)
regcache_xfree (stop_registers);
stop_registers = NULL;
}
-
- /* Discard any remaining commands or status from previous stop. */
- bpstat_clear (&stop_bpstat);
}
/* This should be suitable for any targets that support threads. */
@@ -1184,11 +1286,6 @@ prepare_to_proceed (int step)
return 0;
}
-/* Record the pc of the program the last time it stopped. This is
- just used internally by wait_for_inferior, but need to be preserved
- over calls to it and cleared when the inferior is started. */
-static CORE_ADDR prev_pc;
-
/* Basic routine for continuing the program in various fashions.
ADDR is the address to resume at, or -1 for resume where stopped.
@@ -1206,6 +1303,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
{
struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct thread_info *tp;
CORE_ADDR pc = regcache_read_pc (regcache);
int oneproc = 0;
@@ -1214,9 +1312,9 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
if (step < 0)
stop_after_trap = 1;
- /* When GDB resume the inferior, process record target doesn't need to
- record the memory and register store operation of GDB. So set
- record_not_record to 1. */
+ /* When GDB resume the inferior, process record target doesn't need to
+ record the memory and register store operation of GDB. So set
+ record_not_record to 1. */
if (RECORD_IS_USED)
record_not_record_set ();
@@ -1273,9 +1371,12 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
oneproc = 1;
}
+ /* prepare_to_proceed may change the current thread. */
+ tp = inferior_thread ();
+
if (oneproc)
{
- stepping_over_breakpoint = 1;
+ tp->trap_expected = 1;
/* If displaced stepping is enabled, we can step over the
breakpoint without hitting it, so leave all breakpoints
inserted. Otherwise we need to disable all breakpoints, step
@@ -1288,15 +1389,40 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
/* We can insert breakpoints if we're not trying to step over one,
or if we are stepping over one but we're using displaced stepping
to do so. */
- if (! stepping_over_breakpoint || use_displaced_stepping (gdbarch))
+ if (! tp->trap_expected || use_displaced_stepping (gdbarch))
insert_breakpoints ();
+ if (!non_stop)
+ {
+ /* Pass the last stop signal to the thread we're resuming,
+ irrespective of whether the current thread is the thread that
+ got the last event or not. This was historically GDB's
+ behaviour before keeping a stop_signal per thread. */
+
+ struct thread_info *last_thread;
+ ptid_t last_ptid;
+ struct target_waitstatus last_status;
+
+ get_last_target_status (&last_ptid, &last_status);
+ if (!ptid_equal (inferior_ptid, last_ptid)
+ && !ptid_equal (last_ptid, null_ptid)
+ && !ptid_equal (last_ptid, minus_one_ptid))
+ {
+ last_thread = find_thread_pid (last_ptid);
+ if (last_thread)
+ {
+ tp->stop_signal = last_thread->stop_signal;
+ last_thread->stop_signal = TARGET_SIGNAL_0;
+ }
+ }
+ }
+
if (siggnal != TARGET_SIGNAL_DEFAULT)
- stop_signal = siggnal;
+ tp->stop_signal = siggnal;
/* If this signal should not be seen by program,
give it zero. Used for debugging signals. */
- else if (!signal_program[stop_signal])
- stop_signal = TARGET_SIGNAL_0;
+ else if (!signal_program[tp->stop_signal])
+ tp->stop_signal = TARGET_SIGNAL_0;
annotate_starting ();
@@ -1326,19 +1452,16 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
are not guaranteed the inferior is stopped and so the regcache_read_pc ()
call can fail. Setting the prev_pc value here ensures the value is
updated correctly when the inferior is stopped. */
- prev_pc = regcache_read_pc (get_current_regcache ());
+ tp->prev_pc = regcache_read_pc (get_current_regcache ());
/* Fill in with reasonable starting values. */
- init_thread_stepping_state (tss);
-
- /* We'll update this if & when we switch to a new thread. */
- previous_inferior_ptid = inferior_ptid;
+ init_thread_stepping_state (tp);
/* Reset to normal state. */
init_infwait_state ();
/* Resume inferior. */
- resume (oneproc || step || bpstat_should_step (), stop_signal);
+ resume (oneproc || step || bpstat_should_step (), tp->stop_signal);
/* Wait for it to stop (if not standalone)
and in any case decode why it stopped, and act accordingly. */
@@ -1357,9 +1480,11 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
void
start_remote (int from_tty)
{
+ struct inferior *inferior;
init_wait_for_inferior ();
- stop_soon = STOP_QUIETLY_REMOTE;
- stepping_over_breakpoint = 0;
+
+ inferior = current_inferior ();
+ inferior->stop_soon = STOP_QUIETLY_REMOTE;
/* Always go on waiting for the target, regardless of the mode. */
/* FIXME: cagney/1999-09-23: At present it isn't possible to
@@ -1391,13 +1516,9 @@ void
init_wait_for_inferior (void)
{
/* These are meaningless until the first time through wait_for_inferior. */
- prev_pc = 0;
breakpoint_init_inferior (inf_starting);
- /* Don't confuse first call to proceed(). */
- stop_signal = TARGET_SIGNAL_0;
-
/* The first resume is not following a fork/vfork/exec. */
pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */
@@ -1408,7 +1529,6 @@ init_wait_for_inferior (void)
target_last_wait_ptid = minus_one_ptid;
- init_thread_stepping_state (tss);
previous_inferior_ptid = null_ptid;
init_infwait_state ();
@@ -1455,6 +1575,10 @@ enum infwait_states infwait_state;
struct execution_control_state
{
ptid_t ptid;
+ /* The thread that got the event, if this was a thread event; NULL
+ otherwise. */
+ struct thread_info *event_thread;
+
struct target_waitstatus ws;
int random_signal;
CORE_ADDR stop_func_start;
@@ -1482,6 +1606,147 @@ static void keep_going (struct execution_control_state *ecs);
static void print_stop_reason (enum inferior_stop_reason stop_reason,
int stop_info);
+/* Callback for iterate over threads. If the thread is stopped, but
+ the user/frontend doesn't know about that yet, go through
+ normal_stop, as if the thread had just stopped now. ARG points at
+ a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If
+ ptid_is_pid(PTID) is true, applies to all threads of the process
+ pointed at by PTID. Otherwise, apply only to the thread pointed by
+ PTID. */
+
+static int
+infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
+{
+ ptid_t ptid = * (ptid_t *) arg;
+
+ if ((ptid_equal (info->ptid, ptid)
+ || ptid_equal (minus_one_ptid, ptid)
+ || (ptid_is_pid (ptid)
+ && ptid_get_pid (ptid) == ptid_get_pid (info->ptid)))
+ && is_running (info->ptid)
+ && !is_executing (info->ptid))
+ {
+ struct cleanup *old_chain;
+ struct execution_control_state ecss;
+ struct execution_control_state *ecs = &ecss;
+
+ memset (ecs, 0, sizeof (*ecs));
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ switch_to_thread (info->ptid);
+
+ /* Go through handle_inferior_event/normal_stop, so we always
+ have consistent output as if the stop event had been
+ reported. */
+ ecs->ptid = info->ptid;
+ ecs->event_thread = find_thread_pid (info->ptid);
+ ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+ ecs->ws.value.sig = TARGET_SIGNAL_0;
+
+ handle_inferior_event (ecs);
+
+ if (!ecs->wait_some_more)
+ {
+ struct thread_info *tp;
+
+ normal_stop ();
+
+ /* Finish off the continuations. The continations
+ themselves are responsible for realising the thread
+ didn't finish what it was supposed to do. */
+ tp = inferior_thread ();
+ do_all_intermediate_continuations_thread (tp);
+ do_all_continuations_thread (tp);
+ }
+
+ do_cleanups (old_chain);
+ }
+
+ return 0;
+}
+
+/* This function is attached as a "thread_stop_requested" observer.
+ Cleanup local state that assumed the PTID was to be resumed, and
+ report the stop to the frontend. */
+
+void
+infrun_thread_stop_requested (ptid_t ptid)
+{
+ struct displaced_step_request *it, *next, *prev = NULL;
+
+ /* PTID was requested to stop. Remove it from the displaced
+ stepping queue, so we don't try to resume it automatically. */
+ for (it = displaced_step_request_queue; it; it = next)
+ {
+ next = it->next;
+
+ if (ptid_equal (it->ptid, ptid)
+ || ptid_equal (minus_one_ptid, ptid)
+ || (ptid_is_pid (ptid)
+ && ptid_get_pid (ptid) == ptid_get_pid (it->ptid)))
+ {
+ if (displaced_step_request_queue == it)
+ displaced_step_request_queue = it->next;
+ else
+ prev->next = it->next;
+
+ xfree (it);
+ }
+ else
+ prev = it;
+ }
+
+ iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
+}
+
+/* Callback for iterate_over_threads. */
+
+static int
+delete_step_resume_breakpoint_callback (struct thread_info *info, void *data)
+{
+ if (is_exited (info->ptid))
+ return 0;
+
+ delete_step_resume_breakpoint (info);
+ return 0;
+}
+
+/* In all-stop, delete the step resume breakpoint of any thread that
+ had one. In non-stop, delete the step resume breakpoint of the
+ thread that just stopped. */
+
+static void
+delete_step_thread_step_resume_breakpoint (void)
+{
+ if (!target_has_execution
+ || ptid_equal (inferior_ptid, null_ptid))
+ /* If the inferior has exited, we have already deleted the step
+ resume breakpoints out of GDB's lists. */
+ return;
+
+ if (non_stop)
+ {
+ /* If in non-stop mode, only delete the step-resume or
+ longjmp-resume breakpoint of the thread that just stopped
+ stepping. */
+ struct thread_info *tp = inferior_thread ();
+ delete_step_resume_breakpoint (tp);
+ }
+ else
+ /* In all-stop mode, delete all step-resume and longjmp-resume
+ breakpoints of any thread that had them. */
+ iterate_over_threads (delete_step_resume_breakpoint_callback, NULL);
+}
+
+/* A cleanup wrapper. */
+
+static void
+delete_step_thread_step_resume_breakpoint_cleanup (void *arg)
+{
+ delete_step_thread_step_resume_breakpoint ();
+}
+
/* Wait for control to return from inferior to debugger.
If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
@@ -1506,14 +1771,17 @@ wait_for_inferior (int treat_exec_as_sigtrap)
(gdb_stdlog, "infrun: wait_for_inferior (treat_exec_as_sigtrap=%d)\n",
treat_exec_as_sigtrap);
- old_cleanups = make_cleanup (delete_step_resume_breakpoint,
- &step_resume_breakpoint);
+ old_cleanups =
+ make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
ecs = &ecss;
memset (ecs, 0, sizeof (*ecs));
overlay_cache_invalid = 1;
+ /* We'll update this if & when we switch to a new thread. */
+ previous_inferior_ptid = inferior_ptid;
+
/* 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
@@ -1542,6 +1810,7 @@ wait_for_inferior (int treat_exec_as_sigtrap)
if (!ecs->wait_some_more)
break;
}
+
do_cleanups (old_cleanups);
}
@@ -1566,6 +1835,13 @@ fetch_inferior_event (void *client_data)
overlay_cache_invalid = 1;
+ /* We can only rely on wait_for_more being correct before handling
+ the event in all-stop, but previous_inferior_ptid isn't used in
+ non-stop. */
+ if (!ecs->wait_some_more)
+ /* We'll update this if & when we switch to a new thread. */
+ previous_inferior_ptid = inferior_ptid;
+
if (non_stop)
/* In non-stop mode, the user/frontend should not notice a thread
switch due to internal events. Make sure we reverse to the
@@ -1601,10 +1877,19 @@ fetch_inferior_event (void *client_data)
if (!ecs->wait_some_more)
{
- delete_step_resume_breakpoint (&step_resume_breakpoint);
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
- normal_stop ();
- if (step_multi && stop_step)
+ delete_step_thread_step_resume_breakpoint ();
+
+ /* We may not find an inferior if this was a process exit. */
+ if (inf == NULL || inf->stop_soon == NO_STOP_QUIETLY)
+ normal_stop ();
+
+ if (target_has_execution
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+ && ecs->event_thread->step_multi
+ && ecs->event_thread->stop_step)
inferior_event_handler (INF_EXEC_CONTINUE, NULL);
else
inferior_event_handler (INF_EXEC_COMPLETE, NULL);
@@ -1631,7 +1916,7 @@ init_execution_control_state (struct execution_control_state *ecs)
/* Clear context switchable stepping state. */
void
-init_thread_stepping_state (struct thread_stepping_state *tss)
+init_thread_stepping_state (struct thread_info *tss)
{
struct symtab_and_line sal;
@@ -1640,7 +1925,7 @@ init_thread_stepping_state (struct thread_stepping_state *tss)
tss->stepping_through_solib_after_catch = 0;
tss->stepping_through_solib_catchpoints = NULL;
- sal = find_pc_line (prev_pc, 0);
+ sal = find_pc_line (tss->prev_pc, 0);
tss->current_line = sal.line;
tss->current_symtab = sal.symtab;
}
@@ -1663,17 +1948,11 @@ nullify_last_target_wait_ptid (void)
target_last_wait_ptid = minus_one_ptid;
}
-/* Switch thread contexts, maintaining "infrun state". */
+/* Switch thread contexts. */
static void
context_switch (ptid_t ptid)
{
- /* Caution: it may happen that the new thread (or the old one!)
- is not in the thread list. In this case we must not attempt
- to "switch context", or we run the risk that our context may
- be lost. This may happen as a result of the target module
- mishandling thread creation. */
-
if (debug_infrun)
{
fprintf_unfiltered (gdb_stdlog, "infrun: Switching context from %s ",
@@ -1682,72 +1961,16 @@ context_switch (ptid_t ptid)
target_pid_to_str (ptid));
}
- if (in_thread_list (inferior_ptid) && in_thread_list (ptid))
- { /* Perform infrun state context switch: */
- /* Save infrun state for the old thread. */
- save_infrun_state (inferior_ptid, prev_pc,
- stepping_over_breakpoint, step_resume_breakpoint,
- step_range_start,
- step_range_end, &step_frame_id,
- tss->stepping_over_breakpoint,
- tss->stepping_through_solib_after_catch,
- tss->stepping_through_solib_catchpoints,
- tss->current_line, tss->current_symtab,
- cmd_continuation, intermediate_continuation,
- proceed_to_finish,
- step_over_calls,
- stop_step,
- step_multi,
- stop_signal,
- stop_bpstat);
-
- /* Load infrun state for the new thread. */
- load_infrun_state (ptid, &prev_pc,
- &stepping_over_breakpoint, &step_resume_breakpoint,
- &step_range_start,
- &step_range_end, &step_frame_id,
- &tss->stepping_over_breakpoint,
- &tss->stepping_through_solib_after_catch,
- &tss->stepping_through_solib_catchpoints,
- &tss->current_line, &tss->current_symtab,
- &cmd_continuation, &intermediate_continuation,
- &proceed_to_finish,
- &step_over_calls,
- &stop_step,
- &step_multi,
- &stop_signal,
- &stop_bpstat);
- }
-
switch_to_thread (ptid);
}
-/* Context switch to thread PTID. */
-ptid_t
-context_switch_to (ptid_t ptid)
-{
- ptid_t current_ptid = inferior_ptid;
-
- /* Context switch to the new thread. */
- if (!ptid_equal (ptid, inferior_ptid))
- {
- context_switch (ptid);
- }
- return current_ptid;
-}
-
static void
adjust_pc_after_break (struct execution_control_state *ecs)
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct regcache *regcache;
+ struct gdbarch *gdbarch;
CORE_ADDR breakpoint_pc;
- /* If this target does not decrement the PC after breakpoints, then
- we have nothing to do. */
- if (gdbarch_decr_pc_after_break (gdbarch) == 0)
- return;
-
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
we aren't, just return.
@@ -1775,14 +1998,57 @@ adjust_pc_after_break (struct execution_control_state *ecs)
if (ecs->ws.value.sig != TARGET_SIGNAL_TRAP)
return;
+ /* In reverse execution, when a breakpoint is hit, the instruction
+ under it has already been de-executed. The reported PC always
+ points at the breakpoint address, so adjusting it further would
+ be wrong. E.g., consider this case on a decr_pc_after_break == 1
+ architecture:
+
+ B1 0x08000000 : INSN1
+ B2 0x08000001 : INSN2
+ 0x08000002 : INSN3
+ PC -> 0x08000003 : INSN4
+
+ Say you're stopped at 0x08000003 as above. Reverse continuing
+ from that point should hit B2 as below. Reading the PC when the
+ SIGTRAP is reported should read 0x08000001 and INSN2 should have
+ been de-executed already.
+
+ B1 0x08000000 : INSN1
+ B2 PC -> 0x08000001 : INSN2
+ 0x08000002 : INSN3
+ 0x08000003 : INSN4
+
+ We can't apply the same logic as for forward execution, because
+ we would wrongly adjust the PC to 0x08000000, since there's a
+ breakpoint at PC - 1. We'd then report a hit on B1, although
+ INSN1 hadn't been de-executed yet. Doing nothing is the correct
+ behaviour. */
+ if (execution_direction == EXEC_REVERSE)
+ return;
+
+ /* If this target does not decrement the PC after breakpoints, then
+ we have nothing to do. */
+ regcache = get_thread_regcache (ecs->ptid);
+ gdbarch = get_regcache_arch (regcache);
+ if (gdbarch_decr_pc_after_break (gdbarch) == 0)
+ return;
+
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
- gdbarch_decr_pc_after_break (gdbarch);
- /* Check whether there actually is a software breakpoint inserted
- at that location. */
- if (software_breakpoint_inserted_here_p (breakpoint_pc))
+ /* Check whether there actually is a software breakpoint inserted at
+ that location.
+
+ If in non-stop mode, a race condition is possible where we've
+ removed a breakpoint, but stop events for that breakpoint were
+ already queued and arrive later. To suppress those spurious
+ SIGTRAPs, we keep a list of such breakpoint locations for a bit,
+ and retire them after a number of stop events are reported. */
+ if (software_breakpoint_inserted_here_p (breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
{
/* When using hardware single-step, a SIGTRAP is reported for both
a completed single-step and a software breakpoint. Need to
@@ -1804,8 +2070,8 @@ adjust_pc_after_break (struct execution_control_state *ecs)
if (singlestep_breakpoints_inserted_p
|| !ptid_equal (ecs->ptid, inferior_ptid)
- || !currently_stepping (tss)
- || prev_pc == breakpoint_pc)
+ || !currently_stepping (ecs->event_thread)
+ || ecs->event_thread->prev_pc == breakpoint_pc)
regcache_write_pc (regcache, breakpoint_pc);
}
}
@@ -1842,11 +2108,18 @@ handle_inferior_event (struct execution_control_state *ecs)
int stopped_by_watchpoint;
int stepped_after_stopped_by_watchpoint = 0;
struct symtab_and_line stop_pc_sal;
+ enum stop_kind stop_soon;
- /* Reset reverse_resume_need_step to 0. */
- reverse_resume_need_step = 0;
-
- breakpoint_retire_moribund ();
+ if (ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+ && ecs->ws.kind != TARGET_WAITKIND_IGNORE)
+ {
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+ gdb_assert (inf);
+ stop_soon = inf->stop_soon;
+ }
+ else
+ stop_soon = NO_STOP_QUIETLY;
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
@@ -1855,10 +2128,6 @@ handle_inferior_event (struct execution_control_state *ecs)
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = 0;
- adjust_pc_after_break (ecs);
-
- reinit_frame_cache ();
-
/* If it's a new process, add it to the thread database */
ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
@@ -1869,15 +2138,29 @@ handle_inferior_event (struct execution_control_state *ecs)
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
+ ecs->event_thread = find_thread_pid (ecs->ptid);
+
+ /* Dependent on valid ECS->EVENT_THREAD. */
+ adjust_pc_after_break (ecs);
+
+ /* Dependent on the current PC value modified by adjust_pc_after_break. */
+ reinit_frame_cache ();
+
if (ecs->ws.kind != TARGET_WAITKIND_IGNORE)
{
- /* Mark the non-executing threads accordingly. */
- if (!non_stop
- || ecs->ws.kind == TARGET_WAITKIND_EXITED
- || ecs->ws.kind == TARGET_WAITKIND_SIGNALLED)
- set_executing (pid_to_ptid (-1), 0);
- else
- set_executing (ecs->ptid, 0);
+ breakpoint_retire_moribund ();
+
+ /* Mark the non-executing threads accordingly. In all-stop, all
+ threads of all processes are stopped when we get any event
+ reported. In non-stop mode, only the event thread stops. If
+ we're handling a process exit in non-stop mode, there's
+ nothing to do, as threads of the dead process are gone, and
+ threads of any other process were left running. */
+ if (!non_stop)
+ set_executing (minus_one_ptid, 0);
+ else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED)
+ set_executing (inferior_ptid, 0);
}
switch (infwait_state)
@@ -2001,13 +2284,14 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_EXITED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
+ inferior_ptid = ecs->ptid;
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);
/* Record the exit code in the convenience variable $_exitcode, so
that the user can inspect this again later. */
set_internalvar (lookup_internalvar ("_exitcode"),
- value_from_longest (builtin_type_int,
+ value_from_longest (builtin_type_int32,
(LONGEST) ecs->ws.value.integer));
gdb_flush (gdb_stdout);
target_mourn_inferior ();
@@ -2019,8 +2303,8 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SIGNALLED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
+ inferior_ptid = ecs->ptid;
stop_print_frame = 0;
- stop_signal = ecs->ws.value.sig;
target_terminal_ours (); /* Must do this before mourn anyway */
/* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't
@@ -2030,7 +2314,7 @@ handle_inferior_event (struct execution_control_state *ecs)
may be needed. */
target_mourn_inferior ();
- print_stop_reason (SIGNAL_EXITED, stop_signal);
+ print_stop_reason (SIGNAL_EXITED, ecs->ws.value.sig);
singlestep_breakpoints_inserted_p = 0;
stop_stepping (ecs);
return;
@@ -2041,7 +2325,6 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_VFORKED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
- stop_signal = TARGET_SIGNAL_TRAP;
pending_follow.kind = ecs->ws.kind;
pending_follow.fork_event.parent_pid = ecs->ptid;
@@ -2055,61 +2338,52 @@ handle_inferior_event (struct execution_control_state *ecs)
stop_pc = read_pc ();
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
- ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
- stop_signal = TARGET_SIGNAL_0;
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
keep_going (ecs);
return;
}
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
case TARGET_WAITKIND_EXECD:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
- stop_signal = TARGET_SIGNAL_TRAP;
-
pending_follow.execd_pathname =
savestring (ecs->ws.value.execd_pathname,
strlen (ecs->ws.value.execd_pathname));
- /* This causes the eventpoints and symbol table to be reset. Must
- do this now, before trying to determine whether to stop. */
- follow_exec (inferior_ptid, pending_follow.execd_pathname);
- xfree (pending_follow.execd_pathname);
-
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
-
- {
- /* The breakpoints module may need to touch the inferior's
- memory. Switch to the (stopped) event ptid
- momentarily. */
- ptid_t saved_inferior_ptid = inferior_ptid;
- inferior_ptid = ecs->ptid;
-
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
- ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
- inferior_ptid = saved_inferior_ptid;
- }
-
if (!ptid_equal (ecs->ptid, inferior_ptid))
{
context_switch (ecs->ptid);
reinit_frame_cache ();
}
+ stop_pc = read_pc ();
+
+ /* This causes the eventpoints and symbol table to be reset.
+ Must do this now, before trying to determine whether to
+ stop. */
+ follow_exec (inferior_ptid, pending_follow.execd_pathname);
+ xfree (pending_follow.execd_pathname);
+
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
- stop_signal = TARGET_SIGNAL_0;
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
keep_going (ecs);
return;
}
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
/* Be careful not to try to gather much state about a thread
@@ -2136,11 +2410,12 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
- stop_signal = ecs->ws.value.sig;
+ ecs->event_thread->stop_signal = ecs->ws.value.sig;
break;
case TARGET_WAITKIND_NO_HISTORY:
/* Reverse execution: target ran out of history info. */
+ stop_pc = read_pc ();
print_stop_reason (NO_HISTORY, 0);
stop_stepping (ecs);
return;
@@ -2182,10 +2457,21 @@ targets should add new threads to the thread list themselves in non-stop mode.")
return;
}
- /* Do we need to clean up the state of a thread that has completed a
- displaced single-step? (Doing so usually affects the PC, so do
- it here, before we set stop_pc.) */
- displaced_step_fixup (ecs->ptid, stop_signal);
+ if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
+ {
+ /* Do we need to clean up the state of a thread that has
+ completed a displaced single-step? (Doing so usually affects
+ the PC, so do it here, before we set stop_pc.) */
+ displaced_step_fixup (ecs->ptid, ecs->event_thread->stop_signal);
+
+ /* If we either finished a single-step or hit a breakpoint, but
+ the user wanted this thread to be stopped, pretend we got a
+ SIG0 (generic unsignaled stop). */
+
+ if (ecs->event_thread->stop_requested
+ && ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ }
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
@@ -2219,7 +2505,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
/* We've either finished single-stepping past the single-step
breakpoint, or stopped for some other reason. It would be nice if
we could tell, but we can't reliably. */
- if (stop_signal == TARGET_SIGNAL_TRAP)
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepping_past_singlestep_breakpoint\n");
@@ -2239,8 +2525,6 @@ targets should add new threads to the thread list themselves in non-stop mode.")
}
}
- stepping_past_singlestep_breakpoint = 0;
-
if (!ptid_equal (deferred_step_ptid, null_ptid))
{
/* In non-stop mode, there's never a deferred_step_ptid set. */
@@ -2248,7 +2532,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
/* If we stopped for some other reason than single-stepping, ignore
the fact that we were supposed to switch back. */
- if (stop_signal == TARGET_SIGNAL_TRAP)
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -2280,7 +2564,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
another thread. If so, then step that thread past the breakpoint,
and continue it. */
- if (stop_signal == TARGET_SIGNAL_TRAP)
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
@@ -2334,6 +2618,8 @@ targets should add new threads to the thread list themselves in non-stop mode.")
if (new_singlestep_pc != singlestep_pc)
{
+ enum target_signal stop_signal;
+
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: unexpected thread,"
" but expected thread advanced also\n");
@@ -2342,7 +2628,11 @@ targets should add new threads to the thread list themselves in non-stop mode.")
singlestep_ptid. Don't swap here, since that's
the context we want to use. Just fudge our
state and continue. */
+ stop_signal = ecs->event_thread->stop_signal;
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
ecs->ptid = singlestep_ptid;
+ ecs->event_thread = find_thread_pid (ecs->ptid);
+ ecs->event_thread->stop_signal = stop_signal;
stop_pc = new_singlestep_pc;
}
else
@@ -2402,7 +2692,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
infwait_state = infwait_thread_hop_state;
}
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
registers_changed ();
return;
@@ -2491,17 +2781,17 @@ targets should add new threads to the thread list themselves in non-stop mode.")
&ecs->stop_func_start, &ecs->stop_func_end);
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (current_gdbarch);
- tss->stepping_over_breakpoint = 0;
- bpstat_clear (&stop_bpstat);
- stop_step = 0;
+ ecs->event_thread->stepping_over_breakpoint = 0;
+ bpstat_clear (&ecs->event_thread->stop_bpstat);
+ ecs->event_thread->stop_step = 0;
stop_print_frame = 1;
ecs->random_signal = 0;
stopped_by_random_signal = 0;
- if (stop_signal == TARGET_SIGNAL_TRAP
- && stepping_over_breakpoint
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ && ecs->event_thread->trap_expected
&& gdbarch_single_step_through_delay_p (current_gdbarch)
- && currently_stepping (tss))
+ && currently_stepping (ecs->event_thread))
{
/* We're trying to step off a breakpoint. Turns out that we're
also on an instruction that needs to be stepped multiple
@@ -2513,11 +2803,11 @@ targets should add new threads to the thread list themselves in non-stop mode.")
get_current_frame ());
if (debug_infrun && step_through_delay)
fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
- if (step_range_end == 0 && step_through_delay)
+ if (ecs->event_thread->step_range_end == 0 && step_through_delay)
{
/* The user issued a continue when stopped at a breakpoint.
Set up for another trap and get out of here. */
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@@ -2529,7 +2819,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
case, don't decide that here, just set
ecs->stepping_over_breakpoint, making sure we
single-step again before breakpoints are re-inserted. */
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
}
}
@@ -2537,7 +2827,7 @@ targets should add new threads to the thread list themselves in non-stop mode.")
The alternatives are:
1) stop_stepping and return; to really stop and return to the debugger,
2) keep_going and return to start up again
- (set tss->stepping_over_breakpoint to 1 to single step once)
+ (set ecs->event_thread->stepping_over_breakpoint to 1 to single step once)
3) set ecs->random_signal to 1, and the decision between 1 and 2
will be made according to the signal handling tables. */
@@ -2555,16 +2845,16 @@ targets should add new threads to the thread list themselves in non-stop mode.")
If we're doing a displaced step past a breakpoint, then the
breakpoint is always inserted at the original instruction;
non-standard signals can't be explained by the breakpoint. */
- if (stop_signal == TARGET_SIGNAL_TRAP
- || (! stepping_over_breakpoint
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ || (! ecs->event_thread->trap_expected
&& breakpoint_inserted_here_p (stop_pc)
- && (stop_signal == TARGET_SIGNAL_ILL
- || stop_signal == TARGET_SIGNAL_SEGV
- || stop_signal == TARGET_SIGNAL_EMT))
+ && (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
|| stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
|| stop_soon == STOP_QUIETLY_REMOTE)
{
- if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
@@ -2594,18 +2884,27 @@ targets should add new threads to the thread list themselves in non-stop mode.")
SIGTRAP. Some systems (e.g. Windows), and stubs supporting
target extended-remote report it instead of a SIGSTOP
(e.g. gdbserver). We already rely on SIGTRAP being our
- signal, so this is no exception. */
+ signal, so this is no exception.
+
+ Also consider that the attach is complete when we see a
+ TARGET_SIGNAL_0. In non-stop mode, GDB will explicitly tell
+ the target to stop all threads of the inferior, in case the
+ low level attach operation doesn't stop them implicitly. If
+ they weren't stopped implicitly, then the stub will report a
+ TARGET_SIGNAL_0, meaning: stopped for no particular reason
+ other than GDB's request. */
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
- && (stop_signal == TARGET_SIGNAL_STOP
- || stop_signal == TARGET_SIGNAL_TRAP))
+ && (ecs->event_thread->stop_signal == TARGET_SIGNAL_STOP
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_0))
{
stop_stepping (ecs);
- stop_signal = TARGET_SIGNAL_0;
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
return;
}
/* See if there is a breakpoint at the current PC. */
- stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
/* Following in case break condition called a
function. */
@@ -2631,24 +2930,17 @@ targets should add new threads to the thread list themselves in non-stop mode.")
be necessary for call dummies on a non-executable stack on
SPARC. */
- /* When execution direction is reverse or process record target is used,
- maybe GDB will set next resume to step. Then the next step will be
- set to random signal. It will make GDB stop the inferior. So
- When execution direction is reverse or record target is used, not set
- the random signal. */
-
- if (stop_signal == TARGET_SIGNAL_TRAP)
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
ecs->random_signal
- = !(bpstat_explains_signal (stop_bpstat)
- || stepping_over_breakpoint
- || (step_range_end && step_resume_breakpoint == NULL)
- || (execution_direction == EXEC_REVERSE)
- || RECORD_IS_USED);
+ = !(bpstat_explains_signal (ecs->event_thread->stop_bpstat)
+ || ecs->event_thread->trap_expected
+ || (ecs->event_thread->step_range_end
+ && ecs->event_thread->step_resume_breakpoint == NULL));
else
{
- ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
if (!ecs->random_signal)
- stop_signal = TARGET_SIGNAL_TRAP;
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
}
}
@@ -2669,17 +2961,23 @@ process_event_stop_test:
int printed = 0;
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n", stop_signal);
+ fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n",
+ ecs->event_thread->stop_signal);
stopped_by_random_signal = 1;
- if (signal_print[stop_signal])
+ if (signal_print[ecs->event_thread->stop_signal])
{
printed = 1;
target_terminal_ours_for_output ();
- print_stop_reason (SIGNAL_RECEIVED, stop_signal);
+ print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
}
- if (signal_stop_state (stop_signal))
+ /* Always stop on signals if we're either just gaining control
+ of the program, or the user explicitly requested this thread
+ to remain stopped. */
+ if (stop_soon != NO_STOP_QUIETLY
+ || ecs->event_thread->stop_requested
+ || signal_stop_state (ecs->event_thread->stop_signal))
{
stop_stepping (ecs);
return;
@@ -2690,12 +2988,12 @@ process_event_stop_test:
target_terminal_inferior ();
/* Clear the signal if it should not be passed. */
- if (signal_program[stop_signal] == 0)
- stop_signal = TARGET_SIGNAL_0;
+ if (signal_program[ecs->event_thread->stop_signal] == 0)
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
- if (prev_pc == read_pc ()
- && stepping_over_breakpoint
- && step_resume_breakpoint == NULL)
+ if (ecs->event_thread->prev_pc == read_pc ()
+ && ecs->event_thread->trap_expected
+ && ecs->event_thread->step_resume_breakpoint == NULL)
{
/* We were just starting a new sequence, attempting to
single-step off of a breakpoint and expecting a SIGTRAP.
@@ -2713,17 +3011,18 @@ process_event_stop_test:
"breakpoint\n");
insert_step_resume_breakpoint_at_frame (get_current_frame ());
- tss->step_after_step_resume_breakpoint = 1;
+ ecs->event_thread->step_after_step_resume_breakpoint = 1;
keep_going (ecs);
return;
}
- if (step_range_end != 0
- && stop_signal != TARGET_SIGNAL_0
- && stop_pc >= step_range_start && stop_pc < step_range_end
+ if (ecs->event_thread->step_range_end != 0
+ && ecs->event_thread->stop_signal != TARGET_SIGNAL_0
+ && (ecs->event_thread->step_range_start <= stop_pc
+ && stop_pc < ecs->event_thread->step_range_end)
&& frame_id_eq (get_frame_id (get_current_frame ()),
- step_frame_id)
- && step_resume_breakpoint == NULL)
+ ecs->event_thread->step_frame_id)
+ && ecs->event_thread->step_resume_breakpoint == NULL)
{
/* The inferior is about to take a signal that will take it
out of the single step range. Set a breakpoint at the
@@ -2759,7 +3058,7 @@ process_event_stop_test:
CORE_ADDR jmp_buf_pc;
struct bpstat_what what;
- what = bpstat_what (stop_bpstat);
+ what = bpstat_what (ecs->event_thread->stop_bpstat);
if (what.call_dummy)
{
@@ -2777,7 +3076,7 @@ process_event_stop_test:
fprintf_unfiltered (gdb_stdlog,
"infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
if (!gdbarch_get_longjmp_target_p (current_gdbarch)
|| !gdbarch_get_longjmp_target (current_gdbarch,
@@ -2792,8 +3091,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* We're going to replace the current step-resume breakpoint
with a longjmp-resume breakpoint. */
- if (step_resume_breakpoint != NULL)
- delete_step_resume_breakpoint (&step_resume_breakpoint);
+ delete_step_resume_breakpoint (ecs->event_thread);
/* Insert a breakpoint at resume address. */
insert_longjmp_resume_breakpoint (jmp_buf_pc);
@@ -2806,10 +3104,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog,
"infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
- gdb_assert (step_resume_breakpoint != NULL);
- delete_step_resume_breakpoint (&step_resume_breakpoint);
+ gdb_assert (ecs->event_thread->step_resume_breakpoint != NULL);
+ delete_step_resume_breakpoint (ecs->event_thread);
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
@@ -2817,7 +3115,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
case BPSTAT_WHAT_SINGLE:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n");
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
/* Still need to check other stuff, at least the case
where we are stepping and step out of the right range. */
break;
@@ -2845,39 +3143,17 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
case BPSTAT_WHAT_STEP_RESUME:
- /* This proably demands a more elegant solution, but, yeah
- right...
-
- This function's use of the simple variable
- step_resume_breakpoint doesn't seem to accomodate
- simultaneously active step-resume bp's, although the
- breakpoint list certainly can.
-
- If we reach here and step_resume_breakpoint is already
- NULL, then apparently we have multiple active
- step-resume bp's. We'll just delete the breakpoint we
- stopped at, and carry on.
-
- Correction: what the code currently does is delete a
- step-resume bp, but it makes no effort to ensure that
- the one deleted is the one currently stopped at. MVS */
-
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
- if (step_resume_breakpoint == NULL)
- {
- step_resume_breakpoint =
- bpstat_find_step_resume_breakpoint (stop_bpstat);
- }
- delete_step_resume_breakpoint (&step_resume_breakpoint);
- if (tss->step_after_step_resume_breakpoint)
+ delete_step_resume_breakpoint (ecs->event_thread);
+ if (ecs->event_thread->step_after_step_resume_breakpoint)
{
/* Back when the step-resume breakpoint was inserted, we
were trying to single-step off a breakpoint. Go back
to doing that. */
- tss->step_after_step_resume_breakpoint = 0;
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->step_after_step_resume_breakpoint = 0;
+ ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@@ -2888,14 +3164,13 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
just hit the step-resume breakpoint at the start
address of the function. Go back to single-stepping,
which should take us back to the function call. */
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
break;
case BPSTAT_WHAT_CHECK_SHLIBS:
- case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK:
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n");
@@ -2936,46 +3211,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
stop_stepping (ecs);
return;
}
-
- /* If we stopped due to an explicit catchpoint, then the
- (see above) call to SOLIB_ADD pulled in any symbols
- from a newly-loaded library, if appropriate.
-
- We do want the inferior to stop, but not where it is
- now, which is in the dynamic linker callback. Rather,
- we would like it stop in the user's program, just after
- the call that caused this catchpoint to trigger. That
- gives the user a more useful vantage from which to
- examine their program's state. */
- else if (what.main_action
- == BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK)
- {
- /* ??rehrauer: If I could figure out how to get the
- right return PC from here, we could just set a temp
- breakpoint and resume. I'm not sure we can without
- cracking open the dld's shared libraries and sniffing
- their unwind tables and text/data ranges, and that's
- not a terribly portable notion.
-
- Until that time, we must step the inferior out of the
- dld callback, and also out of the dld itself (and any
- code or stubs in libdld.sl, such as "shl_load" and
- friends) until we reach non-dld code. At that point,
- we can stop stepping. */
- bpstat_get_triggered_catchpoints (stop_bpstat,
- &tss->
- stepping_through_solib_catchpoints);
- tss->stepping_through_solib_after_catch = 1;
-
- /* Be sure to lift all breakpoints, so the inferior does
- actually step past this point... */
- tss->stepping_over_breakpoint = 1;
- break;
- }
else
{
/* We want to step over this breakpoint, then keep going. */
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
break;
}
}
@@ -2995,10 +3234,47 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
test for stepping. But, if not stepping,
do not stop. */
+ /* In all-stop mode, if we're currently stepping but have stopped in
+ some other thread, we need to switch back to the stepped thread. */
+ if (!non_stop)
+ {
+ struct thread_info *tp;
+ tp = iterate_over_threads (currently_stepping_callback,
+ ecs->event_thread);
+ if (tp)
+ {
+ /* However, if the current thread is blocked on some internal
+ breakpoint, and we simply need to step over that breakpoint
+ to get it going again, do that first. */
+ if ((ecs->event_thread->trap_expected
+ && ecs->event_thread->stop_signal != TARGET_SIGNAL_TRAP)
+ || ecs->event_thread->stepping_over_breakpoint)
+ {
+ keep_going (ecs);
+ return;
+ }
+
+ /* Otherwise, we no longer expect a trap in the current thread.
+ Clear the trap_expected flag before switching back -- this is
+ what keep_going would do as well, if we called it. */
+ ecs->event_thread->trap_expected = 0;
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: switching back to stepped thread\n");
+
+ ecs->event_thread = tp;
+ ecs->ptid = tp->ptid;
+ context_switch (ecs->ptid);
+ keep_going (ecs);
+ return;
+ }
+ }
+
/* Are we stepping to get the inferior out of the dynamic linker's
hook (and possibly the dld itself) after catching a shlib
event? */
- if (tss->stepping_through_solib_after_catch)
+ if (ecs->event_thread->stepping_through_solib_after_catch)
{
#if defined(SOLIB_ADD)
/* Have we reached our destination? If not, keep going. */
@@ -3006,7 +3282,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepping in dynamic linker\n");
- tss->stepping_over_breakpoint = 1;
+ ecs->event_thread->stepping_over_breakpoint = 1;
keep_going (ecs);
return;
}
@@ -3015,16 +3291,17 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
fprintf_unfiltered (gdb_stdlog, "infrun: step past dynamic linker\n");
/* Else, stop and report the catchpoint(s) whose triggering
caused us to begin stepping. */
- tss->stepping_through_solib_after_catch = 0;
- bpstat_clear (&stop_bpstat);
- stop_bpstat = bpstat_copy (tss->stepping_through_solib_catchpoints);
- bpstat_clear (&tss->stepping_through_solib_catchpoints);
+ ecs->event_thread->stepping_through_solib_after_catch = 0;
+ bpstat_clear (&ecs->event_thread->stop_bpstat);
+ ecs->event_thread->stop_bpstat
+ = bpstat_copy (ecs->event_thread->stepping_through_solib_catchpoints);
+ bpstat_clear (&ecs->event_thread->stepping_through_solib_catchpoints);
stop_print_frame = 1;
stop_stepping (ecs);
return;
}
- if (step_resume_breakpoint)
+ if (ecs->event_thread->step_resume_breakpoint)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -3037,7 +3314,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
}
- if (step_range_end == 0)
+ if (ecs->event_thread->step_range_end == 0)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no stepping, continue\n");
@@ -3051,21 +3328,22 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
Note that step_range_end is the address of the first instruction
beyond the step range, and NOT the address of the last instruction
within it! */
- if (stop_pc >= step_range_start && stop_pc < step_range_end)
+ if (stop_pc >= ecs->event_thread->step_range_start
+ && stop_pc < ecs->event_thread->step_range_end)
{
if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
- paddr_nz (step_range_start),
- paddr_nz (step_range_end));
+ fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
+ paddr_nz (ecs->event_thread->step_range_start),
+ paddr_nz (ecs->event_thread->step_range_end));
/* When stepping backward, stop at beginning of line range
(unless it's the function entry point, in which case
keep going back to the call point). */
- if (stop_pc == step_range_start
+ if (stop_pc == ecs->event_thread->step_range_start
&& stop_pc != ecs->stop_func_start
&& execution_direction == EXEC_REVERSE)
{
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
}
@@ -3081,13 +3359,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
loader dynamic symbol resolution code, we keep on single stepping
until we exit the run time loader code and reach the callee's
address. */
- if (step_over_calls == STEP_OVER_UNDEBUGGABLE
-#ifdef IN_SOLIB_DYNSYM_RESOLVE_CODE
- && IN_SOLIB_DYNSYM_RESOLVE_CODE (stop_pc)
-#else
- && in_solib_dynsym_resolve_code (stop_pc)
-#endif
- )
+ if (ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
+ && in_solib_dynsym_resolve_code (stop_pc))
{
CORE_ADDR pc_after_resolver =
gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
@@ -3110,9 +3383,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
return;
}
- if (step_range_end != 1
- && (step_over_calls == STEP_OVER_UNDEBUGGABLE
- || step_over_calls == STEP_OVER_ALL)
+ if (ecs->event_thread->step_range_end != 1
+ && (ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
+ || ecs->event_thread->step_over_calls == STEP_OVER_ALL)
&& get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME)
{
if (debug_infrun)
@@ -3134,17 +3407,21 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
NOTE: frame_id_eq will never report two invalid frame IDs as
being equal, so to get into this block, both the current and
previous frame must have valid frame IDs. */
- if (!frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)
- && frame_id_eq (frame_unwind_id (get_current_frame ()), step_frame_id))
+ if (!frame_id_eq (get_frame_id (get_current_frame ()),
+ ecs->event_thread->step_frame_id)
+ && (frame_id_eq (frame_unwind_id (get_current_frame ()),
+ ecs->event_thread->step_frame_id)
+ || execution_direction == EXEC_REVERSE))
{
CORE_ADDR real_stop_pc;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
- if ((step_over_calls == STEP_OVER_NONE)
- || ((step_range_end == 1)
- && in_prologue (prev_pc, ecs->stop_func_start)))
+ if ((ecs->event_thread->step_over_calls == STEP_OVER_NONE)
+ || ((ecs->event_thread->step_range_end == 1)
+ && in_prologue (ecs->event_thread->prev_pc,
+ ecs->stop_func_start)))
{
/* I presume that step_over_calls is only 0 when we're
supposed to be stepping at the assembly language level
@@ -3152,13 +3429,13 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* Also, maybe we just did a "nexti" inside a prolog, so we
thought it was a subroutine call but it was not. Stop as
well. FENN */
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
}
- if (step_over_calls == STEP_OVER_ALL)
+ if (ecs->event_thread->step_over_calls == STEP_OVER_ALL)
{
/* We're doing a "next".
@@ -3169,32 +3446,30 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
Reverse (backward) execution. set the step-resume
breakpoint at the start of the function that we just
stepped into (backwards), and continue to there. When we
- get there, we'll need to single-step back to the
- caller. */
+ get there, we'll need to single-step back to the caller. */
if (execution_direction == EXEC_REVERSE)
{
- if (ecs->stop_func_start == 0)
- {
- reverse_resume_need_step = 1;
- }
- else
- {
- struct symtab_and_line sr_sal;
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+ struct symtab_and_line sr_sal;
+
+ if (ecs->stop_func_start == 0
+ && in_solib_dynsym_resolve_code (stop_pc))
+ {
+ /* Stepped into runtime loader dynamic symbol
+ resolution code. Since we're in reverse,
+ we have already backed up through the runtime
+ loader and the dynamic function. This is just
+ the trampoline (jump table).
+
+ Just keep stepping, we'll soon be home.
+ */
+ keep_going (ecs);
+ return;
}
- }
- /* If process record target is recording and real running target
- doesn't support record wait, Record target need execute single
- instruction for each step to call funtion "record_message" for
- each instruction. So set "reverse_resume_need_step" to execute
- single step. */
- else if (RECORD_IS_USED && !RECORD_IS_REPLAY
- && !RECORD_TARGET_SUPPORT_RECORD_WAIT)
- {
- reverse_resume_need_step = 1;
+ /* Normal (staticly linked) function call return. */
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
}
else
insert_step_resume_breakpoint_at_caller (get_current_frame ());
@@ -3215,13 +3490,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
if (real_stop_pc != 0)
ecs->stop_func_start = real_stop_pc;
- if (
-#ifdef IN_SOLIB_DYNSYM_RESOLVE_CODE
- IN_SOLIB_DYNSYM_RESOLVE_CODE (ecs->stop_func_start)
-#else
- in_solib_dynsym_resolve_code (ecs->stop_func_start)
-#endif
-)
+ if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
{
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
@@ -3255,9 +3524,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* If we have no line number and the step-stop-if-no-debug is
set, we stop the step so that the user has a chance to switch
in assembly mode. */
- if (step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug)
+ if (ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
+ && step_stop_if_no_debug)
{
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
@@ -3267,27 +3537,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
{
/* Set a breakpoint at callee's start address.
From there we can step once and be back in the caller. */
- /* FIXME: I'm not sure we've handled the frame for recursion. */
- if (ecs->stop_func_start == 0)
- {
- reverse_resume_need_step = 1;
- }
- else
- {
- struct symtab_and_line sr_sal;
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
- }
+ struct symtab_and_line sr_sal;
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
}
- /* If process record target is recording and real running target doesn't
- support record wait, process record target need execute single
- instruction for each step to call funtion "record_message" for each
- instruction. So set "reverse_resume_need_step" to execute single
- step. */
- else if (RECORD_IS_USED && !RECORD_IS_REPLAY
- && !RECORD_TARGET_SUPPORT_RECORD_WAIT)
- reverse_resume_need_step = 1;
else
/* Set a breakpoint at callee's return address (the address
at which the caller will resume). */
@@ -3337,26 +3591,13 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* NOTE: tausq/2004-05-24: This if block used to be done before all
the trampoline processing logic, however, there are some trampolines
that have no names, so we should do trampoline handling first. */
- if (step_over_calls == STEP_OVER_UNDEBUGGABLE
+ if (ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
&& ecs->stop_func_name == NULL
&& stop_pc_sal.line == 0)
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped into undebuggable function\n");
- /* If process record target is recording and real running target doesn't
- support record wait, process record target need execute single
- instruction for each step to call funtion "record_message" for each
- instruction. So set "reverse_resume_need_step" to execute single
- step. */
- if (RECORD_IS_USED && !RECORD_IS_REPLAY
- && !RECORD_TARGET_SUPPORT_RECORD_WAIT)
- {
- reverse_resume_need_step = 1;
- keep_going (ecs);
- return;
- }
-
/* The inferior just stepped into, or returned to, an
undebuggable function (where there is no debugging information
and no line number corresponding to the address where the
@@ -3371,7 +3612,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* If we have no line number and the step-stop-if-no-debug
is set, we stop the step so that the user has a chance to
switch in assembly mode. */
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
@@ -3386,13 +3627,13 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
}
}
- if (step_range_end == 1)
+ if (ecs->event_thread->step_range_end == 1)
{
/* It is stepi or nexti. We always want to stop stepping after
one instruction. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
@@ -3406,110 +3647,15 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
or can this happen as a result of a return or longjmp?). */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
-
- if (execution_direction == EXEC_REVERSE)
- {
- /* Set a breakpoint at callee's start address.
- From there we can step once and be back in the caller. */
- /* FIXME: I'm not sure we've handled the frame for recursion. */
- if (ecs->stop_func_start == 0)
- {
- reverse_resume_need_step = 1;
- }
- else
- {
- struct symtab_and_line sr_sal;
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
- }
- keep_going (ecs);
- return;
- }
-
- /* If process record target is recording and real running target doesn't
- support record wait, process record target need execute single
- instruction for each step to call funtion "record_message" for each
- instruction. So set "reverse_resume_need_step" to execute single
- step. */
- if (RECORD_IS_USED && !RECORD_IS_REPLAY
- && !RECORD_TARGET_SUPPORT_RECORD_WAIT)
- {
- reverse_resume_need_step = 1;
- keep_going (ecs);
- return;
- }
-
- stop_step = 1;
- print_stop_reason (END_STEPPING_RANGE, 0);
- stop_stepping (ecs);
- return;
- }
-
- if (execution_direction == EXEC_REVERSE
- && frame_id_eq (get_frame_id (get_current_frame ()),
- step_prev_frame_id))
- {
- if (debug_infrun)
- {
- fprintf_unfiltered (gdb_stdlog,
- "infrun: return to the prev function\n");
- }
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
}
- if (!frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)
- && (execution_direction == EXEC_REVERSE
- || RECORD_IS_USED))
- {
- if (stop_pc != stop_pc_sal.pc
- && execution_direction == EXEC_REVERSE
- && step_over_calls == STEP_OVER_ALL)
- {
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: maybe stepped into subroutine\n");
- if (ecs->stop_func_start == 0)
- {
- reverse_resume_need_step = 1;
- }
- else
- {
- struct symtab_and_line sr_sal;
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
- }
- keep_going (ecs);
- return;
- }
- }
-#if 0
- if (((stop_pc == stop_pc_sal.pc
- && execution_direction != EXEC_REVERSE)
- || (stop_pc >= stop_pc_sal.pc && stop_pc < stop_pc_sal.end
- && execution_direction == EXEC_REVERSE))
- && (tss->current_line != stop_pc_sal.line
- || tss->current_symtab != stop_pc_sal.symtab))
- {
- /* We are at the start of a different line. So stop. Note that
- we don't stop if we step into the middle of a different line.
- That is said to make things like for (;;) statements work
- better. */
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n");
- stop_step = 1;
- print_stop_reason (END_STEPPING_RANGE, 0);
- stop_stepping (ecs);
- return;
- }
-#else
if ((stop_pc == stop_pc_sal.pc)
- && (tss->current_line != stop_pc_sal.line
- || tss->current_symtab != stop_pc_sal.symtab))
+ && (ecs->event_thread->current_line != stop_pc_sal.line
+ || ecs->event_thread->current_symtab != stop_pc_sal.symtab))
{
/* We are at the start of a different line. So stop. Note that
we don't stop if we step into the middle of a different line.
@@ -3517,12 +3663,12 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
better. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n");
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
}
-#endif
+
/* We aren't done stepping.
Optimize by setting the stepping range to the line.
@@ -3530,38 +3676,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
new line in mid-statement, we continue stepping. This makes
things like for(;;) statements work better.) */
- step_range_start = stop_pc_sal.pc;
- step_range_end = stop_pc_sal.end;
- step_frame_id = get_frame_id (get_current_frame ());
- tss->current_line = stop_pc_sal.line;
- tss->current_symtab = stop_pc_sal.symtab;
-
- /* In the case where we just stepped out of a function into the
- middle of a line of the caller, continue stepping, but
- step_frame_id must be modified to current frame */
-#if 0
- /* NOTE: cagney/2003-10-16: I think this frame ID inner test is too
- generous. It will trigger on things like a step into a frameless
- stackless leaf function. I think the logic should instead look
- at the unwound frame ID has that should give a more robust
- indication of what happened. */
- if (step - ID == current - ID)
- still stepping in same function;
- else if (step - ID == unwind (current - ID))
- stepped into a function;
- else
- stepped out of a function;
- /* Of course this assumes that the frame ID unwind code is robust
- and we're willing to introduce frame unwind logic into this
- function. Fortunately, those days are nearly upon us. */
-#endif
- {
- struct frame_info *frame = get_current_frame ();
- struct frame_id current_frame = get_frame_id (frame);
- if (!(frame_id_inner (get_frame_arch (frame), current_frame,
- step_frame_id)))
- step_frame_id = current_frame;
- }
+ ecs->event_thread->step_range_start = stop_pc_sal.pc;
+ ecs->event_thread->step_range_end = stop_pc_sal.end;
+ ecs->event_thread->step_frame_id = get_frame_id (get_current_frame ());
+ ecs->event_thread->current_line = stop_pc_sal.line;
+ ecs->event_thread->current_symtab = stop_pc_sal.symtab;
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
@@ -3571,20 +3690,32 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
/* Are we in the middle of stepping? */
static int
-currently_stepping (struct thread_stepping_state *tss)
+currently_stepping_thread (struct thread_info *tp)
+{
+ return (tp->step_range_end && tp->step_resume_breakpoint == NULL)
+ || tp->trap_expected
+ || tp->stepping_through_solib_after_catch;
+}
+
+static int
+currently_stepping_callback (struct thread_info *tp, void *data)
{
- return (((step_range_end && step_resume_breakpoint == NULL)
- || stepping_over_breakpoint)
- || tss->stepping_through_solib_after_catch
- || bpstat_should_step ()
- || reverse_resume_need_step);
+ /* Return true if any thread *but* the one passed in "data" is
+ in the middle of stepping. */
+ return tp != data && currently_stepping_thread (tp);
+}
+
+static int
+currently_stepping (struct thread_info *tp)
+{
+ return currently_stepping_thread (tp) || bpstat_should_step ();
}
/* Inferior has stepped into a subroutine call with source code that
we should not step over. Do step to the first line of code in
it. */
-
- static void
+
+static void
handle_step_into_function (struct execution_control_state *ecs)
{
struct symtab *s;
@@ -3633,7 +3764,7 @@ handle_step_into_function (struct execution_control_state *ecs)
if (ecs->stop_func_start == stop_pc)
{
/* We are already there: stop now. */
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
@@ -3651,7 +3782,7 @@ handle_step_into_function (struct execution_control_state *ecs)
insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
/* And make sure stepping stops right away then. */
- step_range_end = step_range_start;
+ ecs->event_thread->step_range_end = ecs->event_thread->step_range_start;
}
keep_going (ecs);
}
@@ -3677,7 +3808,7 @@ handle_step_into_function_backward (struct execution_control_state *ecs)
if (stop_func_sal.pc == stop_pc)
{
/* We're there already. Just stop stepping now. */
- stop_step = 1;
+ ecs->event_thread->stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
}
@@ -3686,8 +3817,8 @@ handle_step_into_function_backward (struct execution_control_state *ecs)
/* Else just reset the step range and keep going.
No step-resume breakpoint, they don't work for
epilogues, which can have multiple entry paths. */
- step_range_start = stop_func_sal.pc;
- step_range_end = stop_func_sal.end;
+ ecs->event_thread->step_range_start = stop_func_sal.pc;
+ ecs->event_thread->step_range_end = stop_func_sal.end;
keep_going (ecs);
}
return;
@@ -3703,15 +3834,15 @@ insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal,
/* There should never be more than one step-resume or longjmp-resume
breakpoint per thread, so we should never be setting a new
step_resume_breakpoint when one is already active. */
- gdb_assert (step_resume_breakpoint == NULL);
+ gdb_assert (inferior_thread ()->step_resume_breakpoint == NULL);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: inserting step-resume breakpoint at 0x%s\n",
paddr_nz (sr_sal.pc));
- step_resume_breakpoint = set_momentary_breakpoint (sr_sal, sr_id,
- bp_step_resume);
+ inferior_thread ()->step_resume_breakpoint
+ = set_momentary_breakpoint (sr_sal, sr_id, bp_step_resume);
}
/* Insert a "step-resume breakpoint" at RETURN_FRAME.pc. This is used
@@ -3780,14 +3911,14 @@ insert_longjmp_resume_breakpoint (CORE_ADDR pc)
/* There should never be more than one step-resume or longjmp-resume
breakpoint per thread, so we should never be setting a new
longjmp_resume_breakpoint when one is already active. */
- gdb_assert (step_resume_breakpoint == NULL);
+ gdb_assert (inferior_thread ()->step_resume_breakpoint == NULL);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
"infrun: inserting longjmp-resume breakpoint at 0x%s\n",
paddr_nz (pc));
- step_resume_breakpoint =
+ inferior_thread ()->step_resume_breakpoint =
set_momentary_breakpoint_at_pc (pc, bp_longjmp_resume);
}
@@ -3809,17 +3940,19 @@ static void
keep_going (struct execution_control_state *ecs)
{
/* Save the pc before execution, to compare with pc after stop. */
- prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
+ ecs->event_thread->prev_pc = read_pc (); /* Might have been DECR_AFTER_BREAK */
/* If we did not do break;, it means we should keep running the
inferior and not return to debugger. */
- if (stepping_over_breakpoint && stop_signal != TARGET_SIGNAL_TRAP)
+ if (ecs->event_thread->trap_expected
+ && ecs->event_thread->stop_signal != TARGET_SIGNAL_TRAP)
{
/* We took a signal (which we are supposed to pass through to
- the inferior, else we'd have done a break above) and we
- haven't yet gotten our trap. Simply continue. */
- resume (currently_stepping (tss), stop_signal);
+ the inferior, else we'd not get here) and we haven't yet
+ gotten our trap. Simply continue. */
+ resume (currently_stepping (ecs->event_thread),
+ ecs->event_thread->stop_signal);
}
else
{
@@ -3836,7 +3969,7 @@ keep_going (struct execution_control_state *ecs)
already inserted breakpoints. Therefore, we don't
care if breakpoints were already inserted, or not. */
- if (tss->stepping_over_breakpoint)
+ if (ecs->event_thread->stepping_over_breakpoint)
{
if (! use_displaced_stepping (current_gdbarch))
/* Since we can't do a displaced step, we have to remove
@@ -3860,7 +3993,7 @@ keep_going (struct execution_control_state *ecs)
}
}
- stepping_over_breakpoint = tss->stepping_over_breakpoint;
+ ecs->event_thread->trap_expected = ecs->event_thread->stepping_over_breakpoint;
/* Do not deliver SIGNAL_TRAP (except when the user explicitly
specifies that such a signal should be delivered to the
@@ -3874,11 +4007,12 @@ keep_going (struct execution_control_state *ecs)
simulator; the simulator then delivers the hardware
equivalent of a SIGNAL_TRAP to the program being debugged. */
- if (stop_signal == TARGET_SIGNAL_TRAP && !signal_program[stop_signal])
- stop_signal = TARGET_SIGNAL_0;
+ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ && !signal_program[ecs->event_thread->stop_signal])
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
-
- resume (currently_stepping (tss), stop_signal);
+ resume (currently_stepping (ecs->event_thread),
+ ecs->event_thread->stop_signal);
}
prepare_to_wait (ecs);
@@ -3927,7 +4061,8 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
/* For now print nothing. */
/* Print a message only if not in the middle of doing a "step n"
operation for n > 1 */
- if (!step_multi || !stop_step)
+ if (!inferior_thread ()->step_multi
+ || !inferior_thread ()->stop_step)
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string
(uiout, "reason",
@@ -3978,22 +4113,36 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
return_child_result_value = stop_info;
break;
case SIGNAL_RECEIVED:
- /* Signal received. The signal table tells us to print about
- it. */
+ /* Signal received. The signal table tells us to print about
+ it. */
annotate_signal ();
- ui_out_text (uiout, "\nProgram received signal ");
- annotate_signal_name ();
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
- ui_out_field_string (uiout, "signal-name",
- target_signal_to_name (stop_info));
- annotate_signal_name_end ();
- ui_out_text (uiout, ", ");
- annotate_signal_string ();
- ui_out_field_string (uiout, "signal-meaning",
- target_signal_to_string (stop_info));
- annotate_signal_string_end ();
+
+ if (stop_info == TARGET_SIGNAL_0 && !ui_out_is_mi_like_p (uiout))
+ {
+ struct thread_info *t = inferior_thread ();
+
+ ui_out_text (uiout, "\n[");
+ ui_out_field_string (uiout, "thread-name",
+ target_pid_to_str (t->ptid));
+ ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num);
+ ui_out_text (uiout, " stopped");
+ }
+ else
+ {
+ ui_out_text (uiout, "\nProgram received signal ");
+ annotate_signal_name ();
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason", async_reason_lookup (EXEC_ASYNC_SIGNAL_RECEIVED));
+ ui_out_field_string (uiout, "signal-name",
+ target_signal_to_name (stop_info));
+ annotate_signal_name_end ();
+ ui_out_text (uiout, ", ");
+ annotate_signal_string ();
+ ui_out_field_string (uiout, "signal-meaning",
+ target_signal_to_string (stop_info));
+ annotate_signal_string_end ();
+ }
ui_out_text (uiout, ".\n");
break;
case NO_HISTORY:
@@ -4080,7 +4229,11 @@ Further execution is probably impossible.\n"));
/* Don't print a message if in the middle of doing a "step n"
operation for n > 1 */
- if (step_multi && stop_step)
+ if (target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED
+ && inferior_thread ()->step_multi
+ && inferior_thread ()->stop_step)
goto done;
target_terminal_ours ();
@@ -4091,17 +4244,12 @@ Further execution is probably impossible.\n"));
if (target_has_stack && !stop_stack_dummy)
set_current_sal_from_frame (get_current_frame (), 1);
- /* Look up the hook_stop and run it (CLI internally handles problem
- of stop_command's pre-hook not existing). */
- if (stop_command)
- catch_errors (hook_stop_stub, stop_command,
- "Error while running hook_stop:\n", RETURN_MASK_ALL);
-
if (!target_has_stack)
- {
+ goto done;
- goto done;
- }
+ if (last.kind == TARGET_WAITKIND_SIGNALLED
+ || last.kind == TARGET_WAITKIND_EXITED)
+ goto done;
/* Select innermost stack frame - i.e., current frame is frame 0,
and current location is based on that.
@@ -4126,8 +4274,9 @@ Further execution is probably impossible.\n"));
int bpstat_ret;
int source_flag;
int do_frame_printing = 1;
+ struct thread_info *tp = inferior_thread ();
- bpstat_ret = bpstat_print (stop_bpstat);
+ bpstat_ret = bpstat_print (tp->stop_bpstat);
switch (bpstat_ret)
{
case PRINT_UNKNOWN:
@@ -4146,8 +4295,8 @@ Further execution is probably impossible.\n"));
/* FIXME: cagney/2002-12-01: Given that a frame ID does
(or should) carry around the function and does (or
should) use that when doing a frame comparison. */
- if (stop_step
- && frame_id_eq (step_frame_id,
+ if (tp->stop_step
+ && frame_id_eq (tp->step_frame_id,
get_frame_id (get_current_frame ()))
&& step_start_function == find_pc_function (stop_pc))
source_flag = SRC_LINE; /* finished step, just print source line */
@@ -4199,7 +4348,7 @@ Further execution is probably impossible.\n"));
/* Save the function value return registers, if we care.
We might be about to restore their previous contents. */
- if (proceed_to_finish)
+ if (inferior_thread ()->proceed_to_finish)
{
/* This should not be necessary. */
if (stop_registers)
@@ -4225,21 +4374,45 @@ Further execution is probably impossible.\n"));
done:
annotate_stopped ();
- if (!suppress_stop_observer && !step_multi)
- observer_notify_normal_stop (stop_bpstat);
- /* Delete the breakpoint we stopped at, if it wants to be deleted.
- Delete any breakpoint that is to be deleted at the next stop. */
- breakpoint_auto_delete (stop_bpstat);
+ if (!suppress_stop_observer
+ && !(target_has_execution
+ && last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED
+ && inferior_thread ()->step_multi))
+ {
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ observer_notify_normal_stop (inferior_thread ()->stop_bpstat);
+ else
+ observer_notify_normal_stop (NULL);
+ }
- if (target_has_execution
- && last.kind != TARGET_WAITKIND_SIGNALLED
- && last.kind != TARGET_WAITKIND_EXITED)
+ if (target_has_execution)
{
+ if (last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
+ /* Delete the breakpoint we stopped at, if it wants to be deleted.
+ Delete any breakpoint that is to be deleted at the next stop. */
+ breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
+
+ /* Mark the stopped threads accordingly. In all-stop, all
+ threads of all processes are stopped when we get any event
+ reported. In non-stop mode, only the event thread stops. If
+ we're handling a process exit in non-stop mode, there's
+ nothing to do, as threads of the dead process are gone, and
+ threads of any other process were left running. */
if (!non_stop)
- set_running (pid_to_ptid (-1), 0);
- else
+ set_running (minus_one_ptid, 0);
+ else if (last.kind != TARGET_WAITKIND_SIGNALLED
+ && last.kind != TARGET_WAITKIND_EXITED)
set_running (inferior_ptid, 0);
}
+
+ /* Look up the hook_stop and run it (CLI internally handles problem
+ of stop_command's pre-hook not existing). */
+ if (stop_command)
+ catch_errors (hook_stop_stub, stop_command,
+ "Error while running hook_stop:\n", RETURN_MASK_ALL);
+
}
static int
@@ -4252,9 +4425,7 @@ hook_stop_stub (void *cmd)
int
signal_stop_state (int signo)
{
- /* Always stop on signals if we're just gaining control of the
- program. */
- return signal_stop[signo] || stop_soon != NO_STOP_QUIETLY;
+ return signal_stop[signo];
}
int
@@ -4344,11 +4515,7 @@ handle_command (char *args, int from_tty)
/* Break the command line up into args. */
- argv = buildargv (args);
- if (argv == NULL)
- {
- nomem (0);
- }
+ argv = gdb_buildargv (args);
old_chain = make_cleanup_freeargv (argv);
/* Walk through the args, looking for signal oursigs, signal names, and
@@ -4505,13 +4672,12 @@ xdb_handle_command (char *args, int from_tty)
char **argv;
struct cleanup *old_chain;
+ if (args == NULL)
+ error_no_arg (_("xdb command"));
+
/* Break the command line up into args. */
- argv = buildargv (args);
- if (argv == NULL)
- {
- nomem (0);
- }
+ argv = gdb_buildargv (args);
old_chain = make_cleanup_freeargv (argv);
if (argv[1] != (char *) NULL)
{
@@ -4637,16 +4803,6 @@ struct inferior_status
int proceed_to_finish;
};
-void
-write_inferior_status_register (struct inferior_status *inf_status, int regno,
- LONGEST val)
-{
- int size = register_size (current_gdbarch, regno);
- void *buf = alloca (size);
- store_signed_integer (buf, size, val);
- regcache_raw_write (inf_status->registers, regno, buf);
-}
-
/* 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). */
@@ -4655,28 +4811,30 @@ struct inferior_status *
save_inferior_status (int restore_stack_info)
{
struct inferior_status *inf_status = XMALLOC (struct inferior_status);
+ struct thread_info *tp = inferior_thread ();
+ struct inferior *inf = current_inferior ();
- inf_status->stop_signal = stop_signal;
+ inf_status->stop_signal = tp->stop_signal;
inf_status->stop_pc = stop_pc;
- inf_status->stop_step = stop_step;
+ 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;
- inf_status->stepping_over_breakpoint = stepping_over_breakpoint;
- inf_status->step_range_start = step_range_start;
- inf_status->step_range_end = step_range_end;
- inf_status->step_frame_id = step_frame_id;
- inf_status->step_over_calls = step_over_calls;
+ inf_status->stepping_over_breakpoint = tp->trap_expected;
+ inf_status->step_range_start = tp->step_range_start;
+ inf_status->step_range_end = tp->step_range_end;
+ inf_status->step_frame_id = tp->step_frame_id;
+ inf_status->step_over_calls = tp->step_over_calls;
inf_status->stop_after_trap = stop_after_trap;
- inf_status->stop_soon = stop_soon;
+ inf_status->stop_soon = inf->stop_soon;
/* Save original bpstat chain here; replace it with copy of chain.
If caller's caller is walking the chain, they'll be happier if we
hand them back the original chain when restore_inferior_status is
called. */
- inf_status->stop_bpstat = stop_bpstat;
- stop_bpstat = bpstat_copy (stop_bpstat);
+ 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 = proceed_to_finish;
+ inf_status->proceed_to_finish = tp->proceed_to_finish;
inf_status->registers = regcache_dup (get_current_regcache ());
@@ -4708,22 +4866,25 @@ restore_selected_frame (void *args)
void
restore_inferior_status (struct inferior_status *inf_status)
{
- stop_signal = inf_status->stop_signal;
+ struct thread_info *tp = inferior_thread ();
+ struct inferior *inf = current_inferior ();
+
+ tp->stop_signal = inf_status->stop_signal;
stop_pc = inf_status->stop_pc;
- stop_step = inf_status->stop_step;
+ 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;
- stepping_over_breakpoint = inf_status->stepping_over_breakpoint;
- step_range_start = inf_status->step_range_start;
- step_range_end = inf_status->step_range_end;
- step_frame_id = inf_status->step_frame_id;
- step_over_calls = inf_status->step_over_calls;
+ tp->trap_expected = inf_status->stepping_over_breakpoint;
+ tp->step_range_start = inf_status->step_range_start;
+ tp->step_range_end = inf_status->step_range_end;
+ tp->step_frame_id = inf_status->step_frame_id;
+ tp->step_over_calls = inf_status->step_over_calls;
stop_after_trap = inf_status->stop_after_trap;
- stop_soon = inf_status->stop_soon;
- bpstat_clear (&stop_bpstat);
- stop_bpstat = inf_status->stop_bpstat;
+ inf->stop_soon = inf_status->stop_soon;
+ bpstat_clear (&tp->stop_bpstat);
+ tp->stop_bpstat = inf_status->stop_bpstat;
breakpoint_proceeded = inf_status->breakpoint_proceeded;
- proceed_to_finish = inf_status->proceed_to_finish;
+ 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). */
@@ -4890,6 +5051,19 @@ ptid_equal (ptid_t ptid1, ptid_t ptid2)
&& ptid1.tid == ptid2.tid);
}
+/* Returns true if PTID represents a process. */
+
+int
+ptid_is_pid (ptid_t ptid)
+{
+ if (ptid_equal (minus_one_ptid, ptid))
+ return 0;
+ if (ptid_equal (null_ptid, ptid))
+ return 0;
+
+ return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0);
+}
+
/* restore_inferior_ptid() will be used by the cleanup machinery
to restore the inferior_ptid value saved in a call to
save_inferior_ptid(). */
@@ -5180,16 +5354,20 @@ function is skipped and the step command stops at a different source line."),
show_step_stop_if_no_debug,
&setlist, &showlist);
- add_setshow_boolean_cmd ("can-use-displaced-stepping", class_maintenance,
- &can_use_displaced_stepping, _("\
+ add_setshow_enum_cmd ("displaced-stepping", class_run,
+ can_use_displaced_stepping_enum,
+ &can_use_displaced_stepping, _("\
Set debugger's willingness to use displaced stepping."), _("\
Show debugger's willingness to use displaced stepping."), _("\
-If zero, gdb will not use displaced stepping to step over\n\
-breakpoints, even if such is supported by the target."),
- NULL,
- show_can_use_displaced_stepping,
- &maintenance_set_cmdlist,
- &maintenance_show_cmdlist);
+If on, gdb will use displaced stepping to step over breakpoints if it is\n\
+supported by the target architecture. If off, gdb will not use displaced\n\
+stepping to step over breakpoints, even if such is supported by the target\n\
+architecture. If auto (which is the default), gdb will use displaced stepping\n\
+if the target architecture supports it and non-stop mode is active, but will not\n\
+use it in all-stop mode (see help set non-stop)."),
+ NULL,
+ show_can_use_displaced_stepping,
+ &setlist, &showlist);
add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names,
&exec_direction, _("Set direction of execution.\n\
@@ -5205,4 +5383,7 @@ Options are 'forward' or 'reverse'."),
inferior_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
displaced_step_ptid = null_ptid;
+
+ observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
+ observer_attach_thread_stop_requested (infrun_thread_stop_requested);
}