This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


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

[RFA] PTRACE_*REGS and x86-64-linux support for gdbserver


This patch contains:
 - Support for the regset register interface on GNU/Linux.
 - The associated code to support floating point on i386.
 - The x86-64 port.

If anyone insists, I should be able to break the latter two off from the
former one, but as they are the only consumers of the regset code and as the
x86-64 code in fact depends on i386 floating point, I didn't see much point.

This took rather longer than I thought; what I get for claiming it would be
done on Sunday, I expect.  I blame i387-fp.c and its parent in i387-nat.c
for this; or at least, I blame the hardware they support.

OK to commit this?  I'm reasonably confident that the x86-64 code works, but
I would appreciate it if someone with the tools set up were to try it.  I
don't have the simulator installed.

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer

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.

Index: gdbserver/acconfig.h
===================================================================
RCS file: N/A
diff -u /dev/null gdbserver/acconfig.h
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ gdbserver/acconfig.h	Tue Feb 26 22:19:32 2002
@@ -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: gdbserver/i387-fp.c
===================================================================
RCS file: N/A
diff -u /dev/null gdbserver/i387-fp.c
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ gdbserver/i387-fp.c	Tue Feb 26 22:44:44 2002
@@ -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);
+}
+
Index: gdbserver/linux-low.h
===================================================================
RCS file: N/A
diff -u /dev/null gdbserver/linux-low.h
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ gdbserver/linux-low.h	Mon Feb 25 01:01:08 2002
@@ -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: gdbserver/i387-fp.h
===================================================================
RCS file: N/A
diff -u /dev/null gdbserver/i387-fp.h
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ gdbserver/i387-fp.h	Tue Feb 26 22:44:25 2002
@@ -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: gdbserver/linux-x86-64-low.c
===================================================================
RCS file: N/A
diff -u /dev/null gdbserver/linux-x86-64-low.c
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ gdbserver/linux-x86-64-low.c	Tue Feb 26 22:51:50 2002
@@ -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: regformats/reg-x86-64.dat
===================================================================
RCS file: N/A
diff -u /dev/null regformats/reg-x86-64.dat
--- /dev/null	Wed Dec 31 19:00:00 1969
+++ regformats/reg-x86-64.dat	Tue Feb 26 23:00:28 2002
@@ -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
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.53
diff -u -p -r1.53 configure.tgt
--- configure.tgt	2002/02/19 14:04:41	1.53
+++ configure.tgt	2002/02/27 06:23:43
@@ -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: gdbserver/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/Makefile.in,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile.in
--- gdbserver/Makefile.in	2002/02/27 06:22:10	1.10
+++ gdbserver/Makefile.in	2002/02/27 06:23:43
@@ -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,14 +232,19 @@ remote-utils.o: remote-utils.c terminal.
 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
 # OBSOLETE # low-nbsd.o : ${srcdir}/low-nbsd.c ${srcdir}/server.h
@@ -272,5 +277,8 @@ reg-ppc.c : $(srcdir)/../regformats/reg-
 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".
Index: gdbserver/config.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/config.in,v
retrieving revision 1.1
diff -u -p -r1.1 config.in
--- gdbserver/config.in	2002/02/19 23:48:14	1.1
+++ gdbserver/config.in	2002/02/27 06:23:43
@@ -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: gdbserver/configure
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure,v
retrieving revision 1.5
diff -u -p -r1.5 configure
--- gdbserver/configure	2002/02/25 02:47:23	1.5
+++ gdbserver/configure	2002/02/27 06:23:43
@@ -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: gdbserver/configure.in
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.in,v
retrieving revision 1.6
diff -u -p -r1.6 configure.in
--- gdbserver/configure.in	2002/02/25 02:47:23	1.6
+++ gdbserver/configure.in	2002/02/27 06:23:43
@@ -34,6 +34,34 @@ AC_CHECK_HEADERS(sgtty.h termio.h termio
 
 . ${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: gdbserver/configure.srv
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/configure.srv,v
retrieving revision 1.2
diff -u -p -r1.2 configure.srv
--- gdbserver/configure.srv	2002/02/27 06:18:08	1.2
+++ gdbserver/configure.srv	2002/02/27 06:23:43
@@ -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
Index: gdbserver/linux-arm-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-arm-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-arm-low.c
--- gdbserver/linux-arm-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-arm-low.c	2002/02/27 06:23:43
@@ -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: gdbserver/linux-i386-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-i386-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-i386-low.c
--- gdbserver/linux-i386-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-i386-low.c	2002/02/27 06:23:43
@@ -20,18 +20,15 @@
    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.
+/* This module only supports access to the general purpose registers.  */
 
-   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.  */
-
 int num_regs = 16;
 
 /* This stuff comes from i386-linux-nat.c.  */
@@ -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: gdbserver/linux-ia64-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-ia64-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-ia64-low.c
--- gdbserver/linux-ia64-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-ia64-low.c	2002/02/27 06:23:43
@@ -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: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.8
diff -u -p -r1.8 linux-low.c
--- gdbserver/linux-low.c	2002/02/20 22:58:57	1.8
+++ gdbserver/linux-low.c	2002/02/27 06:23:43
@@ -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.  */
Index: gdbserver/linux-m68k-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-m68k-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-m68k-low.c
--- gdbserver/linux-m68k-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-m68k-low.c	2002/02/27 06:23:43
@@ -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: gdbserver/linux-mips-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-mips-low.c,v
retrieving revision 1.3
diff -u -p -r1.3 linux-mips-low.c
--- gdbserver/linux-mips-low.c	2002/02/26 01:40:06	1.3
+++ gdbserver/linux-mips-low.c	2002/02/27 06:23:43
@@ -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: gdbserver/linux-ppc-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-ppc-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-ppc-low.c
--- gdbserver/linux-ppc-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-ppc-low.c	2002/02/27 06:23:43
@@ -21,6 +21,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include "server.h"
+#include "linux-low.h"
 
 #include <asm/ptrace.h>
 
Index: gdbserver/linux-sh-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-sh-low.c,v
retrieving revision 1.1
diff -u -p -r1.1 linux-sh-low.c
--- gdbserver/linux-sh-low.c	2002/02/14 06:21:22	1.1
+++ gdbserver/linux-sh-low.c	2002/02/27 06:23:43
@@ -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: gdbserver/regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/regcache.c,v
retrieving revision 1.1
diff -u -p -r1.1 regcache.c
--- gdbserver/regcache.c	2002/02/14 06:21:22	1.1
+++ gdbserver/regcache.c	2002/02/27 06:23:43
@@ -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);
+}


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