Re: [PATCH 3/11] Add MIPS_MAX_REGISTER_SIZE (2/4)

Alan Hayward
2017-05-23T17:49:44Z

> On 22 May 2017, at 18:15, Pedro Alves <palves@redhat.com> wrote:
>
> 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.

Is it the case that gdb always does a store_integer after a raw_collect
of a (U)LONGEST?
And always an extract_integer before a raw_supply of a (U)LONGEST ?
(Both of these are tricky to grep for, because the code sequence is over
multiple lines)

I was going to mock up a new raw_collect_integer, but then got carried
away and wrote the full patch changes.
This version makes the MIPS files look neater.

>
>
>> --- 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?
>

I think I needed it in an earlier version of my patch.
Removed.

New version with raw_collect_integer and raw_supply_integer.

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-23 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 raw_supply_integer.
(mips_fbsd_collect_reg): Use templated raw_collect_integer.
* mips-linux-tdep.c (supply_32bit_reg): Use raw_supply_integer.
(mips64_fill_gregset): Use raw_collect_integer.
(mips64_fill_fpregset): Use raw_supply_integer.
* gdb/regcache.c (regcache::raw_supply_integer): New function and
instantiations.
(regcache::raw_collect_integer): Likewise
* gdb/regcache.h (regcache::raw_supply): New declaration.
(regcache::raw_collect): Likewise

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..7278fb71e3ad1f18d35cd696832d99bf90198620 100644
--- a/gdb/mips-fbsd-tdep.c
+++ b/gdb/mips-fbsd-tdep.c
@@ -48,9 +48,8 @@
#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
- they are different, this copies the source register into a buffer
- that can be passed to regcache_raw_supply(). */
+ size the regcache expects, this can use regcache->raw_supply (). If
+ they are different, this can use regcache->raw_supply_integer (). */

static void
mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
@@ -59,25 +58,16 @@ mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
struct gdbarch *gdbarch = get_regcache_arch (regcache);

if (register_size (gdbarch, regnum) == len)
- regcache_raw_supply (regcache, regnum, addr);
+ regcache->raw_supply (regnum, 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);
- }
+ regcache->raw_supply_integer<LONGEST> (regnum, (const gdb_byte *) addr,
+ len);
}

/* 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
- into the final destination. */
+ regcache->raw_collect (). If they are different, this can use
+ regcache->raw_collect_integer (). */

static void
mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
@@ -86,18 +76,9 @@ mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
struct gdbarch *gdbarch = get_regcache_arch (regcache);

if (register_size (gdbarch, regnum) == len)
- regcache_raw_collect (regcache, regnum, addr);
+ regcache->raw_collect (regnum, 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);
- }
+ regcache->raw_collect_integer<LONGEST> (regnum, (gdb_byte *) addr, len);
}

/* Supply the floating-point registers stored in FPREGS to REGCACHE.
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c
index 48a582a16c934abe6e8f87c46a6009649c606d49..b30fe294a0bbbb815418e65149a88f59eb15befb 100644
--- a/gdb/mips-linux-tdep.c
+++ b/gdb/mips-linux-tdep.c
@@ -116,13 +116,7 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
static void
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);
+ regcache->raw_supply_integer<LONGEST> (regnum, (const gdb_byte *) addr, 4);
}

/* Unpack an elf_gregset_t into GDB's register cache. */
@@ -417,7 +411,6 @@ mips64_fill_gregset (const struct regcache *regcache,
mips64_elf_gregset_t *gregsetp, int regno)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int regaddr, regi;
mips64_elf_greg_t *regp = *gregsetp;
void *dst;
@@ -460,14 +453,8 @@ 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);
dst = regp + regaddr;
- store_signed_integer ((gdb_byte *) dst, 8, byte_order, val);
+ regcache->raw_collect_integer<LONGEST> (regno, (gdb_byte *) dst, 8);
}
}

@@ -564,25 +551,13 @@ 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);
to = (gdb_byte *) (*fpregsetp + 32);
- store_signed_integer (to, 4, byte_order, val);
+ regcache->raw_collect_integer<LONGEST> (regno, to, 4);
}
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);
to = (gdb_byte *) (*fpregsetp + 32) + 4;
- store_signed_integer (to, 4, byte_order, val);
+ regcache->raw_collect_integer<LONGEST> (regno, to, 4);
}
else if (regno == -1)
{
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 4dcfccbac70f0f962bf5e5596d035fda42322795..c47401948270b1c75d9d3b02cbbc3256db85f84e 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -294,8 +294,20 @@ public:

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

+ template<typename T>
+ typename std::enable_if<(std::is_same<T, LONGEST>::value
+ || std::is_same<T, ULONGEST>::value),
+ void>::type
+ raw_collect_integer (int regnum, gdb_byte *addr, int addr_len) 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_integer (int regnum, const gdb_byte *addr, int addr_len);
+
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..cc9ab74b087cbda2d79264674e9b463e1528363f 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -1189,6 +1189,39 @@ regcache::raw_supply (int regnum, const void *buf)
}
}

+/* Supply register REGNUM, whose contents are stored in ADDR, with length
+ ADDR_LEN to a (U)LONGEST, then store to REGCACHE, taking BYTE_ORDER into
+ account. */
+
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+ || std::is_same<T, ULONGEST>::value),
+ void>::type
+regcache::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+ gdb_byte *regbuf;
+ size_t regsize;
+ T val;
+
+ gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+ gdb_assert (!m_readonly_p);
+
+ regbuf = register_buffer (regnum);
+ regsize = m_descr->sizeof_register[regnum];
+
+ val = extract_integer<T> (addr, addr_len, byte_order);
+ store_integer (regbuf, regsize, byte_order, val);
+ m_register_status[regnum] = REG_VALID;
+}
+
+template void regcache::raw_supply_integer<ULONGEST> (int regnum,
+ const gdb_byte *addr,
+ int addr_len);
+template void regcache::raw_supply_integer<LONGEST> (int regnum,
+ const gdb_byte *addr,
+ int addr_len);
+
/* 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 +1265,37 @@ regcache::raw_collect (int regnum, void *buf) const
memcpy (buf, regbuf, size);
}

+/* Collect register REGNUM from REGCACHE into a (U)LONGEST, then store ADDR_LEN
+ bytes into buffer ADDR, taking BYTE_ORDER into account. */
+
+template<typename T>
+typename std::enable_if<(std::is_same<T, LONGEST>::value
+ || std::is_same<T, ULONGEST>::value),
+ void>::type
+regcache::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len) const
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch);
+ const gdb_byte *regbuf;
+ size_t regsize;
+ T val;
+
+ gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
+
+ regbuf = register_buffer (regnum);
+ regsize = m_descr->sizeof_register[regnum];
+
+ val = extract_integer<T> (regbuf, regsize, byte_order);
+ store_integer (addr, addr_len, byte_order, val);
+}
+
+template void regcache::raw_collect_integer<ULONGEST> (int regnum,
+ gdb_byte *addr,
+ int addr_len) const;
+template void regcache::raw_collect_integer<LONGEST> (int regnum,
+ gdb_byte *addr,
+ int addr_len) const;
+
+
void
regcache::raw_copy (int regnum, struct regcache *src_regcache)
{