Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer.
@ 2015-10-29 17:14 Antoine Tremblay
  2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
                   ` (9 more replies)
  0 siblings, 10 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:14 UTC (permalink / raw)
  To: gdb-patches

This patch series adds support for software single step and conditional
breakpoints on ARM in GDBServer.

Patches 1 and 2 fix general issues in the software single step control flow.

Patches 3 to 5 Removes the too simple implementations of software single
step that were in place and paves to way for full software single step to
be implemented.

Patches 6 and 7 Prepares the sharing of the software single step code for
ARM in GDB with GDBServer.

Patch 8 Implements the support for ARM software single step.

Patch 9 Adds support for while-stepping actions.

Patch 10 Adds supports for conditional breakpoints in GDBServer.

This patchset has no observed regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

Note also that while I could not test directly thumbv1 instructions with gcc
-marmv4t , manual testing of the software single step was done for thumv1
instructions.



^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
@ 2015-10-29 17:15 ` Antoine Tremblay
  2015-11-03 17:05   ` Yao Qi
  2015-11-04 18:19   ` [PATCH 04/10] " Pedro Alves
  2015-10-29 17:15 ` [PATCH 10/10] Enable conditional breakpoints for targets that support software single step " Antoine Tremblay
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch removes support for thread events if TRACE_EVENT_CLONE is not
supported in GDBServer.

Before, on systems that did not support PTRACE_EVENT_CLONE, both GDB and
GDBServer coordinated with libthread_db.so to insert breakpoints at magic
locations in libpthread.so, in order to break at thread creation and thread
death.

Simple software single stepping support was implemented to step over these
breakpoints in case there was no hardware single stepping support. However,
these simple software single stepping implementations were not fit for any other
use as discussed in :
https://sourceware.org/ml/gdb-patches/2015-04/msg01110.html

These too simple implementations conflict with ongoing work to make proper
implementations of software single stepping in GDBServer.

The problem is that if some implementations are correct and others are not and
only there for the thread magic breakpoint, we can't enable features based
solely software single step support since some would be broken.

To keep the incorrect implementations and allow the new proper ones at the same
time we would need to implement fallback code and it quickly becomes ugly and
confusing with multiple checks for legacy software single step or proper
software single step.

However, PTRACE_EVENT_CLONE was first introduced in Linux 2.5.46,
released in November 2002.

So I think it's reasonable to just remove support for kernels that don't support
PTRACE_EVENT_CLONE, and sidestep the libthread_db breakpoints issues entirely.

This thread on the mailling list discusses the issue :
https://sourceware.org/ml/gdb/2015-10/msg00078.html

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-low.c (linux_look_up_symbols): Don't call
	linux_supports_traceclone.
	* linux-low.h (thread_db_init): Remove use_events argument.
	* thread-db.c (thread_db_use_event): Remove global variable.
	(struct thread_db) <td_thr_event_enable_ftype>: Remove field.
	(thread_db_create_event): Remove function.
	(thread_db_enable_reporting): Likewise.
	(find_one_thread): Don't check for thread_db_use_events.
	(attach_thread): Likewise.
	(thread_db_load_search): Remove td_thr_event_enable_p initialization.
	(try_thread_db_load_1): Don't check for thread_db_use_events.
	(thread_db_init): Remove use_events argument.
	(thread_db_init): Remove thread events handling.
---
 gdb/gdbserver/linux-low.c |   2 +-
 gdb/gdbserver/linux-low.h |   2 +-
 gdb/gdbserver/thread-db.c | 124 ++--------------------------------------------
 3 files changed, 6 insertions(+), 122 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ceddf4d..a3b0f3a 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5515,7 +5515,7 @@ linux_look_up_symbols (void)
   /* If the kernel supports tracing clones, then we don't need to
      use the magic thread event breakpoint to learn about
      threads.  */
-  thread_db_init (!linux_supports_traceclone ());
+  thread_db_init ();
 #endif
 }
 
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 2e1f32f..d60d97d 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -379,7 +379,7 @@ void initialize_regsets_info (struct regsets_info *regsets_info);
 void initialize_low_arch (void);
 
 /* From thread-db.c  */
-int thread_db_init (int use_events);
+int thread_db_init (void);
 void thread_db_detach (struct process_info *);
 void thread_db_mourn (struct process_info *);
 int thread_db_handle_monitor_command (char *);
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index 3df10ff..7bd10b6 100644
--- a/gdb/gdbserver/thread-db.c
+++ b/gdb/gdbserver/thread-db.c
@@ -24,8 +24,6 @@
 
 extern int debug_threads;
 
-static int thread_db_use_events;
-
 #include "gdb_proc_service.h"
 #include "nat/gdb_thread_db.h"
 #include "gdb_vecs.h"
@@ -73,7 +71,6 @@ struct thread_db
   td_ta_event_addr_ftype *td_ta_event_addr_p;
   td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
   td_thr_get_info_ftype *td_thr_get_info_p;
-  td_thr_event_enable_ftype *td_thr_event_enable_p;
   td_ta_thr_iter_ftype *td_ta_thr_iter_p;
   td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
   td_thr_tlsbase_ftype *td_thr_tlsbase_p;
@@ -172,84 +169,6 @@ thread_db_state_str (td_thr_state_e state)
 #endif
 
 static int
-thread_db_create_event (CORE_ADDR where)
-{
-  td_event_msg_t msg;
-  td_err_e err;
-  struct lwp_info *lwp;
-  struct thread_db *thread_db = current_process ()->priv->thread_db;
-
-  gdb_assert (thread_db->td_ta_event_getmsg_p != NULL);
-
-  if (debug_threads)
-    debug_printf ("Thread creation event.\n");
-
-  /* FIXME: This assumes we don't get another event.
-     In the LinuxThreads implementation, this is safe,
-     because all events come from the manager thread
-     (except for its own creation, of course).  */
-  err = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
-  if (err != TD_OK)
-    fprintf (stderr, "thread getmsg err: %s\n",
-	     thread_db_err_str (err));
-
-  /* If we do not know about the main thread yet, this would be a good time to
-     find it.  We need to do this to pick up the main thread before any newly
-     created threads.  */
-  lwp = get_thread_lwp (current_thread);
-  if (lwp->thread_known == 0)
-    find_one_thread (current_thread->entry.id);
-
-  /* msg.event == TD_EVENT_CREATE */
-
-  find_new_threads_callback (msg.th_p, NULL);
-
-  return 0;
-}
-
-static int
-thread_db_enable_reporting (void)
-{
-  td_thr_events_t events;
-  td_notify_t notify;
-  td_err_e err;
-  struct thread_db *thread_db = current_process ()->priv->thread_db;
-
-  if (thread_db->td_ta_set_event_p == NULL
-      || thread_db->td_ta_event_addr_p == NULL
-      || thread_db->td_ta_event_getmsg_p == NULL)
-    /* This libthread_db is missing required support.  */
-    return 0;
-
-  /* Set the process wide mask saying which events we're interested in.  */
-  td_event_emptyset (&events);
-  td_event_addset (&events, TD_CREATE);
-
-  err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
-  if (err != TD_OK)
-    {
-      warning ("Unable to set global thread event mask: %s",
-	       thread_db_err_str (err));
-      return 0;
-    }
-
-  /* Get address for thread creation breakpoint.  */
-  err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
-				       &notify);
-  if (err != TD_OK)
-    {
-      warning ("Unable to get location for thread creation breakpoint: %s",
-	       thread_db_err_str (err));
-      return 0;
-    }
-  thread_db->td_create_bp
-    = set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
-			 thread_db_create_event);
-
-  return 1;
-}
-
-static int
 find_one_thread (ptid_t ptid)
 {
   td_thrhandle_t th;
@@ -287,14 +206,6 @@ find_one_thread (ptid_t ptid)
       return 0;
     }
 
-  if (thread_db_use_events)
-    {
-      err = thread_db->td_thr_event_enable_p (&th, 1);
-      if (err != TD_OK)
-	error ("Cannot enable thread event reporting for %d: %s",
-	       ti.ti_lid, thread_db_err_str (err));
-    }
-
   /* If the new thread ID is zero, a final thread ID will be available
      later.  Do not enable thread debugging yet.  */
   if (ti.ti_tid == 0)
@@ -334,17 +245,6 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
   lwp->thread_known = 1;
   lwp->th = *th_p;
 
-  if (thread_db_use_events)
-    {
-      td_err_e err;
-      struct thread_db *thread_db = proc->priv->thread_db;
-
-      err = thread_db->td_thr_event_enable_p (th_p, 1);
-      if (err != TD_OK)
-	error ("Cannot enable thread event reporting for %d: %s",
-	       ti_p->ti_lid, thread_db_err_str (err));
-    }
-
   return 1;
 }
 
@@ -584,9 +484,6 @@ thread_db_load_search (void)
   tdb->td_ta_thr_iter_p = &td_ta_thr_iter;
   tdb->td_symbol_list_p = &td_symbol_list;
 
-  /* This is required only when thread_db_use_events is on.  */
-  tdb->td_thr_event_enable_p = &td_thr_event_enable;
-
   /* These are not essential.  */
   tdb->td_ta_event_addr_p = &td_ta_event_addr;
   tdb->td_ta_set_event_p = &td_ta_set_event;
@@ -654,9 +551,6 @@ try_thread_db_load_1 (void *handle)
   CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter));
   CHK (1, TDB_DLSYM (tdb, td_symbol_list));
 
-  /* This is required only when thread_db_use_events is on.  */
-  CHK (thread_db_use_events, TDB_DLSYM (tdb, td_thr_event_enable));
-
   /* These are not essential.  */
   CHK (0, TDB_DLSYM (tdb, td_ta_event_addr));
   CHK (0, TDB_DLSYM (tdb, td_ta_set_event));
@@ -824,7 +718,7 @@ thread_db_load_search (void)
 #endif  /* USE_LIBTHREAD_DB_DIRECTLY */
 
 int
-thread_db_init (int use_events)
+thread_db_init (void)
 {
   struct process_info *proc = current_process ();
 
@@ -839,31 +733,21 @@ thread_db_init (int use_events)
      This isn't the only place in gdbserver that assumes that the first
      process in the list is the thread group leader.  */
 
-  thread_db_use_events = use_events;
-
   if (thread_db_load_search ())
     {
-      if (use_events && thread_db_enable_reporting () == 0)
-	{
-	  /* Keep trying; maybe event reporting will work later.  */
-	  thread_db_mourn (proc);
-	  return 0;
-	}
-
       /* It's best to avoid td_ta_thr_iter if possible.  That walks
 	 data structures in the inferior's address space that may be
 	 corrupted, or, if the target is running, the list may change
 	 while we walk it.  In the latter case, it's possible that a
 	 thread exits just at the exact time that causes GDBserver to
-	 get stuck in an infinite loop.  If the kernel supports clone
-	 events, and /proc/PID/task/ exits, then we already know about
+	 get stuck in an infinite loop.  As the kernel supports clone
+	 events and /proc/PID/task/ exists, then we already know about
 	 all threads in the process.  When we need info out of
 	 thread_db on a given thread (e.g., for TLS), we'll use
 	 find_one_thread then.  That uses thread_db entry points that
 	 do not walk libpthread's thread list, so should be safe, as
 	 well as more efficient.  */
-      if (use_events
-	  || !linux_proc_task_list_dir_exists (pid_of (proc)))
+      if (!linux_proc_task_list_dir_exists (pid_of (proc)))
 	thread_db_find_new_threads ();
       thread_db_look_up_symbols ();
       return 1;
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
  2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
  2015-10-29 17:15 ` [PATCH 10/10] Enable conditional breakpoints for targets that support software single step " Antoine Tremblay
@ 2015-10-29 17:15 ` Antoine Tremblay
  2015-11-04 19:56   ` Pedro Alves
  2015-10-29 17:16 ` [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer Antoine Tremblay
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch is in preparation for software single stepping support on ARM it
shares some functions and defenitions that will be needed.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

Not tested : wince/bsd build.

gdb/ChangeLog:

	* arch/arm.c (bitcount): Move from arm-tdep.c
	(condition_true): Likewise.
	* arch/arm.h (Instruction Definitions): Move form arm-tdep.h.
	(condition_true): Move defenition from arm-tdep.h
	(bitcount): Likewise.
	* arm-tdep.c (condition_true): Move to arch/arm.c.
	(bitcount): Likewise.
	* arm-tdep.h (Instruction Definitions): Move to arch/arm.h.
	* arm-wince-tdep.c: Include arch/arm.h.
	* armnbsd-tdep.c: Likewise.
---
 gdb/arch/arm.c       | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/arch/arm.h       | 36 +++++++++++++++++++++++++++++++++
 gdb/arm-tdep.c       | 55 --------------------------------------------------
 gdb/arm-tdep.h       | 29 --------------------------
 gdb/arm-wince-tdep.c |  1 +
 gdb/armnbsd-tdep.c   |  1 +
 6 files changed, 95 insertions(+), 84 deletions(-)

diff --git a/gdb/arch/arm.c b/gdb/arch/arm.c
index b11c684..f5913c9 100644
--- a/gdb/arch/arm.c
+++ b/gdb/arch/arm.c
@@ -31,3 +31,60 @@ thumb_insn_size (unsigned short inst1)
   else
     return 2;
 }
+
+/* Return number of 1-bits in VAL.  */
+
+int
+bitcount (unsigned long val)
+{
+  int nbits;
+  for (nbits = 0; val != 0; nbits++)
+    val &= val - 1;		/* Delete rightmost 1-bit in val.  */
+  return nbits;
+}
+
+/* Returns true of the condition evaluates to true.  */
+
+int
+condition_true (unsigned long cond, unsigned long status_reg)
+{
+  if (cond == INST_AL || cond == INST_NV)
+    return 1;
+
+  switch (cond)
+    {
+    case INST_EQ:
+      return ((status_reg & FLAG_Z) != 0);
+    case INST_NE:
+      return ((status_reg & FLAG_Z) == 0);
+    case INST_CS:
+      return ((status_reg & FLAG_C) != 0);
+    case INST_CC:
+      return ((status_reg & FLAG_C) == 0);
+    case INST_MI:
+      return ((status_reg & FLAG_N) != 0);
+    case INST_PL:
+      return ((status_reg & FLAG_N) == 0);
+    case INST_VS:
+      return ((status_reg & FLAG_V) != 0);
+    case INST_VC:
+      return ((status_reg & FLAG_V) == 0);
+    case INST_HI:
+      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
+    case INST_LS:
+      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
+    case INST_GE:
+      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
+    case INST_LT:
+      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0));
+    case INST_GT:
+      return (((status_reg & FLAG_Z) == 0)
+	      && (((status_reg & FLAG_N) == 0)
+		  == ((status_reg & FLAG_V) == 0)));
+    case INST_LE:
+      return (((status_reg & FLAG_Z) != 0)
+	      || (((status_reg & FLAG_N) == 0)
+		  != ((status_reg & FLAG_V) == 0)));
+    }
+  return 1;
+}
diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h
index a054776..d4144dd 100644
--- a/gdb/arch/arm.h
+++ b/gdb/arch/arm.h
@@ -58,6 +58,36 @@ enum gdb_regnum {
   ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
 };
 
+/* Instruction condition field values.  */
+#define INST_EQ		0x0
+#define INST_NE		0x1
+#define INST_CS		0x2
+#define INST_CC		0x3
+#define INST_MI		0x4
+#define INST_PL		0x5
+#define INST_VS		0x6
+#define INST_VC		0x7
+#define INST_HI		0x8
+#define INST_LS		0x9
+#define INST_GE		0xa
+#define INST_LT		0xb
+#define INST_GT		0xc
+#define INST_LE		0xd
+#define INST_AL		0xe
+#define INST_NV		0xf
+
+#define FLAG_N		0x80000000
+#define FLAG_Z		0x40000000
+#define FLAG_C		0x20000000
+#define FLAG_V		0x10000000
+
+#define CPSR_T		0x20
+
+#define XPSR_T		0x01000000
+
+/* Size of integer registers.  */
+#define INT_REGISTER_SIZE		4
+
 /* Addresses for calling Thumb functions have the bit 0 set.
    Here are some macros to test, set, or clear bit 0 of addresses.  */
 #define IS_THUMB_ADDR(addr)    ((addr) & 1)
@@ -68,4 +98,10 @@ enum gdb_regnum {
    first halfword is INST1.  */
 int thumb_insn_size (unsigned short inst1);
 
+/* Returns true of the condition evaluates to true.  */
+int condition_true (unsigned long cond, unsigned long status_reg);
+
+/* Return number of 1-bits in VAL.  */
+int bitcount (unsigned long val);
+
 #endif
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 3a6c6d8..3eaf63e 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4252,50 +4252,6 @@ convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
 			       &d, dbl);
 }
 
-static int
-condition_true (unsigned long cond, unsigned long status_reg)
-{
-  if (cond == INST_AL || cond == INST_NV)
-    return 1;
-
-  switch (cond)
-    {
-    case INST_EQ:
-      return ((status_reg & FLAG_Z) != 0);
-    case INST_NE:
-      return ((status_reg & FLAG_Z) == 0);
-    case INST_CS:
-      return ((status_reg & FLAG_C) != 0);
-    case INST_CC:
-      return ((status_reg & FLAG_C) == 0);
-    case INST_MI:
-      return ((status_reg & FLAG_N) != 0);
-    case INST_PL:
-      return ((status_reg & FLAG_N) == 0);
-    case INST_VS:
-      return ((status_reg & FLAG_V) != 0);
-    case INST_VC:
-      return ((status_reg & FLAG_V) == 0);
-    case INST_HI:
-      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
-    case INST_LS:
-      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
-    case INST_GE:
-      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
-    case INST_LT:
-      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0));
-    case INST_GT:
-      return (((status_reg & FLAG_Z) == 0)
-	      && (((status_reg & FLAG_N) == 0)
-		  == ((status_reg & FLAG_V) == 0)));
-    case INST_LE:
-      return (((status_reg & FLAG_Z) != 0)
-	      || (((status_reg & FLAG_N) == 0)
-		  != ((status_reg & FLAG_V) == 0)));
-    }
-  return 1;
-}
-
 static unsigned long
 shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
 		 unsigned long pc_val, unsigned long status_reg)
@@ -4346,17 +4302,6 @@ shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
   return res & 0xffffffff;
 }
 
-/* Return number of 1-bits in VAL.  */
-
-static int
-bitcount (unsigned long val)
-{
-  int nbits;
-  for (nbits = 0; val != 0; nbits++)
-    val &= val - 1;		/* Delete rightmost 1-bit in val.  */
-  return nbits;
-}
-
 static int
 thumb_advance_itstate (unsigned int itstate)
 {
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 3e06f79..9b8447b 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -26,9 +26,6 @@ struct address_space;
 
 #include "arch/arm.h"
 
-/* Size of integer registers.  */
-#define INT_REGISTER_SIZE		4
-
 /* Say how long FP registers are.  Used for documentation purposes and
    code readability in this header.  IEEE extended doubles are 80
    bits.  DWORD aligned they use 96 bits.  */
@@ -50,32 +47,6 @@ struct address_space;
 #define NUM_GREGS	16	/* Number of general purpose registers.  */
 
 
-/* Instruction condition field values.  */
-#define INST_EQ		0x0
-#define INST_NE		0x1
-#define INST_CS		0x2
-#define INST_CC		0x3
-#define INST_MI		0x4
-#define INST_PL		0x5
-#define INST_VS		0x6
-#define INST_VC		0x7
-#define INST_HI		0x8
-#define INST_LS		0x9
-#define INST_GE		0xa
-#define INST_LT		0xb
-#define INST_GT		0xc
-#define INST_LE		0xd
-#define INST_AL		0xe
-#define INST_NV		0xf
-
-#define FLAG_N		0x80000000
-#define FLAG_Z		0x40000000
-#define FLAG_C		0x20000000
-#define FLAG_V		0x10000000
-
-#define CPSR_T		0x20
-
-#define XPSR_T		0x01000000
 
 /* Type of floating-point code in use by inferior.  There are really 3 models
    that are traditionally supported (plus the endianness issue), but gcc can
diff --git a/gdb/arm-wince-tdep.c b/gdb/arm-wince-tdep.c
index 72295ba..3abd89d 100644
--- a/gdb/arm-wince-tdep.c
+++ b/gdb/arm-wince-tdep.c
@@ -24,6 +24,7 @@
 #include "target.h"
 #include "frame.h"
 
+#include "arch/arm.h"
 #include "arm-tdep.h"
 #include "windows-tdep.h"
 
diff --git a/gdb/armnbsd-tdep.c b/gdb/armnbsd-tdep.c
index 4c128c2..14eceaa 100644
--- a/gdb/armnbsd-tdep.c
+++ b/gdb/armnbsd-tdep.c
@@ -20,6 +20,7 @@
 #include "defs.h"
 #include "osabi.h"
 
+#include "arch/arm.h"
 #include "arm-tdep.h"
 #include "solib-svr4.h"
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 10/10] Enable conditional breakpoints for targets that support software single step in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
  2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
@ 2015-10-29 17:15 ` Antoine Tremblay
  2015-11-04 18:58   ` Pedro Alves
  2015-10-29 17:15 ` [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer Antoine Tremblay
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch enables support for conditional breakpoints if the target supports
software single step.

This was disabled before as the implementations of software single step were too
simple as discussed in
https://sourceware.org/ml/gdb-patches/2015-04/msg01110.html.

Since these issues are now fixed support can be added back.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* server.c (handle_query): Call target_supports_software_single_step.
---
 gdb/gdbserver/server.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 3232da1..2ce2104 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -2210,13 +2210,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 	  strcat (own_buf, ";tracenz+");
 	}
 
-      if (target_supports_hardware_single_step ())
+      if (target_supports_hardware_single_step () ||
+	  target_supports_software_single_step () )
 	{
-	  /* Support target-side breakpoint conditions and commands.
-	     GDBserver needs to step over the breakpoint if the condition
-	     is false.  GDBserver software single step is too simple, so
-	     disable conditional breakpoints if the target doesn't have
-	     hardware single step.  */
 	  strcat (own_buf, ";ConditionalBreakpoints+");
 	}
       strcat (own_buf, ";BreakpointCommands+");
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (2 preceding siblings ...)
  2015-10-29 17:15 ` [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer Antoine Tremblay
@ 2015-10-29 17:16 ` Antoine Tremblay
  2015-11-04 18:55   ` Pedro Alves
  2015-10-29 17:28 ` [PATCH 03/10] Refactor queries for hardware and software single stepping support " Antoine Tremblay
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch enables software single stepping if the targets supports it,
to do while-stepping actions.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-low.c (single_step): New function.
	(linux_resume_one_lwp_throw): Call single_step.
	(start_step_over): Likewise.
---
 gdb/gdbserver/linux-low.c | 59 +++++++++++++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 1f423ba..d0a9c2a 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -3900,7 +3900,34 @@ install_software_single_step_breakpoints (struct lwp_info *lwp)
   VEC_free (CORE_ADDR, next_pcs.result);
 }
 
-/* Resume execution of LWP.  If STEP is nonzero, single-step it.  If
+/* Single step via hardware or software single step.
+   Return 1 if hardware single stepping, 0 if software single stepping
+   or can't single step.  */
+
+static int
+single_step (struct lwp_info* lwp)
+{
+  int step = 0;
+
+  if (can_hardware_single_step ())
+    {
+      step = 1;
+    }
+  else if (can_software_single_step ())
+    {
+      install_software_single_step_breakpoints (lwp);
+      step = 0;
+    }
+  else
+    {
+      if (debug_threads)
+	debug_printf ("stepping is not implemented on this target");
+    }
+
+  return step;
+}
+
+/* RESUME execution of LWP.  If STEP is nonzero, single-step it.  If
    SIGNAL is nonzero, give it that signal.  */
 
 static void
@@ -4045,14 +4072,13 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp,
      address, continue, and carry on catching this while-stepping
      action only when that breakpoint is hit.  A future
      enhancement.  */
-  if (thread->while_stepping != NULL
-      && can_hardware_single_step ())
-    {
-      if (debug_threads)
-	debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n",
-		      lwpid_of (thread));
-      step = 1;
-    }
+  if (thread->while_stepping != NULL) {
+    if (debug_threads)
+      debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n",
+		    lwpid_of (thread));
+
+    step = single_step (lwp);
+  }
 
   if (proc->tdesc != NULL && the_low_target.get_pc != NULL)
     {
@@ -4457,20 +4483,7 @@ start_step_over (struct lwp_info *lwp)
   uninsert_breakpoints_at (pc);
   uninsert_fast_tracepoint_jumps_at (pc);
 
-  if (can_hardware_single_step ())
-    {
-      step = 1;
-    }
-  else if (can_software_single_step ())
-    {
-      install_software_single_step_breakpoints (lwp);
-      step = 0;
-    }
-  else
-    {
-      internal_error (__FILE__, __LINE__,
-		      "stepping is not implemented on this target");
-    }
+  step = single_step (lwp);
 
   current_thread = saved_thread;
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 03/10] Refactor queries for hardware and software single stepping support in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (3 preceding siblings ...)
  2015-10-29 17:16 ` [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer Antoine Tremblay
@ 2015-10-29 17:28 ` Antoine Tremblay
  2015-11-04 18:47   ` Pedro Alves
  2015-10-29 17:31 ` [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations Antoine Tremblay
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

Before this patch there was only one call: can_hardware_single_step. Its
implementation was a check on breakpoint_reinsert_addr if NULL it assumed
that the target could hardware single step.

This patch prepares for the case where this is not true anymore.

In order to improve software single stepping in GDBServer the
breakpoint_reinsert_addr operation of targets that had a very simple
software implementation used only for stepping over thread creation events
will be removed.

This will create a case where a target does not support hardware single
step and has the operation breakpoint_reinsert_addr set to NULL, thus
can_hardware_single_step needs to be implemented another way.

A new target operation supports_hardware_single_step is introduced and is
to return true if the target does support such a feature, support for the
feature is manually hardcoded.

Note that the hardware single step support was enabled as per the current
behavior, I did not check if tile for example really has ptrace singlestep
support but since the current implementation assumed it had, I kept it
that way.

No regressions on Ubuntu 14.04 on ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

Compilation tested on: aarch64,arm,bfind,crisv32,m32r,ppc,s390,tic6x,tile,
xtensa.
Not tested : sh.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-low.c (aarch64_supports_hardware_single_step):
	New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-arm-low.c (arm_supports_hardware_single_step): New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-bfin-low.c (bfin_supports_hardware_single_step): New function.
	(struct linux_target_ops) <bfin_supports_hardware_single_step>:
	Initialize.
	* linux-crisv32-low.c (cris_supports_hardware_single_step):
	New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-low.c (can_hardware_single_step): Use
	supports_hardware_single_step.
	(can_software_single_step): New function.
	(start_step_over): Call can_software_single_step.
	(linux_supports_hardware_single_step): New function.
	(struct target_ops) <supports_software_single_step>: Initialize.
	* linux-low.h (struct linux_target_ops)
	<supports_hardware_single_step>: Initialize.
	* linux-m32r-low.c (m32r_supports_hardware_single_step): New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-ppc-low.c (ppc_supports_hardware_single_step): New function.
	(struct linux_target_ops) <supports_hardware_single_step> Initialize.
	* linux-s390-low.c (s390_supports_hardware_single_step): New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-sh-low.c (sh_supports_hardware_single_step): New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-tic6x-low.c (tic6x_supports_hardware_single_step): New function.
	(struct linux_target_ops) <tic6x_supports_hardware_single_step>:
	Initialize.
	* linux-tile-low.c (tile_supports_hardware_single_step): New function.
	(struct linux_target_ops) <tile_supports_hardware_single_step>:
	Initialize.
	* linux-x86-low.c (x86_supports_hardware_single_step) New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* linux-xtensa-low.c (xtensa_supports_hardware_single_step):
	New function.
	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
	* target.h (struct target_ops): <supports_software_single_step>:
	New field.
	(target_supports_software_single_step): New macro.
---
 gdb/gdbserver/linux-aarch64-low.c | 10 ++++++++++
 gdb/gdbserver/linux-arm-low.c     | 11 ++++++++++-
 gdb/gdbserver/linux-bfin-low.c    | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/linux-crisv32-low.c | 24 ++++++++++++++++++++++++
 gdb/gdbserver/linux-low.c         | 33 ++++++++++++++++++++++++++++-----
 gdb/gdbserver/linux-low.h         |  3 +++
 gdb/gdbserver/linux-m32r-low.c    | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/linux-ppc-low.c     | 22 ++++++++++++++++++++++
 gdb/gdbserver/linux-s390-low.c    | 22 ++++++++++++++++++++++
 gdb/gdbserver/linux-sh-low.c      | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/linux-tic6x-low.c   | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/linux-tile-low.c    | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/linux-x86-low.c     | 11 +++++++++++
 gdb/gdbserver/linux-xtensa-low.c  | 29 +++++++++++++++++++++++++++++
 gdb/gdbserver/target.h            |  7 +++++++
 15 files changed, 311 insertions(+), 6 deletions(-)

diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index 4f23392..a0bc1c2 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -2940,6 +2940,14 @@ aarch64_sw_breakpoint_from_kind (int kind, int *size)
   return aarch64_breakpoint;
 }
 
+/* Support for hardware single step.  */
+
+static int
+aarch64_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 struct linux_target_ops the_low_target =
 {
   aarch64_arch_setup,
@@ -2973,6 +2981,8 @@ struct linux_target_ops the_low_target =
   aarch64_emit_ops,
   aarch64_get_min_fast_tracepoint_insn_len,
   aarch64_supports_range_stepping,
+  NULL, /* breakpoint_kind_from_current_state */
+  aarch64_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index d6767d7..2a840bf 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -897,6 +897,14 @@ arm_arch_setup (void)
     have_ptrace_getregset = 0;
 }
 
