#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,
#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;
static void
follow_exec (ptid_t pid, char *execd_pathname)
{
- struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
struct inferior *inf = current_inferior ();
char *name = alloca (strlen (gdb_sysroot)
+ strlen (execd_pathname)
+ 1);
+
strcpy (name, gdb_sysroot);
strcat (name, execd_pathname);
execd_pathname = name;
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. */
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;
+
+ /* 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;
+
+ /* 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 architecture the thread had when we stepped it. */
+ struct gdbarch *step_gdbarch;
+
+ /* 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;
-/* The architecture the thread had when we stepped it. */
-static struct gdbarch *displaced_step_gdbarch;
+ return state;
+}
-/* The closure provided gdbarch_displaced_step_copy_insn, to be used
- for post-step cleanup. */
-static struct displaced_step_closure *displaced_step_closure;
+/* Remove the displaced stepping state of process PID. */
-/* The address of the original instruction, and the copy we made. */
-static CORE_ADDR displaced_step_original, displaced_step_copy;
+static void
+remove_displaced_stepping_state (int pid)
+{
+ struct displaced_step_inferior_state *it, **prev_next_p;
-/* Saved contents of copy area. */
-static gdb_byte *displaced_step_saved_copy;
+ 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. */
+
+ displaced = add_displaced_stepping_state (ptid_get_pid (ptid));
- if (!ptid_equal (displaced_step_ptid, null_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);
write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
{
struct cleanup *ptid_cleanup = save_inferior_ptid ();
+
inferior_ptid = ptid;
write_memory (memaddr, myaddr, len);
do_cleanups (ptid_cleanup);
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;
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);
displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
}
- if (gdbarch_displaced_step_hw_singlestep
- (gdbarch, displaced_step_closure))
+ 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);
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
"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
|| (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
return;
}
- step = gdbarch_displaced_step_hw_singlestep
- (gdbarch, displaced_step_closure);
+ 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? */
/* 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;
}
"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. */
start_remote (int from_tty)
{
struct inferior *inferior;
- init_wait_for_inferior ();
+ init_wait_for_inferior ();
inferior = current_inferior ();
inferior->stop_soon = STOP_QUIETLY_REMOTE;
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);
longjmp-resume breakpoint of the thread that just stopped
stepping. */
struct thread_info *tp = inferior_thread ();
+
delete_step_resume_breakpoint (tp);
}
else
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
|| (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
+
if (RECORD_IS_USED)
old_cleanups = record_gdb_operation_disable_set ();
&& ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
{
struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid));
+
gdb_assert (inf);
stop_soon = inf->stop_soon;
}
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 */
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))
+ {
+ 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
if (target_stopped_by_watchpoint ())
{
CORE_ADDR addr;
+
fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n");
if (target_stopped_data_address (¤t_target, &addr))
the instruction and once for the delay slot. */
int step_through_delay
= gdbarch_single_step_through_delay (gdbarch, frame);
+
if (debug_infrun && step_through_delay)
fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
if (ecs->event_thread->step_range_end == 0 && step_through_delay)
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 (get_regcache_aspace (get_current_regcache ()),
- 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)
{
{
/* 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)
if (!non_stop)
{
struct thread_info *tp;
+
tp = iterate_over_threads (currently_stepping_or_nexting_callback,
ecs->event_thread);
if (tp)
/* Set up a step-resume breakpoint at the address
indicated by SKIP_SOLIB_RESOLVER. */
struct symtab_and_line sr_sal;
+
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
sr_sal.pspace = get_frame_program_space (frame);
if (real_stop_pc != 0 && in_solib_dynsym_resolve_code (real_stop_pc))
{
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);
/* Set a breakpoint at callee's start address.
From there we can step once and be back in the caller. */
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);
Set a breakpoint at its start and continue, then
one more step will take us out. */
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);
{
/* Determine where this trampoline returns. */
CORE_ADDR real_stop_pc;
+
real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc);
if (debug_infrun)
struct execution_control_state *ecs)
{
struct symtab *s;
- struct symtab_and_line stop_func_sal, sr_sal;
+ struct symtab_and_line stop_func_sal;
s = find_pc_symtab (stop_pc);
if (s && s->language != language_asm)
if (ecs->event_thread->stepping_over_breakpoint)
{
struct regcache *thread_regcache = get_thread_regcache (ecs->ptid);
+
if (!use_displaced_stepping (get_regcache_arch (thread_regcache)))
/* Since we can't do a displaced step, we have to remove
the breakpoint while we step it. To keep things
else
{
struct gdb_exception e;
+
/* Stop stepping when inserting breakpoints
has failed. */
TRY_CATCH (e, RETURN_MASK_ERROR)
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
(struct inferior_thread_state). */
struct frame_info *frame = get_current_frame ();
+
gdb_assert (get_frame_type (frame) == DUMMY_FRAME);
frame_pop (frame);
/* frame_pop() calls reinit_frame_cache as the last thing it does
signal_stop_update (int signo, int state)
{
int ret = signal_stop[signo];
+
signal_stop[signo] = state;
return ret;
}
signal_print_update (int signo, int state)
{
int ret = signal_print[signo];
+
signal_print[signo] = state;
return ret;
}
signal_pass_update (int signo, int state)
{
int ret = signal_program[signo];
+
signal_program[signo] = state;
return ret;
}
signals_info (char *signum_exp, int from_tty)
{
enum target_signal oursig;
+
sig_print_header ();
if (signum_exp)
&& gdbarch_get_siginfo_type_p (gdbarch))
{
struct type *type = gdbarch_get_siginfo_type (gdbarch);
+
return allocate_computed_value (type, &siginfo_value_funcs, NULL);
}
{
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(). */
restore_inferior_ptid (void *arg)
{
ptid_t *saved_ptid_ptr = arg;
+
inferior_ptid = *saved_ptid_ptr;
xfree (arg);
}
{
int i;
int numsigs;
- struct cmd_list_element *c;
add_info ("signals", signals_info, _("\
What debugger does when program gets various signals.\n\
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