This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Clear *VAL in regcache_raw_read_unsigned


On 02/11/2016 10:12 AM, Yao Qi wrote:> Pedro Alves <palves@redhat.com> writes:
>
>> The issue you noticed exposed that regcache_raw_read_unsigned function
>> is broken for memcpy'ing a 32-bit value into a 64-bit variable, and I think
>> your patch papered over the problem for little endian, only.
>
> regcache_raw_read_unsigned has two orthogonal issues, one is VAL isn't
> cleared, and the other one is the endianness issue.  My "Clear *VAL"
> patch fixes the former, and I didn't realize the latter then.

I guess you could see it that way, though the way I imagine fixing this
handles both issues as one.

> diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
> index 2af8e24..d69ed5b 100644
> --- a/gdb/gdbserver/regcache.c
> +++ b/gdb/gdbserver/regcache.c
> @@ -21,6 +21,8 @@
>  #include "gdbthread.h"
>  #include "tdesc.h"
>  #include "rsp-low.h"
> +#include <endian.h>
> +
>  #ifndef IN_PROCESS_AGENT
>  
>  struct regcache *
> @@ -441,7 +443,27 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
>            (int) sizeof (ULONGEST));
>  
>    *val = 0;
> -  collect_register (regcache, regnum, val);
> +
> +  if (__BYTE_ORDER == __LITTLE_ENDIAN)
> +    {
> +      /* Little-endian values always sit at the left end of the buffer.  */
> +      collect_register (regcache, regnum, val);
> +    }
> +  else if (__BYTE_ORDER == __BIG_ENDIAN)
> +    {
> +      /* Big-endian values sit at the right end of the buffer.  In case of
> +	 registers whose sizes are smaller than sizeof (long), we must use a
> +	 padding to access them correctly.  */
> +      int size = register_size (regcache->tdesc, regnum);
> +
> +      if (size < sizeof (ULONGEST))
> +	{
> +	  collect_register (regcache, regnum,
> +			    (char *) val + sizeof (ULONGEST) - size);
> +	}
> +      else
> +	collect_register (regcache, regnum, val);
> +    }

I was thinking we'd just use properly sized types, and the let the
compiler do the zero extension:

uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;

switch (size)
{
   case 1:
     collect_register (regcache, regnum, &u8);
     *val = u8;
     break;
   case 2:
     collect_register (regcache, regnum, &u16);
     *val = u16;
     break;
   case 4:
     collect_register (regcache, regnum, &u32);
     *val = u32;
     break;
   case 8:
     collect_register (regcache, regnum, &u64);
     *val = u64;
     break;
}

This should work in either endianess, and the '*val = 0' is no longer
necessary either.

Or maybe better, just byte the bullet and make gdbserver use
extract_unsigned_integer, like gdb.

The problem with that is that gdbserver can't currently use 'enum bfd_endian',
which IIRC, was already an issue in the get-next-pcs stuff.  I've attached a
patch series that handles that by moving bfd_endian to a separate header.
I've pushed it to the users/palves/gdbserver-extract-unsigned-integer branch
as well.

If you agree with this, I'll run the bfd_endian patch by the binutils folks.

Thanks,
Pedro Alves

>From dd4a4f86240eac1262c760b6109b42242e007923 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 11 Feb 2016 11:35:04 +0000
Subject: [PATCH 1/3] Move 'enum bfd_endian' to a non-generated header

Because:

- GDB uses enum bfd_endian extensively.
- gdbserver does not build/link-with bfd.
- We'd like to share more code between gdb and gdbserver.

It'd make our lives easier if we could just use bfd_endian in
gdbserver as well.

The problem is that bfd_endian is defined in a header that only exists
if bfd is built/configured.

Thus this moves bfd_endian to a separate header, so gdbserver can
include it.

bfd/ChangeLog:
2016-02-11  Pedro Alves  <palves@redhat.com>

	* bfd-in.h: Include bfd-types.h
	* bfd-in2.h: Regenerate.
	* targets.c (enum bfd_endian): Moved to include/bfd-types.h.

