Patchwork [v2,03/10] Add reg_buffer_common

login
register
mail settings
Submitter Alan Hayward
Date June 6, 2018, 3:16 p.m.
Message ID <20180606151629.36602-4-alan.hayward@arm.com>
Download mbox | patch
Permalink /patch/27661/
State New
Headers show

Comments

Alan Hayward - June 6, 2018, 3:16 p.m.
A purely virtual class containing functions from gdb/regcache.h

Both the gdb regcache structures and gdbserver regcache inherit
directly from reg_buffer_common. This will allow for common
functions which require the use of a regcache.

2018-06-06  Alan Hayward  <alan.hayward@arm.com>

gdb/
	* common/common-regcache.h (reg_buffer_common): New structure.
	* regcache.h (reg_buffer_common:get_register_status) Add override.
	(reg_buffer_common:raw_supply): Add dummy function.
	reg_buffer_common:raw_collect): Likewise
	(readable_regcache:raw_supply) Add override.
	(detached_regcache:raw_collect) Likewise.

gdbserver/
	* regcache.c (new_register_cache): Use new.
	(free_register_cache): Use delete.
	register_data): Use const.
	(supply_register): Call member function.
	(regcache::raw_supply): Replacement for supply_register.
        (collect_register): Call member function.
	(regcache::raw_collect): Replacement for collect_register.
	(regcache::get_register_status): New function.
	* regcache.h (regcache:raw_supply): Add dummy function.
	(regcache:raw_collect): Likewise
	(regcache:get_register_status) Likewise.
---
 gdb/common/common-regcache.h |  8 ++++++++
 gdb/gdbserver/regcache.c     | 47 ++++++++++++++++++++++++++++++++------------
 gdb/gdbserver/regcache.h     | 18 +++++++++++------
 gdb/regcache.h               | 19 ++++++++++++++----
 4 files changed, 69 insertions(+), 23 deletions(-)
Simon Marchi - June 7, 2018, 8:18 p.m.
Hi Alan,

Just some quick comments.

I get this when building on x86-64 with --enable-targets=all:

  CXX    aarch64-tdep.o
In file included from /home/emaisin/src/binutils-gdb/gdb/nat/aarch64-sve-linux-ptrace.h:29:0,
                 from /home/emaisin/src/binutils-gdb/gdb/aarch64-tdep.c:61:
/home/emaisin/src/binutils-gdb/gdb/nat/aarch64-linux-sigcontext.h:19:22: error: field ‘head’ has incomplete type ‘_aarch64_ctx’
  struct _aarch64_ctx head;
                      ^
/home/emaisin/src/binutils-gdb/gdb/nat/aarch64-linux-sigcontext.h:19:9: note: forward declaration of ‘struct _aarch64_ctx’
  struct _aarch64_ctx head;
         ^

First, we should not include "nat/aarch64-sve-linux-ptrace.h" (a file that only makes
sense when building on AArch64) in aarch64-tdep.c, a file built on all architecture
when including the support for AArch64 debugging.  It looks like aarch64-tdep.c
needs sve_vq_from_vl.  Maybe that definition could be moved to arch/, which can be
included in aarch64-tdep.c.

Then, is the _aarch64_ctx structure guaranteed to be defined on older AArch64 kernels
or should we include it too?

