[PATCH 3/7] Support multiple breakpoint types per target in GDBServer.

Antoine Tremblay
2015-09-11T12:14:08Z

This patch is in preparation for software single stepping on ARM
aarch32-linux. It refactors breakpoint and breakpoint_len into
breakpoint_from_pc to prepare the case where we have multiple types of
breakpoints.

breakpoint_from_pc returns the breakpoint for this PC as a string of bytes,
the length of the breakpoint and ajusts the PC to the real memory location in
case a flag was present in the PC.

No regressions, tested on Ubuntu 14.04 on ARMv7 and x86

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

gdbserver/ChangeLog:
* linux-aarch64-low.c
(aarch64_breakpoint_from_pc): New function.
* linux-arm-low.c (arm_breakpoint_from_pc): Likewise.
* linux-bfin-low.c (bfin_breakpoint_from_pc): Likewise.
* linux-cris-low.c (cris_breakpoint_from_pc): Likewise.
* linux-crisv32-low.c: (cris_breakpoint_from_pc): Likewise.
* linux-low.c (linux_wait_1): Add call to breakpoint_from_pc.
(linux_breakpoint_from_pc): New function.
(initialize_low): Add call to breakpoint_from_pc.
* linux-low.h: Add breakpoint_from_pc operation.
* linux-m32r-low.c (m32r_breakpoint_from_pc): New function.
* linux-m68k-low.c (m68k_breakpoint_from_pc): Likewise.
* linux-mips-low.c (mips_breakpoint_from_pc): Likewise.
* linux-nios2-low.c (nios2_breakpoint_from_pc): Likewise.
* linux-ppc-low.c (ppc_breakpoint_from_pc): Likewise.
* linux-s390-low.c (s390_breakpoint_from_pc): Likewise.
* linux-sh-low.c (sh_breakpoint_from_pc): Likewise.
* linux-sparc-low.c (sparc_breakpoint_from_pc): Likewise.
* linux-tic6x-low.c (tic6x_breakpoint_from_pc): Likewise.
* linux-tile-low.c (tile_breakpoint_from_pc): Likewise.
* linux-x86-low.c (x86_breakpoint_from_pc): Likewise.
* linux-xtensa-low.c(xtensa_breakpoint_from_pc): Likewise.
* target.h (struct target_ops): Add breakpoint_from_pc operation.
* win32-arm-low.c (arm_wince_breakpoint_from_pc): New Function.
* win32-i386-low.c(i386_win32_breakpoint_from_pc): Likewise.
---
gdb/gdbserver/linux-aarch64-low.c | 10 ++++++++--
gdb/gdbserver/linux-arm-low.c | 28 ++++++++++++++++------------
gdb/gdbserver/linux-bfin-low.c | 10 ++++++++--
gdb/gdbserver/linux-cris-low.c | 12 +++++++++---
gdb/gdbserver/linux-crisv32-low.c | 10 ++++++++--
gdb/gdbserver/linux-low.c | 28 +++++++++++++++++++++++++---
gdb/gdbserver/linux-low.h | 9 +++++++--
gdb/gdbserver/linux-m32r-low.c | 10 ++++++++--
gdb/gdbserver/linux-m68k-low.c | 10 ++++++++--
gdb/gdbserver/linux-mips-low.c | 10 ++++++++--
gdb/gdbserver/linux-nios2-low.c | 22 +++++++++++++---------
gdb/gdbserver/linux-ppc-low.c | 10 ++++++++--
gdb/gdbserver/linux-s390-low.c | 10 ++++++++--
gdb/gdbserver/linux-sh-low.c | 10 ++++++++--
gdb/gdbserver/linux-sparc-low.c | 9 +++++++--
gdb/gdbserver/linux-tic6x-low.c | 13 +++++++++----
gdb/gdbserver/linux-tile-low.c | 10 ++++++++--
gdb/gdbserver/linux-x86-low.c | 10 ++++++++--
gdb/gdbserver/linux-xtensa-low.c | 10 ++++++++--
gdb/gdbserver/target.h | 5 +++++
gdb/gdbserver/win32-arm-low.c | 10 ++++++++--
gdb/gdbserver/win32-i386-low.c | 10 ++++++++--
22 files changed, 203 insertions(+), 63 deletions(-)