+/* Support for hardware single step.  */
+
+static int
+arm_supports_hardware_single_step (void)
+{
+  return 0;
+}
+
 /* Register sets without using PTRACE_GETREGSET.  */
 
 static struct regset_info arm_regsets[] = {
@@ -1053,7 +1061,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* emit_ops */
   NULL, /* get_min_fast_tracepoint_insn_len */
   NULL, /* supports_range_stepping */
-  arm_breakpoint_kind_from_current_state
+  arm_breakpoint_kind_from_current_state,
+  arm_supports_hardware_single_step
 };
 
 void
diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c
index d3b83fc..912d253 100644
--- a/gdb/gdbserver/linux-bfin-low.c
+++ b/gdb/gdbserver/linux-bfin-low.c
@@ -105,6 +105,14 @@ bfin_arch_setup (void)
   current_process ()->tdesc = tdesc_bfin;
 }
 
+/* Support for hardware single step.  */
+
+static int
+bfin_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct usrregs_info bfin_usrregs_info =
   {
     bfin_num_regs,
@@ -136,6 +144,27 @@ struct linux_target_ops the_low_target = {
   NULL, /* breakpoint_reinsert_addr */
   2,
   bfin_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  bfin_supports_hardware_single_step,
 };
 
 
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
index 8d9ef04..4f9afa6 100644
--- a/gdb/gdbserver/linux-crisv32-low.c
+++ b/gdb/gdbserver/linux-crisv32-low.c
@@ -388,6 +388,14 @@ cris_arch_setup (void)
   current_process ()->tdesc = tdesc_crisv32;
 }
 
