2002-02-27 Daniel Jacobowitz <drow@mvista.com>
authorDaniel Jacobowitz <drow@false.org>
Wed, 27 Feb 2002 07:07:49 +0000 (07:07 +0000)
committerDaniel Jacobowitz <drow@false.org>
Wed, 27 Feb 2002 07:07:49 +0000 (07:07 +0000)
        * gdbserver/acconfig.h: New file.
        * gdbserver/i387-fp.c: New file.
        * gdbserver/i387-fp.h: New file.
        * gdbserver/linux-x86-64.c: New file.
        * regformats/reg-x86-64.dat: New file.
        * configure.tgt: Add x86_64-*-linux* gdbserver support.
        & gdbserver/configure.srv: Add x86_64-*-linux* and regset support.
        * gdbserver/configure.in: Add support for regsets.
        * gdbserver/config.in: Regenerate.
        * gdbserver/configure: Regenerate.
        * gdbserver/Makefile.in: Likewise.  Add $(linux_low_h).
        * gdbserver/linux-low.h: New file.
        * gdbserver/linux-low.c: Include "linux-low.h".  Add support
        for regsets.
        * gdbserver/linux-arm-low.c: Include "linux-low.h".
        * gdbserver/linux-ia64-low.c: Include "linux-low.h".
        * gdbserver/linux-m68k-low.c: Include "linux-low.h".
        * gdbserver/linux-mips-low.c: Include "linux-low.h".
        * gdbserver/linux-ppc-low.c: Include "linux-low.h".
        * gdbserver/linux-sh-low.c: Include "linux-low.h".
        * gdbserver/linux-i386-low.c: Include "linux-low.h".  Include
        "i387-fp.h".  Add PTRACE_GETREGS and friends.
        * gdbserver/regcache.c (supply_register): New function.
        (supply_register_by_name): New function.
        (collect_register): New function.
        (collect_register_by_name): New function.

22 files changed:
gdb/ChangeLog
gdb/configure.tgt
gdb/gdbserver/Makefile.in
gdb/gdbserver/acconfig.h [new file with mode: 0644]
gdb/gdbserver/config.in
gdb/gdbserver/configure
gdb/gdbserver/configure.in
gdb/gdbserver/configure.srv
gdb/gdbserver/i387-fp.c [new file with mode: 0644]
gdb/gdbserver/i387-fp.h [new file with mode: 0644]
gdb/gdbserver/linux-arm-low.c
gdb/gdbserver/linux-i386-low.c
gdb/gdbserver/linux-ia64-low.c
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h [new file with mode: 0644]
gdb/gdbserver/linux-m68k-low.c
gdb/gdbserver/linux-mips-low.c
gdb/gdbserver/linux-ppc-low.c
gdb/gdbserver/linux-sh-low.c
gdb/gdbserver/linux-x86-64-low.c [new file with mode: 0644]
gdb/gdbserver/regcache.c
gdb/regformats/reg-x86-64.dat [new file with mode: 0644]

index 96e457c90dd4571a2ef517a807e0831104a74737..e77bc1a340698177e8edac0dde2275cd300f7394 100644 (file)
@@ -1,3 +1,32 @@
+2002-02-27  Daniel Jacobowitz  <drow@mvista.com>
+
+       * gdbserver/acconfig.h: New file.
+       * gdbserver/i387-fp.c: New file.
+       * gdbserver/i387-fp.h: New file.
+       * gdbserver/linux-x86-64.c: New file.
+       * regformats/reg-x86-64.dat: New file.
+       * configure.tgt: Add x86_64-*-linux* gdbserver support.
+       * gdbserver/configure.srv: Add x86_64-*-linux* and regset support.
+       * gdbserver/configure.in: Add support for regsets.
+       * gdbserver/config.in: Regenerate.
+       * gdbserver/configure: Regenerate.
+       * gdbserver/Makefile.in: Likewise.  Add $(linux_low_h).
+       * gdbserver/linux-low.h: New file.
+       * gdbserver/linux-low.c: Include "linux-low.h".  Add support
+       for regsets.
+       * gdbserver/linux-arm-low.c: Include "linux-low.h".
+       * gdbserver/linux-ia64-low.c: Include "linux-low.h".
+       * gdbserver/linux-m68k-low.c: Include "linux-low.h".
+       * gdbserver/linux-mips-low.c: Include "linux-low.h".
+       * gdbserver/linux-ppc-low.c: Include "linux-low.h".
+       * gdbserver/linux-sh-low.c: Include "linux-low.h".
+       * gdbserver/linux-i386-low.c: Include "linux-low.h".  Include
+       "i387-fp.h".  Add PTRACE_GETREGS and friends.
+       * gdbserver/regcache.c (supply_register): New function.
+       (supply_register_by_name): New function.
+       (collect_register): New function.
+       (collect_register_by_name): New function.
+
 2002-02-27  Daniel Jacobowitz  <drow@mvista.com>
 
        * gdbserver/Makefile.in (INTERNAL_CFLAGS): Remove -DGDBSERVER.
