current_thread = saved_thread;
}
-/* This function should only be called if LWP got a SIGTRAP.
- The SIGTRAP could mean several things.
+static int check_stopped_by_watchpoint (struct lwp_info *child);
- On i386, where decr_pc_after_break is non-zero:
-
- If we were single-stepping this process using PTRACE_SINGLESTEP, we
- will get only the one SIGTRAP. The value of $eip will be the next
- instruction. If the instruction we stepped over was a breakpoint,
- we need to decrement the PC.
-
- If we continue the process using PTRACE_CONT, we will get a
- SIGTRAP when we hit a breakpoint. The value of $eip will be
- the instruction after the breakpoint (i.e. needs to be
- decremented). If we report the SIGTRAP to GDB, we must also
- report the undecremented PC. If the breakpoint is removed, we
- must resume at the decremented PC.
-
- On a non-decr_pc_after_break machine with hardware or kernel
- single-step:
-
- If we either single-step a breakpoint instruction, or continue and
- hit a breakpoint instruction, our PC will point at the breakpoint
- instruction. */
+/* Called when the LWP stopped for a signal/trap. If it stopped for a
+ trap check what caused it (breakpoint, watchpoint, trace, etc.),
+ and save the result in the LWP's stop_reason field. If it stopped
+ for a breakpoint, decrement the PC if necessary on the lwp's
+ architecture. Returns true if we now have the LWP's stop PC. */
static int
-check_stopped_by_breakpoint (struct lwp_info *lwp)
+save_stop_reason (struct lwp_info *lwp)
{
CORE_ADDR pc;
CORE_ADDR sw_breakpoint_pc;
{
if (siginfo.si_signo == SIGTRAP)
{
- if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code))
+ if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code)
+ && GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code))
{
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by software breakpoint\n",
- target_pid_to_str (ptid_of (thr)));
- }
-
- /* Back up the PC if necessary. */
- if (pc != sw_breakpoint_pc)
- {
- struct regcache *regcache
- = get_thread_regcache (current_thread, 1);
- (*the_low_target.set_pc) (regcache, sw_breakpoint_pc);
- }
-
- lwp->stop_pc = sw_breakpoint_pc;
+ /* The si_code is ambiguous on this arch -- check debug
+ registers. */
+ if (!check_stopped_by_watchpoint (lwp))
+ lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
+ }
+ else if (GDB_ARCH_IS_TRAP_BRKPT (siginfo.si_code))
+ {
+ /* If we determine the LWP stopped for a SW breakpoint,
+ trust it. Particularly don't check watchpoint
+ registers, because at least on s390, we'd find
+ stopped-by-watchpoint as long as there's a watchpoint
+ set. */
lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
- current_thread = saved_thread;
- return 1;
}
- else if (siginfo.si_code == TRAP_HWBKPT)
+ else if (GDB_ARCH_IS_TRAP_HWBKPT (siginfo.si_code))
{
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by hardware "
- "breakpoint/watchpoint\n",
- target_pid_to_str (ptid_of (thr)));
- }
-
- lwp->stop_pc = pc;
- lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
- current_thread = saved_thread;
- return 1;
+ /* This can indicate either a hardware breakpoint or
+ hardware watchpoint. Check debug registers. */
+ if (!check_stopped_by_watchpoint (lwp))
+ lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
}
else if (siginfo.si_code == TRAP_TRACE)
{
- if (debug_threads)
- {
- struct thread_info *thr = get_lwp_thread (lwp);
-
- debug_printf ("CSBB: %s stopped by trace\n",
- target_pid_to_str (ptid_of (thr)));
- }
-
- lwp->stop_reason = TARGET_STOPPED_BY_SINGLE_STEP;
+ /* We may have single stepped an instruction that
+ triggered a watchpoint. In that case, on some
+ architectures (such as x86), instead of TRAP_HWBKPT,
+ si_code indicates TRAP_TRACE, and we need to check
+ the debug registers separately. */
+ if (!check_stopped_by_watchpoint (lwp))
+ lwp->stop_reason = TARGET_STOPPED_BY_SINGLE_STEP;
}
}
}
case we need to report the breakpoint PC. */
if ((!lwp->stepping || lwp->stop_pc == sw_breakpoint_pc)
&& (*the_low_target.breakpoint_at) (sw_breakpoint_pc))
+ lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
+
+ if (hardware_breakpoint_inserted_here (pc))
+ lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
+
+ if (lwp->stop_reason == TARGET_STOPPED_BY_NO_REASON)
+ check_stopped_by_watchpoint (lwp);
+#endif
+
+ if (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
{
if (debug_threads)
{
/* Back up the PC if necessary. */
if (pc != sw_breakpoint_pc)
- {
+ {
struct regcache *regcache
= get_thread_regcache (current_thread, 1);
(*the_low_target.set_pc) (regcache, sw_breakpoint_pc);
}
- lwp->stop_pc = sw_breakpoint_pc;
- lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
- current_thread = saved_thread;
- return 1;
+ /* Update this so we record the correct stop PC below. */
+ pc = sw_breakpoint_pc;
}
-
- if (hardware_breakpoint_inserted_here (pc))
+ else if (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)
{
if (debug_threads)
{
debug_printf ("CSBB: %s stopped by hardware breakpoint\n",
target_pid_to_str (ptid_of (thr)));
}
+ }
+ else if (lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
+ {
+ if (debug_threads)
+ {
+ struct thread_info *thr = get_lwp_thread (lwp);
- lwp->stop_pc = pc;
- lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
- current_thread = saved_thread;
- return 1;
+ debug_printf ("CSBB: %s stopped by hardware watchpoint\n",
+ target_pid_to_str (ptid_of (thr)));
+ }
+ }
+ else if (lwp->stop_reason == TARGET_STOPPED_BY_SINGLE_STEP)
+ {
+ if (debug_threads)
+ {
+ struct thread_info *thr = get_lwp_thread (lwp);
+
+ debug_printf ("CSBB: %s stopped by trace\n",
+ target_pid_to_str (ptid_of (thr)));
+ }
}
-#endif
+ lwp->stop_pc = pc;
current_thread = saved_thread;
- return 0;
+ return 1;
}
static struct lwp_info *
child->syscall_state = TARGET_WAITKIND_IGNORE;
}
- /* Be careful to not overwrite stop_pc until
- check_stopped_by_breakpoint is called. */
+ /* Be careful to not overwrite stop_pc until save_stop_reason is
+ called. */
if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
&& linux_is_extended_waitstatus (wstat))
{
}
}
- /* Check first whether this was a SW/HW breakpoint before checking
- watchpoints, because at least s390 can't tell the data address of
- hardware watchpoint hits, and returns stopped-by-watchpoint as
- long as there's a watchpoint set. */
if (WIFSTOPPED (wstat) && linux_wstatus_maybe_breakpoint (wstat))
{
- if (check_stopped_by_breakpoint (child))
+ if (save_stop_reason (child))
have_stop_pc = 1;
}
- /* Note that TRAP_HWBKPT can indicate either a hardware breakpoint
- or hardware watchpoint. Check which is which if we got
- TARGET_STOPPED_BY_HW_BREAKPOINT. Likewise, we may have single
- stepped an instruction that triggered a watchpoint. In that
- case, on some architectures (such as x86), instead of
- TRAP_HWBKPT, si_code indicates TRAP_TRACE, and we need to check
- the debug registers separately. */
- if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
- && child->stop_reason != TARGET_STOPPED_BY_SW_BREAKPOINT)
- check_stopped_by_watchpoint (child);
-
if (!have_stop_pc)
child->stop_pc = get_pc (child);
hardware single step it means a gdb/gdbserver breakpoint had been
planted on top of a permanent breakpoint, in the case of a software
single step it may just mean that gdbserver hit the reinsert breakpoint.
- The PC has been adjusted by check_stopped_by_breakpoint to point at
+ The PC has been adjusted by save_stop_reason to point at
the breakpoint address.
So in the case of the hardware single step advance the PC manually
past the breakpoint and in the case of software single step advance only
VEC (CORE_ADDR) *next_pcs = NULL;
struct cleanup *old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
- pc = get_pc (lwp);
- next_pcs = (*the_low_target.get_next_pcs) (pc, regcache);
+ next_pcs = (*the_low_target.get_next_pcs) (regcache);
for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); ++i)
set_reinsert_breakpoint (pc);
|| lwp->pending_signals != NULL
|| lwp->bp_reinsert != 0
|| fast_tp_collecting))
- {
- struct pending_signals *p_sig = XNEW (struct pending_signals);
-
- p_sig->prev = lwp->pending_signals;
- p_sig->signal = signal;
- if (info == NULL)
- memset (&p_sig->info, 0, sizeof (siginfo_t));
- else
- memcpy (&p_sig->info, info, sizeof (siginfo_t));
- lwp->pending_signals = p_sig;
- }
+ enqueue_pending_signal (lwp, signal, info);
if (lwp->status_pending_p)
{
layout of the inferiors' architecture. */
static void
-siginfo_fixup (siginfo_t *siginfo, void *inf_siginfo, int direction)
+siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction)
{
int done = 0;
{
int pid;
siginfo_t siginfo;
- char inf_siginfo[sizeof (siginfo_t)];
+ gdb_byte inf_siginfo[sizeof (siginfo_t)];
if (current_thread == NULL)
return -1;
&& linux_supports_tracesysgood ());
}
+static int
+linux_get_ipa_tdesc_idx (void)
+{
+ if (the_low_target.get_ipa_tdesc_idx == NULL)
+ return 0;
+
+ return (*the_low_target.get_ipa_tdesc_idx) ();
+}
+
static int
linux_supports_tracepoints (void)
{
return pc;
}
+/* Default implementation of linux_target_ops method "set_pc" for
+ 64-bit pc register which is literally named "pc". */
+
+void
+linux_set_pc_64bit (struct regcache *regcache, CORE_ADDR pc)
+{
+ uint64_t newpc = pc;
+
+ supply_register_by_name (regcache, "pc", &newpc);
+}
+
+/* Default implementation of linux_target_ops method "get_pc" for
+ 64-bit pc register which is literally named "pc". */
+
+CORE_ADDR
+linux_get_pc_64bit (struct regcache *regcache)
+{
+ uint64_t pc;
+
+ collect_register_by_name (regcache, "pc", &pc);
+ if (debug_threads)
+ debug_printf ("stop pc is 0x%" PRIx64 "\n", pc);
+ return pc;
+}
+
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_post_create_inferior,
linux_breakpoint_kind_from_current_state,
linux_supports_software_single_step,
linux_supports_catch_syscall,
+ linux_get_ipa_tdesc_idx,
};
#ifdef HAVE_LINUX_REGSETS