[3/11] Add MIPS_MAX_REGISTER_SIZE (2/4)

Message ID 78A7E8EA-7203-44DF-B7FD-63E75A5ECEF5@arm.com
State New, archived
Headers

Commit Message

Alan Hayward May 22, 2017, 4:05 p.m. UTC
  > On 22 May 2017, at 13:07, Yao Qi <qiyaoltc@gmail.com> wrote:
> 
> Alan Hayward <Alan.Hayward@arm.com> writes:
> 
>> -extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
>> -					  enum bfd_endian);
>> +inline ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len,
>> +					  enum bfd_endian byte_order)
>> +{
>> +  return extract_integer<LONGEST> (addr, len, byte_order);
> 
> s/LONGEST/ULONGEST/

Oops. Fixed.

> 
>> +}
>> 
> 
> [My C++ knowledge is still poor, so forgive me if I ask something stupid]
> 
> Is there any reason you do not put function template (extract_integer and
> store_integer) in header?  Any benefit of doing this?

It made the header file neater.
But, putting in the header means the instantiations are in the header.
I’ve now moved it into the header.


> 
>> extern int extract_long_unsigned_integer (const gdb_byte *, int,
>> 					  enum bfd_endian, LONGEST *);
>> @@ -649,11 +664,21 @@ extern int extract_long_unsigned_integer (const gdb_byte *, int,
>> extern CORE_ADDR extract_typed_address (const gdb_byte *buf,
>> 					struct type *type);
>> 
>> -extern void store_signed_integer (gdb_byte *, int,
>> -				  enum bfd_endian, LONGEST);
>> +template<typename T> void store_integer (gdb_byte *addr, int len,
>> +					 enum bfd_endian byte_order,
>> +					 LongType<T> val);
> 
> We can define store_integer slightly differently, so that we can use
> implicit instantiation,
> 
> template<typename T>
> typename std::enable_if<(std::is_same<T, LONGEST>::value
> 			 || std::is_same<T, ULONGEST>::value),
> 			void>::type
> store_integer (gdb_byte *addr, int len, enum bfd_endian byte_order, T val)
> {} so that …
> 

Done. It’s a shame we can’t do the same with extract_integer.


<SNIP> (Comments resolved as suggested)

> 
>> 
>> +/* Supply register REGNUM, whose contents are stored in VAL, to
>> +   REGCACHE.  */
>> +
>> +template<typename T>
>> +void
>> +regcache::raw_supply (int regnum, LongType<T> val)
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
>> +  gdb_byte *regbuf;
>> +  size_t size;
>> +
>> +  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
>> +  gdb_assert (!m_readonly_p);
>> +
>> +  regbuf = register_buffer (regnum);
>> +  size = m_descr->sizeof_register[regnum];
>> +
>> +  store_integer<T> (regbuf, size, byte_order, val);
>> +  m_register_status[regnum] = REG_VALID;
>> +}
> 
> Again, why don't you put it in regcache.h?
> 

This bit cannot go into regcache.h.
The function uses m_descr - and regcache_descr is defined in recache.c
I did not want to move regcache_descr into recache.h


Tested on a --enable-targets=all build using make check with board files
unix and native-gdbserver.
I do not have a MIPS machine to test on.
Ok to commit?

Alan.



2017-05-22  Alan Hayward  <alan.hayward@arm.com>

	* gdb/defs.h (LongType): New templated type.
	(extract_integer): New declaration.
	(extract_signed_integer): Switched to inline.
	(extract_unsigned_integer): Likewise.
	(store_integer): New declaration
	(store_signed_integer): Switched to inline.
	(store_unsigned_integer): Likewise.
	* gdb/findvar.c (extract_signed_integer): Removed function.
	(extract_unsigned_integer): Likewise.
	(store_signed_integer): Removed function.
	(store_unsigned_integer): Likewise.
	* mips-fbsd-tdep.c (mips_fbsd_supply_reg): Use templated raw_supply.
	(mips_fbsd_collect_reg): Use templated raw_collect.
	* mips-linux-tdep.c (supply_32bit_reg): Use templated raw_supply.
	(mips64_fill_gregset): Use templated raw_collect.
	(mips64_fill_fpregset): Use templated raw_supply.
	* gdb/regcache.c (regcache::raw_supply): New function and
	instantiations.
	(LongType regcache::raw_collect): Likewise
	* gdb/regcache.h (regcache::raw_supply): New declaration.
	(regcache::raw_collect): Likewise
  

Comments

