#include "target-descriptions.h"
#include "target-dcache.h"
#include "terminal.h"
+#include "solist.h"
/* Prototypes for local functions */
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. */
int stop_after_trap;
-/* Save register contents here when executing a "finish" command or are
- about to pop a stack dummy frame, if-and-only-if proceed_to_finish is set.
- Thus this contains the return value from the called function (assuming
- values are returned in a register). */
-
-struct regcache *stop_registers;
-
/* Nonzero after stop if current stack frame should be printed. */
static int stop_print_frame;
if (info_verbose || debug_infrun)
{
+ /* Ensure that we have a process ptid. */
+ ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid));
+
target_terminal_ours_for_output ();
fprintf_filtered (gdb_stdlog,
_("Detaching after %s from child %s.\n"),
has_vforked ? "vfork" : "fork",
- target_pid_to_str (child_ptid));
+ target_pid_to_str (process_ptid));
}
}
else
{
if (info_verbose || debug_infrun)
{
+ /* Ensure that we have a process ptid. */
+ ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid));
+
target_terminal_ours_for_output ();
fprintf_filtered (gdb_stdlog,
_("Detaching after fork from "
"child %s.\n"),
- target_pid_to_str (child_ptid));
+ target_pid_to_str (process_ptid));
}
target_detach (NULL, 0);
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);
breakpoint_init_inferior (inf_execd);
- if (gdb_sysroot && *gdb_sysroot)
+ if (*gdb_sysroot != '\0')
{
- char *name = alloca (strlen (gdb_sysroot)
- + strlen (execd_pathname)
- + 1);
+ char *name = exec_file_find (execd_pathname, NULL);
- strcpy (name, gdb_sysroot);
- strcat (name, execd_pathname);
- execd_pathname = name;
+ execd_pathname = alloca (strlen (name) + 1);
+ strcpy (execd_pathname, name);
+ xfree (name);
}
/* Reset the shared library package. This ensures that we get a
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
reported to handle_inferior_event. Set a breakpoint
at the current PC, and run to it. Don't update
prev_pc, because if we end in
- switch_back_to_stepping, we want the "expected thread
- advanced also" branch to be taken. IOW, we don't
- want this thread to step further from PC
+ switch_back_to_stepped_thread, we want the "expected
+ thread advanced also" branch to be taken. IOW, we
+ don't want this thread to step further from PC
(overstep). */
+ gdb_assert (!step_over_info_valid_p ());
insert_single_step_breakpoint (gdbarch, aspace, pc);
insert_breakpoints ();
- tp->suspend.stop_signal = GDB_SIGNAL_0;
- /* We're continuing with all breakpoints inserted. It's
- safe to let the target bypass signals. */
- target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
- /* ... and safe to let other threads run, according to
- schedlock. */
resume_ptid = user_visible_resume_ptid (user_step);
- target_resume (resume_ptid, 0, GDB_SIGNAL_0);
+ do_target_resume (resume_ptid, 0, GDB_SIGNAL_0);
discard_cleanups (old_cleanups);
return;
}
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)
{
requests finish. The thread is not executing at this
point, and the call to set_executing will be made later.
But we need to call set_running here, since from the
- user/frontend's point of view, threads were set running.
- Unless we're calling an inferior function, as in that
- case we pretend the inferior doesn't run at all. */
- if (!tp->control.in_infcall)
- set_running (user_visible_resume_ptid (user_step), 1);
+ user/frontend's point of view, threads were set running. */
+ set_running (user_visible_resume_ptid (user_step), 1);
discard_cleanups (old_cleanups);
return;
}
/* Even if RESUME_PTID is a wildcard, and we end up resuming less
(e.g., we might need to step over a breakpoint), from the
user/frontend's point of view, all threads in RESUME_PTID are now
- running. Unless we're calling an inferior function, as in that
- case pretend we inferior doesn't run at all. */
- if (!tp->control.in_infcall)
- set_running (resume_ptid, 1);
+ running. */
+ set_running (resume_ptid, 1);
/* Maybe resume a single thread after all. */
if ((step || thread_has_single_step_breakpoints_set (tp))
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];
clear_step_over_info ();
observer_notify_about_to_proceed ();
-
- if (stop_registers)
- {
- regcache_xfree (stop_registers);
- stop_registers = NULL;
- }
}
/* Returns true if TP is still stopped at a breakpoint that needs
target_pid_to_str (step_over->ptid));
/* Store the prev_pc for the stepping thread too, needed by
- switch_back_to_stepping thread. */
+ switch_back_to_stepped_thread. */
tp->prev_pc = regcache_read_pc (get_current_regcache ());
switch_to_thread (step_over->ptid);
tp = step_over;
is set. */
fprintf_unfiltered (tmp_stream,
- "infrun: target_wait (%d", ptid_get_pid (waiton_ptid));
+ "infrun: target_wait (%d.%ld.%ld",
+ ptid_get_pid (waiton_ptid),
+ ptid_get_lwp (waiton_ptid),
+ ptid_get_tid (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",
+ "infrun: %d.%ld.%ld [%s],\n",
ptid_get_pid (result_ptid),
+ ptid_get_lwp (result_ptid),
+ ptid_get_tid (result_ptid),
target_pid_to_str (result_ptid));
fprintf_unfiltered (tmp_stream,
"infrun: %s\n",
wait_for_inferior (void)
{
struct cleanup *old_cleanups;
+ struct cleanup *thread_state_chain;
if (debug_infrun)
fprintf_unfiltered
= make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup,
NULL);
+ /* If an error happens while handling the event, propagate GDB's
+ knowledge of the executing state to the frontend/user running
+ state. */
+ thread_state_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
while (1)
{
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
- struct cleanup *old_chain;
ptid_t waiton_ptid = minus_one_ptid;
memset (ecs, 0, sizeof (*ecs));
if (debug_infrun)
print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws);
- /* If an error happens while handling the event, propagate GDB's
- knowledge of the executing state to the frontend/user running
- state. */
- old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
-
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
- /* No error, don't finish the state yet. */
- discard_cleanups (old_chain);
-
if (!ecs->wait_some_more)
break;
}
+ /* No error, don't finish the state yet. */
+ discard_cleanups (thread_state_chain);
+
do_cleanups (old_cleanups);
}
once). */
static void
-handle_inferior_event (struct execution_control_state *ecs)
+handle_inferior_event_1 (struct execution_control_state *ecs)
{
enum stop_kind stop_soon;
}
}
+/* A wrapper around handle_inferior_event_1, which also makes sure
+ that all temporary struct value objects that were created during
+ the handling of the event get deleted at the end. */
+
+static void
+handle_inferior_event (struct execution_control_state *ecs)
+{
+ struct value *mark = value_mark ();
+
+ handle_inferior_event_1 (ecs);
+ /* Purge all temporary values created during the event handling,
+ as it could be a long time before we return to the command level
+ where such values would otherwise be purged. */
+ value_free_to_mark (mark);
+}
+
/* Come here when the program has stopped with a signal. */
static void
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);
{
exception_print (gdb_stderr, e);
stop_waiting (ecs);
+ discard_cleanups (old_cleanups);
return;
}
END_CATCH
if (has_stack_frames () && !stop_stack_dummy)
set_current_sal_from_frame (get_current_frame ());
- /* Let the user/frontend see the threads as stopped, but do nothing
- if the thread was running an infcall. We may be e.g., evaluating
- a breakpoint condition. In that case, the thread had state
- THREAD_RUNNING before the infcall, and shall remain set to
- running, all without informing the user/frontend about state
- transition changes. If this is actually a call command, then the
- thread was originally already stopped, so there's no state to
- finish either. */
- if (target_has_execution && inferior_thread ()->control.in_infcall)
+ /* Let the user/frontend see the threads as stopped, but defer to
+ call_function_by_hand if the thread finished an infcall
+ successfully. We may be e.g., evaluating a breakpoint condition.
+ In that case, the thread had state THREAD_RUNNING before the
+ infcall, and shall remain marked running, all without informing
+ the user/frontend about state transition changes. */
+ if (target_has_execution
+ && inferior_thread ()->control.in_infcall
+ && stop_stack_dummy == STOP_STACK_DUMMY)
discard_cleanups (old_chain);
else
do_cleanups (old_chain);
print_stop_event (&last);
}
- /* Save the function value return registers, if we care.
- We might be about to restore their previous contents. */
- if (inferior_thread ()->control.proceed_to_finish
- && execution_direction != EXEC_REVERSE)
- {
- /* This should not be necessary. */
- if (stop_registers)
- regcache_xfree (stop_registers);
-
- /* NB: The copy goes through to the target picking up the value of
- all the registers. */
- stop_registers = regcache_dup (get_current_regcache ());
- }
-
if (stop_stack_dummy == STOP_STACK_DUMMY)
{
/* Pop the empty frame that contains the stack dummy.
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)
{
struct infcall_suspend_state
{
struct thread_suspend_state thread_suspend;
-#if 0 /* Currently unused and empty structures are not valid C. */
- struct inferior_suspend_state inferior_suspend;
-#endif
/* Other fields: */
CORE_ADDR stop_pc;
{
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->thread_suspend = tp->suspend;
-#if 0 /* Currently unused and empty structures are not valid C. */
- inf_state->inferior_suspend = inf->suspend;
-#endif
/* run_inferior_call will not use the signal due to its `proceed' call with
GDB_SIGNAL_0 anyway. */
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);
tp->suspend = inf_state->thread_suspend;
-#if 0 /* Currently unused and empty structures are not valid C. */
- inf->suspend = inf_state->inferior_suspend;
-#endif
stop_pc = inf_state->stop_pc;
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, _("\