int stop_after_trap;
-/* Nonzero means expecting a trap and caller will handle it themselves.
- It is used after attach, due to attaching to a process;
- when running in the shell before the child program has been exec'd;
- and when running some kinds of remote stuff (FIXME?). */
-
-enum stop_kind stop_soon;
-
/* Save register contents here when 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
static void
follow_exec (ptid_t pid, char *execd_pathname)
{
- ptid_t saved_pid = pid;
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
inferior has essentially been killed & reborn. */
gdb_flush (gdb_stdout);
- generic_mourn_inferior ();
- /* Because mourn_inferior resets inferior_ptid. */
- inferior_ptid = saved_pid;
+
+ breakpoint_init_inferior (inf_execd);
if (gdb_sysroot && *gdb_sysroot)
{
static int
displaced_step_prepare (ptid_t ptid)
{
- struct cleanup *old_cleanups;
+ struct cleanup *old_cleanups, *ignore_cleanups;
struct regcache *regcache = get_thread_regcache (ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
CORE_ADDR original, copy;
displaced_step_clear ();
+ old_cleanups = save_inferior_ptid ();
+ inferior_ptid = ptid;
+
original = regcache_read_pc (regcache);
copy = gdbarch_displaced_step_location (gdbarch);
/* Save the original contents of the copy area. */
displaced_step_saved_copy = xmalloc (len);
- old_cleanups = make_cleanup (free_current_contents,
- &displaced_step_saved_copy);
+ ignore_cleanups = make_cleanup (free_current_contents,
+ &displaced_step_saved_copy);
read_memory (copy, displaced_step_saved_copy, len);
if (debug_displaced)
{
};
closure = gdbarch_displaced_step_copy_insn (gdbarch,
- original, copy, regcache);
+ original, copy, regcache);
/* We don't support the fully-simulated case at present. */
gdb_assert (closure);
/* Resume execution at the copy. */
regcache_write_pc (regcache, copy);
- discard_cleanups (old_cleanups);
+ discard_cleanups (ignore_cleanups);
+
+ do_cleanups (old_cleanups);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n",
- paddr_nz (copy));
+ paddr_nz (copy));
/* Save the information we need to fix things up if the step
succeeds. */
do_cleanups (old_cleanups);
+ displaced_step_ptid = null_ptid;
+
/* Are there any pending displaced stepping requests? If so, run
one now. */
- if (displaced_step_request_queue)
+ while (displaced_step_request_queue)
{
struct displaced_step_request *head;
ptid_t ptid;
+ CORE_ADDR actual_pc;
head = displaced_step_request_queue;
ptid = head->ptid;
displaced_step_request_queue = head->next;
xfree (head);
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog,
- "displaced: stepping queued %s now\n",
- target_pid_to_str (ptid));
+ context_switch (ptid);
+
+ actual_pc = read_pc ();
+
+ if (breakpoint_here_p (actual_pc))
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: stepping queued %s now\n",
+ target_pid_to_str (ptid));
+ displaced_step_prepare (ptid);
- displaced_step_ptid = null_ptid;
- displaced_step_prepare (ptid);
- target_resume (ptid, 1, TARGET_SIGNAL_0);
+ if (debug_displaced)
+ {
+ gdb_byte buf[4];
+
+ fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
+ paddr_nz (actual_pc));
+ read_memory (actual_pc, buf, sizeof (buf));
+ displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
+ }
+
+ target_resume (ptid, 1, TARGET_SIGNAL_0);
+
+ /* Done, we're stepping a thread. */
+ break;
+ }
+ else
+ {
+ int step;
+ struct thread_info *tp = inferior_thread ();
+
+ /* The breakpoint we were sitting under has since been
+ removed. */
+ tp->trap_expected = 0;
+
+ /* Go back to what we were trying to do. */
+ step = currently_stepping (tp);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "breakpoint is gone %s: step(%d)\n",
+ target_pid_to_str (tp->ptid), step);
+
+ target_resume (ptid, step, TARGET_SIGNAL_0);
+ tp->stop_signal = TARGET_SIGNAL_0;
+
+ /* This request was discarded. See if there's any other
+ thread waiting for its turn. */
+ }
}
}
{
if (!ptid_equal (inferior_ptid, null_ptid))
{
- struct thread_info *tp = inferior_thread ();
+ struct thread_info *tp;
+ struct inferior *inferior;
+
+ tp = inferior_thread ();
tp->trap_expected = 0;
tp->step_range_start = 0;
/* Discard any remaining commands or status from previous
stop. */
bpstat_clear (&tp->stop_bpstat);
+
+ inferior = current_inferior ();
+ inferior->stop_soon = NO_STOP_QUIETLY;
}
stop_after_trap = 0;
- stop_soon = NO_STOP_QUIETLY;
breakpoint_proceeded = 1; /* We're about to proceed... */
if (stop_registers)
void
start_remote (int from_tty)
{
+ struct inferior *inferior;
init_wait_for_inferior ();
- stop_soon = STOP_QUIETLY_REMOTE;
+
+ inferior = current_inferior ();
+ inferior->stop_soon = STOP_QUIETLY_REMOTE;
/* Always go on waiting for the target, regardless of the mode. */
/* FIXME: cagney/1999-09-23: At present it isn't possible to
else
ecs->ptid = target_wait (waiton_ptid, &ecs->ws);
- ecs->event_thread = find_thread_pid (ecs->ptid);
-
if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
{
xfree (ecs->ws.value.execd_pathname);
thread. */
context_switch (ecs->ptid);
- ecs->event_thread = find_thread_pid (ecs->ptid);
-
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
if (!ecs->wait_some_more)
{
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+
delete_step_thread_step_resume_breakpoint ();
- if (stop_soon == NO_STOP_QUIETLY)
+ /* We may not find an inferior if this was a process exit. */
+ if (inf == NULL || inf->stop_soon == NO_STOP_QUIETLY)
normal_stop ();
if (target_has_execution
breakpoint_pc = regcache_read_pc (regcache)
- gdbarch_decr_pc_after_break (gdbarch);
- /* Check whether there actually is a software breakpoint inserted
- at that location. */
- if (software_breakpoint_inserted_here_p (breakpoint_pc))
+ /* Check whether there actually is a software breakpoint inserted at
+ that location.
+
+ If in non-stop mode, a race condition is possible where we've
+ removed a breakpoint, but stop events for that breakpoint were
+ already queued and arrive later. To suppress those spurious
+ SIGTRAPs, we keep a list of such breakpoint locations for a bit,
+ and retire them after a number of stop events are reported. */
+ if (software_breakpoint_inserted_here_p (breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
{
/* When using hardware single-step, a SIGTRAP is reported for both
a completed single-step and a software breakpoint. Need to
int stopped_by_watchpoint;
int stepped_after_stopped_by_watchpoint = 0;
struct symtab_and_line stop_pc_sal;
+ enum stop_kind stop_soon;
- breakpoint_retire_moribund ();
+ if (ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+ && ecs->ws.kind != TARGET_WAITKIND_IGNORE)
+ {
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+ gdb_assert (inf);
+ stop_soon = inf->stop_soon;
+ }
+ else
+ stop_soon = NO_STOP_QUIETLY;
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
/* Always clear state belonging to the previous time we stopped. */
stop_stack_dummy = 0;
- adjust_pc_after_break (ecs);
-
- reinit_frame_cache ();
-
/* If it's a new process, add it to the thread database */
ecs->new_thread_event = (!ptid_equal (ecs->ptid, inferior_ptid)
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED && ecs->new_thread_event)
add_thread (ecs->ptid);
+ ecs->event_thread = find_thread_pid (ecs->ptid);
+
+ /* Dependent on valid ECS->EVENT_THREAD. */
+ adjust_pc_after_break (ecs);
+
+ /* Dependent on the current PC value modified by adjust_pc_after_break. */
+ reinit_frame_cache ();
+
if (ecs->ws.kind != TARGET_WAITKIND_IGNORE)
{
+ breakpoint_retire_moribund ();
+
/* Mark the non-executing threads accordingly. */
if (!non_stop
|| ecs->ws.kind == TARGET_WAITKIND_EXITED
savestring (ecs->ws.value.execd_pathname,
strlen (ecs->ws.value.execd_pathname));
- /* This causes the eventpoints and symbol table to be reset. Must
- do this now, before trying to determine whether to stop. */
- follow_exec (inferior_ptid, pending_follow.execd_pathname);
- xfree (pending_follow.execd_pathname);
-
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
-
- {
- /* The breakpoints module may need to touch the inferior's
- memory. Switch to the (stopped) event ptid
- momentarily. */
- ptid_t saved_inferior_ptid = inferior_ptid;
- inferior_ptid = ecs->ptid;
-
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
- ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
- inferior_ptid = saved_inferior_ptid;
- }
-
if (!ptid_equal (ecs->ptid, inferior_ptid))
{
context_switch (ecs->ptid);
reinit_frame_cache ();
}
+ stop_pc = read_pc ();
+
+ /* This causes the eventpoints and symbol table to be reset.
+ Must do this now, before trying to determine whether to
+ stop. */
+ follow_exec (inferior_ptid, pending_follow.execd_pathname);
+ xfree (pending_follow.execd_pathname);
+
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
another signal besides SIGTRAP, so check here as well as
above.''
- If someone ever tries to get get call dummys on a
+ 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
target_terminal_ours_for_output ();
print_stop_reason (SIGNAL_RECEIVED, ecs->event_thread->stop_signal);
}
- if (signal_stop_state (ecs->event_thread->stop_signal))
+ /* Always stop on signals if we're just gaining control of the
+ program. */
+ if (stop_soon != NO_STOP_QUIETLY
+ || signal_stop_state (ecs->event_thread->stop_signal))
{
stop_stepping (ecs);
return;
if (real_stop_pc != 0)
ecs->stop_func_start = real_stop_pc;
- if (in_solib_dynsym_resolve_code (ecs->stop_func_start))
+ if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
{
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
int
signal_stop_state (int signo)
{
- /* Always stop on signals if we're just gaining control of the
- program. */
- return signal_stop[signo] || stop_soon != NO_STOP_QUIETLY;
+ return signal_stop[signo];
}
int
/* Break the command line up into args. */
- argv = buildargv (args);
- if (argv == NULL)
- {
- nomem (0);
- }
+ argv = gdb_buildargv (args);
old_chain = make_cleanup_freeargv (argv);
/* Walk through the args, looking for signal oursigs, signal names, and
char **argv;
struct cleanup *old_chain;
+ if (args == NULL)
+ error_no_arg (_("xdb command"));
+
/* Break the command line up into args. */
- argv = buildargv (args);
- if (argv == NULL)
- {
- nomem (0);
- }
+ argv = gdb_buildargv (args);
old_chain = make_cleanup_freeargv (argv);
if (argv[1] != (char *) NULL)
{
{
struct inferior_status *inf_status = XMALLOC (struct inferior_status);
struct thread_info *tp = inferior_thread ();
+ struct inferior *inf = current_inferior ();
inf_status->stop_signal = tp->stop_signal;
inf_status->stop_pc = stop_pc;
inf_status->step_frame_id = tp->step_frame_id;
inf_status->step_over_calls = tp->step_over_calls;
inf_status->stop_after_trap = stop_after_trap;
- inf_status->stop_soon = stop_soon;
+ inf_status->stop_soon = inf->stop_soon;
/* Save original bpstat chain here; replace it with copy of chain.
If caller's caller is walking the chain, they'll be happier if we
hand them back the original chain when restore_inferior_status is
restore_inferior_status (struct inferior_status *inf_status)
{
struct thread_info *tp = inferior_thread ();
+ struct inferior *inf = current_inferior ();
tp->stop_signal = inf_status->stop_signal;
stop_pc = inf_status->stop_pc;
tp->step_frame_id = inf_status->step_frame_id;
tp->step_over_calls = inf_status->step_over_calls;
stop_after_trap = inf_status->stop_after_trap;
- stop_soon = inf_status->stop_soon;
+ inf->stop_soon = inf_status->stop_soon;
bpstat_clear (&tp->stop_bpstat);
tp->stop_bpstat = inf_status->stop_bpstat;
breakpoint_proceeded = inf_status->breakpoint_proceeded;