Pedro Alves May 22, 2017, 5:15 p.m. UTC | #1
On 05/22/2017 05:05 PM, Alan Hayward wrote:

>      {
>        enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> -      gdb_byte buf[MAX_REGISTER_SIZE];
>        LONGEST val;
> 
> -      val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
> -      store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
> -			    val);
> -      regcache_raw_supply (regcache, regnum, buf);
> +      val = extract_integer<LONGEST> ((const gdb_byte *) addr, len, byte_order);
> +      regcache->raw_supply (regnum, val);
>      }
>  }
> 

>    else
>      {
>        enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> -      gdb_byte buf[MAX_REGISTER_SIZE];
> -      LONGEST val;
> -
> -      regcache_raw_collect (regcache, regnum, buf);
> -      val = extract_signed_integer (buf, register_size (gdbarch, regnum),
> -				    byte_order);
> -      store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
> +      LONGEST val = regcache->raw_collect<LONGEST> (regnum);
> +      store_integer ((gdb_byte *) addr, len, byte_order, val);

I wonder whether we can get rid of the LONGEST / host integer
middleman and simplify things while at it.  For instance, what if we
had a version of raw_collect that took the destination buffer length
as parameter:

      regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len);

that would copy bytes over into addr, and if the register is
narrower than LEN, then it'd insert the necessary
leading zeros (or 0xFFs if signed extension necessary),
and if the registers is wider than LEN, then it'd skip
copying enough significant bytes so that LEN fits.

Likewise for regcache->raw_supply.


> --- a/gdb/regcache.h
> +++ b/gdb/regcache.h
> @@ -21,6 +21,7 @@
>  #define REGCACHE_H
> 
>  #include "common-regcache.h"
> +#include "defs.h"

Headers should not include defs.h.  Is there some .c file that
misses including defs.h first thing?

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/defs.h b/gdb/defs.h
index a0b586f401eca205334e9f237081f4da97c83aa1..010fe55a4760ebc7a420115e7590199fcab899a0 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -627,6 +627,11 @@  enum symbol_needs_kind
   SYMBOL_NEEDS_FRAME
 };

+template<typename T>
+using LongType = typename std::enable_if<(std::is_same<T, LONGEST>::value
+					  || std::is_same<T, ULONGEST>::value),
+					 T>::type;
+
 /* Dynamic target-system-dependent parameters for GDB.  */
 #include "gdbarch.h"

@@ -637,11 +642,69 @@  enum { MAX_REGISTER_SIZE = 64 };

 /* In findvar.c.  */

-extern LONGEST extract_signed_integer (const gdb_byte *, int,
-				       enum bfd_endian);
+/* All 'extract' functions return a host-format integer from a target-format
+   integer at ADDR which is LEN bytes long.  */

-extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
-					  enum bfd_endian);
+template<typename T>
+LongType<T>
+extract_integer (const gdb_byte *addr, int len, enum bfd_endian byte_order)
+{
+  T retval = 0;
+  const unsigned char *p;
+  const unsigned char *startaddr = addr;
+  const unsigned char *endaddr = startaddr + len;
+
+  if (len > (int) sizeof (T))
+    error (_("\
+That operation is not available on integers of more than %d bytes."),
+	   (int) sizeof (T));
+
+  /* Start at the most significant end of the integer, and work towards
+     the least significant.  */
+  if (byte_order == BFD_ENDIAN_BIG)
+    {
+      p = startaddr;
+      if (std::is_signed<T>::value)
+	{
+	  /* Do the sign extension once at the start.  */
+	  retval = ((LONGEST) * p ^ 0x80) - 0x80;
+	  ++p;
+	}
+      for (; p < endaddr; ++p)
+	retval = (retval << 8) | *p;
+    }
+  else
+    {
+      p = endaddr - 1;
+      if (std::is_signed<T>::value)
+	{
+	  /* Do the sign extension once at the start.  */
+	  retval = ((LONGEST) * p ^ 0x80) - 0x80;
+	  --p;
+	}
+      for (; p >= startaddr; --p)
+	retval = (retval << 8) | *p;
+    }
+  return retval;
+}
+
+template LongType<ULONGEST> extract_integer<ULONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);
+
+template LongType<LONGEST> extract_integer<LONGEST>
+  (const gdb_byte *addr, int len, enum bfd_endian byte_order);
+
+inline ULONGEST extract_unsigned_integer (const gdb_byte *addr, int len,
+					  enum bfd_endian byte_order)
+{
+  return extract_integer<ULONGEST> (addr, len, byte_order);
+}
+
+inline LONGEST extract_signed_integer (const gdb_byte *addr, int len,
+				       enum bfd_endian byte_order)
+{
+  return extract_integer<LONGEST> (addr, len, byte_order);
+}

 extern int extract_long_unsigned_integer (const gdb_byte *, int,
 					  enum bfd_endian, LONGEST *);