include/ChangeLog:
2016-02-11  Pedro Alves  <palves@redhat.com>

	* bfd-types.h: New file.
---
 bfd/bfd-in.h        |  1 +
 bfd/bfd-in2.h       |  3 +--
 bfd/targets.c       |  2 --
 include/bfd-types.h | 26 ++++++++++++++++++++++++++
 4 files changed, 28 insertions(+), 4 deletions(-)
 create mode 100644 include/bfd-types.h

diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h
index 5df2bab..277ca5f 100644
--- a/bfd/bfd-in.h
+++ b/bfd/bfd-in.h
@@ -35,6 +35,7 @@ extern "C" {
 #include "ansidecl.h"
 #include "symcat.h"
 #include <sys/stat.h>
+#include "bfd-types.h"
 
 #if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
 #ifndef SABER
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index fb4858c..0d6b40f 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -42,6 +42,7 @@ extern "C" {
 #include "ansidecl.h"
 #include "symcat.h"
 #include <sys/stat.h>
+#include "bfd-types.h"
 
 #if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE)
 #ifndef SABER
@@ -7124,8 +7125,6 @@ enum bfd_flavour
   bfd_target_sym_flavour
 };
 
-enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
-
 /* Forward declaration.  */
 typedef struct bfd_link_info _bfd_link_info;
 
diff --git a/bfd/targets.c b/bfd/targets.c
index 50f3712..a2ee6ee 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -171,8 +171,6 @@ DESCRIPTION
 .  bfd_target_sym_flavour
 .};
 .
-.enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
-.
 .{* Forward declaration.  *}
 .typedef struct bfd_link_info _bfd_link_info;
 .
diff --git a/include/bfd-types.h b/include/bfd-types.h
new file mode 100644
index 0000000..816fac4
--- /dev/null
+++ b/include/bfd-types.h
@@ -0,0 +1,26 @@
+/* bfd core types that do not depend on configuration.
+
+   Copyright (C) 1990-2016 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef BFD_TYPES_H
+#define BFD_TYPES_H
+
+enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
+
+#endif
-- 
1.9.3

>From ca47aa93d4a13e676e771041eb7372ff2cdb1487 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 11 Feb 2016 11:35:05 +0000
Subject: [PATCH 2/3] Move store/extract ... integer routines to gdb/common/

In preparation for gdbserver using them as well.

gdb/ChangeLog:
2016-02-11  Pedro Alves  <palves@redhat.com>

	* Makefile.in (SFILES): Add common/gdb-byteswap.c.
	(HFILES_NO_SRCDIR): Add common/gdb-byteswap.h.
	(COMMON_OBS): Add common/gdb-byteswap.o.
	(gdb-byteswap.o): New rule.
	* common/common-types.h: Include bfd-types.h.
	* common/gdb-byteswap.c: New file.
	* common/gdb-byteswap.h: New file.
	* defs.h (extract_signed_integer, extract_unsigned_integer)
	(extract_long_unsigned_integer, extract_typed_address)
	(store_signed_integer, store_unsigned_integer): Moved to
	common/gdb-byteswap.h.
	* findvar.c (extract_signed_integer, extract_unsigned_integer)
	(extract_long_unsigned_integer, extract_typed_address)
	(store_signed_integer, store_unsigned_integer): Moved to
	common/gdb-byteswap.c.
---
 gdb/Makefile.in           |  11 ++-
 gdb/common/common-types.h |   4 +
 gdb/common/gdb-byteswap.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/common/gdb-byteswap.h |  49 +++++++++++
 gdb/defs.h                |  17 +---
 gdb/findvar.c             | 189 -------------------------------------------
 6 files changed, 265 insertions(+), 206 deletions(-)
 create mode 100644 gdb/common/gdb-byteswap.c
 create mode 100644 gdb/common/gdb-byteswap.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ec2af52..d63d8aa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -896,6 +896,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	target/waitstatus.c common/print-utils.c common/rsp-low.c \
 	common/errors.c common/common-debug.c common/common-exceptions.c \
 	common/btrace-common.c common/fileio.c common/common-regcache.c \
+	common/gdb-byteswap.c \
 	$(SUBDIR_GCC_COMPILE_SRCS)
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -988,7 +989,9 @@ common/common-exceptions.h target/target.h common/symbol.h \
 common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
 common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
 nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h
+tid-parse.h \
+common/gdb-byteswap.h
+
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -1087,7 +1090,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	format.o registry.o btrace.o record-btrace.o waitstatus.o \
 	print-utils.o rsp-low.o errors.o common-debug.o debug.o \
 	common-exceptions.o btrace-common.o fileio.o \
-	common-regcache.o \
+	common-regcache.o gdb-byteswap.o \
 	$(SUBDIR_GCC_COMPILE_OBS)
 
 TSOBS = inflow.o
@@ -2275,6 +2278,10 @@ common-regcache.o: ${srcdir}/common/common-regcache.c
 	$(COMPILE) $(srcdir)/common/common-regcache.c
 	$(POSTCOMPILE)
 
+gdb-byteswap.o: ${srcdir}/common/gdb-byteswap.c
+	$(COMPILE) $(srcdir)/common/gdb-byteswap.c
+	$(POSTCOMPILE)
+
 #
 # gdb/target/ dependencies
 #
diff --git a/gdb/common/common-types.h b/gdb/common/common-types.h
index efeb0db..760f477 100644
--- a/gdb/common/common-types.h
+++ b/gdb/common/common-types.h
@@ -20,6 +20,10 @@
 #ifndef COMMON_TYPES_H
 #define COMMON_TYPES_H
 
+/* This header is always available, even when BFD is not
+   configured.  */
+#include "bfd-types.h"
+
 #ifdef GDBSERVER
 
 /* * A byte from the program being debugged.  */
