Add the target_ops needed for software breakpoints in GDBServer.
authorAntoine Tremblay <antoine.tremblay@ericsson.com>
Wed, 21 Oct 2015 15:17:26 +0000 (11:17 -0400)
committerAntoine Tremblay <antoine.tremblay@ericsson.com>
Wed, 21 Oct 2015 15:24:55 +0000 (11:24 -0400)
This patch is in preparation for software breakpoints on ARM linux.  It
refactors breakpoint and breakpoint_len into breakpoint_kind_from_pc and
sw_breakpoint_from kind to prepare the case where we have multiple types of
breakpoints.

Kind is the type of breakpoint (hardware or software) to be inserted, usually it
is the lenght of the software breakpoint but can be something else depending on
the target.

This patch introduces the linux_target_ops breakpoint_kind_from_pc and
sw_breakpoint_from_kind.

breakpoint_kind_from_pc returns the breakpoint kind and adjusts the PC to the
real memory location in case a flag was present in the PC. E.g the instruction
mode on ARM.

sw_breakpoint_from_kind returns the software breakpoint for this kind as a
string of bytes, the length of the breakpoint is adjusted for the breakpoint's
size in memory.

For targets that have only one kind of breakpoint, the default value 0 is
returned by linux_breakpoint_kind_from_pc so that not all targets need to
implement the breakpoint_kind_from_pc operation.

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

Also since the target_ops have been changed compilation was tested on
affected archs namely : aarch64, arm, bfin, cris, crisv32, m32r,
m68k, mips, nios2, ppc, s390, sparc, tic6x, tile, x86, steins.

Not tested : sh

gdb/gdbserver/ChangeLog:

* linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-arm-low.c (arm_breakpoint_kind_from_pc): New function.
(arm_sw_breakpoint_from_kind): New function.
* linux-bfin-low.c (bfin_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-cris-low.c (cris_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-crisv32-low.c (cris_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-low.c (linux_wait_1): Call breakpoint_kind_from_pc
and sw_breakpoint_from_kind to increment the pc.
(linux_breakpoint_kind_from_pc): New function.
(linux_sw_breakpoint_from_kind): New function.
(struct target_ops) <sw_breakpoint_from_kind>: Initialize field.
(initialize_low): Call breakpoint_kind_from_pc and
sw_breakpoint_from_kind to replace breakpoint_data/len.
* linux-low.h (struct linux_target_ops) <breakpoint_kind_from_pc>:
New field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Likewise.
* linux-m32r-low.c (m32r_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-m68k-low.c (m68k_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-mips-low.c (mips_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-nios2-low.c (nios2_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-ppc-low.c (ppc_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-s390-low.c (s390_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-sh-low.c (sh_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-sparc-low.c (sparc_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-tic6x-low.c (tic6x_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-tile-low.c (tile_sw_breakpoint_from_kind): New function.
* linux-x86-low.c (x86_sw_breakpoint_from_kind): New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
* linux-xtensa-low.c (xtensa_sw_breakpoint_from_kind) New function.
(struct linux_target_ops) <breakpoint>: Remove.
(struct linux_target_ops) <breakpoint_len>: Remove.
(struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
(struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.

21 files changed:
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-aarch64-low.c
gdb/gdbserver/linux-arm-low.c
gdb/gdbserver/linux-bfin-low.c
gdb/gdbserver/linux-cris-low.c
gdb/gdbserver/linux-crisv32-low.c
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h
gdb/gdbserver/linux-m32r-low.c
gdb/gdbserver/linux-m68k-low.c
gdb/gdbserver/linux-mips-low.c
gdb/gdbserver/linux-nios2-low.c
gdb/gdbserver/linux-ppc-low.c
gdb/gdbserver/linux-s390-low.c
gdb/gdbserver/linux-sh-low.c
gdb/gdbserver/linux-sparc-low.c
gdb/gdbserver/linux-tic6x-low.c
gdb/gdbserver/linux-tile-low.c
gdb/gdbserver/linux-x86-low.c
gdb/gdbserver/linux-xtensa-low.c
gdb/gdbserver/target.h

index 8e73d9f0753ee6594930888220c82370d81565cf..10ae1589de6a61e54f6848f4abdae0378e4a965f 100644 (file)
@@ -1,3 +1,94 @@
+2015-10-21  Antoine Tremblay  <antoine.tremblay@ericsson.com>
+
+       * linux-aarch64-low.c (aarch64_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-arm-low.c (arm_breakpoint_kind_from_pc): New function.
+       (arm_sw_breakpoint_from_kind): New function.
+       * linux-bfin-low.c (bfin_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-cris-low.c (cris_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-crisv32-low.c (cris_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-low.c (linux_wait_1): Call breakpoint_kind_from_pc
+       and sw_breakpoint_from_kind to increment the pc.
+       (linux_breakpoint_kind_from_pc): New function.
+       (linux_sw_breakpoint_from_kind): New function.
+       (struct target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       (initialize_low): Call breakpoint_kind_from_pc and
+       sw_breakpoint_from_kind to replace breakpoint_data/len.
+       * linux-low.h (struct linux_target_ops) <breakpoint_kind_from_pc>:
+       New field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Likewise.
+       * linux-m32r-low.c (m32r_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-m68k-low.c (m68k_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-mips-low.c (mips_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-nios2-low.c (nios2_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-ppc-low.c (ppc_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-s390-low.c (s390_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-sh-low.c (sh_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-sparc-low.c (sparc_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-tic6x-low.c (tic6x_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-tile-low.c (tile_sw_breakpoint_from_kind): New function.
+       * linux-x86-low.c (x86_sw_breakpoint_from_kind): New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+       * linux-xtensa-low.c (xtensa_sw_breakpoint_from_kind) New function.
+       (struct linux_target_ops) <breakpoint>: Remove.
+       (struct linux_target_ops) <breakpoint_len>: Remove.
+       (struct linux_target_ops) <breakpoint_kind_from_pc>: Initialize field.
+       (struct linux_target_ops) <sw_breakpoint_from_kind>: Initialize field.
+
 2015-10-21  Antoine Tremblay  <antoine.tremblay@ericsson.com>
 
        * linux-cris-low.c (cris_get_pc): Remove void arg.
index 780c5e3f6529ad7ce813f467c810aeed76547117..cb49a044518c7fdf3b0a24eab7ff14298955b5ff 100644 (file)
@@ -2931,6 +2931,15 @@ aarch64_supports_range_stepping (void)
   return 1;
 }
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+aarch64_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = aarch64_breakpoint_len;
+  return aarch64_breakpoint;
+}
+
 struct linux_target_ops the_low_target =
 {
   aarch64_arch_setup,
@@ -2940,8 +2949,8 @@ struct linux_target_ops the_low_target =
   NULL, /* fetch_register */
   aarch64_get_pc,
   aarch64_set_pc,
-  (const unsigned char *) &aarch64_breakpoint,
-  aarch64_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  aarch64_sw_breakpoint_from_kind,
   NULL, /* breakpoint_reinsert_addr */
   0,    /* decr_pc_after_break */
   aarch64_breakpoint_at,
index a277bb6876fb9f98a4e83dacf23b7d585f7e33f4..3a56620181ae3815c45767fb7fdaa171f020fd43 100644 (file)
@@ -913,26 +913,34 @@ arm_regs_info (void)
     return &regs_info_arm;
 }
 
-struct linux_target_ops the_low_target = {
-  arm_arch_setup,
-  arm_regs_info,
-  arm_cannot_fetch_register,
-  arm_cannot_store_register,
-  NULL, /* fetch_register */
-  arm_get_pc,
-  arm_set_pc,
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
 
+static const gdb_byte *
+arm_sw_breakpoint_from_kind (int kind , int *size)
+{
+  *size = arm_breakpoint_len;
   /* Define an ARM-mode breakpoint; we only set breakpoints in the C
      library, which is most likely to be ARM.  If the kernel supports
      clone events, we will never insert a breakpoint, so even a Thumb
      C library will work; so will mixing EABI/non-EABI gdbserver and
      application.  */
 #ifndef __ARM_EABI__
-  (const unsigned char *) &arm_breakpoint,
+  return (const gdb_byte *) &arm_breakpoint;
 #else
-  (const unsigned char *) &arm_eabi_breakpoint,
+  return (const gdb_byte *) &arm_eabi_breakpoint;
 #endif
-  arm_breakpoint_len,
+}
+
+struct linux_target_ops the_low_target = {
+  arm_arch_setup,
+  arm_regs_info,
+  arm_cannot_fetch_register,
+  arm_cannot_store_register,
+  NULL, /* fetch_register */
+  arm_get_pc,
+  arm_set_pc,
+  NULL, /* breakpoint_kind_from_pc */
+  arm_sw_breakpoint_from_kind,
   arm_reinsert_addr,
   0,
   arm_breakpoint_at,
index 4002f220d59839177155e8273785ccd7c4ef53ff..d3b83fc827e971996c5201dc4945a30dd5204784 100644 (file)
@@ -73,7 +73,16 @@ bfin_set_pc (struct regcache *regcache, CORE_ADDR pc)
 }
 
 #define bfin_breakpoint_len 2
-static const unsigned char bfin_breakpoint[bfin_breakpoint_len] = {0xa1, 0x00};
+static const gdb_byte bfin_breakpoint[bfin_breakpoint_len] = {0xa1, 0x00};
+
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+bfin_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = bfin_breakpoint_len;
+  return bfin_breakpoint;
+}
 
 static int
 bfin_breakpoint_at (CORE_ADDR where)
@@ -122,8 +131,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   bfin_get_pc,
   bfin_set_pc,
-  bfin_breakpoint,
-  bfin_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  bfin_sw_breakpoint_from_kind,
   NULL, /* breakpoint_reinsert_addr */
   2,
   bfin_breakpoint_at,
index 135e37a2845358ddfe4ae87d2dda34a3f4816b90..d7b70e3eae3620b6baec445dc950681710d06ed6 100644 (file)
@@ -81,6 +81,15 @@ cris_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned short cris_breakpoint = 0xe938;
 #define cris_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+cris_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = cris_breakpoint_len;
+  return (const gdb_byte *) &cris_breakpoint;
+}
+
 static int
 cris_breakpoint_at (CORE_ADDR where)
 {
@@ -140,8 +149,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   cris_get_pc,
   cris_set_pc,
-  (const unsigned char *) &cris_breakpoint,
-  cris_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  cris_sw_breakpoint_from_kind,
   cris_reinsert_addr,
   0,
   cris_breakpoint_at,
index 51208638d97c96730ef0452833a233ff2c302a44..f97122e3dac58f3e9eee9ceae42387bafd477c06 100644 (file)
@@ -77,6 +77,15 @@ cris_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned short cris_breakpoint = 0xe938;
 #define cris_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+cris_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = cris_breakpoint_len;
+  return (const gdb_byte *) &cris_breakpoint;
+}
+
 static int
 cris_breakpoint_at (CORE_ADDR where)
 {
@@ -420,8 +429,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   cris_get_pc,
   cris_set_pc,
-  (const unsigned char *) &cris_breakpoint,
-  cris_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  cris_sw_breakpoint_from_kind,
   cris_reinsert_addr,
   0,
   cris_breakpoint_at,
index 3a1a6ae57ea3ddab3fd38ca80d326faebc363310..398c0aa6eea46f3519346d2dec2beac59058ffbc 100644 (file)
@@ -3012,7 +3012,12 @@ linux_wait_1 (ptid_t ptid,
   if (!ptid_equal (step_over_bkpt, null_ptid)
       && event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT)
     {
-      unsigned int increment_pc = the_low_target.breakpoint_len;
+      int increment_pc = 0;
+      int breakpoint_kind = 0;
+      CORE_ADDR stop_pc = event_child->stop_pc;
+
+      breakpoint_kind = the_target->breakpoint_kind_from_pc (&stop_pc);
+      the_target->sw_breakpoint_from_kind (breakpoint_kind, &increment_pc);
 
       if (debug_threads)
        {
@@ -6932,6 +6937,28 @@ current_lwp_ptid (void)
   return ptid_of (current_thread);
 }
 
+/* Implementation of the target_ops method "breakpoint_kind_from_pc".  */
+
+static int
+linux_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
+{
+  if (the_low_target.breakpoint_kind_from_pc != NULL)
+    return (*the_low_target.breakpoint_kind_from_pc) (pcptr);
+  else
+    /* Default breakpoint kind value.  */
+    return 0;
+}
+
+/* Implementation of the target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+linux_sw_breakpoint_from_kind (int kind, int *size)
+{
+  gdb_assert (the_low_target.sw_breakpoint_from_kind != NULL);
+
+  return (*the_low_target.sw_breakpoint_from_kind) (kind, size);
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_arch_setup,
@@ -7026,6 +7053,8 @@ static struct target_ops linux_target_ops = {
   linux_mntns_open_cloexec,
   linux_mntns_unlink,
   linux_mntns_readlink,
+  linux_breakpoint_kind_from_pc,
+  linux_sw_breakpoint_from_kind
 };
 
 static void
@@ -7053,10 +7082,20 @@ void
 initialize_low (void)
 {
   struct sigaction sigchld_action;
+  int breakpoint_kind = 0;
+  int breakpoint_size = 0;
+  const gdb_byte *breakpoint = NULL;
+
   memset (&sigchld_action, 0, sizeof (sigchld_action));
   set_target_ops (&linux_target_ops);
-  set_breakpoint_data (the_low_target.breakpoint,
-                      the_low_target.breakpoint_len);
+
+  breakpoint_kind = the_target->breakpoint_kind_from_pc (NULL);
+  breakpoint = the_target->sw_breakpoint_from_kind (breakpoint_kind,
+                                                   &breakpoint_size);
+
+  set_breakpoint_data (breakpoint,
+                      breakpoint_size);
+
   linux_init_signals ();
   linux_ptrace_init_warnings ();
 
index f8f6e78a00170f1f01a13387062df1a7bd1b209b..28dd4db126353b9c1f2ec14fd37f602e1238e522 100644 (file)
@@ -141,8 +141,13 @@ struct linux_target_ops
 
   CORE_ADDR (*get_pc) (struct regcache *regcache);
   void (*set_pc) (struct regcache *regcache, CORE_ADDR newpc);
-  const unsigned char *breakpoint;
-  int breakpoint_len;
+
+  /* See target.h for details.  */
+  int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr);
+
+  /* See target.h for details.  */
+  const gdb_byte *(*sw_breakpoint_from_kind) (int kind, int *size);
+
   CORE_ADDR (*breakpoint_reinsert_addr) (void);
 
   int decr_pc_after_break;
index 8ffeda250eb0449c646ab32a08c9665457d17eec..bb1002f9db4a2b4e601fc8cf4196f88f30decd90 100644 (file)
@@ -73,6 +73,15 @@ m32r_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned short m32r_breakpoint = 0x10f1;
 #define m32r_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+m32r_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = m32r_breakpoint_len;
+  return (const gdb_byte *) &m32r_breakpoint;
+}
+
 static int
 m32r_breakpoint_at (CORE_ADDR where)
 {
@@ -120,8 +129,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   m32r_get_pc,
   m32r_set_pc,
-  (const unsigned char *) &m32r_breakpoint,
-  m32r_breakpoint_len,
+  NULL, /* breakpoint_from_pc */
+  m32r_sw_breakpoint_from_kind,
   NULL,
   0,
   m32r_breakpoint_at,
index 39c9cc5a1f9a542ff1b82126b8091d7c4b57d528..ba8e5e9d5a970df1247a0d12ef34b15434fcf5a4 100644 (file)
@@ -122,9 +122,18 @@ static struct regset_info m68k_regsets[] = {
   { 0, 0, 0, -1, -1, NULL, NULL }
 };
 
-static const unsigned char m68k_breakpoint[] = { 0x4E, 0x4F };
+static const gdb_byte m68k_breakpoint[] = { 0x4E, 0x4F };
 #define m68k_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+m68k_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = m68k_breakpoint_len;
+  return m68k_breakpoint;
+}
+
 static CORE_ADDR
 m68k_get_pc (struct regcache *regcache)
 {
@@ -215,8 +224,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   m68k_get_pc,
   m68k_set_pc,
-  m68k_breakpoint,
-  m68k_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  m68k_sw_breakpoint_from_kind,
   NULL,
   2,
   m68k_breakpoint_at,
index d1181b6c71f368de86dd1e950906ea29270793a6..344d7a5144a16fcdcf003c06e178feac3b08adc1 100644 (file)
@@ -266,6 +266,15 @@ mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned int mips_breakpoint = 0x0005000d;
 #define mips_breakpoint_len 4
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+mips_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = mips_breakpoint_len;
+  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.  */
@@ -881,8 +890,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   mips_get_pc,
   mips_set_pc,
-  (const unsigned char *) &mips_breakpoint,
-  mips_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  mips_sw_breakpoint_from_kind,
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
index 71542b495a61910b4857e96e0f9506eec3382918..95a2d9ee9d13ee305d5181ae23fa16b37477a042 100644 (file)
@@ -127,9 +127,23 @@ nios2_set_pc (struct regcache *regcache, CORE_ADDR pc)
 #define NIOS2_BREAKPOINT 0x003b6ffa
 #endif
 
+/* We only register the 4-byte breakpoint, even on R2 targets which also
+   support 2-byte breakpoints.  Since there is no supports_z_point_type
+   function provided, gdbserver never inserts software breakpoints itself
+   and instead relies on GDB to insert the breakpoint of the correct length
+   via a memory write.  */
 static const unsigned int nios2_breakpoint = NIOS2_BREAKPOINT;
 #define nios2_breakpoint_len 4
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+nios2_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = nios2_breakpoint_len;
+  return (const gdb_byte *) &nios2_breakpoint;
+}
+
 /* Implement the breakpoint_reinsert_addr linux_target_ops method.  */
 
 static CORE_ADDR
@@ -263,14 +277,8 @@ struct linux_target_ops the_low_target =
   NULL,
   nios2_get_pc,
   nios2_set_pc,
-
-  /* We only register the 4-byte breakpoint, even on R2 targets which also
-     support 2-byte breakpoints.  Since there is no supports_z_point_type
-     function provided, gdbserver never inserts software breakpoints itself
-     and instead relies on GDB to insert the breakpoint of the correct length
-     via a memory write.  */
-  (const unsigned char *) &nios2_breakpoint,
-  nios2_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  nios2_sw_breakpoint_from_kind,
   nios2_reinsert_addr,
   0,
   nios2_breakpoint_at,
index 188fac05ac37c22bd61ebddca612c20a0828a4c1..6e6a93644f1f23e8a8b4000dce074da6dc0eeb0c 100644 (file)
@@ -486,6 +486,15 @@ ppc_arch_setup (void)
 static const unsigned int ppc_breakpoint = 0x7d821008;
 #define ppc_breakpoint_len 4
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+ppc_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = ppc_breakpoint_len;
+  return (const gdb_byte *) &ppc_breakpoint;
+}
+
 static int
 ppc_breakpoint_at (CORE_ADDR where)
 {
@@ -685,8 +694,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   ppc_get_pc,
   ppc_set_pc,
-  (const unsigned char *) &ppc_breakpoint,
-  ppc_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  ppc_sw_breakpoint_from_kind,
   NULL,
   0,
   ppc_breakpoint_at,
index 8a0a6891433ec49f4fe9ea1098d9db51de7a636f..2ba12210c62748b5b74a9d73b16ef3cb84963025 100644 (file)
@@ -394,9 +394,18 @@ static struct regset_info s390_regsets[] = {
 };
 
 
-static const unsigned char s390_breakpoint[] = { 0, 1 };
+static const gdb_byte s390_breakpoint[] = { 0, 1 };
 #define s390_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+s390_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = s390_breakpoint_len;
+  return s390_breakpoint;
+}
+
 static CORE_ADDR
 s390_get_pc (struct regcache *regcache)
 {
@@ -665,8 +674,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   s390_get_pc,
   s390_set_pc,
-  s390_breakpoint,
-  s390_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  s390_sw_breakpoint_from_kind,
   NULL,
   s390_breakpoint_len,
   s390_breakpoint_at,
index 218d4d39ab957f3759cfda4b026ca5cb7b0475ea..f7f3239a34b13b97bacb7f71a7a6842343739aaf 100644 (file)
@@ -77,6 +77,15 @@ sh_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static const unsigned short sh_breakpoint = 0xc3c3;
 #define sh_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+sh_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = sh_breakpoint_len;
+  return (const gdb_byte *) &sh_breakpoint;
+}
+
 static int
 sh_breakpoint_at (CORE_ADDR where)
 {
@@ -148,8 +157,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   sh_get_pc,
   sh_set_pc,
-  (const unsigned char *) &sh_breakpoint,
-  sh_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  sh_sw_breakpoint_from_kind,
   NULL,
   0,
   sh_breakpoint_at,
index 796af8aa5764e3b1c26795601f4f672e5d01dbd9..0691867a74e2002fde7c6c13af2693a1bd8ee60e 100644 (file)
@@ -235,11 +235,19 @@ sparc_get_pc (struct regcache *regcache)
   return pc;
 }
 
-static const unsigned char sparc_breakpoint[INSN_SIZE] = {
+static const gdb_byte sparc_breakpoint[INSN_SIZE] = {
   0x91, 0xd0, 0x20, 0x01
 };
 #define sparc_breakpoint_len INSN_SIZE
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const unsigned char *
+sparc_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = sparc_breakpoint_len;
+  return sparc_breakpoint;
+}
 
 static int
 sparc_breakpoint_at (CORE_ADDR where)
@@ -323,8 +331,8 @@ struct linux_target_ops the_low_target = {
   sparc_get_pc,
   /* No sparc_set_pc is needed.  */
   NULL,
-  (const unsigned char *) sparc_breakpoint,
-  sparc_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  sparc_sw_breakpoint_from_kind,
   sparc_reinsert_addr,
   0,
   sparc_breakpoint_at,
index a2ac3eec827cedf0812d63ab0c253e70ecf910e1..d9476fd4e45c7920a4a242ce2ab240d76a7f4512 100644 (file)
@@ -171,6 +171,16 @@ extern struct linux_target_ops the_low_target;
 
 static int *tic6x_regmap;
 static unsigned int tic6x_breakpoint;
+#define tic6x_breakpoint_len 4
+
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+tic6x_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = tic6x_breakpoint_len;
+  return (const gdb_byte *) &tic6x_breakpoint;
+}
 
 /* Forward definition.  */
 static struct usrregs_info tic6x_usrregs_info;
@@ -247,8 +257,6 @@ tic6x_set_pc (struct regcache *regcache, CORE_ADDR pc)
   supply_register_by_name (regcache, "PC", newpc.buf);
 }
 
-#define tic6x_breakpoint_len 4
-
 static int
 tic6x_breakpoint_at (CORE_ADDR where)
 {
@@ -367,8 +375,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   tic6x_get_pc,
   tic6x_set_pc,
-  (const unsigned char *) &tic6x_breakpoint,
-  tic6x_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  tic6x_sw_breakpoint_from_kind,
   NULL,
   0,
   tic6x_breakpoint_at,
index 6aaea6a080e74e023ed3d01a703a1315a1eb01be..e31a620454377ec1e0f1d44dd7feb4cc2fe8d655 100644 (file)
@@ -88,6 +88,15 @@ tile_set_pc (struct regcache *regcache, CORE_ADDR pc)
 static uint64_t tile_breakpoint = 0x400b3cae70166000ULL;
 #define tile_breakpoint_len 8
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+tile_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = tile_breakpoint_len;
+  return (const gdb_byte *) &tile_breakpoint;
+}
+
 static int
 tile_breakpoint_at (CORE_ADDR where)
 {
@@ -182,8 +191,8 @@ struct linux_target_ops the_low_target =
   NULL,
   tile_get_pc,
   tile_set_pc,
-  (const unsigned char *) &tile_breakpoint,
-  tile_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  tile_sw_breakpoint_from_kind,
   NULL,
   0,
   tile_breakpoint_at,
index 20d4257e5fb01e3a84b972584ce2dfce3373c010..406d5524be9c6595cdbcf784099fdd0c84c0672c 100644 (file)
@@ -502,7 +502,7 @@ x86_set_pc (struct regcache *regcache, CORE_ADDR pc)
     }
 }
 \f
-static const unsigned char x86_breakpoint[] = { 0xCC };
+static const gdb_byte x86_breakpoint[] = { 0xCC };
 #define x86_breakpoint_len 1
 
 static int
@@ -3243,6 +3243,15 @@ x86_emit_ops (void)
     return &i386_emit_ops;
 }
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+x86_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = x86_breakpoint_len;
+  return x86_breakpoint;
+}
+
 static int
 x86_supports_range_stepping (void)
 {
@@ -3261,8 +3270,8 @@ struct linux_target_ops the_low_target =
   NULL, /* fetch_register */
   x86_get_pc,
   x86_set_pc,
-  x86_breakpoint,
-  x86_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  x86_sw_breakpoint_from_kind,
   NULL,
   1,
   x86_breakpoint_at,
index debe4678646500d9d7eda10f409c5753e773757e..fa6f418afc21ea86aa9e1e9ed2dee69b4a856e0c 100644 (file)
@@ -151,9 +151,18 @@ static struct regset_info xtensa_regsets[] = {
 #define XTENSA_BREAKPOINT {0x2d,0xf0}
 #endif
 
-static const unsigned char xtensa_breakpoint[] = XTENSA_BREAKPOINT;
+static const gdb_byte xtensa_breakpoint[] = XTENSA_BREAKPOINT;
 #define xtensa_breakpoint_len 2
 
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+xtensa_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = xtensa_breakpoint_len;
+  return xtensa_breakpoint;
+}
+
 static CORE_ADDR
 xtensa_get_pc (struct regcache *regcache)
 {
@@ -234,8 +243,8 @@ struct linux_target_ops the_low_target = {
   NULL, /* fetch_register */
   xtensa_get_pc,
   xtensa_set_pc,
-  xtensa_breakpoint,
-  xtensa_breakpoint_len,
+  NULL, /* breakpoint_kind_from_pc */
+  xtensa_sw_breakpoint_from_kind,
   NULL,
   0,
   xtensa_breakpoint_at,
index a2842b41cc41dea5d5684a7766b9a799f3e15f18..e4c0639396f3157ccc9d74cd4bba146ef5d27469 100644 (file)
@@ -441,6 +441,16 @@ struct target_ops
      readlink(2).  */
   ssize_t (*multifs_readlink) (int pid, const char *filename,
                               char *buf, size_t bufsiz);
+
+  /* Return the breakpoint kind for this target based on 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_pc) (CORE_ADDR *pcptr);
+
+  /* Return the software breakpoint from KIND.  KIND can have target
+     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);
 };
 
 extern struct target_ops *the_target;