[09/31] gdbserver/linux-low: turn 'get_pc' and 'set_pc' into methods

Message ID c91f8468f4d094280df4e8e12feb990ffb1bc495.1583529166.git.tankut.baris.aktemur@intel.com
State New
Headers show
Series
  • Turn gdbserver's linux low targets into classes
Related show

Commit Message

Tankut Baris Aktemur March 6, 2020, 9:31 p.m.
gdbserver/ChangeLog:
2020-03-06  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	Turn the 'get_pc' and 'set_pc' linux target ops into methods
	of linux_process_target.

	* linux-low.h (struct linux_target_ops): Remove the ops.
	(class linux_process_target) <low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	* linux-low.cc (supports_breakpoints): Turn into...
	(linux_process_target::low_supports_breakpoints): ...this.
	(linux_process_target::low_get_pc): Define.
	(linux_process_target::low_set_pc): Define.

	Update the callers below.

	(linux_process_target::get_pc)
	(linux_process_target::save_stop_reason)
	(linux_process_target::maybe_move_out_of_jump_pad)
	(linux_process_target::wait_1)
	(linux_process_target::resume_one_lwp_throw)
	(linux_process_target::resume)
	(linux_process_target::proceed_all_lwps)
	(linux_process_target::read_pc)
	(linux_process_target::write_pc)

	* linux-x86-low.cc (class linux_process_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(x86_target::low_supports_breakpoints): Define.
	(x86_get_pc): Turn into...
	(x86_target::low_get_pc): ...this.
	(x86_set_pc): Turn into...
	(x86_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-arm-low.cc (class arm_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(arm_target::low_supports_breakpoints)
	(arm_target::low_get_pc)
	(arm_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-bfin-low.cc (class bfin_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(bfin_target::low_supports_breakpoints)
	(bfin_target::low_get_pc)
	(bfin_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-cris-low.cc (class cris_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(cris_target::low_supports_breakpoints)
	(cris_target::low_get_pc)
	(cris_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-crisv32-low.cc (class crisv32_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(crisv32_target::low_supports_breakpoints)
	(crisv32_target::low_get_pc)
	(crisv32_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-m32r-low.cc (class m32r_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(m32r_target::low_supports_breakpoints)
	(m32r_target::low_get_pc)
	(m32r_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-m68k-low.cc (class m68k_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(m68k_target::low_supports_breakpoints)
	(m68k_target::low_get_pc)
	(m68k_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-nios2-low.cc (class nios2_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(nios2_target::low_supports_breakpoints)
	(nios2_target::low_get_pc)
	(nios2_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-sh-low.cc (class sh_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(sh_target::low_supports_breakpoints)
	(sh_target::low_get_pc)
	(sh_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-xtensa-low.cc (class xtensa_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(xtensa_target::low_supports_breakpoints)
	(xtensa_target::low_get_pc)
	(xtensa_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-sparc-low.cc (class sparc_target)
	<low_supports_breakpoints>
	<low_get_pc>: Declare.
	(sparc_target::low_supports_breakpoints)
	(sparc_target::low_get_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-tile-low.cc (class tile_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(tile_target::low_supports_breakpoints)
	(tile_target::low_get_pc)
	(tile_target::low_set_pc): Define.
	(the_low_target): Remove the op fields.
	* linux-aarch64-low.cc (class aarch64_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(aarch64_target::low_supports_breakpoints): Define.
	(aarch64_get_pc): Turn into...
	(aarch64_target::low_get_pc): ...this.
	(aarch64_set_pc): Turn into...
	(aarch64_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-mips-low.cc (class mips_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(mips_target::low_supports_breakpoints): Define.
	(mips_get_pc): Turn into...
	(mips_target::low_get_pc): ...this.
	(mips_set_pc): Turn into...
	(mips_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-ppc-low.cc (class ppc_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(ppc_target::low_supports_breakpoints): Define.
	(ppc_get_pc): Turn into...
	(ppc_target::low_get_pc): ...this.
	(ppc_set_pc): Turn into...
	(ppc_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-riscv-low.cc (class riscv_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(riscv_target::low_supports_breakpoints): Define.
	(riscv_get_pc): Turn into...
	(riscv_target::low_get_pc): ...this.
	(riscv_set_pc): Turn into...
	(riscv_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-s390-low.cc (class s390_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(s390_target::low_supports_breakpoints): Define.
	(s390_get_pc): Turn into...
	(s390_target::low_get_pc): ...this.
	(s390_set_pc): Turn into...
	(s390_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
	* linux-tic6x-low.cc (class tic6x_target)
	<low_supports_breakpoints>
	<low_get_pc>
	<low_set_pc>: Declare.
	(tic6x_target::low_supports_breakpoints): Define.
	(tic6x_get_pc): Turn into...
	(tic6x_target::low_get_pc): ...this.
	(tic6x_set_pc): Turn into...
	(tic6x_target::low_set_pc): ...this.
	(the_low_target): Remove the op fields.
---
 gdbserver/linux-aarch64-low.cc | 26 +++++++++++-----
 gdbserver/linux-arm-low.cc     | 26 ++++++++++++++--
 gdbserver/linux-bfin-low.cc    | 26 ++++++++++++++--
 gdbserver/linux-cris-low.cc    | 26 ++++++++++++++--
 gdbserver/linux-crisv32-low.cc | 26 ++++++++++++++--
 gdbserver/linux-low.cc         | 55 ++++++++++++++++++++--------------
 gdbserver/linux-low.h          | 11 +++++--
 gdbserver/linux-m32r-low.cc    | 26 ++++++++++++++--
 gdbserver/linux-m68k-low.cc    | 26 ++++++++++++++--
 gdbserver/linux-mips-low.cc    | 22 ++++++++++----
 gdbserver/linux-nios2-low.cc   | 26 ++++++++++++++--
 gdbserver/linux-ppc-low.cc     | 22 ++++++++++----
 gdbserver/linux-riscv-low.cc   | 26 +++++++++++-----
 gdbserver/linux-s390-low.cc    | 22 ++++++++++----
 gdbserver/linux-sh-low.cc      | 26 ++++++++++++++--
 gdbserver/linux-sparc-low.cc   | 21 +++++++++++--
 gdbserver/linux-tic6x-low.cc   | 22 ++++++++++----
 gdbserver/linux-tile-low.cc    | 26 ++++++++++++++--
 gdbserver/linux-x86-low.cc     | 22 ++++++++++----
 gdbserver/linux-xtensa-low.cc  | 26 ++++++++++++++--
 20 files changed, 414 insertions(+), 95 deletions(-)

-- 
2.17.1

Patch

diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 0bcac19384a..6bed620320d 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -64,6 +64,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -189,10 +195,16 @@  aarch64_store_pauthregset (struct regcache *regcache, const void *buf)
 		   &pauth_regset[1]);
 }
 
-/* Implementation of linux_target_ops method "get_pc".  */
+bool
+aarch64_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+/* Implementation of linux target ops method "low_get_pc".  */
 
-static CORE_ADDR
-aarch64_get_pc (struct regcache *regcache)
+CORE_ADDR
+aarch64_target::low_get_pc (regcache *regcache)
 {
   if (register_size (regcache->tdesc, 0) == 8)
     return linux_get_pc_64bit (regcache);
@@ -200,10 +212,10 @@  aarch64_get_pc (struct regcache *regcache)
     return linux_get_pc_32bit (regcache);
 }
 
-/* Implementation of linux_target_ops method "set_pc".  */
+/* Implementation of linux target ops method "low_set_pc".  */
 
-static void
-aarch64_set_pc (struct regcache *regcache, CORE_ADDR pc)
+void
+aarch64_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
 {
   if (register_size (regcache->tdesc, 0) == 8)
     linux_set_pc_64bit (regcache, pc);
@@ -3085,8 +3097,6 @@  aarch64_supports_hardware_single_step (void)
 
 struct linux_target_ops the_low_target =
 {
-  aarch64_get_pc,
-  aarch64_set_pc,
   aarch64_breakpoint_kind_from_pc,
   aarch64_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-arm-low.cc b/gdbserver/linux-arm-low.cc
index 1bbf0e6977f..7b9ef8999f6 100644
--- a/gdbserver/linux-arm-low.cc
+++ b/gdbserver/linux-arm-low.cc
@@ -69,12 +69,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static arm_target the_arm_target;
 
+bool
+arm_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+arm_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+arm_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Information describing the hardware breakpoint capabilities.  */
 static struct
 {
@@ -1027,8 +1051,6 @@  arm_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   arm_breakpoint_kind_from_pc,
   arm_sw_breakpoint_from_kind,
   arm_gdbserver_get_next_pcs,
diff --git a/gdbserver/linux-bfin-low.cc b/gdbserver/linux-bfin-low.cc
index a8bb8f03ce0..f734c122090 100644
--- a/gdbserver/linux-bfin-low.cc
+++ b/gdbserver/linux-bfin-low.cc
@@ -38,12 +38,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static bfin_target the_bfin_target;
 
+bool
+bfin_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+bfin_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+bfin_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-bfin.c.  */
 void init_registers_bfin (void);
 extern const struct target_desc *tdesc_bfin;
@@ -135,8 +159,6 @@  bfin_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   bfin_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-cris-low.cc b/gdbserver/linux-cris-low.cc
index 7956922f7e5..50c9b5bd858 100644
--- a/gdbserver/linux-cris-low.cc
+++ b/gdbserver/linux-cris-low.cc
@@ -35,12 +35,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static cris_target the_cris_target;
 
+bool
+cris_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+cris_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+cris_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-cris.c.  */
 void init_registers_cris (void);
 extern const struct target_desc *tdesc_cris;
@@ -132,8 +156,6 @@  cris_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-crisv32-low.cc b/gdbserver/linux-crisv32-low.cc
index 828ac111d10..1d650e3ded9 100644
--- a/gdbserver/linux-crisv32-low.cc
+++ b/gdbserver/linux-crisv32-low.cc
@@ -35,6 +35,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -55,6 +61,24 @@  crisv32_target::low_cannot_store_register (int regno)
 			  "is not implemented by the target");
 }
 
+bool
+crisv32_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+crisv32_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+crisv32_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-crisv32.c.  */
 void init_registers_crisv32 (void);
 extern const struct target_desc *tdesc_crisv32;
@@ -429,8 +453,6 @@  crisv32_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   cris_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 65edde8b0e8..47b2ef9fd31 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -301,13 +301,22 @@  can_software_single_step (void)
   return (the_low_target.get_next_pcs != NULL);
 }
 
-/* True if the low target supports memory breakpoints.  If so, we'll
-   have a GET_PC implementation.  */
+bool
+linux_process_target::low_supports_breakpoints ()
+{
+  return false;
+}
 
-static int
-supports_breakpoints (void)
+CORE_ADDR
+linux_process_target::low_get_pc (regcache *regcache)
+{
+  return 0;
+}
+
+void
+linux_process_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
 {
-  return (the_low_target.get_pc != NULL);
+  gdb_assert_not_reached ("linux target op low_set_pc is not implemented");
 }
 
 /* Returns true if this target can support fast tracepoints.  This
@@ -728,14 +737,14 @@  linux_process_target::get_pc (lwp_info *lwp)
   struct regcache *regcache;
   CORE_ADDR pc;
 
-  if (the_low_target.get_pc == NULL)
+  if (!low_supports_breakpoints ())
     return 0;
 
   saved_thread = current_thread;
   current_thread = get_lwp_thread (lwp);
 
   regcache = get_thread_regcache (current_thread, 1);
-  pc = (*the_low_target.get_pc) (regcache);
+  pc = low_get_pc (regcache);
 
   if (debug_threads)
     debug_printf ("pc is 0x%lx\n", (long) pc);
@@ -785,7 +794,7 @@  linux_process_target::save_stop_reason (lwp_info *lwp)
   siginfo_t siginfo;
 #endif
 
-  if (the_low_target.get_pc == NULL)
+  if (!low_supports_breakpoints ())
     return false;
 
   pc = get_pc (lwp);
@@ -868,7 +877,7 @@  linux_process_target::save_stop_reason (lwp_info *lwp)
 	{
 	  struct regcache *regcache
 	    = get_thread_regcache (current_thread, 1);
-	  (*the_low_target.set_pc) (regcache, sw_breakpoint_pc);
+	  low_set_pc (regcache, sw_breakpoint_pc);
 	}
 
       /* Update this so we record the correct stop PC below.  */
@@ -2092,7 +2101,7 @@  linux_process_target::maybe_move_out_of_jump_pad (lwp_info *lwp, int *wstat)
 		}
 
 	      regcache = get_thread_regcache (current_thread, 1);
-	      (*the_low_target.set_pc) (regcache, status.tpoint_addr);
+	      low_set_pc (regcache, status.tpoint_addr);
 	      lwp->stop_pc = status.tpoint_addr;
 
 	      /* Cancel any fast tracepoint lock this thread was
@@ -3170,7 +3179,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	    = get_thread_regcache (current_thread, 1);
 
 	  event_child->stop_pc += increment_pc;
-	  (*the_low_target.set_pc) (regcache, event_child->stop_pc);
+	  low_set_pc (regcache, event_child->stop_pc);
 
 	  if (!(*the_low_target.breakpoint_at) (event_child->stop_pc))
 	    event_child->stop_reason = TARGET_STOPPED_BY_NO_REASON;
@@ -3183,7 +3192,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
      not support internal breakpoints at all, we also report the
      SIGTRAP without further processing; it's of no concern to us.  */
   maybe_internal_trap
-    = (supports_breakpoints ()
+    = (low_supports_breakpoints ()
        && (WSTOPSIG (w) == SIGTRAP
 	   || ((WSTOPSIG (w) == SIGILL
 		|| WSTOPSIG (w) == SIGSEGV)
@@ -3478,11 +3487,11 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	 decr_pc_after_break adjustment to the inferior's regcache
 	 ourselves.  */
 
-      if (the_low_target.set_pc != NULL)
+      if (low_supports_breakpoints ())
 	{
 	  struct regcache *regcache
 	    = get_thread_regcache (current_thread, 1);
-	  (*the_low_target.set_pc) (regcache, event_child->stop_pc);
+	  low_set_pc (regcache, event_child->stop_pc);
 	}
 
       if (step_over_finished)
@@ -3693,7 +3702,7 @@  linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
 	{
 	  struct regcache *regcache
 	    = get_thread_regcache (current_thread, 1);
-	  (*the_low_target.set_pc) (regcache, event_child->stop_pc + decr_pc);
+	  low_set_pc (regcache, event_child->stop_pc + decr_pc);
 	}
     }
 
@@ -4285,11 +4294,11 @@  linux_process_target::resume_one_lwp_throw (lwp_info *lwp, int step,
       step = single_step (lwp);
     }
 
-  if (proc->tdesc != NULL && the_low_target.get_pc != NULL)
+  if (proc->tdesc != NULL && low_supports_breakpoints ())
     {
       struct regcache *regcache = get_thread_regcache (current_thread, 1);
 
-      lwp->stop_pc = (*the_low_target.get_pc) (regcache);
+      lwp->stop_pc = low_get_pc (regcache);
 
       if (debug_threads)
 	{
@@ -4915,7 +4924,7 @@  linux_process_target::resume (thread_resume *resume_info, size_t n)
      other threads stopped, then resume all threads again.  Make sure
      to queue any signals that would otherwise be delivered or
      queued.  */
-  if (!any_pending && supports_breakpoints ())
+  if (!any_pending && low_supports_breakpoints ())
     need_step_over = find_thread ([this] (thread_info *thread)
 		       {
 			 return thread_needs_step_over (thread);
@@ -5077,7 +5086,7 @@  linux_process_target::proceed_all_lwps ()
      resume any threads - have it step over the breakpoint with all
      other threads stopped, then resume all threads again.  */
 
-  if (supports_breakpoints ())
+  if (low_supports_breakpoints ())
     {
       need_step_over = find_thread ([this] (thread_info *thread)
 			 {
@@ -6453,18 +6462,18 @@  linux_process_target::supports_tracepoints ()
 CORE_ADDR
 linux_process_target::read_pc (regcache *regcache)
 {
-  if (the_low_target.get_pc == NULL)
+  if (!low_supports_breakpoints ())
     return 0;
 
-  return (*the_low_target.get_pc) (regcache);
+  return low_get_pc (regcache);
 }
 
 void
 linux_process_target::write_pc (regcache *regcache, CORE_ADDR pc)
 {
-  gdb_assert (the_low_target.set_pc != NULL);
+  gdb_assert (low_supports_breakpoints ());
 
-  (*the_low_target.set_pc) (regcache, pc);
+  low_set_pc (regcache, pc);
 }
 
 bool
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 4f5502b4640..4d2435cd59d 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -131,9 +131,6 @@  struct lwp_info;
 
 struct linux_target_ops
 {
-  CORE_ADDR (*get_pc) (struct regcache *regcache);
-  void (*set_pc) (struct regcache *regcache, CORE_ADDR newpc);
-
   /* See target.h for details.  */
   int (*breakpoint_kind_from_pc) (CORE_ADDR *pcptr);
 
@@ -676,6 +673,14 @@  class linux_process_target : public process_stratum_target
      REGNO was supplied, false if not, and we should fallback to the
      standard ptrace methods.  */
   virtual bool low_fetch_register (regcache *regcache, int regno);
+
+  /* Return true if breakpoints are supported.  Such targets must
+     implement the GET_PC and SET_PC methods.  */
+  virtual bool low_supports_breakpoints ();
+
+  virtual CORE_ADDR low_get_pc (regcache *regcache);
+
+  virtual void low_set_pc (regcache *regcache, CORE_ADDR newpc);
 };
 
 extern linux_process_target *the_linux_target;
diff --git a/gdbserver/linux-m32r-low.cc b/gdbserver/linux-m32r-low.cc
index 82a503401b8..090b75d8112 100644
--- a/gdbserver/linux-m32r-low.cc
+++ b/gdbserver/linux-m32r-low.cc
@@ -38,12 +38,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static m32r_target the_m32r_target;
 
+bool
+m32r_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+m32r_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+m32r_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-m32r.c.  */
 void init_registers_m32r (void);
 extern const struct target_desc *tdesc_m32r;
@@ -134,8 +158,6 @@  m32r_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_from_pc */
   m32r_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-m68k-low.cc b/gdbserver/linux-m68k-low.cc
index 6a3a2aab383..07bbae6da61 100644
--- a/gdbserver/linux-m68k-low.cc
+++ b/gdbserver/linux-m68k-low.cc
@@ -34,12 +34,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static m68k_target the_m68k_target;
 
+bool
+m68k_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+m68k_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+m68k_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-m68k.c.  */
 void init_registers_m68k (void);
 extern const struct target_desc *tdesc_m68k;
@@ -229,8 +253,6 @@  m68k_supports_hardware_single_step (void)
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   m68k_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-mips-low.cc b/gdbserver/linux-mips-low.cc
index ae925ffb6cc..22cd3bd3300 100644
--- a/gdbserver/linux-mips-low.cc
+++ b/gdbserver/linux-mips-low.cc
@@ -42,6 +42,12 @@  protected:
   bool low_cannot_store_register (int regno) override;
 
   bool low_fetch_register (regcache *regcache, int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -279,16 +285,22 @@  mips_target::low_fetch_register (regcache *regcache, int regno)
   return false;
 }
 
-static CORE_ADDR
-mips_get_pc (struct regcache *regcache)
+bool
+mips_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+mips_target::low_get_pc (regcache *regcache)
 {
   union mips_register pc;
   collect_register_by_name (regcache, "pc", pc.buf);
   return register_size (regcache->tdesc, 0) == 4 ? pc.reg32 : pc.reg64;
 }
 
-static void
-mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
+void
+mips_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
 {
   union mips_register newpc;
   if (register_size (regcache->tdesc, 0) == 4)
@@ -952,8 +964,6 @@  mips_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  mips_get_pc,
-  mips_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   mips_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-nios2-low.cc b/gdbserver/linux-nios2-low.cc
index a58d9ca99fb..c1372dd6d3c 100644
--- a/gdbserver/linux-nios2-low.cc
+++ b/gdbserver/linux-nios2-low.cc
@@ -46,12 +46,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static nios2_target the_nios2_target;
 
+bool
+nios2_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+nios2_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+nios2_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* The following definition must agree with the number of registers
    defined in "struct user_regs" in GLIBC
    (sysdeps/unix/sysv/linux/nios2/sys/user.h), and also with
@@ -251,8 +275,6 @@  nios2_target::get_regs_info ()
 
 struct linux_target_ops the_low_target =
 {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   nios2_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-ppc-low.cc b/gdbserver/linux-ppc-low.cc
index 096308a44d8..4aa7f5159b5 100644
--- a/gdbserver/linux-ppc-low.cc
+++ b/gdbserver/linux-ppc-low.cc
@@ -59,6 +59,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -241,8 +247,14 @@  ppc_supply_ptrace_register (struct regcache *regcache,
     perror_with_name ("Unexpected byte order");
 }
 
-static CORE_ADDR
-ppc_get_pc (struct regcache *regcache)
+bool
+ppc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+ppc_target::low_get_pc (regcache *regcache)
 {
   if (register_size (regcache->tdesc, 0) == 4)
     {
@@ -258,8 +270,8 @@  ppc_get_pc (struct regcache *regcache)
     }
 }
 
-static void
-ppc_set_pc (struct regcache *regcache, CORE_ADDR pc)
+void
+ppc_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
 {
   if (register_size (regcache->tdesc, 0) == 4)
     {
@@ -3392,8 +3404,6 @@  ppc_get_ipa_tdesc_idx (void)
 }
 
 struct linux_target_ops the_low_target = {
-  ppc_get_pc,
-  ppc_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   ppc_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-riscv-low.cc b/gdbserver/linux-riscv-low.cc
index 69af59f7200..4fb2308a452 100644
--- a/gdbserver/linux-riscv-low.cc
+++ b/gdbserver/linux-riscv-low.cc
@@ -47,6 +47,12 @@  protected:
   bool low_cannot_store_register (int regno) override;
 
   bool low_fetch_register (regcache *regcache, int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -203,10 +209,16 @@  riscv_target::low_fetch_register (regcache *regcache, int regno)
   return true;
 }
 
-/* Implementation of linux_target_ops method "get_pc".  */
+bool
+riscv_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+/* Implementation of linux target ops method "low_get_pc".  */
 
-static CORE_ADDR
-riscv_get_pc (struct regcache *regcache)
+CORE_ADDR
+riscv_target::low_get_pc (regcache *regcache)
 {
   elf_gregset_t regset;
 
@@ -216,10 +228,10 @@  riscv_get_pc (struct regcache *regcache)
     return linux_get_pc_32bit (regcache);
 }
 
-/* Implementation of linux_target_ops method "set_pc".  */
+/* Implementation of linux target ops method "low_set_pc".  */
 
-static void
-riscv_set_pc (struct regcache *regcache, CORE_ADDR newpc)
+void
+riscv_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
 {
   elf_gregset_t regset;
 
@@ -293,8 +305,6 @@  riscv_breakpoint_at (CORE_ADDR pc)
 /* RISC-V/Linux target operations.  */
 struct linux_target_ops the_low_target =
 {
-  riscv_get_pc,
-  riscv_set_pc,
   riscv_breakpoint_kind_from_pc,
   riscv_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-s390-low.cc b/gdbserver/linux-s390-low.cc
index d25fafa4cdf..ef5e8227d50 100644
--- a/gdbserver/linux-s390-low.cc
+++ b/gdbserver/linux-s390-low.cc
@@ -66,6 +66,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -454,8 +460,14 @@  s390_sw_breakpoint_from_kind (int kind, int *size)
   return s390_breakpoint;
 }
 
-static CORE_ADDR
-s390_get_pc (struct regcache *regcache)
+bool
+s390_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+s390_target::low_get_pc (regcache *regcache)
 {
   if (register_size (regcache->tdesc, 0) == 4)
     {
@@ -471,8 +483,8 @@  s390_get_pc (struct regcache *regcache)
     }
 }
 
-static void
-s390_set_pc (struct regcache *regcache, CORE_ADDR newpc)
+void
+s390_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
 {
   if (register_size (regcache->tdesc, 0) == 4)
     {
@@ -2812,8 +2824,6 @@  s390_emit_ops (void)
 }
 
 struct linux_target_ops the_low_target = {
-  s390_get_pc,
-  s390_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   s390_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-sh-low.cc b/gdbserver/linux-sh-low.cc
index 42bd427d47c..4e514257185 100644
--- a/gdbserver/linux-sh-low.cc
+++ b/gdbserver/linux-sh-low.cc
@@ -34,12 +34,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static sh_target the_sh_target;
 
+bool
+sh_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+sh_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+sh_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-sh.c.  */
 void init_registers_sh (void);
 extern const struct target_desc *tdesc_sh;
@@ -164,8 +188,6 @@  sh_target::low_arch_setup ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   sh_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-sparc-low.cc b/gdbserver/linux-sparc-low.cc
index b68ed2d36ad..b415deeaa6a 100644
--- a/gdbserver/linux-sparc-low.cc
+++ b/gdbserver/linux-sparc-low.cc
@@ -57,12 +57,30 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  /* No low_set_pc is needed.  */
 };
 
 /* The singleton target ops object.  */
 
 static sparc_target the_sparc_target;
 
+bool
+sparc_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+sparc_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_64bit (regcache);
+}
+
 /* Each offset is multiplied by 8, because of the register size.
    These offsets apply to the buffer sent/filled by ptrace.
    Additionally, the array elements order corresponds to the .dat file, and the
@@ -319,9 +337,6 @@  sparc_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_64bit,
-  /* No sparc_set_pc is needed.  */
-  NULL,
   NULL, /* breakpoint_kind_from_pc */
   sparc_sw_breakpoint_from_kind,
   NULL, /* get_next_pcs */
diff --git a/gdbserver/linux-tic6x-low.cc b/gdbserver/linux-tic6x-low.cc
index 5cfdd091c38..790b4e44baf 100644
--- a/gdbserver/linux-tic6x-low.cc
+++ b/gdbserver/linux-tic6x-low.cc
@@ -53,6 +53,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -239,8 +245,14 @@  tic6x_target::low_cannot_store_register (int regno)
   return (tic6x_regmap[regno] == -1);
 }
 
-static CORE_ADDR
-tic6x_get_pc (struct regcache *regcache)
+bool
+tic6x_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+tic6x_target::low_get_pc (regcache *regcache)
 {
   union tic6x_register pc;
 
@@ -248,8 +260,8 @@  tic6x_get_pc (struct regcache *regcache)
   return pc.reg32;
 }
 
-static void
-tic6x_set_pc (struct regcache *regcache, CORE_ADDR pc)
+void
+tic6x_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
 {
   union tic6x_register newpc;
 
@@ -407,8 +419,6 @@  tic6x_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  tic6x_get_pc,
-  tic6x_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   tic6x_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-tile-low.cc b/gdbserver/linux-tile-low.cc
index a6138e78aa7..9756c6c3fb9 100644
--- a/gdbserver/linux-tile-low.cc
+++ b/gdbserver/linux-tile-low.cc
@@ -38,12 +38,36 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
 
 static tile_target the_tile_target;
 
+bool
+tile_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+tile_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_64bit (regcache);
+}
+
+void
+tile_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_64bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-tilegx.c.  */
 void init_registers_tilegx (void);
 extern const struct target_desc *tdesc_tilegx;
@@ -196,8 +220,6 @@  tile_supports_hardware_single_step (void)
 
 struct linux_target_ops the_low_target =
 {
-  linux_get_pc_64bit,
-  linux_set_pc_64bit,
   NULL, /* breakpoint_kind_from_pc */
   tile_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 475d77767f5..9aa29f81522 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -113,6 +113,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -494,8 +500,14 @@  static struct regset_info x86_regsets[] =
   NULL_REGSET
 };
 
-static CORE_ADDR
-x86_get_pc (struct regcache *regcache)
+bool
+x86_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+x86_target::low_get_pc (regcache *regcache)
 {
   int use_64bit = register_size (regcache->tdesc, 0) == 8;
 
@@ -515,8 +527,8 @@  x86_get_pc (struct regcache *regcache)
     }
 }
 
-static void
-x86_set_pc (struct regcache *regcache, CORE_ADDR pc)
+void
+x86_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
 {
   int use_64bit = register_size (regcache->tdesc, 0) == 8;
 
@@ -2885,8 +2897,6 @@  x86_get_ipa_tdesc_idx (void)
 
 struct linux_target_ops the_low_target =
 {
-  x86_get_pc,
-  x86_set_pc,
   NULL, /* breakpoint_kind_from_pc */
   x86_sw_breakpoint_from_kind,
   NULL,
diff --git a/gdbserver/linux-xtensa-low.cc b/gdbserver/linux-xtensa-low.cc
index d71b2c97fa4..fb680bdb965 100644
--- a/gdbserver/linux-xtensa-low.cc
+++ b/gdbserver/linux-xtensa-low.cc
@@ -35,6 +35,12 @@  protected:
   bool low_cannot_fetch_register (int regno) override;
 
   bool low_cannot_store_register (int regno) override;
+
+  bool low_supports_breakpoints () override;
+
+  CORE_ADDR low_get_pc (regcache *regcache) override;
+
+  void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
 };
 
 /* The singleton target ops object.  */
@@ -55,6 +61,24 @@  xtensa_target::low_cannot_store_register (int regno)
 			  "is not implemented by the target");
 }
 
+bool
+xtensa_target::low_supports_breakpoints ()
+{
+  return true;
+}
+
+CORE_ADDR
+xtensa_target::low_get_pc (regcache *regcache)
+{
+  return linux_get_pc_32bit (regcache);
+}
+
+void
+xtensa_target::low_set_pc (regcache *regcache, CORE_ADDR pc)
+{
+  linux_set_pc_32bit (regcache, pc);
+}
+
 /* Defined in auto-generated file reg-xtensa.c.  */
 void init_registers_xtensa (void);
 extern const struct target_desc *tdesc_xtensa;
@@ -302,8 +326,6 @@  xtensa_target::get_regs_info ()
 }
 
 struct linux_target_ops the_low_target = {
-  linux_get_pc_32bit,
-  linux_set_pc_32bit,
   NULL, /* breakpoint_kind_from_pc */
   xtensa_sw_breakpoint_from_kind,
   NULL,