On 2018-06-06 11:16 AM, Alan Hayward wrote:
> A purely virtual class containing functions from gdb/regcache.h
> 
> Both the gdb regcache structures and gdbserver regcache inherit
> directly from reg_buffer_common. This will allow for common
> functions which require the use of a regcache.
> 
> 2018-06-06  Alan Hayward  <alan.hayward@arm.com>
> 
> gdb/
> 	* common/common-regcache.h (reg_buffer_common): New structure.
> 	* regcache.h (reg_buffer_common:get_register_status) Add override.
> 	(reg_buffer_common:raw_supply): Add dummy function.
> 	reg_buffer_common:raw_collect): Likewise
> 	(readable_regcache:raw_supply) Add override.
> 	(detached_regcache:raw_collect) Likewise.
> 
> gdbserver/
> 	* regcache.c (new_register_cache): Use new.
> 	(free_register_cache): Use delete.
> 	register_data): Use const.
> 	(supply_register): Call member function.
> 	(regcache::raw_supply): Replacement for supply_register.
>         (collect_register): Call member function.
> 	(regcache::raw_collect): Replacement for collect_register.
> 	(regcache::get_register_status): New function.
> 	* regcache.h (regcache:raw_supply): Add dummy function.
> 	(regcache:raw_collect): Likewise
> 	(regcache:get_register_status) Likewise.
> ---
>  gdb/common/common-regcache.h |  8 ++++++++
>  gdb/gdbserver/regcache.c     | 47 ++++++++++++++++++++++++++++++++------------
>  gdb/gdbserver/regcache.h     | 18 +++++++++++------
>  gdb/regcache.h               | 19 ++++++++++++++----
>  4 files changed, 69 insertions(+), 23 deletions(-)
> 
> diff --git a/gdb/common/common-regcache.h b/gdb/common/common-regcache.h
> index 696ba00955..487da0a7fb 100644
> --- a/gdb/common/common-regcache.h
> +++ b/gdb/common/common-regcache.h
> @@ -62,4 +62,12 @@ extern enum register_status regcache_raw_read_unsigned
>  
>  ULONGEST regcache_raw_get_unsigned (struct regcache *regcache, int regnum);
>  
> +struct reg_buffer_common
> +{
> +  virtual ~reg_buffer_common () = default;
> +  virtual void raw_supply (int regnum, const void *buf) = 0;
> +  virtual void raw_collect (int regnum, void *buf) const = 0;
> +  virtual register_status get_register_status (int regnum) const = 0;
> +};

Ideally, we would gather the documentation for these methods here.  Where they
are implemented/overriden, we can maybe add a reference such as

  /* See struct reg_buffer_common.  */

?

