From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 69555 invoked by alias); 11 Feb 2016 12:46:28 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 69530 invoked by uid 89); 11 Feb 2016 12:46:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.1 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS,UNSUBSCRIBE_BODY autolearn=no version=3.3.2 spammy=427, inferiors, Header, Arch X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 11 Feb 2016 12:46:22 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 397865A44; Thu, 11 Feb 2016 12:46:21 +0000 (UTC) Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u1BCkKEZ004389; Thu, 11 Feb 2016 07:46:20 -0500 Message-ID: <56BC829B.8060102@redhat.com> Date: Thu, 11 Feb 2016 12:46:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: Yao Qi CC: gdb-patches@sourceware.org Subject: Re: [PATCH] Clear *VAL in regcache_raw_read_unsigned References: <1455029644-6197-1-git-send-email-yao.qi@linaro.org> <86egckqztq.fsf@gmail.com> <56BB6ADB.6070909@redhat.com> <86a8n8qxyp.fsf@gmail.com> <56BB7512.2030507@redhat.com> <8660xvr1wr.fsf@gmail.com> In-Reply-To: <8660xvr1wr.fsf@gmail.com> Content-Type: multipart/mixed; boundary="------------070605070202040302070808" X-SW-Source: 2016-02/txt/msg00344.txt.bz2 This is a multi-part message in MIME format. --------------070605070202040302070808 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Content-length: 2990 On 02/11/2016 10:12 AM, Yao Qi wrote:> Pedro Alves 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 > + > #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 --------------070605070202040302070808 Content-Type: text/x-patch; name="0001-Move-enum-bfd_endian-to-a-non-generated-header.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0001-Move-enum-bfd_endian-to-a-non-generated-header.patch" Content-length: 3579 >From dd4a4f86240eac1262c760b6109b42242e007923 Mon Sep 17 00:00:00 2001 From: Pedro Alves 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 * 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 * 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 +#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 +#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 --------------070605070202040302070808 Content-Type: text/x-patch; name="0002-Move-store-extract-.-integer-routines-to-gdb-common.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0002-Move-store-extract-.-integer-routines-to-gdb-common.pat"; filename*1="ch" Content-length: 16718 >From ca47aa93d4a13e676e771041eb7372ff2cdb1487 Mon Sep 17 00:00:00 2001 From: Pedro Alves 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 * 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 . */ + +#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 . */ + +#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 --------------070605070202040302070808 Content-Type: text/x-patch; name="0003-Fix-gdbserver-s-regcache_raw_read_unsigned-on-big-en.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename*0="0003-Fix-gdbserver-s-regcache_raw_read_unsigned-on-big-en.pa"; filename*1="tch" Content-length: 3964 >From 04956cf9b84b53728e20f0dae1f561ab26714453 Mon Sep 17 00:00:00 2001 From: Pedro Alves 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 * 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 --------------070605070202040302070808--