#include <sys/ptrace.h>
#include "nat/linux-ptrace.h"
#include "nat/linux-procfs.h"
+#include "nat/linux-personality.h"
#include <signal.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#ifdef HAVE_LINUX_BTRACE
# include "nat/linux-btrace.h"
+# include "btrace-common.h"
#endif
#ifndef HAVE_ELF32_AUXV_T
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;
}
/* Normally we will get the pending SIGSTOP. But in some cases
we might get another signal delivered to the group first.
If we do get another signal, be sure not to lose it. */
- if (WSTOPSIG (status) == SIGSTOP)
- {
- if (stopping_threads == NOT_STOPPING_THREADS)
- linux_resume_one_lwp (new_lwp, 0, 0, NULL);
- }
- else
+ if (WSTOPSIG (status) != SIGSTOP)
{
new_lwp->stop_expected = 1;
-
- if (stopping_threads != NOT_STOPPING_THREADS)
- {
- new_lwp->status_pending_p = 1;
- new_lwp->status_pending = status;
- }
- else
- /* Pass the signal on. This is what GDB does - except
- shouldn't we really report it instead? */
- linux_resume_one_lwp (new_lwp, 0, WSTOPSIG (status), NULL);
+ new_lwp->status_pending_p = 1;
+ new_lwp->status_pending = status;
}
-
- /* Always resume the current thread. If we are stopping
- threads, it will have a pending SIGSTOP; we may as well
- collect it now. */
- linux_resume_one_lwp (event_child, event_child->stepping, 0, NULL);
}
}
/* 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;
}
static int
linux_create_inferior (char *program, char **allargs)
{
-#ifdef HAVE_PERSONALITY
- int personality_orig = 0, personality_set = 0;
-#endif
struct lwp_info *new_lwp;
int pid;
ptid_t ptid;
-
-#ifdef HAVE_PERSONALITY
- if (disable_randomization)
- {
- errno = 0;
- personality_orig = personality (0xffffffff);
- if (errno == 0 && !(personality_orig & ADDR_NO_RANDOMIZE))
- {
- personality_set = 1;
- personality (personality_orig | ADDR_NO_RANDOMIZE);
- }
- if (errno != 0 || (personality_set
- && !(personality (0xffffffff) & ADDR_NO_RANDOMIZE)))
- warning ("Error disabling address space randomization: %s",
- strerror (errno));
- }
-#endif
+ struct cleanup *restore_personality
+ = maybe_disable_address_space_randomization (disable_randomization);
#if defined(__UCLIBC__) && defined(HAS_NOMMU)
pid = vfork ();
_exit (0177);
}
-#ifdef HAVE_PERSONALITY
- if (personality_set)
- {
- errno = 0;
- personality (personality_orig);
- if (errno != 0)
- warning ("Error restoring address space randomization: %s",
- strerror (errno));
- }
-#endif
+ do_cleanups (restore_personality);
linux_add_process (pid, 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
+ 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)
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;
}
}
if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
&& check_stopped_by_watchpoint (child))
;
- else if (WIFSTOPPED (wstat) && wstatus_maybe_breakpoint (wstat))
+ else if (WIFSTOPPED (wstat) && linux_wstatus_maybe_breakpoint (wstat))
{
if (check_stopped_by_breakpoint (child))
have_stop_pc = 1;
return child;
}
+/* Resume LWPs that are currently stopped without any pending status
+ to report, but are resumed from the core's perspective. */
+
+static void
+resume_stopped_resumed_lwps (struct inferior_list_entry *entry)
+{
+ struct thread_info *thread = (struct thread_info *) entry;
+ struct lwp_info *lp = get_thread_lwp (thread);
+
+ if (lp->stopped
+ && !lp->status_pending_p
+ && thread->last_resume_kind != resume_stop
+ && thread->last_status.kind == TARGET_WAITKIND_IGNORE)
+ {
+ int step = thread->last_resume_kind == resume_step;
+
+ if (debug_threads)
+ debug_printf ("RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
+ target_pid_to_str (ptid_of (thread)),
+ paddress (lp->stop_pc),
+ step);
+
+ linux_resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL);
+ }
+}
+
/* Wait for an event from child(ren) WAIT_PTID, and return any that
match FILTER_PTID (leaving others pending). The PTIDs can be:
minus_one_ptid, to specify any child; a pid PTID, specifying all
continue;
}
- /* Now that we've pulled all events out of the kernel, check if
- there's any LWP with a status to report to the core. */
+ /* Now that we've pulled all events out of the kernel, resume
+ LWPs that don't have an interesting event to report. */
+ if (stopping_threads == NOT_STOPPING_THREADS)
+ for_each_inferior (&all_threads, resume_stopped_resumed_lwps);
+
+ /* ... and find an LWP with a status to report to the core, if
+ any. */
event_thread = (struct thread_info *)
find_inferior (&all_threads, status_pending_p_callback, &filter_ptid);
if (event_thread != NULL)
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");
/* 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)
+ if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
{
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
{
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;
/* 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);
linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
int type)
{
- VEC (btrace_block_s) *btrace;
+ struct btrace_data btrace;
struct btrace_block *block;
enum btrace_error err;
int i;
- btrace = NULL;
+ btrace_data_init (&btrace);
+
err = linux_read_btrace (&btrace, tinfo, type);
if (err != BTRACE_ERR_NONE)
{
else
buffer_grow_str0 (buffer, "E.Generic Error.");
+ btrace_data_fini (&btrace);
+ return -1;
+ }
+
+ switch (btrace.format)
+ {
+ case BTRACE_FORMAT_NONE:
+ buffer_grow_str0 (buffer, "E.No Trace.");
+ break;
+
+ case BTRACE_FORMAT_BTS:
+ buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
+ buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+
+ for (i = 0;
+ VEC_iterate (btrace_block_s, btrace.variant.bts.blocks, i, block);
+ i++)
+ buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+ paddress (block->begin), paddress (block->end));
+
+ buffer_grow_str0 (buffer, "</btrace>\n");
+ break;
+
+ default:
+ buffer_grow_str0 (buffer, "E.Unknown Trace Format.");
+
+ btrace_data_fini (&btrace);
return -1;
}
- buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
- buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+ btrace_data_fini (&btrace);
+ return 0;
+}
- for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
- buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
- paddress (block->begin), paddress (block->end));
+/* See to_btrace_conf target method. */
- buffer_grow_str0 (buffer, "</btrace>\n");
+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;
- VEC_free (btrace_block_s, btrace);
+ 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 */
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,
};