> diff --git a/gdb/regcache.h b/gdb/regcache.h
> index 3edddf47e1..b559a10752 100644
> --- a/gdb/regcache.h
> +++ b/gdb/regcache.h
> @@ -139,7 +139,7 @@ typedef struct cached_reg
>  
>  /* Buffer of registers.  */
>  
> -class reg_buffer
> +class reg_buffer : public reg_buffer_common
>  {
>  public:
>    reg_buffer (gdbarch *gdbarch, bool has_pseudo);
> @@ -151,13 +151,24 @@ public:
>  
>    /* Get the availability status of the value of register REGNUM in this
>       buffer.  */
> -  enum register_status get_register_status (int regnum) const;
> +  enum register_status get_register_status (int regnum) const override;
>  
>    virtual ~reg_buffer ()
>    {
>      xfree (m_registers);
>      xfree (m_register_status);
>    }
> +
> +  virtual void raw_supply (int regnum, const void *buf) override
> +  {
> +    gdb_assert (false);
> +  }
> +
> +  virtual void raw_collect (int regnum, void *buf) const override
> +  {
> +    gdb_assert (false);
> +  }

Hmm, I understand why you need to do this right now.  But what do you think of the
idea of moving the supply and collect implementations up to reg_buffer?  I think
that the supply/collect operations are a good fit to go in reg_buffer.  Essentially
they just peek/poke in the buffer.  The regcache layer's responsibility is then to
use that register buffer to implement a cache in front of the target registers,
and offer the API to properly read/write registers (including pseudo ones).

For reference here's the patch in the regcache-for-alan branch that did this:
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=0e04bb35765d2717818dddd88328cb975f417b2c;hp=ca9f66e37913be55abaea44813a768b40673a39a

Simon
Simon Marchi - June 7, 2018, 8:41 p.m.
On 2018-06-07 04:18 PM, Simon Marchi wrote:
> Hi Alan,
> 
> Just some quick comments.
> 
> I get this when building on x86-64 with --enable-targets=all:
> 
>   CXX    aarch64-tdep.o
> In file included from /home/emaisin/src/binutils-gdb/gdb/nat/aarch64-sve-linux-ptrace.h:29:0,
>                  from /home/emaisin/src/binutils-gdb/gdb/aarch64-tdep.c:61:
> /home/emaisin/src/binutils-gdb/gdb/nat/aarch64-linux-sigcontext.h:19:22: error: field ‘head’ has incomplete type ‘_aarch64_ctx’
>   struct _aarch64_ctx head;
>                       ^
> /home/emaisin/src/binutils-gdb/gdb/nat/aarch64-linux-sigcontext.h:19:9: note: forward declaration of ‘struct _aarch64_ctx’
>   struct _aarch64_ctx head;
>          ^
> 
> First, we should not include "nat/aarch64-sve-linux-ptrace.h" (a file that only makes
> sense when building on AArch64) in aarch64-tdep.c, a file built on all architecture
> when including the support for AArch64 debugging.  It looks like aarch64-tdep.c
> needs sve_vq_from_vl.  Maybe that definition could be moved to arch/, which can be
> included in aarch64-tdep.c.
> 
> Then, is the _aarch64_ctx structure guaranteed to be defined on older AArch64 kernels
> or should we include it too?

Sorry, I mixed things up, this feedback is about patch 2/10 actually.  The other
comments apply to this patch (3/10).

Simon

Patch

diff --git a/gdb/common/common-regcache.h b/gdb/common/common-regcache.h
index 696ba00955..487da0a7fb 100644
--- a/gdb/common/common-regcache.h
+++ b/gdb/common/common-regcache.h
@@ -62,4 +62,12 @@  extern enum register_status regcache_raw_read_unsigned
 
 ULONGEST regcache_raw_get_unsigned (struct regcache *regcache, int regnum);
 
+struct reg_buffer_common
+{
+  virtual ~reg_buffer_common () = default;
+  virtual void raw_supply (int regnum, const void *buf) = 0;
+  virtual void raw_collect (int regnum, void *buf) const = 0;
+  virtual register_status get_register_status (int regnum) const = 0;
+};
+
 #endif /* COMMON_REGCACHE_H */
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index 0718b9f9a0..857721ee3d 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -159,7 +159,7 @@  init_register_cache (struct regcache *regcache,
 struct regcache *
 new_register_cache (const struct target_desc *tdesc)
 {
-  struct regcache *regcache = XCNEW (struct regcache);
+  struct regcache *regcache = new struct regcache;
 
   gdb_assert (tdesc->registers_size != 0);
 
@@ -174,7 +174,7 @@  free_register_cache (struct regcache *regcache)
       if (regcache->registers_owned)
 	free (regcache->registers);
       free (regcache->register_status);
-      free (regcache);
+      delete regcache;
     }
 }
 
@@ -300,7 +300,7 @@  regcache_register_size (const struct regcache *regcache, int n)
 }
 
 static unsigned char *
-register_data (struct regcache *regcache, int n, int fetch)
+register_data (const struct regcache *regcache, int n, int fetch)
 {
   return (regcache->registers
 	  + find_register_by_number (regcache->tdesc, n).offset / 8);
@@ -312,23 +312,27 @@  register_data (struct regcache *regcache, int n, int fetch)
 
 void
 supply_register (struct regcache *regcache, int n, const void *buf)
+{
+  return regcache->raw_supply (n, buf);
+}
+
+void
+regcache::raw_supply (int n, const void *buf)
 {
   if (buf)
     {
-      memcpy (register_data (regcache, n, 0), buf,
-	      register_size (regcache->tdesc, n));
+      memcpy (register_data (this, n, 0), buf, register_size (tdesc, n));
 #ifndef IN_PROCESS_AGENT
-      if (regcache->register_status != NULL)
-	regcache->register_status[n] = REG_VALID;
+      if (register_status != NULL)
+	register_status[n] = REG_VALID;
 #endif
     }
   else
     {
-      memset (register_data (regcache, n, 0), 0,
-	      register_size (regcache->tdesc, n));
+      memset (register_data (this, n, 0), 0, register_size (tdesc, n));
 #ifndef IN_PROCESS_AGENT
-      if (regcache->register_status != NULL)
-	regcache->register_status[n] = REG_UNAVAILABLE;
+      if (register_status != NULL)
+	register_status[n] = REG_UNAVAILABLE;
 #endif
     }
 }
@@ -410,10 +414,16 @@  supply_register_by_name (struct regcache *regcache,
 void
 collect_register (struct regcache *regcache, int n, void *buf)
 {
-  memcpy (buf, register_data (regcache, n, 1),
-	  register_size (regcache->tdesc, n));
+  regcache->raw_collect (n, buf);
+}
+
+void
+regcache::raw_collect (int n, void *buf) const
+{
+  memcpy (buf, register_data (this, n, 1), register_size (tdesc, n));
 }
 
+
 enum register_status
 regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
 			    ULONGEST *val)
@@ -480,3 +490,14 @@  regcache_write_pc (struct regcache *regcache, CORE_ADDR pc)
 }
 
 #endif