+/* Support for hardware single step.  */
+
+static int
+cris_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct regset_info cris_regsets[] = {
   { PTRACE_GETREGS, PTRACE_SETREGS, 0, cris_num_regs * 4,
     GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
@@ -439,6 +447,22 @@ struct linux_target_ops the_low_target = {
   cris_remove_point,
   cris_stopped_by_watchpoint,
   cris_stopped_data_address,
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  cris_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 853a289..ceddf4d 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -269,13 +269,24 @@ static void complete_ongoing_step_over (void);
    being stepped.  */
 ptid_t step_over_bkpt;
 
-/* True if the low target can hardware single-step.  Such targets
-   don't need a BREAKPOINT_REINSERT_ADDR callback.  */
+/* True if the low target can hardware single-step.  */
 
 static int
 can_hardware_single_step (void)
 {
-  return (the_low_target.breakpoint_reinsert_addr == NULL);
+  if (the_low_target.supports_hardware_single_step != NULL)
+    return the_low_target.supports_hardware_single_step ();
+  else
+    return 0;
+}
+
+/* True if the low target can software single-step.  Such targets
+   implement the BREAKPOINT_REINSERT_ADDR callback.  */
+
+static int
+can_software_single_step (void)
+{
+  return (the_low_target.breakpoint_reinsert_addr != NULL);
 }
 
 /* True if the low target supports memory breakpoints.  If so, we'll
@@ -4426,12 +4437,17 @@ start_step_over (struct lwp_info *lwp)
     {
       step = 1;
     }
-  else
+  else if (can_software_single_step ())
     {
       CORE_ADDR raddr = (*the_low_target.breakpoint_reinsert_addr) ();
       set_reinsert_breakpoint (raddr);
       step = 0;
     }
+  else
+    {
+      internal_error (__FILE__, __LINE__,
+		      "stepping is not implemented on this target");
+    }
 
   current_thread = saved_thread;
 
@@ -5626,6 +5642,12 @@ linux_supports_hardware_single_step (void)
 }
 
 static int
+linux_supports_software_single_step (void)
+{
+  return can_software_single_step ();
+}
+
+static int
 linux_stopped_by_watchpoint (void)
 {
   struct lwp_info *lwp = get_thread_lwp (current_thread);
@@ -7064,7 +7086,8 @@ static struct target_ops linux_target_ops = {
   linux_mntns_readlink,
   linux_breakpoint_kind_from_pc,
   linux_sw_breakpoint_from_kind,
-  linux_breakpoint_kind_from_current_state
+  linux_breakpoint_kind_from_current_state,
+  linux_supports_software_single_step
 };
 
 static void
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index fb15136..2e1f32f 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -236,6 +236,9 @@ struct linux_target_ops
 
   /* See target.h.  */
   int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
+
+  /* See target.h.  */
+  int (*supports_hardware_single_step) (void);
 };
 
 extern struct linux_target_ops the_low_target;
diff --git a/gdb/gdbserver/linux-m32r-low.c b/gdb/gdbserver/linux-m32r-low.c
index bb1002f..c6d79b6 100644
--- a/gdb/gdbserver/linux-m32r-low.c
+++ b/gdb/gdbserver/linux-m32r-low.c
@@ -103,6 +103,14 @@ m32r_arch_setup (void)
   current_process ()->tdesc = tdesc_m32r;
 }
 
+/* Support for hardware single step.  */
+
+static int
+m32r_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct usrregs_info m32r_usrregs_info =
   {
     m32r_num_regs,
@@ -134,6 +142,27 @@ struct linux_target_ops the_low_target = {
   NULL,
   0,
   m32r_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  m32r_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 9e223ea..91e7822 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -645,6 +645,14 @@ ppc_store_evrregset (struct regcache *regcache, const void *buf)
   supply_register_by_name (regcache, "spefscr", &regset->spefscr);
 }
 
+/* Support for hardware single step.  */
+
+static int
+ppc_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct regset_info ppc_regsets[] = {
   /* List the extra register sets before GENERAL_REGS.  That way we will
      fetch them every time, but still fall back to PTRACE_PEEKUSER for the
@@ -706,6 +714,20 @@ struct linux_target_ops the_low_target = {
   NULL,
   ppc_collect_ptrace_register,
   ppc_supply_ptrace_register,
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  ppc_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c
index efede2d..7127373 100644
--- a/gdb/gdbserver/linux-s390-low.c
+++ b/gdb/gdbserver/linux-s390-low.c
@@ -609,6 +609,14 @@ s390_breakpoint_at (CORE_ADDR pc)
   return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
 }
 
+/* Support for hardware single step.  */
+
+static int
+s390_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct usrregs_info s390_usrregs_info =
   {
     s390_num_regs,
@@ -686,6 +694,20 @@ struct linux_target_ops the_low_target = {
   NULL,
   s390_collect_ptrace_register,
   s390_supply_ptrace_register,
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  s390_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c
index 207e87e..1b3189b 100644
--- a/gdb/gdbserver/linux-sh-low.c
+++ b/gdb/gdbserver/linux-sh-low.c
@@ -100,6 +100,14 @@ sh_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Support for hardware single step.  */
+
+static int
+sh_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 /* Provide only a fill function for the general register set.  ps_lgetregs
    will use this for NPTL support.  */
 
@@ -162,6 +170,27 @@ struct linux_target_ops the_low_target = {
   NULL,
   0,
   sh_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  sh_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-tic6x-low.c b/gdb/gdbserver/linux-tic6x-low.c
index cf8b5fb..e4aba15 100644
--- a/gdb/gdbserver/linux-tic6x-low.c
+++ b/gdb/gdbserver/linux-tic6x-low.c
@@ -341,6 +341,14 @@ tic6x_arch_setup (void)
   current_process ()->tdesc = tic6x_read_description ();
 }
 
+/* Support for hardware single step.  */
+
+static int
+tic6x_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static struct regsets_info tic6x_regsets_info =
   {
     tic6x_regsets, /* regsets */
@@ -380,6 +388,27 @@ struct linux_target_ops the_low_target = {
   NULL,
   0,
   tic6x_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  tic6x_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-tile-low.c b/gdb/gdbserver/linux-tile-low.c
index 47ca245..6f16355 100644
--- a/gdb/gdbserver/linux-tile-low.c
+++ b/gdb/gdbserver/linux-tile-low.c
@@ -181,6 +181,14 @@ tile_arch_setup (void)
     current_process ()->tdesc = tdesc_tilegx;
 }
 
+/* Support for hardware single step.  */
+
+static int
+tile_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 
 struct linux_target_ops the_low_target =
 {
@@ -196,6 +204,27 @@ struct linux_target_ops the_low_target =
   NULL,
   0,
   tile_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  tile_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 89ec4e5..7c63919 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -3258,6 +3258,15 @@ x86_supports_range_stepping (void)
   return 1;
 }
 
+/* Implementation of linux_target_ops method "supports_hardware_single_step".
+ */
+
+static int
+x86_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 /* This is initialized assuming an amd64 target.
    x86_arch_setup will correct it for i386 or amd64 targets.  */
 
@@ -3298,6 +3307,8 @@ struct linux_target_ops the_low_target =
   x86_emit_ops,
   x86_get_min_fast_tracepoint_insn_len,
   x86_supports_range_stepping,
+  NULL, /* breakpoint_kind_from_current_state */
+  x86_supports_hardware_single_step,
 };
 
 void
diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c
index 7c71631..b48e8dd 100644
--- a/gdb/gdbserver/linux-xtensa-low.c
+++ b/gdb/gdbserver/linux-xtensa-low.c
@@ -229,6 +229,14 @@ xtensa_arch_setup (void)
   current_process ()->tdesc = tdesc_xtensa;
 }
 
+/* Support for hardware single step.  */
+
+static int
+xtensa_supports_hardware_single_step (void)
+{
+  return 1;
+}
+
 static const struct regs_info *
 xtensa_regs_info (void)
 {
@@ -248,6 +256,27 @@ struct linux_target_ops the_low_target = {
   NULL,
   0,
   xtensa_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  xtensa_supports_hardware_single_step,
 };
 
 
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index f0fb9d7..0e6dfaa 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -457,6 +457,9 @@ struct target_ops
      adjusted to the real memory location in case a flag (e.g., the Thumb
      bit on ARM) was present in the PC.  */
   int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
+
+  /* Returns true if the target can software single step.  */
+  int (*supports_software_single_step) (void);
 };
 
 extern struct target_ops *the_target;
@@ -649,6 +652,10 @@ int kill_inferior (int);
    ? (*the_target->breakpoint_kind_from_current_state) (pcptr) \
    : target_breakpoint_kind_from_pc (pcptr))
 
+#define target_supports_software_single_step() \
+  (the_target->supports_software_single_step ? \
+   (*the_target->supports_software_single_step) () : 0)
+
 /* Start non-stop mode, returns 0 on success, -1 on failure.   */
 
 int start_non_stop (int nonstop);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (4 preceding siblings ...)
  2015-10-29 17:28 ` [PATCH 03/10] Refactor queries for hardware and software single stepping support " Antoine Tremblay
@ 2015-10-29 17:31 ` Antoine Tremblay
  2015-11-04 18:21   ` Pedro Alves
  2015-10-29 17:36 ` [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer Antoine Tremblay
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:31 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch removes too simple implementations of the breakpoint_reinsert_addr
operation.

The only reason to keep them around was to support thread events when
PTRACE_EVENT_CLONE was not present but this support has been removed in a
previous patch.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

Also compilation was tested on aarch64, bfin, cris, crisv32,
m32r, mips, nios2, ppc, s390, sparc, tic6x, tile,  xtensa.

gdb/gdbserver/ChangeLog:

	* linux-arm-low.c (arm_reinsert_addr): Remove function.
	(struct linux_target_ops <breakpoint_reinsert_addr>: Set to NULL.
	* linux-cris-low.c (cris_reinsert_addr> Remove function.
	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
	* linux-crisv32-low.c (cris_reinsert_addr): Remove function.
	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
	* linux-mips-low.c (mips_reinsert_addr): Remove function.
	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
	* linux-nios2-low.c (nios2_reinsert_addr): Remove function.
	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
	* linux-sparc-low.c (sparc_reinsert_addr): Remove function.
	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL;
---
 gdb/gdbserver/linux-arm-low.c     | 14 +-------------
 gdb/gdbserver/linux-cris-low.c    | 18 +-----------------
 gdb/gdbserver/linux-crisv32-low.c | 19 +------------------
 gdb/gdbserver/linux-mips-low.c    | 14 +-------------
 gdb/gdbserver/linux-nios2-low.c   | 14 +-------------
 gdb/gdbserver/linux-sparc-low.c   | 15 +--------------
 6 files changed, 6 insertions(+), 88 deletions(-)

diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 2a840bf..8e32fae 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -315,18 +315,6 @@ arm_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-static CORE_ADDR
-arm_reinsert_addr (void)
-{
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-  unsigned long pc;
-  collect_register_by_name (regcache, "lr", &pc);
-  return pc;
-}
-
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -1039,7 +1027,7 @@ struct linux_target_ops the_low_target = {
   arm_set_pc,
   arm_breakpoint_kind_from_pc,
   arm_sw_breakpoint_from_kind,
-  arm_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   arm_breakpoint_at,
   arm_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c
index d7b70e3..9f4519c 100644
--- a/gdb/gdbserver/linux-cris-low.c
+++ b/gdb/gdbserver/linux-cris-low.c
@@ -105,18 +105,6 @@ cris_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-static CORE_ADDR
-cris_reinsert_addr (void)
-{
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-  unsigned long pc;
-  collect_register_by_name (regcache, "srp", &pc);
-  return pc;
-}
-
 static void
 cris_arch_setup (void)
 {
@@ -151,13 +139,9 @@ struct linux_target_ops the_low_target = {
   cris_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
-  cris_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   cris_breakpoint_at,
-  0,
-  0,
-  0,
-  0,
 };
 
 void
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
index 4f9afa6..2404d0e 100644
--- a/gdb/gdbserver/linux-crisv32-low.c
+++ b/gdb/gdbserver/linux-crisv32-low.c
@@ -101,23 +101,6 @@ cris_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-
-/* FIXME: This function should not be needed, since we have PTRACE_SINGLESTEP
-   for CRISv32.  Without it, td_ta_event_getmsg in thread_db_create_event
-   will fail when debugging multi-threaded applications.  */
-
-static CORE_ADDR
-cris_reinsert_addr (void)
-{
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-  unsigned long pc;
-  collect_register_by_name (regcache, "srp", &pc);
-  return pc;
-}
-
 static void
 cris_write_data_breakpoint (struct regcache *regcache,
 			    int bp, unsigned long start, unsigned long end)
@@ -439,7 +422,7 @@ struct linux_target_ops the_low_target = {
   cris_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
-  cris_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   cris_breakpoint_at,
   cris_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 86f7962..32a91a8 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -275,18 +275,6 @@ mips_sw_breakpoint_from_kind (int kind, int *size)
   return (const gdb_byte *) &mips_breakpoint;
 }
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-static CORE_ADDR
-mips_reinsert_addr (void)
-{
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-  union mips_register ra;
-  collect_register_by_name (regcache, "r31", ra.buf);
-  return register_size (regcache->tdesc, 0) == 4 ? ra.reg32 : ra.reg64;
-}
-
 static int
 mips_breakpoint_at (CORE_ADDR where)
 {
@@ -892,7 +880,7 @@ struct linux_target_ops the_low_target = {
   mips_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   mips_sw_breakpoint_from_kind,
-  mips_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   mips_breakpoint_at,
   mips_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c
index 369e89c..9380c3b 100644
--- a/gdb/gdbserver/linux-nios2-low.c
+++ b/gdb/gdbserver/linux-nios2-low.c
@@ -144,18 +144,6 @@ nios2_sw_breakpoint_from_kind (int kind, int *size)
   return (const gdb_byte *) &nios2_breakpoint;
 }
 
-/* Implement the breakpoint_reinsert_addr linux_target_ops method.  */
-
-static CORE_ADDR
-nios2_reinsert_addr (void)
-{
-  union nios2_register ra;
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-
-  collect_register_by_name (regcache, "ra", ra.buf);
-  return ra.reg32;
-}
-
 /* Implement the breakpoint_at linux_target_ops method.  */
 
 static int
@@ -279,7 +267,7 @@ struct linux_target_ops the_low_target =
   nios2_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   nios2_sw_breakpoint_from_kind,
-  nios2_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   nios2_breakpoint_at,
 };
diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c
index e6a4f84..54a849c 100644
--- a/gdb/gdbserver/linux-sparc-low.c
+++ b/gdb/gdbserver/linux-sparc-low.c
@@ -265,19 +265,6 @@ sparc_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
-/* We only place breakpoints in empty marker functions, and thread locking
-   is outside of the function.  So rather than importing software single-step,
-   we can just run until exit.  */
-static CORE_ADDR
-sparc_reinsert_addr (void)
-{
-  struct regcache *regcache = get_thread_regcache (current_thread, 1);
-  CORE_ADDR lr;
-  /* O7 is the equivalent to the 'lr' of other archs.  */
-  collect_register_by_name (regcache, "o7", &lr);
-  return lr;
-}
-
 static void
 sparc_arch_setup (void)
 {
@@ -333,7 +320,7 @@ struct linux_target_ops the_low_target = {
   NULL,
   NULL, /* breakpoint_kind_from_pc */
   sparc_sw_breakpoint_from_kind,
-  sparc_reinsert_addr,
+  NULL, /* breakpoint_reinsert_addr */
   0,
   sparc_breakpoint_at,
   NULL,  /* supports_z_point_type */
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (5 preceding siblings ...)
  2015-10-29 17:31 ` [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations Antoine Tremblay
@ 2015-10-29 17:36 ` Antoine Tremblay
  2015-11-03 16:22   ` Yao Qi
  2015-10-29 17:43 ` [PATCH 08/10] Support software single step on ARM " Antoine Tremblay
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:36 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

When manually stepping over a permanent breakpoint on ARM we need to fetch the
right breakpoint size based on the current instruction set used.

Since this is not encoded in the stop_pc, the instruction mode needs to be
fetched from the CPSR register.

This is done by introducing a new target operation called :
breakpoint_kind_from_current_state.

For other targets that do not need this, breakpoint_kind_from_pc is used.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-arm-low.c (arm_is_thumb_mode): New function.
	(arm_breakpoint_at): Use arm_is_thumb_mode.
	(arm_breakpoint_kind_from_current_state): New function.
	(struct linux_target_ops) <breakpoint_kind_from_current_state>:
	Initialize.
	* linux-low.c (linux_wait_1): Call breakpoint_kind_from_current_state.
	(linux_breakpoint_kind_from_current_state): New function.
	(struct target_ops <breakpoint_kind_from_current_state>: Initialize.
	* linux-low.h (struct linux_target_ops)
	<breakpoint_kind_from_current_state>: New field.
	* target.h (struct target_ops): Likewise.
	(target_breakpoint_kind_from_current_state): New macro.
---
 gdb/gdbserver/linux-arm-low.c | 38 +++++++++++++++++++++++++++++++++++++-
 gdb/gdbserver/linux-low.c     | 18 ++++++++++++++++--
 gdb/gdbserver/linux-low.h     |  3 +++
 gdb/gdbserver/target.h        | 11 +++++++++++
 4 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index bab2aaf..d6767d7 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -265,7 +265,7 @@ static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 };
 #define thumb2_breakpoint_len 4
 
 static int
-arm_breakpoint_at (CORE_ADDR where)
+arm_is_thumb_mode (void)
 {
   struct regcache *regcache = get_thread_regcache (current_thread, 1);
   unsigned long cpsr;
@@ -273,6 +273,17 @@ arm_breakpoint_at (CORE_ADDR where)
   collect_register_by_name (regcache, "cpsr", &cpsr);
 
   if (cpsr & 0x20)
+    return 1;
+  else
+    return 0;
+}
+
+/* Returns 1 if there is a software breakpoint at location.  */
+
+static int
+arm_breakpoint_at (CORE_ADDR where)
+{
+  if (arm_is_thumb_mode ())
     {
       /* Thumb mode.  */
       unsigned short insn;
@@ -993,6 +1004,23 @@ arm_sw_breakpoint_from_kind (int kind , int *size)
   return NULL;
 }
 
+/* Implementation of the linux_target_ops method
+   "breakpoint_kind_from_current_state".  */
+
+static int
+arm_breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
+{
+  if (arm_is_thumb_mode ())
+    {
+      *pcptr = MAKE_THUMB_ADDR (*pcptr);
+      return arm_breakpoint_kind_from_pc (pcptr);
+    }
+  else
+    {
+      return arm_breakpoint_kind_from_pc (pcptr);
+    }
+}
+
 struct linux_target_ops the_low_target = {
   arm_arch_setup,
   arm_regs_info,
@@ -1018,6 +1046,14 @@ struct linux_target_ops the_low_target = {
   arm_new_thread,
   arm_new_fork,
   arm_prepare_to_resume,
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  arm_breakpoint_kind_from_current_state
 };
 
 void
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 41ab510..3b6c131 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -3006,7 +3006,8 @@ linux_wait_1 (ptid_t ptid,
       int breakpoint_kind = 0;
       CORE_ADDR stop_pc = event_child->stop_pc;
 
-      breakpoint_kind = the_target->breakpoint_kind_from_pc (&stop_pc);
+      breakpoint_kind =
+	the_target->breakpoint_kind_from_current_state (&stop_pc);
       the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc);
 
       if (debug_threads)
@@ -6948,6 +6949,18 @@ linux_sw_breakpoint_from_kind (int kind, int *size)
   return (*the_low_target.sw_breakpoint_from_kind) (kind, size);
 }
 
+/* Implementation of the target_ops method
+   "breakpoint_kind_from_current_state".  */
+
+static int
+linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr)
+{
+  if (the_low_target.breakpoint_kind_from_current_state != NULL)
+    return (*the_low_target.breakpoint_kind_from_current_state) (pcptr);
+  else
+    return linux_breakpoint_kind_from_pc (pcptr);
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_arch_setup,
@@ -7043,7 +7056,8 @@ static struct target_ops linux_target_ops = {
   linux_mntns_unlink,
   linux_mntns_readlink,
   linux_breakpoint_kind_from_pc,
-  linux_sw_breakpoint_from_kind
+  linux_sw_breakpoint_from_kind,
+  linux_breakpoint_kind_from_current_state
 };
 
 static void
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index ccf4c94..fb15136 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -233,6 +233,9 @@ struct linux_target_ops
 
   /* Returns true if the low target supports range stepping.  */
   int (*supports_range_stepping) (void);
+
+  /* See target.h.  */
+  int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
 };
 
 extern struct linux_target_ops the_low_target;
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 769c876..f0fb9d7 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -451,6 +451,12 @@ struct target_ops
      specific meaning like the Z0 kind parameter.
      SIZE is set to the software breakpoint's length in memory.  */
   const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
+
+  /* Return the breakpoint kind for this target based on the current state
+     (e.g. the current instruction mode on ARM) and the PC. The PCPTR is
+     adjusted to the real memory location in case a flag (e.g., the Thumb
+     bit on ARM) was present in the PC.  */
+  int (*breakpoint_kind_from_current_state) (CORE_ADDR *pcptr);
 };
 
 extern struct target_ops *the_target;
@@ -638,6 +644,11 @@ int kill_inferior (int);
    ? (*the_target->breakpoint_kind_from_pc) (pcptr) \
    : default_breakpoint_kind_from_pc (pcptr))
 
+#define target_breakpoint_kind_from_current_state(pcptr) \
+  (the_target->breakpoint_kind_from_current_state \
+   ? (*the_target->breakpoint_kind_from_current_state) (pcptr) \
+   : target_breakpoint_kind_from_pc (pcptr))
+
 /* Start non-stop mode, returns 0 on success, -1 on failure.   */
 
 int start_non_stop (int nonstop);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 08/10] Support software single step on ARM in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (6 preceding siblings ...)
  2015-10-29 17:36 ` [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer Antoine Tremblay
@ 2015-10-29 17:43 ` Antoine Tremblay
  2015-11-04 18:46   ` Pedro Alves
  2015-10-29 17:45 ` [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation " Antoine Tremblay
  2015-10-29 17:48 ` [PATCH 02/10] Fix instruction skipping when using software single step " Antoine Tremblay
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:43 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch teaches GDBserver how to software single step on ARM
linux by sharing code with GDB.

The arm_get_next_pcs function in GDB is now shared with GDBServer.  So that
GDBServer can use the function to return the possible addresses of the next PC.

A proper shared context was also needed so that we could share the code, this
context is described as this data structure (expressed as a class
hierarchy):

struct get_next_pcs
  struct os_arch_get_next_pcs
    struct os_arch_(gdb|gdbserver)_get_next_pcs

Where arch can by replaced by arm for this patch. This structure should be
flexible enough to accomodate any arch or os (optional) that would need a
get_next_pcs context.

Limitations :

GDBServer can't step over a sigreturn or rt_sigreturn syscall since this would
require the DWARF information to identify the caller PC. This situation
only prints a warning for the moment.

Testing :

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/ChangeLog:
	* Makefile.in: Add arm-get-next-pcs.c/o to all arm targets.
	* arch/arm-get-next-pcs.c: New file.
	* arch/arm-get-next-pcs.h: New file.
	* arm-linux-nat.c: Include arch/arm.h and arch/arm-get-next-pcs.h
	* arm-linux-tdep.c: (arm_linux_software_single_step): Adjust for
	arm_get_next_pcs implementation.
	* arm-tdep.c (submask): Move macro to arm-get-next-pcs.h.
	(bit): Likewise.
	(bits): Likewise.
	(sbits): Likewise.
	(BranchDest): Likewise.
	(thumb_instruction_changes_pc): Move to arm-get-next-pcs.c
	(thumb2_instruction_changes_pc): Likewise.
	(arm_instruction_changes_pc): Likewise.
	(thumb_advance_itstate): Likewise.
	(thumb_get_next_pc_raw): Likewise.
	(arm_get_next_pc_raw): Likewise.
	(arm_get_next_pc): Likewise.
	(thumb_deal_with_atomic_sequence_raw): Likewise.
	(arm_deal_with_atomic_sequence_raw): Likewise.
	(arm_deal_with_atomic_sequence): Likewise.
	(arm_get_next_pcs_read_memory_unsigned_integer): New function.
	(arm_get_next_pcs_addr_bits_remove): Likewise.
	(arm_get_next_pcs_collect_register_unsigned): Likewise.
	(arm_get_next_pcs_syscall_next_pc): Likewise.
	(arm_software_single_step): Adjust for arm_get_next_pcs implementation.
	* arm-tdep.h (arm_get_next_pcs_read_memory_unsigned_integer):
	New declaration.
	(arm_get_next_pcs_addr_bits_remove): Likewise.
	(arm_get_next_pcs_collect_register_unsigned): Likewise.
	(arm_get_next_pcs_syscall_next_pc): Likewise.
	(arm_software_single_step): Likewise.
	(arm_deal_with_atomic_sequence: Remove declaration.
	(arm_software_single_step): Likewise.
	* configure.tgt: Add arm-get-next-pcs.o to all arm targets.

gdb/gdbserver/ChangeLog:
	* Makefile.in : Add arm-get-next-pcs.c/o.
	* configure.srv: Add arm-get-next-pcs.o to needed arm targets.
	* linux-arm-low.c (get_next_pcs_addr_bits_remove): New function.
	(get_next_pcs_collect_register_unsigned): Likewise.
	(get_next_pcs_read_memory_unsigned_integer): Likewise.
	(get_next_pcs_syscall_next_pc): Likewise.
	(arm_gdbserver_get_next_pcs): Likewise.
	(struct linux_target_ops) <arm_gdbserver_get_next_pcs>: Initialize.
---
 gdb/Makefile.in               |   12 +-
 gdb/arch/arm-get-next-pcs.c   | 1223 +++++++++++++++++++++++++++++++++
 gdb/arch/arm-get-next-pcs.h   |  100 +++
 gdb/arm-linux-nat.c           |    2 +
 gdb/arm-linux-tdep.c          |   57 +-
 gdb/arm-tdep.c                | 1486 ++++++-----------------------------------
 gdb/arm-tdep.h                |   24 +-
 gdb/configure.tgt             |   19 +-
 gdb/gdbserver/Makefile.in     |    5 +-
 gdb/gdbserver/configure.srv   |    1 +
 gdb/gdbserver/linux-arm-low.c |  133 +++-
 11 files changed, 1741 insertions(+), 1321 deletions(-)
 create mode 100644 gdb/arch/arm-get-next-pcs.c
 create mode 100644 gdb/arch/arm-get-next-pcs.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 14ad405..670b4eb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -657,7 +657,8 @@ ALL_64_TARGET_OBS = \
 
 # All other target-dependent objects files (used with --enable-targets=all).
 ALL_TARGET_OBS = \
-	armbsd-tdep.o arm.o arm-linux-tdep.o arm-symbian-tdep.o \
+	armbsd-tdep.o arm.o arm-linux-tdep.o \
+	arm-get-next-pcs.o arm-symbian-tdep.o \
 	armnbsd-tdep.o armobsd-tdep.o \
 	arm-tdep.o arm-wince-tdep.o \
 	avr-tdep.o \
@@ -1660,8 +1661,9 @@ ALLDEPFILES = \
 	amd64-dicos-tdep.c \
 	amd64-linux-nat.c amd64-linux-tdep.c \
 	amd64-sol2-tdep.c \
-	arm.c \
-	arm-linux-nat.c arm-linux-tdep.c arm-symbian-tdep.c arm-tdep.c \
+	arm.c arm-get-next-pcs.c \
+	arm-linux-nat.c arm-linux-tdep.c \
+	arm-symbian-tdep.c arm-tdep.c \
 	armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c \
 	avr-tdep.c \
 	bfin-linux-tdep.c bfin-tdep.c \
@@ -2286,6 +2288,10 @@ arm.o: ${srcdir}/arch/arm.c
 	$(COMPILE) $(srcdir)/arch/arm.c
 	$(POSTCOMPILE)
 
+arm-get-next-pcs.o: ${srcdir}/arch/arm-get-next-pcs.c
+	$(COMPILE) $(srcdir)/arch/arm-get-next-pcs.c
+	$(POSTCOMPILE)
+
 # gdb/nat/ dependencies
 #
 # Need to explicitly specify the compile rule as make will do nothing
diff --git a/gdb/arch/arm-get-next-pcs.c b/gdb/arch/arm-get-next-pcs.c
new file mode 100644
index 0000000..983752b
--- /dev/null
+++ b/gdb/arch/arm-get-next-pcs.c
@@ -0,0 +1,1223 @@
+/* Common code for ARM software single stepping support.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "vec.h"
+
+#include "arm.h"
+#include "arm-get-next-pcs.h"
+
+/* Advance the state of the IT block and return that state.  */
+
+static int
+thumb_advance_itstate (unsigned int itstate)
+{
+  /* Preserve IT[7:5], the first three bits of the condition.  Shift
+     the upcoming condition flags left by one bit.  */
+  itstate = (itstate & 0xe0) | ((itstate << 1) & 0x1f);
+
+  /* If we have finished the IT block, clear the state.  */
+  if ((itstate & 0x0f) == 0)
+    itstate = 0;
+
+  return itstate;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+int
+arm_instruction_changes_pc (uint32_t this_instr)
+{
+  if (bits (this_instr, 28, 31) == INST_NV)
+    /* Unconditional instructions.  */
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+	/* Branch with Link and change to Thumb.  */
+	return 1;
+      case 0xc:
+      case 0xd:
+      case 0xe:
+	/* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+	  error (_("Invalid update to pc in instruction"));
+	return 0;
+      default:
+	return 0;
+      }
+  else
+    switch (bits (this_instr, 25, 27))
+      {
+      case 0x0:
+	if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
+	  {
+	    /* Multiplies and extra load/stores.  */
+	    if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
+	      /* Neither multiplies nor extension load/stores are allowed
+		 to modify PC.  */
+	      return 0;
+
+	    /* Otherwise, miscellaneous instructions.  */
+
+	    /* BX <reg>, BXJ <reg>, BLX <reg> */
+	    if (bits (this_instr, 4, 27) == 0x12fff1
+		|| bits (this_instr, 4, 27) == 0x12fff2
+		|| bits (this_instr, 4, 27) == 0x12fff3)
+	      return 1;
+
+	    /* Other miscellaneous instructions are unpredictable if they
+	       modify PC.  */
+	    return 0;
+	  }
+	/* Data processing instruction.  Fall through.  */
+
+      case 0x1:
+	if (bits (this_instr, 12, 15) == 15)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x2:
+      case 0x3:
+	/* Media instructions and architecturally undefined instructions.  */
+	if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
+	  return 0;
+
+	/* Stores.  */
+	if (bit (this_instr, 20) == 0)
+	  return 0;
+
+	/* Loads.  */
+	if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x4:
+	/* Load/store multiple.  */
+	if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
+	  return 1;
+	else
+	  return 0;
+
+      case 0x5:
+	/* Branch and branch with link.  */
+	return 1;
+
+      case 0x6:
+      case 0x7:
+	/* Coprocessor transfers or SWIs can not affect PC.  */
+	return 0;
+
+      default:
+	internal_error (__FILE__, __LINE__, _("bad value in switch"));
+      }
+}
+
+/* See arm-get-next-pcs.h.  */
+
+int
+thumb_instruction_changes_pc (unsigned short inst)
+{
+  if ((inst & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
+    return 1;
+
+  if ((inst & 0xf000) == 0xd000)	/* conditional branch */
+    return 1;
+
+  if ((inst & 0xf800) == 0xe000)	/* unconditional branch */
+    return 1;
+
+  if ((inst & 0xff00) == 0x4700)	/* bx REG, blx REG */
+    return 1;
+
+  if ((inst & 0xff87) == 0x4687)	/* mov pc, REG */
+    return 1;
+
+  if ((inst & 0xf500) == 0xb100)	/* CBNZ or CBZ.  */
+    return 1;
+
+  return 0;
+}
+
+
+/* See arm-get-next-pcs.h.  */
+
+int
+thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
+{
+  if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+    {
+      /* Branches and miscellaneous control instructions.  */
+
+      if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+	{
+	  /* B, BL, BLX.  */
+	  return 1;
+	}
+      else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+	{
+	  /* SUBS PC, LR, #imm8.  */
+	  return 1;
+	}
+      else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+	{
+	  /* Conditional branch.  */
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfe50) == 0xe810)
+    {
+      /* Load multiple or RFE.  */
+
+      if (bit (inst1, 7) && !bit (inst1, 8))
+	{
+	  /* LDMIA or POP */
+	  if (bit (inst2, 15))
+	    return 1;
+	}
+      else if (!bit (inst1, 7) && bit (inst1, 8))
+	{
+	  /* LDMDB */
+	  if (bit (inst2, 15))
+	    return 1;
+	}
+      else if (bit (inst1, 7) && bit (inst1, 8))
+	{
+	  /* RFEIA */
+	  return 1;
+	}
+      else if (!bit (inst1, 7) && !bit (inst1, 8))
+	{
+	  /* RFEDB */
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+    {
+      /* MOV PC or MOVS PC.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+    {
+      /* LDR PC.  */
+      if (bits (inst1, 0, 3) == 15)
+	return 1;
+      if (bit (inst1, 7))
+	return 1;
+      if (bit (inst2, 11))
+	return 1;
+      if ((inst2 & 0x0fc0) == 0x0000)
+	return 1;
+
+      return 0;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+    {
+      /* TBB.  */
+      return 1;
+    }
+
+  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+    {
+      /* TBH.  */
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
+   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
+   is found, attempt to step through it.  The end of the sequence address is
+   added to the next_pcs list.  */
+
+static int
+thumb_deal_with_atomic_sequence_raw (struct arm_get_next_pcs* next_pcs)
+{
+  int byte_order_for_code = next_pcs->byte_order_for_code;
+  CORE_ADDR pc = next_pcs->base.pc;
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  unsigned short insn1, insn2;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  ULONGEST status, itstate;
+
+  /* We currently do not support atomic sequences within an IT block.  */
+  status = next_pcs->ops->collect_register_unsigned
+    (&next_pcs->base, ARM_PS_REGNUM);
+  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+  if (itstate & 0x0f)
+    return 0;
+
+  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.  */
+  insn1 = next_pcs->ops->read_memory_unsigned_integer
+    (loc, 2, byte_order_for_code);
+  loc += 2;
+  if (thumb_insn_size (insn1) != 4)
+    return 0;
+
+  insn2 = next_pcs->ops->read_memory_unsigned_integer
+    (loc, 2, byte_order_for_code);
+  loc += 2;
+  if (!((insn1 & 0xfff0) == 0xe850
+        || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      insn1 = next_pcs->ops->read_memory_unsigned_integer
+	(loc, 2, byte_order_for_code);
+      loc += 2;
+
+      if (thumb_insn_size (insn1) != 4)
+	{
+	  /* Assume that there is at most one conditional branch in the
+	     atomic sequence.  If a conditional branch is found, put a
+	     breakpoint in its destination address.  */
+	  if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
+	    {
+	      if (last_breakpoint > 0)
+		return 0; /* More than one conditional branch found,
+			     fallback to the standard code.  */
+
+	      breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
+	      last_breakpoint++;
+	    }
+
+	  /* We do not support atomic sequences that use any *other*
+	     instructions but conditional branches to change the PC.
+	     Fall back to standard code to avoid losing control of
+	     execution.  */
+	  else if (thumb_instruction_changes_pc (insn1))
+	    return 0;
+	}
+      else
+	{
+	  insn2 = next_pcs->ops->read_memory_unsigned_integer
+	    (loc, 2, byte_order_for_code);
+	  loc += 2;
+
+	  /* Assume that there is at most one conditional branch in the
+	     atomic sequence.  If a conditional branch is found, put a
+	     breakpoint in its destination address.  */
+	  if ((insn1 & 0xf800) == 0xf000
+	      && (insn2 & 0xd000) == 0x8000
+	      && (insn1 & 0x0380) != 0x0380)
+	    {
+	      int sign, j1, j2, imm1, imm2;
+	      unsigned int offset;
+
+	      sign = sbits (insn1, 10, 10);
+	      imm1 = bits (insn1, 0, 5);
+	      imm2 = bits (insn2, 0, 10);
+	      j1 = bit (insn2, 13);
+	      j2 = bit (insn2, 11);
+
+	      offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+	      offset += (imm1 << 12) + (imm2 << 1);
+
+	      if (last_breakpoint > 0)
+		return 0; /* More than one conditional branch found,
+			     fallback to the standard code.  */
+
+	      breaks[1] = loc + offset;
+	      last_breakpoint++;
+	    }
+
+	  /* We do not support atomic sequences that use any *other*
+	     instructions but conditional branches to change the PC.
+	     Fall back to standard code to avoid losing control of
+	     execution.  */
+	  else if (thumb2_instruction_changes_pc (insn1, insn2))
+	    return 0;
+
+	  /* If we find a strex{,b,h,d}, we're done.  */
+	  if ((insn1 & 0xfff0) == 0xe840
+	      || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040))
+	    break;
+	}
+    }
+
+  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
+  if (insn_count == atomic_sequence_length)
+    return 0;
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) anywhere in sequence.  */
+  if (last_breakpoint
+      && (breaks[1] == breaks[0]
+	  || (breaks[1] >= pc && breaks[1] < loc)))
+    last_breakpoint = 0;
+
+  /* Adds the breakpoints to the list to be inserted.  */
+  for (index = 0; index <= last_breakpoint; index++) {
+    VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+		   MAKE_THUMB_ADDR (breaks[index]));
+  }
+
+  return 1;
+}
+
+/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
+   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
+   is found, attempt to step through it.  The end of the sequence address is
+   added to the next_pcs list.  */
+
+static int
+arm_deal_with_atomic_sequence_raw (struct arm_get_next_pcs* next_pcs)
+{
+  int byte_order_for_code = next_pcs->byte_order_for_code;
+  CORE_ADDR pc = next_pcs->base.pc;
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  unsigned int insn;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+
+  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
+     Note that we do not currently support conditionally executed atomic
+     instructions.  */
+  insn = next_pcs->ops->read_memory_unsigned_integer
+    (loc, 4, byte_order_for_code);
+  loc += 4;
+  if ((insn & 0xff9000f0) != 0xe1900090)
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      insn = next_pcs->ops->read_memory_unsigned_integer
+	(loc, 4, byte_order_for_code);
+      loc += 4;
+
+      /* Assume that there is at most one conditional branch in the atomic
+         sequence.  If a conditional branch is found, put a breakpoint in
+         its destination address.  */
+      if (bits (insn, 24, 27) == 0xa)
+	{
+          if (last_breakpoint > 0)
+            return 0; /* More than one conditional branch found, fallback
+                         to the standard single-step code.  */
+
+	  breaks[1] = BranchDest (loc - 4, insn);
+	  last_breakpoint++;
+        }
+
+      /* We do not support atomic sequences that use any *other* instructions
+         but conditional branches to change the PC.  Fall back to standard
+	 code to avoid losing control of execution.  */
+      else if (arm_instruction_changes_pc (insn))
+	return 0;
+
+      /* If we find a strex{,b,h,d}, we're done.  */
+      if ((insn & 0xff9000f0) == 0xe1800090)
+	break;
+    }
+
+  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
+  if (insn_count == atomic_sequence_length)
+    return 0;
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) anywhere in sequence.  */
+  if (last_breakpoint
+      && (breaks[1] == breaks[0]
+	  || (breaks[1] >= pc && breaks[1] < loc)))
+    last_breakpoint = 0;
+
+  /* Adds the breakpoints to the list to be inserted.  */
+  for (index = 0; index <= last_breakpoint; index++) {
+    VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+		   breaks[index]);
+  }
+
+  return 1;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+void
+arm_get_next_pcs (struct arm_get_next_pcs *next_pcs)
+{
+  if (next_pcs->is_thumb) {
+    if (!thumb_deal_with_atomic_sequence_raw (next_pcs))
+	thumb_get_next_pcs_raw (next_pcs);
+  }
+  else {
+    if (!arm_deal_with_atomic_sequence_raw (next_pcs))
+      arm_get_next_pcs_raw (next_pcs);
+  }
+}
+
+/* Decode shifted register value.  */
+
+static unsigned long
+shifted_reg_val (struct arm_get_next_pcs* next_pcs, unsigned long inst,
+		 int carry, unsigned long pc_val, unsigned long status_reg)
+{
+  unsigned long res, shift;
+  int rm = bits (inst, 0, 3);
+  unsigned long shifttype = bits (inst, 5, 6);
+
+  if (bit (inst, 4))
+    {
+      int rs = bits (inst, 8, 11);
+      shift = (rs == 15 ? pc_val + 8
+			: next_pcs->ops->collect_register_unsigned
+	       ((struct get_next_pcs*) next_pcs, rs)) & 0xFF;
+    }
+  else
+    shift = bits (inst, 7, 11);
+
+  res = (rm == ARM_PC_REGNUM
+	 ? (pc_val + (bit (inst, 4) ? 12 : 8))
+	 : next_pcs->ops->collect_register_unsigned
+	 ((struct get_next_pcs*) next_pcs, rm));
+
+  switch (shifttype)
+    {
+    case 0:			/* LSL */
+      res = shift >= 32 ? 0 : res << shift;
+      break;
+
+    case 1:			/* LSR */
+      res = shift >= 32 ? 0 : res >> shift;
+      break;
+
+    case 2:			/* ASR */
+      if (shift >= 32)
+	shift = 31;
+      res = ((res & 0x80000000L)
+	     ? ~((~res) >> shift) : res >> shift);
+      break;
+
+    case 3:			/* ROR/RRX */
+      shift &= 31;
+      if (shift == 0)
+	res = (res >> 1) | (carry ? 0x80000000L : 0);
+      else
+	res = (res >> shift) | (res << (32 - shift));
+      break;
+    }
+
+  return res & 0xffffffff;
+}
+
+/* See arm-get-next-pcs.h.  */
+
+void
+thumb_get_next_pcs_raw (struct arm_get_next_pcs* next_pcs)
+{
+  int byte_order = next_pcs->byte_order;
+  int byte_order_for_code = next_pcs->byte_order_for_code;
+  CORE_ADDR pc = next_pcs->base.pc;
+  unsigned long pc_val = ((unsigned long) pc) + 4;	/* PC after prefetch */
+  unsigned short inst1;
+  CORE_ADDR nextpc = pc + 2;		/* Default is next instruction.  */
+  unsigned long offset;
+  ULONGEST status, itstate;
+
+  nextpc = MAKE_THUMB_ADDR (nextpc);
+  pc_val = MAKE_THUMB_ADDR (pc_val);
+
+  inst1 =
+    next_pcs->ops->read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+
+  /* Thumb-2 conditional execution support.  There are eight bits in
+     the CPSR which describe conditional execution state.  Once
+     reconstructed (they're in a funny order), the low five bits
+     describe the low bit of the condition for each instruction and
+     how many instructions remain.  The high three bits describe the
+     base condition.  One of the low four bits will be set if an IT
+     block is active.  These bits read as zero on earlier
+     processors.  */
+  status = next_pcs->ops->collect_register_unsigned
+    ((struct get_next_pcs*) next_pcs, ARM_PS_REGNUM);
+  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
+
+  /* If-Then handling.  On GNU/Linux, where this routine is used, we
+     use an undefined instruction as a breakpoint.  Unlike BKPT, IT
+     can disable execution of the undefined instruction.  So we might
+     miss the breakpoint if we set it on a skipped conditional
+     instruction.  Because conditional instructions can change the
+     flags, affecting the execution of further instructions, we may
+     need to set two breakpoints.  */
+
+  if (next_pcs->arm_linux_thumb2_breakpoint != NULL)
+    {
+      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
+	{
+	  /* An IT instruction.  Because this instruction does not
+	     modify the flags, we can accurately predict the next
+	     executed instruction.  */
+	  itstate = inst1 & 0x00ff;
+	  pc += thumb_insn_size (inst1);
+
+	  while (itstate != 0 && ! condition_true (itstate >> 4, status))
+	    {
+	      inst1 = next_pcs->ops->read_memory_unsigned_integer
+		(pc, 2, byte_order_for_code);
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+	    }
+
+	  VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+			 MAKE_THUMB_ADDR (pc));
+	  return;
+	}
+      else if (itstate != 0)
+	{
+	  /* We are in a conditional block.  Check the condition.  */
+	  if (! condition_true (itstate >> 4, status))
+	    {
+	      /* Advance to the next executed instruction.  */
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+
+	      while (itstate != 0 && ! condition_true (itstate >> 4, status))
+		{
+		  inst1 = next_pcs->ops->read_memory_unsigned_integer
+		    (pc, 2, byte_order_for_code);
+
+		  pc += thumb_insn_size (inst1);
+		  itstate = thumb_advance_itstate (itstate);
+		}
+
+	      VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+			     MAKE_THUMB_ADDR (pc));
+	      return;
+	    }
+	  else if ((itstate & 0x0f) == 0x08)
+	    {
+	      /* This is the last instruction of the conditional
+		 block, and it is executed.  We can handle it normally
+		 because the following instruction is not conditional,
+		 and we must handle it normally because it is
+		 permitted to branch.  Fall through.  */
+	    }
+	  else
+	    {
+	      int cond_negated;
+
+	      /* There are conditional instructions after this one.
+		 If this instruction modifies the flags, then we can
+		 not predict what the next executed instruction will
+		 be.  Fortunately, this instruction is architecturally
+		 forbidden to branch; we know it will fall through.
+		 Start by skipping past it.  */
+	      pc += thumb_insn_size (inst1);
+	      itstate = thumb_advance_itstate (itstate);
+
+	      /* Set a breakpoint on the following instruction.  */
+	      gdb_assert ((itstate & 0x0f) != 0);
+	      VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+			 MAKE_THUMB_ADDR (pc));
+
+	      cond_negated = (itstate >> 4) & 1;
+
+	      /* Skip all following instructions with the same
+		 condition.  If there is a later instruction in the IT
+		 block with the opposite condition, set the other
+		 breakpoint there.  If not, then set a breakpoint on
+		 the instruction after the IT block.  */
+	      do
+		{
+		  inst1 = next_pcs->ops->read_memory_unsigned_integer
+		    (pc, 2, byte_order_for_code);
+
+		  pc += thumb_insn_size (inst1);
+		  itstate = thumb_advance_itstate (itstate);
+		}
+	      while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
+
+	      VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+			 MAKE_THUMB_ADDR (pc));
+
+	      return;
+	    }
+	}
+    }
+  else if (itstate & 0x0f)
+    {
+      /* We are in a conditional block.  Check the condition.  */
+      int cond = itstate >> 4;
+
+      if (! condition_true (cond, status))
+	/* Advance to the next instruction.  All the 32-bit
+	   instructions share a common prefix.  */
+
+	VEC_safe_push (CORE_ADDR, next_pcs->base.result,
+		       MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));
+
+	return;
+
+      /* Otherwise, handle the instruction normally.  */
+    }
+
+  if ((inst1 & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
+    {
+      CORE_ADDR sp;
+
+      /* Fetch the saved PC from the stack.  It's stored above
+         all of the other registers.  */
+      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
+
+      sp = next_pcs->ops->collect_register_unsigned
+	((struct get_next_pcs*) next_pcs, ARM_SP_REGNUM);
+
+      nextpc = next_pcs->ops->read_memory_unsigned_integer
+	(sp + offset, 4, byte_order);
+    }
+  else if ((inst1 & 0xf000) == 0xd000)	/* conditional branch */
+    {
+      unsigned long cond = bits (inst1, 8, 11);
+      if (cond == 0x0f)  /* 0x0f = SWI */
+	{
+	  nextpc = next_pcs->ops->syscall_next_pc (next_pcs);
+	}
+      else if (cond != 0x0f && condition_true (cond, status))
+	nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
+    }
+  else if ((inst1 & 0xf800) == 0xe000)	/* unconditional branch */
+    {
+      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
+    }
+  else if (thumb_insn_size (inst1) == 4) /* 32-bit instruction */
+    {
+      unsigned short inst2;
+      inst2 = next_pcs->ops->read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
+
+      /* Default to the next instruction.  */
+      nextpc = pc + 4;
+      nextpc = MAKE_THUMB_ADDR (nextpc);
+
+      if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
+	{
+	  /* Branches and miscellaneous control instructions.  */
+
+	  if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
+	    {
+	      /* B, BL, BLX.  */
+	      int j1, j2, imm1, imm2;
+
+	      imm1 = sbits (inst1, 0, 10);
+	      imm2 = bits (inst2, 0, 10);
+	      j1 = bit (inst2, 13);
+	      j2 = bit (inst2, 11);
+
+	      offset = ((imm1 << 12) + (imm2 << 1));
+	      offset ^= ((!j2) << 22) | ((!j1) << 23);
+
+	      nextpc = pc_val + offset;
+	      /* For BLX make sure to clear the low bits.  */
+	      if (bit (inst2, 12) == 0)
+		nextpc = nextpc & 0xfffffffc;
+	    }
+	  else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
+	    {
+	      /* SUBS PC, LR, #imm8.  */
+	      nextpc = next_pcs->ops->collect_register_unsigned
+		((struct get_next_pcs*) next_pcs, ARM_LR_REGNUM);
+	      nextpc -= inst2 & 0x00ff;
+	    }
+	  else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
+	    {
+	      /* Conditional branch.  */
+	      if (condition_true (bits (inst1, 6, 9), status))
+		{
+		  int sign, j1, j2, imm1, imm2;
+
+		  sign = sbits (inst1, 10, 10);
+		  imm1 = bits (inst1, 0, 5);
+		  imm2 = bits (inst2, 0, 10);
+		  j1 = bit (inst2, 13);
+		  j2 = bit (inst2, 11);
+
+		  offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+		  offset += (imm1 << 12) + (imm2 << 1);
+
+		  nextpc = pc_val + offset;
+		}
+	    }
+	}
+      else if ((inst1 & 0xfe50) == 0xe810)
+	{
+	  /* Load multiple or RFE.  */
+	  int rn, offset, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  if (bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* LDMIA or POP */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = bitcount (inst2) * 4 - 4;
+	    }
+	  else if (!bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* LDMDB */
+	      if (!bit (inst2, 15))
+		load_pc = 0;
+	      offset = -4;
+	    }
+	  else if (bit (inst1, 7) && bit (inst1, 8))
+	    {
+	      /* RFEIA */
+	      offset = 0;
+	    }
+	  else if (!bit (inst1, 7) && !bit (inst1, 8))
+	    {
+	      /* RFEDB */
+	      offset = -8;
+	    }
+	  else
+	    load_pc = 0;
+
+	  if (load_pc)
+	    {
+	      CORE_ADDR addr = next_pcs->ops->collect_register_unsigned
+		((struct get_next_pcs*) next_pcs, rn);
+	      nextpc = next_pcs->ops->read_memory_unsigned_integer
+		(addr + offset, 4, byte_order);
+	    }
+	}
+      else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
+	{
+	  /* MOV PC or MOVS PC.  */
+	  nextpc = next_pcs->ops->collect_register_unsigned
+		((struct get_next_pcs*) next_pcs, bits (inst2, 0, 3));
+	  nextpc = MAKE_THUMB_ADDR (nextpc);
+	}
+      else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
+	{
+	  /* LDR PC.  */
+	  CORE_ADDR base;
+	  int rn, load_pc = 1;
+
+	  rn = bits (inst1, 0, 3);
+	  base = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, rn);
+	  if (rn == ARM_PC_REGNUM)
+	    {
+	      base = (base + 4) & ~(CORE_ADDR) 0x3;
+	      if (bit (inst1, 7))
+		base += bits (inst2, 0, 11);
+	      else
+		base -= bits (inst2, 0, 11);
+	    }
+	  else if (bit (inst1, 7))
+	    base += bits (inst2, 0, 11);
+	  else if (bit (inst2, 11))
+	    {
+	      if (bit (inst2, 10))
+		{
+		  if (bit (inst2, 9))
+		    base += bits (inst2, 0, 7);
+		  else
+		    base -= bits (inst2, 0, 7);
+		}
+	    }
+	  else if ((inst2 & 0x0fc0) == 0x0000)
+	    {
+	      int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
+	      base += next_pcs->ops->collect_register_unsigned
+		((struct get_next_pcs*) next_pcs, rm) << shift;
+	    }
+	  else
+	    /* Reserved.  */
+	    load_pc = 0;
+
+	  if (load_pc)
+	    nextpc = next_pcs->ops->read_memory_unsigned_integer
+	      (base, 4, byte_order);
+
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
+	{
+	  /* TBB.  */
+	  CORE_ADDR tbl_reg, table, offset, length;
+
+	  tbl_reg = bits (inst1, 0, 3);
+	  if (tbl_reg == 0x0f)
+	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+	  else
+	    table = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, tbl_reg);
+
+	  offset = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs,bits (inst2, 0, 3));
+	  length = 2 * next_pcs->ops->read_memory_unsigned_integer
+	    (table + offset, 1, byte_order);
+	  nextpc = pc_val + length;
+	}
+      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
+	{
+	  /* TBH.  */
+	  CORE_ADDR tbl_reg, table, offset, length;
+
+	  tbl_reg = bits (inst1, 0, 3);
+	  if (tbl_reg == 0x0f)
+	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
+	  else
+	    table = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, tbl_reg);
+
+	  offset = 2 * next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, bits (inst2, 0, 3));
+	  length = 2 * next_pcs->ops->read_memory_unsigned_integer
+	    (table + offset, 2, byte_order);
+	  nextpc = pc_val + length;
+	}
+    }
+  else if ((inst1 & 0xff00) == 0x4700)	/* bx REG, blx REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+	nextpc = UNMAKE_THUMB_ADDR (pc_val);
+      else
+	nextpc = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, bits (inst1, 3, 6));
+    }
+  else if ((inst1 & 0xff87) == 0x4687)	/* mov pc, REG */
+    {
+      if (bits (inst1, 3, 6) == 0x0f)
+	nextpc = pc_val;
+      else
+	nextpc = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, bits (inst1, 3, 6));
+
+      nextpc = MAKE_THUMB_ADDR (nextpc);
+    }
+  else if ((inst1 & 0xf500) == 0xb100)
+    {
+      /* CBNZ or CBZ.  */
+      int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
+      ULONGEST reg = next_pcs->ops->collect_register_unsigned
+	((struct get_next_pcs*) next_pcs, bits (inst1, 0, 2));
+
+      if (bit (inst1, 11) && reg != 0)
+	nextpc = pc_val + imm;
+      else if (!bit (inst1, 11) && reg == 0)
+	nextpc = pc_val + imm;
+    }
+
+  VEC_safe_push (CORE_ADDR, next_pcs->base.result, nextpc);
+  return;
+}
+
+
+/* Get the raw next possible addresses.  PC in next_pcs is the current program
+   counter, which is assumed to be executing in ARM mode.
+
+   The values returned have the execution state of the next instruction
+   encoded in it.  Use IS_THUMB_ADDR () to see whether the instruction is
+   in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
+   address in GDB and arm_addr_bits_remove in GDBServer.  */
+
+void
+arm_get_next_pcs_raw (struct arm_get_next_pcs *next_pcs)
+{
+  int byte_order = next_pcs->byte_order;
+  CORE_ADDR pc = next_pcs->base.pc;
+  unsigned long pc_val;
+  unsigned long this_instr = 0;
+  unsigned long status;
+  CORE_ADDR nextpc;
+
+  pc_val = (unsigned long) pc;
+  this_instr =
+    next_pcs->ops->read_memory_unsigned_integer (pc, 4, byte_order);
+
+  status = next_pcs->ops->collect_register_unsigned
+    ((struct get_next_pcs*) next_pcs, ARM_PS_REGNUM);
+  nextpc = (CORE_ADDR) (pc_val + 4);	/* Default case */
+
+  if (bits (this_instr, 28, 31) == INST_NV)
+    switch (bits (this_instr, 24, 27))
+      {
+      case 0xa:
+      case 0xb:
+	{
+	  /* Branch with Link and change to Thumb.  */
+	  nextpc = BranchDest (pc, this_instr);
+	  nextpc |= bit (this_instr, 24) << 1;
+	  nextpc = MAKE_THUMB_ADDR (nextpc);
+	  break;
+	}
+      case 0xc:
+      case 0xd:
+      case 0xe:
+	/* Coprocessor register transfer.  */
+        if (bits (this_instr, 12, 15) == 15)
+	  error (_("Invalid update to pc in instruction"));
+	break;
+      }
+  else if (condition_true (bits (this_instr, 28, 31), status))
+    {
+      switch (bits (this_instr, 24, 27))
+	{
+	case 0x0:
+	case 0x1:			/* data processing */
+	case 0x2:
+	case 0x3:
+	  {
+	    unsigned long operand1, operand2, result = 0;
+	    unsigned long rn;
+	    int c;
+
+	    if (bits (this_instr, 12, 15) != 15)
+	      break;
+
+	    if (bits (this_instr, 22, 25) == 0
+		&& bits (this_instr, 4, 7) == 9)	/* multiply */
+	      error (_("Invalid update to pc in instruction"));
+
+	    /* BX <reg>, BLX <reg> */
+	    if (bits (this_instr, 4, 27) == 0x12fff1
+		|| bits (this_instr, 4, 27) == 0x12fff3)
+	      {
+		rn = bits (this_instr, 0, 3);
+		nextpc = ((rn == ARM_PC_REGNUM)
+			  ? (pc_val + 8)
+			  : next_pcs->ops->collect_register_unsigned
+			  ((struct get_next_pcs*) next_pcs, rn));
+
+		VEC_safe_push (CORE_ADDR, next_pcs->base.result, nextpc);
+		return;
+	      }
+
+	    /* Multiply into PC.  */
+	    c = (status & FLAG_C) ? 1 : 0;
+	    rn = bits (this_instr, 16, 19);
+	    operand1 = ((rn == ARM_PC_REGNUM)
+			? (pc_val + 8)
+			: next_pcs->ops->collect_register_unsigned
+			((struct get_next_pcs*) next_pcs, rn));
+
+	    if (bit (this_instr, 25))
+	      {
+		unsigned long immval = bits (this_instr, 0, 7);
+		unsigned long rotate = 2 * bits (this_instr, 8, 11);
+		operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
+		  & 0xffffffff;
+	      }
+	    else		/* operand 2 is a shifted register.  */
+	      operand2 = shifted_reg_val (next_pcs, this_instr, c,
+					  pc_val, status);
+
+	    switch (bits (this_instr, 21, 24))
+	      {
+	      case 0x0:	/*and */
+		result = operand1 & operand2;
+		break;
+
+	      case 0x1:	/*eor */
+		result = operand1 ^ operand2;
+		break;
+
+	      case 0x2:	/*sub */
+		result = operand1 - operand2;
+		break;
+
+	      case 0x3:	/*rsb */
+		result = operand2 - operand1;
+		break;
+
+	      case 0x4:	/*add */
+		result = operand1 + operand2;
+		break;
+
+	      case 0x5:	/*adc */
+		result = operand1 + operand2 + c;
+		break;
+
+	      case 0x6:	/*sbc */
+		result = operand1 - operand2 + c;
+		break;
+
+	      case 0x7:	/*rsc */
+		result = operand2 - operand1 + c;
+		break;
+
+	      case 0x8:
+	      case 0x9:
+	      case 0xa:
+	      case 0xb:	/* tst, teq, cmp, cmn */
+		result = (unsigned long) nextpc;
+		break;
+
+	      case 0xc:	/*orr */
+		result = operand1 | operand2;
+		break;
+
+	      case 0xd:	/*mov */
+		/* Always step into a function.  */
+		result = operand2;
+		break;
+
+	      case 0xe:	/*bic */
+		result = operand1 & ~operand2;
+		break;
+
+	      case 0xf:	/*mvn */
+		result = ~operand2;
+		break;
+	      }
+
+            /* In 26-bit APCS the bottom two bits of the result are
+	       ignored, and we always end up in ARM state.  */
+	    if (!next_pcs->arm_apcs_32)
+	      nextpc = next_pcs->ops->addr_bits_remove (next_pcs, result);
+	      else
+	      nextpc = result;
+	    break;
+	  }
+
+	case 0x4:
+	case 0x5:		/* data transfer */
+	case 0x6:
+	case 0x7:
+	  if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
+	    {
+	      /* Media instructions and architecturally undefined
+		 instructions.  */
+	      break;
+	    }
+	  if (bit (this_instr, 20))
+	    {
+	      /* load */
+	      if (bits (this_instr, 12, 15) == 15)
+		{
+		  /* rd == pc */
+		  unsigned long rn;
+		  unsigned long base;
+
+		  if (bit (this_instr, 22))
+		    error (_("Invalid update to pc in instruction"));
+
+		  /* byte write to PC */
+		  rn = bits (this_instr, 16, 19);
+		  base = ((rn == ARM_PC_REGNUM)
+			  ? (pc_val + 8)
+			  : next_pcs->ops->collect_register_unsigned
+			  ((struct get_next_pcs*) next_pcs, rn));
+
+		  if (bit (this_instr, 24))
+		    {
+		      /* pre-indexed */
+		      int c = (status & FLAG_C) ? 1 : 0;
+		      unsigned long offset =
+		      (bit (this_instr, 25)
+		       ? shifted_reg_val (next_pcs, this_instr, c,
+					  pc_val, status)
+		       : bits (this_instr, 0, 11));
+
+		      if (bit (this_instr, 23))
+			base += offset;
+		      else
+			base -= offset;
+		    }
+		  nextpc =
+		    (CORE_ADDR) next_pcs->ops->read_memory_unsigned_integer
+		    ((CORE_ADDR) base, 4, byte_order);
+		}
+	    }
+	  break;
+
+	case 0x8:
+	case 0x9:		/* block transfer */
+	  if (bit (this_instr, 20))
+	    {
+	      /* LDM */
+	      if (bit (this_instr, 15))
+		{
+		  /* loading pc */
+		  int offset = 0;
+		  unsigned long rn_val
+		    = next_pcs->ops->collect_register_unsigned
+		    ((struct get_next_pcs*) next_pcs,bits (this_instr, 16, 19));
+
+		  if (bit (this_instr, 23))
+		    {
+		      /* up */
+		      unsigned long reglist = bits (this_instr, 0, 14);
+		      offset = bitcount (reglist) * 4;
+		      if (bit (this_instr, 24))		/* pre */
+			offset += 4;
+		    }
+		  else if (bit (this_instr, 24))
+		    offset = -4;
+
+		  nextpc =
+		    (CORE_ADDR) next_pcs->ops->
+		    read_memory_unsigned_integer ((CORE_ADDR) (rn_val + offset),
+						  4, byte_order);
+		}
+	    }
+	  break;
+
+	case 0xb:		/* branch & link */
+	case 0xa:		/* branch */
+	  {
+	    nextpc = BranchDest (pc, this_instr);
+	    break;
+	  }
+
+	case 0xc:
+	case 0xd:
+	case 0xe:		/* coproc ops */
+	  break;
+	case 0xf:		/* SWI */
+	  {
+	    nextpc = next_pcs->ops->syscall_next_pc (next_pcs);
+	  }
+	  break;
+
+	default:
+	  error (_("Bad bit-field extraction\n"));
+	  return;
+	}
+    }
+
+  VEC_safe_push (CORE_ADDR, next_pcs->base.result, nextpc);
+  return;
+}
diff --git a/gdb/arch/arm-get-next-pcs.h b/gdb/arch/arm-get-next-pcs.h
new file mode 100644
index 0000000..2b127ed
--- /dev/null
+++ b/gdb/arch/arm-get-next-pcs.h
@@ -0,0 +1,100 @@
+/* Common code for ARM software single stepping support.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARM_GET_NEXT_PCS_H
+#define ARM_GET_NEXT_PCS_H 1
+
+#include "get-next-pcs.h"
+
+/* Support routines for instruction parsing.  */
+#define submask(x) ((1L << ((x) + 1)) - 1)
+#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
+#define bit(obj,st) (((obj) >> (st)) & 1)
+#define sbits(obj,st,fn) \
+  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
+#define BranchDest(addr,instr) \
+  ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
+
+
+/* Forward declaration.  */
+struct arm_get_next_pcs;
+
+/* get_next_pcs operations.  */
+struct arm_get_next_pcs_ops
+{
+  ULONGEST (*read_memory_unsigned_integer) (CORE_ADDR memaddr, int len,
+					    int byte_order);
+  ULONGEST (*collect_register_unsigned) (struct get_next_pcs* self, int n);
+  CORE_ADDR (*syscall_next_pc) (struct arm_get_next_pcs* next_pcs);
+  CORE_ADDR (*addr_bits_remove) (struct arm_get_next_pcs *next_pcs,
+				 CORE_ADDR val);
+};
+
+/* Context for a get_next_pcs call on ARM.  */
+struct arm_get_next_pcs
+{
+  struct get_next_pcs base;
+  struct arm_get_next_pcs_ops *ops;
+  int byte_order;
+  int byte_order_for_code;
+  int is_thumb;
+  int arm_apcs_32;
+  const gdb_byte *arm_linux_thumb2_breakpoint;
+};
+
+/* Context for a get_next_pcs call on ARM in GDB.  */
+struct arm_gdb_get_next_pcs
+{
+  struct arm_get_next_pcs base;
+  struct frame_info *frame;
+  struct gdbarch *gdbarch;
+};
+
+/* Context for a get_next_pcs call on ARM in GDBServer.  */
+struct arm_gdbserver_get_next_pcs
+{
+  struct arm_get_next_pcs base;
+};
+
+/* Find the next possible PCs after the current instruction executes.  */
+void arm_get_next_pcs (struct arm_get_next_pcs *next_pcs);
+
+/* Find the next possible PCs for thumb mode.  */
+void thumb_get_next_pcs_raw (struct arm_get_next_pcs *next_pcs);
+
+/* Find the next possible PCs for arm mode.  */
+void arm_get_next_pcs_raw (struct arm_get_next_pcs *next_pcs);
+
+/*  Checks for an atomic sequence of instructions and add the end of the
+    sequence to the next_pcs list.  */
+int arm_deal_with_atomic_sequence (struct arm_get_next_pcs *next_pcs);
+
+/* Return 1 if THIS_INSTR might change control flow, 0 otherwise.  */
+int arm_instruction_changes_pc (uint32_t this_instr);
+
+/* Return 1 if the 16-bit Thumb instruction INST might change
+   control flow, 0 otherwise.  */
+int thumb_instruction_changes_pc (unsigned short inst);
+
+/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
+   might change control flow, 0 otherwise.  */
+int thumb2_instruction_changes_pc
+(unsigned short inst1, unsigned short inst2);
+
+#endif /* ARM_GET_NEXT_PCS_H */
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index a63b181..02021c5 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -27,6 +27,8 @@
 #include "observer.h"
 #include "gdbthread.h"
 
+#include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 #include "aarch32-linux-nat.h"
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index dc0a8a9..1522c9d 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -35,6 +35,8 @@
 #include "auxv.h"
 #include "xml-syscall.h"
 
+#include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "arm-linux-tdep.h"
 #include "linux-tdep.h"
@@ -257,6 +259,14 @@ static const gdb_byte arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa
 #define ARM_LDR_PC_SP_12		0xe49df00c
 #define ARM_LDR_PC_SP_4			0xe49df004
 
+/* Operation function pointers for get_next_pcs.  */
+static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
+  arm_get_next_pcs_read_memory_unsigned_integer,
+  arm_get_next_pcs_collect_register_unsigned,
+  arm_get_next_pcs_syscall_next_pc,
+  arm_get_next_pcs_addr_bits_remove
+};
+
 static void
 arm_linux_sigtramp_cache (struct frame_info *this_frame,
 			  struct trad_frame_cache *this_cache,
@@ -912,27 +922,46 @@ arm_linux_software_single_step (struct frame_info *frame)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   struct address_space *aspace = get_frame_address_space (frame);
-  CORE_ADDR next_pc;
-
-  if (arm_deal_with_atomic_sequence (frame))
-    return 1;
+  struct arm_gdb_get_next_pcs next_pcs;
+  CORE_ADDR pc;
+  int i;
 
   /* If the target does have hardware single step, GDB doesn't have
      to bother software single step.  */
   if (target_can_do_single_step () == 1)
     return 0;
 
-  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
-
-  /* The Linux kernel offers some user-mode helpers in a high page.  We can
-     not read this page (as of 2.6.23), and even if we could then we couldn't
-     set breakpoints in it, and even if we could then the atomic operations
-     would fail when interrupted.  They are all called as functions and return
-     to the address in LR, so step to there instead.  */
-  if (next_pc > 0xffff0000)
-    next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+  next_pcs.base.base.result = VEC_alloc (CORE_ADDR, 1);
+  next_pcs.gdbarch = gdbarch;
+  next_pcs.frame = frame;
+  next_pcs.base.ops = &arm_linux_get_next_pcs_ops;
+  next_pcs.base.byte_order = gdbarch_byte_order (gdbarch);
+  next_pcs.base.byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  next_pcs.base.is_thumb = arm_frame_is_thumb (frame);
+  next_pcs.base.arm_apcs_32 = arm_apcs_32;
+  next_pcs.base.base.pc = get_frame_pc (frame);
+  next_pcs.base.arm_linux_thumb2_breakpoint =
+    gdbarch_tdep (gdbarch)->thumb2_breakpoint;
+
+  arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs);
+
+  for (i = 0;
+       VEC_iterate (CORE_ADDR, next_pcs.base.base.result, i, pc);
+       ++i)
+    {
+       /* The Linux kernel offers some user-mode helpers in a high page.  We can
+	 not read this page (as of 2.6.23), and even if we could then we
+	 couldn't set breakpoints in it, and even if we could then the atomic
+	 operations would fail when interrupted.  They are all called as
+	 functions and return to the address in LR, so step to there
+	 instead.  */
+      if (pc > 0xffff0000)
+	pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+
+       arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    }
 
-  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
+  VEC_free (CORE_ADDR, next_pcs.base.base.result);
 
   return 1;
 }
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 3eaf63e..31956ec 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -46,6 +46,7 @@
 #include "observer.h"
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 #include "arm-tdep.h"
 #include "gdb/sim-arm.h"
 
@@ -236,6 +237,14 @@ static void arm_neon_quad_write (struct gdbarch *gdbarch,
 				 struct regcache *regcache,
 				 int regnum, const gdb_byte *buf);
 
+/* get_next_pcs operations.  */
+static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = {
+  arm_get_next_pcs_read_memory_unsigned_integer,
+  arm_get_next_pcs_collect_register_unsigned,
+  arm_get_next_pcs_syscall_next_pc,
+  arm_get_next_pcs_addr_bits_remove
+};
+
 struct arm_prologue_cache
 {
   /* The stack pointer at the time this frame was created; i.e. the
@@ -507,15 +516,6 @@ skip_prologue_function (struct gdbarch *gdbarch, CORE_ADDR pc, int is_thumb)
   return 0;
 }
 
-/* Support routines for instruction parsing.  */
-#define submask(x) ((1L << ((x) + 1)) - 1)
-#define bit(obj,st) (((obj) >> (st)) & 1)
-#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
-#define sbits(obj,st,fn) \
-  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
-#define BranchDest(addr,instr) \
-  ((CORE_ADDR) (((unsigned long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
-
 /* Extract the immediate from instruction movw/movt of encoding T.  INSN1 is
    the first 16-bit of instruction, and INSN2 is the second 16-bit of
    instruction.  */
@@ -555,128 +555,6 @@ thumb_expand_immediate (unsigned int imm)
   return (0x80 | (imm & 0x7f)) << (32 - count);
 }
 
-/* Return 1 if the 16-bit Thumb instruction INST might change
-   control flow, 0 otherwise.  */
-
-static int
-thumb_instruction_changes_pc (unsigned short inst)
-{
-  if ((inst & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
-    return 1;
-
-  if ((inst & 0xf000) == 0xd000)	/* conditional branch */
-    return 1;
-
-  if ((inst & 0xf800) == 0xe000)	/* unconditional branch */
-    return 1;
-
-  if ((inst & 0xff00) == 0x4700)	/* bx REG, blx REG */
-    return 1;
-
-  if ((inst & 0xff87) == 0x4687)	/* mov pc, REG */
-    return 1;
-
-  if ((inst & 0xf500) == 0xb100)	/* CBNZ or CBZ.  */
-    return 1;
-
-  return 0;
-}
-
-/* Return 1 if the 32-bit Thumb instruction in INST1 and INST2
-   might change control flow, 0 otherwise.  */
-
-static int
-thumb2_instruction_changes_pc (unsigned short inst1, unsigned short inst2)
-{
-  if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
-    {
-      /* Branches and miscellaneous control instructions.  */
-
-      if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
-	{
-	  /* B, BL, BLX.  */
-	  return 1;
-	}
-      else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
-	{
-	  /* SUBS PC, LR, #imm8.  */
-	  return 1;
-	}
-      else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
-	{
-	  /* Conditional branch.  */
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  if ((inst1 & 0xfe50) == 0xe810)
-    {
-      /* Load multiple or RFE.  */
-
-      if (bit (inst1, 7) && !bit (inst1, 8))
-	{
-	  /* LDMIA or POP */
-	  if (bit (inst2, 15))
-	    return 1;
-	}
-      else if (!bit (inst1, 7) && bit (inst1, 8))
-	{
-	  /* LDMDB */
-	  if (bit (inst2, 15))
-	    return 1;
-	}
-      else if (bit (inst1, 7) && bit (inst1, 8))
-	{
-	  /* RFEIA */
-	  return 1;
-	}
-      else if (!bit (inst1, 7) && !bit (inst1, 8))
-	{
-	  /* RFEDB */
-	  return 1;
-	}
-
-      return 0;
-    }
-
-  if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
-    {
-      /* MOV PC or MOVS PC.  */
-      return 1;
-    }
-
-  if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
-    {
-      /* LDR PC.  */
-      if (bits (inst1, 0, 3) == 15)
-	return 1;
-      if (bit (inst1, 7))
-	return 1;
-      if (bit (inst2, 11))
-	return 1;
-      if ((inst2 & 0x0fc0) == 0x0000)
-	return 1;	
-
-      return 0;
-    }
-
-  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
-    {
-      /* TBB.  */
-      return 1;
-    }
-
-  if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
-    {
-      /* TBH.  */
-      return 1;
-    }
-
-  return 0;
-}
-
 /* Return 1 if the 16-bit Thumb instruction INSN restores SP in
    epilogue, 0 otherwise.  */
 
@@ -1504,98 +1382,6 @@ thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
   thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
 }
 
-/* Return 1 if THIS_INSTR might change control flow, 0 otherwise.  */
-
-static int
-arm_instruction_changes_pc (uint32_t this_instr)
-{
-  if (bits (this_instr, 28, 31) == INST_NV)
-    /* Unconditional instructions.  */
-    switch (bits (this_instr, 24, 27))
-      {
-      case 0xa:
-      case 0xb:
-	/* Branch with Link and change to Thumb.  */
-	return 1;
-      case 0xc:
-      case 0xd:
-      case 0xe:
-	/* Coprocessor register transfer.  */
-        if (bits (this_instr, 12, 15) == 15)
-	  error (_("Invalid update to pc in instruction"));
-	return 0;
-      default:
-	return 0;
-      }
-  else
-    switch (bits (this_instr, 25, 27))
-      {
-      case 0x0:
-	if (bits (this_instr, 23, 24) == 2 && bit (this_instr, 20) == 0)
-	  {
-	    /* Multiplies and extra load/stores.  */
-	    if (bit (this_instr, 4) == 1 && bit (this_instr, 7) == 1)
-	      /* Neither multiplies nor extension load/stores are allowed
-		 to modify PC.  */
-	      return 0;
-
-	    /* Otherwise, miscellaneous instructions.  */
-
-	    /* BX <reg>, BXJ <reg>, BLX <reg> */
-	    if (bits (this_instr, 4, 27) == 0x12fff1
-		|| bits (this_instr, 4, 27) == 0x12fff2
-		|| bits (this_instr, 4, 27) == 0x12fff3)
-	      return 1;
-
-	    /* Other miscellaneous instructions are unpredictable if they
-	       modify PC.  */
-	    return 0;
-	  }
-	/* Data processing instruction.  Fall through.  */
-
-      case 0x1:
-	if (bits (this_instr, 12, 15) == 15)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x2:
-      case 0x3:
-	/* Media instructions and architecturally undefined instructions.  */
-	if (bits (this_instr, 25, 27) == 3 && bit (this_instr, 4) == 1)
-	  return 0;
-
-	/* Stores.  */
-	if (bit (this_instr, 20) == 0)
-	  return 0;
-
-	/* Loads.  */
-	if (bits (this_instr, 12, 15) == ARM_PC_REGNUM)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x4:
-	/* Load/store multiple.  */
-	if (bit (this_instr, 20) == 1 && bit (this_instr, 15) == 1)
-	  return 1;
-	else
-	  return 0;
-
-      case 0x5:
-	/* Branch and branch with link.  */
-	return 1;
-
-      case 0x6:
-      case 0x7:
-	/* Coprocessor transfers or SWIs can not affect PC.  */
-	return 0;
-
-      default:
-	internal_error (__FILE__, __LINE__, _("bad value in switch"));
-      }
-}
-
 /* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
    otherwise.  */
 
@@ -4252,1102 +4038,131 @@ convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
 			       &d, dbl);
 }
 
-static unsigned long
-shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
-		 unsigned long pc_val, unsigned long status_reg)
+/* Like insert_single_step_breakpoint, but make sure we use a breakpoint
+   of the appropriate mode (as encoded in the PC value), even if this
+   differs from what would be expected according to the symbol tables.  */
+
+void
+arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
+				   struct address_space *aspace,
+				   CORE_ADDR pc)
 {
-  unsigned long res, shift;
-  int rm = bits (inst, 0, 3);
-  unsigned long shifttype = bits (inst, 5, 6);
+  struct cleanup *old_chain
+    = make_cleanup_restore_integer (&arm_override_mode);
 
-  if (bit (inst, 4))
-    {
-      int rs = bits (inst, 8, 11);
-      shift = (rs == 15 ? pc_val + 8
-			: get_frame_register_unsigned (frame, rs)) & 0xFF;
-    }
-  else
-    shift = bits (inst, 7, 11);
+  arm_override_mode = IS_THUMB_ADDR (pc);
+  pc = gdbarch_addr_bits_remove (gdbarch, pc);
 
-  res = (rm == ARM_PC_REGNUM
-	 ? (pc_val + (bit (inst, 4) ? 12 : 8))
-	 : get_frame_register_unsigned (frame, rm));
+  insert_single_step_breakpoint (gdbarch, aspace, pc);
 
-  switch (shifttype)
-    {
-    case 0:			/* LSL */
-      res = shift >= 32 ? 0 : res << shift;
-      break;
+  do_cleanups (old_chain);
+}
 
-    case 1:			/* LSR */
-      res = shift >= 32 ? 0 : res >> shift;
-      break;
+/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
+   the buffer to be NEW_LEN bytes ending at ENDADDR.  Return
+   NULL if an error occurs.  BUF is freed.  */
 
-    case 2:			/* ASR */
-      if (shift >= 32)
-	shift = 31;
-      res = ((res & 0x80000000L)
-	     ? ~((~res) >> shift) : res >> shift);
-      break;
+static gdb_byte *
+extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
+		       int old_len, int new_len)
+{
+  gdb_byte *new_buf;
+  int bytes_to_read = new_len - old_len;
 
-    case 3:			/* ROR/RRX */
-      shift &= 31;
-      if (shift == 0)
-	res = (res >> 1) | (carry ? 0x80000000L : 0);
-      else
-	res = (res >> shift) | (res << (32 - shift));
-      break;
+  new_buf = (gdb_byte *) xmalloc (new_len);
+  memcpy (new_buf + bytes_to_read, buf, old_len);
+  xfree (buf);
+  if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
+    {
+      xfree (new_buf);
+      return NULL;
     }
-
-  return res & 0xffffffff;
+  return new_buf;
 }
 
-static int
-thumb_advance_itstate (unsigned int itstate)
-{
-  /* Preserve IT[7:5], the first three bits of the condition.  Shift
-     the upcoming condition flags left by one bit.  */
-  itstate = (itstate & 0xe0) | ((itstate << 1) & 0x1f);
-
-  /* If we have finished the IT block, clear the state.  */
-  if ((itstate & 0x0f) == 0)
-    itstate = 0;
-
-  return itstate;
-}
+/* An IT block is at most the 2-byte IT instruction followed by
+   four 4-byte instructions.  The furthest back we must search to
+   find an IT block that affects the current instruction is thus
+   2 + 3 * 4 == 14 bytes.  */
+#define MAX_IT_BLOCK_PREFIX 14
 
-/* Find the next PC after the current instruction executes.  In some
-   cases we can not statically determine the answer (see the IT state
-   handling in this function); in that case, a breakpoint may be
-   inserted in addition to the returned PC, which will be used to set
-   another breakpoint by our caller.  */
+/* Use a quick scan if there are more than this many bytes of
+   code.  */
+#define IT_SCAN_THRESHOLD 32
 
+/* Adjust a breakpoint's address to move breakpoints out of IT blocks.
+   A breakpoint in an IT block may not be hit, depending on the
+   condition flags.  */
 static CORE_ADDR
-thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
+arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 {
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  unsigned long pc_val = ((unsigned long) pc) + 4;	/* PC after prefetch */
-  unsigned short inst1;
-  CORE_ADDR nextpc = pc + 2;		/* Default is next instruction.  */
-  unsigned long offset;
-  ULONGEST status, itstate;
-
-  nextpc = MAKE_THUMB_ADDR (nextpc);
-  pc_val = MAKE_THUMB_ADDR (pc_val);
-
-  inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
-
-  /* Thumb-2 conditional execution support.  There are eight bits in
-     the CPSR which describe conditional execution state.  Once
-     reconstructed (they're in a funny order), the low five bits
-     describe the low bit of the condition for each instruction and
-     how many instructions remain.  The high three bits describe the
-     base condition.  One of the low four bits will be set if an IT
-     block is active.  These bits read as zero on earlier
-     processors.  */
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
-
-  /* If-Then handling.  On GNU/Linux, where this routine is used, we
-     use an undefined instruction as a breakpoint.  Unlike BKPT, IT
-     can disable execution of the undefined instruction.  So we might
-     miss the breakpoint if we set it on a skipped conditional
-     instruction.  Because conditional instructions can change the
-     flags, affecting the execution of further instructions, we may
-     need to set two breakpoints.  */
-
-  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint != NULL)
-    {
-      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
-	{
-	  /* An IT instruction.  Because this instruction does not
-	     modify the flags, we can accurately predict the next
-	     executed instruction.  */
-	  itstate = inst1 & 0x00ff;
-	  pc += thumb_insn_size (inst1);
-
-	  while (itstate != 0 && ! condition_true (itstate >> 4, status))
-	    {
-	      inst1 = read_memory_unsigned_integer (pc, 2,
-						    byte_order_for_code);
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
-	    }
-
-	  return MAKE_THUMB_ADDR (pc);
-	}
-      else if (itstate != 0)
-	{
-	  /* We are in a conditional block.  Check the condition.  */
-	  if (! condition_true (itstate >> 4, status))
-	    {
-	      /* Advance to the next executed instruction.  */
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
+  gdb_byte *buf;
+  char map_type;
+  CORE_ADDR boundary, func_start;
+  int buf_len;
+  enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
+  int i, any, last_it, last_it_count;
 
-	      while (itstate != 0 && ! condition_true (itstate >> 4, status))
-		{
-		  inst1 = read_memory_unsigned_integer (pc, 2, 
-							byte_order_for_code);
-		  pc += thumb_insn_size (inst1);
-		  itstate = thumb_advance_itstate (itstate);
-		}
+  /* If we are using BKPT breakpoints, none of this is necessary.  */
+  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint == NULL)
+    return bpaddr;
 
-	      return MAKE_THUMB_ADDR (pc);
-	    }
-	  else if ((itstate & 0x0f) == 0x08)
-	    {
-	      /* This is the last instruction of the conditional
-		 block, and it is executed.  We can handle it normally
-		 because the following instruction is not conditional,
-		 and we must handle it normally because it is
-		 permitted to branch.  Fall through.  */
-	    }
-	  else
-	    {
-	      int cond_negated;
-
-	      /* There are conditional instructions after this one.
-		 If this instruction modifies the flags, then we can
-		 not predict what the next executed instruction will
-		 be.  Fortunately, this instruction is architecturally
-		 forbidden to branch; we know it will fall through.
-		 Start by skipping past it.  */
-	      pc += thumb_insn_size (inst1);
-	      itstate = thumb_advance_itstate (itstate);
-
-	      /* Set a breakpoint on the following instruction.  */
-	      gdb_assert ((itstate & 0x0f) != 0);
-	      arm_insert_single_step_breakpoint (gdbarch, aspace,
-						 MAKE_THUMB_ADDR (pc));
-	      cond_negated = (itstate >> 4) & 1;
-
-	      /* Skip all following instructions with the same
-		 condition.  If there is a later instruction in the IT
-		 block with the opposite condition, set the other
-		 breakpoint there.  If not, then set a breakpoint on
-		 the instruction after the IT block.  */
-	      do
-		{
-		  inst1 = read_memory_unsigned_integer (pc, 2,
-							byte_order_for_code);
-		  pc += thumb_insn_size (inst1);
-		  itstate = thumb_advance_itstate (itstate);
-		}
-	      while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
+  /* ARM mode does not have this problem.  */
+  if (!arm_pc_is_thumb (gdbarch, bpaddr))
+    return bpaddr;
 
-	      return MAKE_THUMB_ADDR (pc);
-	    }
-	}
-    }
-  else if (itstate & 0x0f)
-    {
-      /* We are in a conditional block.  Check the condition.  */
-      int cond = itstate >> 4;
+  /* We are setting a breakpoint in Thumb code that could potentially
+     contain an IT block.  The first step is to find how much Thumb
+     code there is; we do not need to read outside of known Thumb
+     sequences.  */
+  map_type = arm_find_mapping_symbol (bpaddr, &boundary);
+  if (map_type == 0)
+    /* Thumb-2 code must have mapping symbols to have a chance.  */
+    return bpaddr;
 
-      if (! condition_true (cond, status))
-	/* Advance to the next instruction.  All the 32-bit
-	   instructions share a common prefix.  */
-	return MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1));
+  bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
 
-      /* Otherwise, handle the instruction normally.  */
-    }
+  if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
+      && func_start > boundary)
+    boundary = func_start;
 
-  if ((inst1 & 0xff00) == 0xbd00)	/* pop {rlist, pc} */
-    {
-      CORE_ADDR sp;
+  /* Search for a candidate IT instruction.  We have to do some fancy
+     footwork to distinguish a real IT instruction from the second
+     half of a 32-bit instruction, but there is no need for that if
+     there's no candidate.  */
+  buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
+  if (buf_len == 0)
+    /* No room for an IT instruction.  */
+    return bpaddr;
 
-      /* Fetch the saved PC from the stack.  It's stored above
-         all of the other registers.  */
-      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
-      sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
-      nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order);
-    }
-  else if ((inst1 & 0xf000) == 0xd000)	/* conditional branch */
+  buf = (gdb_byte *) xmalloc (buf_len);
+  if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
+    return bpaddr;
+  any = 0;
+  for (i = 0; i < buf_len; i += 2)
     {
-      unsigned long cond = bits (inst1, 8, 11);
-      if (cond == 0x0f)  /* 0x0f = SWI */
+      unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
+      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
 	{
-	  struct gdbarch_tdep *tdep;
-	  tdep = gdbarch_tdep (gdbarch);
-
-	  if (tdep->syscall_next_pc != NULL)
-	    nextpc = tdep->syscall_next_pc (frame);
-
+	  any = 1;
+	  break;
 	}
-      else if (cond != 0x0f && condition_true (cond, status))
-	nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
     }
-  else if ((inst1 & 0xf800) == 0xe000)	/* unconditional branch */
+  if (any == 0)
     {
-      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
+      xfree (buf);
+      return bpaddr;
     }
-  else if (thumb_insn_size (inst1) == 4) /* 32-bit instruction */
-    {
-      unsigned short inst2;
-      inst2 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
-
-      /* Default to the next instruction.  */
-      nextpc = pc + 4;
-      nextpc = MAKE_THUMB_ADDR (nextpc);
 
-      if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000)
-	{
-	  /* Branches and miscellaneous control instructions.  */
-
-	  if ((inst2 & 0x1000) != 0 || (inst2 & 0xd001) == 0xc000)
-	    {
-	      /* B, BL, BLX.  */
-	      int j1, j2, imm1, imm2;
-
-	      imm1 = sbits (inst1, 0, 10);
-	      imm2 = bits (inst2, 0, 10);
-	      j1 = bit (inst2, 13);
-	      j2 = bit (inst2, 11);
-
-	      offset = ((imm1 << 12) + (imm2 << 1));
-	      offset ^= ((!j2) << 22) | ((!j1) << 23);
-
-	      nextpc = pc_val + offset;
-	      /* For BLX make sure to clear the low bits.  */
-	      if (bit (inst2, 12) == 0)
-		nextpc = nextpc & 0xfffffffc;
-	    }
-	  else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
-	    {
-	      /* SUBS PC, LR, #imm8.  */
-	      nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
-	      nextpc -= inst2 & 0x00ff;
-	    }
-	  else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
-	    {
-	      /* Conditional branch.  */
-	      if (condition_true (bits (inst1, 6, 9), status))
-		{
-		  int sign, j1, j2, imm1, imm2;
-
-		  sign = sbits (inst1, 10, 10);
-		  imm1 = bits (inst1, 0, 5);
-		  imm2 = bits (inst2, 0, 10);
-		  j1 = bit (inst2, 13);
-		  j2 = bit (inst2, 11);
-
-		  offset = (sign << 20) + (j2 << 19) + (j1 << 18);
-		  offset += (imm1 << 12) + (imm2 << 1);
-
-		  nextpc = pc_val + offset;
-		}
-	    }
-	}
-      else if ((inst1 & 0xfe50) == 0xe810)
-	{
-	  /* Load multiple or RFE.  */
-	  int rn, offset, load_pc = 1;
-
-	  rn = bits (inst1, 0, 3);
-	  if (bit (inst1, 7) && !bit (inst1, 8))
-	    {
-	      /* LDMIA or POP */
-	      if (!bit (inst2, 15))
-		load_pc = 0;
-	      offset = bitcount (inst2) * 4 - 4;
-	    }
-	  else if (!bit (inst1, 7) && bit (inst1, 8))
-	    {
-	      /* LDMDB */
-	      if (!bit (inst2, 15))
-		load_pc = 0;
-	      offset = -4;
-	    }
-	  else if (bit (inst1, 7) && bit (inst1, 8))
-	    {
-	      /* RFEIA */
-	      offset = 0;
-	    }
-	  else if (!bit (inst1, 7) && !bit (inst1, 8))
-	    {
-	      /* RFEDB */
-	      offset = -8;
-	    }
-	  else
-	    load_pc = 0;
-
-	  if (load_pc)
-	    {
-	      CORE_ADDR addr = get_frame_register_unsigned (frame, rn);
-	      nextpc = get_frame_memory_unsigned (frame, addr + offset, 4);
-	    }
-	}
-      else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
-	{
-	  /* MOV PC or MOVS PC.  */
-	  nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  nextpc = MAKE_THUMB_ADDR (nextpc);
-	}
-      else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
-	{
-	  /* LDR PC.  */
-	  CORE_ADDR base;
-	  int rn, load_pc = 1;
-
-	  rn = bits (inst1, 0, 3);
-	  base = get_frame_register_unsigned (frame, rn);
-	  if (rn == ARM_PC_REGNUM)
-	    {
-	      base = (base + 4) & ~(CORE_ADDR) 0x3;
-	      if (bit (inst1, 7))
-		base += bits (inst2, 0, 11);
-	      else
-		base -= bits (inst2, 0, 11);
-	    }
-	  else if (bit (inst1, 7))
-	    base += bits (inst2, 0, 11);
-	  else if (bit (inst2, 11))
-	    {
-	      if (bit (inst2, 10))
-		{
-		  if (bit (inst2, 9))
-		    base += bits (inst2, 0, 7);
-		  else
-		    base -= bits (inst2, 0, 7);
-		}
-	    }
-	  else if ((inst2 & 0x0fc0) == 0x0000)
-	    {
-	      int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
-	      base += get_frame_register_unsigned (frame, rm) << shift;
-	    }
-	  else
-	    /* Reserved.  */
-	    load_pc = 0;
-
-	  if (load_pc)
-	    nextpc = get_frame_memory_unsigned (frame, base, 4);
-	}
-      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
-	{
-	  /* TBB.  */
-	  CORE_ADDR tbl_reg, table, offset, length;
-
-	  tbl_reg = bits (inst1, 0, 3);
-	  if (tbl_reg == 0x0f)
-	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
-	  else
-	    table = get_frame_register_unsigned (frame, tbl_reg);
-
-	  offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
-	  nextpc = pc_val + length;
-	}
-      else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
-	{
-	  /* TBH.  */
-	  CORE_ADDR tbl_reg, table, offset, length;
-
-	  tbl_reg = bits (inst1, 0, 3);
-	  if (tbl_reg == 0x0f)
-	    table = pc + 4;  /* Regcache copy of PC isn't right yet.  */
-	  else
-	    table = get_frame_register_unsigned (frame, tbl_reg);
-
-	  offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
-	  length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
-	  nextpc = pc_val + length;
-	}
-    }
-  else if ((inst1 & 0xff00) == 0x4700)	/* bx REG, blx REG */
-    {
-      if (bits (inst1, 3, 6) == 0x0f)
-	nextpc = UNMAKE_THUMB_ADDR (pc_val);
-      else
-	nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
-    }
-  else if ((inst1 & 0xff87) == 0x4687)	/* mov pc, REG */
-    {
-      if (bits (inst1, 3, 6) == 0x0f)
-	nextpc = pc_val;
-      else
-	nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
-
-      nextpc = MAKE_THUMB_ADDR (nextpc);
-    }
-  else if ((inst1 & 0xf500) == 0xb100)
-    {
-      /* CBNZ or CBZ.  */
-      int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
-      ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2));
-
-      if (bit (inst1, 11) && reg != 0)
-	nextpc = pc_val + imm;
-      else if (!bit (inst1, 11) && reg == 0)
-	nextpc = pc_val + imm;
-    }
-  return nextpc;
-}
-
-/* Get the raw next address.  PC is the current program counter, in 
-   FRAME, which is assumed to be executing in ARM mode.
-
-   The value returned has the execution state of the next instruction 
-   encoded in it.  Use IS_THUMB_ADDR () to see whether the instruction is
-   in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
-   address.  */
-
-static CORE_ADDR
-arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  unsigned long pc_val;
-  unsigned long this_instr;
-  unsigned long status;
-  CORE_ADDR nextpc;
-
-  pc_val = (unsigned long) pc;
-  this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
-
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  nextpc = (CORE_ADDR) (pc_val + 4);	/* Default case */
-
-  if (bits (this_instr, 28, 31) == INST_NV)
-    switch (bits (this_instr, 24, 27))
-      {
-      case 0xa:
-      case 0xb:
-	{
-	  /* Branch with Link and change to Thumb.  */
-	  nextpc = BranchDest (pc, this_instr);
-	  nextpc |= bit (this_instr, 24) << 1;
-	  nextpc = MAKE_THUMB_ADDR (nextpc);
-	  break;
-	}
-      case 0xc:
-      case 0xd:
-      case 0xe:
-	/* Coprocessor register transfer.  */
-        if (bits (this_instr, 12, 15) == 15)
-	  error (_("Invalid update to pc in instruction"));
-	break;
-      }
-  else if (condition_true (bits (this_instr, 28, 31), status))
-    {
-      switch (bits (this_instr, 24, 27))
-	{
-	case 0x0:
-	case 0x1:			/* data processing */
-	case 0x2:
-	case 0x3:
-	  {
-	    unsigned long operand1, operand2, result = 0;
-	    unsigned long rn;
-	    int c;
-
-	    if (bits (this_instr, 12, 15) != 15)
-	      break;
-
-	    if (bits (this_instr, 22, 25) == 0
-		&& bits (this_instr, 4, 7) == 9)	/* multiply */
-	      error (_("Invalid update to pc in instruction"));
-
-	    /* BX <reg>, BLX <reg> */
-	    if (bits (this_instr, 4, 27) == 0x12fff1
-		|| bits (this_instr, 4, 27) == 0x12fff3)
-	      {
-		rn = bits (this_instr, 0, 3);
-		nextpc = ((rn == ARM_PC_REGNUM)
-			  ? (pc_val + 8)
-			  : get_frame_register_unsigned (frame, rn));
-
-		return nextpc;
-	      }
-
-	    /* Multiply into PC.  */
-	    c = (status & FLAG_C) ? 1 : 0;
-	    rn = bits (this_instr, 16, 19);
-	    operand1 = ((rn == ARM_PC_REGNUM)
-			? (pc_val + 8)
-			: get_frame_register_unsigned (frame, rn));
-
-	    if (bit (this_instr, 25))
-	      {
-		unsigned long immval = bits (this_instr, 0, 7);
-		unsigned long rotate = 2 * bits (this_instr, 8, 11);
-		operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
-		  & 0xffffffff;
-	      }
-	    else		/* operand 2 is a shifted register.  */
-	      operand2 = shifted_reg_val (frame, this_instr, c,
-					  pc_val, status);
-
-	    switch (bits (this_instr, 21, 24))
-	      {
-	      case 0x0:	/*and */
-		result = operand1 & operand2;
-		break;
-
-	      case 0x1:	/*eor */
-		result = operand1 ^ operand2;
-		break;
-
-	      case 0x2:	/*sub */
-		result = operand1 - operand2;
-		break;
-
-	      case 0x3:	/*rsb */
-		result = operand2 - operand1;
-		break;
-
-	      case 0x4:	/*add */
-		result = operand1 + operand2;
-		break;
-
-	      case 0x5:	/*adc */
-		result = operand1 + operand2 + c;
-		break;
-
-	      case 0x6:	/*sbc */
-		result = operand1 - operand2 + c;
-		break;
-
-	      case 0x7:	/*rsc */
-		result = operand2 - operand1 + c;
-		break;
-
-	      case 0x8:
-	      case 0x9:
-	      case 0xa:
-	      case 0xb:	/* tst, teq, cmp, cmn */
-		result = (unsigned long) nextpc;
-		break;
-
-	      case 0xc:	/*orr */
-		result = operand1 | operand2;
-		break;
-
-	      case 0xd:	/*mov */
-		/* Always step into a function.  */
-		result = operand2;
-		break;
-
-	      case 0xe:	/*bic */
-		result = operand1 & ~operand2;
-		break;
-
-	      case 0xf:	/*mvn */
-		result = ~operand2;
-		break;
-	      }
-
-            /* In 26-bit APCS the bottom two bits of the result are 
-	       ignored, and we always end up in ARM state.  */
-	    if (!arm_apcs_32)
-	      nextpc = arm_addr_bits_remove (gdbarch, result);
-	    else
-	      nextpc = result;
-
-	    break;
-	  }
-
-	case 0x4:
-	case 0x5:		/* data transfer */
-	case 0x6:
-	case 0x7:
-	  if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
-	    {
-	      /* Media instructions and architecturally undefined
-		 instructions.  */
-	      break;
-	    }
-
-	  if (bit (this_instr, 20))
-	    {
-	      /* load */
-	      if (bits (this_instr, 12, 15) == 15)
-		{
-		  /* rd == pc */
-		  unsigned long rn;
-		  unsigned long base;
-
-		  if (bit (this_instr, 22))
-		    error (_("Invalid update to pc in instruction"));
-
-		  /* byte write to PC */
-		  rn = bits (this_instr, 16, 19);
-		  base = ((rn == ARM_PC_REGNUM)
-			  ? (pc_val + 8)
-			  : get_frame_register_unsigned (frame, rn));
-
-		  if (bit (this_instr, 24))
-		    {
-		      /* pre-indexed */
-		      int c = (status & FLAG_C) ? 1 : 0;
-		      unsigned long offset =
-		      (bit (this_instr, 25)
-		       ? shifted_reg_val (frame, this_instr, c, pc_val, status)
-		       : bits (this_instr, 0, 11));
-
-		      if (bit (this_instr, 23))
-			base += offset;
-		      else
-			base -= offset;
-		    }
-		  nextpc =
-		    (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR) base,
-							      4, byte_order);
-		}
-	    }
-	  break;
-
-	case 0x8:
-	case 0x9:		/* block transfer */
-	  if (bit (this_instr, 20))
-	    {
-	      /* LDM */
-	      if (bit (this_instr, 15))
-		{
-		  /* loading pc */
-		  int offset = 0;
-		  unsigned long rn_val
-		    = get_frame_register_unsigned (frame,
-						   bits (this_instr, 16, 19));
-
-		  if (bit (this_instr, 23))
-		    {
-		      /* up */
-		      unsigned long reglist = bits (this_instr, 0, 14);
-		      offset = bitcount (reglist) * 4;
-		      if (bit (this_instr, 24))		/* pre */
-			offset += 4;
-		    }
-		  else if (bit (this_instr, 24))
-		    offset = -4;
-
-		  nextpc =
-		    (CORE_ADDR) read_memory_unsigned_integer ((CORE_ADDR)
-							      (rn_val + offset),
-							      4, byte_order);
-		}
-	    }
-	  break;
-
-	case 0xb:		/* branch & link */
-	case 0xa:		/* branch */
-	  {
-	    nextpc = BranchDest (pc, this_instr);
-	    break;
-	  }
-
-	case 0xc:
-	case 0xd:
-	case 0xe:		/* coproc ops */
-	  break;
-	case 0xf:		/* SWI */
-	  {
-	    struct gdbarch_tdep *tdep;
-	    tdep = gdbarch_tdep (gdbarch);
-
-	    if (tdep->syscall_next_pc != NULL)
-	      nextpc = tdep->syscall_next_pc (frame);
-
-	  }
-	  break;
-
-	default:
-	  fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
-	  return (pc);
-	}
-    }
-
-  return nextpc;
-}
-
-/* Determine next PC after current instruction executes.  Will call either
-   arm_get_next_pc_raw or thumb_get_next_pc_raw.  Error out if infinite
-   loop is detected.  */
-
-CORE_ADDR
-arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
-{
-  CORE_ADDR nextpc;
-
-  if (arm_frame_is_thumb (frame))
-    nextpc = thumb_get_next_pc_raw (frame, pc);
-  else
-    nextpc = arm_get_next_pc_raw (frame, pc);
-
-  return nextpc;
-}
-
-/* Like insert_single_step_breakpoint, but make sure we use a breakpoint
-   of the appropriate mode (as encoded in the PC value), even if this
-   differs from what would be expected according to the symbol tables.  */
-
-void
-arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
-				   struct address_space *aspace,
-				   CORE_ADDR pc)
-{
-  struct cleanup *old_chain
-    = make_cleanup_restore_integer (&arm_override_mode);
-
-  arm_override_mode = IS_THUMB_ADDR (pc);
-  pc = gdbarch_addr_bits_remove (gdbarch, pc);
-
-  insert_single_step_breakpoint (gdbarch, aspace, pc);
-
-  do_cleanups (old_chain);
-}
-
-/* Checks for an atomic sequence of instructions beginning with a LDREX{,B,H,D}
-   instruction and ending with a STREX{,B,H,D} instruction.  If such a sequence
-   is found, attempt to step through it.  A breakpoint is placed at the end of
-   the sequence.  */
-
-static int
-thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR breaks[2] = {-1, -1};
-  CORE_ADDR loc = pc;
-  unsigned short insn1, insn2;
-  int insn_count;
-  int index;
-  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
-  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
-  ULONGEST status, itstate;
-
-  /* We currently do not support atomic sequences within an IT block.  */
-  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
-  itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
-  if (itstate & 0x0f)
-    return 0;
-
-  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.  */
-  insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-  loc += 2;
-  if (thumb_insn_size (insn1) != 4)
-    return 0;
-
-  insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-  loc += 2;
-  if (!((insn1 & 0xfff0) == 0xe850
-        || ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
-    return 0;
-
-  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
-     instructions.  */
-  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
-    {
-      insn1 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-      loc += 2;
-
-      if (thumb_insn_size (insn1) != 4)
-	{
-	  /* Assume that there is at most one conditional branch in the
-	     atomic sequence.  If a conditional branch is found, put a
-	     breakpoint in its destination address.  */
-	  if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
-	    {
-	      if (last_breakpoint > 0)
-		return 0; /* More than one conditional branch found,
-			     fallback to the standard code.  */
-
-	      breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
-	      last_breakpoint++;
-	    }
-
-	  /* We do not support atomic sequences that use any *other*
-	     instructions but conditional branches to change the PC.
-	     Fall back to standard code to avoid losing control of
-	     execution.  */
-	  else if (thumb_instruction_changes_pc (insn1))
-	    return 0;
-	}
-      else
-	{
-	  insn2 = read_memory_unsigned_integer (loc, 2, byte_order_for_code);
-	  loc += 2;
-
-	  /* Assume that there is at most one conditional branch in the
-	     atomic sequence.  If a conditional branch is found, put a
-	     breakpoint in its destination address.  */
-	  if ((insn1 & 0xf800) == 0xf000
-	      && (insn2 & 0xd000) == 0x8000
-	      && (insn1 & 0x0380) != 0x0380)
-	    {
-	      int sign, j1, j2, imm1, imm2;
-	      unsigned int offset;
-
-	      sign = sbits (insn1, 10, 10);
-	      imm1 = bits (insn1, 0, 5);
-	      imm2 = bits (insn2, 0, 10);
-	      j1 = bit (insn2, 13);
-	      j2 = bit (insn2, 11);
-
-	      offset = (sign << 20) + (j2 << 19) + (j1 << 18);
-	      offset += (imm1 << 12) + (imm2 << 1);
-
-	      if (last_breakpoint > 0)
-		return 0; /* More than one conditional branch found,
-			     fallback to the standard code.  */
-
-	      breaks[1] = loc + offset;
-	      last_breakpoint++;
-	    }
-
-	  /* We do not support atomic sequences that use any *other*
-	     instructions but conditional branches to change the PC.
-	     Fall back to standard code to avoid losing control of
-	     execution.  */
-	  else if (thumb2_instruction_changes_pc (insn1, insn2))
-	    return 0;
-
-	  /* If we find a strex{,b,h,d}, we're done.  */
-	  if ((insn1 & 0xfff0) == 0xe840
-	      || ((insn1 & 0xfff0) == 0xe8c0 && (insn2 & 0x00c0) == 0x0040))
-	    break;
-	}
-    }
-
-  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
-  if (insn_count == atomic_sequence_length)
-    return 0;
-
-  /* Insert a breakpoint right after the end of the atomic sequence.  */
-  breaks[0] = loc;
-
-  /* Check for duplicated breakpoints.  Check also for a breakpoint
-     placed (branch instruction's destination) anywhere in sequence.  */
-  if (last_breakpoint
-      && (breaks[1] == breaks[0]
-	  || (breaks[1] >= pc && breaks[1] < loc)))
-    last_breakpoint = 0;
-
-  /* Effectively inserts the breakpoints.  */
-  for (index = 0; index <= last_breakpoint; index++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace,
-				       MAKE_THUMB_ADDR (breaks[index]));
-
-  return 1;
-}
-
-static int
-arm_deal_with_atomic_sequence_raw (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
-  CORE_ADDR pc = get_frame_pc (frame);
-  CORE_ADDR breaks[2] = {-1, -1};
-  CORE_ADDR loc = pc;
-  unsigned int insn;
-  int insn_count;
-  int index;
-  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
-  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
-
-  /* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
-     Note that we do not currently support conditionally executed atomic
-     instructions.  */
-  insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
-  loc += 4;
-  if ((insn & 0xff9000f0) != 0xe1900090)
-    return 0;
-
-  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
-     instructions.  */
-  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
-    {
-      insn = read_memory_unsigned_integer (loc, 4, byte_order_for_code);
-      loc += 4;
-
-      /* Assume that there is at most one conditional branch in the atomic
-         sequence.  If a conditional branch is found, put a breakpoint in
-         its destination address.  */
-      if (bits (insn, 24, 27) == 0xa)
-	{
-          if (last_breakpoint > 0)
-            return 0; /* More than one conditional branch found, fallback
-                         to the standard single-step code.  */
-
-	  breaks[1] = BranchDest (loc - 4, insn);
-	  last_breakpoint++;
-        }
-
-      /* We do not support atomic sequences that use any *other* instructions
-         but conditional branches to change the PC.  Fall back to standard
-	 code to avoid losing control of execution.  */
-      else if (arm_instruction_changes_pc (insn))
-	return 0;
-
-      /* If we find a strex{,b,h,d}, we're done.  */
-      if ((insn & 0xff9000f0) == 0xe1800090)
-	break;
-    }
-
-  /* If we didn't find the strex{,b,h,d}, we cannot handle the sequence.  */
-  if (insn_count == atomic_sequence_length)
-    return 0;
-
-  /* Insert a breakpoint right after the end of the atomic sequence.  */
-  breaks[0] = loc;
-
-  /* Check for duplicated breakpoints.  Check also for a breakpoint
-     placed (branch instruction's destination) anywhere in sequence.  */
-  if (last_breakpoint
-      && (breaks[1] == breaks[0]
-	  || (breaks[1] >= pc && breaks[1] < loc)))
-    last_breakpoint = 0;
-
-  /* Effectively inserts the breakpoints.  */
-  for (index = 0; index <= last_breakpoint; index++)
-    arm_insert_single_step_breakpoint (gdbarch, aspace, breaks[index]);
-
-  return 1;
-}
-
-int
-arm_deal_with_atomic_sequence (struct frame_info *frame)
-{
-  if (arm_frame_is_thumb (frame))
-    return thumb_deal_with_atomic_sequence_raw (frame);
-  else
-    return arm_deal_with_atomic_sequence_raw (frame);
-}
-
-/* single_step() is called just before we want to resume the inferior,
-   if we want to single-step it but there is no hardware or kernel
-   single-step support.  We find the target of the coming instruction
-   and breakpoint it.  */
-
-int
-arm_software_single_step (struct frame_info *frame)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  struct address_space *aspace = get_frame_address_space (frame);
-  CORE_ADDR next_pc;
-
-  if (arm_deal_with_atomic_sequence (frame))
-    return 1;
-
-  next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
-  arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);
-
-  return 1;
-}
-
-/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
-   the buffer to be NEW_LEN bytes ending at ENDADDR.  Return
-   NULL if an error occurs.  BUF is freed.  */
-
-static gdb_byte *
-extend_buffer_earlier (gdb_byte *buf, CORE_ADDR endaddr,
-		       int old_len, int new_len)
-{
-  gdb_byte *new_buf;
-  int bytes_to_read = new_len - old_len;
-
-  new_buf = (gdb_byte *) xmalloc (new_len);
-  memcpy (new_buf + bytes_to_read, buf, old_len);
-  xfree (buf);
-  if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
-    {
-      xfree (new_buf);
-      return NULL;
-    }
-  return new_buf;
-}
-
-/* An IT block is at most the 2-byte IT instruction followed by
-   four 4-byte instructions.  The furthest back we must search to
-   find an IT block that affects the current instruction is thus
-   2 + 3 * 4 == 14 bytes.  */
-#define MAX_IT_BLOCK_PREFIX 14
-
-/* Use a quick scan if there are more than this many bytes of
-   code.  */
-#define IT_SCAN_THRESHOLD 32
-
-/* Adjust a breakpoint's address to move breakpoints out of IT blocks.
-   A breakpoint in an IT block may not be hit, depending on the
-   condition flags.  */
-static CORE_ADDR
-arm_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
-{
-  gdb_byte *buf;
-  char map_type;
-  CORE_ADDR boundary, func_start;
-  int buf_len;
-  enum bfd_endian order = gdbarch_byte_order_for_code (gdbarch);
-  int i, any, last_it, last_it_count;
-
-  /* If we are using BKPT breakpoints, none of this is necessary.  */
-  if (gdbarch_tdep (gdbarch)->thumb2_breakpoint == NULL)
-    return bpaddr;
-
-  /* ARM mode does not have this problem.  */
-  if (!arm_pc_is_thumb (gdbarch, bpaddr))
-    return bpaddr;
-
-  /* We are setting a breakpoint in Thumb code that could potentially
-     contain an IT block.  The first step is to find how much Thumb
-     code there is; we do not need to read outside of known Thumb
-     sequences.  */
-  map_type = arm_find_mapping_symbol (bpaddr, &boundary);
-  if (map_type == 0)
-    /* Thumb-2 code must have mapping symbols to have a chance.  */
-    return bpaddr;
-
-  bpaddr = gdbarch_addr_bits_remove (gdbarch, bpaddr);
-
-  if (find_pc_partial_function (bpaddr, NULL, &func_start, NULL)
-      && func_start > boundary)
-    boundary = func_start;
-
-  /* Search for a candidate IT instruction.  We have to do some fancy
-     footwork to distinguish a real IT instruction from the second
-     half of a 32-bit instruction, but there is no need for that if
-     there's no candidate.  */
-  buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
-  if (buf_len == 0)
-    /* No room for an IT instruction.  */
-    return bpaddr;
-
-  buf = (gdb_byte *) xmalloc (buf_len);
-  if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
-    return bpaddr;
-  any = 0;
-  for (i = 0; i < buf_len; i += 2)
-    {
-      unsigned short inst1 = extract_unsigned_integer (&buf[i], 2, order);
-      if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
-	{
-	  any = 1;
-	  break;
-	}
-    }
-  if (any == 0)
-    {
-      xfree (buf);
-      return bpaddr;
-    }
-
-  /* OK, the code bytes before this instruction contain at least one
-     halfword which resembles an IT instruction.  We know that it's
-     Thumb code, but there are still two possibilities.  Either the
-     halfword really is an IT instruction, or it is the second half of
-     a 32-bit Thumb instruction.  The only way we can tell is to
-     scan forwards from a known instruction boundary.  */
-  if (bpaddr - boundary > IT_SCAN_THRESHOLD)
-    {
-      int definite;
+  /* OK, the code bytes before this instruction contain at least one
+     halfword which resembles an IT instruction.  We know that it's
+     Thumb code, but there are still two possibilities.  Either the
+     halfword really is an IT instruction, or it is the second half of
+     a 32-bit Thumb instruction.  The only way we can tell is to
+     scan forwards from a known instruction boundary.  */
+  if (bpaddr - boundary > IT_SCAN_THRESHOLD)
+    {
+      int definite;
 
       /* There's a lot of code before this instruction.  Start with an
 	 optimistic search; it's easy to recognize halfwords that can
@@ -7253,6 +6068,95 @@ thumb2_copy_block_xfer (struct gdbarch *gdbarch, uint16_t insn1, uint16_t insn2,
   return 0;
 }
 
+/* Wrapper over read_memory_unsigned_integer for use in arm_get_next_pcs.
+ This is used to avoid a dependency on BFD's bfd_endian enum.  */
+
+ULONGEST
+arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
+					       int byte_order)
+{
+  return read_memory_unsigned_integer (memaddr, len, byte_order);
+}
+
+/* Wrapper over gdbarch_addr_bits_remove for use in arm_get_next_pcs.  */
+
+CORE_ADDR
+arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *arm_next_pcs,
+				   CORE_ADDR val)
+{
+  struct arm_gdb_get_next_pcs* next_pcs =
+    (struct arm_gdb_get_next_pcs*) arm_next_pcs;
+
+  return gdbarch_addr_bits_remove (next_pcs->gdbarch, val);
+}
+
+/* Wrapper over gdbarch_addr_bits_remove for use in arm_get_next_pcs.  */
+
+ULONGEST
+arm_get_next_pcs_collect_register_unsigned (struct get_next_pcs *self, int n)
+{
+  struct arm_gdb_get_next_pcs* next_pcs =
+    (struct arm_gdb_get_next_pcs*) self;
+
+  return get_frame_register_unsigned (next_pcs->frame, n);
+}
+
+/* Wrapper over syscall_next_pc for use in get_next_pcs.  */
+
+CORE_ADDR
+arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *arm_next_pcs)
+{
+  struct arm_gdb_get_next_pcs* next_pcs =
+    (struct arm_gdb_get_next_pcs*) arm_next_pcs;
+  struct gdbarch_tdep *tdep;
+
+  tdep = gdbarch_tdep (next_pcs->gdbarch);
+  if (tdep->syscall_next_pc != NULL)
+    return tdep->syscall_next_pc (next_pcs->frame);
+
+  return 0;
+}
+
+/* single_step() is called just before we want to resume the inferior,
+   if we want to single-step it but there is no hardware or kernel
+   single-step support.  We find the target of the coming instructions
+   and breakpoint them.  */
+
+int
+arm_software_single_step (struct frame_info *frame)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct address_space *aspace = get_frame_address_space (frame);
+  struct arm_gdb_get_next_pcs next_pcs;
+  CORE_ADDR pc;
+  int i;
+
+  next_pcs.base.base.result = VEC_alloc (CORE_ADDR, 1);
+  next_pcs.gdbarch = gdbarch;
+  next_pcs.frame = frame;
+  next_pcs.base.ops = &arm_get_next_pcs_ops;
+  next_pcs.base.byte_order = gdbarch_byte_order (gdbarch);
+  next_pcs.base.byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  next_pcs.base.is_thumb = arm_frame_is_thumb (frame);
+  next_pcs.base.arm_apcs_32 = arm_apcs_32;
+  next_pcs.base.base.pc = get_frame_pc (frame);
+  next_pcs.base.arm_linux_thumb2_breakpoint =
+    gdbarch_tdep (gdbarch)->thumb2_breakpoint;
+
+  arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs);
+
+  for (i = 0;
+       VEC_iterate (CORE_ADDR, next_pcs.base.base.result, i, pc);
+       ++i)
+    {
+       arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+    }
+
+  VEC_free (CORE_ADDR, next_pcs.base.base.result);
+
+  return 1;
+}
+
 /* Cleanup/copy SVC (SWI) instructions.  These two functions are overridden
    for Linux, where some SVC instructions must be treated specially.  */
 
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 9b8447b..4029a5b 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -23,6 +23,9 @@
 struct gdbarch;
 struct regset;
 struct address_space;
+struct get_next_pcs;
+struct arm_get_next_pcs;
+struct gdb_get_next_pcs;
 
 #include "arch/arm.h"
 
@@ -250,11 +253,26 @@ extern void
 		       ULONGEST val, enum pc_write_style write_pc);
 
 CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
-CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
+
+
+ULONGEST arm_get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr,
+							int len,
+							int byte_order);
+
+CORE_ADDR arm_get_next_pcs_addr_bits_remove (struct arm_get_next_pcs
+					     *arm_next_pcs, CORE_ADDR val);
+
+ULONGEST arm_get_next_pcs_collect_register_unsigned (struct get_next_pcs *self,
+						     int n);
+
+CORE_ADDR
+arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *arm_next_pcs);
+
+int arm_software_single_step (struct frame_info *frame);
+
 void arm_insert_single_step_breakpoint (struct gdbarch *,
 					struct address_space *, CORE_ADDR);
-int arm_deal_with_atomic_sequence (struct frame_info *);
-int arm_software_single_step (struct frame_info *);
+
 int arm_frame_is_thumb (struct frame_info *frame);
 
 extern struct displaced_step_closure *
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 2e824ad..d9e9991 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -44,7 +44,7 @@ aarch64*-*-elf)
 aarch64*-*-linux*)
 	# Target: AArch64 linux
 	gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o aarch64-insn.o \
-			arm.o arm-tdep.o arm-linux-tdep.o \
+			arm.o arm-get-next-pcs.o arm-tdep.o arm-linux-tdep.o \
 			glibc-tdep.o linux-tdep.o solib-svr4.o \
 			symfile-mem.o linux-record.o"
 	build_gdbserver=yes
@@ -84,31 +84,34 @@ am33_2.0*-*-linux*)
 
 arm*-wince-pe | arm*-*-mingw32ce*)
 	# Target: ARM based machine running Windows CE (win32)
-	gdb_target_obs="arm.o arm-tdep.o arm-wince-tdep.o windows-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o arm-wince-tdep.o \
+			windows-tdep.o"
 	build_gdbserver=yes
 	;;
 arm*-*-linux*)
 	# Target: ARM based machine running GNU/Linux
-	gdb_target_obs="arm.o arm-tdep.o arm-linux-tdep.o glibc-tdep.o \
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o \
+                        arm-linux-tdep.o glibc-tdep.o \
 			solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o"
 	build_gdbserver=yes
 	;;
 arm*-*-netbsd* | arm*-*-knetbsd*-gnu)
 	# Target: NetBSD/arm
-	gdb_target_obs="arm.o arm-tdep.o armnbsd-tdep.o solib-svr4.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o armnbsd-tdep.o \
+			solib-svr4.o"
 	;;
 arm*-*-openbsd*)
 	# Target: OpenBSD/arm
-	gdb_target_obs="arm.o arm-tdep.o armbsd-tdep.o armobsd-tdep.o \
-			obsd-tdep.o solib-svr4.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o armbsd-tdep.o \
+			armobsd-tdep.o obsd-tdep.o solib-svr4.o"
 	;;
 arm*-*-symbianelf*)
 	# Target: SymbianOS/arm
-	gdb_target_obs="arm.o arm-tdep.o arm-symbian-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o arm-symbian-tdep.o"
 	;;
 arm*-*-*)
 	# Target: ARM embedded system
-	gdb_target_obs="arm.o arm-tdep.o"
+	gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o"
 	gdb_sim=../sim/arm/libsim.a
 	;;
 
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 97e1e62..96c7433 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -181,7 +181,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \
 	$(srcdir)/common/btrace-common.c \
 	$(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \
-	$(srcdir)/arch/arm.c
+	$(srcdir)/arch/arm.c $(srcdir)/arch/arm-get-next-pcs.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -589,6 +589,9 @@ fileio.o: ../common/fileio.c
 arm.o: ../arch/arm.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+arm-get-next-pcs.o: ../arch/arm-get-next-pcs.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 # Native object files rules from ../nat
 
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index e854110..838dedd 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -71,6 +71,7 @@ case "${target}" in
 			srv_tgtobj="$srv_linux_obj linux-arm-low.o"
 			srv_tgtobj="$srv_tgtobj linux-aarch32-low.o"
 			srv_tgtobj="${srv_tgtobj} arm.o"
+			srv_tgtobj="${srv_tgtobj} arm-get-next-pcs.o"
 			srv_xmlfiles="arm-with-iwmmxt.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
 			srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 0b87367..8054e59 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -31,6 +31,7 @@
 #include <signal.h>
 
 #include "arch/arm.h"
+#include "arch/arm-get-next-pcs.h"
 
 /* Defined in auto-generated files.  */
 void init_registers_arm (void);
@@ -146,6 +147,29 @@ static int arm_regmap[] = {
   64
 };
 
+/* Forward declarations needed for get_next_pcs ops.  */
+static ULONGEST
+get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, int len,
+			      int byte_order);
+
+static ULONGEST
+get_next_pcs_collect_register_unsigned (struct get_next_pcs* self, int n);
+
+static CORE_ADDR
+get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self,
+				   CORE_ADDR val);
+
+static CORE_ADDR
+get_next_pcs_syscall_next_pc (struct arm_get_next_pcs* next_pcs);
+
+/* get_next_pcs operations.  */
+static struct arm_get_next_pcs_ops get_next_pcs_ops = {
+  get_next_pcs_read_memory_unsigned_integer,
+  get_next_pcs_collect_register_unsigned,
+  get_next_pcs_syscall_next_pc,
+  get_next_pcs_addr_bits_remove
+};
+
 static int
 arm_cannot_store_register (int regno)
 {
@@ -208,6 +232,13 @@ arm_fill_vfpregset (struct regcache *regcache, void *buf)
   arm_fill_vfpregset_num (regcache, buf, num);
 }
 
+/* Wrapper of UNMAKE_THUMB_ADDR for get_next_pcs.  */
+static CORE_ADDR
+get_next_pcs_addr_bits_remove (struct arm_get_next_pcs *self, CORE_ADDR val)
+{
+  return UNMAKE_THUMB_ADDR (val);
+}
+
 static void
 arm_store_vfpregset (struct regcache *regcache, const void *buf)
 {
@@ -315,6 +346,36 @@ arm_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Wrapper of collect_register for get_next_pcs.  */
+
+static ULONGEST
+get_next_pcs_collect_register_unsigned (struct get_next_pcs* self, int n)
+{
+  struct arm_gdbserver_get_next_pcs *next_pcs =
+    (struct arm_gdbserver_get_next_pcs*) self;
+  ULONGEST res = 0;
+  int size = register_size (next_pcs->base.base.regcache->tdesc, n);
+
+  if (size > (int) sizeof (ULONGEST))
+    error (_("That operation is not available on integers of more than"
+	     "%d bytes."), (int) sizeof (ULONGEST));
+
+  collect_register (next_pcs->base.base.regcache, n, &res);
+  return res;
+}
+
+/* Read memory from the inferiror.
+   BYTE_ORDER is ignored and there to keep compatiblity with GDB's
+   read_memory_unsigned_integer. */
+static ULONGEST
+get_next_pcs_read_memory_unsigned_integer (CORE_ADDR memaddr, int len, int byte_order)
+{
+  ULONGEST res;
+
+  (*the_target->read_memory) (memaddr, (unsigned char *) &res, len);
+  return res;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -796,6 +857,55 @@ arm_prepare_to_resume (struct lwp_info *lwp)
       }
 }
 
+/* When PC is at a syscall instruction, return the PC of the next
+   instruction to be executed.  */
+static CORE_ADDR
+get_next_pcs_syscall_next_pc (struct arm_get_next_pcs* next_pcs)
+{
+  CORE_ADDR pc = next_pcs->base.pc;
+  CORE_ADDR return_addr = 0;
+  int is_thumb = next_pcs->is_thumb;
+  ULONGEST svc_number = 0;
+
+  if (is_thumb)
+    {
+      svc_number = next_pcs->ops->collect_register_unsigned
+	((struct get_next_pcs*) next_pcs, 7);
+      return_addr = pc + 2;
+    }
+  else
+    {
+      unsigned long this_instr = next_pcs->ops->read_memory_unsigned_integer
+	((CORE_ADDR) pc, 4, next_pcs->byte_order_for_code);
+
+      unsigned long svc_operand = (0x00ffffff & this_instr);
+      if (svc_operand)  /* OABI.  */
+	{
+	  svc_number = svc_operand - 0x900000;
+	}
+      else /* EABI.  */
+	{
+	  svc_number = next_pcs->ops->collect_register_unsigned
+	    ((struct get_next_pcs*) next_pcs, 7);
+	}
+
+      return_addr = pc + 4;
+    }
+
+  /* Is this a sigreturn or rt_sigreturn syscall?
+     If so it is currently not handeled.  */
+  if (svc_number == 119 || svc_number == 173)
+    {
+      if (debug_threads)
+	debug_printf ("Unhandled sigreturn or rt_sigreturn syscall\n");
+    }
+
+  /* Addresses for calling Thumb functions have the bit 0 set.  */
+  if (is_thumb)
+    return_addr = MAKE_THUMB_ADDR (return_addr);
+
+  return return_addr;
+}
 
 static int
 arm_get_hwcap (unsigned long *valp)
@@ -885,6 +995,27 @@ arm_arch_setup (void)
     have_ptrace_getregset = 0;
 }
 
+/* Fetch the next possible PCs after the current instruction executes.  */
+
+static void
+arm_gdbserver_get_next_pcs (struct get_next_pcs *base_next_pcs)
+{
+  struct arm_gdbserver_get_next_pcs next_pcs;
+
+  next_pcs.base.ops = &get_next_pcs_ops;
+  next_pcs.base.base = *base_next_pcs;
+  /* Byte order is ignored for GDBServer.  */
+  next_pcs.base.byte_order = 0;
+  next_pcs.base.byte_order_for_code = 0;
+  next_pcs.base.is_thumb = arm_is_thumb_mode();
+  /* 32-bit mode supported only in GDBServer.  */
+  next_pcs.base.arm_apcs_32 = 1;
+  next_pcs.base.arm_linux_thumb2_breakpoint =
+    (const gdb_byte *) &thumb2_breakpoint;
+
+  arm_get_next_pcs ((struct arm_get_next_pcs *) &next_pcs);
+}
+
 /* Support for hardware single step.  */
 
 static int
@@ -1027,7 +1158,7 @@ struct linux_target_ops the_low_target = {
   arm_set_pc,
   arm_breakpoint_kind_from_pc,
   arm_sw_breakpoint_from_kind,
-  NULL, /* get_next_pcs */
+  arm_gdbserver_get_next_pcs,
   0,
   arm_breakpoint_at,
   arm_supports_z_point_type,
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation in GDBServer.
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (7 preceding siblings ...)
  2015-10-29 17:43 ` [PATCH 08/10] Support software single step on ARM " Antoine Tremblay
@ 2015-10-29 17:45 ` Antoine Tremblay
  2015-11-04 18:48   ` Pedro Alves
  2015-10-29 17:48 ` [PATCH 02/10] Fix instruction skipping when using software single step " Antoine Tremblay
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

This patch in preparation for software single step support on ARM. It refactors
breakpoint_reinsert_addr into get_next_pcs so that multiple location can be
returned.

When software single stepping there can be multiple possible next addresses
because we're stepping over a branch instruction for example.

The operation get_next_pcs handles that by returning a vector of all the
possible next addresses.

Software breakpoints are installed at each location returned.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/ChangeLog:

	* common/get-next-pcs.h: New file.
	* common/gdb_vecs.h: Add CORE_ADDR vect.
	* symtab.h: Move CORE_ADDR vect to gdb_vecs.h

gdb/gdbserver/ChangeLog:
	* linux-aarch64-low.c (struct linux_target_ops): Rename
	breakpoint_reinsert_addr to get_next_pcs.
	* linux-arm-low.c (struct linux_target_ops): Likewise.
	* linux-bfin-low.c (struct linux_target_ops): Likewise.
	* linux-cris-low.c (struct linux_target_ops): Likewise.
	* linux-crisv32-low.c (struct linux_target_ops): Likewise.
	* linux-low.c (can_software_single_step): Likewise.
	(install_software_single_step_breakpoints): New function.
	(start_step_over): Use isntall_software_single_step_breakpoints.
	* linux-low.h: Rename breakpoint_reinsert_addr to
	get_next_pcs.
	* linux-mips-low.c (struct linux_target_ops): Likewise.
	* linux-nios2-low.c (struct linux_target_ops): Likewise.
	* linux-sparc-low.c (struct linux_target_ops): Likewise.
---
 gdb/common/gdb_vecs.h             |  2 ++
 gdb/common/get-next-pcs.h         | 34 ++++++++++++++++++++++++++++++++++
 gdb/gdbserver/linux-aarch64-low.c |  2 +-
 gdb/gdbserver/linux-arm-low.c     |  2 +-
 gdb/gdbserver/linux-bfin-low.c    |  2 +-
 gdb/gdbserver/linux-cris-low.c    |  2 +-
 gdb/gdbserver/linux-crisv32-low.c |  2 +-
 gdb/gdbserver/linux-low.c         | 31 +++++++++++++++++++++++++++----
 gdb/gdbserver/linux-low.h         |  6 +++++-
 gdb/gdbserver/linux-mips-low.c    |  2 +-
 gdb/gdbserver/linux-nios2-low.c   |  2 +-
 gdb/gdbserver/linux-sparc-low.c   |  2 +-
 gdb/symtab.h                      |  2 --
 13 files changed, 76 insertions(+), 15 deletions(-)
 create mode 100644 gdb/common/get-next-pcs.h

diff --git a/gdb/common/gdb_vecs.h b/gdb/common/gdb_vecs.h
index b3f56f8..1ed6182 100644
--- a/gdb/common/gdb_vecs.h
+++ b/gdb/common/gdb_vecs.h
@@ -31,6 +31,8 @@ DEF_VEC_P (const_char_ptr);
 
 DEF_VEC_I (int);
 
+DEF_VEC_I(CORE_ADDR);
+
 extern void free_char_ptr_vec (VEC (char_ptr) *char_ptr_vec);
 
 extern struct cleanup *
diff --git a/gdb/common/get-next-pcs.h b/gdb/common/get-next-pcs.h
new file mode 100644
index 0000000..dfe3461
--- /dev/null
+++ b/gdb/common/get-next-pcs.h
@@ -0,0 +1,34 @@
+/* Common code for software single stepping support.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GET_NEXT_PCS_H
+#define GET_NEXT_PCS_H 1
+
+#include "gdb_vecs.h"
+
+struct get_next_pcs
+{
+  /* Resulting vector of possible next addresses.  */
+  VEC (CORE_ADDR) *result;
+  /* Base PC from which to get the next pcs.  */
+  CORE_ADDR pc;
+  struct regcache* regcache;
+};
+
+#endif /* GET_NEXT_PCS_H */
diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index a0bc1c2..3e21042 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -2959,7 +2959,7 @@ struct linux_target_ops the_low_target =
   aarch64_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   aarch64_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,    /* decr_pc_after_break */
   aarch64_breakpoint_at,
   aarch64_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 8e32fae..0b87367 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -1027,7 +1027,7 @@ struct linux_target_ops the_low_target = {
   arm_set_pc,
   arm_breakpoint_kind_from_pc,
   arm_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   arm_breakpoint_at,
   arm_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c
index 912d253..1de2f78 100644
--- a/gdb/gdbserver/linux-bfin-low.c
+++ b/gdb/gdbserver/linux-bfin-low.c
@@ -141,7 +141,7 @@ struct linux_target_ops the_low_target = {
   bfin_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   bfin_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   2,
   bfin_breakpoint_at,
   NULL, /* supports_z_point_type */
diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c
index 9f4519c..6902a45 100644
--- a/gdb/gdbserver/linux-cris-low.c
+++ b/gdb/gdbserver/linux-cris-low.c
@@ -139,7 +139,7 @@ struct linux_target_ops the_low_target = {
   cris_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   cris_breakpoint_at,
 };
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
index 2404d0e..28c1981 100644
--- a/gdb/gdbserver/linux-crisv32-low.c
+++ b/gdb/gdbserver/linux-crisv32-low.c
@@ -422,7 +422,7 @@ struct linux_target_ops the_low_target = {
   cris_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   cris_breakpoint_at,
   cris_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index a3b0f3a..1f423ba 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -54,6 +54,7 @@
 #include <elf.h>
 #endif
 #include "nat/linux-namespaces.h"
+#include "common/get-next-pcs.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -281,12 +282,12 @@ can_hardware_single_step (void)
 }
 
 /* True if the low target can software single-step.  Such targets
-   implement the BREAKPOINT_REINSERT_ADDR callback.  */
+   implement the GET_NEXT_PCS callback.  */
 
 static int
 can_software_single_step (void)
 {
-  return (the_low_target.breakpoint_reinsert_addr != NULL);
+  return (the_low_target.get_next_pcs != NULL);
 }
 
 /* True if the low target supports memory breakpoints.  If so, we'll
@@ -3876,6 +3877,29 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info)
   lwp->pending_signals = p_sig;
 }
 
+/* Install breakpoints for software single stepping.  */
+
+static void
+install_software_single_step_breakpoints (struct lwp_info *lwp)
+{
+  struct get_next_pcs next_pcs;
+  int i;
+  CORE_ADDR pc;
+
+  struct regcache *regcache = get_thread_regcache (current_thread, 1);
+  next_pcs.pc = get_pc (lwp);
+  next_pcs.regcache = regcache;
+  next_pcs.result = VEC_alloc (CORE_ADDR, 1);
+  (*the_low_target.get_next_pcs) (&next_pcs);
+
+  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs.result, i, pc); ++i)
+    {
+      set_reinsert_breakpoint (pc);
+    }
+
+  VEC_free (CORE_ADDR, next_pcs.result);
+}
+
 /* Resume execution of LWP.  If STEP is nonzero, single-step it.  If
    SIGNAL is nonzero, give it that signal.  */
 
@@ -4439,8 +4463,7 @@ start_step_over (struct lwp_info *lwp)
     }
   else if (can_software_single_step ())
     {
-      CORE_ADDR raddr = (*the_low_target.breakpoint_reinsert_addr) ();
-      set_reinsert_breakpoint (raddr);
+      install_software_single_step_breakpoints (lwp);
       step = 0;
     }
   else
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index d60d97d..6bb638f 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -29,6 +29,9 @@
 
 #define PTRACE_XFER_TYPE long
 
+/* Forward declaration for get_next_pcs.  */
+struct get_next_pcs;
+
 #ifdef HAVE_LINUX_REGSETS
 typedef void (*regset_fill_func) (struct regcache *, void *);
 typedef void (*regset_store_func) (struct regcache *, const void *);
@@ -153,7 +156,8 @@ struct linux_target_ops
   /* See target.h for details.  */
   const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
 
-  CORE_ADDR (*breakpoint_reinsert_addr) (void);
+  /* Find the next possible PCs after the current instruction executes.  */
+  void (*get_next_pcs) (struct get_next_pcs *next_pcs);
 
   int decr_pc_after_break;
   int (*breakpoint_at) (CORE_ADDR pc);
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 32a91a8..5edc097 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -880,7 +880,7 @@ struct linux_target_ops the_low_target = {
   mips_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   mips_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   mips_breakpoint_at,
   mips_supports_z_point_type,
diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c
index 9380c3b..1accc03 100644
--- a/gdb/gdbserver/linux-nios2-low.c
+++ b/gdb/gdbserver/linux-nios2-low.c
@@ -267,7 +267,7 @@ struct linux_target_ops the_low_target =
   nios2_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   nios2_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   nios2_breakpoint_at,
 };
diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c
index 54a849c..bfdd8c1 100644
--- a/gdb/gdbserver/linux-sparc-low.c
+++ b/gdb/gdbserver/linux-sparc-low.c
@@ -320,7 +320,7 @@ struct linux_target_ops the_low_target = {
   NULL,
   NULL, /* breakpoint_kind_from_pc */
   sparc_sw_breakpoint_from_kind,
-  NULL, /* breakpoint_reinsert_addr */
+  NULL, /* get_next_pcs */
   0,
   sparc_breakpoint_at,
   NULL,  /* supports_z_point_type */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 477befd..bdc0921 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1607,8 +1607,6 @@ void iterate_over_symtabs (const char *name,
 					    void *data),
 			   void *data);
 
-DEF_VEC_I (CORE_ADDR);
-
 VEC (CORE_ADDR) *find_pcs_for_symtab_line (struct symtab *symtab, int line,
 					   struct linetable_entry **best_entry);
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 02/10] Fix instruction skipping when using software single step in GDBServer
  2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
                   ` (8 preceding siblings ...)
  2015-10-29 17:45 ` [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation " Antoine Tremblay
@ 2015-10-29 17:48 ` Antoine Tremblay
  2015-11-04 18:08   ` Pedro Alves
  9 siblings, 1 reply; 28+ messages in thread
From: Antoine Tremblay @ 2015-10-29 17:48 UTC (permalink / raw)
  To: gdb-patches; +Cc: Antoine Tremblay

Without this patch, when doing a software single step, with for example
a conditional breakpoint, gdbserver would wrongly avance the pc of
breakpoint_len and skips an instruction.

This is due to gdbserver assuming that it's hardware single stepping.
When it resumes from the breakpoint address it expects the trap to be
caused by ptrace and if it's rather caused by a software breakpoint
it assumes this is a permanent breakpoint and that it needs to skip
over it.

However when software single stepping, this breakpoint is legitimate as
it's the reinsert breakpoint gdbserver has put in place to break at
the next instruction. Thus gdbserver wrongly advances the pc and skips
an instruction.

This patch fixes this behavior so that gdbserver checks if it is a
reinsert breakpoint from software single stepping. If it is it won't
advance the pc. And if there's no reinsert breakpoint there we assume
then that it's a permanent breakpoint and advance the pc.

Here's a commented log of what would happen before and after the fix on
gdbserver :

/* Here there is a conditional breakpoint at 0x10428 that needs to be
stepped over. */

Need step over [LWP 11204]? yes, found breakpoint at 0x10428
...
/* e7f001f0 is a breakpoint instruction on arm
   Here gdbserver writes the software breakpoint we would like to hit
*/
Writing e7f001f0 to 0x0001042c in process 11204
...
Resuming lwp 11220 (continue, signal 0, stop not expected)
  pending reinsert at 0x10428
stop pc is 00010428
  continue from pc 0x10428
...

/* Here gdbserver hit the software breakpoint that was in place
   for the step over */

stop pc is 0001042c
pc is 0x1042c
step-over for LWP 11220.11220 executed software breakpoint
Finished step over.
Could not find fast tracepoint jump at 0x10428 in list (reinserting).

/* Here gdbserver writes back the original instruction */
Writing e50b3008 to 0x0001042c in process 11220
Step-over finished.
Need step over [LWP 11220]? No

/* Here because gdbserver assumes this is a permenant breakpoint it advances
the pc of breakpoint_len, in this case 4 bytes, so we have just skipped
the instruction that was written back here :
Writing e50b3008 to 0x0001042c in process 11220
*/

stop pc is 00010430
pc is 0x10430
Need step over [LWP 11220]? No, no breakpoint found at 0x10430
Proceeding, no step-over needed
proceed_one_lwp: lwp 11220
stop pc is 00010430

This patch fixes this situation and we get the right behavior :

Writing e50b3008 to 0x0001042c in process 11245
Hit a gdbserver breakpoint.
Hit a gdbserver breakpoint.
Step-over finished.
proceeding all threads.
Need step over [LWP 11245]? No
stop pc is 0001042c
pc is 0x1042c
Need step over [LWP 11245]? No, no breakpoint found at 0x1042c
Proceeding, no step-over needed
proceed_one_lwp: lwp 11245
stop pc is 0001042c
pc is 0x1042c
Resuming lwp 11245 (continue, signal 0, stop not expected)
stop pc is 0001042c
  continue from pc 0x1042c

It also works if the value at 0x0001042c is a permanent breakpoint.
If so gdbserver will finish the step over, remove the reinserted breakpoint,
resume at that location and on the next SIGTRAP gdbserver will trigger
the advance PC condition as reinsert_breakpoint_inserted_here will be false.

I also tested this against bp-permanent.exp on arm (with a work in progress
software single step patchset) without any regressions.

It's also tested against x86 bp-permanent.exp without any regression.

So both software and hardware single step are tested.

No regressions on Ubuntu 14.04 on ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-low.c (linux_wait_1): Fix pc advance condition.
	* mem-break.c (reinsert_breakpoint_inserted_here): New function.
	* mem-break.h (reinsert_breakpoint_inserted_here): New declaration.
---
 gdb/gdbserver/linux-low.c | 23 +++++++++++++++--------
 gdb/gdbserver/mem-break.c | 17 +++++++++++++++++
 gdb/gdbserver/mem-break.h |  4 ++++
 3 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 3b6c131..853a289 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -2993,14 +2993,21 @@ linux_wait_1 (ptid_t ptid,
       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)
+  /* If step-over executes a breakpoint instruction, in the case of a
+     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 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
+     if it's not the reinsert_breakpoint we are hitting.
+     This avoids that a program would keep trapping a permanent breakpoint
+     forever.  */
+  if ((!ptid_equal (step_over_bkpt, null_ptid)
+       && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) &&
+      (event_child->stepping ||
+       !reinsert_breakpoint_inserted_here (event_child->stop_pc)))
     {
       int increment_pc = 0;
       int breakpoint_kind = 0;
diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c
index c808a84..267f29d 100644
--- a/gdb/gdbserver/mem-break.c
+++ b/gdb/gdbserver/mem-break.c
@@ -1665,6 +1665,23 @@ hardware_breakpoint_inserted_here (CORE_ADDR addr)
   return 0;
 }
 
+/* See mem-break.h.  */
+
+int
+reinsert_breakpoint_inserted_here (CORE_ADDR addr)
+{
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp;
+
+  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
+    if (bp->type == reinsert_breakpoint
+	&& bp->raw->pc == addr
+	&& bp->raw->inserted)
+      return 1;
+
+  return 0;
+}
+
 static int
 validate_inserted_breakpoint (struct raw_breakpoint *bp)
 {
diff --git a/gdb/gdbserver/mem-break.h b/gdb/gdbserver/mem-break.h
index d199cc4..40b66a7 100644
--- a/gdb/gdbserver/mem-break.h
+++ b/gdb/gdbserver/mem-break.h
@@ -100,6 +100,10 @@ int software_breakpoint_inserted_here (CORE_ADDR addr);
 
 int hardware_breakpoint_inserted_here (CORE_ADDR addr);
 
+/* Returns TRUE if there's any reinsert breakpoint at ADDR.  */
+
+int reinsert_breakpoint_inserted_here (CORE_ADDR addr);
+
 /* Clear all breakpoint conditions and commands associated with a
    breakpoint.  */
 
-- 
1.9.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer.
  2015-10-29 17:36 ` [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer Antoine Tremblay
@ 2015-11-03 16:22   ` Yao Qi
  2015-11-03 17:05     ` Antoine Tremblay
  0 siblings, 1 reply; 28+ messages in thread
From: Yao Qi @ 2015-11-03 16:22 UTC (permalink / raw)
  To: Antoine Tremblay; +Cc: gdb-patches

Antoine Tremblay <antoine.tremblay@ericsson.com> writes:

>  static int
> -arm_breakpoint_at (CORE_ADDR where)
> +arm_is_thumb_mode (void)
>  {

Please add comments to arm_is_thumb_mode.

> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
> index 769c876..f0fb9d7 100644
> --- a/gdb/gdbserver/target.h
> +++ b/gdb/gdbserver/target.h
> @@ -451,6 +451,12 @@ struct target_ops
>       specific meaning like the Z0 kind parameter.
>       SIZE is set to the software breakpoint's length in memory.  */
>    const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
> +
> +  /* Return the breakpoint kind for this target based on the current state

Maybe "current machine state" or "current processor state" is better
than "current state"?

> +     (e.g. the current instruction mode on ARM) and the PC. The PCPTR is

Two spaces before "The PCPTR".

> +     adjusted to the real memory location in case a flag (e.g., the Thumb
> +     bit on ARM) was present in the PC.  */

"is present in the PC." ?

Otherwise, looks good to me.

-- 
Yao (齐尧)


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
@ 2015-11-03 17:05   ` Yao Qi
  2015-11-03 17:24     ` Antoine Tremblay
  2015-11-03 17:27     ` [PATCH v2] " Antoine Tremblay
  2015-11-04 18:19   ` [PATCH 04/10] " Pedro Alves
  1 sibling, 2 replies; 28+ messages in thread
From: Yao Qi @ 2015-11-03 17:05 UTC (permalink / raw)
  To: Antoine Tremblay; +Cc: gdb-patches

Antoine Tremblay <antoine.tremblay@ericsson.com> writes:

Hi,
I don't have objection to this direction...

> gdb/gdbserver/ChangeLog:
>
> 	* linux-low.c (linux_look_up_symbols): Don't call
> 	linux_supports_traceclone.
> 	* linux-low.h (thread_db_init): Remove use_events argument.
> 	* thread-db.c (thread_db_use_event): Remove global variable.
> 	(struct thread_db) <td_thr_event_enable_ftype>: Remove field.

s/td_thr_event_enable_ftype/td_thr_event_enable_p

We can also remove td_create_bp field.

> 	(thread_db_create_event): Remove function.
> 	(thread_db_enable_reporting): Likewise.

We can also remove remove_thread_event_breakpoints.

> 	(find_one_thread): Don't check for thread_db_use_events.
> 	(attach_thread): Likewise.
> 	(thread_db_load_search): Remove td_thr_event_enable_p initialization.
> 	(try_thread_db_load_1): Don't check for thread_db_use_events.
> 	(thread_db_init): Remove use_events argument.
> 	(thread_db_init): Remove thread events handling.

You mention function thread_db_init twice.

-- 
Yao (齐尧)


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer.
  2015-11-03 16:22   ` Yao Qi
@ 2015-11-03 17:05     ` Antoine Tremblay
  0 siblings, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-03 17:05 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches



On 11/03/2015 11:21 AM, Yao Qi wrote:
> Antoine Tremblay <antoine.tremblay@ericsson.com> writes:
>
>>   static int
>> -arm_breakpoint_at (CORE_ADDR where)
>> +arm_is_thumb_mode (void)
>>   {
>
> Please add comments to arm_is_thumb_mode.

Fixed as : /* Returns 1 if the current instruction set is thumb, 0 
otherwise.  */

>
>> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
>> index 769c876..f0fb9d7 100644
>> --- a/gdb/gdbserver/target.h
>> +++ b/gdb/gdbserver/target.h
>> @@ -451,6 +451,12 @@ struct target_ops
>>        specific meaning like the Z0 kind parameter.
>>        SIZE is set to the software breakpoint's length in memory.  */
>>     const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
>> +
>> +  /* Return the breakpoint kind for this target based on the current state
>
> Maybe "current machine state" or "current processor state" is better
> than "current state"?

Agreed. set as "current processor state"

>
>> +     (e.g. the current instruction mode on ARM) and the PC. The PCPTR is
>
> Two spaces before "The PCPTR".

Fixed.
>
>> +     adjusted to the real memory location in case a flag (e.g., the Thumb
>> +     bit on ARM) was present in the PC.  */
>
> "is present in the PC." ?
>

Fixed, thanks.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-11-03 17:05   ` Yao Qi
@ 2015-11-03 17:24     ` Antoine Tremblay
  2015-11-03 17:27     ` [PATCH v2] " Antoine Tremblay
  1 sibling, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-03 17:24 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches



On 11/03/2015 12:04 PM, Yao Qi wrote:
> Antoine Tremblay <antoine.tremblay@ericsson.com> writes:

> s/td_thr_event_enable_ftype/td_thr_event_enable_p

Done.
>
> We can also remove td_create_bp field.
>
Indeed, fixed.

>> 	(thread_db_create_event): Remove function.
>> 	(thread_db_enable_reporting): Likewise.
>
> We can also remove remove_thread_event_breakpoints.

Yes fixed.

>
>> 	(find_one_thread): Don't check for thread_db_use_events.
>> 	(attach_thread): Likewise.
>> 	(thread_db_load_search): Remove td_thr_event_enable_p initialization.
>> 	(try_thread_db_load_1): Don't check for thread_db_use_events.
>> 	(thread_db_init): Remove use_events argument.
>> 	(thread_db_init): Remove thread events handling.
>
> You mention function thread_db_init twice.
>
Oops, done.

V2 follows in next mail.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v2] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-11-03 17:05   ` Yao Qi
  2015-11-03 17:24     ` Antoine Tremblay
@ 2015-11-03 17:27     ` Antoine Tremblay
  1 sibling, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-03 17:27 UTC (permalink / raw)
  To: gdb-patches, qiyaoltc; +Cc: Antoine Tremblay

This patch removes support for thread events if TRACE_EVENT_CLONE is not
supported in GDBServer.

Before, on systems that did not support PTRACE_EVENT_CLONE, both GDB and
GDBServer coordinated with libthread_db.so to insert breakpoints at magic
locations in libpthread.so, in order to break at thread creation and thread
death.

Simple software single stepping support was implemented to step over these
breakpoints in case there was no hardware single stepping support. However,
these simple software single stepping implementations were not fit for any other
use as discussed in :
https://sourceware.org/ml/gdb-patches/2015-04/msg01110.html

These too simple implementations conflict with ongoing work to make proper
implementations of software single stepping in GDBServer.

The problem is that if some implementations are correct and others are not and
only there for the thread magic breakpoint, we can't enable features based
solely software single step support since some would be broken.

To keep the incorrect implementations and allow the new proper ones at the same
time we would need to implement fallback code and it quickly becomes ugly and
confusing with multiple checks for legacy software single step or proper
software single step.

However, PTRACE_EVENT_CLONE was first introduced in Linux 2.5.46,
released in November 2002.

So I think it's reasonable to just remove support for kernels that don't support
PTRACE_EVENT_CLONE, and sidestep the libthread_db breakpoints issues entirely.

This thread on the mailling list discusses the issue :
https://sourceware.org/ml/gdb/2015-10/msg00078.html

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/gdbserver/ChangeLog:

	* linux-low.c (linux_look_up_symbols): Don't call
	linux_supports_traceclone.
	* linux-low.h (thread_db_init): Remove use_events argument.
	* thread-db.c (thread_db_use_event): Remove global variable.
	(struct thread_db) <td_thr_event_enable_p>: Remove field.
	(struct thread_db) <td_create_bp>: Remove field.
	(thread_db_create_event): Remove function.
	(thread_db_enable_reporting): Likewise.
	(find_one_thread): Don't check for thread_db_use_events.
	(attach_thread): Likewise.
	(thread_db_load_search): Remove td_thr_event_enable_p initialization.
	(try_thread_db_load_1): Don't check for thread_db_use_events.
	(thread_db_init): Remove use_events argument and thread events
	handling.
	(remove_thread_event_breakpoints): Remove function.
	(thread_db_detach): Remove call to remove_thred_event_breakpoints.
---
 gdb/gdbserver/linux-low.c |   2 +-
 gdb/gdbserver/linux-low.h |   2 +-
 gdb/gdbserver/thread-db.c | 153 ++--------------------------------------------
 3 files changed, 6 insertions(+), 151 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index ceddf4d..a3b0f3a 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5515,7 +5515,7 @@ linux_look_up_symbols (void)
   /* If the kernel supports tracing clones, then we don't need to
      use the magic thread event breakpoint to learn about
      threads.  */
-  thread_db_init (!linux_supports_traceclone ());
+  thread_db_init ();
 #endif
 }
 
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 2e1f32f..d60d97d 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -379,7 +379,7 @@ void initialize_regsets_info (struct regsets_info *regsets_info);
 void initialize_low_arch (void);
 
 /* From thread-db.c  */
-int thread_db_init (int use_events);
+int thread_db_init (void);
 void thread_db_detach (struct process_info *);
 void thread_db_mourn (struct process_info *);
 int thread_db_handle_monitor_command (char *);
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
index 3df10ff..8b3057a 100644
--- a/gdb/gdbserver/thread-db.c
+++ b/gdb/gdbserver/thread-db.c
@@ -24,8 +24,6 @@
 
 extern int debug_threads;
 
-static int thread_db_use_events;
-
 #include "gdb_proc_service.h"
 #include "nat/gdb_thread_db.h"
 #include "gdb_vecs.h"
@@ -56,16 +54,6 @@ struct thread_db
   void *handle;
 #endif
 
-  /* Thread creation event breakpoint.  The code at this location in
-     the child process will be called by the pthread library whenever
-     a new thread is created.  By setting a special breakpoint at this
-     location, GDB can detect when a new thread is created.  We obtain
-     this location via the td_ta_event_addr call.  Note that if the
-     running kernel supports tracing clones, then we don't need to use
-     (and in fact don't use) this magic thread event breakpoint to
-     learn about threads.  */
-  struct breakpoint *td_create_bp;
-
   /* Addresses of libthread_db functions.  */
   td_ta_new_ftype *td_ta_new_p;
   td_ta_event_getmsg_ftype * td_ta_event_getmsg_p;
@@ -73,7 +61,6 @@ struct thread_db
   td_ta_event_addr_ftype *td_ta_event_addr_p;
   td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
   td_thr_get_info_ftype *td_thr_get_info_p;
-  td_thr_event_enable_ftype *td_thr_event_enable_p;
   td_ta_thr_iter_ftype *td_ta_thr_iter_p;
   td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
   td_thr_tlsbase_ftype *td_thr_tlsbase_p;
@@ -172,84 +159,6 @@ thread_db_state_str (td_thr_state_e state)
 #endif
 
 static int
-thread_db_create_event (CORE_ADDR where)
-{
-  td_event_msg_t msg;
-  td_err_e err;
-  struct lwp_info *lwp;
-  struct thread_db *thread_db = current_process ()->priv->thread_db;
-
-  gdb_assert (thread_db->td_ta_event_getmsg_p != NULL);
-
-  if (debug_threads)
-    debug_printf ("Thread creation event.\n");
-
-  /* FIXME: This assumes we don't get another event.
-     In the LinuxThreads implementation, this is safe,
-     because all events come from the manager thread
-     (except for its own creation, of course).  */
-  err = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
-  if (err != TD_OK)
-    fprintf (stderr, "thread getmsg err: %s\n",
-	     thread_db_err_str (err));
-
-  /* If we do not know about the main thread yet, this would be a good time to
-     find it.  We need to do this to pick up the main thread before any newly
-     created threads.  */
-  lwp = get_thread_lwp (current_thread);
-  if (lwp->thread_known == 0)
-    find_one_thread (current_thread->entry.id);
-
-  /* msg.event == TD_EVENT_CREATE */
-
-  find_new_threads_callback (msg.th_p, NULL);
-
-  return 0;
-}
-
-static int
-thread_db_enable_reporting (void)
-{
-  td_thr_events_t events;
-  td_notify_t notify;
-  td_err_e err;
-  struct thread_db *thread_db = current_process ()->priv->thread_db;
-
-  if (thread_db->td_ta_set_event_p == NULL
-      || thread_db->td_ta_event_addr_p == NULL
-      || thread_db->td_ta_event_getmsg_p == NULL)
-    /* This libthread_db is missing required support.  */
-    return 0;
-
-  /* Set the process wide mask saying which events we're interested in.  */
-  td_event_emptyset (&events);
-  td_event_addset (&events, TD_CREATE);
-
-  err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
-  if (err != TD_OK)
-    {
-      warning ("Unable to set global thread event mask: %s",
-	       thread_db_err_str (err));
-      return 0;
-    }
-
-  /* Get address for thread creation breakpoint.  */
-  err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
-				       &notify);
-  if (err != TD_OK)
-    {
-      warning ("Unable to get location for thread creation breakpoint: %s",
-	       thread_db_err_str (err));
-      return 0;
-    }
-  thread_db->td_create_bp
-    = set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
-			 thread_db_create_event);
-
-  return 1;
-}
-
-static int
 find_one_thread (ptid_t ptid)
 {
   td_thrhandle_t th;
@@ -287,14 +196,6 @@ find_one_thread (ptid_t ptid)
       return 0;
     }
 
-  if (thread_db_use_events)
-    {
-      err = thread_db->td_thr_event_enable_p (&th, 1);
-      if (err != TD_OK)
-	error ("Cannot enable thread event reporting for %d: %s",
-	       ti.ti_lid, thread_db_err_str (err));
-    }
-
   /* If the new thread ID is zero, a final thread ID will be available
      later.  Do not enable thread debugging yet.  */
   if (ti.ti_tid == 0)
@@ -334,17 +235,6 @@ attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
   lwp->thread_known = 1;
   lwp->th = *th_p;
 
-  if (thread_db_use_events)
-    {
-      td_err_e err;
-      struct thread_db *thread_db = proc->priv->thread_db;
-
-      err = thread_db->td_thr_event_enable_p (th_p, 1);
-      if (err != TD_OK)
-	error ("Cannot enable thread event reporting for %d: %s",
-	       ti_p->ti_lid, thread_db_err_str (err));
-    }
-
   return 1;
 }
 
@@ -584,9 +474,6 @@ thread_db_load_search (void)
   tdb->td_ta_thr_iter_p = &td_ta_thr_iter;
   tdb->td_symbol_list_p = &td_symbol_list;
 
-  /* This is required only when thread_db_use_events is on.  */
-  tdb->td_thr_event_enable_p = &td_thr_event_enable;
-
   /* These are not essential.  */
   tdb->td_ta_event_addr_p = &td_ta_event_addr;
   tdb->td_ta_set_event_p = &td_ta_set_event;
@@ -654,9 +541,6 @@ try_thread_db_load_1 (void *handle)
   CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter));
   CHK (1, TDB_DLSYM (tdb, td_symbol_list));
 
-  /* This is required only when thread_db_use_events is on.  */
-  CHK (thread_db_use_events, TDB_DLSYM (tdb, td_thr_event_enable));
-
   /* These are not essential.  */
   CHK (0, TDB_DLSYM (tdb, td_ta_event_addr));
   CHK (0, TDB_DLSYM (tdb, td_ta_set_event));
@@ -824,7 +708,7 @@ thread_db_load_search (void)
 #endif  /* USE_LIBTHREAD_DB_DIRECTLY */
 
 int
-thread_db_init (int use_events)
+thread_db_init (void)
 {
   struct process_info *proc = current_process ();
 
@@ -839,31 +723,21 @@ thread_db_init (int use_events)
      This isn't the only place in gdbserver that assumes that the first
      process in the list is the thread group leader.  */
 
-  thread_db_use_events = use_events;
-
   if (thread_db_load_search ())
     {
-      if (use_events && thread_db_enable_reporting () == 0)
-	{
-	  /* Keep trying; maybe event reporting will work later.  */
-	  thread_db_mourn (proc);
-	  return 0;
-	}
-
       /* It's best to avoid td_ta_thr_iter if possible.  That walks
 	 data structures in the inferior's address space that may be
 	 corrupted, or, if the target is running, the list may change
 	 while we walk it.  In the latter case, it's possible that a
 	 thread exits just at the exact time that causes GDBserver to
-	 get stuck in an infinite loop.  If the kernel supports clone
-	 events, and /proc/PID/task/ exits, then we already know about
+	 get stuck in an infinite loop.  As the kernel supports clone
+	 events and /proc/PID/task/ exists, then we already know about
 	 all threads in the process.  When we need info out of
 	 thread_db on a given thread (e.g., for TLS), we'll use
 	 find_one_thread then.  That uses thread_db entry points that
 	 do not walk libpthread's thread list, so should be safe, as
 	 well as more efficient.  */
-      if (use_events
-	  || !linux_proc_task_list_dir_exists (pid_of (proc)))
+      if (!linux_proc_task_list_dir_exists (pid_of (proc)))
 	thread_db_find_new_threads ();
       thread_db_look_up_symbols ();
       return 1;
@@ -929,24 +803,6 @@ disable_thread_event_reporting (struct process_info *proc)
     }
 }
 
-static void
-remove_thread_event_breakpoints (struct process_info *proc)
-{
-  struct thread_db *thread_db = proc->priv->thread_db;
-
-  if (thread_db->td_create_bp != NULL)
-    {
-      struct thread_info *saved_thread = current_thread;
-
-      switch_to_process (proc);
-
-      delete_breakpoint (thread_db->td_create_bp);
-      thread_db->td_create_bp = NULL;
-
-      current_thread = saved_thread;
-    }
-}
-
 void
 thread_db_detach (struct process_info *proc)
 {
@@ -955,7 +811,6 @@ thread_db_detach (struct process_info *proc)
   if (thread_db)
     {
       disable_thread_event_reporting (proc);
-      remove_thread_event_breakpoints (proc);
     }
 }
 
-- 
2.6.2


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 02/10] Fix instruction skipping when using software single step in GDBServer
  2015-10-29 17:48 ` [PATCH 02/10] Fix instruction skipping when using software single step " Antoine Tremblay
@ 2015-11-04 18:08   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:08 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:

> ---
>  gdb/gdbserver/linux-low.c | 23 +++++++++++++++--------
>  gdb/gdbserver/mem-break.c | 17 +++++++++++++++++
>  gdb/gdbserver/mem-break.h |  4 ++++
>  3 files changed, 36 insertions(+), 8 deletions(-)
> 
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index 3b6c131..853a289 100644
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -2993,14 +2993,21 @@ linux_wait_1 (ptid_t ptid,
>        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)
> +  /* If step-over executes a breakpoint instruction, in the case of a
> +     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 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
> +     if it's not the reinsert_breakpoint we are hitting.
> +     This avoids that a program would keep trapping a permanent breakpoint
> +     forever.  */
> +  if ((!ptid_equal (step_over_bkpt, null_ptid)
> +       && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) &&
> +      (event_child->stepping ||
> +       !reinsert_breakpoint_inserted_here (event_child->stop_pc)))

Formatting isn't right.  && and || go at the beginning of the next line.
Unnecessary parens.  Like:

  if (!ptid_equal (step_over_bkpt, null_ptid)
      && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT
      && (event_child->stepping
          || !reinsert_breakpoint_inserted_here (event_child->stop_pc)))

Looks good to me with that change.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
  2015-11-03 17:05   ` Yao Qi
@ 2015-11-04 18:19   ` Pedro Alves
  2015-11-05 11:43     ` Antoine Tremblay
  1 sibling, 1 reply; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:19 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch removes support for thread events if TRACE_EVENT_CLONE is not
> supported in GDBServer.

(I had never seen it spelled without the leading P(RACE_EVENT_CLONE).
Is that a typo?  (subject too).)

> 
> Before, on systems that did not support PTRACE_EVENT_CLONE, both GDB and
> GDBServer coordinated with libthread_db.so to insert breakpoints at magic
> locations in libpthread.so, in order to break at thread creation and thread
> death.
> 
> Simple software single stepping support was implemented to step over these
> breakpoints in case there was no hardware single stepping support. However,
> these simple software single stepping implementations were not fit for any other
> use as discussed in :
> https://sourceware.org/ml/gdb-patches/2015-04/msg01110.html
> 
> These too simple implementations conflict with ongoing work to make proper
> implementations of software single stepping in GDBServer.
> 
> The problem is that if some implementations are correct and others are not and
> only there for the thread magic breakpoint, we can't enable features based
> solely software single step support since some would be broken.
> 
> To keep the incorrect implementations and allow the new proper ones at the same
> time we would need to implement fallback code and it quickly becomes ugly and
> confusing with multiple checks for legacy software single step or proper
> software single step.
> 
> However, PTRACE_EVENT_CLONE was first introduced in Linux 2.5.46,
> released in November 2002.
> 
> So I think it's reasonable to just remove support for kernels that don't support
> PTRACE_EVENT_CLONE, and sidestep the libthread_db breakpoints issues entirely.
> 
> This thread on the mailling list discusses the issue :
> https://sourceware.org/ml/gdb/2015-10/msg00078.html
> 
> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
> With gdbserver-{native,extended} / { -marm -mthumb }
> 
> gdb/gdbserver/ChangeLog:
> 
> 	* linux-low.c (linux_look_up_symbols): Don't call
> 	linux_supports_traceclone.
> 	* linux-low.h (thread_db_init): Remove use_events argument.
> 	* thread-db.c (thread_db_use_event): Remove global variable.
> 	(struct thread_db) <td_thr_event_enable_ftype>: Remove field.
> 	(thread_db_create_event): Remove function.
> 	(thread_db_enable_reporting): Likewise.
> 	(find_one_thread): Don't check for thread_db_use_events.
> 	(attach_thread): Likewise.
> 	(thread_db_load_search): Remove td_thr_event_enable_p initialization.
> 	(try_thread_db_load_1): Don't check for thread_db_use_events.
> 	(thread_db_init): Remove use_events argument.
> 	(thread_db_init): Remove thread events handling.

LGTM.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations.
  2015-10-29 17:31 ` [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations Antoine Tremblay
@ 2015-11-04 18:21   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:21 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch removes too simple implementations of the breakpoint_reinsert_addr
> operation.
> 
> The only reason to keep them around was to support thread events when
> PTRACE_EVENT_CLONE was not present but this support has been removed in a
> previous patch.
> 
> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
> With gdbserver-{native,extended} / { -marm -mthumb }
> 
> Also compilation was tested on aarch64, bfin, cris, crisv32,
> m32r, mips, nios2, ppc, s390, sparc, tic6x, tile,  xtensa.
> 
> gdb/gdbserver/ChangeLog:
> 
> 	* linux-arm-low.c (arm_reinsert_addr): Remove function.
> 	(struct linux_target_ops <breakpoint_reinsert_addr>: Set to NULL.
> 	* linux-cris-low.c (cris_reinsert_addr> Remove function.
> 	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
> 	* linux-crisv32-low.c (cris_reinsert_addr): Remove function.
> 	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
> 	* linux-mips-low.c (mips_reinsert_addr): Remove function.
> 	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
> 	* linux-nios2-low.c (nios2_reinsert_addr): Remove function.
> 	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL.
> 	* linux-sparc-low.c (sparc_reinsert_addr): Remove function.
> 	(struct linux_target_ops) <breakpoint_reinsert_addr>: Set to NULL;

Typo in last "Set to NULL;".

Otherwise LGTM.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 08/10] Support software single step on ARM in GDBServer.
  2015-10-29 17:43 ` [PATCH 08/10] Support software single step on ARM " Antoine Tremblay
@ 2015-11-04 18:46   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:46 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch teaches GDBserver how to software single step on ARM
> linux by sharing code with GDB.
> 
> The arm_get_next_pcs function in GDB is now shared with GDBServer.  So that
> GDBServer can use the function to return the possible addresses of the next PC.
> 
> A proper shared context was also needed so that we could share the code, this
> context is described as this data structure (expressed as a class
> hierarchy):
> 
> struct get_next_pcs
>   struct os_arch_get_next_pcs
>     struct os_arch_(gdb|gdbserver)_get_next_pcs
> 
> Where arch can by replaced by arm for this patch. This structure should be
> flexible enough to accomodate any arch or os (optional) that would need a
> get_next_pcs context.

Thanks for following through with this.  I skimmed this and it looks very
much like what I had imagined, so LGTM from a general design perspective.
But I'd rather leave it to Yao to go over the ARM details.

(BTW, I noticed several formatting problems just from skimming.  I'd be good
if you did a pass over the patch fixing them; I'm sure you'll notice them too.)

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 03/10] Refactor queries for hardware and software single stepping support in GDBServer.
  2015-10-29 17:28 ` [PATCH 03/10] Refactor queries for hardware and software single stepping support " Antoine Tremblay
@ 2015-11-04 18:47   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:47 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> Before this patch there was only one call: can_hardware_single_step. Its
> implementation was a check on breakpoint_reinsert_addr if NULL it assumed
> that the target could hardware single step.
> 
> This patch prepares for the case where this is not true anymore.
> 
> In order to improve software single stepping in GDBServer the
> breakpoint_reinsert_addr operation of targets that had a very simple
> software implementation used only for stepping over thread creation events
> will be removed.
> 
> This will create a case where a target does not support hardware single
> step and has the operation breakpoint_reinsert_addr set to NULL, thus
> can_hardware_single_step needs to be implemented another way.
> 
> A new target operation supports_hardware_single_step is introduced and is
> to return true if the target does support such a feature, support for the
> feature is manually hardcoded.
> 
> Note that the hardware single step support was enabled as per the current
> behavior, I did not check if tile for example really has ptrace singlestep
> support but since the current implementation assumed it had, I kept it
> that way.
> 
> No regressions on Ubuntu 14.04 on ARMv7 and x86.
> With gdbserver-{native,extended} / { -marm -mthumb }
> 
> Compilation tested on: aarch64,arm,bfind,crisv32,m32r,ppc,s390,tic6x,tile,
> xtensa.
> Not tested : sh.
> 
> gdb/gdbserver/ChangeLog:
> 
> 	* linux-aarch64-low.c (aarch64_supports_hardware_single_step):
> 	New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-arm-low.c (arm_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-bfin-low.c (bfin_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <bfin_supports_hardware_single_step>:
> 	Initialize.
> 	* linux-crisv32-low.c (cris_supports_hardware_single_step):
> 	New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-low.c (can_hardware_single_step): Use
> 	supports_hardware_single_step.
> 	(can_software_single_step): New function.
> 	(start_step_over): Call can_software_single_step.
> 	(linux_supports_hardware_single_step): New function.
> 	(struct target_ops) <supports_software_single_step>: Initialize.
> 	* linux-low.h (struct linux_target_ops)
> 	<supports_hardware_single_step>: Initialize.
> 	* linux-m32r-low.c (m32r_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-ppc-low.c (ppc_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <supports_hardware_single_step> Initialize.
> 	* linux-s390-low.c (s390_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-sh-low.c (sh_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-tic6x-low.c (tic6x_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <tic6x_supports_hardware_single_step>:
> 	Initialize.
> 	* linux-tile-low.c (tile_supports_hardware_single_step): New function.
> 	(struct linux_target_ops) <tile_supports_hardware_single_step>:
> 	Initialize.
> 	* linux-x86-low.c (x86_supports_hardware_single_step) New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* linux-xtensa-low.c (xtensa_supports_hardware_single_step):
> 	New function.
> 	(struct linux_target_ops) <supports_hardware_single_step>: Initialize.
> 	* target.h (struct target_ops): <supports_software_single_step>:
> 	New field.
> 	(target_supports_software_single_step): New macro.

LGTM.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation in GDBServer.
  2015-10-29 17:45 ` [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation " Antoine Tremblay
@ 2015-11-04 18:48   ` Pedro Alves
  2015-11-05 14:35     ` Antoine Tremblay
  0 siblings, 1 reply; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:48 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch in preparation for software single step support on ARM. It refactors
> breakpoint_reinsert_addr into get_next_pcs so that multiple location can be
> returned.
> 
> When software single stepping there can be multiple possible next addresses
> because we're stepping over a branch instruction for example.

ITYM mean a _conditional_ branch instruction.

> 
> The operation get_next_pcs handles that by returning a vector of all the
> possible next addresses.
> 
> Software breakpoints are installed at each location returned.
> 
> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
> With gdbserver-{native,extended} / { -marm -mthumb }
> 
> gdb/ChangeLog:
> 
> 	* common/get-next-pcs.h: New file.
> 	* common/gdb_vecs.h: Add CORE_ADDR vect.
> 	* symtab.h: Move CORE_ADDR vect to gdb_vecs.h

Missing period in last line.  (Pedantically, AFAICS, in this patch,
nothing in gdb includes common/get-next-pcs.h, and nothing
in gdbserver includes symtab.h.  So seems like putting the VEC
in common/gdb_vecs.h here is premature.)

> 
> gdb/gdbserver/ChangeLog:
> 	* linux-aarch64-low.c (struct linux_target_ops): Rename
> 	breakpoint_reinsert_addr to get_next_pcs.
> 	* linux-arm-low.c (struct linux_target_ops): Likewise.
> 	* linux-bfin-low.c (struct linux_target_ops): Likewise.
> 	* linux-cris-low.c (struct linux_target_ops): Likewise.
> 	* linux-crisv32-low.c (struct linux_target_ops): Likewise.
> 	* linux-low.c (can_software_single_step): Likewise.
> 	(install_software_single_step_breakpoints): New function.
> 	(start_step_over): Use isntall_software_single_step_breakpoints.
> 	* linux-low.h: Rename breakpoint_reinsert_addr to
> 	get_next_pcs.
> 	* linux-mips-low.c (struct linux_target_ops): Likewise.
> 	* linux-nios2-low.c (struct linux_target_ops): Likewise.
> 	* linux-sparc-low.c (struct linux_target_ops): Likewise.


This LGTM.  Some nits below.

> +++ b/gdb/common/get-next-pcs.h
> @@ -0,0 +1,34 @@
> +/* Common code for software single stepping support.
> +
> +   Copyright (C) 2015 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GET_NEXT_PCS_H
> +#define GET_NEXT_PCS_H 1
> +
> +#include "gdb_vecs.h"
> +
> +struct get_next_pcs

There should be an intro comment mentioning the purpose of
this structure.

> +{
> +  /* Resulting vector of possible next addresses.  */
> +  VEC (CORE_ADDR) *result;
> +  /* Base PC from which to get the next pcs.  */
> +  CORE_ADDR pc;
> +  struct regcache* regcache;

This field should be documented too.

> +};
> +
> +#endif /* GET_NEXT_PCS_H */
> diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
> index a0bc1c2..3e21042 100644
> --- a/gdb/gdbserver/linux-aarch64-low.c
> +++ b/gdb/gdbserver/linux-aarch64-low.c
> @@ -2959,7 +2959,7 @@ struct linux_target_ops the_low_target =
>    aarch64_set_pc,
>    NULL, /* breakpoint_kind_from_pc */
>    aarch64_sw_breakpoint_from_kind,
> -  NULL, /* breakpoint_reinsert_addr */
> +  NULL, /* get_next_pcs */
>    0,    /* decr_pc_after_break */
>    aarch64_breakpoint_at,
>    aarch64_supports_z_point_type,
> diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
> index 8e32fae..0b87367 100644
> --- a/gdb/gdbserver/linux-arm-low.c
> +++ b/gdb/gdbserver/linux-arm-low.c
> @@ -1027,7 +1027,7 @@ struct linux_target_ops the_low_target = {
>    arm_set_pc,
>    arm_breakpoint_kind_from_pc,
>    arm_sw_breakpoint_from_kind,
> -  NULL, /* breakpoint_reinsert_addr */
> +  NULL, /* get_next_pcs */
>    0,
>    arm_breakpoint_at,
>    arm_supports_z_point_type,
> diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c
> index 912d253..1de2f78 100644
> --- a/gdb/gdbserver/linux-bfin-low.c
> +++ b/gdb/gdbserver/linux-bfin-low.c
> @@ -141,7 +141,7 @@ struct linux_target_ops the_low_target = {
>    bfin_set_pc,
>    NULL, /* breakpoint_kind_from_pc */
>    bfin_sw_breakpoint_from_kind,
> -  NULL, /* breakpoint_reinsert_addr */
> +  NULL, /* get_next_pcs */
>    2,
>    bfin_breakpoint_at,
>    NULL, /* supports_z_point_type */
> diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c
> index 9f4519c..6902a45 100644
> --- a/gdb/gdbserver/linux-cris-low.c
> +++ b/gdb/gdbserver/linux-cris-low.c
> @@ -139,7 +139,7 @@ struct linux_target_ops the_low_target = {
>    cris_set_pc,
>    NULL, /* breakpoint_kind_from_pc */
>    cris_sw_breakpoint_from_kind,
> -  NULL, /* breakpoint_reinsert_addr */
> +  NULL, /* get_next_pcs */
>    0,
>    cris_breakpoint_at,
>  };
> diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
> index 2404d0e..28c1981 100644
> --- a/gdb/gdbserver/linux-crisv32-low.c
> +++ b/gdb/gdbserver/linux-crisv32-low.c
> @@ -422,7 +422,7 @@ struct linux_target_ops the_low_target = {
>    cris_set_pc,
>    NULL, /* breakpoint_kind_from_pc */
>    cris_sw_breakpoint_from_kind,
> -  NULL, /* breakpoint_reinsert_addr */
> +  NULL, /* get_next_pcs */
>    0,
>    cris_breakpoint_at,
>    cris_supports_z_point_type,
> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
> index a3b0f3a..1f423ba 100644
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -54,6 +54,7 @@
>  #include <elf.h>
>  #endif
>  #include "nat/linux-namespaces.h"
> +#include "common/get-next-pcs.h"
>  
>  #ifndef SPUFS_MAGIC
>  #define SPUFS_MAGIC 0x23c9b64e
> @@ -281,12 +282,12 @@ can_hardware_single_step (void)
>  }
>  
>  /* True if the low target can software single-step.  Such targets
> -   implement the BREAKPOINT_REINSERT_ADDR callback.  */
> +   implement the GET_NEXT_PCS callback.  */
>  
>  static int
>  can_software_single_step (void)
>  {
> -  return (the_low_target.breakpoint_reinsert_addr != NULL);
> +  return (the_low_target.get_next_pcs != NULL);
>  }
>  
>  /* True if the low target supports memory breakpoints.  If so, we'll
> @@ -3876,6 +3877,29 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info)
>    lwp->pending_signals = p_sig;
>  }
>  
> +/* Install breakpoints for software single stepping.  */
> +
> +static void
> +install_software_single_step_breakpoints (struct lwp_info *lwp)
> +{
> +  struct get_next_pcs next_pcs;
> +  int i;
> +  CORE_ADDR pc;
> +
> +  struct regcache *regcache = get_thread_regcache (current_thread, 1);

Formatting.  Variable should be declared in the declaration block
along with the others, and then there should be a line break.

> +  next_pcs.pc = get_pc (lwp);
> +  next_pcs.regcache = regcache;
> +  next_pcs.result = VEC_alloc (CORE_ADDR, 1);

Is there a reason to allocate upfront instead of setting it to NULL?

> +  (*the_low_target.get_next_pcs) (&next_pcs);
> +
> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs.result, i, pc); ++i)
> +    {
> +      set_reinsert_breakpoint (pc);
> +    }

At some point we should do a pass and rename "reinsert breakpoint"
to "software single-step breakpoint" throughout.  It's no longer
just about reinserting a breakpoint that we step over.

> +
> +  VEC_free (CORE_ADDR, next_pcs.result);
> +}
> +



Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer.
  2015-10-29 17:16 ` [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer Antoine Tremblay
@ 2015-11-04 18:55   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:55 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch enables software single stepping if the targets supports it,
> to do while-stepping actions.


> +  if (thread->while_stepping != NULL) {
> +    if (debug_threads)
> +      debug_printf ("lwp %ld has a while-stepping action -> forcing step.\n",
> +		    lwpid_of (thread));

  if (thread->while_stepping != NULL)
    {

Otherwise LGTM.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 10/10] Enable conditional breakpoints for targets that support software single step in GDBServer.
  2015-10-29 17:15 ` [PATCH 10/10] Enable conditional breakpoints for targets that support software single step " Antoine Tremblay
@ 2015-11-04 18:58   ` Pedro Alves
  0 siblings, 0 replies; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 18:58 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:

>  
> -      if (target_supports_hardware_single_step ())
> +      if (target_supports_hardware_single_step () ||
> +	  target_supports_software_single_step () )

|| on the next line.

Otherwise LGTM.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer.
  2015-10-29 17:15 ` [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer Antoine Tremblay
@ 2015-11-04 19:56   ` Pedro Alves
  2015-11-05 14:44     ` Antoine Tremblay
  0 siblings, 1 reply; 28+ messages in thread
From: Pedro Alves @ 2015-11-04 19:56 UTC (permalink / raw)
  To: Antoine Tremblay, gdb-patches

On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
> This patch is in preparation for software single stepping support on ARM it
> shares some functions and defenitions that will be needed.
> 
> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
> With gdbserver-{native,extended} / { -marm -mthumb }
> 
> Not tested : wince/bsd build.

Please make sure that --enable-targets=all still builds.

> 
> gdb/ChangeLog:
> 
> 	* arch/arm.c (bitcount): Move from arm-tdep.c
> 	(condition_true): Likewise.
> 	* arch/arm.h (Instruction Definitions): Move form arm-tdep.h.
> 	(condition_true): Move defenition from arm-tdep.h
> 	(bitcount): Likewise.
> 	* arm-tdep.c (condition_true): Move to arch/arm.c.
> 	(bitcount): Likewise.
> 	* arm-tdep.h (Instruction Definitions): Move to arch/arm.h.
> 	* arm-wince-tdep.c: Include arch/arm.h.
> 	* armnbsd-tdep.c: Likewise.

Missing a couple periods.

> +/* Returns true of the condition evaluates to true.  */

s/of/if/ ?

> +
> +int
> +condition_true (unsigned long cond, unsigned long status_reg)
> +{


> +
>  /* Addresses for calling Thumb functions have the bit 0 set.
>     Here are some macros to test, set, or clear bit 0 of addresses.  */
>  #define IS_THUMB_ADDR(addr)    ((addr) & 1)
> @@ -68,4 +98,10 @@ enum gdb_regnum {
>     first halfword is INST1.  */
>  int thumb_insn_size (unsigned short inst1);
>  
> +/* Returns true of the condition evaluates to true.  */

Likewise.

> +int condition_true (unsigned long cond, unsigned long status_reg);
> +
> +/* Return number of 1-bits in VAL.  */
> +int bitcount (unsigned long val);

These comments are duplicated though.  The .c file's comments should
instead point to the .h file.

Thanks,
Pedro Alves


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE in GDBServer.
  2015-11-04 18:19   ` [PATCH 04/10] " Pedro Alves
@ 2015-11-05 11:43     ` Antoine Tremblay
  0 siblings, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-05 11:43 UTC (permalink / raw)
  To: gdb-patches@sourceware.org >> GDB



On 11/04/2015 01:19 PM, Pedro Alves wrote:
> On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
>> This patch removes support for thread events if TRACE_EVENT_CLONE is not
>> supported in GDBServer.
>
> (I had never seen it spelled without the leading P(RACE_EVENT_CLONE).
> Is that a typo?  (subject too).)
>

Indeed it was, weird, fixed. thank you.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation in GDBServer.
  2015-11-04 18:48   ` Pedro Alves
@ 2015-11-05 14:35     ` Antoine Tremblay
  0 siblings, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-05 14:35 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches



On 11/04/2015 01:48 PM, Pedro Alves wrote:
> On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
>> This patch in preparation for software single step support on ARM. It refactors
>> breakpoint_reinsert_addr into get_next_pcs so that multiple location can be
>> returned.
>>
>> When software single stepping there can be multiple possible next addresses
>> because we're stepping over a branch instruction for example.
>
> ITYM mean a _conditional_ branch instruction.
>

Yes, fixed.

>>
>> The operation get_next_pcs handles that by returning a vector of all the
>> possible next addresses.
>>
>> Software breakpoints are installed at each location returned.
>>
>> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
>> With gdbserver-{native,extended} / { -marm -mthumb }
>>
>> gdb/ChangeLog:
>>
>> 	* common/get-next-pcs.h: New file.
>> 	* common/gdb_vecs.h: Add CORE_ADDR vect.
>> 	* symtab.h: Move CORE_ADDR vect to gdb_vecs.h
>
> Missing period in last line.  (Pedantically, AFAICS, in this patch,
> nothing in gdb includes common/get-next-pcs.h, and nothing
> in gdbserver includes symtab.h.  So seems like putting the VEC
> in common/gdb_vecs.h here is premature.)
>

Yes I could do another patch with just that change since I really wanted 
it to be out of the big 08/10 Support software single step on ARM in 
GDBServer patch, but that would kinda remove some context and it would 
still be premature in the same way.

Same applies to 07/10 Share some ARM target dependant code from GDB with 
GDBServer...

I'm keeping it there in the context that this is a preparatory patch 
unless there's an objection.

>>
>> gdb/gdbserver/ChangeLog:
>> 	* linux-aarch64-low.c (struct linux_target_ops): Rename
>> 	breakpoint_reinsert_addr to get_next_pcs.
>> 	* linux-arm-low.c (struct linux_target_ops): Likewise.
>> 	* linux-bfin-low.c (struct linux_target_ops): Likewise.
>> 	* linux-cris-low.c (struct linux_target_ops): Likewise.
>> 	* linux-crisv32-low.c (struct linux_target_ops): Likewise.
>> 	* linux-low.c (can_software_single_step): Likewise.
>> 	(install_software_single_step_breakpoints): New function.
>> 	(start_step_over): Use isntall_software_single_step_breakpoints.
>> 	* linux-low.h: Rename breakpoint_reinsert_addr to
>> 	get_next_pcs.
>> 	* linux-mips-low.c (struct linux_target_ops): Likewise.
>> 	* linux-nios2-low.c (struct linux_target_ops): Likewise.
>> 	* linux-sparc-low.c (struct linux_target_ops): Likewise.
>
>
> This LGTM.  Some nits below.
>
>> +++ b/gdb/common/get-next-pcs.h
>> @@ -0,0 +1,34 @@
>> +/* Common code for software single stepping support.
>> +
>> +   Copyright (C) 2015 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef GET_NEXT_PCS_H
>> +#define GET_NEXT_PCS_H 1
>> +
>> +#include "gdb_vecs.h"
>> +
>> +struct get_next_pcs
>
> There should be an intro comment mentioning the purpose of
> this structure.
>
Done as :

/* This structure contains the shared context of a get_next_pcs call, as
    used in linux target operation "get_next_pcs" in GDBServer and the
    software_single_step architecture dependent function in GDB.  */

>> +{
>> +  /* Resulting vector of possible next addresses.  */
>> +  VEC (CORE_ADDR) *result;
>> +  /* Base PC from which to get the next pcs.  */
>> +  CORE_ADDR pc;
>> +  struct regcache* regcache;
>
> This field should be documented too.
>

Done.

>> @@ -3876,6 +3877,29 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info)
>>     lwp->pending_signals = p_sig;
>>   }
>>
>> +/* Install breakpoints for software single stepping.  */
>> +
>> +static void
>> +install_software_single_step_breakpoints (struct lwp_info *lwp)
>> +{
>> +  struct get_next_pcs next_pcs;
>> +  int i;
>> +  CORE_ADDR pc;
>> +
>> +  struct regcache *regcache = get_thread_regcache (current_thread, 1);
>
> Formatting.  Variable should be declared in the declaration block
> along with the others, and then there should be a line break.
>

Done thanks,

>> +  next_pcs.pc = get_pc (lwp);
>> +  next_pcs.regcache = regcache;
>> +  next_pcs.result = VEC_alloc (CORE_ADDR, 1);
>
> Is there a reason to allocate upfront instead of setting it to NULL?
>

No that was a mistake, fixed.

>> +  (*the_low_target.get_next_pcs) (&next_pcs);
>> +
>> +  for (i = 0; VEC_iterate (CORE_ADDR, next_pcs.result, i, pc); ++i)
>> +    {
>> +      set_reinsert_breakpoint (pc);
>> +    }
>
> At some point we should do a pass and rename "reinsert breakpoint"
> to "software single-step breakpoint" throughout.  It's no longer
> just about reinserting a breakpoint that we step over.
>

Ok, noted.

Thanks,
Antoine Tremblay


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer.
  2015-11-04 19:56   ` Pedro Alves
@ 2015-11-05 14:44     ` Antoine Tremblay
  0 siblings, 0 replies; 28+ messages in thread
From: Antoine Tremblay @ 2015-11-05 14:44 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches



On 11/04/2015 02:56 PM, Pedro Alves wrote:
> On 10/29/2015 05:09 PM, Antoine Tremblay wrote:
>> This patch is in preparation for software single stepping support on ARM it
>> shares some functions and defenitions that will be needed.
>>
>> No regressions, tested on ubuntu 14.04 ARMv7 and x86.
>> With gdbserver-{native,extended} / { -marm -mthumb }
>>
>> Not tested : wince/bsd build.
>
> Please make sure that --enable-targets=all still builds.
>

Yes that builds, I mean I have not tested the host build of wince/bsd.

>>
>> gdb/ChangeLog:
>>
>> 	* arch/arm.c (bitcount): Move from arm-tdep.c
>> 	(condition_true): Likewise.
>> 	* arch/arm.h (Instruction Definitions): Move form arm-tdep.h.
>> 	(condition_true): Move defenition from arm-tdep.h
>> 	(bitcount): Likewise.
>> 	* arm-tdep.c (condition_true): Move to arch/arm.c.
>> 	(bitcount): Likewise.
>> 	* arm-tdep.h (Instruction Definitions): Move to arch/arm.h.
>> 	* arm-wince-tdep.c: Include arch/arm.h.
>> 	* armnbsd-tdep.c: Likewise.
>
> Missing a couple periods.
>

Done.

>> +/* Returns true of the condition evaluates to true.  */
>
> s/of/if/ ?
>

Done.

>> +
>> +int
>> +condition_true (unsigned long cond, unsigned long status_reg)
>> +{
>
>
>> +
>>   /* Addresses for calling Thumb functions have the bit 0 set.
>>      Here are some macros to test, set, or clear bit 0 of addresses.  */
>>   #define IS_THUMB_ADDR(addr)    ((addr) & 1)
>> @@ -68,4 +98,10 @@ enum gdb_regnum {
>>      first halfword is INST1.  */
>>   int thumb_insn_size (unsigned short inst1);
>>
>> +/* Returns true of the condition evaluates to true.  */
>
> Likewise.
>

Done/Moved.

>> +int condition_true (unsigned long cond, unsigned long status_reg);
>> +
>> +/* Return number of 1-bits in VAL.  */
>> +int bitcount (unsigned long val);
>
> These comments are duplicated though.  The .c file's comments should
> instead point to the .h file.

Done.

See v2 below : OK for master ?

-----

commit 61d17a90b6d011914c382fb18a5670e9dc6612b4
Author: Antoine Tremblay <antoine.tremblay@ericsson.com>
Date:   Thu Oct 29 10:54:47 2015 -0400

     Share some ARM target dependant code from GDB with GDBServer.

     This patch is in preparation for software single stepping support
     on ARM it shares some functions and defenitions that will be needed.

     No regressions, tested on ubuntu 14.04 ARMv7 and x86.
     With gdbserver-{native,extended} / { -marm -mthumb }

     Not tested : wince/bsd build.

     gdb/ChangeLog:

     	* arch/arm.c (bitcount): Move from arm-tdep.c.
     	(condition_true): Likewise.
     	* arch/arm.h (Instruction Definitions): Move form arm-tdep.h.
     	(condition_true): Move defenition from arm-tdep.h.
     	(bitcount): Likewise.
     	* arm-tdep.c (condition_true): Move to arch/arm.c.
     	(bitcount): Likewise.
     	* arm-tdep.h (Instruction Definitions): Move to arch/arm.h.
     	* arm-wince-tdep.c: Include arch/arm.h.
     	* armnbsd-tdep.c: Likewise.

diff --git a/gdb/arch/arm.c b/gdb/arch/arm.c
index b11c684..426377f 100644
--- a/gdb/arch/arm.c
+++ b/gdb/arch/arm.c
@@ -20,8 +20,7 @@
  #include "common-defs.h"
  #include "arm.h"

-/* Return the size in bytes of the complete Thumb instruction whose
-   first halfword is INST1.  */
+/* See arm.h.  */

  int
  thumb_insn_size (unsigned short inst1)
@@ -31,3 +30,60 @@ thumb_insn_size (unsigned short inst1)
    else
      return 2;
  }
+
+/* See arm.h.  */
+
+int
+bitcount (unsigned long val)
+{
+  int nbits;
+  for (nbits = 0; val != 0; nbits++)
+    val &= val - 1;		/* Delete rightmost 1-bit in val.  */
+  return nbits;
+}
+
+/* See arm.h.  */
+
+int
+condition_true (unsigned long cond, unsigned long status_reg)
+{
+  if (cond == INST_AL || cond == INST_NV)
+    return 1;
+
+  switch (cond)
+    {
+    case INST_EQ:
+      return ((status_reg & FLAG_Z) != 0);
+    case INST_NE:
+      return ((status_reg & FLAG_Z) == 0);
+    case INST_CS:
+      return ((status_reg & FLAG_C) != 0);
+    case INST_CC:
+      return ((status_reg & FLAG_C) == 0);
+    case INST_MI:
+      return ((status_reg & FLAG_N) != 0);
+    case INST_PL:
+      return ((status_reg & FLAG_N) == 0);
+    case INST_VS:
+      return ((status_reg & FLAG_V) != 0);
+    case INST_VC:
+      return ((status_reg & FLAG_V) == 0);
+    case INST_HI:
+      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
+    case INST_LS:
+      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
+    case INST_GE:
+      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 
0));
+    case INST_LT:
+      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 
0));
+    case INST_GT:
+      return (((status_reg & FLAG_Z) == 0)
+	      && (((status_reg & FLAG_N) == 0)
+		  == ((status_reg & FLAG_V) == 0)));
+    case INST_LE:
+      return (((status_reg & FLAG_Z) != 0)
+	      || (((status_reg & FLAG_N) == 0)
+		  != ((status_reg & FLAG_V) == 0)));
+    }
+  return 1;
+}
diff --git a/gdb/arch/arm.h b/gdb/arch/arm.h
index a054776..1a877bc 100644
--- a/gdb/arch/arm.h
+++ b/gdb/arch/arm.h
@@ -58,6 +58,36 @@ enum gdb_regnum {
    ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM
  };

+/* Instruction condition field values.  */
+#define INST_EQ		0x0
+#define INST_NE		0x1
+#define INST_CS		0x2
+#define INST_CC		0x3
+#define INST_MI		0x4
+#define INST_PL		0x5
+#define INST_VS		0x6
+#define INST_VC		0x7
+#define INST_HI		0x8
+#define INST_LS		0x9
+#define INST_GE		0xa
+#define INST_LT		0xb
+#define INST_GT		0xc
+#define INST_LE		0xd
+#define INST_AL		0xe
+#define INST_NV		0xf
+
+#define FLAG_N		0x80000000
+#define FLAG_Z		0x40000000
+#define FLAG_C		0x20000000
+#define FLAG_V		0x10000000
+
+#define CPSR_T		0x20
+
+#define XPSR_T		0x01000000
+
+/* Size of integer registers.  */
+#define INT_REGISTER_SIZE		4
+
  /* Addresses for calling Thumb functions have the bit 0 set.
     Here are some macros to test, set, or clear bit 0 of addresses.  */
  #define IS_THUMB_ADDR(addr)    ((addr) & 1)
@@ -68,4 +98,10 @@ enum gdb_regnum {
     first halfword is INST1.  */
  int thumb_insn_size (unsigned short inst1);

+/* Returns true if the condition evaluates to true.  */
+int condition_true (unsigned long cond, unsigned long status_reg);
+
+/* Return number of 1-bits in VAL.  */
+int bitcount (unsigned long val);
+
  #endif
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 3a6c6d8..3eaf63e 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4252,50 +4252,6 @@ convert_to_extended (const struct floatformat 
*fmt, void *dbl, const void *ptr,
  			       &d, dbl);
  }

-static int
-condition_true (unsigned long cond, unsigned long status_reg)
-{
-  if (cond == INST_AL || cond == INST_NV)
-    return 1;
-
-  switch (cond)
-    {
-    case INST_EQ:
-      return ((status_reg & FLAG_Z) != 0);
-    case INST_NE:
-      return ((status_reg & FLAG_Z) == 0);
-    case INST_CS:
-      return ((status_reg & FLAG_C) != 0);
-    case INST_CC:
-      return ((status_reg & FLAG_C) == 0);
-    case INST_MI:
-      return ((status_reg & FLAG_N) != 0);
-    case INST_PL:
-      return ((status_reg & FLAG_N) == 0);
-    case INST_VS:
-      return ((status_reg & FLAG_V) != 0);
-    case INST_VC:
-      return ((status_reg & FLAG_V) == 0);
-    case INST_HI:
-      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
-    case INST_LS:
-      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
-    case INST_GE:
-      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 
0));
-    case INST_LT:
-      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 
0));
-    case INST_GT:
-      return (((status_reg & FLAG_Z) == 0)
-	      && (((status_reg & FLAG_N) == 0)
-		  == ((status_reg & FLAG_V) == 0)));
-    case INST_LE:
-      return (((status_reg & FLAG_Z) != 0)
-	      || (((status_reg & FLAG_N) == 0)
-		  != ((status_reg & FLAG_V) == 0)));
-    }
-  return 1;
-}
-
  static unsigned long
  shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
  		 unsigned long pc_val, unsigned long status_reg)