diff --git a/gdb/common/gdb-byteswap.c b/gdb/common/gdb-byteswap.c
new file mode 100644
index 0000000..ed2c8f5
--- /dev/null
+++ b/gdb/common/gdb-byteswap.c
@@ -0,0 +1,201 @@
+/* Basic byte-swapping routines, for GDB, the GNU debugger.
+
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "gdb-byteswap.h"
+#include "host-defs.h"
+
+/* See gdb-byteswap.h.  */
+
+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;
+}
+
+/* See gdb-byteswap.h.  */
+
+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;
+}
+
+/* See gdb_byteswap.h.  */
+
+int
+extract_long_unsigned_integer (const gdb_byte *addr, int orig_len,
+			       enum bfd_endian byte_order, LONGEST *pval)
+{
+  const gdb_byte *p;
+  const gdb_byte *first_addr;
+  int len;
+
+  len = orig_len;
+  if (byte_order == BFD_ENDIAN_BIG)
+    {
+      for (p = addr;
+	   len > (int) sizeof (LONGEST) && p < addr + orig_len;
+	   p++)
+	{
+	  if (*p == 0)
+	    len--;
+	  else
+	    break;
+	}
+      first_addr = p;
+    }
+  else
+    {
+      first_addr = addr;
+      for (p = addr + orig_len - 1;
+	   len > (int) sizeof (LONGEST) && p >= addr;
+	   p--)
+	{
+	  if (*p == 0)
+	    len--;
+	  else
+	    break;
+	}
+    }
+
+  if (len <= (int) sizeof (LONGEST))
+    {
+      *pval = (LONGEST) extract_unsigned_integer (first_addr,
+						  sizeof (LONGEST),
+						  byte_order);
+      return 1;
+    }
+
+  return 0;
+}
+
+
+/* See gdb-byteswap.h.  */
+
+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;
+	}
+    }
+}
+
+/* See gdb-byteswap.h.  */
+
+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;
+	}
+    }
+}
diff --git a/gdb/common/gdb-byteswap.h b/gdb/common/gdb-byteswap.h
new file mode 100644
index 0000000..9cf1d22
--- /dev/null
+++ b/gdb/common/gdb-byteswap.h
@@ -0,0 +1,49 @@
+/* Basic byte-swapping routines, for GDB, the GNU debugger.
+
+   Copyright (C) 2009-2016 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_BYTESWAP_H
+#define GDB_BYTESWAP_H 1
+
+/* All 'extract' functions return a host-format integer from a
+   target-format integer at ADDR which is LEN bytes long.  */
+
+extern LONGEST extract_signed_integer (const gdb_byte *, int,
+				       enum bfd_endian);
+
+extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
+					  enum bfd_endian);
+
+/* Sometimes a long long unsigned integer can be extracted as a
+   LONGEST value.  This is done so that we can print these values
+   better.  If this integer can be converted to a LONGEST, this
+   function returns 1 and sets *PVAL.  Otherwise it returns 0.  */
+
+extern int extract_long_unsigned_integer (const 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_signed_integer (gdb_byte *, int,
+				  enum bfd_endian, LONGEST);
+
+extern void store_unsigned_integer (gdb_byte *, int,
+				    enum bfd_endian, ULONGEST);
+
+#endif
diff --git a/gdb/defs.h b/gdb/defs.h
index f6ffeac..1e7fd10 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -594,26 +594,13 @@ extern double atof (const char *);	/* X3.159-1989  4.10.1.1 */
 
 enum { MAX_REGISTER_SIZE = 64 };
 
-/* In findvar.c.  */
-
-extern LONGEST extract_signed_integer (const gdb_byte *, int,
-				       enum bfd_endian);
-
-extern ULONGEST extract_unsigned_integer (const gdb_byte *, int,
-					  enum bfd_endian);
+#include "gdb-byteswap.h"
 
-extern int extract_long_unsigned_integer (const gdb_byte *, int,
-					  enum bfd_endian, LONGEST *);
+/* In findvar.c.  */
 
 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);
