struct process_info *proc;
proc = add_process (pid, attached);
- proc->private = xcalloc (1, sizeof (*proc->private));
+ proc->priv = xcalloc (1, sizeof (*proc->priv));
/* Set the arch when the first LWP stops. */
- proc->private->new_inferior = 1;
+ proc->priv->new_inferior = 1;
if (the_low_target.new_process != NULL)
- proc->private->arch_private = the_low_target.new_process ();
+ proc->priv->arch_private = the_low_target.new_process ();
return proc;
}
CORE_ADDR pc;
CORE_ADDR sw_breakpoint_pc;
struct thread_info *saved_thread;
+#if USE_SIGTRAP_SIGINFO
+ siginfo_t siginfo;
+#endif
if (the_low_target.get_pc == NULL)
return 0;
saved_thread = current_thread;
current_thread = get_lwp_thread (lwp);
+#if USE_SIGTRAP_SIGINFO
+ if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread),
+ (PTRACE_TYPE_ARG3) 0, &siginfo) == 0)
+ {
+ if (siginfo.si_signo == SIGTRAP)
+ {
+ if (siginfo.si_code == GDB_ARCH_TRAP_BRKPT)
+ {
+ if (debug_threads)
+ {
+ struct thread_info *thr = get_lwp_thread (lwp);
+
+ debug_printf ("CSBB: Push back software breakpoint for %s\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;
+ lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
+ current_thread = saved_thread;
+ return 1;
+ }
+ else if (siginfo.si_code == TRAP_HWBKPT)
+ {
+ if (debug_threads)
+ {
+ struct thread_info *thr = get_lwp_thread (lwp);
+
+ debug_printf ("CSBB: Push back hardware "
+ "breakpoint/watchpoint for %s\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;
+ }
+ }
+ }
+#else
/* We may have just stepped a breakpoint instruction. E.g., in
non-stop mode, GDB first tells the thread A to step a range, and
then the user inserts a breakpoint inside the range. In that
- case, we need to report the breakpoint PC. But, when we're
- trying to step past one of our own breakpoints, that happens to
- have been placed on top of a permanent breakpoint instruction, we
- shouldn't adjust the PC, otherwise the program would keep
- trapping the permanent breakpoint forever. */
- if ((!lwp->stepping
- || (!ptid_equal (ptid_of (current_thread), step_over_bkpt)
- && lwp->stop_pc == sw_breakpoint_pc))
+ 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))
{
if (debug_threads)
}
lwp->stop_pc = sw_breakpoint_pc;
- lwp->stop_reason = LWP_STOPPED_BY_SW_BREAKPOINT;
+ lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
current_thread = saved_thread;
return 1;
}
}
lwp->stop_pc = pc;
- lwp->stop_reason = LWP_STOPPED_BY_HW_BREAKPOINT;
+ lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
current_thread = saved_thread;
return 1;
}
+#endif
current_thread = saved_thread;
return 0;
find_inferior (&all_threads, delete_lwp_callback, process);
/* Freeing all private data. */
- priv = process->private;
+ priv = process->priv;
free (priv->arch_private);
free (priv);
- process->private = NULL;
+ process->priv = NULL;
remove_process (process);
}
return 0;
if (thread->last_resume_kind != resume_stop
- && (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT
- || lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT))
+ && (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
+ || lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT))
{
struct thread_info *saved_thread;
CORE_ADDR pc;
lwpid_of (thread));
discard = 1;
}
- else if (lp->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT
+
+#if !USE_SIGTRAP_SIGINFO
+ else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
&& !(*the_low_target.breakpoint_at) (pc))
{
if (debug_threads)
lwpid_of (thread));
discard = 1;
}
- else if (lp->stop_reason == LWP_STOPPED_BY_HW_BREAKPOINT
+ else if (lp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT
&& !hardware_breakpoint_inserted_here (pc))
{
if (debug_threads)
lwpid_of (thread));
discard = 1;
}
+#endif
current_thread = saved_thread;
ptid_t ptid = * (ptid_t *) arg;
/* Check if we're only interested in events from a specific process
- or its lwps. */
- if (!ptid_equal (minus_one_ptid, ptid)
- && ptid_get_pid (ptid) != ptid_get_pid (thread->entry.id))
+ or a specific LWP. */
+ if (!ptid_match (ptid_of (thread), ptid))
return 0;
if (lp->status_pending_p
return 0;
}
-/* Return true if the event in LP may be caused by breakpoint. */
-
-static int
-wstatus_maybe_breakpoint (int wstatus)
-{
- return (WIFSTOPPED (wstatus)
- && (WSTOPSIG (wstatus) == SIGTRAP
- /* SIGILL and SIGSEGV are also treated as traps in case a
- breakpoint is inserted at the current PC. */
- || WSTOPSIG (wstatus) == SIGILL
- || WSTOPSIG (wstatus) == SIGSEGV));
-}
-
/* Fetch the possibly triggered data watchpoint info and store it in
CHILD.
if (the_low_target.stopped_by_watchpoint ())
{
- child->stop_reason = LWP_STOPPED_BY_WATCHPOINT;
+ child->stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
if (the_low_target.stopped_data_address != NULL)
child->stopped_data_address
current_thread = saved_thread;
}
- return child->stop_reason == LWP_STOPPED_BY_WATCHPOINT;
+ return child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
}
/* Do low-level handling of the event, and check if we should go on
is stopped for the first time, but before we access any
inferior registers. */
proc = find_process_pid (pid_of (thread));
- if (proc->private->new_inferior)
+ if (proc->priv->new_inferior)
{
struct thread_info *saved_thread;
current_thread = saved_thread;
- proc->private->new_inferior = 0;
+ proc->priv->new_inferior = 0;
}
}
return NULL;
}
- if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
- && check_stopped_by_watchpoint (child))
- ;
- else if (WIFSTOPPED (wstat) && wstatus_maybe_breakpoint (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))
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. */
+ if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
+ && (child->stop_reason == TARGET_STOPPED_BY_NO_REASON
+ || child->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT))
+ check_stopped_by_watchpoint (child);
+
if (!have_stop_pc)
child->stop_pc = get_pc (child);
return 0;
}
-/* Select the Nth LWP that has had a SIGTRAP event that should be
- reported to GDB. */
+/* Select the Nth LWP that has had an event. */
static int
select_event_lwp_callback (struct inferior_list_entry *entry, void *data)
if (event_thread == NULL)
{
/* No single-stepping LWP. Select one at random, out of those
- which have had SIGTRAP events. */
+ which have had events. */
- /* First see how many SIGTRAP events we have. */
+ /* First see how many events we have. */
find_inferior (&all_threads, count_events_callback, &num_events);
- /* Now randomly pick a LWP out of those that have had a SIGTRAP. */
+ /* Now randomly pick a LWP out of those that have had
+ events. */
random_selector = (int)
((num_events * (double) rand ()) / (RAND_MAX + 1.0));
return ptid_of (current_thread);
}
+ /* If step-over executes a breakpoint instruction, it means a
+ gdb/gdbserver breakpoint had been planted on top of a permanent
+ breakpoint. The PC has been adjusted by
+ check_stopped_by_breakpoint to point at the breakpoint address.
+ Advance the PC manually past the breakpoint, otherwise the
+ program would keep trapping the permanent breakpoint forever. */
+ if (!ptid_equal (step_over_bkpt, null_ptid)
+ && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
+ {
+ unsigned int increment_pc = the_low_target.breakpoint_len;
+
+ if (debug_threads)
+ {
+ debug_printf ("step-over for %s executed software breakpoint\n",
+ target_pid_to_str (ptid_of (current_thread)));
+ }
+
+ if (increment_pc != 0)
+ {
+ struct regcache *regcache
+ = get_thread_regcache (current_thread, 1);
+
+ event_child->stop_pc += increment_pc;
+ (*the_low_target.set_pc) (regcache, event_child->stop_pc);
+
+ if (!(*the_low_target.breakpoint_at) (event_child->stop_pc))
+ event_child->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+ }
+ }
+
/* If this event was not handled before, and is not a SIGTRAP, we
report it. SIGILL and SIGSEGV are also treated as traps in case
a breakpoint is inserted at the current PC. If this target does
any that GDB specifically requested we ignore. But never ignore
SIGSTOP if we sent it ourselves, and do not ignore signals when
stepping - they may require special handling to skip the signal
- handler. */
+ handler. Also never ignore signals that could be caused by a
+ breakpoint. */
/* FIXME drow/2002-06-09: Get signal numbers from the inferior's
thread library? */
if (WIFSTOPPED (w)
&& current_thread->last_resume_kind != resume_step
&& (
#if defined (USE_THREAD_DB) && !defined (__ANDROID__)
- (current_process ()->private->thread_db != NULL
+ (current_process ()->priv->thread_db != NULL
&& (WSTOPSIG (w) == __SIGRTMIN
|| WSTOPSIG (w) == __SIGRTMIN + 1))
||
#endif
(pass_signals[gdb_signal_from_host (WSTOPSIG (w))]
&& !(WSTOPSIG (w) == SIGSTOP
- && current_thread->last_resume_kind == resume_stop))))
+ && current_thread->last_resume_kind == resume_stop)
+ && !linux_wstatus_maybe_breakpoint (w))))
{
siginfo_t info, *info_p;
report_to_gdb = (!maybe_internal_trap
|| (current_thread->last_resume_kind == resume_step
&& !in_step_range)
- || event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT
+ || event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT
|| (!step_over_finished && !in_step_range
&& !bp_explains_trap && !trace_event)
|| (gdb_breakpoint_here (event_child->stop_pc)
else if (!lwp_in_step_range (event_child))
debug_printf ("Out of step range, reporting event.\n");
}
- if (event_child->stop_reason == LWP_STOPPED_BY_WATCHPOINT)
+ if (event_child->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
debug_printf ("Stopped by watchpoint.\n");
else if (gdb_breakpoint_here (event_child->stop_pc))
debug_printf ("Stopped by GDB breakpoint.\n");
ourstatus->kind = TARGET_WAITKIND_STOPPED;
/* Now that we've selected our final event LWP, un-adjust its PC if
- it was a software breakpoint. */
- if (event_child->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT)
+ it was a software breakpoint, and the client doesn't know we can
+ adjust the breakpoint ourselves. */
+ if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
+ && !swbreak_feature)
{
int decr_pc = the_low_target.decr_pc_after_break;
return (supports_fast_tracepoints ()
&& agent_loaded_p ()
&& (gdb_breakpoint_here (lwp->stop_pc)
- || lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT
+ || lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT
|| thread->last_resume_kind == resume_step)
&& linux_fast_tracepoint_collecting (lwp, NULL));
}
/* Allow debugging the jump pad, gdb_collect, etc. */
if (!gdb_breakpoint_here (lwp->stop_pc)
- && lwp->stop_reason != LWP_STOPPED_BY_WATCHPOINT
+ && lwp->stop_reason != TARGET_STOPPED_BY_WATCHPOINT
&& thread->last_resume_kind != resume_step
&& maybe_move_out_of_jump_pad (lwp, wstat))
{
regcache_invalidate_thread (thread);
errno = 0;
lwp->stopped = 0;
- lwp->stop_reason = LWP_STOPPED_BY_NO_REASON;
+ lwp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
lwp->stepping = step;
ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread),
(PTRACE_TYPE_ARG3) 0,
#ifdef USE_THREAD_DB
struct process_info *proc = current_process ();
- if (proc->private->thread_db != NULL)
+ if (proc->priv->thread_db != NULL)
return;
/* If the kernel supports tracing clones, then we don't need to
return 1;
}
+/* Implement the to_stopped_by_sw_breakpoint target_ops
+ method. */
+
+static int
+linux_stopped_by_sw_breakpoint (void)
+{
+ struct lwp_info *lwp = get_thread_lwp (current_thread);
+
+ return (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT);
+}
+
+/* Implement the to_supports_stopped_by_sw_breakpoint target_ops
+ method. */
+
+static int
+linux_supports_stopped_by_sw_breakpoint (void)
+{
+ return USE_SIGTRAP_SIGINFO;
+}
+
+/* Implement the to_stopped_by_hw_breakpoint target_ops
+ method. */
+
+static int
+linux_stopped_by_hw_breakpoint (void)
+{
+ struct lwp_info *lwp = get_thread_lwp (current_thread);
+
+ return (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT);
+}
+
+/* Implement the to_supports_stopped_by_hw_breakpoint target_ops
+ method. */
+
+static int
+linux_supports_stopped_by_hw_breakpoint (void)
+{
+ return USE_SIGTRAP_SIGINFO;
+}
+
static int
linux_stopped_by_watchpoint (void)
{
struct lwp_info *lwp = get_thread_lwp (current_thread);
- return lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT;
+ return lwp->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
}
static CORE_ADDR
{
char *document;
unsigned document_len;
- struct process_info_private *const priv = current_process ()->private;
+ struct process_info_private *const priv = current_process ()->priv;
char filename[PATH_MAX];
int pid, is_elf64;
break;
len = sep - annex;
- if (len == 5 && strncmp (annex, "start", 5) == 0)
+ if (len == 5 && startswith (annex, "start"))
addrp = &lm_addr;
- else if (len == 4 && strncmp (annex, "prev", 4) == 0)
+ else if (len == 4 && startswith (annex, "prev"))
addrp = &lm_prev;
else
{
/* See to_enable_btrace target method. */
static struct btrace_target_info *
-linux_low_enable_btrace (ptid_t ptid)
+linux_low_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
{
struct btrace_target_info *tinfo;
- tinfo = linux_enable_btrace (ptid);
+ tinfo = linux_enable_btrace (ptid, conf);
- if (tinfo != NULL)
+ if (tinfo != NULL && tinfo->ptr_bits == 0)
{
struct thread_info *thread = find_thread_ptid (ptid);
struct regcache *regcache = get_thread_regcache (thread, 0);
btrace_data_fini (&btrace);
return 0;
}
+
+/* See to_btrace_conf target method. */
+
+static int
+linux_low_btrace_conf (const struct btrace_target_info *tinfo,
+ struct buffer *buffer)
+{
+ const struct btrace_config *conf;
+
+ buffer_grow_str (buffer, "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n");
+ buffer_grow_str (buffer, "<btrace-conf version=\"1.0\">\n");
+
+ conf = linux_btrace_conf (tinfo);
+ if (conf != NULL)
+ {
+ switch (conf->format)
+ {
+ case BTRACE_FORMAT_NONE:
+ break;
+
+ case BTRACE_FORMAT_BTS:
+ buffer_xml_printf (buffer, "<bts");
+ buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
+ buffer_xml_printf (buffer, " />\n");
+ break;
+ }
+ }
+
+ buffer_grow_str0 (buffer, "</btrace-conf>\n");
+ return 0;
+}
#endif /* HAVE_LINUX_BTRACE */
static struct target_ops linux_target_ops = {
linux_supports_z_point_type,
linux_insert_point,
linux_remove_point,
+ linux_stopped_by_sw_breakpoint,
+ linux_supports_stopped_by_sw_breakpoint,
+ linux_stopped_by_hw_breakpoint,
+ linux_supports_stopped_by_hw_breakpoint,
linux_stopped_by_watchpoint,
linux_stopped_data_address,
#if defined(__UCLIBC__) && defined(HAS_NOMMU) \
linux_low_enable_btrace,
linux_low_disable_btrace,
linux_low_read_btrace,
+ linux_low_btrace_conf,
#else
NULL,
NULL,
NULL,
NULL,
+ NULL,
#endif
linux_supports_range_stepping,
};