aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2002-02-27 07:07:49 +0000
committerDaniel Jacobowitz <drow@false.org>2002-02-27 07:07:49 +0000
commit58caa3dcdb43a5d66932182338f41df0bfd6cc98 (patch)
tree8932e0b600933a36f94b2668449ca3626bc0b5ac /gdb/gdbserver
parent936521746ce912bf28fbeb3be2a006f6ffe23929 (diff)
downloadgdb-58caa3dcdb43a5d66932182338f41df0bfd6cc98.zip
gdb-58caa3dcdb43a5d66932182338f41df0bfd6cc98.tar.gz
gdb-58caa3dcdb43a5d66932182338f41df0bfd6cc98.tar.bz2
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.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/Makefile.in24
-rw-r--r--gdb/gdbserver/acconfig.h9
-rw-r--r--gdb/gdbserver/config.in10
-rwxr-xr-xgdb/gdbserver/configure75
-rw-r--r--gdb/gdbserver/configure.in28
-rw-r--r--gdb/gdbserver/configure.srv18
-rw-r--r--gdb/gdbserver/i387-fp.c290
-rw-r--r--gdb/gdbserver/i387-fp.h33
-rw-r--r--gdb/gdbserver/linux-arm-low.c1
-rw-r--r--gdb/gdbserver/linux-i386-low.c76
-rw-r--r--gdb/gdbserver/linux-ia64-low.c1
-rw-r--r--gdb/gdbserver/linux-low.c155
-rw-r--r--gdb/gdbserver/linux-low.h37
-rw-r--r--gdb/gdbserver/linux-m68k-low.c1
-rw-r--r--gdb/gdbserver/linux-mips-low.c1
-rw-r--r--gdb/gdbserver/linux-ppc-low.c1
-rw-r--r--gdb/gdbserver/linux-sh-low.c1
-rw-r--r--gdb/gdbserver/linux-x86-64-low.c79
-rw-r--r--gdb/gdbserver/regcache.c23
19 files changed, 840 insertions, 23 deletions
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d62ff71..31d3f62 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -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
index 0000000..968feb8
--- /dev/null
+++ b/gdb/gdbserver/acconfig.h
@@ -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
diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in
index 4d91a22..e77d5a7 100644
--- a/gdb/gdbserver/config.in
+++ b/gdb/gdbserver/config.in
@@ -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
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index 27a340b..c08d5c2 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -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"
diff --git a/gdb/gdbserver/configure.in b/gdb/gdbserver/configure.in
index 28f95a6..744aac2 100644
--- a/gdb/gdbserver/configure.in
+++ b/gdb/gdbserver/configure.in
@@ -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)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 6c0b00d..523dcb6 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -10,30 +10,46 @@
# 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
index 0000000..3d1d6a6
--- /dev/null
+++ b/gdb/gdbserver/i387-fp.c
@@ -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
index 0000000..90fe4ca
--- /dev/null
+++ b/gdb/gdbserver/i387-fp.h
@@ -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 */
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 761653a..f873b07 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -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-i386-low.c b/gdb/gdbserver/linux-i386-low.c
index cb7b55f..2a66efa 100644
--- a/gdb/gdbserver/linux-i386-low.c
+++ b/gdb/gdbserver/linux-i386-low.c
@@ -20,17 +20,14 @@
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 */
+
diff --git a/gdb/gdbserver/linux-ia64-low.c b/gdb/gdbserver/linux-ia64-low.c
index d7ab99b..f0f238f9 100644
--- a/gdb/gdbserver/linux-ia64-low.c
+++ b/gdb/gdbserver/linux-ia64-low.c
@@ -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-low.c b/gdb/gdbserver/linux-low.c
index f9152c7..b1e3d13 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -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>
@@ -37,6 +38,10 @@
#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
index 0000000..421fa22
--- /dev/null
+++ b/gdb/gdbserver/linux-low.h
@@ -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
diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c
index 334084a..9e59fbd 100644
--- a/gdb/gdbserver/linux-m68k-low.c
+++ b/gdb/gdbserver/linux-m68k-low.c
@@ -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-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 0fbe92b..a9114d3 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -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-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 38f7b70..dcefa59 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -21,6 +21,7 @@
Boston, MA 02111-1307, USA. */
#include "server.h"
+#include "linux-low.h"
#include <asm/ptrace.h>
diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c
index 9fdb757..f763339 100644
--- a/gdb/gdbserver/linux-sh-low.c
+++ b/gdb/gdbserver/linux-sh-low.c
@@ -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
index 0000000..d176613
--- /dev/null
+++ b/gdb/gdbserver/linux-x86-64-low.c
@@ -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 */
+
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index 551a71a..bec20bb 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -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);
+}