index f5085608daf79bb12e37193e0bed0b8ba50b1650..ce262746a61dfcd282b07a9c61f1875524604681 100644 (file)
@@ -290,7 +290,9 @@ v850*-*-*)          gdb_target=v850
                        esac
                        ;;
 
-x86_64-*-linux*)       gdb_target=x86-64linux ;;
+x86_64-*-linux*)       gdb_target=x86-64linux
+                       build_gdbserver=yes
+                       ;;
 
 
 z8k-*-coff*)           gdb_target=z8k ;;
index d62ff7139bd8a106eee7f71617f58feb0f2c091f..31d3f62be075b610df3b720fb17be9951b5eb8df 100644 (file)
@@ -183,7 +183,7 @@ clean:
        rm -f *.o ${ADD_FILES} *~
        rm -f gdbserver gdbreplay core make.log
        rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m68k.c reg-mips.c
-       rm -f reg-ppc.c reg-sh.c reg-i386-linux.c
+       rm -f reg-ppc.c reg-sh.c reg-x86-64.c reg-i386-linux.c
 
 distclean: clean
        rm -f nm.h tm.h xm.h config.status
@@ -232,13 +232,18 @@ remote-utils.o: remote-utils.c terminal.h $(server_h)
 utils.o: utils.c $(server_h)
 regcache.o: regcache.c $(server_h) $(regdef_h)
 
-linux-low.o: linux-low.c $(server_h)
-linux-arm-low.o: linux-arm-low.c $(server_h)
-linux-i386-low.o: linux-i386-low.c $(server_h)
-linux-ia64-low.o: linux-ia64-low.c $(server_h)
-linux-mips-low.o: linux-mips-low.c $(server_h)
-linux-ppc-low.o: linux-ppc-low.c $(server_h)
-linux-sh-low.o: linux-sh-low.c $(server_h)
+i387-fp.o: i387-fp.c $(server_h)
+
+linux_low_h = $(srcdir)/linux-low.h
+
+linux-low.o: linux-low.c $(linux_low_h) $(server_h)
+linux-arm-low.o: linux-arm-low.c $(linux_low_h) $(server_h)
+linux-i386-low.o: linux-i386-low.c $(linux_low_h) $(server_h)
+linux-ia64-low.o: linux-ia64-low.c $(linux_low_h) $(server_h)
+linux-mips-low.o: linux-mips-low.c $(linux_low_h) $(server_h)
+linux-ppc-low.o: linux-ppc-low.c $(linux_low_h) $(server_h)
+linux-sh-low.o: linux-sh-low.c $(linux_low_h) $(server_h)
+linux-x86-64-low.o: linux-x86-64-low.c $(linux_low_h) $(server_h)
 
 # OBSOLETE TARGETS
 # OBSOLETE # low-lynx.o : ${srcdir}/low-lynx.c ${srcdir}/server.h
@@ -272,5 +277,8 @@ reg-ppc.c : $(srcdir)/../regformats/reg-ppc.dat $(regdat_sh)
 reg-sh.o : reg-sh.c $(regdef_h)
 reg-sh.c : $(srcdir)/../regformats/reg-sh.dat $(regdat_sh)
        sh $(regdat_sh) $(srcdir)/../regformats/reg-sh.dat reg-sh.c
+reg-x86-64.o : reg-x86-64.c $(regdef_h)
+reg-x86-64.c : $(srcdir)/../regformats/reg-x86-64.dat $(regdat_sh)
+       sh $(regdat_sh) $(srcdir)/../regformats/reg-x86-64.dat reg-x86-64.c
 
 # This is the end of "Makefile.in".
diff --git a/gdb/gdbserver/acconfig.h b/gdb/gdbserver/acconfig.h
new file mode 100644 (file)
index 0000000..968feb8
--- /dev/null
@@ -0,0 +1,9 @@
+/* Define if the target supports PTRACE_PEEKUSR for register access.  */
+#undef HAVE_LINUX_USRREGS
+
+/* Define if the target supports PTRACE_GETREGS for register access.  */
+#undef HAVE_LINUX_REGSETS
+
+/* Define if the target supports PTRACE_GETFPXREGS for extended
+   register access.  */
+#undef HAVE_PTRACE_GETFPXREGS
index 4d91a2269e47f2a70df519aa1310725e731bdc05..e77d5a78a5088ef260c79db40fc859bba59d590c 100644 (file)
@@ -3,6 +3,16 @@
 /* Define if you have the ANSI C header files.  */
 #undef STDC_HEADERS
 