diff --git a/gdb/gdbserver/linux-aarch64-low.c b/gdb/gdbserver/linux-aarch64-low.c
index aebf1e3..0b2c5f1 100644
--- a/gdb/gdbserver/linux-aarch64-low.c
+++ b/gdb/gdbserver/linux-aarch64-low.c
@@ -200,6 +200,13 @@ aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc)
(aarch64_default_breakpoint). */
static const gdb_byte aarch64_breakpoint[] = {0x00, 0x00, 0x20, 0xd4};

+static const unsigned char *
+aarch64_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = aarch64_breakpoint_len;
+ return (const unsigned char *) &aarch64_breakpoint;
+}
+
/* Implementation of linux_target_ops method "breakpoint_at". */

static int
@@ -569,8 +576,7 @@ struct linux_target_ops the_low_target =
NULL, /* fetch_register */
aarch64_get_pc,
aarch64_set_pc,
- (const unsigned char *) &aarch64_breakpoint,
- aarch64_breakpoint_len,
+ aarch64_breakpoint_from_pc,
NULL, /* breakpoint_reinsert_addr */
0, /* decr_pc_after_break */
aarch64_breakpoint_at,
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index a277bb6..367c704 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -913,6 +913,21 @@ arm_regs_info (void)
return &regs_info_arm;
}

