static int currently_stepping (struct thread_info *tp);
-static void xdb_handle_command (char *args, int from_tty);
-
void _initialize_infrun (void);
void nullify_last_target_wait_ptid (void);
static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR);
+static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc);
+
/* When set, stop the 'step' command if we enter a function which has
no line number information. The normal behavior is that we step
over such function. */
them. Deleting them now rather than at the next user-visible
stop provides a nicer sequence of events for user and MI
notifications. */
- ALL_NON_EXITED_THREADS_SAFE (th, tmp)
+ ALL_THREADS_SAFE (th, tmp)
if (ptid_get_pid (th->ptid) == pid && !ptid_equal (th->ptid, ptid))
delete_thread (th->ptid);
return NULL;
}
+/* Return true if process PID has a thread doing a displaced step. */
+
+static int
+displaced_step_in_progress (int pid)
+{
+ struct displaced_step_inferior_state *displaced;
+
+ displaced = get_displaced_stepping_state (pid);
+ if (displaced != NULL && !ptid_equal (displaced->step_ptid, null_ptid))
+ return 1;
+
+ return 0;
+}
+
/* Add a new displaced stepping state for process PID to the displaced
stepping state list, or return a pointer to an already existing
entry, if it already exists. Never returns NULL. */
displaced_step_restore (displaced, displaced->step_ptid);
+ /* Fixup may need to read memory/registers. Switch to the thread
+ that we're fixing up. Also, target_stopped_by_watchpoint checks
+ the current thread. */
+ switch_to_thread (event_ptid);
+
/* Did the instruction complete successfully? */
- if (signal == GDB_SIGNAL_TRAP)
+ if (signal == GDB_SIGNAL_TRAP
+ && !(target_stopped_by_watchpoint ()
+ && (gdbarch_have_nonsteppable_watchpoint (displaced->step_gdbarch)
+ || target_have_steppable_watchpoint)))
{
- /* Fixup may need to read memory/registers. Switch to the
- thread that we're fixing up. */
- switch_to_thread (event_ptid);
-
/* Fix up the resulting state. */
gdbarch_displaced_step_fixup (displaced->step_gdbarch,
displaced->step_closure,
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
aspace = get_regcache_aspace (regcache);
+ gdbarch = get_regcache_arch (regcache);
if (breakpoint_here_p (aspace, actual_pc))
{
displaced_step_prepare (ptid);
- gdbarch = get_regcache_arch (regcache);
-
if (debug_displaced)
{
CORE_ADDR actual_pc = regcache_read_pc (regcache);
/* Go back to what we were trying to do. */
step = currently_stepping (tp);
+ if (step)
+ step = maybe_software_singlestep (gdbarch, actual_pc);
+
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: breakpoint is gone: %s, step(%d)\n",
happens to apply to another thread. */
tp->suspend.stop_signal = GDB_SIGNAL_0;
- /* Advise target which signals may be handled silently. If we have
- removed breakpoints because we are stepping over one (in any
- thread), we need to receive all signals to avoid accidentally
- skipping a breakpoint during execution of a signal handler. */
- if (step_over_info_valid_p ())
+ /* Advise target which signals may be handled silently.
+
+ If we have removed breakpoints because we are stepping over one
+ in-line (in any thread), we need to receive all signals to avoid
+ accidentally skipping a breakpoint during execution of a signal
+ handler.
+
+ Likewise if we're displaced stepping, otherwise a trap for a
+ breakpoint in a signal handler might be confused with the
+ displaced step finishing. We don't make the displaced_step_fixup
+ step distinguish the cases instead, because:
+
+ - a backtrace while stopped in the signal handler would show the
+ scratch pad as frame older than the signal handler, instead of
+ the real mainline code.
+
+ - when the thread is later resumed, the signal handler would
+ return to the scratch pad area, which would no longer be
+ valid. */
+ if (step_over_info_valid_p ()
+ || displaced_step_in_progress (ptid_get_pid (tp->ptid)))
target_pass_signals (0, NULL);
else
target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
This can decay from a step to a continue, if e.g., we need to
implement single-stepping with breakpoints (software
single-step). */
- int step = currently_stepping (tp);
+ int step;
tp->stepped_breakpoint = 0;
QUIT;
+ /* Depends on stepped_breakpoint. */
+ step = currently_stepping (tp);
+
if (current_inferior ()->waiting_for_vfork_done)
{
/* Don't try to single-step a vfork parent that is waiting for
step software breakpoint. */
if (use_displaced_stepping (gdbarch)
&& tp->control.trap_expected
+ && !step_over_info_valid_p ()
&& sig == GDB_SIGNAL_0
&& !current_inferior ()->waiting_for_vfork_done)
{
if (debug_displaced
&& use_displaced_stepping (gdbarch)
- && tp->control.trap_expected)
+ && tp->control.trap_expected
+ && !step_over_info_valid_p ())
{
- struct regcache *resume_regcache = get_thread_regcache (resume_ptid);
+ struct regcache *resume_regcache = get_thread_regcache (tp->ptid);
struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache);
CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
gdb_byte buf[4];
struct breakpoint *sr_bp
= ecs->event_thread->control.step_resume_breakpoint;
- if (sr_bp->loc->permanent
+ if (sr_bp != NULL
+ && sr_bp->loc->permanent
&& sr_bp->type == bp_hp_step_resume
&& sr_bp->loc->address == ecs->event_thread->prev_pc)
{
remove_wps = (ecs->event_thread->stepping_over_watchpoint
&& !target_have_steppable_watchpoint);
- if (remove_bp && !use_displaced_stepping (get_regcache_arch (regcache)))
+ /* We can't use displaced stepping if we need to step past a
+ watchpoint. The instruction copied to the scratch pad would
+ still trigger the watchpoint. */
+ if (remove_bp
+ && (remove_wps
+ || !use_displaced_stepping (get_regcache_arch (regcache))))
{
set_step_over_info (get_regcache_aspace (regcache),
regcache_read_pc (regcache), remove_wps);
return return_val;
}
-static void
-xdb_handle_command (char *args, int from_tty)
-{
- char **argv;
- struct cleanup *old_chain;
-
- if (args == NULL)
- error_no_arg (_("xdb command"));
-
- /* Break the command line up into args. */
-
- argv = gdb_buildargv (args);
- old_chain = make_cleanup_freeargv (argv);
- if (argv[1] != (char *) NULL)
- {
- char *argBuf;
- int bufLen;
-
- bufLen = strlen (argv[0]) + 20;
- argBuf = (char *) xmalloc (bufLen);
- if (argBuf)
- {
- int validFlag = 1;
- enum gdb_signal oursig;
-
- oursig = gdb_signal_from_name (argv[0]);
- memset (argBuf, 0, bufLen);
- if (strcmp (argv[1], "Q") == 0)
- sprintf (argBuf, "%s %s", argv[0], "noprint");
- else
- {
- if (strcmp (argv[1], "s") == 0)
- {
- if (!signal_stop[oursig])
- sprintf (argBuf, "%s %s", argv[0], "stop");
- else
- sprintf (argBuf, "%s %s", argv[0], "nostop");
- }
- else if (strcmp (argv[1], "i") == 0)
- {
- if (!signal_program[oursig])
- sprintf (argBuf, "%s %s", argv[0], "pass");
- else
- sprintf (argBuf, "%s %s", argv[0], "nopass");
- }
- else if (strcmp (argv[1], "r") == 0)
- {
- if (!signal_print[oursig])
- sprintf (argBuf, "%s %s", argv[0], "print");
- else
- sprintf (argBuf, "%s %s", argv[0], "noprint");
- }
- else
- validFlag = 0;
- }
- if (validFlag)
- handle_command (argBuf, from_tty);
- else
- printf_filtered (_("Invalid signal handling flag.\n"));
- if (argBuf)
- xfree (argBuf);
- }
- }
- do_cleanups (old_chain);
-}
-
enum gdb_signal
gdb_signal_from_command (int num)
{
all signals cumulatively specified."));
set_cmd_completer (c, handle_completer);
- if (xdb_commands)
- {
- add_com ("lz", class_info, signals_info, _("\
-What debugger does when program gets various signals.\n\
-Specify a signal as argument to print info on that signal only."));
- add_com ("z", class_run, xdb_handle_command, _("\
-Specify how to handle a signal.\n\
-Args are signals and actions to apply to those signals.\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\
-Recognized actions include \"s\" (toggles between stop and nostop),\n\
-\"r\" (toggles between print and noprint), \"i\" (toggles between pass and \
-nopass), \"Q\" (noprint)\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."));
- }
-
if (!dbx_commands)
stop_command = add_cmd ("stop", class_obscure,
not_just_help_class_command, _("\