+/* Define if the target supports PTRACE_PEEKUSR for register access.  */
+#undef HAVE_LINUX_USRREGS
+
+/* Define if the target supports PTRACE_GETREGS for register access.  */
+#undef HAVE_LINUX_REGSETS
+
+/* Define if the target supports PTRACE_GETFPXREGS for extended
+   register access.  */
+#undef HAVE_PTRACE_GETFPXREGS
+
 /* Define if you have the <sgtty.h> header file.  */
 #undef HAVE_SGTTY_H
 
index 27a340bd37b73e1b93a965c0afaed55e767c73fc..c08d5c20508bf030b3c6b7e145d267f551b4a181 100755 (executable)
@@ -1148,6 +1148,81 @@ done
 
 . ${srcdir}/configure.srv
 
+if test "${srv_linux_usrregs}" = "yes"; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_USRREGS 1
+EOF
+
+fi
+
+if test "${srv_linux_regsets}" = "yes"; then
+  echo $ac_n "checking for PTRACE_GETREGS""... $ac_c" 1>&6
+echo "configure:1161: checking for PTRACE_GETREGS" >&5
+  if eval "test \"`echo '$''{'gdbsrv_cv_have_ptrace_getregs'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1166 "configure"
+#include "confdefs.h"
+#include <sys/ptrace.h>
+int main() {
+PTRACE_GETREGS;
+; return 0; }
+EOF
+if { (eval echo configure:1173: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  gdbsrv_cv_have_ptrace_getregs=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  gdbsrv_cv_have_ptrace_getregs=no
+fi
+rm -f conftest*
+fi
+
+  echo "$ac_t""$gdbsrv_cv_have_ptrace_getregs" 1>&6
+  if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_LINUX_REGSETS 1
+EOF
+
+  fi
+
+  echo $ac_n "checking for PTRACE_GETFPXREGS""... $ac_c" 1>&6
+echo "configure:1194: checking for PTRACE_GETFPXREGS" >&5
+  if eval "test \"`echo '$''{'gdbsrv_cv_have_ptrace_getfpxregs'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1199 "configure"
+#include "confdefs.h"
+#include <sys/ptrace.h>
+int main() {
+PTRACE_GETFPXREGS;
+; return 0; }
+EOF
+if { (eval echo configure:1206: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  gdbsrv_cv_have_ptrace_getfpxregs=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  gdbsrv_cv_have_ptrace_getfpxregs=no
+fi
+rm -f conftest*
+fi
+
+  echo "$ac_t""$gdbsrv_cv_have_ptrace_getfpxregs" 1>&6
+  if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then
+    cat >> confdefs.h <<\EOF
+#define HAVE_PTRACE_GETFPXREGS 1
+EOF
+
+  fi
+fi
+
 GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
 
 
index 28f95a64ed10cd07da3815b58e9e92246d8ea3f2..744aac206c03fc650ad5fc60d69e9de5530aa88d 100644 (file)
@@ -34,6 +34,34 @@ AC_CHECK_HEADERS(sgtty.h termio.h termios.h sys/reg.h)
 
 . ${srcdir}/configure.srv
 
+if test "${srv_linux_usrregs}" = "yes"; then
+  AC_DEFINE(HAVE_LINUX_USRREGS)
+fi
+
+if test "${srv_linux_regsets}" = "yes"; then
+  AC_MSG_CHECKING(for PTRACE_GETREGS)
+  AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getregs,
+  [AC_TRY_COMPILE([#include <sys/ptrace.h>],
+                 [PTRACE_GETREGS;],
+                 [gdbsrv_cv_have_ptrace_getregs=yes],
+                 [gdbsrv_cv_have_ptrace_getregs=no])])
+  AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getregs)
+  if test "${gdbsrv_cv_have_ptrace_getregs}" = "yes"; then
+    AC_DEFINE(HAVE_LINUX_REGSETS)
+  fi
+
+  AC_MSG_CHECKING(for PTRACE_GETFPXREGS)
+  AC_CACHE_VAL(gdbsrv_cv_have_ptrace_getfpxregs,
+  [AC_TRY_COMPILE([#include <sys/ptrace.h>],
+                 [PTRACE_GETFPXREGS;],
+                 [gdbsrv_cv_have_ptrace_getfpxregs=yes],
+                 [gdbsrv_cv_have_ptrace_getfpxregs=no])])
+  AC_MSG_RESULT($gdbsrv_cv_have_ptrace_getfpxregs)
+  if test "${gdbsrv_cv_have_ptrace_getfpxregs}" = "yes"; then
+    AC_DEFINE(HAVE_PTRACE_GETFPXREGS)
+  fi
+fi
+
 GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
 
 AC_SUBST(GDBSERVER_DEPFILES)
index 6c0b00d903b87ccd66219bbfdace7a2e3500bba3..523dcb6aaebfd90be642dc20f1b89fa646ace95f 100644 (file)
 # In addition, on GNU/Linux the following shell variables will be set:
 #   srv_linux_regsets  Set to "yes" if ptrace(PTRACE_GETREGS) and friends
 #                      may be available on this platform;  unset otherwise.
+#                      They will only be used if <sys/ptrace.h> defines
+#                      PTRACE_GETREGS.
+#   srv_linux_usrregs  Set to "yes" if we can get at registers via
+#                      PTRACE_PEEKUSR / PTRACE_POKEUSR.
 
 # Input is taken from the "${target}" variable.
 
 case "${target}" in
   arm*-*-linux*)       srv_regobj=reg-arm.o
                        srv_tgtobj="linux-low.o linux-arm-low.o"
+                       srv_linux_usrregs=yes
                        ;;
   i[3456]86-*-linux*)  srv_regobj=reg-i386-linux.o
-                       srv_tgtobj="linux-low.o linux-i386-low.o"
+                       srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
+                       srv_linux_usrregs=yes
+                       srv_linux_regsets=yes
                        ;;
   ia64-*-linux*)       srv_regobj=reg-ia64.o
                        srv_tgtobj="linux-low.o linux-ia64-low.o"
+                       srv_linux_usrregs=yes
                        ;;
   m68*-*-linux*)       srv_regobj=reg-m68k.o
                        srv_tgtobj="linux-low.o linux-m68k-low.o"