+
+enum register_status
+regcache::get_register_status (int regnum) const
+{
+#ifndef IN_PROCESS_AGENT
+  gdb_assert (regnum >= 0 && regnum < tdesc->reg_defs.size ());
+  return (enum register_status) (register_status[regnum]);
+#else
+  return REG_VALID;
+#endif
+}
diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h
index 2c0df648f6..1842f1d9cf 100644
--- a/gdb/gdbserver/regcache.h
+++ b/gdb/gdbserver/regcache.h
@@ -28,23 +28,29 @@  struct target_desc;
    inferior; this is primarily for simplicity, as the performance
    benefit is minimal.  */
 
-struct regcache
+struct regcache : public reg_buffer_common
 {
   /* The regcache's target description.  */
-  const struct target_desc *tdesc;
+  const struct target_desc *tdesc = nullptr;
 
   /* Whether the REGISTERS buffer's contents are valid.  If false, we
      haven't fetched the registers from the target yet.  Not that this
      register cache is _not_ pass-through, unlike GDB's.  Note that
      "valid" here is unrelated to whether the registers are available
      in a traceframe.  For that, check REGISTER_STATUS below.  */
-  int registers_valid;
-  int registers_owned;
-  unsigned char *registers;
+  int registers_valid = 0;
+  int registers_owned = 0;
+  unsigned char *registers = nullptr;
 #ifndef IN_PROCESS_AGENT
   /* One of REG_UNAVAILBLE or REG_VALID.  */
-  unsigned char *register_status;
+  unsigned char *register_status = nullptr;
 #endif
+
+  void raw_supply (int regnum, const void *buf) override;
+
+  void raw_collect (int regnum, void *buf) const override;
+
+  enum register_status get_register_status (int regnum) const override;
 };
 
 struct regcache *init_register_cache (struct regcache *regcache,
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 3edddf47e1..b559a10752 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -139,7 +139,7 @@  typedef struct cached_reg
 
 /* Buffer of registers.  */
 
-class reg_buffer
+class reg_buffer : public reg_buffer_common
 {
 public:
   reg_buffer (gdbarch *gdbarch, bool has_pseudo);
@@ -151,13 +151,24 @@  public:
 
   /* Get the availability status of the value of register REGNUM in this
      buffer.  */
-  enum register_status get_register_status (int regnum) const;
+  enum register_status get_register_status (int regnum) const override;
 
   virtual ~reg_buffer ()
   {
     xfree (m_registers);
     xfree (m_register_status);
   }
+
+  virtual void raw_supply (int regnum, const void *buf) override
+  {
+    gdb_assert (false);
+  }
+
+  virtual void raw_collect (int regnum, void *buf) const override
+  {
+    gdb_assert (false);
+  }
+
 protected:
   /* Assert on the range of REGNUM.  */
   void assert_regnum (int regnum) const;
@@ -235,7 +246,7 @@  public:
   {}
 
   /* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE.  */
-  void raw_supply (int regnum, const void *buf);
+  void raw_supply (int regnum, const void *buf) override;
 
   void raw_supply (int regnum, const reg_buffer &src)
   {
@@ -293,7 +304,7 @@  public:
   void raw_update (int regnum) override;
 
   /* Collect register REGNUM from REGCACHE and store its contents in BUF.  */
-  void raw_collect (int regnum, void *buf) const;
+  void raw_collect (int regnum, void *buf) const override;
 
   void raw_collect_integer (int regnum, gdb_byte *addr, int addr_len,
 			    bool is_signed) const;