Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
#include "record.h"
#include "inline-frame.h"
#include "jit.h"
+#include "tracepoint.h"
/* Prototypes for local functions */
static int restore_selected_frame (void *);
-static void build_infrun (void);
-
static int follow_fork (void);
static void set_schedlock_func (char *args, int from_tty,
static ptid_t previous_inferior_ptid;
+/* Default behavior is to detach newly forked processes (legacy). */
+int detach_fork = 1;
+
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
#endif
-/* Convert the #defines into values. This is temporary until wfi control
- flow is completely sorted out. */
-
-#ifndef CANNOT_STEP_HW_WATCHPOINTS
-#define CANNOT_STEP_HW_WATCHPOINTS 0
-#else
-#undef CANNOT_STEP_HW_WATCHPOINTS
-#define CANNOT_STEP_HW_WATCHPOINTS 1
-#endif
-
/* Tables of how to react to signals; the user sets them. */
static unsigned char *signal_stop;
insert_breakpoints ();
}
+/* The child has exited or execed: resume threads of the parent the
+ user wanted to be executing. */
+
+static int
+proceed_after_vfork_done (struct thread_info *thread,
+ void *arg)
+{
+ int pid = * (int *) arg;
+
+ if (ptid_get_pid (thread->ptid) == pid
+ && is_running (thread->ptid)
+ && !is_executing (thread->ptid)
+ && !thread->stop_requested
+ && thread->stop_signal == TARGET_SIGNAL_0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resuming vfork parent thread %s\n",
+ target_pid_to_str (thread->ptid));
+
+ switch_to_thread (thread->ptid);
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+
+ return 0;
+}
+
+/* Called whenever we notice an exec or exit event, to handle
+ detaching or resuming a vfork parent. */
+
+static void
+handle_vfork_child_exec_or_exit (int exec)
+{
+ struct inferior *inf = current_inferior ();
+
+ if (inf->vfork_parent)
+ {
+ int resume_parent = -1;
+
+ /* This exec or exit marks the end of the shared memory region
+ between the parent and the child. If the user wanted to
+ detach from the parent, now is the time. */
+
+ if (inf->vfork_parent->pending_detach)
+ {
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+ struct program_space *pspace;
+ struct address_space *aspace;
+
+ /* follow-fork child, detach-on-fork on */
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ /* We're letting loose of the parent. */
+ tp = any_live_thread_of_process (inf->vfork_parent->pid);
+ switch_to_thread (tp->ptid);
+
+ /* We're about to detach from the parent, which implicitly
+ removes breakpoints from its address space. There's a
+ catch here: we want to reuse the spaces for the child,
+ but, parent/child are still sharing the pspace at this
+ point, although the exec in reality makes the kernel give
+ the child a fresh set of new pages. The problem here is
+ that the breakpoints module being unaware of this, would
+ likely chose the child process to write to the parent
+ address space. Swapping the child temporarily away from
+ the spaces has the desired effect. Yes, this is "sort
+ of" a hack. */
+
+ pspace = inf->pspace;
+ aspace = inf->aspace;
+ inf->aspace = NULL;
+ inf->pspace = NULL;
+
+ if (debug_infrun || info_verbose)
+ {
+ target_terminal_ours ();
+
+ if (exec)
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exec.\n",
+ inf->vfork_parent->pid);
+ else
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exit.\n",
+ inf->vfork_parent->pid);
+ }
+
+ target_detach (NULL, 0);
+
+ /* Put it back. */
+ inf->pspace = pspace;
+ inf->aspace = aspace;
+
+ do_cleanups (old_chain);
+ }
+ else if (exec)
+ {
+ /* We're staying attached to the parent, so, really give the
+ child a new address space. */
+ inf->pspace = add_program_space (maybe_new_address_space ());
+ inf->aspace = inf->pspace->aspace;
+ inf->removable = 1;
+ set_current_program_space (inf->pspace);
+
+ resume_parent = inf->vfork_parent->pid;
+
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+ else
+ {
+ struct cleanup *old_chain;
+ struct program_space *pspace;
+
+ /* If this is a vfork child exiting, then the pspace and
+ aspaces were shared with the parent. Since we're
+ reporting the process exit, we'll be mourning all that is
+ found in the address space, and switching to null_ptid,
+ preparing to start a new inferior. But, since we don't
+ want to clobber the parent's address/program spaces, we
+ go ahead and create a new one for this exiting
+ inferior. */
+
+ /* Switch to null_ptid, so that clone_program_space doesn't want
+ to read the selected frame of a dead process. */
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = null_ptid;
+
+ /* This inferior is dead, so avoid giving the breakpoints
+ module the option to write through to it (cloning a
+ program space resets breakpoints). */
+ inf->aspace = NULL;
+ inf->pspace = NULL;
+ pspace = add_program_space (maybe_new_address_space ());
+ set_current_program_space (pspace);
+ inf->removable = 1;
+ clone_program_space (pspace, inf->vfork_parent->pspace);
+ inf->pspace = pspace;
+ inf->aspace = pspace->aspace;
+
+ /* Put back inferior_ptid. We'll continue mourning this
+ inferior. */
+ do_cleanups (old_chain);
+
+ resume_parent = inf->vfork_parent->pid;
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+
+ inf->vfork_parent = NULL;
+
+ gdb_assert (current_program_space == inf->pspace);
+
+ if (non_stop && resume_parent != -1)
+ {
+ /* If the user wanted the parent to be running, let it go
+ free now. */
+ struct cleanup *old_chain = make_cleanup_restore_current_thread ();
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent process %d\n",
+ resume_parent);
+
+ iterate_over_threads (proceed_after_vfork_done, &resume_parent);
+
+ do_cleanups (old_chain);
+ }
+ }
+}
+
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char follow_exec_mode_new[] = "new";
+static const char follow_exec_mode_same[] = "same";
+static const char *follow_exec_mode_names[] =
+{
+ follow_exec_mode_new,
+ follow_exec_mode_same,
+ NULL,
+};
+
+static const char *follow_exec_mode_string = follow_exec_mode_same;
+static void
+show_follow_exec_mode_string (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
+}
+
/* EXECD_PATHNAME is assumed to be non-NULL. */
static void
{
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
+ struct inferior *inf = current_inferior ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
that may write the bp's "shadow contents" (the instruction
value that was overwritten witha TRAP instruction). Since
we now have a new a.out, those shadow contents aren't valid. */
+
+ mark_breakpoints_out ();
+
update_breakpoints_after_exec ();
/* If there was one, it's gone now. We cannot truly step-to-next
th->stop_requested = 0;
/* What is this a.out's name? */
- printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
+ printf_unfiltered (_("%s is executing new program: %s\n"),
+ target_pid_to_str (inferior_ptid),
+ execd_pathname);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
execd_pathname = name;
}
- /* That a.out is now the one to use. */
- exec_file_attach (execd_pathname, 0);
-
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
dld will have had a chance to initialize the child. */
previous incarnation of this process. */
no_shared_libraries (NULL, 0);
+ if (follow_exec_mode_string == follow_exec_mode_new)
+ {
+ struct program_space *pspace;
+ struct inferior *new_inf;
+
+ /* The user wants to keep the old inferior and program spaces
+ around. Create a new fresh one, and switch to it. */
+
+ inf = add_inferior (current_inferior ()->pid);
+ pspace = add_program_space (maybe_new_address_space ());
+ inf->pspace = pspace;
+ inf->aspace = pspace->aspace;
+
+ exit_inferior_num_silent (current_inferior ()->num);
+
+ set_current_inferior (inf);
+ set_current_program_space (pspace);
+ }
+
+ gdb_assert (current_program_space == inf->pspace);
+
+ /* That a.out is now the one to use. */
+ exec_file_attach (execd_pathname, 0);
+
/* Load the main file's symbols. */
symbol_file_add_main (execd_pathname, 0);
#ifdef SOLIB_CREATE_INFERIOR_HOOK
SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
#else
- solib_create_inferior_hook ();
+ solib_create_inferior_hook (0);
#endif
jit_inferior_created_hook ();
displaced step operation on it. See displaced_step_prepare and
displaced_step_fixup for details. */
-/* If this is not null_ptid, this is the thread carrying out a
- displaced single-step. This thread's state will require fixing up
- once it has completed its step. */
-static ptid_t displaced_step_ptid;
-
struct displaced_step_request
{
ptid_t ptid;
struct displaced_step_request *next;
};
-/* A queue of pending displaced stepping requests. */
-struct displaced_step_request *displaced_step_request_queue;
+/* Per-inferior displaced stepping state. */
+struct displaced_step_inferior_state
+{
+ /* Pointer to next in linked list. */
+ struct displaced_step_inferior_state *next;
+
+ /* The process this displaced step state refers to. */
+ int pid;
-/* The architecture the thread had when we stepped it. */
-static struct gdbarch *displaced_step_gdbarch;
+ /* A queue of pending displaced stepping requests. One entry per
+ thread that needs to do a displaced step. */
+ struct displaced_step_request *step_request_queue;
-/* The closure provided gdbarch_displaced_step_copy_insn, to be used
- for post-step cleanup. */
-static struct displaced_step_closure *displaced_step_closure;
+ /* If this is not null_ptid, this is the thread carrying out a
+ displaced single-step in process PID. This thread's state will
+ require fixing up once it has completed its step. */
+ ptid_t step_ptid;
-/* The address of the original instruction, and the copy we made. */
-static CORE_ADDR displaced_step_original, displaced_step_copy;
+ /* The architecture the thread had when we stepped it. */
+ struct gdbarch *step_gdbarch;
-/* Saved contents of copy area. */
-static gdb_byte *displaced_step_saved_copy;
+ /* The closure provided gdbarch_displaced_step_copy_insn, to be used
+ for post-step cleanup. */
+ struct displaced_step_closure *step_closure;
+
+ /* The address of the original instruction, and the copy we
+ made. */
+ CORE_ADDR step_original, step_copy;
+
+ /* Saved contents of copy area. */
+ gdb_byte *step_saved_copy;
+};
+
+/* The list of states of processes involved in displaced stepping
+ presently. */
+static struct displaced_step_inferior_state *displaced_step_inferior_states;
+
+/* Get the displaced stepping state of process PID. */
+
+static struct displaced_step_inferior_state *
+get_displaced_stepping_state (int pid)
+{
+ struct displaced_step_inferior_state *state;
+
+ for (state = displaced_step_inferior_states;
+ state != NULL;
+ state = state->next)
+ if (state->pid == pid)
+ return state;
+
+ return NULL;
+}
+
+/* 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. */
+
+static struct displaced_step_inferior_state *
+add_displaced_stepping_state (int pid)
+{
+ struct displaced_step_inferior_state *state;
+
+ for (state = displaced_step_inferior_states;
+ state != NULL;
+ state = state->next)
+ if (state->pid == pid)
+ return state;
+
+ state = xcalloc (1, sizeof (*state));
+ state->pid = pid;
+ state->next = displaced_step_inferior_states;
+ displaced_step_inferior_states = state;
+
+ return state;
+}
+
+/* Remove the displaced stepping state of process PID. */
+
+static void
+remove_displaced_stepping_state (int pid)
+{
+ struct displaced_step_inferior_state *it, **prev_next_p;
+
+ gdb_assert (pid != 0);
+
+ it = displaced_step_inferior_states;
+ prev_next_p = &displaced_step_inferior_states;
+ while (it)
+ {
+ if (it->pid == pid)
+ {
+ *prev_next_p = it->next;
+ xfree (it);
+ return;
+ }
+
+ prev_next_p = &it->next;
+ it = *prev_next_p;
+ }
+}
+
+static void
+infrun_inferior_exit (struct inferior *inf)
+{
+ remove_displaced_stepping_state (inf->pid);
+}
/* Enum strings for "set|show displaced-stepping". */
/* Clean out any stray displaced stepping state. */
static void
-displaced_step_clear (void)
+displaced_step_clear (struct displaced_step_inferior_state *displaced)
{
/* Indicate that there is no cleanup pending. */
- displaced_step_ptid = null_ptid;
+ displaced->step_ptid = null_ptid;
- if (displaced_step_closure)
+ if (displaced->step_closure)
{
- gdbarch_displaced_step_free_closure (displaced_step_gdbarch,
- displaced_step_closure);
- displaced_step_closure = NULL;
+ gdbarch_displaced_step_free_closure (displaced->step_gdbarch,
+ displaced->step_closure);
+ displaced->step_closure = NULL;
}
}
static void
-displaced_step_clear_cleanup (void *ignore)
+displaced_step_clear_cleanup (void *arg)
{
- displaced_step_clear ();
+ struct displaced_step_inferior_state *state = arg;
+
+ displaced_step_clear (state);
}
/* Dump LEN bytes at BUF in hex to FILE, followed by a newline. */
CORE_ADDR original, copy;
ULONGEST len;
struct displaced_step_closure *closure;
+ struct displaced_step_inferior_state *displaced;
/* We should never reach this function if the architecture does not
support displaced stepping. */
gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
- /* For the first cut, we're displaced stepping one thread at a
- time. */
+ /* We have to displaced step one thread at a time, as we only have
+ access to a single scratch space per inferior. */
- if (!ptid_equal (displaced_step_ptid, null_ptid))
+ displaced = add_displaced_stepping_state (ptid_get_pid (ptid));
+
+ if (!ptid_equal (displaced->step_ptid, null_ptid))
{
/* Already waiting for a displaced step to finish. Defer this
request and place in queue. */
new_req->ptid = ptid;
new_req->next = NULL;
- if (displaced_step_request_queue)
+ if (displaced->step_request_queue)
{
- for (req = displaced_step_request_queue;
+ for (req = displaced->step_request_queue;
req && req->next;
req = req->next)
;
req->next = new_req;
}
else
- displaced_step_request_queue = new_req;
+ displaced->step_request_queue = new_req;
return 0;
}
target_pid_to_str (ptid));
}
- displaced_step_clear ();
+ displaced_step_clear (displaced);
old_cleanups = save_inferior_ptid ();
inferior_ptid = ptid;
len = gdbarch_max_insn_length (gdbarch);
/* Save the original contents of the copy area. */
- displaced_step_saved_copy = xmalloc (len);
+ displaced->step_saved_copy = xmalloc (len);
ignore_cleanups = make_cleanup (free_current_contents,
- &displaced_step_saved_copy);
- read_memory (copy, displaced_step_saved_copy, len);
+ &displaced->step_saved_copy);
+ read_memory (copy, displaced->step_saved_copy, len);
if (debug_displaced)
{
fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
paddress (gdbarch, copy));
- displaced_step_dump_bytes (gdb_stdlog, displaced_step_saved_copy, len);
+ displaced_step_dump_bytes (gdb_stdlog,
+ displaced->step_saved_copy,
+ len);
};
closure = gdbarch_displaced_step_copy_insn (gdbarch,
/* Save the information we need to fix things up if the step
succeeds. */
- displaced_step_ptid = ptid;
- displaced_step_gdbarch = gdbarch;
- displaced_step_closure = closure;
- displaced_step_original = original;
- displaced_step_copy = copy;
+ displaced->step_ptid = ptid;
+ displaced->step_gdbarch = gdbarch;
+ displaced->step_closure = closure;
+ displaced->step_original = original;
+ displaced->step_copy = copy;
- make_cleanup (displaced_step_clear_cleanup, 0);
+ make_cleanup (displaced_step_clear_cleanup, displaced);
/* Resume execution at the copy. */
regcache_write_pc (regcache, copy);
displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
{
struct cleanup *old_cleanups;
+ struct displaced_step_inferior_state *displaced
+ = get_displaced_stepping_state (ptid_get_pid (event_ptid));
+
+ /* Was any thread of this process doing a displaced step? */
+ if (displaced == NULL)
+ return;
/* Was this event for the pid we displaced? */
- if (ptid_equal (displaced_step_ptid, null_ptid)
- || ! ptid_equal (displaced_step_ptid, event_ptid))
+ if (ptid_equal (displaced->step_ptid, null_ptid)
+ || ! ptid_equal (displaced->step_ptid, event_ptid))
return;
- old_cleanups = make_cleanup (displaced_step_clear_cleanup, 0);
+ old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced);
/* Restore the contents of the copy area. */
{
- ULONGEST len = gdbarch_max_insn_length (displaced_step_gdbarch);
- write_memory_ptid (displaced_step_ptid, displaced_step_copy,
- displaced_step_saved_copy, len);
+ ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch);
+ write_memory_ptid (displaced->step_ptid, displaced->step_copy,
+ displaced->step_saved_copy, len);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: restored %s\n",
- paddress (displaced_step_gdbarch,
- displaced_step_copy));
+ paddress (displaced->step_gdbarch,
+ displaced->step_copy));
}
/* Did the instruction complete successfully? */
if (signal == TARGET_SIGNAL_TRAP)
{
/* Fix up the resulting state. */
- gdbarch_displaced_step_fixup (displaced_step_gdbarch,
- displaced_step_closure,
- displaced_step_original,
- displaced_step_copy,
- get_thread_regcache (displaced_step_ptid));
+ gdbarch_displaced_step_fixup (displaced->step_gdbarch,
+ displaced->step_closure,
+ displaced->step_original,
+ displaced->step_copy,
+ get_thread_regcache (displaced->step_ptid));
}
else
{
relocate the PC. */
struct regcache *regcache = get_thread_regcache (event_ptid);
CORE_ADDR pc = regcache_read_pc (regcache);
- pc = displaced_step_original + (pc - displaced_step_copy);
+ pc = displaced->step_original + (pc - displaced->step_copy);
regcache_write_pc (regcache, pc);
}
do_cleanups (old_cleanups);
- displaced_step_ptid = null_ptid;
+ displaced->step_ptid = null_ptid;
/* Are there any pending displaced stepping requests? If so, run
- one now. */
- while (displaced_step_request_queue)
+ one now. Leave the state object around, since we're likely to
+ need it again soon. */
+ while (displaced->step_request_queue)
{
struct displaced_step_request *head;
ptid_t ptid;
struct regcache *regcache;
struct gdbarch *gdbarch;
CORE_ADDR actual_pc;
+ struct address_space *aspace;
- head = displaced_step_request_queue;
+ head = displaced->step_request_queue;
ptid = head->ptid;
- displaced_step_request_queue = head->next;
+ displaced->step_request_queue = head->next;
xfree (head);
context_switch (ptid);
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
+ aspace = get_regcache_aspace (regcache);
- if (breakpoint_here_p (actual_pc))
+ if (breakpoint_here_p (aspace, actual_pc))
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
}
- if (gdbarch_software_single_step_p (gdbarch))
- target_resume (ptid, 0, TARGET_SIGNAL_0);
- else
+ if (gdbarch_displaced_step_hw_singlestep (gdbarch,
+ displaced->step_closure))
target_resume (ptid, 1, TARGET_SIGNAL_0);
+ else
+ target_resume (ptid, 0, TARGET_SIGNAL_0);
/* Done, we're stepping a thread. */
break;
infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
{
struct displaced_step_request *it;
+ struct displaced_step_inferior_state *displaced;
if (ptid_equal (inferior_ptid, old_ptid))
inferior_ptid = new_ptid;
if (ptid_equal (singlestep_ptid, old_ptid))
singlestep_ptid = new_ptid;
- if (ptid_equal (displaced_step_ptid, old_ptid))
- displaced_step_ptid = new_ptid;
-
if (ptid_equal (deferred_step_ptid, old_ptid))
deferred_step_ptid = new_ptid;
- for (it = displaced_step_request_queue; it; it = it->next)
- if (ptid_equal (it->ptid, old_ptid))
- it->ptid = new_ptid;
+ for (displaced = displaced_step_inferior_states;
+ displaced;
+ displaced = displaced->next)
+ {
+ if (ptid_equal (displaced->step_ptid, old_ptid))
+ displaced->step_ptid = new_ptid;
+
+ for (it = displaced->step_request_queue; it; it = it->next)
+ if (ptid_equal (it->ptid, old_ptid))
+ it->ptid = new_ptid;
+ }
}
\f
{
int hw_step = 1;
- if (gdbarch_software_single_step_p (gdbarch))
+ if (gdbarch_software_single_step_p (gdbarch)
+ && gdbarch_software_single_step (gdbarch, get_current_frame ()))
{
- if (use_displaced_stepping (gdbarch))
- hw_step = 0;
- else if (gdbarch_software_single_step (gdbarch, get_current_frame ()))
- {
- hw_step = 0;
- /* Do not pull these breakpoints until after a `wait' in
- `wait_for_inferior' */
- singlestep_breakpoints_inserted_p = 1;
- singlestep_ptid = inferior_ptid;
- singlestep_pc = pc;
- }
+ hw_step = 0;
+ /* Do not pull these breakpoints until after a `wait' in
+ `wait_for_inferior' */
+ singlestep_breakpoints_inserted_p = 1;
+ singlestep_ptid = inferior_ptid;
+ singlestep_pc = pc;
}
return hw_step;
}
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
QUIT;
"trap_expected=%d\n",
step, sig, tp->trap_expected);
- /* Some targets (e.g. Solaris x86) have a kernel bug when stepping
- over an instruction that causes a page fault without triggering
- a hardware watchpoint. The kernel properly notices that it shouldn't
- stop, because the hardware watchpoint is not triggered, but it forgets
- the step request and continues the program normally.
- Work around the problem by removing hardware watchpoints if a step is
- requested, GDB will check for a hardware watchpoint trigger after the
- step anyway. */
- if (CANNOT_STEP_HW_WATCHPOINTS && step)
- remove_hw_watchpoints ();
-
-
/* Normally, by the time we reach `resume', the breakpoints are either
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
- if (breakpoint_here_p (pc) == permanent_breakpoint_here)
+ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
|| (step && gdbarch_software_single_step_p (gdbarch)))
&& sig == TARGET_SIGNAL_0)
{
+ struct displaced_step_inferior_state *displaced;
+
if (!displaced_step_prepare (inferior_ptid))
{
/* Got placed in displaced stepping queue. Will be resumed
discard_cleanups (old_cleanups);
return;
}
+
+ displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid));
+ step = gdbarch_displaced_step_hw_singlestep (gdbarch,
+ displaced->step_closure);
}
/* Do we need to do it the hard way, w/temp breakpoints? */
- if (step)
+ else if (step)
step = maybe_software_singlestep (gdbarch, pc);
if (should_resume)
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
- if (step && breakpoint_inserted_here_p (pc))
+ if (step && breakpoint_inserted_here_p (aspace, pc))
step = 0;
}
void
clear_proceed_status (void)
{
+ if (!non_stop)
+ {
+ /* In all-stop mode, delete the per-thread status of all
+ threads, even if inferior_ptid is null_ptid, there may be
+ threads on the list. E.g., we may be launching a new
+ process, while selecting the executable. */
+ iterate_over_threads (clear_proceed_status_callback, NULL);
+ }
+
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inferior;
if (non_stop)
{
- /* If in non-stop mode, only delete the per-thread status
- of the current thread. */
+ /* If in non-stop mode, only delete the per-thread status of
+ the current thread. */
clear_proceed_status_thread (inferior_thread ());
}
- else
- {
- /* In all-stop mode, delete the per-thread status of
- *all* threads. */
- iterate_over_threads (clear_proceed_status_callback, NULL);
- }
-
+
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
}
/* Make sure we were stopped at a breakpoint. */
if (wait_status.kind != TARGET_WAITKIND_STOPPED
- || wait_status.value.sig != TARGET_SIGNAL_TRAP)
+ || (wait_status.value.sig != TARGET_SIGNAL_TRAP
+ && wait_status.value.sig != TARGET_SIGNAL_ILL
+ && wait_status.value.sig != TARGET_SIGNAL_SEGV
+ && wait_status.value.sig != TARGET_SIGNAL_EMT))
{
return 0;
}
{
struct regcache *regcache = get_thread_regcache (wait_ptid);
- if (breakpoint_here_p (regcache_read_pc (regcache)))
+ if (breakpoint_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache)))
{
/* If stepping, remember current thread to switch back to. */
if (step)
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
+ struct address_space *aspace;
int oneproc = 0;
/* If we're stopped at a fork/vfork, follow the branch set by the
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
+ aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);
if (step > 0)
if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc && breakpoint_here_p (pc)
+ if (pc == stop_pc && breakpoint_here_p (aspace, pc)
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
step one instruction before inserting breakpoints so that
"infrun: proceed (addr=%s, signal=%d, step=%d)\n",
paddress (gdbarch, addr), siggnal, step);
+ /* We're handling a live event, so make sure we're doing live
+ debugging. If we're looking at traceframes while the target is
+ running, we're going to need to get back to that mode after
+ handling the event. */
+ if (non_stop)
+ {
+ make_cleanup_restore_current_traceframe ();
+ set_traceframe_number (-1);
+ }
+
if (non_stop)
/* In non-stop, each thread is handled individually. The context
must already be set to the right thread here. */
or a return command, we often end up a few instructions forward, still
within the original line we started.
- An attempt was made to have init_execution_control_state () refresh
- the prev_pc value before calculating the line number. This approach
- did not work because on platforms that use ptrace, the pc register
- cannot be read unless the inferior is stopped. At that point, we
- are not guaranteed the inferior is stopped and so the regcache_read_pc ()
- call can fail. Setting the prev_pc value here ensures the value is
- updated correctly when the inferior is stopped. */
+ An attempt was made to refresh the prev_pc at the same time the
+ execution_control_state is initialized (for instance, just before
+ waiting for an inferior event). But this approach did not work
+ because of platforms that use ptrace, where the pc register cannot
+ be read unless the inferior is stopped. At that point, we are not
+ guaranteed the inferior is stopped and so the regcache_read_pc() call
+ can fail. Setting the prev_pc value here ensures the value is updated
+ correctly when the inferior is stopped. */
tp->prev_pc = regcache_read_pc (get_current_regcache ());
/* Fill in with reasonable starting values. */
previous_inferior_ptid = null_ptid;
init_infwait_state ();
- displaced_step_clear ();
-
/* Discard any skipped inlined frames. */
clear_inline_frame_state (minus_one_ptid);
}
int wait_some_more;
};
-static void init_execution_control_state (struct execution_control_state *ecs);
-
static void handle_inferior_event (struct execution_control_state *ecs);
static void handle_step_into_function (struct gdbarch *gdbarch,
static void
infrun_thread_stop_requested (ptid_t ptid)
{
- struct displaced_step_request *it, *next, *prev = NULL;
+ struct displaced_step_inferior_state *displaced;
/* PTID was requested to stop. Remove it from the displaced
stepping queue, so we don't try to resume it automatically. */
- for (it = displaced_step_request_queue; it; it = next)
+
+ for (displaced = displaced_step_inferior_states;
+ displaced;
+ displaced = displaced->next)
{
- next = it->next;
+ struct displaced_step_request *it, **prev_next_p;
- if (ptid_equal (it->ptid, ptid)
- || ptid_equal (minus_one_ptid, ptid)
- || (ptid_is_pid (ptid)
- && ptid_get_pid (ptid) == ptid_get_pid (it->ptid)))
+ it = displaced->step_request_queue;
+ prev_next_p = &displaced->step_request_queue;
+ while (it)
{
- if (displaced_step_request_queue == it)
- displaced_step_request_queue = it->next;
+ if (ptid_match (it->ptid, ptid))
+ {
+ *prev_next_p = it->next;
+ it->next = NULL;
+ xfree (it);
+ }
else
- prev->next = it->next;
+ {
+ prev_next_p = &it->next;
+ }
- xfree (it);
+ it = *prev_next_p;
}
- else
- prev = it;
}
iterate_over_threads (infrun_thread_stop_requested_callback, &ptid);
ui_file_delete (tmp_stream);
}
+/* Prepare and stabilize the inferior for detaching it. E.g.,
+ detaching while a thread is displaced stepping is a recipe for
+ crashing it, as nothing would readjust the PC out of the scratch
+ pad. */
+
+void
+prepare_for_detach (void)
+{
+ struct inferior *inf = current_inferior ();
+ ptid_t pid_ptid = pid_to_ptid (inf->pid);
+ struct cleanup *old_chain_1;
+ struct displaced_step_inferior_state *displaced;
+
+ displaced = get_displaced_stepping_state (inf->pid);
+
+ /* Is any thread of this process displaced stepping? If not,
+ there's nothing else to do. */
+ if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid))
+ return;
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced-stepping in-process while detaching");
+
+ old_chain_1 = make_cleanup_restore_integer (&inf->detaching);
+ inf->detaching = 1;
+
+ while (!ptid_equal (displaced->step_ptid, null_ptid))
+ {
+ struct cleanup *old_chain_2;
+ struct execution_control_state ecss;
+ struct execution_control_state *ecs;
+
+ ecs = &ecss;
+ memset (ecs, 0, sizeof (*ecs));
+
+ overlay_cache_invalid = 1;
+
+ /* We have to invalidate the registers BEFORE calling
+ target_wait because they can be loaded from the target while
+ in target_wait. This makes remote debugging a bit more
+ efficient for those targets that provide critical registers
+ as part of their normal status mechanism. */
+
+ registers_changed ();
+
+ if (deprecated_target_wait_hook)
+ ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0);
+ else
+ ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0);
+
+ if (debug_infrun)
+ print_target_wait_results (pid_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_2 = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+
+ /* In non-stop mode, each thread is handled individually.
+ Switch early, so the global state is set correctly for this
+ thread. */
+ if (non_stop
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+ context_switch (ecs->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_2);
+
+ /* Breakpoints and watchpoints are not installed on the target
+ at this point, and signals are passed directly to the
+ inferior, so this must mean the process is gone. */
+ if (!ecs->wait_some_more)
+ {
+ discard_cleanups (old_chain_1);
+ error (_("Program exited while detaching"));
+ }
+ }
+
+ discard_cleanups (old_chain_1);
+}
+
/* Wait for control to return from inferior to debugger.
If TREAT_EXEC_AS_SIGTRAP is non-zero, then handle EXEC signals
tp->current_line = sal.line;
}
-/* Prepare an execution control state for looping through a
- wait_for_inferior-type loop. */
-
-static void
-init_execution_control_state (struct execution_control_state *ecs)
-{
- ecs->random_signal = 0;
-}
-
/* Clear context switchable stepping state. */
void
{
struct regcache *regcache;
struct gdbarch *gdbarch;
+ struct address_space *aspace;
CORE_ADDR breakpoint_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
if (gdbarch_decr_pc_after_break (gdbarch) == 0)
return;
+ aspace = get_regcache_aspace (regcache);
+
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
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)))
+ if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
It returns 1 if the inferior should keep going (and GDB
should ignore the event), or 0 if the event deserves to be
processed. */
+
static int
-deal_with_syscall_event (struct execution_control_state *ecs)
+handle_syscall_event (struct execution_control_state *ecs)
{
- struct regcache *regcache = get_thread_regcache (ecs->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int syscall_number = gdbarch_get_syscall_number (gdbarch,
- ecs->ptid);
+ 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 = gdbarch_get_syscall_number (gdbarch, ecs->ptid);
+ stop_pc = regcache_read_pc (regcache);
+
target_last_waitstatus.value.syscall_number = syscall_number;
if (catch_syscall_enabled () > 0
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
syscall_number);
- ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
-
- if (!ptid_equal (ecs->ptid, inferior_ptid))
- {
- context_switch (ecs->ptid);
- reinit_frame_cache ();
- }
-
- stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
-
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (regcache),
+ 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)
- {
- ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
- keep_going (ecs);
- return 1;
- }
- return 0;
- }
- else
- {
- resume (0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return 1;
+ if (!ecs->random_signal)
+ {
+ /* Catchpoint hit. */
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
+ return 0;
+ }
}
+
+ /* If no catchpoint triggered for this, then keep going. */
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return 1;
}
/* Given an execution control state that has been freshly filled in
struct symtab_and_line stop_pc_sal;
enum stop_kind stop_soon;
+ if (ecs->ws.kind == TARGET_WAITKIND_IGNORE)
+ {
+ /* We had an event in the inferior, but we are not interested in
+ handling it at this level. The lower layers have already
+ done what needs to be done, if anything.
+
+ One of the possible circumstances for this is when the
+ inferior produces output for the console. The inferior has
+ not stopped, and we are ignoring the event. Another possible
+ circumstance is any event which the lower level knows will be
+ reported multiple times without an intervening resume. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_IGNORE\n");
+ prepare_to_wait (ecs);
+ return;
+ }
+
if (ecs->ws.kind != TARGET_WAITKIND_EXITED
- && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
- && ecs->ws.kind != TARGET_WAITKIND_IGNORE)
+ && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
gdb_assert (inf);
target_last_waitstatus = ecs->ws;
/* Always clear state belonging to the previous time we stopped. */
- stop_stack_dummy = 0;
+ stop_stack_dummy = STOP_NONE;
/* If it's a new process, add it to the thread database */
/* 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 ();
+
+ /* First, distinguish signals caused by the debugger from signals
+ that have to do with the program's own actions. Note that
+ breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending
+ on the operating system version. Here we detect when a SIGILL or
+ SIGEMT is really a breakpoint and change it to SIGTRAP. We do
+ something similar for SIGSEGV, since a SIGSEGV will be generated
+ when we're trying to execute a breakpoint instruction on a
+ non-executable stack. This happens for call dummy breakpoints
+ for architectures like SPARC that place call dummies on the
+ stack. */
+ if (ecs->ws.kind == TARGET_WAITKIND_STOPPED
+ && (ecs->ws.value.sig == TARGET_SIGNAL_ILL
+ || ecs->ws.value.sig == TARGET_SIGNAL_SEGV
+ || ecs->ws.value.sig == TARGET_SIGNAL_EMT))
{
- breakpoint_retire_moribund ();
-
- /* Mark the non-executing threads accordingly. In all-stop, all
- threads of all processes are stopped when we get any event
- reported. In non-stop mode, only the event thread stops. If
- we're handling a process exit in non-stop mode, there's
- nothing to do, as threads of the dead process are gone, and
- threads of any other process were left running. */
- if (!non_stop)
- set_executing (minus_one_ptid, 0);
- else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
- && ecs->ws.kind != TARGET_WAITKIND_EXITED)
- set_executing (inferior_ptid, 0);
+ struct regcache *regcache = get_thread_regcache (ecs->ptid);
+
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache)))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: Treating signal as SIGTRAP\n");
+ ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
+ }
}
+ /* Mark the non-executing threads accordingly. In all-stop, all
+ threads of all processes are stopped when we get any event
+ reported. In non-stop mode, only the event thread stops. If
+ we're handling a process exit in non-stop mode, there's nothing
+ to do, as threads of the dead process are gone, and threads of
+ any other process were left running. */
+ if (!non_stop)
+ set_executing (minus_one_ptid, 0);
+ else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+ && ecs->ws.kind != TARGET_WAITKIND_EXITED)
+ set_executing (inferior_ptid, 0);
+
switch (infwait_state)
{
case infwait_thread_hop_state:
dynamically loaded objects (among other things). */
if (stop_on_solib_events)
{
+ /* Make sure we print "Stopped due to solib-event" in
+ normal_stop. */
+ stop_print_frame = 1;
+
stop_stepping (ecs);
return;
}
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\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_stop_reason (EXITED, ecs->ws.value.integer);
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 */
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
- ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+ /* 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->stop_bpstat);
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
+ ptid_t parent;
+ ptid_t child;
int should_resume;
+ int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
should_resume = follow_fork ();
+ parent = ecs->ptid;
+ child = ecs->ws.value.related_pid;
+
+ /* In non-stop mode, also resume the other branch. */
+ if (non_stop && !detach_fork)
+ {
+ if (follow_child)
+ switch_to_thread (parent);
+ else
+ switch_to_thread (child);
+
+ ecs->event_thread = inferior_thread ();
+ ecs->ptid = inferior_ptid;
+ keep_going (ecs);
+ }
+
+ if (follow_child)
+ switch_to_thread (child);
+ else
+ switch_to_thread (parent);
+
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;
ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
+ case TARGET_WAITKIND_VFORK_DONE:
+ /* Done with the shared memory region. Re-insert breakpoints in
+ the parent, and keep going. */
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORK_DONE\n");
+
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ context_switch (ecs->ptid);
+
+ current_inferior ()->waiting_for_vfork_done = 0;
+ current_inferior ()->pspace->breakpoints_not_allowed = 0;
+ /* This also takes care of reinserting breakpoints in the
+ previously locked inferior. */
+ keep_going (ecs);
+ return;
+
case TARGET_WAITKIND_EXECD:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Do whatever is necessary to the parent branch of the vfork. */
+ handle_vfork_child_exec_or_exit (1);
+
/* 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, ecs->ws.value.execd_pathname);
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* Note that this may be referenced from inside
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
/* Getting the current syscall number */
- if (deal_with_syscall_event (ecs) != 0)
+ if (handle_syscall_event (ecs) != 0)
return;
goto process_event_stop_test;
- break;
/* Before examining the threads further, step this thread to
get it entirely out of the syscall. (We get notice of the
case TARGET_WAITKIND_SYSCALL_RETURN:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
- if (deal_with_syscall_event (ecs) != 0)
+ if (handle_syscall_event (ecs) != 0)
return;
goto process_event_stop_test;
- break;
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
print_stop_reason (NO_HISTORY, 0);
stop_stepping (ecs);
return;
-
- /* We had an event in the inferior, but we are not interested
- in handling it at this level. The lower layers have already
- done what needs to be done, if anything.
-
- One of the possible circumstances for this is when the
- inferior produces output for the console. The inferior has
- not stopped, and we are ignoring the event. Another possible
- circumstance is any event which the lower level knows will be
- reported multiple times without an intervening resume. */
- case TARGET_WAITKIND_IGNORE:
- if (debug_infrun)
- fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_IGNORE\n");
- prepare_to_wait (ecs);
- return;
}
if (ecs->new_thread_event)
{
struct regcache *regcache = get_thread_regcache (ecs->ptid);
struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct cleanup *old_chain = save_inferior_ptid ();
+
+ inferior_ptid = ecs->ptid;
fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n",
paddress (gdbarch, stop_pc));
fprintf_unfiltered (gdb_stdlog,
"infrun: (no data address available)\n");
}
+
+ do_cleanups (old_chain);
}
if (stepping_past_singlestep_breakpoint)
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
+ struct address_space *aspace =
+ get_regcache_aspace (get_thread_regcache (ecs->ptid));
/* Check if a regular breakpoint has been hit before checking
for a potential single step breakpoint. Otherwise, GDB will
not see this breakpoint hit when stepping onto breakpoints. */
- if (regular_breakpoint_inserted_here_p (stop_pc))
+ if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
{
ecs->random_signal = 0;
- if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
thread_hop_needed = 1;
}
else if (singlestep_breakpoints_inserted_p)
3) set ecs->random_signal to 1, and the decision between 1 and 2
will be made according to the signal handling tables. */
- /* First, distinguish signals caused by the debugger from signals
- that have to do with the program's own actions. Note that
- breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending
- on the operating system version. Here we detect when a SIGILL or
- SIGEMT is really a breakpoint and change it to SIGTRAP. We do
- something similar for SIGSEGV, since a SIGSEGV will be generated
- when we're trying to execute a breakpoint instruction on a
- non-executable stack. This happens for call dummy breakpoints
- for architectures like SPARC that place call dummies on the
- stack.
-
- If we're doing a displaced step past a breakpoint, then the
- breakpoint is always inserted at the original instruction;
- non-standard signals can't be explained by the breakpoint. */
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
- || (! ecs->event_thread->trap_expected
- && breakpoint_inserted_here_p (stop_pc)
- && (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
- || ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
- || ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
|| stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
|| stop_soon == STOP_QUIETLY_REMOTE)
{
}
/* See if there is a breakpoint at the current PC. */
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
+
/* 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->stop_signal == TARGET_SIGNAL_TRAP
+ && !bpstat_explains_signal (ecs->event_thread->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
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
ecs->random_signal
= !(bpstat_explains_signal (ecs->event_thread->stop_bpstat)
+ || stopped_by_watchpoint
|| ecs->event_thread->trap_expected
|| (ecs->event_thread->step_range_end
&& ecs->event_thread->step_resume_breakpoint == NULL));
{
/* 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",
to remain stopped. */
if (stop_soon != NO_STOP_QUIETLY
|| ecs->event_thread->stop_requested
- || signal_stop_state (ecs->event_thread->stop_signal))
+ || (!inf->detaching
+ && signal_stop_state (ecs->event_thread->stop_signal)))
{
stop_stepping (ecs);
return;
if (what.call_dummy)
{
- stop_stack_dummy = 1;
+ stop_stack_dummy = what.call_dummy;
}
switch (what.main_action)
return;
}
+ /* Re-fetch current thread's frame in case the code above caused
+ the frame cache to be re-initialized, making our FRAME variable
+ a dangling pointer. */
+ frame = get_current_frame ();
+
/* If stepping through a line, keep going if still within it.
Note that step_range_end is the address of the first instruction
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
+ sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
"outermost" function. This could be fixed by marking
outermost frames as !stack_p,code_p,special_p. Then the
initial outermost frame, before sp was valid, would
- have code_addr == &_start. See the commend in frame_id_eq
+ have code_addr == &_start. See the comment in frame_id_eq
for more. */
if (!frame_id_eq (get_stack_frame_id (frame),
ecs->event_thread->step_stack_frame_id)
/* Normal function call return (static or dynamic). */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ 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);
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);
struct symtab_and_line tmp_sal;
tmp_sal = find_pc_line (ecs->stop_func_start, 0);
+ tmp_sal.pspace = get_frame_program_space (frame);
if (tmp_sal.line != 0)
{
if (execution_direction == EXEC_REVERSE)
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);
}
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);
keep_going (ecs);
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = get_frame_program_space (frame);
/* Do not specify what the fp should be when we stop since
on some machines the prologue is where the new fp value
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ sr_sal.pspace = get_frame_program_space (get_current_frame ());
/* Do not specify what the fp should be when we stop since on
some machines the prologue is where the new fp value is
gdbarch = get_frame_arch (return_frame);
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = get_frame_program_space (return_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
get_stack_frame_id (return_frame));
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
frame_unwind_caller_pc (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = frame_unwind_program_space (next_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
frame_unwind_caller_id (next_frame));
static void
keep_going (struct execution_control_state *ecs)
{
+ /* Make sure normal_stop is called if we get a QUIT handled before
+ reaching resume. */
+ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0);
+
/* Save the pc before execution, to compare with pc after stop. */
ecs->event_thread->prev_pc
= regcache_read_pc (get_thread_regcache (ecs->ptid));
/* 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. */
+
+ discard_cleanups (old_cleanups);
resume (currently_stepping (ecs->event_thread),
ecs->event_thread->stop_signal);
}
}
if (e.reason < 0)
{
+ exception_print (gdb_stderr, e);
stop_stepping (ecs);
return;
}
&& !signal_program[ecs->event_thread->stop_signal])
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ discard_cleanups (old_cleanups);
resume (currently_stepping (ecs->event_thread),
ecs->event_thread->stop_signal);
}
stop_registers = regcache_dup (get_current_regcache ());
}
- if (stop_stack_dummy)
+ if (stop_stack_dummy == STOP_STACK_DUMMY)
{
/* Pop the empty frame that contains the stack dummy.
This also restores inferior state prior to the call
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
}
+
+ /* Try to get rid of automatically added inferiors that are no
+ longer needed. Keeping those around slows down things linearly.
+ Note that this never removes the current inferior. */
+ prune_inferiors ();
}
static int
{
bpstat stop_bpstat;
int stop_step;
- int stop_stack_dummy;
+ enum stop_stack_kind stop_stack_dummy;
int stopped_by_random_signal;
int stepping_over_breakpoint;
CORE_ADDR step_range_start;
return (ptid_get_lwp (ptid) == 0 && ptid_get_tid (ptid) == 0);
}
+int
+ptid_match (ptid_t ptid, ptid_t filter)
+{
+ /* Since both parameters have the same type, prevent easy mistakes
+ from happening. */
+ gdb_assert (!ptid_equal (ptid, minus_one_ptid)
+ && !ptid_equal (ptid, null_ptid));
+
+ if (ptid_equal (filter, minus_one_ptid))
+ return 1;
+ if (ptid_is_pid (filter)
+ && ptid_get_pid (ptid) == ptid_get_pid (filter))
+ return 1;
+ else if (ptid_equal (ptid, filter))
+ return 1;
+
+ return 0;
+}
+
/* restore_inferior_ptid() will be used by the cleanup machinery
to restore the inferior_ptid value saved in a call to
save_inferior_ptid(). */
show_follow_fork_mode_string,
&setlist, &showlist);
+ add_setshow_enum_cmd ("follow-exec-mode", class_run,
+ follow_exec_mode_names,
+ &follow_exec_mode_string, _("\
+Set debugger response to a program call of exec."), _("\
+Show debugger response to a program call of exec."), _("\
+An exec call replaces the program image of a process.\n\
+\n\
+follow-exec-mode can be:\n\
+\n\
+ new - the debugger creates a new inferior and rebinds the process \n\
+to this new inferior. The program the process was running before\n\
+the exec call can be restarted afterwards by restarting the original\n\
+inferior.\n\
+\n\
+ same - the debugger keeps the process bound to the same inferior.\n\
+The new executable image replaces the previous executable loaded in\n\
+the inferior. Restarting the inferior after the exec call restarts\n\
+the executable the process was running after the exec call.\n\
+\n\
+By default, the debugger will use the same inferior."),
+ NULL,
+ show_follow_exec_mode_string,
+ &setlist, &showlist);
+
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
set_exec_direction_func, show_exec_direction_func,
&setlist, &showlist);
+ /* Set/show detach-on-fork: user-settable mode. */
+
+ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
+Set whether gdb will detach the child of a fork."), _("\
+Show whether gdb will detach the child of a fork."), _("\
+Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);
inferior_ptid = null_ptid;
target_last_wait_ptid = minus_one_ptid;
- displaced_step_ptid = null_ptid;
observer_attach_thread_ptid_changed (infrun_thread_ptid_changed);
observer_attach_thread_stop_requested (infrun_thread_stop_requested);
observer_attach_thread_exit (infrun_thread_thread_exit);
+ observer_attach_inferior_exit (infrun_inferior_exit);
/* Explicitly create without lookup, since that tries to create a
value with a void typed value, and when we get here, gdbarch