-
-extern void store_unsigned_integer (gdb_byte *, int,
-				    enum bfd_endian, ULONGEST);
-
 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 a39d897..70b9249 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -34,136 +34,6 @@
 #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.  */
-
-#if TARGET_CHAR_BIT != 8 || HOST_CHAR_BIT != 8
-  /* 8 bit characters are a pretty safe assumption these days, so we
-     assume it throughout all these swapping routines.  If we had to deal with
-     9 bit characters, we would need to make len be in bits and would have
-     to re-write these routines...  */
-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
-   better.  If this integer can be converted to a LONGEST, this
-   function returns 1 and sets *PVAL.  Otherwise it returns 0.  */
-
-int
-extract_long_unsigned_integer (const gdb_byte *addr, int orig_len,
-			       enum bfd_endian byte_order, LONGEST *pval)
-{
-  const gdb_byte *p;
-  const gdb_byte *first_addr;
-  int len;
-
-  len = orig_len;
-  if (byte_order == BFD_ENDIAN_BIG)
-    {
-      for (p = addr;
-	   len > (int) sizeof (LONGEST) && p < addr + orig_len;
-	   p++)
-	{
-	  if (*p == 0)
-	    len--;
-	  else
-	    break;
-	}
-      first_addr = p;
-    }
-  else
-    {
-      first_addr = addr;
-      for (p = addr + orig_len - 1;
-	   len > (int) sizeof (LONGEST) && p >= addr;
-	   p--)
-	{
-	  if (*p == 0)
-	    len--;
-	  else
-	    break;
-	}
-    }
-
-  if (len <= (int) sizeof (LONGEST))
-    {
-      *pval = (LONGEST) extract_unsigned_integer (first_addr,
-						  sizeof (LONGEST),
-						  byte_order);
-      return 1;
-    }
-
-  return 0;
-}
-
-
 /* Treat the bytes at BUF as a pointer of type TYPE, and return the
    address it represents.  */
 CORE_ADDR
