/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2014 Free Software Foundation, Inc.
This file is part of GDB.
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"
#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"
#include "skip.h"
#include "probe.h"
#include "objfiles.h"
+#include "completer.h"
+#include "target-descriptions.h"
+#include "target-dcache.h"
/* Prototypes for local functions */
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
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)
"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;
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;
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. */
/* 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)
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";
/* 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. */
/* 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);
}
}
-/* 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";
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);
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 ();
remove_displaced_stepping_state (inf->pid);
}
-/* Enum strings for "set|show displaced-stepping". */
-
-static const char can_use_displaced_stepping_auto[] = "auto";
-static const char can_use_displaced_stepping_on[] = "on";
-static const char can_use_displaced_stepping_off[] = "off";
-static const char *const can_use_displaced_stepping_enum[] =
-{
- can_use_displaced_stepping_auto,
- can_use_displaced_stepping_on,
- can_use_displaced_stepping_off,
- NULL,
-};
-
/* If ON, and the architecture supports it, GDB will use displaced
stepping to step over breakpoints. If OFF, or if the architecture
doesn't support it, GDB will instead use the traditional
which of all-stop or non-stop mode is active --- displaced stepping
in non-stop mode; hold-and-step in all-stop mode. */
-static const char *can_use_displaced_stepping =
- can_use_displaced_stepping_auto;
+static enum auto_boolean can_use_displaced_stepping = AUTO_BOOLEAN_AUTO;
static void
show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
- if (can_use_displaced_stepping == can_use_displaced_stepping_auto)
+ if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO)
fprintf_filtered (file,
_("Debugger's willingness to use displaced stepping "
"to step over breakpoints is %s (currently %s).\n"),
static int
use_displaced_stepping (struct gdbarch *gdbarch)
{
- return (((can_use_displaced_stepping == can_use_displaced_stepping_auto
- && non_stop)
- || can_use_displaced_stepping == can_use_displaced_stepping_on)
+ return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop)
+ || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
&& gdbarch_displaced_step_copy_insn_p (gdbarch)
- && !RECORD_IS_USED);
+ && find_record_target () == NULL);
}
/* Clean out any stray displaced stepping state. */
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;
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. */
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));
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.
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 ();
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;
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
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
{
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
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
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. */
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. */
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);
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
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. */
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);
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);
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
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 ();
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 ();
+ if (record_full_is_used ())
+ 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
|| 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)
{
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);
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
}
}
-/* 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)
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;
}
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. */
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:
/* 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:
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 ();
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
/* 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
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 ();
+
+ 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);
- /* Also record this in the inferior itself. */
- current_inferior ()->has_exit_code = 1;
- current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer;
+ /* Also record this in the inferior itself. */
+ current_inferior ()->has_exit_code = 1;
+ current_inferior ()->exit_code = (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;
+ print_exited_reason (ecs->ws.value.integer);
+ }
+ else
+ {
+ struct regcache *regcache = get_thread_regcache (ecs->ptid);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
- 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. */
+ 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"));
+ }
- /* 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 ();
+ 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;
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. */
{
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)
= 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;
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
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. */
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. */
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
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)
{
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);
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);
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;
}
"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
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. */
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);
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
skip_inline_frames call would break things. Fortunately
that's an extremely unlikely scenario. */
if (!pc_at_non_inline_function (aspace, stop_pc, &ecs->ws)
- && !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
- && ecs->event_thread->control.trap_expected
- && pc_at_non_inline_function (aspace,
- ecs->event_thread->prev_pc,
+ && !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
+ && ecs->event_thread->control.trap_expected
+ && pc_at_non_inline_function (aspace,
+ ecs->event_thread->prev_pc,
&ecs->ws)))
- skip_inline_frames (ecs->ptid);
+ {
+ skip_inline_frames (ecs->ptid);
+
+ /* Re-fetch current thread's frame in case that invalidated
+ the frame cache. */
+ frame = get_current_frame ();
+ gdbarch = get_frame_arch (frame);
+ }
}
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
}
}
- /* 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)
+ /* 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;
+
+ if (signal_print[ecs->event_thread->suspend.stop_signal])
{
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
- stop_print_frame = 0;
- stop_stepping (ecs);
- return;
+ printed = 1;
+ target_terminal_ours_for_output ();
+ print_signal_received_reason
+ (ecs->event_thread->suspend.stop_signal);
}
-
- /* This is originated from start_remote(), start_inferior() and
- shared libraries hook functions. */
- if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
- {
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
- 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_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;
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)
(leaving the inferior at the step-resume-breakpoint without
actually executing it). Either way continue until the
breakpoint is really hit. */
- keep_going (ecs);
- return;
- }
- /* 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)
- {
- 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 (!switch_back_to_stepped_thread (ecs))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: random signal, keep going\n");
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
+ keep_going (ecs);
+ }
+ return;
+ }
- ecs->event_thread->stepping_over_breakpoint = 1;
+ process_event_stop_test (ecs);
+}
- 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;
- }
+/* 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. */
- /* Insert a breakpoint at resume address. */
- insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
- }
- else
- check_exception_resume (ecs, frame);
- keep_going (ecs);
- return;
+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;
- case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
- {
- struct frame_info *init_frame;
+ /* Handle cases caused by hitting a breakpoint. */
- /* There are several cases to consider.
+ frame = get_current_frame ();
+ gdbarch = get_frame_arch (frame);
- 1. The initiating frame no longer exists. In this case
- we must stop, because the exception or longjmp has gone
- too far.
+ what = bpstat_what (ecs->event_thread->control.stop_bpstat);
- 2. The initiating frame exists, and is the same as the
- current frame. We stop, because the exception or longjmp
- has been caught.
+ if (what.call_dummy)
+ {
+ stop_stack_dummy = what.call_dummy;
+ }
- 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. */
+ /* 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 (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
+ 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. */
- init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
- gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
- != NULL);
- delete_exception_resume_breakpoint (ecs->event_thread);
+ ecs->event_thread->stepping_over_breakpoint = 1;
- if (init_frame)
+ 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))
{
- 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 (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);
-
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ /* Insert a breakpoint at resume address. */
+ insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
}
- return;
-
- 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;
+ else
+ check_exception_resume (ecs, frame);
+ keep_going (ecs);
+ return;
- case BPSTAT_WHAT_STEP_RESUME:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
+ case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
+ {
+ struct frame_info *init_frame;
- 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;
+ /* There are several cases to consider.
- case BPSTAT_WHAT_STOP_NOISY:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
- stop_print_frame = 1;
+ 1. The initiating frame no longer exists. In this case we
+ must stop, because the exception or longjmp has gone too
+ far.
- /* We are about to nuke the step_resume_breakpointt via the
- cleanup chain, so no need to worry about it here. */
+ 2. The initiating frame exists, and is the same as the
+ current frame. We stop, because the exception or longjmp
+ has been caught.
- stop_stepping (ecs);
- return;
+ 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.
+
+ 4. longjmp breakpoint has been placed just to protect
+ against stale dummy frames and user is not interested in
+ stopping around longjmps. */
- case BPSTAT_WHAT_STOP_SILENT:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
- stop_print_frame = 0;
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
- /* We are about to nuke the step_resume_breakpoin via the
- cleanup chain, so no need to worry about it here. */
+ gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
+ != NULL);
+ delete_exception_resume_breakpoint (ecs->event_thread);
- stop_stepping (ecs);
- return;
+ if (what.is_longjmp)
+ {
+ check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
- case BPSTAT_WHAT_HP_STEP_RESUME:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
+ if (!frame_id_p (ecs->event_thread->initiating_frame))
+ {
+ /* Case 4. */
+ keep_going (ecs);
+ return;
+ }
+ }
- delete_step_resume_breakpoint (ecs->event_thread);
- if (ecs->event_thread->step_after_step_resume_breakpoint)
+ init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
+
+ if (init_frame)
{
- /* 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;
+ 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;
+ }
}
- break;
- 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);
+
+ ecs->event_thread->control.stop_step = 1;
+ print_end_stepping_range_reason ();
+ stop_stepping (ecs);
}
- }
+ return;
- /* 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. */
+ 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;
- /* 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_STEP_RESUME:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
- tp = iterate_over_threads (currently_stepping_or_nexting_callback,
- ecs->event_thread);
- if (tp)
+ 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)
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)))
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). */
if (execution_direction == EXEC_REVERSE)
{
- struct symtab_and_line sr_sal;
-
- /* Normal function call return (static or dynamic). */
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ /* If we're already at the start of the function, we've either
+ just stepped backward into a single instruction function,
+ 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 && ecs->stop_func_start != 0)
+ {
+ struct symtab_and_line sr_sal;
+
+ /* Normal function call return (static or dynamic). */
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ sr_sal.pspace = get_frame_program_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
+ }
}
else
insert_step_resume_breakpoint_at_caller (frame);
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);
if (execution_direction == EXEC_REVERSE)
{
- /* Set a breakpoint at callee's start address.
- From there we can step once and be back in the caller. */
- struct symtab_and_line sr_sal;
+ /* If we're already at the start of the function, we've either just
+ stepped backward into a single instruction function without line
+ number info, or stepped back out of a signal handler to the first
+ instruction of the function without line number info. Just keep
+ going, which will single-step back to the caller. */
+ if (ecs->stop_func_start != stop_pc)
+ {
+ /* Set a breakpoint at callee's start address.
+ From there we can step once and be back in the caller. */
+ struct symtab_and_line sr_sal;
- init_sal (&sr_sal);
- sr_sal.pc = ecs->stop_func_start;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ init_sal (&sr_sal);
+ sr_sal.pc = ecs->stop_func_start;
+ sr_sal.pspace = get_frame_program_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
+ }
}
else
/* Set a breakpoint at callee's return address (the address
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)
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
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;
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),
struct frame_info *frame)
{
volatile struct gdb_exception e;
- struct objfile *objfile;
const struct probe *probe;
struct symbol *func;
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;
}
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)
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);
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 ();
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;
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 ();
signal_pass[signo] = (signal_stop[signo] == 0
&& signal_print[signo] == 0
- && signal_program[signo] == 1);
+ && signal_program[signo] == 1
+ && signal_catch[signo] == 0);
}
int
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)
{
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)
{
{
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;
}
}
- inf_state = XZALLOC (struct infcall_suspend_state);
+ inf_state = XCNEW (struct infcall_suspend_state);
if (siginfo_data)
{
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);
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)"
*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"));
+}
\f
/* User interface for reverse debugging:
}
}
-/* 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)
{
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, _("\
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, _("\
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++)
signal_stop[i] = 1;
signal_print[i] = 1;
signal_program[i] = 1;
+ signal_catch[i] = 0;
}
/* Signals caused by debugger's own actions
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);
show_step_stop_if_no_debug,
&setlist, &showlist);
- add_setshow_enum_cmd ("displaced-stepping", class_run,
- can_use_displaced_stepping_enum,
- &can_use_displaced_stepping, _("\
+ add_setshow_auto_boolean_cmd ("displaced-stepping", class_run,
+ &can_use_displaced_stepping, _("\
Set debugger's willingness to use displaced stepping."), _("\
Show debugger's willingness to use displaced stepping."), _("\
If on, gdb will use displaced stepping to step over breakpoints if it is\n\
architecture. If auto (which is the default), gdb will use displaced stepping\n\
if the target architecture supports it and non-stop mode is active, but will not\n\
use it in all-stop mode (see help set non-stop)."),
- NULL,
- show_can_use_displaced_stepping,
- &setlist, &showlist);
+ NULL,
+ show_can_use_displaced_stepping,
+ &setlist, &showlist);
add_setshow_enum_cmd ("exec-direction", class_run, exec_direction_names,
&exec_direction, _("Set direction of execution.\n\