@@ -649,11 +712,58 @@  extern int extract_long_unsigned_integer (const gdb_byte *, int,
 extern CORE_ADDR extract_typed_address (const gdb_byte *buf,
 					struct type *type);

-extern void store_signed_integer (gdb_byte *, int,
-				  enum bfd_endian, LONGEST);
+/* All 'store' functions accept a host-format integer and store a
+   target-format integer at ADDR which is LEN bytes long.  */

-extern void store_unsigned_integer (gdb_byte *, int,
-				    enum bfd_endian, ULONGEST);
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+			 || std::is_same<T, ULONGEST>::value),
+			void>::type
+store_integer (gdb_byte *addr, int len, enum bfd_endian byte_order,
+	       T val)
+{
+  gdb_byte *p;
+  gdb_byte *startaddr = addr;
+  gdb_byte *endaddr = startaddr + len;
+
+  /* Start at the least significant end of the integer, and work towards
+     the most significant.  */
+  if (byte_order == BFD_ENDIAN_BIG)
+    {
+      for (p = endaddr - 1; p >= startaddr; --p)
+	{
+	  *p = val & 0xff;
+	  val >>= 8;
+	}
+    }
+  else
+    {
+      for (p = startaddr; p < endaddr; ++p)
+	{
+	  *p = val & 0xff;
+	  val >>= 8;
+	}
+    }
+}
+
+template void store_integer (gdb_byte *addr, int len,
+				       enum bfd_endian byte_order,
+				       LongType<ULONGEST> val);
+template void store_integer (gdb_byte *addr, int len,
+				      enum bfd_endian byte_order,
+				      LongType<LONGEST> val);
+
+inline void store_signed_integer (gdb_byte *addr, int len,
+				  enum bfd_endian byte_order, LONGEST val)
+{
+  store_integer (addr, len, byte_order, val);
+}
+
+inline void store_unsigned_integer (gdb_byte *addr, int len,
+				    enum bfd_endian byte_order, ULONGEST val)
+{
+  store_integer (addr, len, byte_order, val);
+}

 extern void store_typed_address (gdb_byte *buf, struct type *type,
 				 CORE_ADDR addr);
diff --git a/gdb/findvar.c b/gdb/findvar.c
index ed4d5c1266c9de069981b306bc8229ae5fb02350..614d1291eac5a7438a1bf3f6dd0b5d012a0dfaa7 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -34,9 +34,7 @@ 
 #include "language.h"
 #include "dwarf2loc.h"

