/* Target-struct-independent code to start (run) and stop an inferior
process.
- Copyright (C) 1986-2013 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 "objfiles.h"
#include "completer.h"
#include "target-descriptions.h"
+#include "target-dcache.h"
/* Prototypes for local functions */
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
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. */
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 (catch_syscall_enabled () > 0
&& catching_syscall_number (syscall_number) > 0)
{
- enum bpstat_signal_value sval;
-
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
syscall_number);
= bpstat_stop_status (get_regcache_aspace (regcache),
stop_pc, ecs->ptid, &ecs->ws);
- sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
- GDB_SIGNAL_TRAP);
- ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
-
- 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;
}
}
}
-/* 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;
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;
- enum bpstat_signal_value sval;
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- context_switch (ecs->ptid);
regcache = get_thread_regcache (ecs->ptid);
handle_solib_event ();
= bpstat_stop_status (get_regcache_aspace (regcache),
stop_pc, ecs->ptid, &ecs->ws);
- sval
- = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
- GDB_SIGNAL_TRAP);
- ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
-
- 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)
= 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,
- GDB_SIGNAL_TRAP)
- == BPSTAT_SIGNAL_NO);
/* 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)
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);
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);
}
}
- /* 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. */
-
- 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;
- }
-
- /* 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
if (debug_infrun
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
- && (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
+ && !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
GDB_SIGNAL_TRAP)
- == BPSTAT_SIGNAL_NO)
&& 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
+ /* 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:
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,
- GDB_SIGNAL_TRAP)
- != BPSTAT_SIGNAL_NO)
- || 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
- {
- enum bpstat_signal_value sval;
-
- sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat,
- ecs->event_thread->suspend.stop_signal);
- ecs->random_signal = (sval == BPSTAT_SIGNAL_NO);
+ /* 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 (sval == BPSTAT_SIGNAL_HIDE)
- ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
- }
+ /* 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));
-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);
+ /* 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 (ecs->random_signal)
+ if (random_signal)
{
/* Signal not for debugging purposes. */
int printed = 0;
}
return;
}
- else
- {
- /* Handle cases caused by hitting a breakpoint. */
- CORE_ADDR jmp_buf_pc;
- struct bpstat_what what;
+ process_event_stop_test (ecs);
+}
- what = bpstat_what (ecs->event_thread->control.stop_bpstat);
+/* 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. */
- if (what.call_dummy)
- {
- stop_stack_dummy = what.call_dummy;
- }
+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;
- /* 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);
+ /* Handle cases caused by hitting a breakpoint. */
- 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. */
+ frame = get_current_frame ();
+ gdbarch = get_frame_arch (frame);
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
+ what = bpstat_what (ecs->event_thread->control.stop_bpstat);
- ecs->event_thread->stepping_over_breakpoint = 1;
+ if (what.call_dummy)
+ {
+ stop_stack_dummy = what.call_dummy;
+ }
- 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;
- }
+ /* 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);
- /* Insert a breakpoint at resume address. */
- insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
- }
- else
- check_exception_resume (ecs, frame);
- keep_going (ecs);
- return;
+ 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. */
- case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
- {
- struct frame_info *init_frame;
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
+
+ ecs->event_thread->stepping_over_breakpoint = 1;
- /* There are several cases to consider.
+ 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;
+ }
- 1. The initiating frame no longer exists. In this case
- we must stop, because the exception or longjmp has gone
- too far.
+ /* Insert a breakpoint at resume address. */
+ insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
+ }
+ else
+ check_exception_resume (ecs, frame);
+ keep_going (ecs);
+ return;
- 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_CLEAR_LONGJMP_RESUME:
+ {
+ struct frame_info *init_frame;
- 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.
+ /* There are several cases to consider.
- 4. longjmp breakpoint has been placed just to protect
- against stale dummy frames and user is not interested
- in stopping around longjmps. */
+ 1. The initiating frame no longer exists. In this case we
+ must stop, because the exception or longjmp has gone too
+ far.
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog,
- "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
+ 2. The initiating frame exists, and is the same as the
+ current frame. We stop, because the exception or longjmp
+ has been caught.
- gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
- != NULL);
- delete_exception_resume_breakpoint (ecs->event_thread);
+ 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 (what.is_longjmp)
- {
- check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
+ 4. longjmp breakpoint has been placed just to protect
+ against stale dummy frames and user is not interested in
+ stopping around longjmps. */
- 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_CLEAR_LONGJMP_RESUME\n");
- init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
+ gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
+ != NULL);
+ delete_exception_resume_breakpoint (ecs->event_thread);
+
+ if (what.is_longjmp)
+ {
+ check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num);
- if (init_frame)
+ if (!frame_id_p (ecs->event_thread->initiating_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 4. */
+ keep_going (ecs);
+ return;
}
+ }
- /* For Cases 1 and 2, remove the step-resume breakpoint,
- if it exists. */
- delete_step_resume_breakpoint (ecs->event_thread);
+ init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
- ecs->event_thread->control.stop_step = 1;
- print_end_stepping_range_reason ();
- stop_stepping (ecs);
+ 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;
+ }
}
- 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;
-
- case BPSTAT_WHAT_STEP_RESUME:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
+ /* For Cases 1 and 2, remove the step-resume breakpoint, if it
+ exists. */
+ delete_step_resume_breakpoint (ecs->event_thread);
- 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;
+ ecs->event_thread->control.stop_step = 1;
+ print_end_stepping_range_reason ();
+ stop_stepping (ecs);
+ }
+ return;
- case BPSTAT_WHAT_STOP_NOISY:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
- stop_print_frame = 1;
+ 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;
- /* We are about to nuke the step_resume_breakpointt via the
- cleanup chain, so no need to worry about it here. */
+ case BPSTAT_WHAT_STEP_RESUME:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
- stop_stepping (ecs);
+ 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;
- case BPSTAT_WHAT_STOP_SILENT:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
- stop_print_frame = 0;
+ case BPSTAT_WHAT_STOP_NOISY:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
+ stop_print_frame = 1;
- /* We are about to nuke the step_resume_breakpoin via the
- cleanup chain, so no need to worry about it here. */
+ /* We are about to nuke the step_resume_breakpointt via the
+ cleanup chain, so no need to worry about it here. */
- stop_stepping (ecs);
- return;
+ stop_stepping (ecs);
+ return;
- case BPSTAT_WHAT_HP_STEP_RESUME:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
+ case BPSTAT_WHAT_STOP_SILENT:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
+ stop_print_frame = 0;
- 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;
+ /* We are about to nuke the step_resume_breakpoin via the
+ cleanup chain, so no need to worry about it here. */
- case BPSTAT_WHAT_KEEP_CHECKING:
- break;
+ stop_stepping (ecs);
+ return;
+
+ case BPSTAT_WHAT_HP_STEP_RESUME:
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_HP_STEP_RESUME\n");
+
+ 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. */
+ /* 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. */