| Index: gdb/infrun.c
|
| diff --git a/gdb/infrun.c b/gdb/infrun.c
|
| index d443ae7e0bff9ce9bf6a3003f43be64181848a8d..d8f9787ff283bd86e66d38b991e24f2a8cb87547 100644
|
| --- a/gdb/infrun.c
|
| +++ b/gdb/infrun.c
|
| @@ -1,7 +1,7 @@
|
| /* Target-struct-independent code to start (run) and stop an inferior
|
| process.
|
|
|
| - Copyright (C) 1986-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 1986-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -19,7 +19,7 @@
|
| along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
| #include "defs.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include <ctype.h>
|
| #include "symtab.h"
|
| #include "frame.h"
|
| @@ -49,6 +49,7 @@
|
| #include "mi/mi-common.h"
|
| #include "event-top.h"
|
| #include "record.h"
|
| +#include "record-full.h"
|
| #include "inline-frame.h"
|
| #include "jit.h"
|
| #include "tracepoint.h"
|
| @@ -57,6 +58,9 @@
|
| #include "skip.h"
|
| #include "probe.h"
|
| #include "objfiles.h"
|
| +#include "completer.h"
|
| +#include "target-descriptions.h"
|
| +#include "target-dcache.h"
|
|
|
| /* Prototypes for local functions */
|
|
|
| @@ -129,8 +133,12 @@ int sync_execution = 0;
|
|
|
| static ptid_t previous_inferior_ptid;
|
|
|
| -/* Default behavior is to detach newly forked processes (legacy). */
|
| -int detach_fork = 1;
|
| +/* If set (default for legacy reasons), when following a fork, GDB
|
| + will detach from one of the fork branches, child or parent.
|
| + Exactly which branch is detached depends on 'set follow-fork-mode'
|
| + setting. */
|
| +
|
| +static int detach_fork = 1;
|
|
|
| int debug_displaced = 0;
|
| static void
|
| @@ -140,7 +148,7 @@ show_debug_displaced (struct ui_file *file, int from_tty,
|
| fprintf_filtered (file, _("Displace stepping debugging is %s.\n"), value);
|
| }
|
|
|
| -int debug_infrun = 0;
|
| +unsigned int debug_infrun = 0;
|
| static void
|
| show_debug_infrun (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| @@ -178,64 +186,37 @@ set_disable_randomization (char *args, int from_tty,
|
| "this platform."));
|
| }
|
|
|
| +/* User interface for non-stop mode. */
|
|
|
| -/* If the program uses ELF-style shared libraries, then calls to
|
| - functions in shared libraries go through stubs, which live in a
|
| - table called the PLT (Procedure Linkage Table). The first time the
|
| - function is called, the stub sends control to the dynamic linker,
|
| - which looks up the function's real address, patches the stub so
|
| - that future calls will go directly to the function, and then passes
|
| - control to the function.
|
| -
|
| - If we are stepping at the source level, we don't want to see any of
|
| - this --- we just want to skip over the stub and the dynamic linker.
|
| - The simple approach is to single-step until control leaves the
|
| - dynamic linker.
|
| -
|
| - However, on some systems (e.g., Red Hat's 5.2 distribution) the
|
| - dynamic linker calls functions in the shared C library, so you
|
| - can't tell from the PC alone whether the dynamic linker is still
|
| - running. In this case, we use a step-resume breakpoint to get us
|
| - 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
|
| - 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
|
| - pretty portable way, by comparing the PC against the address ranges
|
| - of the dynamic linker's sections.
|
| -
|
| - SKIP_SOLIB_RESOLVER is generally going to be system-specific, since
|
| - it depends on internal details of the dynamic linker. It's usually
|
| - not too hard to figure out where to put a breakpoint, but it
|
| - certainly isn't portable. SKIP_SOLIB_RESOLVER should do plenty of
|
| - sanity checking. If it can't figure things out, returning zero and
|
| - getting the (possibly confusing) stepping behavior is better than
|
| - signalling an error, which will obscure the change in the
|
| - inferior's state. */
|
| -
|
| -/* This function returns TRUE if pc is the address of an instruction
|
| - that lies within the dynamic linker (such as the event hook, or the
|
| - dld itself).
|
| -
|
| - This function must be used only when a dynamic linker event has
|
| - been caught, and the inferior is being stepped out of the hook, or
|
| - undefined results are guaranteed. */
|
| -
|
| -#ifndef SOLIB_IN_DYNAMIC_LINKER
|
| -#define SOLIB_IN_DYNAMIC_LINKER(pid,pc) 0
|
| -#endif
|
| +int non_stop = 0;
|
| +static int non_stop_1 = 0;
|
| +
|
| +static void
|
| +set_non_stop (char *args, int from_tty,
|
| + struct cmd_list_element *c)
|
| +{
|
| + if (target_has_execution)
|
| + {
|
| + non_stop_1 = non_stop;
|
| + error (_("Cannot change this setting while the inferior is running."));
|
| + }
|
| +
|
| + non_stop = non_stop_1;
|
| +}
|
| +
|
| +static void
|
| +show_non_stop (struct ui_file *file, int from_tty,
|
| + struct cmd_list_element *c, const char *value)
|
| +{
|
| + fprintf_filtered (file,
|
| + _("Controlling the inferior in non-stop mode is %s.\n"),
|
| + value);
|
| +}
|
|
|
| /* "Observer mode" is somewhat like a more extreme version of
|
| non-stop, in which all GDB operations that might affect the
|
| target's execution have been disabled. */
|
|
|
| -static int non_stop_1 = 0;
|
| -
|
| int observer_mode = 0;
|
| static int observer_mode_1 = 0;
|
|
|
| @@ -243,8 +224,6 @@ static void
|
| set_observer_mode (char *args, int from_tty,
|
| struct cmd_list_element *c)
|
| {
|
| - extern int pagination_enabled;
|
| -
|
| if (target_has_execution)
|
| {
|
| observer_mode_1 = observer_mode;
|
| @@ -316,6 +295,12 @@ static unsigned char *signal_stop;
|
| static unsigned char *signal_print;
|
| static unsigned char *signal_program;
|
|
|
| +/* Table of signals that are registered with "catch signal". A
|
| + non-zero entry indicates that the signal is caught by some "catch
|
| + signal" command. This has size GDB_SIGNAL_LAST, to accommodate all
|
| + signals. */
|
| +static unsigned char *signal_catch;
|
| +
|
| /* Table of signals that the target may silently handle.
|
| This is automatically determined from the flags above,
|
| and simply cached here. */
|
| @@ -361,6 +346,16 @@ static struct symbol *step_start_function;
|
| /* Nonzero if we want to give control to the user when we're notified
|
| of shared library events by the dynamic linker. */
|
| int stop_on_solib_events;
|
| +
|
| +/* Enable or disable optional shared library event breakpoints
|
| + as appropriate when the above flag is changed. */
|
| +
|
| +static void
|
| +set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
|
| +{
|
| + update_solib_breakpoints ();
|
| +}
|
| +
|
| static void
|
| show_stop_on_solib_events (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| @@ -395,7 +390,7 @@ static void context_switch (ptid_t ptid);
|
|
|
| void init_thread_stepping_state (struct thread_info *tss);
|
|
|
| -void init_infwait_state (void);
|
| +static void init_infwait_state (void);
|
|
|
| static const char follow_fork_mode_child[] = "child";
|
| static const char follow_fork_mode_parent[] = "parent";
|
| @@ -507,7 +502,7 @@ follow_fork (void)
|
|
|
| /* Tell the target to do whatever is necessary to follow
|
| either parent or child. */
|
| - if (target_follow_fork (follow_child))
|
| + if (target_follow_fork (follow_child, detach_fork))
|
| {
|
| /* Target refused to follow, or there's some other reason
|
| we shouldn't resume. */
|
| @@ -662,7 +657,18 @@ handle_vfork_child_exec_or_exit (int exec)
|
|
|
| /* follow-fork child, detach-on-fork on. */
|
|
|
| - old_chain = make_cleanup_restore_current_thread ();
|
| + inf->vfork_parent->pending_detach = 0;
|
| +
|
| + if (!exec)
|
| + {
|
| + /* If we're handling a child exit, then inferior_ptid
|
| + points at the inferior's pid, not to a thread. */
|
| + old_chain = save_inferior_ptid ();
|
| + save_current_program_space ();
|
| + save_current_inferior ();
|
| + }
|
| + else
|
| + old_chain = save_current_space_and_thread ();
|
|
|
| /* We're letting loose of the parent. */
|
| tp = any_live_thread_of_process (inf->vfork_parent->pid);
|
| @@ -786,7 +792,7 @@ handle_vfork_child_exec_or_exit (int exec)
|
| }
|
| }
|
|
|
| -/* Enum strings for "set|show displaced-stepping". */
|
| +/* Enum strings for "set|show follow-exec-mode". */
|
|
|
| static const char follow_exec_mode_new[] = "new";
|
| static const char follow_exec_mode_same[] = "same";
|
| @@ -901,6 +907,16 @@ follow_exec (ptid_t pid, char *execd_pathname)
|
| set_current_inferior (inf);
|
| set_current_program_space (pspace);
|
| }
|
| + else
|
| + {
|
| + /* The old description may no longer be fit for the new image.
|
| + E.g, a 64-bit process exec'ed a 32-bit process. Clear the
|
| + old description; we'll read a new one below. No need to do
|
| + this on "follow-exec-mode new", as the old inferior stays
|
| + around (its description is later cleared/refetched on
|
| + restart). */
|
| + target_clear_description ();
|
| + }
|
|
|
| gdb_assert (current_program_space == inf->pspace);
|
|
|
| @@ -920,11 +936,15 @@ follow_exec (ptid_t pid, char *execd_pathname)
|
| if ((inf->symfile_flags & SYMFILE_NO_READ) == 0)
|
| set_initial_language ();
|
|
|
| -#ifdef SOLIB_CREATE_INFERIOR_HOOK
|
| - SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
| -#else
|
| + /* If the target can specify a description, read it. Must do this
|
| + after flipping to the new executable (because the target supplied
|
| + description must be compatible with the executable's
|
| + architecture, and the old executable may e.g., be 32-bit, while
|
| + the new one 64-bit), and before anything involving memory or
|
| + registers. */
|
| + target_find_description ();
|
| +
|
| solib_create_inferior_hook (0);
|
| -#endif
|
|
|
| jit_inferior_created_hook ();
|
|
|
| @@ -1277,6 +1297,7 @@ static int
|
| displaced_step_prepare (ptid_t ptid)
|
| {
|
| struct cleanup *old_cleanups, *ignore_cleanups;
|
| + struct thread_info *tp = find_thread_ptid (ptid);
|
| struct regcache *regcache = get_thread_regcache (ptid);
|
| struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| CORE_ADDR original, copy;
|
| @@ -1289,6 +1310,12 @@ displaced_step_prepare (ptid_t ptid)
|
| support displaced stepping. */
|
| gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
|
|
|
| + /* Disable range stepping while executing in the scratch pad. We
|
| + want a single-step even if executing the displaced instruction in
|
| + the scratch buffer lands within the stepping range (e.g., a
|
| + jump/branch). */
|
| + tp->control.may_range_step = 0;
|
| +
|
| /* We have to displaced step one thread at a time, as we only have
|
| access to a single scratch space per inferior. */
|
|
|
| @@ -1723,9 +1750,10 @@ resume (int step, enum gdb_signal sig)
|
|
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: resume (step=%d, signal=%d), "
|
| + "infrun: resume (step=%d, signal=%s), "
|
| "trap_expected=%d, current thread [%s] at %s\n",
|
| - step, sig, tp->control.trap_expected,
|
| + step, gdb_signal_to_symbol_string (sig),
|
| + tp->control.trap_expected,
|
| target_pid_to_str (inferior_ptid),
|
| paddress (gdbarch, pc));
|
|
|
| @@ -1744,6 +1772,11 @@ how to step past a permanent breakpoint on this architecture. Try using\n\
|
| a command like `return' or `jump' to continue execution."));
|
| }
|
|
|
| + /* If we have a breakpoint to step over, make sure to do a single
|
| + step only. Same if we have software watchpoints. */
|
| + if (tp->control.trap_expected || bpstat_should_step ())
|
| + tp->control.may_range_step = 0;
|
| +
|
| /* If enabled, step over breakpoints by executing a copy of the
|
| instruction at a different address.
|
|
|
| @@ -1905,6 +1938,16 @@ a command like `return' or `jump' to continue execution."));
|
| displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
|
| }
|
|
|
| + if (tp->control.may_range_step)
|
| + {
|
| + /* If we're resuming a thread with the PC out of the step
|
| + range, then we're doing some nested/finer run control
|
| + operation, like stepping the thread out of the dynamic
|
| + linker or the displaced stepping scratch pad. We
|
| + shouldn't have allowed a range step then. */
|
| + gdb_assert (pc_in_thread_step_range (pc, tp));
|
| + }
|
| +
|
| /* Install inferior's terminal modes. */
|
| target_terminal_inferior ();
|
|
|
| @@ -1946,6 +1989,7 @@ clear_proceed_status_thread (struct thread_info *tp)
|
| tp->control.trap_expected = 0;
|
| tp->control.step_range_start = 0;
|
| tp->control.step_range_end = 0;
|
| + tp->control.may_range_step = 0;
|
| tp->control.step_frame_id = null_frame_id;
|
| tp->control.step_stack_frame_id = null_frame_id;
|
| tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE;
|
| @@ -2102,7 +2146,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
|
| struct thread_info *tp;
|
| CORE_ADDR pc;
|
| struct address_space *aspace;
|
| - int oneproc = 0;
|
| + /* GDB may force the inferior to step due to various reasons. */
|
| + int force_step = 0;
|
|
|
| /* If we're stopped at a fork/vfork, follow the branch set by the
|
| "set follow-fork-mode" command; otherwise, we'll just proceed
|
| @@ -2142,13 +2187,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
|
| actually be executing the breakpoint insn anyway.
|
| We'll be (un-)executing the previous instruction. */
|
|
|
| - oneproc = 1;
|
| + force_step = 1;
|
| else if (gdbarch_single_step_through_delay_p (gdbarch)
|
| && gdbarch_single_step_through_delay (gdbarch,
|
| get_current_frame ()))
|
| /* We stepped onto an instruction that needs to be stepped
|
| again before re-inserting the breakpoint, do so. */
|
| - oneproc = 1;
|
| + force_step = 1;
|
| }
|
| else
|
| {
|
| @@ -2157,8 +2202,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
|
|
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: proceed (addr=%s, signal=%d, step=%d)\n",
|
| - paddress (gdbarch, addr), siggnal, step);
|
| + "infrun: proceed (addr=%s, signal=%s, step=%d)\n",
|
| + paddress (gdbarch, addr),
|
| + gdb_signal_to_symbol_string (siggnal), step);
|
|
|
| if (non_stop)
|
| /* In non-stop, each thread is handled individually. The context
|
| @@ -2179,13 +2225,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
|
| is required it returns TRUE and sets the current thread to
|
| the old thread. */
|
| if (prepare_to_proceed (step))
|
| - oneproc = 1;
|
| + force_step = 1;
|
| }
|
|
|
| /* prepare_to_proceed may change the current thread. */
|
| tp = inferior_thread ();
|
|
|
| - if (oneproc)
|
| + if (force_step)
|
| {
|
| tp->control.trap_expected = 1;
|
| /* If displaced stepping is enabled, we can step over the
|
| @@ -2273,7 +2319,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step)
|
| init_infwait_state ();
|
|
|
| /* Resume inferior. */
|
| - resume (oneproc || step || bpstat_should_step (), tp->suspend.stop_signal);
|
| + resume (force_step || step || bpstat_should_step (),
|
| + tp->suspend.stop_signal);
|
|
|
| /* Wait for it to stop (if not standalone)
|
| and in any case decode why it stopped, and act accordingly. */
|
| @@ -2361,7 +2408,7 @@ enum infwait_states
|
| ptid_t waiton_ptid;
|
|
|
| /* Current inferior wait state. */
|
| -enum infwait_states infwait_state;
|
| +static enum infwait_states infwait_state;
|
|
|
| /* Data to be passed around while handling an event. This data is
|
| discarded between events. */
|
| @@ -2373,12 +2420,16 @@ struct execution_control_state
|
| struct thread_info *event_thread;
|
|
|
| struct target_waitstatus ws;
|
| - int random_signal;
|
| int stop_func_filled_in;
|
| CORE_ADDR stop_func_start;
|
| CORE_ADDR stop_func_end;
|
| const char *stop_func_name;
|
| int wait_some_more;
|
| +
|
| + /* We were in infwait_step_watch_state or
|
| + infwait_nonstep_watch_state state, and the thread reported an
|
| + event. */
|
| + int stepped_after_stopped_by_watchpoint;
|
| };
|
|
|
| static void handle_inferior_event (struct execution_control_state *ecs);
|
| @@ -2387,12 +2438,15 @@ static void handle_step_into_function (struct gdbarch *gdbarch,
|
| struct execution_control_state *ecs);
|
| static void handle_step_into_function_backward (struct gdbarch *gdbarch,
|
| struct execution_control_state *ecs);
|
| +static void handle_signal_stop (struct execution_control_state *ecs);
|
| static void check_exception_resume (struct execution_control_state *,
|
| struct frame_info *);
|
|
|
| static void stop_stepping (struct execution_control_state *ecs);
|
| static void prepare_to_wait (struct execution_control_state *ecs);
|
| static void keep_going (struct execution_control_state *ecs);
|
| +static void process_event_stop_test (struct execution_control_state *ecs);
|
| +static int switch_back_to_stepped_thread (struct execution_control_state *ecs);
|
|
|
| /* Callback for iterate over threads. If the thread is stopped, but
|
| the user/frontend doesn't know about that yet, go through
|
| @@ -2422,6 +2476,13 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
|
|
|
| old_chain = make_cleanup_restore_current_thread ();
|
|
|
| + overlay_cache_invalid = 1;
|
| + /* Flush target cache before starting to handle each event.
|
| + Target was running and cache could be stale. This is just a
|
| + heuristic. Running threads may modify target memory, but we
|
| + don't get any event. */
|
| + target_dcache_invalidate ();
|
| +
|
| /* Go through handle_inferior_event/normal_stop, so we always
|
| have consistent output as if the stop event had been
|
| reported. */
|
| @@ -2563,14 +2624,15 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid,
|
| is set. */
|
|
|
| fprintf_unfiltered (tmp_stream,
|
| - "infrun: target_wait (%d", PIDGET (waiton_ptid));
|
| - if (PIDGET (waiton_ptid) != -1)
|
| + "infrun: target_wait (%d", ptid_get_pid (waiton_ptid));
|
| + if (ptid_get_pid (waiton_ptid) != -1)
|
| fprintf_unfiltered (tmp_stream,
|
| " [%s]", target_pid_to_str (waiton_ptid));
|
| fprintf_unfiltered (tmp_stream, ", status) =\n");
|
| fprintf_unfiltered (tmp_stream,
|
| "infrun: %d [%s],\n",
|
| - PIDGET (result_ptid), target_pid_to_str (result_ptid));
|
| + ptid_get_pid (result_ptid),
|
| + target_pid_to_str (result_ptid));
|
| fprintf_unfiltered (tmp_stream,
|
| "infrun: %s\n",
|
| status_string);
|
| @@ -2623,6 +2685,11 @@ prepare_for_detach (void)
|
| memset (ecs, 0, sizeof (*ecs));
|
|
|
| overlay_cache_invalid = 1;
|
| + /* Flush target cache before starting to handle each event.
|
| + Target was running and cache could be stale. This is just a
|
| + heuristic. Running threads may modify target memory, but we
|
| + don't get any event. */
|
| + target_dcache_invalidate ();
|
|
|
| if (deprecated_target_wait_hook)
|
| ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0);
|
| @@ -2686,6 +2753,12 @@ wait_for_inferior (void)
|
|
|
| overlay_cache_invalid = 1;
|
|
|
| + /* Flush target cache before starting to handle each event.
|
| + Target was running and cache could be stale. This is just a
|
| + heuristic. Running threads may modify target memory, but we
|
| + don't get any event. */
|
| + target_dcache_invalidate ();
|
| +
|
| if (deprecated_target_wait_hook)
|
| ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws, 0);
|
| else
|
| @@ -2751,6 +2824,11 @@ fetch_inferior_event (void *client_data)
|
| make_cleanup_restore_current_thread ();
|
|
|
| overlay_cache_invalid = 1;
|
| + /* Flush target cache before starting to handle each event. Target
|
| + was running and cache could be stale. This is just a heuristic.
|
| + Running threads may modify target memory, but we don't get any
|
| + event. */
|
| + target_dcache_invalidate ();
|
|
|
| make_cleanup_restore_integer (&execution_direction);
|
| execution_direction = target_execution_direction ();
|
| @@ -2968,10 +3046,10 @@ adjust_pc_after_break (struct execution_control_state *ecs)
|
| if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
|
| || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
|
| {
|
| - struct cleanup *old_cleanups = NULL;
|
| + struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
|
|
|
| if (RECORD_IS_USED)
|
| - old_cleanups = record_gdb_operation_disable_set ();
|
| + record_full_gdb_operation_disable_set ();
|
|
|
| /* When using hardware single-step, a SIGTRAP is reported for both
|
| a completed single-step and a software breakpoint. Need to
|
| @@ -2997,32 +3075,17 @@ adjust_pc_after_break (struct execution_control_state *ecs)
|
| || ecs->event_thread->prev_pc == breakpoint_pc)
|
| regcache_write_pc (regcache, breakpoint_pc);
|
|
|
| - if (RECORD_IS_USED)
|
| - do_cleanups (old_cleanups);
|
| + do_cleanups (old_cleanups);
|
| }
|
| }
|
|
|
| -void
|
| +static void
|
| init_infwait_state (void)
|
| {
|
| waiton_ptid = pid_to_ptid (-1);
|
| infwait_state = infwait_normal_state;
|
| }
|
|
|
| -void
|
| -error_is_running (void)
|
| -{
|
| - error (_("Cannot execute this command while "
|
| - "the selected thread is running."));
|
| -}
|
| -
|
| -void
|
| -ensure_not_running (void)
|
| -{
|
| - if (is_running (inferior_ptid))
|
| - error_is_running ();
|
| -}
|
| -
|
| static int
|
| stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
|
| {
|
| @@ -3048,14 +3111,12 @@ static int
|
| handle_syscall_event (struct execution_control_state *ecs)
|
| {
|
| struct regcache *regcache;
|
| - struct gdbarch *gdbarch;
|
| int syscall_number;
|
|
|
| if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| context_switch (ecs->ptid);
|
|
|
| regcache = get_thread_regcache (ecs->ptid);
|
| - gdbarch = get_regcache_arch (regcache);
|
| syscall_number = ecs->ws.value.syscall_number;
|
| stop_pc = regcache_read_pc (regcache);
|
|
|
| @@ -3069,34 +3130,19 @@ handle_syscall_event (struct execution_control_state *ecs)
|
| ecs->event_thread->control.stop_bpstat
|
| = bpstat_stop_status (get_regcache_aspace (regcache),
|
| stop_pc, ecs->ptid, &ecs->ws);
|
| - ecs->random_signal
|
| - = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
|
|
| - if (!ecs->random_signal)
|
| + if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
|
| {
|
| /* Catchpoint hit. */
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
| return 0;
|
| }
|
| }
|
|
|
| /* If no catchpoint triggered for this, then keep going. */
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| keep_going (ecs);
|
| return 1;
|
| }
|
|
|
| -/* Clear the supplied execution_control_state's stop_func_* fields. */
|
| -
|
| -static void
|
| -clear_stop_func (struct execution_control_state *ecs)
|
| -{
|
| - ecs->stop_func_filled_in = 0;
|
| - ecs->stop_func_start = 0;
|
| - ecs->stop_func_end = 0;
|
| - ecs->stop_func_name = NULL;
|
| -}
|
| -
|
| /* Lazily fill in the execution_control_state's stop_func_* fields. */
|
|
|
| static void
|
| @@ -3116,18 +3162,34 @@ fill_in_stop_func (struct gdbarch *gdbarch,
|
| }
|
| }
|
|
|
| -/* Given an execution control state that has been freshly filled in
|
| - by an event from the inferior, figure out what it means and take
|
| - appropriate action. */
|
| +
|
| +/* Return the STOP_SOON field of the inferior pointed at by PTID. */
|
| +
|
| +static enum stop_kind
|
| +get_inferior_stop_soon (ptid_t ptid)
|
| +{
|
| + struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid));
|
| +
|
| + gdb_assert (inf != NULL);
|
| + return inf->control.stop_soon;
|
| +}
|
| +
|
| +/* Given an execution control state that has been freshly filled in by
|
| + an event from the inferior, figure out what it means and take
|
| + appropriate action.
|
| +
|
| + The alternatives are:
|
| +
|
| + 1) stop_stepping and return; to really stop and return to the
|
| + debugger.
|
| +
|
| + 2) keep_going and return; to wait for the next event (set
|
| + ecs->event_thread->stepping_over_breakpoint to 1 to single step
|
| + once). */
|
|
|
| static void
|
| handle_inferior_event (struct execution_control_state *ecs)
|
| {
|
| - struct frame_info *frame;
|
| - struct gdbarch *gdbarch;
|
| - int stopped_by_watchpoint;
|
| - int stepped_after_stopped_by_watchpoint = 0;
|
| - struct symtab_and_line stop_pc_sal;
|
| enum stop_kind stop_soon;
|
|
|
| if (ecs->ws.kind == TARGET_WAITKIND_IGNORE)
|
| @@ -3162,18 +3224,6 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| return;
|
| }
|
|
|
| - if (ecs->ws.kind != TARGET_WAITKIND_EXITED
|
| - && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
|
| - && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED)
|
| - {
|
| - struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
|
| -
|
| - gdb_assert (inf);
|
| - stop_soon = inf->control.stop_soon;
|
| - }
|
| - else
|
| - stop_soon = NO_STOP_QUIETLY;
|
| -
|
| /* Cache the last pid/waitstatus. */
|
| target_last_wait_ptid = ecs->ptid;
|
| target_last_waitstatus = ecs->ws;
|
| @@ -3194,13 +3244,16 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| }
|
|
|
| if (ecs->ws.kind != TARGET_WAITKIND_EXITED
|
| - && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
|
| - && !ptid_equal (ecs->ptid, minus_one_ptid))
|
| + && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
|
| {
|
| ecs->event_thread = find_thread_ptid (ecs->ptid);
|
| /* If it's a new thread, add it to the thread database. */
|
| if (ecs->event_thread == NULL)
|
| ecs->event_thread = add_thread (ecs->ptid);
|
| +
|
| + /* Disable range stepping. If the next step request could use a
|
| + range, this will be end up re-enabled then. */
|
| + ecs->event_thread->control.may_range_step = 0;
|
| }
|
|
|
| /* Dependent on valid ECS->EVENT_THREAD. */
|
| @@ -3267,7 +3320,7 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "infrun: infwait_step_watch_state\n");
|
|
|
| - stepped_after_stopped_by_watchpoint = 1;
|
| + ecs->stepped_after_stopped_by_watchpoint = 1;
|
| break;
|
|
|
| case infwait_nonstep_watch_state:
|
| @@ -3279,7 +3332,7 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| /* FIXME-maybe: is this cleaner than setting a flag? Does it
|
| handle things like signals arriving and other things happening
|
| in combination correctly? */
|
| - stepped_after_stopped_by_watchpoint = 1;
|
| + ecs->stepped_after_stopped_by_watchpoint = 1;
|
| break;
|
|
|
| default:
|
| @@ -3294,18 +3347,20 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| case TARGET_WAITKIND_LOADED:
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
|
| + if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| + context_switch (ecs->ptid);
|
| /* Ignore gracefully during startup of the inferior, as it might
|
| be the shell which has just loaded some objects, otherwise
|
| add the symbols for the newly loaded objects. Also ignore at
|
| the beginning of an attach or remote session; we will query
|
| the full list of libraries once the connection is
|
| established. */
|
| +
|
| + stop_soon = get_inferior_stop_soon (ecs->ptid);
|
| if (stop_soon == NO_STOP_QUIETLY)
|
| {
|
| struct regcache *regcache;
|
|
|
| - if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| - context_switch (ecs->ptid);
|
| regcache = get_thread_regcache (ecs->ptid);
|
|
|
| handle_solib_event ();
|
| @@ -3313,14 +3368,12 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| ecs->event_thread->control.stop_bpstat
|
| = bpstat_stop_status (get_regcache_aspace (regcache),
|
| stop_pc, ecs->ptid, &ecs->ws);
|
| - ecs->random_signal
|
| - = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
|
|
| - if (!ecs->random_signal)
|
| + if (bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
|
| {
|
| /* A catchpoint triggered. */
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
| - goto process_event_stop_test;
|
| + process_event_stop_test (ecs);
|
| + return;
|
| }
|
|
|
| /* If requested, stop when the dynamic linker notifies
|
| @@ -3341,13 +3394,9 @@ handle_inferior_event (struct execution_control_state *ecs)
|
|
|
| /* If we are skipping through a shell, or through shared library
|
| loading that we aren't interested in, resume the program. If
|
| - we're running the program normally, also resume. But stop if
|
| - we're attaching or setting up a remote connection. */
|
| + we're running the program normally, also resume. */
|
| if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
|
| {
|
| - if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| - context_switch (ecs->ptid);
|
| -
|
| /* Loading of shared libraries might have changed breakpoint
|
| addresses. Make sure new breakpoints are inserted. */
|
| if (stop_soon == NO_STOP_QUIETLY
|
| @@ -3358,65 +3407,98 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| return;
|
| }
|
|
|
| - break;
|
| + /* But stop if we're attaching or setting up a remote
|
| + connection. */
|
| + if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
| + || stop_soon == STOP_QUIETLY_REMOTE)
|
| + {
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
| + stop_stepping (ecs);
|
| + return;
|
| + }
|
| +
|
| + internal_error (__FILE__, __LINE__,
|
| + _("unhandled stop_soon: %d"), (int) stop_soon);
|
|
|
| case TARGET_WAITKIND_SPURIOUS:
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n");
|
| - if (!ptid_equal (ecs->ptid, inferior_ptid)
|
| - && !ptid_equal (ecs->ptid, minus_one_ptid))
|
| + if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| context_switch (ecs->ptid);
|
| resume (0, GDB_SIGNAL_0);
|
| prepare_to_wait (ecs);
|
| return;
|
|
|
| case TARGET_WAITKIND_EXITED:
|
| + case TARGET_WAITKIND_SIGNALLED:
|
| if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
|
| + {
|
| + if (ecs->ws.kind == TARGET_WAITKIND_EXITED)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: TARGET_WAITKIND_EXITED\n");
|
| + else
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: TARGET_WAITKIND_SIGNALLED\n");
|
| + }
|
| +
|
| inferior_ptid = ecs->ptid;
|
| set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
|
| set_current_program_space (current_inferior ()->pspace);
|
| handle_vfork_child_exec_or_exit (0);
|
| target_terminal_ours (); /* Must do this before mourn anyway. */
|
| - print_exited_reason (ecs->ws.value.integer);
|
|
|
| - /* Record the exit code in the convenience variable $_exitcode, so
|
| - that the user can inspect this again later. */
|
| - set_internalvar_integer (lookup_internalvar ("_exitcode"),
|
| - (LONGEST) ecs->ws.value.integer);
|
| + /* Clearing any previous state of convenience variables. */
|
| + clear_exit_convenience_vars ();
|
|
|
| - /* Also record this in the inferior itself. */
|
| - current_inferior ()->has_exit_code = 1;
|
| - current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
|
| + if (ecs->ws.kind == TARGET_WAITKIND_EXITED)
|
| + {
|
| + /* Record the exit code in the convenience variable $_exitcode, so
|
| + that the user can inspect this again later. */
|
| + set_internalvar_integer (lookup_internalvar ("_exitcode"),
|
| + (LONGEST) ecs->ws.value.integer);
|
|
|
| - gdb_flush (gdb_stdout);
|
| - target_mourn_inferior ();
|
| - singlestep_breakpoints_inserted_p = 0;
|
| - cancel_single_step_breakpoints ();
|
| - stop_print_frame = 0;
|
| - stop_stepping (ecs);
|
| - return;
|
| + /* Also record this in the inferior itself. */
|
| + current_inferior ()->has_exit_code = 1;
|
| + current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
|
|
|
| - case TARGET_WAITKIND_SIGNALLED:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
|
| - inferior_ptid = ecs->ptid;
|
| - set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
|
| - set_current_program_space (current_inferior ()->pspace);
|
| - handle_vfork_child_exec_or_exit (0);
|
| - stop_print_frame = 0;
|
| - target_terminal_ours (); /* Must do this before mourn anyway. */
|
| + print_exited_reason (ecs->ws.value.integer);
|
| + }
|
| + else
|
| + {
|
| + struct regcache *regcache = get_thread_regcache (ecs->ptid);
|
| + struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
|
| - /* Note: By definition of TARGET_WAITKIND_SIGNALLED, we shouldn't
|
| - reach here unless the inferior is dead. However, for years
|
| - target_kill() was called here, which hints that fatal signals aren't
|
| - really fatal on some systems. If that's true, then some changes
|
| - may be needed. */
|
| - target_mourn_inferior ();
|
| + if (gdbarch_gdb_signal_to_target_p (gdbarch))
|
| + {
|
| + /* Set the value of the internal variable $_exitsignal,
|
| + which holds the signal uncaught by the inferior. */
|
| + set_internalvar_integer (lookup_internalvar ("_exitsignal"),
|
| + gdbarch_gdb_signal_to_target (gdbarch,
|
| + ecs->ws.value.sig));
|
| + }
|
| + else
|
| + {
|
| + /* We don't have access to the target's method used for
|
| + converting between signal numbers (GDB's internal
|
| + representation <-> target's representation).
|
| + Therefore, we cannot do a good job at displaying this
|
| + information to the user. It's better to just warn
|
| + her about it (if infrun debugging is enabled), and
|
| + give up. */
|
| + if (debug_infrun)
|
| + fprintf_filtered (gdb_stdlog, _("\
|
| +Cannot fill $_exitsignal with the correct signal number.\n"));
|
| + }
|
| +
|
| + print_signal_exited_reason (ecs->ws.value.sig);
|
| + }
|
|
|
| - print_signal_exited_reason (ecs->ws.value.sig);
|
| + gdb_flush (gdb_stdout);
|
| + target_mourn_inferior ();
|
| singlestep_breakpoints_inserted_p = 0;
|
| cancel_single_step_breakpoints ();
|
| + stop_print_frame = 0;
|
| stop_stepping (ecs);
|
| return;
|
|
|
| @@ -3425,7 +3507,12 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| case TARGET_WAITKIND_FORKED:
|
| case TARGET_WAITKIND_VFORKED:
|
| if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
|
| + {
|
| + if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
|
| + else
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORKED\n");
|
| + }
|
|
|
| /* Check whether the inferior is displaced stepping. */
|
| {
|
| @@ -3498,11 +3585,9 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| vfork follow are detached. */
|
| if (ecs->ws.kind != TARGET_WAITKIND_VFORKED)
|
| {
|
| - int child_pid = ptid_get_pid (ecs->ws.value.related_pid);
|
| -
|
| /* This won't actually modify the breakpoint list, but will
|
| physically remove the breakpoints from the child. */
|
| - detach_breakpoints (child_pid);
|
| + detach_breakpoints (ecs->ws.value.related_pid);
|
| }
|
|
|
| if (singlestep_breakpoints_inserted_p)
|
| @@ -3523,15 +3608,11 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
| stop_pc, ecs->ptid, &ecs->ws);
|
|
|
| - /* Note that we're interested in knowing the bpstat actually
|
| - causes a stop, not just if it may explain the signal.
|
| - Software watchpoints, for example, always appear in the
|
| - bpstat. */
|
| - ecs->random_signal
|
| - = !bpstat_causes_stop (ecs->event_thread->control.stop_bpstat);
|
| -
|
| - /* If no catchpoint triggered for this, then keep going. */
|
| - if (ecs->random_signal)
|
| + /* If no catchpoint triggered for this, then keep going. Note
|
| + that we're interested in knowing the bpstat actually causes a
|
| + stop, not just if it may explain the signal. Software
|
| + watchpoints, for example, always appear in the bpstat. */
|
| + if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
|
| {
|
| ptid_t parent;
|
| ptid_t child;
|
| @@ -3573,8 +3654,8 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| stop_stepping (ecs);
|
| return;
|
| }
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
| - goto process_event_stop_test;
|
| + process_event_stop_test (ecs);
|
| + return;
|
|
|
| case TARGET_WAITKIND_VFORK_DONE:
|
| /* Done with the shared memory region. Re-insert breakpoints in
|
| @@ -3617,8 +3698,6 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| ecs->event_thread->control.stop_bpstat
|
| = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
| stop_pc, ecs->ptid, &ecs->ws);
|
| - ecs->random_signal
|
| - = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
|
|
| /* Note that this may be referenced from inside
|
| bpstat_stop_status above, through inferior_has_execd. */
|
| @@ -3626,14 +3705,14 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| ecs->ws.value.execd_pathname = NULL;
|
|
|
| /* If no catchpoint triggered for this, then keep going. */
|
| - if (ecs->random_signal)
|
| + if (!bpstat_causes_stop (ecs->event_thread->control.stop_bpstat))
|
| {
|
| ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| keep_going (ecs);
|
| return;
|
| }
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
| - goto process_event_stop_test;
|
| + process_event_stop_test (ecs);
|
| + return;
|
|
|
| /* Be careful not to try to gather much state about a thread
|
| that's in a syscall. It's frequently a losing proposition. */
|
| @@ -3642,9 +3721,9 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
|
| /* Getting the current syscall number. */
|
| - if (handle_syscall_event (ecs) != 0)
|
| - return;
|
| - goto process_event_stop_test;
|
| + if (handle_syscall_event (ecs) == 0)
|
| + process_event_stop_test (ecs);
|
| + return;
|
|
|
| /* Before examining the threads further, step this thread to
|
| get it entirely out of the syscall. (We get notice of the
|
| @@ -3655,25 +3734,47 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
|
| - if (handle_syscall_event (ecs) != 0)
|
| - return;
|
| - goto process_event_stop_test;
|
| + if (handle_syscall_event (ecs) == 0)
|
| + process_event_stop_test (ecs);
|
| + return;
|
|
|
| case TARGET_WAITKIND_STOPPED:
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
|
| ecs->event_thread->suspend.stop_signal = ecs->ws.value.sig;
|
| - break;
|
| + handle_signal_stop (ecs);
|
| + return;
|
|
|
| case TARGET_WAITKIND_NO_HISTORY:
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
|
| /* Reverse execution: target ran out of history info. */
|
| +
|
| + /* Pull the single step breakpoints out of the target. */
|
| + if (singlestep_breakpoints_inserted_p)
|
| + {
|
| + if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| + context_switch (ecs->ptid);
|
| + remove_single_step_breakpoints ();
|
| + singlestep_breakpoints_inserted_p = 0;
|
| + }
|
| stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
|
| print_no_history_reason ();
|
| stop_stepping (ecs);
|
| return;
|
| }
|
| +}
|
| +
|
| +/* Come here when the program has stopped with a signal. */
|
| +
|
| +static void
|
| +handle_signal_stop (struct execution_control_state *ecs)
|
| +{
|
| + struct frame_info *frame;
|
| + struct gdbarch *gdbarch;
|
| + int stopped_by_watchpoint;
|
| + enum stop_kind stop_soon;
|
| + int random_signal;
|
|
|
| if (ecs->ws.kind == TARGET_WAITKIND_STOPPED)
|
| {
|
| @@ -3722,6 +3823,63 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| do_cleanups (old_chain);
|
| }
|
|
|
| + /* This is originated from start_remote(), start_inferior() and
|
| + shared libraries hook functions. */
|
| + stop_soon = get_inferior_stop_soon (ecs->ptid);
|
| + if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
|
| + {
|
| + if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| + context_switch (ecs->ptid);
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
| + stop_print_frame = 1;
|
| + stop_stepping (ecs);
|
| + return;
|
| + }
|
| +
|
| + if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| + && stop_after_trap)
|
| + {
|
| + if (!ptid_equal (ecs->ptid, inferior_ptid))
|
| + context_switch (ecs->ptid);
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
|
| + stop_print_frame = 0;
|
| + stop_stepping (ecs);
|
| + return;
|
| + }
|
| +
|
| + /* This originates from attach_command(). We need to overwrite
|
| + the stop_signal here, because some kernels don't ignore a
|
| + SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
|
| + See more comments in inferior.h. On the other hand, if we
|
| + get a non-SIGSTOP, report it to the user - assume the backend
|
| + will handle the SIGSTOP if it should show up later.
|
| +
|
| + Also consider that the attach is complete when we see a
|
| + 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.
|
| +
|
| + Also consider that the attach is complete when we see a
|
| + GDB_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
|
| + GDB_SIGNAL_0, meaning: stopped for no particular reason
|
| + other than GDB's request. */
|
| + if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
| + && (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_STOP
|
| + || ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| + || ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0))
|
| + {
|
| + stop_print_frame = 1;
|
| + stop_stepping (ecs);
|
| + ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| + return;
|
| + }
|
| +
|
| if (stepping_past_singlestep_breakpoint)
|
| {
|
| gdb_assert (singlestep_breakpoints_inserted_p);
|
| @@ -3745,12 +3903,11 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| remove_single_step_breakpoints ();
|
| singlestep_breakpoints_inserted_p = 0;
|
|
|
| - ecs->random_signal = 0;
|
| ecs->event_thread->control.trap_expected = 0;
|
|
|
| context_switch (saved_singlestep_ptid);
|
| if (deprecated_context_hook)
|
| - deprecated_context_hook (pid_to_thread_id (ecs->ptid));
|
| + deprecated_context_hook (pid_to_thread_id (saved_singlestep_ptid));
|
|
|
| resume (1, GDB_SIGNAL_0);
|
| prepare_to_wait (ecs);
|
| @@ -3810,7 +3967,6 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| not see this breakpoint hit when stepping onto breakpoints. */
|
| if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
|
| {
|
| - ecs->random_signal = 0;
|
| if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
|
| thread_hop_needed = 1;
|
| }
|
| @@ -3824,7 +3980,6 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| "trap for %s\n",
|
| target_pid_to_str (ecs->ptid));
|
|
|
| - ecs->random_signal = 0;
|
| /* The call to in_thread_list is necessary because PTIDs sometimes
|
| change when we go from single-threaded to multi-threaded. If
|
| the singlestep_ptid is still in the list, assume that it is
|
| @@ -3938,13 +4093,7 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| return;
|
| }
|
| }
|
| - else if (singlestep_breakpoints_inserted_p)
|
| - {
|
| - ecs->random_signal = 0;
|
| - }
|
| }
|
| - else
|
| - ecs->random_signal = 1;
|
|
|
| /* See if something interesting happened to the non-current thread. If
|
| so, then switch to that thread. */
|
| @@ -3970,7 +4119,7 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| singlestep_breakpoints_inserted_p = 0;
|
| }
|
|
|
| - if (stepped_after_stopped_by_watchpoint)
|
| + if (ecs->stepped_after_stopped_by_watchpoint)
|
| stopped_by_watchpoint = 0;
|
| else
|
| stopped_by_watchpoint = watchpoints_triggered (&ecs->ws);
|
| @@ -4022,12 +4171,10 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| return;
|
| }
|
|
|
| - clear_stop_func (ecs);
|
| ecs->event_thread->stepping_over_breakpoint = 0;
|
| bpstat_clear (&ecs->event_thread->control.stop_bpstat);
|
| ecs->event_thread->control.stop_step = 0;
|
| stop_print_frame = 1;
|
| - ecs->random_signal = 0;
|
| stopped_by_random_signal = 0;
|
|
|
| /* Hide inlined functions starting here, unless we just performed stepi or
|
| @@ -4105,174 +4252,97 @@ handle_inferior_event (struct execution_control_state *ecs)
|
| }
|
| }
|
|
|
| - /* Look at the cause of the stop, and decide what to do.
|
| - 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 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. */
|
| + /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
|
| + handles this event. */
|
| + ecs->event_thread->control.stop_bpstat
|
| + = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
| + stop_pc, ecs->ptid, &ecs->ws);
|
|
|
| - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| - || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
| - || stop_soon == STOP_QUIETLY_REMOTE)
|
| + /* Following in case break condition called a
|
| + function. */
|
| + stop_print_frame = 1;
|
| +
|
| + /* This is where we handle "moribund" watchpoints. Unlike
|
| + software breakpoints traps, hardware watchpoint traps are
|
| + always distinguishable from random traps. If no high-level
|
| + watchpoint is associated with the reported stop data address
|
| + anymore, then the bpstat does not explain the signal ---
|
| + simply make sure to ignore it if `stopped_by_watchpoint' is
|
| + set. */
|
| +
|
| + if (debug_infrun
|
| + && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| + && !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
|
| + GDB_SIGNAL_TRAP)
|
| + && stopped_by_watchpoint)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: no user watchpoint explains "
|
| + "watchpoint SIGTRAP, ignoring\n");
|
| +
|
| + /* NOTE: cagney/2003-03-29: These checks for a random signal
|
| + at one stage in the past included checks for an inferior
|
| + function call's call dummy's return breakpoint. The original
|
| + comment, that went with the test, read:
|
| +
|
| + ``End of a stack dummy. Some systems (e.g. Sony news) give
|
| + another signal besides SIGTRAP, so check here as well as
|
| + above.''
|
| +
|
| + If someone ever tries to get call dummys on a
|
| + non-executable stack to work (where the target would stop
|
| + with something like a SIGSEGV), then those tests might need
|
| + to be re-instated. Given, however, that the tests were only
|
| + enabled when momentary breakpoints were not being used, I
|
| + suspect that it won't be the case.
|
| +
|
| + NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
|
| + be necessary for call dummies on a non-executable stack on
|
| + SPARC. */
|
| +
|
| + /* See if the breakpoints module can explain the signal. */
|
| + random_signal
|
| + = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
|
| + ecs->event_thread->suspend.stop_signal);
|
| +
|
| + /* If not, perhaps stepping/nexting can. */
|
| + if (random_signal)
|
| + random_signal = !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| + && currently_stepping (ecs->event_thread));
|
| +
|
| + /* No? Perhaps we got a moribund watchpoint. */
|
| + if (random_signal)
|
| + random_signal = !stopped_by_watchpoint;
|
| +
|
| + /* For the program's own signals, act according to
|
| + the signal handling tables. */
|
| +
|
| + if (random_signal)
|
| {
|
| - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| - && stop_after_trap)
|
| - {
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
|
| - stop_print_frame = 0;
|
| - stop_stepping (ecs);
|
| - return;
|
| - }
|
| + /* Signal not for debugging purposes. */
|
| + int printed = 0;
|
| + struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
|
| + enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal;
|
| +
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: random signal (%s)\n",
|
| + gdb_signal_to_symbol_string (stop_signal));
|
| +
|
| + stopped_by_random_signal = 1;
|
|
|
| - /* This is originated from start_remote(), start_inferior() and
|
| - shared libraries hook functions. */
|
| - if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
|
| + if (signal_print[ecs->event_thread->suspend.stop_signal])
|
| {
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
| - stop_stepping (ecs);
|
| - return;
|
| + printed = 1;
|
| + target_terminal_ours_for_output ();
|
| + print_signal_received_reason
|
| + (ecs->event_thread->suspend.stop_signal);
|
| }
|
| -
|
| - /* This originates from attach_command(). We need to overwrite
|
| - the stop_signal here, because some kernels don't ignore a
|
| - SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
|
| - See more comments in inferior.h. On the other hand, if we
|
| - get a non-SIGSTOP, report it to the user - assume the backend
|
| - will handle the SIGSTOP if it should show up later.
|
| -
|
| - Also consider that the attach is complete when we see a
|
| - 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.
|
| -
|
| - Also consider that the attach is complete when we see a
|
| - GDB_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
|
| - GDB_SIGNAL_0, meaning: stopped for no particular reason
|
| - other than GDB's request. */
|
| - if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
| - && (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_STOP
|
| - || ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| - || ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0))
|
| - {
|
| - stop_stepping (ecs);
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| - return;
|
| - }
|
| -
|
| - /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
|
| - handles this event. */
|
| - ecs->event_thread->control.stop_bpstat
|
| - = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
| - stop_pc, ecs->ptid, &ecs->ws);
|
| -
|
| - /* Following in case break condition called a
|
| - function. */
|
| - stop_print_frame = 1;
|
| -
|
| - /* This is where we handle "moribund" watchpoints. Unlike
|
| - software breakpoints traps, hardware watchpoint traps are
|
| - always distinguishable from random traps. If no high-level
|
| - watchpoint is associated with the reported stop data address
|
| - anymore, then the bpstat does not explain the signal ---
|
| - simply make sure to ignore it if `stopped_by_watchpoint' is
|
| - set. */
|
| -
|
| - if (debug_infrun
|
| - && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| - && !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
| - && stopped_by_watchpoint)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: no user watchpoint explains "
|
| - "watchpoint SIGTRAP, ignoring\n");
|
| -
|
| - /* NOTE: cagney/2003-03-29: These two checks for a random signal
|
| - at one stage in the past included checks for an inferior
|
| - function call's call dummy's return breakpoint. The original
|
| - comment, that went with the test, read:
|
| -
|
| - ``End of a stack dummy. Some systems (e.g. Sony news) give
|
| - another signal besides SIGTRAP, so check here as well as
|
| - above.''
|
| -
|
| - If someone ever tries to get call dummys on a
|
| - non-executable stack to work (where the target would stop
|
| - with something like a SIGSEGV), then those tests might need
|
| - to be re-instated. Given, however, that the tests were only
|
| - enabled when momentary breakpoints were not being used, I
|
| - suspect that it won't be the case.
|
| -
|
| - NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
|
| - be necessary for call dummies on a non-executable stack on
|
| - SPARC. */
|
| -
|
| - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
|
| - ecs->random_signal
|
| - = !(bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
| - || stopped_by_watchpoint
|
| - || ecs->event_thread->control.trap_expected
|
| - || (ecs->event_thread->control.step_range_end
|
| - && (ecs->event_thread->control.step_resume_breakpoint
|
| - == NULL)));
|
| - else
|
| - {
|
| - ecs->random_signal = !bpstat_explains_signal
|
| - (ecs->event_thread->control.stop_bpstat);
|
| - if (!ecs->random_signal)
|
| - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
| - }
|
| - }
|
| -
|
| - /* When we reach this point, we've pretty much decided
|
| - that the reason for stopping must've been a random
|
| - (unexpected) signal. */
|
| -
|
| - else
|
| - ecs->random_signal = 1;
|
| -
|
| -process_event_stop_test:
|
| -
|
| - /* Re-fetch current thread's frame in case we did a
|
| - "goto process_event_stop_test" above. */
|
| - frame = get_current_frame ();
|
| - gdbarch = get_frame_arch (frame);
|
| -
|
| - /* For the program's own signals, act according to
|
| - the signal handling tables. */
|
| -
|
| - if (ecs->random_signal)
|
| - {
|
| - /* Signal not for debugging purposes. */
|
| - int printed = 0;
|
| - struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
|
| -
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n",
|
| - ecs->event_thread->suspend.stop_signal);
|
| -
|
| - stopped_by_random_signal = 1;
|
| -
|
| - if (signal_print[ecs->event_thread->suspend.stop_signal])
|
| - {
|
| - printed = 1;
|
| - target_terminal_ours_for_output ();
|
| - print_signal_received_reason
|
| - (ecs->event_thread->suspend.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
|
| - || (!inf->detaching
|
| - && signal_stop_state (ecs->event_thread->suspend.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
|
| + || (!inf->detaching
|
| + && signal_stop_state (ecs->event_thread->suspend.stop_signal)))
|
| {
|
| stop_stepping (ecs);
|
| return;
|
| @@ -4315,8 +4385,7 @@ process_event_stop_test:
|
|
|
| if (ecs->event_thread->control.step_range_end != 0
|
| && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
|
| - && (ecs->event_thread->control.step_range_start <= stop_pc
|
| - && stop_pc < ecs->event_thread->control.step_range_end)
|
| + && pc_in_thread_step_range (stop_pc, ecs->event_thread)
|
| && frame_id_eq (get_stack_frame_id (frame),
|
| ecs->event_thread->control.step_stack_frame_id)
|
| && ecs->event_thread->control.step_resume_breakpoint == NULL)
|
| @@ -4348,304 +4417,262 @@ process_event_stop_test:
|
| (leaving the inferior at the step-resume-breakpoint without
|
| actually executing it). Either way continue until the
|
| breakpoint is really hit. */
|
| - }
|
| - else
|
| - {
|
| - /* Handle cases caused by hitting a breakpoint. */
|
| -
|
| - CORE_ADDR jmp_buf_pc;
|
| - struct bpstat_what what;
|
| -
|
| - what = bpstat_what (ecs->event_thread->control.stop_bpstat);
|
|
|
| - if (what.call_dummy)
|
| + if (!switch_back_to_stepped_thread (ecs))
|
| {
|
| - stop_stack_dummy = what.call_dummy;
|
| - }
|
| -
|
| - /* If we hit an internal event that triggers symbol changes, the
|
| - current frame will be invalidated within bpstat_what (e.g.,
|
| - if we hit an internal solib event). Re-fetch it. */
|
| - frame = get_current_frame ();
|
| - gdbarch = get_frame_arch (frame);
|
| -
|
| - switch (what.main_action)
|
| - {
|
| - case BPSTAT_WHAT_SET_LONGJMP_RESUME:
|
| - /* If we hit the breakpoint at longjmp while stepping, we
|
| - install a momentary breakpoint at the target of the
|
| - jmp_buf. */
|
| -
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
|
| -
|
| - ecs->event_thread->stepping_over_breakpoint = 1;
|
| -
|
| - if (what.is_longjmp)
|
| - {
|
| - struct value *arg_value;
|
| -
|
| - /* If we set the longjmp breakpoint via a SystemTap
|
| - probe, then use it to extract the arguments. The
|
| - destination PC is the third argument to the
|
| - probe. */
|
| - arg_value = probe_safe_evaluate_at_pc (frame, 2);
|
| - if (arg_value)
|
| - jmp_buf_pc = value_as_address (arg_value);
|
| - else if (!gdbarch_get_longjmp_target_p (gdbarch)
|
| - || !gdbarch_get_longjmp_target (gdbarch,
|
| - frame, &jmp_buf_pc))
|
| - {
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME "
|
| - "(!gdbarch_get_longjmp_target)\n");
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| + "infrun: random signal, keep going\n");
|
|
|
| - /* Insert a breakpoint at resume address. */
|
| - insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
|
| - }
|
| - else
|
| - check_exception_resume (ecs, frame);
|
| keep_going (ecs);
|
| - return;
|
| + }
|
| + return;
|
| + }
|
|
|
| - case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
|
| - {
|
| - struct frame_info *init_frame;
|
| + process_event_stop_test (ecs);
|
| +}
|
|
|
| - /* There are several cases to consider.
|
| +/* Come here when we've got some debug event / signal we can explain
|
| + (IOW, not a random signal), and test whether it should cause a
|
| + stop, or whether we should resume the inferior (transparently).
|
| + E.g., could be a breakpoint whose condition evaluates false; we
|
| + could be still stepping within the line; etc. */
|
|
|
| - 1. The initiating frame no longer exists. In this case
|
| - we must stop, because the exception or longjmp has gone
|
| - too far.
|
| +static void
|
| +process_event_stop_test (struct execution_control_state *ecs)
|
| +{
|
| + struct symtab_and_line stop_pc_sal;
|
| + struct frame_info *frame;
|
| + struct gdbarch *gdbarch;
|
| + CORE_ADDR jmp_buf_pc;
|
| + struct bpstat_what what;
|
|
|
| - 2. The initiating frame exists, and is the same as the
|
| - current frame. We stop, because the exception or
|
| - longjmp has been caught.
|
| + /* Handle cases caused by hitting a breakpoint. */
|
|
|
| - 3. The initiating frame exists and is different from
|
| - the current frame. This means the exception or longjmp
|
| - has been caught beneath the initiating frame, so keep
|
| - going.
|
| + frame = get_current_frame ();
|
| + gdbarch = get_frame_arch (frame);
|
|
|
| - 4. longjmp breakpoint has been placed just to protect
|
| - against stale dummy frames and user is not interested
|
| - in stopping around longjmps. */
|
| + what = bpstat_what (ecs->event_thread->control.stop_bpstat);
|
|
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
|
| + if (what.call_dummy)
|
| + {
|
| + stop_stack_dummy = what.call_dummy;
|
| + }
|
|
|
| - gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
|
| - != NULL);
|
| - delete_exception_resume_breakpoint (ecs->event_thread);
|
| + /* If we hit an internal event that triggers symbol changes, the
|
| + current frame will be invalidated within bpstat_what (e.g., if we
|
| + hit an internal solib event). Re-fetch it. */
|
| + frame = get_current_frame ();
|
| + gdbarch = get_frame_arch (frame);
|
|
|
| - if (what.is_longjmp)
|
| - {
|
| - check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
|
| + switch (what.main_action)
|
| + {
|
| + case BPSTAT_WHAT_SET_LONGJMP_RESUME:
|
| + /* If we hit the breakpoint at longjmp while stepping, we
|
| + install a momentary breakpoint at the target of the
|
| + jmp_buf. */
|
|
|
| - if (!frame_id_p (ecs->event_thread->initiating_frame))
|
| - {
|
| - /* Case 4. */
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| - }
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
|
|
|
| - init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
|
| + ecs->event_thread->stepping_over_breakpoint = 1;
|
|
|
| - if (init_frame)
|
| - {
|
| - struct frame_id current_id
|
| - = get_frame_id (get_current_frame ());
|
| - if (frame_id_eq (current_id,
|
| - ecs->event_thread->initiating_frame))
|
| - {
|
| - /* Case 2. Fall through. */
|
| - }
|
| - else
|
| - {
|
| - /* Case 3. */
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| - }
|
| + if (what.is_longjmp)
|
| + {
|
| + struct value *arg_value;
|
| +
|
| + /* If we set the longjmp breakpoint via a SystemTap probe,
|
| + then use it to extract the arguments. The destination PC
|
| + is the third argument to the probe. */
|
| + arg_value = probe_safe_evaluate_at_pc (frame, 2);
|
| + if (arg_value)
|
| + jmp_buf_pc = value_as_address (arg_value);
|
| + else if (!gdbarch_get_longjmp_target_p (gdbarch)
|
| + || !gdbarch_get_longjmp_target (gdbarch,
|
| + frame, &jmp_buf_pc))
|
| + {
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME "
|
| + "(!gdbarch_get_longjmp_target)\n");
|
| + keep_going (ecs);
|
| + return;
|
| + }
|
|
|
| - /* For Cases 1 and 2, remove the step-resume breakpoint,
|
| - if it exists. */
|
| - delete_step_resume_breakpoint (ecs->event_thread);
|
| + /* Insert a breakpoint at resume address. */
|
| + insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
|
| + }
|
| + else
|
| + check_exception_resume (ecs, frame);
|
| + keep_going (ecs);
|
| + return;
|
|
|
| - ecs->event_thread->control.stop_step = 1;
|
| - print_end_stepping_range_reason ();
|
| - stop_stepping (ecs);
|
| - }
|
| - return;
|
| + case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
|
| + {
|
| + struct frame_info *init_frame;
|
|
|
| - case BPSTAT_WHAT_SINGLE:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n");
|
| - 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;
|
| + /* There are several cases to consider.
|
|
|
| - case BPSTAT_WHAT_STEP_RESUME:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
|
| + 1. The initiating frame no longer exists. In this case we
|
| + must stop, because the exception or longjmp has gone too
|
| + far.
|
|
|
| - delete_step_resume_breakpoint (ecs->event_thread);
|
| - if (ecs->event_thread->control.proceed_to_finish
|
| - && execution_direction == EXEC_REVERSE)
|
| - {
|
| - struct thread_info *tp = ecs->event_thread;
|
| -
|
| - /* We are finishing a function in reverse, and just hit
|
| - the step-resume breakpoint at the start address of
|
| - the function, and we're almost there -- just need to
|
| - back up by one more single-step, which should take us
|
| - back to the function call. */
|
| - tp->control.step_range_start = tp->control.step_range_end = 1;
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| - fill_in_stop_func (gdbarch, ecs);
|
| - if (stop_pc == ecs->stop_func_start
|
| - && execution_direction == EXEC_REVERSE)
|
| - {
|
| - /* We are stepping over a function call in reverse, and
|
| - 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. */
|
| - ecs->event_thread->stepping_over_breakpoint = 1;
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| - break;
|
| + 2. The initiating frame exists, and is the same as the
|
| + current frame. We stop, because the exception or longjmp
|
| + has been caught.
|
|
|
| - case BPSTAT_WHAT_STOP_NOISY:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
|
| - stop_print_frame = 1;
|
| + 3. The initiating frame exists and is different from the
|
| + current frame. This means the exception or longjmp has
|
| + been caught beneath the initiating frame, so keep going.
|
|
|
| - /* We are about to nuke the step_resume_breakpointt via the
|
| - cleanup chain, so no need to worry about it here. */
|
| + 4. longjmp breakpoint has been placed just to protect
|
| + against stale dummy frames and user is not interested in
|
| + stopping around longjmps. */
|
|
|
| - stop_stepping (ecs);
|
| - return;
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
|
|
|
| - case BPSTAT_WHAT_STOP_SILENT:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
|
| - stop_print_frame = 0;
|
| + gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
|
| + != NULL);
|
| + delete_exception_resume_breakpoint (ecs->event_thread);
|
|
|
| - /* We are about to nuke the step_resume_breakpoin via the
|
| - cleanup chain, so no need to worry about it here. */
|
| + if (what.is_longjmp)
|
| + {
|
| + check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
|
|
|
| - stop_stepping (ecs);
|
| - return;
|
| + if (!frame_id_p (ecs->event_thread->initiating_frame))
|
| + {
|
| + /* Case 4. */
|
| + keep_going (ecs);
|
| + return;
|
| + }
|
| + }
|
|
|
| - case BPSTAT_WHAT_HP_STEP_RESUME:
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
|
| + init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
|
|
|
| - 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. */
|
| - ecs->event_thread->step_after_step_resume_breakpoint = 0;
|
| - ecs->event_thread->stepping_over_breakpoint = 1;
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| - break;
|
| + if (init_frame)
|
| + {
|
| + struct frame_id current_id
|
| + = get_frame_id (get_current_frame ());
|
| + if (frame_id_eq (current_id,
|
| + ecs->event_thread->initiating_frame))
|
| + {
|
| + /* Case 2. Fall through. */
|
| + }
|
| + else
|
| + {
|
| + /* Case 3. */
|
| + keep_going (ecs);
|
| + return;
|
| + }
|
| + }
|
|
|
| - case BPSTAT_WHAT_KEEP_CHECKING:
|
| - break;
|
| - }
|
| - }
|
| + /* For Cases 1 and 2, remove the step-resume breakpoint, if it
|
| + exists. */
|
| + delete_step_resume_breakpoint (ecs->event_thread);
|
|
|
| - /* We come here if we hit a breakpoint but should not
|
| - stop for it. Possibly we also were stepping
|
| - and should stop for that. So fall through and
|
| - test for stepping. But, if not stepping,
|
| - do not stop. */
|
| + ecs->event_thread->control.stop_step = 1;
|
| + print_end_stepping_range_reason ();
|
| + stop_stepping (ecs);
|
| + }
|
| + return;
|
|
|
| - /* 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;
|
| + case BPSTAT_WHAT_SINGLE:
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n");
|
| + 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;
|
|
|
| - tp = iterate_over_threads (currently_stepping_or_nexting_callback,
|
| - ecs->event_thread);
|
| - if (tp)
|
| + case BPSTAT_WHAT_STEP_RESUME:
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
|
| +
|
| + delete_step_resume_breakpoint (ecs->event_thread);
|
| + if (ecs->event_thread->control.proceed_to_finish
|
| + && execution_direction == EXEC_REVERSE)
|
| {
|
| - /* 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->control.trap_expected
|
| - && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
|
| - || ecs->event_thread->stepping_over_breakpoint)
|
| - {
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| + struct thread_info *tp = ecs->event_thread;
|
| +
|
| + /* We are finishing a function in reverse, and just hit the
|
| + step-resume breakpoint at the start address of the
|
| + function, and we're almost there -- just need to back up
|
| + by one more single-step, which should take us back to the
|
| + function call. */
|
| + tp->control.step_range_start = tp->control.step_range_end = 1;
|
| + keep_going (ecs);
|
| + return;
|
| + }
|
| + fill_in_stop_func (gdbarch, ecs);
|
| + if (stop_pc == ecs->stop_func_start
|
| + && execution_direction == EXEC_REVERSE)
|
| + {
|
| + /* We are stepping over a function call in reverse, and 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. */
|
| + ecs->event_thread->stepping_over_breakpoint = 1;
|
| + keep_going (ecs);
|
| + return;
|
| + }
|
| + break;
|
|
|
| - /* If the stepping thread exited, then don't try to switch
|
| - back and resume it, which could fail in several different
|
| - ways depending on the target. Instead, just keep going.
|
| + case BPSTAT_WHAT_STOP_NOISY:
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
|
| + stop_print_frame = 1;
|
|
|
| - We can find a stepping dead thread in the thread list in
|
| - two cases:
|
| + /* We are about to nuke the step_resume_breakpointt via the
|
| + cleanup chain, so no need to worry about it here. */
|
|
|
| - - The target supports thread exit events, and when the
|
| - target tries to delete the thread from the thread list,
|
| - inferior_ptid pointed at the exiting thread. In such
|
| - case, calling delete_thread does not really remove the
|
| - thread from the list; instead, the thread is left listed,
|
| - with 'exited' state.
|
| + stop_stepping (ecs);
|
| + return;
|
|
|
| - - The target's debug interface does not support thread
|
| - exit events, and so we have no idea whatsoever if the
|
| - previously stepping thread is still alive. For that
|
| - reason, we need to synchronously query the target
|
| - now. */
|
| - if (is_exited (tp->ptid)
|
| - || !target_thread_alive (tp->ptid))
|
| - {
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: not switching back to "
|
| - "stepped thread, it has vanished\n");
|
| + case BPSTAT_WHAT_STOP_SILENT:
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
|
| + stop_print_frame = 0;
|
|
|
| - delete_thread (tp->ptid);
|
| - keep_going (ecs);
|
| - return;
|
| - }
|
| + /* We are about to nuke the step_resume_breakpoin via the
|
| + cleanup chain, so no need to worry about it here. */
|
|
|
| - /* 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->control.trap_expected = 0;
|
| + stop_stepping (ecs);
|
| + return;
|
|
|
| - if (debug_infrun)
|
| - fprintf_unfiltered (gdb_stdlog,
|
| - "infrun: switching back to stepped thread\n");
|
| + case BPSTAT_WHAT_HP_STEP_RESUME:
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
|
|
|
| - ecs->event_thread = tp;
|
| - ecs->ptid = tp->ptid;
|
| - context_switch (ecs->ptid);
|
| + 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. */
|
| + ecs->event_thread->step_after_step_resume_breakpoint = 0;
|
| + ecs->event_thread->stepping_over_breakpoint = 1;
|
| keep_going (ecs);
|
| return;
|
| }
|
| + break;
|
| +
|
| + case BPSTAT_WHAT_KEEP_CHECKING:
|
| + break;
|
| }
|
|
|
| + /* We come here if we hit a breakpoint but should not stop for it.
|
| + Possibly we also were stepping and should stop for that. So fall
|
| + through and 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 (switch_back_to_stepped_thread (ecs))
|
| + return;
|
| +
|
| if (ecs->event_thread->control.step_resume_breakpoint)
|
| {
|
| if (debug_infrun)
|
| @@ -4685,8 +4712,7 @@ process_event_stop_test:
|
| through a function epilogue and therefore must detect when
|
| the current-frame changes in the middle of a line. */
|
|
|
| - if (stop_pc >= ecs->event_thread->control.step_range_start
|
| - && stop_pc < ecs->event_thread->control.step_range_end
|
| + if (pc_in_thread_step_range (stop_pc, ecs->event_thread)
|
| && (execution_direction != EXEC_REVERSE
|
| || frame_id_eq (get_frame_id (frame),
|
| ecs->event_thread->control.step_frame_id)))
|
| @@ -4697,6 +4723,11 @@ process_event_stop_test:
|
| paddress (gdbarch, ecs->event_thread->control.step_range_start),
|
| paddress (gdbarch, ecs->event_thread->control.step_range_end));
|
|
|
| + /* Tentatively re-enable range stepping; `resume' disables it if
|
| + necessary (e.g., if we're stepping over a breakpoint or we
|
| + have software watchpoints). */
|
| + ecs->event_thread->control.may_range_step = 1;
|
| +
|
| /* 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). */
|
| @@ -4901,7 +4932,7 @@ process_event_stop_test:
|
| or stepped back out of a signal handler to the first instruction
|
| of the function. Just keep going, which will single-step back
|
| to the caller. */
|
| - if (ecs->stop_func_start != stop_pc)
|
| + if (ecs->stop_func_start != stop_pc && ecs->stop_func_start != 0)
|
| {
|
| struct symtab_and_line sr_sal;
|
|
|
| @@ -4957,7 +4988,8 @@ process_event_stop_test:
|
|
|
| tmp_sal = find_pc_line (ecs->stop_func_start, 0);
|
| if (tmp_sal.line != 0
|
| - && !function_pc_is_marked_for_skip (ecs->stop_func_start))
|
| + && !function_name_is_marked_for_skip (ecs->stop_func_name,
|
| + &tmp_sal))
|
| {
|
| if (execution_direction == EXEC_REVERSE)
|
| handle_step_into_function_backward (gdbarch, ecs);
|
| @@ -5212,6 +5244,7 @@ process_event_stop_test:
|
|
|
| ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
|
| ecs->event_thread->control.step_range_end = stop_pc_sal.end;
|
| + ecs->event_thread->control.may_range_step = 1;
|
| set_step_info (frame, stop_pc_sal);
|
|
|
| if (debug_infrun)
|
| @@ -5219,6 +5252,84 @@ process_event_stop_test:
|
| keep_going (ecs);
|
| }
|
|
|
| +/* In all-stop mode, if we're currently stepping but have stopped in
|
| + some other thread, we may need to switch back to the stepped
|
| + thread. Returns true we set the inferior running, false if we left
|
| + it stopped (and the event needs further processing). */
|
| +
|
| +static int
|
| +switch_back_to_stepped_thread (struct execution_control_state *ecs)
|
| +{
|
| + if (!non_stop)
|
| + {
|
| + struct thread_info *tp;
|
| +
|
| + tp = iterate_over_threads (currently_stepping_or_nexting_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->control.trap_expected
|
| + && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
|
| + || ecs->event_thread->stepping_over_breakpoint)
|
| + {
|
| + keep_going (ecs);
|
| + return 1;
|
| + }
|
| +
|
| + /* If the stepping thread exited, then don't try to switch
|
| + back and resume it, which could fail in several different
|
| + ways depending on the target. Instead, just keep going.
|
| +
|
| + We can find a stepping dead thread in the thread list in
|
| + two cases:
|
| +
|
| + - The target supports thread exit events, and when the
|
| + target tries to delete the thread from the thread list,
|
| + inferior_ptid pointed at the exiting thread. In such
|
| + case, calling delete_thread does not really remove the
|
| + thread from the list; instead, the thread is left listed,
|
| + with 'exited' state.
|
| +
|
| + - The target's debug interface does not support thread
|
| + exit events, and so we have no idea whatsoever if the
|
| + previously stepping thread is still alive. For that
|
| + reason, we need to synchronously query the target
|
| + now. */
|
| + if (is_exited (tp->ptid)
|
| + || !target_thread_alive (tp->ptid))
|
| + {
|
| + if (debug_infrun)
|
| + fprintf_unfiltered (gdb_stdlog,
|
| + "infrun: not switching back to "
|
| + "stepped thread, it has vanished\n");
|
| +
|
| + delete_thread (tp->ptid);
|
| + keep_going (ecs);
|
| + return 1;
|
| + }
|
| +
|
| + /* 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->control.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 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| /* Is thread TP in the middle of single-stepping? */
|
|
|
| static int
|
| @@ -5534,7 +5645,6 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
|
| static void
|
| insert_exception_resume_from_probe (struct thread_info *tp,
|
| const struct probe *probe,
|
| - struct objfile *objfile,
|
| struct frame_info *frame)
|
| {
|
| struct value *arg_value;
|
| @@ -5550,7 +5660,7 @@ insert_exception_resume_from_probe (struct thread_info *tp,
|
| if (debug_infrun)
|
| fprintf_unfiltered (gdb_stdlog,
|
| "infrun: exception resume at %s\n",
|
| - paddress (get_objfile_arch (objfile),
|
| + paddress (get_objfile_arch (probe->objfile),
|
| handler));
|
|
|
| bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
|
| @@ -5568,7 +5678,6 @@ check_exception_resume (struct execution_control_state *ecs,
|
| struct frame_info *frame)
|
| {
|
| volatile struct gdb_exception e;
|
| - struct objfile *objfile;
|
| const struct probe *probe;
|
| struct symbol *func;
|
|
|
| @@ -5576,11 +5685,10 @@ check_exception_resume (struct execution_control_state *ecs,
|
| SystemTap probe point. If so, the probe has two arguments: the
|
| CFA and the HANDLER. We ignore the CFA, extract the handler, and
|
| set a breakpoint there. */
|
| - probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
|
| + probe = find_probe_by_pc (get_frame_pc (frame));
|
| if (probe)
|
| {
|
| - insert_exception_resume_from_probe (ecs->event_thread, probe,
|
| - objfile, frame);
|
| + insert_exception_resume_from_probe (ecs->event_thread, probe, frame);
|
| return;
|
| }
|
|
|
| @@ -5637,9 +5745,9 @@ stop_stepping (struct execution_control_state *ecs)
|
| ecs->wait_some_more = 0;
|
| }
|
|
|
| -/* This function handles various cases where we need to continue
|
| - waiting for the inferior. */
|
| -/* (Used to be the keep_going: label in the old wait_for_inferior). */
|
| +/* Called when we should continue running the inferior, because the
|
| + current event doesn't cause a user visible stop. This does the
|
| + resuming part; waiting for the next event is done elsewhere. */
|
|
|
| static void
|
| keep_going (struct execution_control_state *ecs)
|
| @@ -5652,16 +5760,13 @@ keep_going (struct execution_control_state *ecs)
|
| ecs->event_thread->prev_pc
|
| = regcache_read_pc (get_thread_regcache (ecs->ptid));
|
|
|
| - /* If we did not do break;, it means we should keep running the
|
| - inferior and not return to debugger. */
|
| -
|
| if (ecs->event_thread->control.trap_expected
|
| && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP)
|
| {
|
| - /* We took a signal (which we are supposed to pass through to
|
| - the inferior, else we'd not get here) and we haven't yet
|
| - gotten our trap. Simply continue. */
|
| -
|
| + /* We haven't yet gotten our trap, and either: intercepted a
|
| + non-signal event (e.g., a fork); or took a signal which we
|
| + are supposed to pass through to the inferior. Simply
|
| + continue. */
|
| discard_cleanups (old_cleanups);
|
| resume (currently_stepping (ecs->event_thread),
|
| ecs->event_thread->suspend.stop_signal);
|
| @@ -5669,34 +5774,35 @@ keep_going (struct execution_control_state *ecs)
|
| else
|
| {
|
| /* Either the trap was not expected, but we are continuing
|
| - anyway (the user asked that this signal be passed to the
|
| - child)
|
| - -- or --
|
| - The signal was SIGTRAP, e.g. it was our signal, but we
|
| - decided we should resume from it.
|
| + anyway (if we got a signal, the user asked it be passed to
|
| + the child)
|
| + -- or --
|
| + We got our expected trap, but decided we should resume from
|
| + it.
|
|
|
| - We're going to run this baby now!
|
| + We're going to run this baby now!
|
|
|
| Note that insert_breakpoints won't try to re-insert
|
| already inserted breakpoints. Therefore, we don't
|
| care if breakpoints were already inserted, or not. */
|
| -
|
| +
|
| if (ecs->event_thread->stepping_over_breakpoint)
|
| {
|
| struct regcache *thread_regcache = get_thread_regcache (ecs->ptid);
|
|
|
| if (!use_displaced_stepping (get_regcache_arch (thread_regcache)))
|
| - /* Since we can't do a displaced step, we have to remove
|
| - the breakpoint while we step it. To keep things
|
| - simple, we remove them all. */
|
| - remove_breakpoints ();
|
| + {
|
| + /* Since we can't do a displaced step, we have to remove
|
| + the breakpoint while we step it. To keep things
|
| + simple, we remove them all. */
|
| + remove_breakpoints ();
|
| + }
|
| }
|
| else
|
| {
|
| volatile struct gdb_exception e;
|
|
|
| - /* Stop stepping when inserting breakpoints
|
| - has failed. */
|
| + /* Stop stepping if inserting breakpoints fails. */
|
| TRY_CATCH (e, RETURN_MASK_ERROR)
|
| {
|
| insert_breakpoints ();
|
| @@ -5712,18 +5818,16 @@ keep_going (struct execution_control_state *ecs)
|
| ecs->event_thread->control.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
|
| - target program).
|
| -
|
| - Typically, this would occure when a user is debugging a
|
| - target monitor on a simulator: the target monitor sets a
|
| - breakpoint; the simulator encounters this break-point and
|
| - halts the simulation handing control to GDB; GDB, noteing
|
| - that the break-point isn't valid, returns control back to the
|
| - simulator; the simulator then delivers the hardware
|
| - equivalent of a SIGNAL_TRAP to the program being debugged. */
|
| -
|
| + /* Do not deliver GDB_SIGNAL_TRAP (except when the user
|
| + explicitly specifies that such a signal should be delivered
|
| + to the target program). Typically, that would occur when a
|
| + user is debugging a target monitor on a simulator: the target
|
| + monitor sets a breakpoint; the simulator encounters this
|
| + breakpoint and halts the simulation handing control to GDB;
|
| + GDB, noting that the stop address doesn't map to any known
|
| + breakpoint, returns control back to the simulator; the
|
| + simulator then delivers the hardware equivalent of a
|
| + GDB_SIGNAL_TRAP to the program being debugged. */
|
| if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
| && !signal_program[ecs->event_thread->suspend.stop_signal])
|
| ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
| @@ -6061,7 +6165,7 @@ normal_stop (void)
|
| LOCATION: Print only location
|
| SRC_AND_LOC: Print location and source line. */
|
| if (do_frame_printing)
|
| - print_stack_frame (get_selected_frame (NULL), 0, source_flag);
|
| + print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
|
|
|
| /* Display the auto-display expressions. */
|
| do_displays ();
|
| @@ -6188,7 +6292,8 @@ signal_cache_update (int signo)
|
|
|
| signal_pass[signo] = (signal_stop[signo] == 0
|
| && signal_print[signo] == 0
|
| - && signal_program[signo] == 1);
|
| + && signal_program[signo] == 1
|
| + && signal_catch[signo] == 0);
|
| }
|
|
|
| int
|
| @@ -6221,6 +6326,20 @@ signal_pass_update (int signo, int state)
|
| return ret;
|
| }
|
|
|
| +/* Update the global 'signal_catch' from INFO and notify the
|
| + target. */
|
| +
|
| +void
|
| +signal_catch_update (const unsigned int *info)
|
| +{
|
| + int i;
|
| +
|
| + for (i = 0; i < GDB_SIGNAL_LAST; ++i)
|
| + signal_catch[i] = info[i] > 0;
|
| + signal_cache_update (-1);
|
| + target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
|
| +}
|
| +
|
| static void
|
| sig_print_header (void)
|
| {
|
| @@ -6428,6 +6547,36 @@ Are you sure you want to change it? "),
|
| do_cleanups (old_chain);
|
| }
|
|
|
| +/* Complete the "handle" command. */
|
| +
|
| +static VEC (char_ptr) *
|
| +handle_completer (struct cmd_list_element *ignore,
|
| + const char *text, const char *word)
|
| +{
|
| + VEC (char_ptr) *vec_signals, *vec_keywords, *return_val;
|
| + static const char * const keywords[] =
|
| + {
|
| + "all",
|
| + "stop",
|
| + "ignore",
|
| + "print",
|
| + "pass",
|
| + "nostop",
|
| + "noignore",
|
| + "noprint",
|
| + "nopass",
|
| + NULL,
|
| + };
|
| +
|
| + vec_signals = signal_completer (ignore, text, word);
|
| + vec_keywords = complete_on_enum (keywords, word, word);
|
| +
|
| + return_val = VEC_merge (char_ptr, vec_signals, vec_keywords);
|
| + VEC_free (char_ptr, vec_signals);
|
| + VEC_free (char_ptr, vec_keywords);
|
| + return return_val;
|
| +}
|
| +
|
| static void
|
| xdb_handle_command (char *args, int from_tty)
|
| {
|
| @@ -6675,7 +6824,9 @@ save_infcall_suspend_state (void)
|
| {
|
| struct infcall_suspend_state *inf_state;
|
| struct thread_info *tp = inferior_thread ();
|
| +#if 0
|
| struct inferior *inf = current_inferior ();
|
| +#endif
|
| struct regcache *regcache = get_current_regcache ();
|
| struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| gdb_byte *siginfo_data = NULL;
|
| @@ -6730,7 +6881,9 @@ void
|
| restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
|
| {
|
| struct thread_info *tp = inferior_thread ();
|
| +#if 0
|
| struct inferior *inf = current_inferior ();
|
| +#endif
|
| struct regcache *regcache = get_current_regcache ();
|
| struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
|
| @@ -6744,11 +6897,10 @@ restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
|
| if (inf_state->siginfo_gdbarch == gdbarch)
|
| {
|
| struct type *type = gdbarch_get_siginfo_type (gdbarch);
|
| - size_t len = TYPE_LENGTH (type);
|
|
|
| /* Errors ignored. */
|
| target_write (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL,
|
| - inf_state->siginfo_data, 0, len);
|
| + inf_state->siginfo_data, 0, TYPE_LENGTH (type));
|
| }
|
|
|
| /* The inferior can be gone if the user types "print exit(0)"
|
| @@ -6971,6 +7123,15 @@ save_inferior_ptid (void)
|
| *saved_ptid_ptr = inferior_ptid;
|
| return make_cleanup (restore_inferior_ptid, saved_ptid_ptr);
|
| }
|
| +
|
| +/* See inferior.h. */
|
| +
|
| +void
|
| +clear_exit_convenience_vars (void)
|
| +{
|
| + clear_internalvar (lookup_internalvar ("_exitsignal"));
|
| + clear_internalvar (lookup_internalvar ("_exitcode"));
|
| +}
|
|
|
|
|
| /* User interface for reverse debugging:
|
| @@ -7023,32 +7184,6 @@ show_exec_direction_func (struct ui_file *out, int from_tty,
|
| }
|
| }
|
|
|
| -/* User interface for non-stop mode. */
|
| -
|
| -int non_stop = 0;
|
| -
|
| -static void
|
| -set_non_stop (char *args, int from_tty,
|
| - struct cmd_list_element *c)
|
| -{
|
| - if (target_has_execution)
|
| - {
|
| - non_stop_1 = non_stop;
|
| - error (_("Cannot change this setting while the inferior is running."));
|
| - }
|
| -
|
| - non_stop = non_stop_1;
|
| -}
|
| -
|
| -static void
|
| -show_non_stop (struct ui_file *file, int from_tty,
|
| - struct cmd_list_element *c, const char *value)
|
| -{
|
| - fprintf_filtered (file,
|
| - _("Controlling the inferior in non-stop mode is %s.\n"),
|
| - value);
|
| -}
|
| -
|
| static void
|
| show_schedule_multiple (struct ui_file *file, int from_tty,
|
| struct cmd_list_element *c, const char *value)
|
| @@ -7071,27 +7206,39 @@ _initialize_infrun (void)
|
| {
|
| int i;
|
| int numsigs;
|
| + struct cmd_list_element *c;
|
|
|
| add_info ("signals", signals_info, _("\
|
| What debugger does when program gets various signals.\n\
|
| Specify a signal as argument to print info on that signal only."));
|
| add_info_alias ("handle", "signals", 0);
|
|
|
| - add_com ("handle", class_run, handle_command, _("\
|
| -Specify how to handle a signal.\n\
|
| + c = add_com ("handle", class_run, handle_command, _("\
|
| +Specify how to handle signals.\n\
|
| +Usage: handle SIGNAL [ACTIONS]\n\
|
| Args are signals and actions to apply to those signals.\n\
|
| +If no actions are specified, the current settings for the specified signals\n\
|
| +will be displayed instead.\n\
|
| +\n\
|
| Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\
|
| from 1-15 are allowed for compatibility with old versions of GDB.\n\
|
| Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\
|
| The special arg \"all\" is recognized to mean all signals except those\n\
|
| used by the debugger, typically SIGTRAP and SIGINT.\n\
|
| +\n\
|
| Recognized actions include \"stop\", \"nostop\", \"print\", \"noprint\",\n\
|
| \"pass\", \"nopass\", \"ignore\", or \"noignore\".\n\
|
| Stop means reenter debugger if this signal happens (implies print).\n\
|
| Print means print a message if this signal happens.\n\
|
| Pass means let program see this signal; otherwise program doesn't know.\n\
|
| Ignore is a synonym for nopass and noignore is a synonym for pass.\n\
|
| -Pass and Stop may be combined."));
|
| +Pass and Stop may be combined.\n\
|
| +\n\
|
| +Multiple signals may be specified. Signal numbers and signal names\n\
|
| +may be interspersed with actions, with the actions being performed for\n\
|
| +all signals cumulatively specified."));
|
| + set_cmd_completer (c, handle_completer);
|
| +
|
| if (xdb_commands)
|
| {
|
| add_com ("lz", class_info, signals_info, _("\
|
| @@ -7122,13 +7269,13 @@ There is no `stop' command, but you can set a hook on `stop'.\n\
|
| This allows you to set a list of commands to be run each time execution\n\
|
| of the program stops."), &cmdlist);
|
|
|
| - add_setshow_zinteger_cmd ("infrun", class_maintenance, &debug_infrun, _("\
|
| + add_setshow_zuinteger_cmd ("infrun", class_maintenance, &debug_infrun, _("\
|
| Set inferior debugging."), _("\
|
| Show inferior debugging."), _("\
|
| When non-zero, inferior specific debugging is enabled."),
|
| - NULL,
|
| - show_debug_infrun,
|
| - &setdebuglist, &showdebuglist);
|
| + NULL,
|
| + show_debug_infrun,
|
| + &setdebuglist, &showdebuglist);
|
|
|
| add_setshow_boolean_cmd ("displaced", class_maintenance,
|
| &debug_displaced, _("\
|
| @@ -7165,6 +7312,8 @@ leave it stopped or free to run as needed."),
|
| xmalloc (sizeof (signal_print[0]) * numsigs);
|
| signal_program = (unsigned char *)
|
| xmalloc (sizeof (signal_program[0]) * numsigs);
|
| + signal_catch = (unsigned char *)
|
| + xmalloc (sizeof (signal_catch[0]) * numsigs);
|
| signal_pass = (unsigned char *)
|
| xmalloc (sizeof (signal_program[0]) * numsigs);
|
| for (i = 0; i < numsigs; i++)
|
| @@ -7172,6 +7321,7 @@ leave it stopped or free to run as needed."),
|
| signal_stop[i] = 1;
|
| signal_print[i] = 1;
|
| signal_program[i] = 1;
|
| + signal_catch[i] = 0;
|
| }
|
|
|
| /* Signals caused by debugger's own actions
|
| @@ -7220,7 +7370,7 @@ Show stopping for shared library events."), _("\
|
| If nonzero, gdb will give control to the user when the dynamic linker\n\
|
| notifies gdb of shared library events. The most common event of interest\n\
|
| to the user would be loading/unloading of a new library."),
|
| - NULL,
|
| + set_stop_on_solib_events,
|
| show_stop_on_solib_events,
|
| &setlist, &showlist);
|
|
|
|
|