-/* Basic byte-swapping routines.  All 'extract' functions return a
-   host-format integer from a target-format integer at ADDR which is
-   LEN bytes long.  */
+/* Basic byte-swapping routines.  */

 #if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8
   /* 8 bit characters are a pretty safe assumption these days, so we
@@ -46,70 +44,6 @@ 
 you lose
 #endif

-LONGEST
-extract_signed_integer (const gdb_byte *addr, int len,
-			enum bfd_endian byte_order)
-{
-  LONGEST retval;
-  const unsigned char *p;
-  const unsigned char *startaddr = addr;
-  const unsigned char *endaddr = startaddr + len;
-
-  if (len > (int) sizeof (LONGEST))
-    error (_("\
-That operation is not available on integers of more than %d bytes."),
-	   (int) sizeof (LONGEST));
-
-  /* Start at the most significant end of the integer, and work towards
-     the least significant.  */
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      p = startaddr;
-      /* Do the sign extension once at the start.  */
-      retval = ((LONGEST) * p ^ 0x80) - 0x80;
-      for (++p; p < endaddr; ++p)
-	retval = (retval << 8) | *p;
-    }
-  else
-    {
-      p = endaddr - 1;
-      /* Do the sign extension once at the start.  */
-      retval = ((LONGEST) * p ^ 0x80) - 0x80;
-      for (--p; p >= startaddr; --p)
-	retval = (retval << 8) | *p;
-    }
-  return retval;
-}
-
-ULONGEST
-extract_unsigned_integer (const gdb_byte *addr, int len,
-			  enum bfd_endian byte_order)
-{
-  ULONGEST retval;
-  const unsigned char *p;
-  const unsigned char *startaddr = addr;
-  const unsigned char *endaddr = startaddr + len;
-
-  if (len > (int) sizeof (ULONGEST))
-    error (_("\
-That operation is not available on integers of more than %d bytes."),
-	   (int) sizeof (ULONGEST));
-
-  /* Start at the most significant end of the integer, and work towards
-     the least significant.  */
-  retval = 0;
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = startaddr; p < endaddr; ++p)
-	retval = (retval << 8) | *p;
-    }
-  else
-    {
-      for (p = endaddr - 1; p >= startaddr; --p)
-	retval = (retval << 8) | *p;
-    }
-  return retval;
-}

 /* Sometimes a long long unsigned integer can be extracted as a
    LONGEST value.  This is done so that we can print these values
@@ -177,65 +111,6 @@  extract_typed_address (const gdb_byte *buf, struct type *type)
   return gdbarch_pointer_to_address (get_type_arch (type), type, buf);
 }

-/* All 'store' functions accept a host-format integer and store a
-   target-format integer at ADDR which is LEN bytes long.  */
-
-void
-store_signed_integer (gdb_byte *addr, int len,
-		      enum bfd_endian byte_order, LONGEST val)
-{
-  gdb_byte *p;
-  gdb_byte *startaddr = addr;
-  gdb_byte *endaddr = startaddr + len;
-
-  /* Start at the least significant end of the integer, and work towards
-     the most significant.  */
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = endaddr - 1; p >= startaddr; --p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-  else
-    {
-      for (p = startaddr; p < endaddr; ++p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-}
-
-void
-store_unsigned_integer (gdb_byte *addr, int len,
-			enum bfd_endian byte_order, ULONGEST val)
-{
-  unsigned char *p;
-  unsigned char *startaddr = (unsigned char *) addr;
-  unsigned char *endaddr = startaddr + len;
-
-  /* Start at the least significant end of the integer, and work towards
-     the most significant.  */
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = endaddr - 1; p >= startaddr; --p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-  else
-    {
-      for (p = startaddr; p < endaddr; ++p)
-	{
-	  *p = val & 0xff;
-	  val >>= 8;
-	}
-    }
-}
-
 /* Store the address ADDR as a pointer of type TYPE at BUF, in target
    form.  */
 void
diff --git a/gdb/mips-fbsd-tdep.c b/gdb/mips-fbsd-tdep.c
index 00fae0ec60ddc9e645d3236efe29f2f9e9ceab5c..9e2025e58c4cf6d887acb0019f39a1993777aeab 100644
--- a/gdb/mips-fbsd-tdep.c
+++ b/gdb/mips-fbsd-tdep.c
@@ -48,9 +48,9 @@ 
 #define MIPS_FBSD_NUM_FPREGS	34

 /* Supply a single register.  If the source register size matches the
-   size the regcache expects, this can use regcache_raw_supply().  If
+   size the regcache expects, this can use regcache->raw_supply ().  If
    they are different, this copies the source register into a buffer
-   that can be passed to regcache_raw_supply().  */
+   that can be passed to regcache->raw_supply ().  */

 static void
 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
@@ -63,20 +63,17 @@  mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
   else
     {
       enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-      gdb_byte buf[MAX_REGISTER_SIZE];
       LONGEST val;

-      val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
-      store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
-			    val);
-      regcache_raw_supply (regcache, regnum, buf);
+      val = extract_integer<LONGEST> ((const gdb_byte *) addr, len, byte_order);
+      regcache->raw_supply (regnum, val);
     }
 }

 /* Collect a single register.  If the destination register size
    matches the size the regcache expects, this can use
-   regcache_raw_supply().  If they are different, this fetches the
-   register via regcache_raw_supply() into a buffer and then copies it
+   regcache->raw_supply ().  If they are different, this fetches the
+   register via regcache->raw_supply () into a buffer and then copies it
    into the final destination.  */

 static void
@@ -90,13 +87,8 @@  mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
   else
     {
       enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regnum, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regnum),
-				    byte_order);
-      store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
+      LONGEST val = regcache->raw_collect<LONGEST> (regnum);
+      store_integer ((gdb_byte *) addr, len, byte_order, val);
     }
 }

diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 48a582a16c934abe6e8f87c46a6009649c606d49..6dcb759cb85083a426466b8cd00560bebe6a35a3 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -118,11 +118,10 @@  supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  gdb_byte buf[MAX_REGISTER_SIZE];
-  store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
-			extract_signed_integer ((const gdb_byte *) addr, 4,
-						byte_order));
-  regcache_raw_supply (regcache, regnum, buf);
+  LONGEST val;
+
+  val = extract_integer<LONGEST> ((const gdb_byte *) addr, 4, byte_order);
+  regcache->raw_supply (regnum, val);
 }

 /* Unpack an elf_gregset_t into GDB's register cache.  */
@@ -460,14 +459,9 @@  mips64_fill_gregset (const struct regcache *regcache,

   if (regaddr != -1)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       dst = regp + regaddr;
-      store_signed_integer ((gdb_byte *) dst, 8, byte_order, val);
+      store_integer ((gdb_byte *) dst, 8, byte_order, val);
     }
 }

@@ -564,25 +558,15 @@  mips64_fill_fpregset (const struct regcache *regcache,
     }
   else if (regno == mips_regnum (gdbarch)->fp_control_status)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       to = (gdb_byte *) (*fpregsetp + 32);
-      store_signed_integer (to, 4, byte_order, val);
+      store_integer (to, 4, byte_order, val);
     }
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     {
-      gdb_byte buf[MAX_REGISTER_SIZE];
-      LONGEST val;
-
-      regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno),
-				    byte_order);
+      LONGEST val = regcache->raw_collect<LONGEST> (regno);
       to = (gdb_byte *) (*fpregsetp + 32) + 4;
-      store_signed_integer (to, 4, byte_order, val);
+      store_integer (to, 4, byte_order, val);
     }
   else if (regno == -1)
     {
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 4dcfccbac70f0f962bf5e5596d035fda42322795..ee5e12312fe731b03b6b4e54802988d239aed488 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -21,6 +21,7 @@ 
 #define REGCACHE_H

 #include "common-regcache.h"
+#include "defs.h"

 struct regcache;
 struct regset;
@@ -294,8 +295,16 @@  public:

   void raw_collect (int regnum, void *buf) const;

+  template<typename T> LongType<T> raw_collect (int regnum) const;
+
   void raw_supply (int regnum, const void *buf);

+  template<typename T>
+  typename std::enable_if<(std::is_same<T, LONGEST>::value
+			   || std::is_same<T, ULONGEST>::value),
+			  void>::type
+  raw_supply (int regnum, T val);
+
   void raw_supply_zeroed (int regnum);

   void raw_copy (int regnum, struct regcache *src_regcache);
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 660558f7ff10f9d8346b6e08422e16c38c3c4d7d..1412c16beb97841847690ecfcac64121298edfc9 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1189,6 +1189,32 @@  regcache::raw_supply (int regnum, const void *buf)
     }
 }

+/* Supply register REGNUM, whose contents are stored in VAL, to
+   REGCACHE.  */
+
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+			 || std::is_same<T, ULONGEST>::value),
+			void>::type
+regcache::raw_supply (int regnum, T val)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  gdb_byte *regbuf;
+  size_t size;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+  gdb_assert (!m_readonly_p);
+
+  regbuf = register_buffer (regnum);
+  size = m_descr->sizeof_register[regnum];
+
+  store_integer (regbuf, size, byte_order, val);
+  m_register_status[regnum] = REG_VALID;
+}
+
+template void regcache::raw_supply (int regnum, LONGEST val);
+template void regcache::raw_supply (int regnum, ULONGEST val);
+
 /* Supply register REGNUM with zeroed value to REGCACHE.  This is not the same
    as calling raw_supply with NULL (which will set the state to
    unavailable).  */
@@ -1232,6 +1258,30 @@  regcache::raw_collect (int regnum, void *buf) const
   memcpy (buf, regbuf, size);
 }

+/* Collect register REGNUM from REGCACHE and extract its contents into a
+   LONGEST.  */
+
+template<typename T>
+LongType<T> regcache::raw_collect (int regnum) const
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+  const gdb_byte *regbuf;
+  size_t size;
+
+  gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+
+  regbuf = register_buffer (regnum);
+  size = m_descr->sizeof_register[regnum];
+
+  if (std::is_signed<T>::value)
+    return extract_signed_integer (regbuf, size, byte_order);
+  else
+    return extract_unsigned_integer (regbuf, size, byte_order);
+}
+
+template LongType<ULONGEST> regcache::raw_collect<ULONGEST> (int regnum) const;
+template LongType<LONGEST> regcache::raw_collect<LONGEST> (int regnum) const;
+
 void
 regcache::raw_copy (int regnum, struct regcache *src_regcache)
 {