+                       srv_linux_usrregs=yes
                        ;;
   mips*-*-linux*)      srv_regobj=reg-mips.o
                        srv_tgtobj="linux-low.o linux-mips-low.o"
+                       srv_linux_usrregs=yes
                        ;;
   powerpc*-*-linux*)   srv_regobj=reg-ppc.o
                        srv_tgtobj="linux-low.o linux-ppc-low.o"
+                       srv_linux_usrregs=yes
                        ;;
   sh*-*-linux*)                srv_regobj=reg-sh.o
                        srv_tgtobj="linux-low.o linux-sh-low.o"
+                       srv_linux_usrregs=yes
+                       ;;
+  x86_64-*-linux*)     srv_regobj=reg-x86-64.o
+                       srv_tgtobj="linux-low.o linux-x86-64-low.o i387-fp.o"
+                       srv_linux_regsets=yes
                        ;;
   *)                   echo "Error: target not supported by gdbserver."
                        exit 1
diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c
new file mode 100644 (file)
index 0000000..3d1d6a6
--- /dev/null
@@ -0,0 +1,290 @@
+/* i387-specific utility functions, for the remote server for GDB.
+   Copyright 2000, 2001, 2002
+   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 2 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+
+int num_xmm_registers = 8;
+
+/* Note: These functions preserve the reserved bits in control registers.
+   However, gdbserver promptly throws away that information.  */
+
+/* These structs should have the proper sizes and alignment on both
+   i386 and x86-64 machines.  */
+
+struct i387_fsave {
+  /* All these are only sixteen bits, plus padding, except for fop (which
+     is only eleven bits), and fooff / fioff (which are 32 bits each).  */
+  unsigned int fctrl;
+  unsigned int fstat;
+  unsigned int ftag;
+  unsigned int fioff;
+  unsigned short fiseg;
+  unsigned short fop;
+  unsigned int fooff;
+  unsigned int foseg;
+
+  /* Space for eight 80-bit FP values.  */
+  char st_space[80];
+};
+
+struct i387_fxsave {
+  /* All these are only sixteen bits, plus padding, except for fop (which
+     is only eleven bits), and fooff / fioff (which are 32 bits each).  */
+  unsigned short fctrl;
+  unsigned short fstat;
+  unsigned short ftag;
+  unsigned short fop;
+  unsigned int fioff;
+  unsigned int fiseg;
+  unsigned int fooff;
+  unsigned int foseg;
+
+  unsigned int mxcsr;
+
+  unsigned int _pad1;
+
+  /* Space for eight 80-bit FP values in 128-bit spaces.  */
+  char st_space[128];
+
+  /* Space for eight 128-bit XMM values, or 16 on x86-64.  */
+  char xmm_space[256];
+};
+
+void
+i387_cache_to_fsave (void *buf)
+{
+  struct i387_fsave *fp = (struct i387_fsave *) buf;
+  int i;
+  int st0_regnum = find_regno ("st0");
+  unsigned long val, val2;
+
+  for (i = 0; i < 8; i++)
+    collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10);
+
+  collect_register_by_name ("fioff", &fp->fioff);
+  collect_register_by_name ("fooff", &fp->fooff);
+  
+  /* This one's 11 bits... */
+  collect_register_by_name ("fop", &val2);
+  fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
+
+  /* Some registers are 16-bit.  */
+  collect_register_by_name ("fctrl", &val);
+  *(unsigned short *) &fp->fctrl = val;
+
+  collect_register_by_name ("fstat", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->fstat = val;
+
+  collect_register_by_name ("ftag", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->ftag = val;
+
+  collect_register_by_name ("fiseg", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->fiseg = val;
+
+  collect_register_by_name ("foseg", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->foseg = val;
+}
+
+void
+i387_fsave_to_cache (void *buf)
+{
+  struct i387_fsave *fp = (struct i387_fsave *) buf;
+  int i;
+  int st0_regnum = find_regno ("st0");
+  unsigned long val;
+
+  for (i = 0; i < 8; i++)
+    supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 10);
+
+  supply_register_by_name ("fioff", &fp->fioff);
+  supply_register_by_name ("fooff", &fp->fooff);
+  
+  /* Some registers are 16-bit.  */
+  val = fp->fctrl & 0xFFFF;
+  supply_register_by_name ("fctrl", &val);
+
+  val = fp->fstat & 0xFFFF;
+  supply_register_by_name ("fstat", &val);
+
+  val = fp->ftag & 0xFFFF;
+  supply_register_by_name ("ftag", &val);
+
+  val = fp->fiseg & 0xFFFF;
+  supply_register_by_name ("fiseg", &val);
+
+  val = fp->foseg & 0xFFFF;
+  supply_register_by_name ("foseg", &val);
+
+  val = (fp->fop) & 0x7FF;
+  supply_register_by_name ("fop", &val);
+}
+
+void
+i387_cache_to_fxsave (void *buf)
+{
+  struct i387_fxsave *fp = (struct i387_fxsave *) buf;
+  int i;
+  int st0_regnum = find_regno ("st0");
+  int xmm0_regnum = find_regno ("xmm0");
+  unsigned long val, val2;
+
+  for (i = 0; i < 8; i++)
+    collect_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
+  for (i = 0; i < num_xmm_registers; i++)
+    collect_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+  collect_register_by_name ("fioff", &fp->fioff);
+  collect_register_by_name ("fooff", &fp->fooff);
+  collect_register_by_name ("mxcsr", &fp->mxcsr);
+  
+  /* This one's 11 bits... */
+  collect_register_by_name ("fop", &val2);
+  fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
+
+  /* Some registers are 16-bit.  */
+  collect_register_by_name ("fctrl", &val);
+  *(unsigned short *) &fp->fctrl = val;
+
+  collect_register_by_name ("fstat", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->fstat = val;
+
+  /* Convert to the simplifed tag form stored in fxsave data.  */
+  collect_register_by_name ("ftag", &val);
+  val &= 0xFFFF;
+  for (i = 7; i >= 0; i--)
+    {
+      int tag = (val >> (i * 2)) & 3;
+
+      if (tag != 3)
+       val2 |= (1 << i);
+    }
+  *(unsigned short *) &fp->ftag = val2;
+
+  collect_register_by_name ("fiseg", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->fiseg = val;
+
+  collect_register_by_name ("foseg", &val);
+  val &= 0xFFFF;
+  *(unsigned short *) &fp->foseg = val;
+}
+
+static int
+i387_ftag (struct i387_fxsave *fp, int regno)
+{
+  unsigned char *raw = &fp->st_space[regno * 16];
+  unsigned int exponent;
+  unsigned long fraction[2];
+  int integer;
+
+  integer = raw[7] & 0x80;
+  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+                 | (raw[5] << 8) | raw[4]);
+
+  if (exponent == 0x7fff)
+    {
+      /* Special.  */
+      return (2);
+    }
+  else if (exponent == 0x0000)
+    {
+      if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
+        {
+          /* Zero.  */
+          return (1);
+        }
+      else
+        {
+          /* Special.  */
+          return (2);
+        }
+    }
+  else
+    {
+      if (integer)
+        {
+          /* Valid.  */
+          return (0);
+        }
+      else
+        {
+          /* Special.  */
+          return (2);
+        }
+    }
+}
+
+void
+i387_fxsave_to_cache (void *buf)
+{
+  struct i387_fxsave *fp = (struct i387_fxsave *) buf;
+  int i, top;
+  int st0_regnum = find_regno ("st0");
+  int xmm0_regnum = find_regno ("xmm0");
+  unsigned long val;
+
+  for (i = 0; i < 8; i++)
+    supply_register (i + st0_regnum, ((char *) &fp->st_space[0]) + i * 16);
+  for (i = 0; i < num_xmm_registers; i++)
+    supply_register (i + xmm0_regnum, ((char *) &fp->xmm_space[0]) + i * 16);
+
+  supply_register_by_name ("fioff", &fp->fioff);
+  supply_register_by_name ("fooff", &fp->fooff);
+  supply_register_by_name ("mxcsr", &fp->mxcsr);
+  
+  /* Some registers are 16-bit.  */
+  val = fp->fctrl & 0xFFFF;
+  supply_register_by_name ("fctrl", &val);
+
+  val = fp->fstat & 0xFFFF;
+  supply_register_by_name ("fstat", &val);
+
+  /* Generate the form of ftag data that GDB expects.  */
+  top = (fp->fstat >> 11) & 0x7;
+  val = 0;
+  for (i = 7; i >= 0; i--)
+    {
+      int tag;
+      if (val & (1 << i))
+       tag = i387_ftag (fp, (i + 8 - top) % 8);
+      else
+       tag = 3;
+      val |= tag << (2 * i);
+    }
+  supply_register_by_name ("ftag", &val);
+
+  val = fp->fiseg & 0xFFFF;
+  supply_register_by_name ("fiseg", &val);
+
+  val = fp->foseg & 0xFFFF;
+  supply_register_by_name ("foseg", &val);
+
+  val = (fp->fop) & 0x7FF;
+  supply_register_by_name ("fop", &val);
+}
+
diff --git a/gdb/gdbserver/i387-fp.h b/gdb/gdbserver/i387-fp.h
new file mode 100644 (file)
index 0000000..90fe4ca
--- /dev/null
@@ -0,0 +1,33 @@
+/* i387-specific utility functions, for the remote server for GDB.
+   Copyright 2000, 2001, 2002
+   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 2 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef I387_FP_H
+#define I387_FP_H
+
+void i387_cache_to_fsave (void *buf);
+void i387_fsave_to_cache (void *buf);
+
+void i387_cache_to_fxsave (void *buf);
+void i387_fxsave_to_cache (void *buf);
+
+extern int num_xmm_registers;
+
+#endif /* I387_FP_H */
index 761653af4234ac6f1119e6cb81cb34fa7ffa8d0f..f873b071a812c8e73b0d425312c8ef5b13d0b1e0 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
index cb7b55f0f6cdaa1884c1256bdfa3dda56b5b6fa2..2a66efaa70ead11150af388204a290cdd453f2af 100644 (file)
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
+#include "i387-fp.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
 #endif
 
-/* This module only supports access to the general purpose registers.
-   Adjust the relevant constants accordingly.
-
-   FIXME: kettenis/2001-03-28: We should really use PTRACE_GETREGS to
-   get at the registers.  Better yet, we should try to share code with
-   i386-linux-nat.c.  */
+/* This module only supports access to the general purpose registers.  */
 
 int num_regs = 16;
 
@@ -57,3 +54,70 @@ cannot_fetch_register (int regno)
 {
   return (regno >= num_regs);
 }
+
+
+#ifdef HAVE_LINUX_REGSETS
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+
+static void
+i386_fill_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < num_regs; i++)
+    collect_register (i, ((char *) buf) + regmap[i]);
+
+  collect_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
+}
+
+static void
+i386_store_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < num_regs; i++)
+    supply_register (i, ((char *) buf) + regmap[i]);
+
+  supply_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4);
+}
+
+static void
+i386_fill_fpregset (void *buf)
+{
+  i387_cache_to_fsave (buf);
+}
+
+static void
+i386_store_fpregset (void *buf)
+{
+  i387_fsave_to_cache (buf);
+}
+
+static void
+i386_fill_fpxregset (void *buf)
+{
+  i387_cache_to_fxsave (buf);
+}
+
+static void
+i386_store_fpxregset (void *buf)
+{
+  i387_fxsave_to_cache (buf);
+}
+
+
+struct regset_info target_regsets[] = {
+  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    i386_fill_gregset, i386_store_gregset },
+#ifdef HAVE_PTRACE_GETFPXREGS
+  { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
+    i386_fill_fpxregset, i386_store_fpxregset },
+#endif
+  { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+    i386_fill_fpregset, i386_store_fpregset },
+  { 0, 0, -1, NULL, NULL }
+};
+
+#endif /* HAVE_LINUX_REGSETS */
+
index d7ab99bf9efe28c8a7dd116cd2af5760a65a8ee8..f0f238f9320de273682bc455984b58de4e66d1b6 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
index f9152c7ea3c6c6c8e12a0d86ff7cb93af763fa02..b1e3d1329802135330c329dc74ca1f58295b33ed 100644 (file)
@@ -20,8 +20,9 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
-#include <sys/wait.h>
+#include "linux-low.h"
 
+#include <sys/wait.h>
 #include <stdio.h>
 #include <sys/param.h>
 #include <sys/dir.h>
 #define PTRACE_ARG3_TYPE long
 #define PTRACE_XFER_TYPE int
 
+#ifdef HAVE_LINUX_REGSETS
+static int use_regsets_p = 1;
+#endif
+
 extern int errno;
 extern int num_regs;
 extern int regmap[];
@@ -166,8 +171,11 @@ register_addr (int regnum)
   return addr;
 }
 
-/* Fetch one register.  */
 
+
+#ifdef HAVE_LINUX_USRREGS
+
+/* Fetch one register.  */
 static void
 fetch_register (int regno)
 {
@@ -203,9 +211,8 @@ error_exit:;
 }
 
 /* Fetch all registers, or just one, from the child process.  */
-
-void
-fetch_inferior_registers (int regno)
+static void
+usr_fetch_inferior_registers (int regno)
 {
   if (regno == -1 || regno == 0)
     for (regno = 0; regno < num_regs; regno++)
@@ -217,9 +224,8 @@ fetch_inferior_registers (int regno)
 /* Store our register values back into the inferior.
    If REGNO is -1, do this for all registers.
    Otherwise, REGNO specifies which register (so we can save time).  */
-
-void
-store_inferior_registers (int regno)
+static void
+usr_store_inferior_registers (int regno)
 {
   CORE_ADDR regaddr;
   int i;
@@ -259,6 +265,139 @@ store_inferior_registers (int regno)
     for (regno = 0; regno < num_regs; regno++)
       store_inferior_registers (regno);
 }
+#endif /* HAVE_LINUX_USRREGS */
+
+
+
+#ifdef HAVE_LINUX_REGSETS
+
+static int
+regsets_fetch_inferior_registers (void)
+{
+  struct regset_info *regset;
+
+  regset = target_regsets;
+
+  while (regset->size >= 0)
+    {
+      void *buf;
+      int res;
+
+      if (regset->size == 0)
+       {
+         regset ++;
+         continue;
+       }
+
+      buf = malloc (regset->size);
+      res = ptrace (regset->get_request, inferior_pid, 0, (int) buf);
+      if (res < 0)
+       {
+         if (errno == EIO)
+           {
+             /* If we get EIO on the first regset, do not try regsets again.
+                If we get EIO on a later regset, disable that regset.  */
+             if (regset == target_regsets)
+               {
+                 use_regsets_p = 0;
+                 return -1;
+               }
+             else
+               {
+                 regset->size = 0;
+                 continue;
+               }
+           }
+         else
+           {
+             perror ("Warning: ptrace(regsets_fetch_inferior_registers)");
+           }
+       }
+      regset->store_function (buf);
+      regset ++;
+    }
+}
+
+static int
+regsets_store_inferior_registers (void)
+{
+  struct regset_info *regset;
+
+  regset = target_regsets;
+
+  while (regset->size >= 0)
+    {
+      void *buf;
+      int res;
+
+      if (regset->size == 0)
+       {
+         regset ++;
+         continue;
+       }
+
+      buf = malloc (regset->size);
+      regset->fill_function (buf);
+      res = ptrace (regset->set_request, inferior_pid, 0, (int) buf);
+      if (res < 0)
+       {
+         if (errno == EIO)
+           {
+             /* If we get EIO on the first regset, do not try regsets again.
+                If we get EIO on a later regset, disable that regset.  */
+             if (regset == target_regsets)
+               {
+                 use_regsets_p = 0;
+                 return -1;
+               }
+             else
+               {
+                 regset->size = 0;
+                 continue;
+               }
+           }
+         else
+           {
+             perror ("Warning: ptrace(regsets_fetch_inferior_registers)");
+           }
+       }
+      regset ++;
+    }
+}
+
+#endif /* HAVE_LINUX_REGSETS */
+
+
+void
+fetch_inferior_registers (int regno)
+{
+#ifdef HAVE_LINUX_REGSETS
+  if (use_regsets_p)
+    {
+      if (regsets_fetch_inferior_registers () == 0)
+       return;
+    }
+#endif
+#ifdef HAVE_LINUX_USRREGS
+  usr_fetch_inferior_registers (regno);
+#endif
+}
+
+void
+store_inferior_registers (int regno)
+{
+#ifdef HAVE_LINUX_REGSETS
+  if (use_regsets_p)
+    {
+      if (regsets_store_inferior_registers () == 0)
+       return;
+    }
+#endif
+#ifdef HAVE_LINUX_USRREGS
+  usr_store_inferior_registers (regno);
+#endif
+}
+
 
 /* Copy LEN bytes from inferior's memory starting at MEMADDR
    to debugger memory starting at MYADDR.  */
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
new file mode 100644 (file)
index 0000000..421fa22
--- /dev/null
@@ -0,0 +1,37 @@
+/* Internal interfaces for the GNU/Linux specific target code for gdbserver.
+   Copyright 2002, 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 2 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_LINUX_USR_REGISTERS
+extern int regmap[];
+extern int num_regs;
+int cannot_fetch_register (int regno);
+int cannot_store_register (int regno);
+#endif
+
+#ifdef HAVE_LINUX_REGSETS
+typedef void (*regset_func) (void *);
+struct regset_info
+{
+  int get_request, set_request;
+  int size;
+  regset_func fill_function, store_function;
+};
+extern struct regset_info target_regsets[];
+#endif
index 334084ad61c548551d74e6487eda141a23d3bd61..9e59fbdeee930ca46506ae9a646585e6c9e22865 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
index 0fbe92b145d0b9635b22abbf64f9a9f54dcdd82a..a9114d3fb6496ef6b41604954ea9c8955d9f6863 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
index 38f7b70a80af26d9b280c9aa92fabeb91d451ec4..dcefa59a677daa584a372bfa0449d68c83500eed 100644 (file)
@@ -21,6 +21,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #include <asm/ptrace.h>
 
index 9fdb75700a948555742ef1b0e033e4385819c5cf..f763339e3d27280252199fb49e9fc0a357db6767 100644 (file)
@@ -20,6 +20,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #ifdef HAVE_SYS_REG_H
 #include <sys/reg.h>
diff --git a/gdb/gdbserver/linux-x86-64-low.c b/gdb/gdbserver/linux-x86-64-low.c
new file mode 100644 (file)
index 0000000..d176613
--- /dev/null
@@ -0,0 +1,79 @@
+/* GNU/Linux/x86-64 specific low level interface, for the remote server
+   for GDB.
+   Copyright 2002
+   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 2 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+#include "linux-low.h"
+#include "i387-fp.h"
+
+#include <sys/reg.h>
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+
+static int regmap[] = {
+  RAX, RDX, RCX, RBX,
+  RSI, RDI, RBP, RSP,
+  R8, R9, R10, R11,
+  R12, R13, R14, R15,
+  RIP, EFLAGS
+};
+
+static void
+x86_64_fill_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < 18; i++)
+    collect_register (i, ((char *) buf) + regmap[i]);
+}
+
+static void
+x86_64_store_gregset (void *buf)
+{
+  int i;
+
+  for (i = 0; i < 18; i++)
+    supply_register (i, ((char *) buf) + regmap[i]);
+}
+
+static void
+x86_64_fill_fpregset (void *buf)
+{
+  i387_cache_to_fxsave (buf);
+}
+
+static void
+x86_64_store_fpregset (void *buf)
+{
+  i387_fxsave_to_cache (buf);
+}
+
+
+struct regset_info target_regsets[] = {
+  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
+    x86_64_fill_gregset, x86_64_store_gregset },
+  { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
+    x86_64_fill_fpregset, x86_64_store_fpregset },
+  { 0, 0, -1, NULL, NULL }
+};
+
+#endif /* HAVE_LINUX_REGSETS */
+
index 551a71a349a55b0c982718751a9a714770d4577f..bec20bb6fd87c328c7ffe329296b4ee05a59f9e9 100644 (file)
@@ -122,3 +122,26 @@ register_data (int n)
   return registers + (reg_defs[n].offset / 8);
 }
 