@@ -4346,17 +4302,6 @@ shifted_reg_val (struct frame_info *frame, 
unsigned long inst, int carry,
    return res & 0xffffffff;
  }

-/* Return number of 1-bits in VAL.  */
-
-static int
-bitcount (unsigned long val)
-{
-  int nbits;
-  for (nbits = 0; val != 0; nbits++)
-    val &= val - 1;		/* Delete rightmost 1-bit in val.  */
-  return nbits;
-}
-
  static int
  thumb_advance_itstate (unsigned int itstate)
  {
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 3e06f79..9b8447b 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -26,9 +26,6 @@ struct address_space;

  #include "arch/arm.h"

-/* Size of integer registers.  */
-#define INT_REGISTER_SIZE		4
-
  /* Say how long FP registers are.  Used for documentation purposes and
     code readability in this header.  IEEE extended doubles are 80
     bits.  DWORD aligned they use 96 bits.  */
@@ -50,32 +47,6 @@ struct address_space;
  #define NUM_GREGS	16	/* Number of general purpose registers.  */


-/* Instruction condition field values.  */
-#define INST_EQ		0x0
-#define INST_NE		0x1
-#define INST_CS		0x2
-#define INST_CC		0x3
-#define INST_MI		0x4
-#define INST_PL		0x5
-#define INST_VS		0x6
-#define INST_VC		0x7
-#define INST_HI		0x8
-#define INST_LS		0x9
-#define INST_GE		0xa
-#define INST_LT		0xb
-#define INST_GT		0xc
-#define INST_LE		0xd
-#define INST_AL		0xe
-#define INST_NV		0xf
-
-#define FLAG_N		0x80000000
-#define FLAG_Z		0x40000000
-#define FLAG_C		0x20000000
-#define FLAG_V		0x10000000
-
-#define CPSR_T		0x20
-
-#define XPSR_T		0x01000000

  /* Type of floating-point code in use by inferior.  There are really 3 
models
     that are traditionally supported (plus the endianness issue), but 
gcc can
diff --git a/gdb/arm-wince-tdep.c b/gdb/arm-wince-tdep.c
index 72295ba..3abd89d 100644
--- a/gdb/arm-wince-tdep.c
+++ b/gdb/arm-wince-tdep.c
@@ -24,6 +24,7 @@
  #include "target.h"
  #include "frame.h"

+#include "arch/arm.h"
  #include "arm-tdep.h"
  #include "windows-tdep.h"

diff --git a/gdb/armnbsd-tdep.c b/gdb/armnbsd-tdep.c
index 4c128c2..14eceaa 100644
--- a/gdb/armnbsd-tdep.c
+++ b/gdb/armnbsd-tdep.c
@@ -20,6 +20,7 @@
  #include "defs.h"
  #include "osabi.h"

+#include "arch/arm.h"
  #include "arm-tdep.h"
  #include "solib-svr4.h"


^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2015-11-05 14:44 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-29 17:14 [PATCH 0/10] Support software single step and conditional breakpoints on ARM in GDBServer Antoine Tremblay
2015-10-29 17:15 ` [PATCH 04/10] Remove support for thread events without TRACE_EVENT_CLONE " Antoine Tremblay
2015-11-03 17:05   ` Yao Qi
2015-11-03 17:24     ` Antoine Tremblay
2015-11-03 17:27     ` [PATCH v2] " Antoine Tremblay
2015-11-04 18:19   ` [PATCH 04/10] " Pedro Alves
2015-11-05 11:43     ` Antoine Tremblay
2015-10-29 17:15 ` [PATCH 10/10] Enable conditional breakpoints for targets that support software single step " Antoine Tremblay
2015-11-04 18:58   ` Pedro Alves
2015-10-29 17:15 ` [PATCH 07/10] Share some ARM target dependant code from GDB with GDBServer Antoine Tremblay
2015-11-04 19:56   ` Pedro Alves
2015-11-05 14:44     ` Antoine Tremblay
2015-10-29 17:16 ` [PATCH 09/10] Enable software single stepping for while-stepping actions in GDBServer Antoine Tremblay
2015-11-04 18:55   ` Pedro Alves
2015-10-29 17:28 ` [PATCH 03/10] Refactor queries for hardware and software single stepping support " Antoine Tremblay
2015-11-04 18:47   ` Pedro Alves
2015-10-29 17:31 ` [PATCH 05/10] Remove too simple breakpoint_reinsert_addr implementations Antoine Tremblay
2015-11-04 18:21   ` Pedro Alves
2015-10-29 17:36 ` [PATCH 01/10] Fix breakpoint size when stepping over a permanent breakpoint in GDBServer Antoine Tremblay
2015-11-03 16:22   ` Yao Qi
2015-11-03 17:05     ` Antoine Tremblay
2015-10-29 17:43 ` [PATCH 08/10] Support software single step on ARM " Antoine Tremblay
2015-11-04 18:46   ` Pedro Alves
2015-10-29 17:45 ` [PATCH 06/10] Replace breakpoint_reinsert_addr by get_next_pcs operation " Antoine Tremblay
2015-11-04 18:48   ` Pedro Alves
2015-11-05 14:35     ` Antoine Tremblay
2015-10-29 17:48 ` [PATCH 02/10] Fix instruction skipping when using software single step " Antoine Tremblay
2015-11-04 18:08   ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox