From 58caa3dcdb43a5d66932182338f41df0bfd6cc98 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 27 Feb 2002 07:07:49 +0000 Subject: [PATCH] 2002-02-27 Daniel Jacobowitz * 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. --- gdb/ChangeLog | 29 ++++ gdb/configure.tgt | 4 +- gdb/gdbserver/Makefile.in | 24 ++- gdb/gdbserver/acconfig.h | 9 + gdb/gdbserver/config.in | 10 ++ gdb/gdbserver/configure | 75 ++++++++ gdb/gdbserver/configure.in | 28 +++ gdb/gdbserver/configure.srv | 18 +- gdb/gdbserver/i387-fp.c | 290 +++++++++++++++++++++++++++++++ gdb/gdbserver/i387-fp.h | 33 ++++ gdb/gdbserver/linux-arm-low.c | 1 + gdb/gdbserver/linux-i386-low.c | 76 +++++++- gdb/gdbserver/linux-ia64-low.c | 1 + gdb/gdbserver/linux-low.c | 155 ++++++++++++++++- gdb/gdbserver/linux-low.h | 37 ++++ gdb/gdbserver/linux-m68k-low.c | 1 + gdb/gdbserver/linux-mips-low.c | 1 + gdb/gdbserver/linux-ppc-low.c | 1 + gdb/gdbserver/linux-sh-low.c | 1 + gdb/gdbserver/linux-x86-64-low.c | 79 +++++++++ gdb/gdbserver/regcache.c | 23 +++ gdb/regformats/reg-x86-64.dat | 53 ++++++ 22 files changed, 925 insertions(+), 24 deletions(-) create mode 100644 gdb/gdbserver/acconfig.h create mode 100644 gdb/gdbserver/i387-fp.c create mode 100644 gdb/gdbserver/i387-fp.h create mode 100644 gdb/gdbserver/linux-low.h create mode 100644 gdb/gdbserver/linux-x86-64-low.c create mode 100644 gdb/regformats/reg-x86-64.dat diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 96e457c90d..e77bc1a340 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,32 @@ +2002-02-27 Daniel Jacobowitz + + * 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 * gdbserver/Makefile.in (INTERNAL_CFLAGS): Remove -DGDBSERVER. diff --git a/gdb/configure.tgt b/gdb/configure.tgt index f5085608da..ce262746a6 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -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 ;; diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index d62ff7139b..31d3f62be0 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 0000000000..968feb8b43 --- /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 4d91a2269e..e77d5a78a5 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 header file. */ #undef HAVE_SGTTY_H diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure index 27a340bd37..c08d5c2050 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 < +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 < +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 28f95a64ed..744aac206c 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 ], + [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 ], + [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 6c0b00d903..523dcb6aae 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 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 0000000000..3d1d6a6fd5 --- /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 0000000000..90fe4ca6eb --- /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 761653af42..f873b071a8 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 diff --git a/gdb/gdbserver/linux-i386-low.c b/gdb/gdbserver/linux-i386-low.c index cb7b55f0f6..2a66efaa70 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 #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 +#include + +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 d7ab99bf9e..f0f238f932 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 diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index f9152c7ea3..b1e3d13298 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 +#include "linux-low.h" +#include #include #include #include @@ -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 0000000000..421fa22786 --- /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 334084ad61..9e59fbdeee 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 diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c index 0fbe92b145..a9114d3fb6 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 diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c index 38f7b70a80..dcefa59a67 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 diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c index 9fdb75700a..f763339e3d 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 diff --git a/gdb/gdbserver/linux-x86-64-low.c b/gdb/gdbserver/linux-x86-64-low.c new file mode 100644 index 0000000000..d1766133aa --- /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 +#include +#include + +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 551a71a349..bec20bb6fd 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); +} diff --git a/gdb/regformats/reg-x86-64.dat b/gdb/regformats/reg-x86-64.dat new file mode 100644 index 0000000000..a8a2e8c77b --- /dev/null +++ b/gdb/regformats/reg-x86-64.dat @@ -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 -- 2.34.1