+void
+supply_register (int n, const char *buf)
+{
+  memcpy (register_data (n), buf, register_size (n));
+}
+
+void
+supply_register_by_name (const char *name, const char *buf)
+{
+  supply_register (find_regno (name), buf);
+}
+
+void
+collect_register (int n, char *buf)
+{
+  memcpy (buf, register_data (n), register_size (n));
+}
+
+void
+collect_register_by_name (const char *name, char *buf)
+{
+  collect_register (find_regno (name), buf);
+}
diff --git a/gdb/regformats/reg-x86-64.dat b/gdb/regformats/reg-x86-64.dat
new file mode 100644 (file)
index 0000000..a8a2e8c
--- /dev/null
@@ -0,0 +1,53 @@
+name:x86_64
+expedite:rbp,rsp,rip
+64:rax
+64:rdx
+64:rcx
+64:rbx
+64:rsi
+64:rdi
+64:rbp
+64:rsp
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:rip
+32:eflags
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+128:xmm0
+128:xmm1
+128:xmm2
+128:xmm3
+128:xmm4
+128:xmm5
+128:xmm6
+128:xmm7
+128:xmm8
+128:xmm9
+128:xmm10
+128:xmm11
+128:xmm12
+128:xmm13
+128:xmm14
+128:xmm15
+32:mxcsr