@@ -178,65 +48,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
-- 
1.9.3

>From 04956cf9b84b53728e20f0dae1f561ab26714453 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 11 Feb 2016 11:44:35 +0000
Subject: [PATCH 3/3] Fix gdbserver's regcache_raw_read_unsigned on big endian
 hosts

The regcache_raw_read_unsigned function is memcpy'ing a 32-bit value
directly into a 64-bit variable, which doesn't work on big endian
targets.

Fix this by memcpy'ing to a buffer, and then using
extract_unsigned_integer, just like gdb's version.

gdb/gdbserver/ChangeLog:
2016-02-11  Pedro Alves  <palves@redhat.com>

	* Makefile.in (SFILES): Add $(srcdir)/common/gdb-byteswap.c.
	(gdb-byteswap.o): New rule.
	* regcache.c: Include "gdb-byteswap.h".
	(host_bfd_endian): New function.
	(regcache_raw_read_unsigned): Use extract_unsigned_integer and
	host_bfd_endian.
---
 gdb/gdbserver/Makefile.in |  7 ++++++-
 gdb/gdbserver/regcache.c  | 31 ++++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1e874e3..06a6f1b 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -185,7 +185,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/btrace-common.c \
 	$(srcdir)/common/fileio.c $(srcdir)/nat/linux-namespaces.c \
 	$(srcdir)/arch/arm.c $(srcdir)/common/common-regcache.c \
-	$(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c
+	$(srcdir)/arch/arm-linux.c $(srcdir)/arch/arm-get-next-pcs.c \
+	$(srcdir)/common/gdb-byteswap.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -200,6 +201,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
       common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
       tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
       common-exceptions.o symbol.o btrace-common.o fileio.o common-regcache.o \
+      gdb-byteswap.o \
       $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
@@ -590,6 +592,9 @@ fileio.o: ../common/fileio.c
 common-regcache.o: ../common/common-regcache.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+gdb-byteswap.o: ../common/gdb-byteswap.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 # Arch object files rules form ../arch
 
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index 2af8e24..f875b10 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -21,6 +21,9 @@
 #include "gdbthread.h"
 #include "tdesc.h"
 #include "rsp-low.h"
+#include "bfd-types.h"
+#include "gdb-byteswap.h"
+
 #ifndef IN_PROCESS_AGENT
 
 struct regcache *
@@ -424,14 +427,25 @@ collect_register (struct regcache *regcache, int n, void *buf)
 	  register_size (regcache->tdesc, n));
 }
 
+#ifndef IN_PROCESS_AGENT
+
+/* Return host endianness as an enum bfd_endian.  */
+
+static enum bfd_endian
+host_bfd_endian (void)
+{
+  return (__BYTE_ORDER == __LITTLE_ENDIAN
+	  ? BFD_ENDIAN_LITTLE
+	  : BFD_ENDIAN_BIG);
+}
+
 enum register_status
 regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
 			    ULONGEST *val)
 {
   int size;
-
-  gdb_assert (regcache != NULL);
-  gdb_assert (regnum >= 0 && regnum < regcache->tdesc->num_registers);
+  gdb_byte *buf;
+  enum bfd_endian byteorder;
 
   size = register_size (regcache->tdesc, regnum);
 
@@ -440,14 +454,17 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
             "%d bytes."),
           (int) sizeof (ULONGEST));
 
-  *val = 0;
-  collect_register (regcache, regnum, val);
+  buf = (gdb_byte *) alloca (size);
+  collect_register (regcache, regnum, buf);
+
+  /* Assume the inferior's byte order is the same as gdbserver's (the
+     host).  */
+  byteorder = host_bfd_endian ();
 
+  *val = extract_unsigned_integer (buf, size, byteorder);
   return REG_VALID;
 }
 
-#ifndef IN_PROCESS_AGENT
-
 void
 collect_register_as_string (struct regcache *regcache, int n, char *buf)
 {
-- 
1.9.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]