+static const unsigned char *
+arm_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = 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__
+ return (const unsigned char *) &arm_breakpoint;
+#else
+ return (const unsigned char *) &arm_eabi_breakpoint;
+#endif
+}
struct linux_target_ops the_low_target = {
arm_arch_setup,
arm_regs_info,
@@ -921,18 +936,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
arm_get_pc,
arm_set_pc,
-
- /* 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,
-#else
- (const unsigned char *) &arm_eabi_breakpoint,
-#endif
- arm_breakpoint_len,
+ arm_breakpoint_from_pc,
arm_reinsert_addr,
0,
arm_breakpoint_at,
diff --git a/gdb/gdbserver/linux-bfin-low.c b/gdb/gdbserver/linux-bfin-low.c
index 4002f22..1c0e1e9 100644
--- a/gdb/gdbserver/linux-bfin-low.c
+++ b/gdb/gdbserver/linux-bfin-low.c
@@ -75,6 +75,13 @@ 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 unsigned char *
+bfin_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = bfin_breakpoint_len;
+ return (const unsigned char *) &bfin_breakpoint;
+}
+
static int
bfin_breakpoint_at (CORE_ADDR where)
{
@@ -122,8 +129,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
bfin_get_pc,
bfin_set_pc,
- bfin_breakpoint,
- bfin_breakpoint_len,
+ bfin_breakpoint_from_pc,
NULL, /* breakpoint_reinsert_addr */
2,
bfin_breakpoint_at,
diff --git a/gdb/gdbserver/linux-cris-low.c b/gdb/gdbserver/linux-cris-low.c
index e0bfa1a..da5876d 100644
--- a/gdb/gdbserver/linux-cris-low.c
+++ b/gdb/gdbserver/linux-cris-low.c
@@ -62,7 +62,7 @@ cris_cannot_fetch_register (int regno)
extern int debug_threads;

static CORE_ADDR
-cris_get_pc (struct regcache *regcache, void)
+cris_get_pc (struct regcache *regcache)
{
unsigned long pc;
collect_register_by_name (regcache, "pc", &pc);
@@ -81,6 +81,13 @@ cris_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned short cris_breakpoint = 0xe938;
#define cris_breakpoint_len 2

+static const unsigned char *
+cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = cris_breakpoint_len;
+ return (const unsigned char *) &cris_breakpoint;
+}
+
static int
cris_breakpoint_at (CORE_ADDR where)
{
@@ -140,8 +147,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
cris_get_pc,
cris_set_pc,
- (const unsigned char *) &cris_breakpoint,
- cris_breakpoint_len,
+ cris_breakpoint_from_pc,
cris_reinsert_addr,
0,
cris_breakpoint_at,
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
index 5120863..d2dba91 100644
--- a/gdb/gdbserver/linux-crisv32-low.c
+++ b/gdb/gdbserver/linux-crisv32-low.c
@@ -77,6 +77,13 @@ cris_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned short cris_breakpoint = 0xe938;
#define cris_breakpoint_len 2

+static const unsigned char *
+cris_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = cris_breakpoint_len;
+ return (const unsigned char *) &cris_breakpoint;
+}
+
static int
cris_breakpoint_at (CORE_ADDR where)
{
@@ -420,8 +427,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
cris_get_pc,
cris_set_pc,
- (const unsigned char *) &cris_breakpoint,
- cris_breakpoint_len,
+ cris_breakpoint_from_pc,
cris_reinsert_addr,
0,
cris_breakpoint_at,
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 7d979f8..ef6075b 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -2929,7 +2929,11 @@ linux_wait_1 (ptid_t ptid,
(event_child->stepping ||
!reinsert_breakpoint_inserted_here (event_child->stop_pc)))
{
- unsigned int increment_pc = the_low_target.breakpoint_len;
+ int increment_pc = 0;
+ CORE_ADDR stop_pc = event_child->stop_pc;
+
+ (*the_low_target.breakpoint_from_pc)
+ (&stop_pc, &increment_pc);

if (debug_threads)
{
@@ -6861,6 +6865,17 @@ current_lwp_ptid (void)
return ptid_of (current_thread);
}

+const unsigned char *
+linux_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+ if (the_low_target.breakpoint_from_pc != NULL)
+ {
+ return (*the_low_target.breakpoint_from_pc) (pcptr, lenptr);
+ }
+ else
+ return NULL;
+}
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_arch_setup,
@@ -6954,6 +6969,7 @@ static struct target_ops linux_target_ops = {
linux_mntns_open_cloexec,
linux_mntns_unlink,
linux_mntns_readlink,
+ linux_breakpoint_from_pc,
};

static void
@@ -6981,10 +6997,16 @@ void
initialize_low (void)
{
struct sigaction sigchld_action;
+ int breakpoint_len = 0;
+ const unsigned char *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 = the_target->breakpoint_from_pc (NULL, &breakpoint_len);
+
+ set_breakpoint_data (breakpoint,
+ breakpoint_len);
linux_init_signals ();
linux_ptrace_init_warnings ();

diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index f8f6e78..c623150 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -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;
+
+ /* Return the raw breakpoint for this target based on PC. Note that the PC
+ can be NULL, the default breakpoint for the target should be returned in
+ this case. The PC is ajusted to the real memory location in case a flag was
+ present in the PC. */
+ const unsigned char *(*breakpoint_from_pc) (CORE_ADDR *pcptr, int *lenptr);
+
CORE_ADDR (*breakpoint_reinsert_addr) (void);

int decr_pc_after_break;
diff --git a/gdb/gdbserver/linux-m32r-low.c b/gdb/gdbserver/linux-m32r-low.c
index 8ffeda2..4712a32 100644
--- a/gdb/gdbserver/linux-m32r-low.c
+++ b/gdb/gdbserver/linux-m32r-low.c
@@ -73,6 +73,13 @@ m32r_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned short m32r_breakpoint = 0x10f1;
#define m32r_breakpoint_len 2

+static const unsigned char *
+m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = m32r_breakpoint_len;
+ return (const unsigned char *) &m32r_breakpoint;
+}
+
static int
m32r_breakpoint_at (CORE_ADDR where)
{
@@ -120,8 +127,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
m32r_get_pc,
m32r_set_pc,
- (const unsigned char *) &m32r_breakpoint,
- m32r_breakpoint_len,
+ m32r_breakpoint_from_pc,
NULL,
0,
m32r_breakpoint_at,
diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c
index 39c9cc5..39a9753 100644
--- a/gdb/gdbserver/linux-m68k-low.c
+++ b/gdb/gdbserver/linux-m68k-low.c
@@ -125,6 +125,13 @@ static struct regset_info m68k_regsets[] = {
static const unsigned char m68k_breakpoint[] = { 0x4E, 0x4F };
#define m68k_breakpoint_len 2

+static const unsigned char *
+m68k_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = m68k_breakpoint_len;
+ return (unsigned char*) &m68k_breakpoint;
+}
+
static CORE_ADDR
m68k_get_pc (struct regcache *regcache)
{
@@ -215,8 +222,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
m68k_get_pc,
m68k_set_pc,
- m68k_breakpoint,
- m68k_breakpoint_len,
+ m68k_breakpoint_from_pc,
NULL,
2,
m68k_breakpoint_at,
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index d1181b6..d5333ab 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -266,6 +266,13 @@ mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned int mips_breakpoint = 0x0005000d;
#define mips_breakpoint_len 4

+static const unsigned char *
+mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = mips_breakpoint_len;
+ return (const unsigned char *) &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 +888,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
mips_get_pc,
mips_set_pc,
- (const unsigned char *) &mips_breakpoint,
- mips_breakpoint_len,
+ mips_breakpoint_from_pc,
mips_reinsert_addr,
0,
mips_breakpoint_at,
diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c
index 71542b4..bf9ecc2 100644
--- a/gdb/gdbserver/linux-nios2-low.c
+++ b/gdb/gdbserver/linux-nios2-low.c
@@ -119,7 +119,6 @@ nios2_set_pc (struct regcache *regcache, CORE_ADDR pc)

/* Breakpoint support. Also see comments on nios2_breakpoint_from_pc
in nios2-tdep.c. */
-
#if defined(__nios2_arch__) && __nios2_arch__ == 2
#define NIOS2_BREAKPOINT 0xb7fd0020
#define CDX_BREAKPOINT 0xd7c9
@@ -127,9 +126,21 @@ 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

+static const unsigned char *
+nios2_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = nios2_breakpoint_len;
+ return (const unsigned char *) &nios2_breakpoint;
+}
+
/* Implement the breakpoint_reinsert_addr linux_target_ops method. */

static CORE_ADDR
@@ -263,14 +274,7 @@ 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,
+ nios2_breakpoint_from_pc,
nios2_reinsert_addr,
0,
nios2_breakpoint_at,
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 188fac0..4c71cd9 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -486,6 +486,13 @@ ppc_arch_setup (void)
static const unsigned int ppc_breakpoint = 0x7d821008;
#define ppc_breakpoint_len 4

+static const unsigned char *
+ppc_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = ppc_breakpoint_len;
+ return (const unsigned char *) &ppc_breakpoint;
+}
+
static int
ppc_breakpoint_at (CORE_ADDR where)
{
@@ -685,8 +692,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
ppc_get_pc,
ppc_set_pc,
- (const unsigned char *) &ppc_breakpoint,
- ppc_breakpoint_len,
+ ppc_breakpoint_from_pc,
NULL,
0,
ppc_breakpoint_at,
diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c
index 8a0a689..f76f867 100644
--- a/gdb/gdbserver/linux-s390-low.c
+++ b/gdb/gdbserver/linux-s390-low.c
@@ -397,6 +397,13 @@ static struct regset_info s390_regsets[] = {
static const unsigned char s390_breakpoint[] = { 0, 1 };
#define s390_breakpoint_len 2

+static const unsigned char *
+s390_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = s390_breakpoint_len;
+ return (const unsigned char *) &s390_breakpoint;
+}
+
static CORE_ADDR
s390_get_pc (struct regcache *regcache)
{
@@ -665,8 +672,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
s390_get_pc,
s390_set_pc,
- s390_breakpoint,
- s390_breakpoint_len,
+ s390_breakpoint_from_pc,
NULL,
s390_breakpoint_len,
s390_breakpoint_at,
diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c
index 218d4d3..5c11fd7 100644
--- a/gdb/gdbserver/linux-sh-low.c
+++ b/gdb/gdbserver/linux-sh-low.c
@@ -77,6 +77,13 @@ sh_set_pc (struct regcache *regcache, CORE_ADDR pc)
static const unsigned short sh_breakpoint = 0xc3c3;
#define sh_breakpoint_len 2

+static const unsigned char *
+sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = sh_breakpoint_len;
+ return (const unsigned char *) &sh_breakpoint;
+}
+
static int
sh_breakpoint_at (CORE_ADDR where)
{
@@ -148,8 +155,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
sh_get_pc,
sh_set_pc,
- (const unsigned char *) &sh_breakpoint,
- sh_breakpoint_len,
+ sh_breakpoint_from_pc,
NULL,
0,
sh_breakpoint_at,
diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c
index 796af8a..35820fb 100644
--- a/gdb/gdbserver/linux-sparc-low.c
+++ b/gdb/gdbserver/linux-sparc-low.c
@@ -240,6 +240,12 @@ static const unsigned char sparc_breakpoint[INSN_SIZE] = {
};
#define sparc_breakpoint_len INSN_SIZE

+static const unsigned char *
+sparc_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = sparc_breakpoint_len;
+ return (const unsigned char *) &sparc_breakpoint;
+}

static int
sparc_breakpoint_at (CORE_ADDR where)
@@ -323,8 +329,7 @@ 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,
+ sparc_breakpoint_from_pc,
sparc_reinsert_addr,
0,
sparc_breakpoint_at,
diff --git a/gdb/gdbserver/linux-tic6x-low.c b/gdb/gdbserver/linux-tic6x-low.c
index a2ac3ee..86b433c 100644
--- a/gdb/gdbserver/linux-tic6x-low.c
+++ b/gdb/gdbserver/linux-tic6x-low.c
@@ -171,6 +171,14 @@ extern struct linux_target_ops the_low_target;

static int *tic6x_regmap;
static unsigned int tic6x_breakpoint;
+#define tic6x_breakpoint_len 4
+
+static const unsigned char *
+tic6x_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = tic6x_breakpoint_len;
+ return (const unsigned char *) &tic6x_breakpoint;
+}

/* Forward definition. */
static struct usrregs_info tic6x_usrregs_info;
@@ -247,8 +255,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 +373,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
tic6x_get_pc,
tic6x_set_pc,
- (const unsigned char *) &tic6x_breakpoint,
- tic6x_breakpoint_len,
+ tic6x_breakpoint_from_pc,
NULL,
0,
tic6x_breakpoint_at,
diff --git a/gdb/gdbserver/linux-tile-low.c b/gdb/gdbserver/linux-tile-low.c
index 6aaea6a..802812b 100644
--- a/gdb/gdbserver/linux-tile-low.c
+++ b/gdb/gdbserver/linux-tile-low.c
@@ -88,6 +88,13 @@ tile_set_pc (struct regcache *regcache, CORE_ADDR pc)
static uint64_t tile_breakpoint = 0x400b3cae70166000ULL;
#define tile_breakpoint_len 8

+static const unsigned char *
+tile_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = tile_breakpoint_len;
+ return (const unsigned char *) &tile_breakpoint;
+}
+
static int
tile_breakpoint_at (CORE_ADDR where)
{
@@ -182,8 +189,7 @@ struct linux_target_ops the_low_target =
NULL,
tile_get_pc,
tile_set_pc,
- (const unsigned char *) &tile_breakpoint,
- tile_breakpoint_len,
+ tile_breakpoint_from_pc,
NULL,
0,
tile_breakpoint_at,
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 20d4257..699eb4d 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -3243,6 +3243,13 @@ x86_emit_ops (void)
return &i386_emit_ops;
}

+static const unsigned char *
+x86_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = x86_breakpoint_len;
+ return x86_breakpoint;
+}
+
static int
x86_supports_range_stepping (void)
{
@@ -3261,8 +3268,7 @@ struct linux_target_ops the_low_target =
NULL, /* fetch_register */
x86_get_pc,
x86_set_pc,
- x86_breakpoint,
- x86_breakpoint_len,
+ x86_breakpoint_from_pc,
NULL,
1,
x86_breakpoint_at,
diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c
index debe467..1e2cf94 100644
--- a/gdb/gdbserver/linux-xtensa-low.c
+++ b/gdb/gdbserver/linux-xtensa-low.c
@@ -154,6 +154,13 @@ static struct regset_info xtensa_regsets[] = {
static const unsigned char xtensa_breakpoint[] = XTENSA_BREAKPOINT;
#define xtensa_breakpoint_len 2

+static const unsigned char *
+xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = xtensa_breakpoint_len;
+ return xtensa_breakpoint;
+}
+
static CORE_ADDR
xtensa_get_pc (struct regcache *regcache)
{
@@ -234,8 +241,7 @@ struct linux_target_ops the_low_target = {
NULL, /* fetch_register */
xtensa_get_pc,
xtensa_set_pc,
- xtensa_breakpoint,
- xtensa_breakpoint_len,
+ xtensa_breakpoint_from_pc,
NULL,
0,
xtensa_breakpoint_at,
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 7df8df3..fc2dbd7 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -438,6 +438,11 @@ struct target_ops
readlink(2). */
ssize_t (*multifs_readlink) (int pid, const char *filename,
char *buf, size_t bufsiz);
+
+ /* Return the raw breakpoint for this target based on PC. Note that the PC
+ can be NULL, the default breakpoint for the target should be returned in
+ this case. */
+ const unsigned char *(*breakpoint_from_pc) (CORE_ADDR *pcptr, int *lenptr);
};

extern struct target_ops *the_target;
diff --git a/gdb/gdbserver/win32-arm-low.c b/gdb/gdbserver/win32-arm-low.c
index d4b2c6f..1b469a3 100644
--- a/gdb/gdbserver/win32-arm-low.c
+++ b/gdb/gdbserver/win32-arm-low.c
@@ -113,6 +113,13 @@ arm_arch_setup (void)
static const unsigned long arm_wince_breakpoint = 0xe6000010;
#define arm_wince_breakpoint_len 4

+static const unsigned char *
+arm_wince_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = arm_wince_breakpoint_len;
+ return (const unsigned char *) &arm_wince_breakpoint;
+}
+
struct win32_target_ops the_low_target = {
arm_arch_setup,
sizeof (mappings) / sizeof (mappings[0]),
@@ -123,8 +130,7 @@ struct win32_target_ops the_low_target = {
arm_fetch_inferior_register,
arm_store_inferior_register,
NULL, /* single_step */
- (const unsigned char *) &arm_wince_breakpoint,
- arm_wince_breakpoint_len,
+ arm_wince_breakpoint_from_pc,
/* Watchpoint related functions. See target.h for comments. */
NULL, /* supports_z_point_type */
NULL, /* insert_point */
diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c
index 7c22f05..b9d60a7 100644
--- a/gdb/gdbserver/win32-i386-low.c
+++ b/gdb/gdbserver/win32-i386-low.c
@@ -444,6 +444,13 @@ i386_store_inferior_register (struct regcache *regcache,
static const unsigned char i386_win32_breakpoint = 0xcc;
#define i386_win32_breakpoint_len 1

+static const unsigned char *
+i386_win32_breakpoint_from_pc (CORE_ADDR *pcptr, int *len)
+{
+ *len = i386_win32_breakpoint_len;
+ return (const unsigned char *) &i386_win32_breakpoint;
+}
+
static void
i386_arch_setup (void)
{
@@ -466,8 +473,7 @@ struct win32_target_ops the_low_target = {
i386_fetch_inferior_register,
i386_store_inferior_register,
i386_single_step,
- &i386_win32_breakpoint,
- i386_win32_breakpoint_len,
+ i386_win32_breakpoint_from_pc,
i386_supports_z_point_type,
i386_insert_point,
i386_remove_point,
--
1.9.1