Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA]: x86_64 target - multiarch
@ 2001-09-05  7:02 Jiri Smid
  2001-09-05  7:38 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Jiri Smid @ 2001-09-05  7:02 UTC (permalink / raw)
  To: gdb-patches

  Hello,

  Here is x86_64 target files turned to multiarch.

Index: ChangeLog
from  Jiri Smid <smid@suse.cz>

	* configure.tgt: Recognize x86_64-*-linux* as a x86_64linux.
	* configure.host: Recognize x86_64-*-linux* as a x86_64linux.
	* NEWS: New target x86-64.
	* config/i386/x86_64linux.mh: New file.
	* config/i386/x86_64linux.mt: New file.
	* config/i386/nm-x86_64.h: New file.
	* x86_64-linux-tdep.c: New file.
	* x86_64-linux-nat.c: New file.
	* x86_64-nat.c: New file.
	* x86_64-tdep.c: New file.
	* x86_64-tdep.h: New file.
	* i386-tdep.h: New file.
	* i387-nat.c: Include i386-tdep.h when multiarch.
	* i387-tdep.c: Ditto.
	* config/djgpp/fnchange.lst: Add entries for x86_64-linux-tdep.c
	and x86_64-linux-nat.c
	* Makefile.in: Add x86_64-linux-tdep.o, x86_64-tdep.o,
	x86_64-linux-tdep.o, x86_64-nat.o, update dependencies.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.114
diff -c -3 -p -r1.114 Makefile.in
*************** i386-linux-tdep.o: i386-linux-tdep.c $(d
*** 1552,1558 ****
  i386v4-nat.o: i386v4-nat.c $(defs_h) $(regcache_h)
  
  i387-tdep.o: i387-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \
! 	$(inferior_h) language.h $(regcache_h) $(doublest_h)
  
  i960-tdep.o: i960-tdep.c $(floatformat_h) $(defs_h) $(expression_h) \
  	$(frame_h) $(gdbtypes_h) $(symtab_h) $(value_h) $(gdbcore_h) \
--- 1556,1562 ----
  i386v4-nat.o: i386v4-nat.c $(defs_h) $(regcache_h)
  
  i387-tdep.o: i387-tdep.c $(floatformat_h) $(defs_h) $(gdbcore_h) \
! 	$(inferior_h) language.h $(regcache_h) $(doublest_h) i386-tdep.h
  
  i960-tdep.o: i960-tdep.c $(floatformat_h) $(defs_h) $(expression_h) \
  	$(frame_h) $(gdbtypes_h) $(symtab_h) $(value_h) $(gdbcore_h) \
*************** values.o: values.c $(defs_h) $(expressio
*** 2075,2080 ****
--- 2079,2096 ----
  vax-tdep.o: vax-tdep.c $(OP_INCLUDE)/vax.h $(defs_h) $(symtab_h)
  
  w65-tdep.o : w65-tdep.c $(gdbcore_h) $(regcache_h)
+ 
+ x86_64-linux-tdep.o : x86_64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
+ 	$(regcache_h) x86_64-tdep.h i386-tdep.h $(dwarw2cfi_h)
+ 
+ x86_64-tdep.o : x86_64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) $(gdbcmd_h) \
+ 	$(arch_utils_h) $(regcache_h) $(symfile_h) x86_64-tdep.h i386-tdep.h \
+ 	$(dwarf2cfi_h)
+ 
+ x86_64-linux-tdep.o : x86_64-linux-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \
+ 	$(regcache_h) i387-nat.h x86_64-tdep.h i386-tdep.h
+ 
+ x86_64-nat.o : x86_64-nat.c $(defs_h) x86_64-tdep.h i386-tdep.h
  
  win32-nat.o: win32-nat.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) \
  	$(gdb_string_h) $(regcache_h) $(completer_h)
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.32
diff -c -3 -p -r1.32 NEWS
*** NEWS	2001/08/02 18:42:18	1.32
--- NEWS	2001/09/05 12:06:19
*************** ia64 AIX					ia64-*-aix*
*** 16,21 ****
--- 16,22 ----
  Motorola 68HC11 and 68HC12			m68hc11-elf
  CRIS						cris-axis
  UltraSparc running Linux			sparc64-*-linux*
+ Amd x86-64 running Linux			x86_64-*-linux-*
  
  * OBSOLETE configurations and files
  
Index: configure.host
===================================================================
RCS file: /cvs/src/src/gdb/configure.host,v
retrieving revision 1.23
diff -c -3 -p -r1.23 configure.host
*** configure.host	2001/07/10 20:41:54	1.23
--- configure.host	2001/09/05 12:06:19
*************** mips*)			gdb_host_cpu=mips ;;
*** 20,25 ****
--- 20,26 ----
  powerpc*)		gdb_host_cpu=powerpc ;;
  sparc64)		gdb_host_cpu=sparc ;;
  s390*)			gdb_host_cpu=s390 ;;
+ x86_64*)		gdb_host_cpu=i386 ;;
  *)			gdb_host_cpu=$host_cpu ;;
  
  esac
*************** xscale-*-*)		gdb_host=arm ;;
*** 162,166 ****
--- 163,169 ----
  vax-*-bsd*)		gdb_host=vaxbsd ;;
  vax-*-ultrix2*)		gdb_host=vaxult2 ;;
  vax-*-ultrix*)		gdb_host=vaxult ;;
+ 
+ x86_64-*-linux*)	gdb_host=x86_64linux ;;
  
  esac
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.35
diff -c -3 -p -r1.35 configure.tgt
*** configure.tgt	2001/08/12 03:39:11	1.35
--- configure.tgt	2001/09/05 12:06:19
*************** s390*)			gdb_target_cpu=s390 ;;
*** 27,32 ****
--- 27,33 ----
  strongarm*)		gdb_target_cpu=arm ;;
  xscale*)		gdb_target_cpu=arm ;;
  v850*)			gdb_target_cpu=v850 ;;
+ x86_64*)		gdb_target_cpu=i386 ;;
  *)			gdb_target_cpu=$target_cpu ;;
  
  esac
*************** v850*-*-*)		gdb_target=v850
*** 313,318 ****
--- 314,322 ----
  
  # OBSOLETE w65-*-*)		gdb_target=w65 ;;
  
+ x86_64-*-linux*)	gdb_target=x86_64linux
+  		configdirs="${configdirs} gdbserver" ;;
+ 
  z8k-*-coff*)		gdb_target=z8k ;;
  
  esac
*************** cris)		gdb_multi_arch=yes ;;
*** 325,328 ****
--- 329,333 ----
  d10v)		gdb_multi_arch=yes ;;
  m68hc11)	gdb_multi_arch=yes ;;
  mn10300)	gdb_multi_arch=yes ;;
+ x86_64linux)    gdb_multi_arch=yes ;;
  esac
Index: i386-tdep.h
===================================================================
RCS file: i386-tdep.h
diff -N i386-tdep.h
*** /dev/null	Tue May  5 13:32:27 1998
--- i386-tdep.h	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,77 ----
+ /* Target-dependent code for GDB, the GNU debugger.
+    Copyright 2001
+    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 I386_TDEP_H
+ #define I386_TDEP_H
+ 
+ #define FPU_REG_RAW_SIZE 10
+ 
+ #define XMM0_REGNUM FIRST_XMM_REGNUM
+ #define FIRST_FPU_REGNUM FP0_REGNUM
+ #define LAST_FPU_REGNUM (gdbarch_tdep (current_gdbarch)->last_fpu_regnum)
+ #define FIRST_XMM_REGNUM (gdbarch_tdep (current_gdbarch)->first_xmm_regnum)
+ #define LAST_XMM_REGNUM (gdbarch_tdep (current_gdbarch)->last_xmm_regnum)
+ #define FIRST_FPU_CTRL_REGNUM (gdbarch_tdep (current_gdbarch)->first_fpu_ctrl_regnum)
+ #define LAST_FPU_CTRL_REGNUM (gdbarch_tdep (current_gdbarch)->last_fpu_ctrl_regnum)
+ #define MXCSR_REGNUM (gdbarch_tdep (current_gdbarch)->mxcsr_regnum)
+ #define FCTRL_REGNUM (gdbarch_tdep (current_gdbarch)->fctrl_regnum)
+ #define FSTAT_REGNUM (gdbarch_tdep (current_gdbarch)->fstat_regnum)
+ #define FTAG_REGNUM (gdbarch_tdep (current_gdbarch)->ftag_regnum)
+ #define FCS_REGNUM (gdbarch_tdep (current_gdbarch)->fcs_regnum)
+ #define FCOFF_REGNUM (gdbarch_tdep (current_gdbarch)->fcoff_regnum)
+ #define FDS_REGNUM (gdbarch_tdep (current_gdbarch)->fds_regnum)
+ #define FDOFF_REGNUM (gdbarch_tdep (current_gdbarch)->fdoff_regnum)
+ #define FOP_REGNUM (gdbarch_tdep (current_gdbarch)->fop_regnum)
+ 
+ 
+ /* i386 architecture specific information.  */
+ struct gdbarch_tdep
+ {
+   int mxcsr_regnum;		/* Streaming SIMD Extension control/status.  */
+ 
+   int last_fpu_regnum;
+   int first_xmm_regnum;
+   int last_xmm_regnum;
+   int first_fpu_ctrl_regnum;
+   int last_fpu_ctrl_regnum;
+   /* All of these control registers (except for FCOFF and FDOFF) are
+      sixteen bits long (at most) in the FPU, but are zero-extended to
+      thirty-two bits in GDB's register file.  This makes it easier to
+      compute the size of the control register file, and somewhat easier
+      to convert to and from the FSAVE instruction's 32-bit format.  */
+   int fctrl_regnum;		/* FPU control word.  */
+   int fstat_regnum;		/* FPU status word.  */
+   int ftag_regnum;		/* FPU register tag word.  */
+   int fcs_regnum;		/* FPU instruction's code segment selector
+ 				   16 bits, called "FPU Instruction Pointer
+ 				   Selector" in the x86 manuals.  */
+   int fcoff_regnum;		/* FPU instruction's offset within segment
+ 				   ("Fpu Code OFFset").  */
+   int fds_regnum;		/* FPU operand's data segment.  */
+   int fdoff_regnum;		/* FPU operand's offset within segment.  */
+   int fop_regnum;		/* FPU opcode, bottom eleven bits.  */
+ };
+ 
+ #define IS_FP_REGNUM(n) (FIRST_FPU_REGNUM <= (n) && (n) <= LAST_FPU_REGNUM)
+ #define IS_FPU_CTRL_REGNUM(n) (FIRST_FPU_CTRL_REGNUM <= (n) && (n) <= LAST_FPU_CTRL_REGNUM)
+ #define IS_SSE_REGNUM(n) (FIRST_XMM_REGNUM <= (n) && (n) <= LAST_XMM_REGNUM)
+ 
+ #endif
Index: i387-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i387-nat.c,v
retrieving revision 1.5
diff -c -3 -p -r1.5 i387-nat.c
*** i387-nat.c	2001/04/27 16:06:53	1.5
--- i387-nat.c	2001/09/05 12:06:20
***************
*** 25,30 ****
--- 25,34 ----
  
  #include "i387-nat.h"
  
+ #if GDB_MULTI_ARCH > 0
+ #include "i386-tdep.h"
+ #endif
+ 
  /* FIXME: kettenis/2000-05-21: Right now more than a few i386 targets
     define their own routines to manage the floating-point registers in
     GDB's register array.  Most (if not all) of these targets use the
Index: i387-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i387-tdep.c,v
retrieving revision 1.13
diff -c -3 -p -r1.13 i387-tdep.c
*** i387-tdep.c	2001/08/01 18:39:23	1.13
--- i387-tdep.c	2001/09/05 12:06:20
***************
*** 30,35 ****
--- 30,38 ----
  #include "gdb_assert.h"
  #include "doublest.h"
  
+ #if GDB_MULTI_ARCH >0
+ #include "i386-tdep.h"
+ #endif
  
  /* FIXME: Eliminate the next two functions when we have the time to
     change all the callers.  */
Index: x86_64-linux-nat.c
===================================================================
RCS file: x86_64-linux-nat.c
diff -N x86_64-linux-nat.c
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64-linux-nat.c	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,910 ----
+ /* Native-dependent code for Linux/x86-64.
+    Copyright 1999, 2000, 2001 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 "defs.h"
+ #include "inferior.h"
+ #include "gdbcore.h"
+ #include "regcache.h"
+ #include "i387-nat.h"
+ #include "x86_64-tdep.h"
+ 
+ #include <sys/ptrace.h>
+ #include <asm/debugreg.h>
+ #include <asm/unistd.h>
+ #include <sys/procfs.h>
+ 
+ /* The register sets used in Linux ELF core-dumps are identical to the
+    register sets in `struct user' that is used for a.out core-dumps,
+    and is also used by `ptrace'.  The corresponding types are
+    `elf_gregset_t' for the general-purpose registers (with
+    `elf_greg_t' the type of a single GP register) and `elf_fpregset_t'
+    for the floating-point registers.
+ 
+    Those types used to be available under the names `gregset_t' and
+    `fpregset_t' too, and this file used those names in the past.  But
+    those names are now used for the register sets used in the
+    `mcontext_t' type, and have a different size and layout.  */
+ 
+ /* Which ptrace request retrieves which registers?
+    These apply to the corresponding SET requests as well.  */
+ #define GETREGS_SUPPLIES(regno) \
+   (0 <= (regno) && (regno) <= 17)
+ #define GETFPREGS_SUPPLIES(regno) \
+   (FP0_REGNUM <= (regno) && (regno) <= MXCSR_REGNUM)
+ 
+ /* Does the current host support the GETREGS request?  */
+ int have_ptrace_getregs =
+ #ifdef HAVE_PTRACE_GETREGS
+   1
+ #else
+   0
+ #endif
+  ;
+ \f
+ 
+ 
+ /* Fetching registers directly from the U area, one at a time.  */
+ 
+ /* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'.
+    The problem is that we define FETCH_INFERIOR_REGISTERS since we
+    want to use our own versions of {fetch,store}_inferior_registers
+    that use the GETREGS request.  This means that the code in
+    `infptrace.c' is #ifdef'd out.  But we need to fall back on that
+    code when GDB is running on top of a kernel that doesn't support
+    the GETREGS request.  I want to avoid changing `infptrace.c' right
+    now.  */
+ 
+ #ifndef PT_READ_U
+ #define PT_READ_U PTRACE_PEEKUSR
+ #endif
+ #ifndef PT_WRITE_U
+ #define PT_WRITE_U PTRACE_POKEUSR
+ #endif
+ 
+ /* Default the type of the ptrace transfer to int.  */
+ #ifndef PTRACE_XFER_TYPE
+ #define PTRACE_XFER_TYPE unsigned long
+ #endif
+ 
+ /* Registers we shouldn't try to fetch.  */
+ #define OLD_CANNOT_FETCH_REGISTER(regno) ((regno) >= X86_64_NUM_GREGS)
+ 
+ /* Fetch one register.  */
+ 
+ static void
+ fetch_register (int regno)
+ {
+   /* This isn't really an address.  But ptrace thinks of it as one.  */
+   CORE_ADDR regaddr;
+   char mess[128];		/* For messages */
+   register int i;
+   unsigned int offset;		/* Offset of registers within the u area.  */
+   char buf[MAX_REGISTER_RAW_SIZE];
+   int tid;
+ 
+   if (OLD_CANNOT_FETCH_REGISTER (regno))
+     {
+       memset (buf, '\0', REGISTER_RAW_SIZE (regno));	/* Supply zeroes */
+       supply_register (regno, buf);
+       return;
+     }
+ 
+   /* Overload thread id onto process id */
+   if ((tid = TIDGET (inferior_ptid)) == 0)
+     tid = PIDGET (inferior_ptid);	/* no thread id, just use process id */
+ 
+   offset = U_REGS_OFFSET;
+ 
+   regaddr = register_addr (regno, offset);
+   for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+     {
+       errno = 0;
+       ptrace (PT_READ_U, tid, (PTRACE_ARG3_TYPE) regaddr,
+ 	      ((PTRACE_XFER_TYPE *) buf) + i);
+       regaddr += sizeof (PTRACE_XFER_TYPE);
+       if (errno != 0)
+ 	{
+ 	  sprintf (mess, "reading register %s (#%d)",
+ 		   REGISTER_NAME (regno), regno);
+ 	  perror_with_name (mess);
+ 	}
+     }
+   supply_register (regno, buf);
+ }
+ 
+ /* Fetch register values from the inferior.
+    If REGNO is negative, do this for all registers.
+    Otherwise, REGNO specifies which register (so we can save time). */
+ 
+ void
+ old_fetch_inferior_registers (int regno)
+ {
+   if (regno >= 0)
+     {
+       fetch_register (regno);
+     }
+   else
+     {
+       for (regno = 0; regno < X86_64_NUM_REGS; regno++)
+ 	{
+ 	  fetch_register (regno);
+ 	}
+     }
+ }
+ 
+ /* Registers we shouldn't try to store.  */
+ #define OLD_CANNOT_STORE_REGISTER(regno) ((regno) >= X86_64_NUM_GREGS)
+ 
+ /* Store one register. */
+ 
+ static void
+ store_register (int regno)
+ {
+   /* This isn't really an address.  But ptrace thinks of it as one.  */
+   CORE_ADDR regaddr;
+   char mess[128];		/* For messages */
+   register int i;
+   unsigned int offset;		/* Offset of registers within the u area.  */
+   int tid;
+ 
+   if (OLD_CANNOT_STORE_REGISTER (regno))
+     {
+       return;
+     }
+ 
+   /* Overload thread id onto process id */
+   if ((tid = TIDGET (inferior_ptid)) == 0)
+     tid = PIDGET (inferior_ptid);	/* no thread id, just use process id */
+ 
+   offset = U_REGS_OFFSET;
+ 
+   regaddr = register_addr (regno, offset);
+   for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
+     {
+       errno = 0;
+       ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
+ 	      *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i]);
+       regaddr += sizeof (PTRACE_XFER_TYPE);
+       if (errno != 0)
+ 	{
+ 	  sprintf (mess, "writing register %s (#%d)",
+ 		   REGISTER_NAME (regno), regno);
+ 	  perror_with_name (mess);
+ 	}
+     }
+ }
+ 
+ /* Store our register values back into the inferior.
+    If REGNO is negative, do this for all registers.
+    Otherwise, REGNO specifies which register (so we can save time).  */
+ 
+ void
+ old_store_inferior_registers (int regno)
+ {
+   if (regno >= 0)
+     {
+       store_register (regno);
+     }
+   else
+     {
+       for (regno = 0; regno < X86_64_NUM_REGS; regno++)
+ 	{
+ 	  store_register (regno);
+ 	}
+     }
+ }
+ \f
+ 
+ /* Transfering the general-purpose registers between GDB, inferiors
+    and core files.  */
+ 
+ /* Fill GDB's register array with the general-purpose register values
+    in *GREGSETP.  */
+ 
+ void
+ supply_gregset (elf_gregset_t * gregsetp)
+ {
+   elf_greg_t *regp = (elf_greg_t *) gregsetp;
+   int i;
+ 
+   for (i = 0; i < X86_64_NUM_GREGS; i++)
+     supply_register (i, (char *) (regp + x86_64_regmap[i]));
+ }
+ 
+ /* Fill register REGNO (if it is a general-purpose register) in
+    *GREGSETPS with the value in GDB's register array.  If REGNO is -1,
+    do this for all registers.  */
+ 
+ void
+ fill_gregset (elf_gregset_t * gregsetp, int regno)
+ {
+   elf_greg_t *regp = (elf_greg_t *) gregsetp;
+   int i;
+ 
+   for (i = 0; i < X86_64_NUM_GREGS; i++)
+     if ((regno == -1 || regno == i))
+       *(regp + x86_64_regmap[i]) =
+ 	*(elf_greg_t *) & registers[REGISTER_BYTE (i)];
+ }
+ 
+ #ifdef HAVE_PTRACE_GETREGS
+ 
+ /* Fetch all general-purpose registers from process/thread TID and
+    store their values in GDB's register array.  */
+ 
+ static void
+ fetch_regs (int tid)
+ {
+   elf_gregset_t regs;
+ 
+   if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+     {
+       if (errno == EIO)
+ 	{
+ 	  /* The kernel we're running on doesn't support the GETREGS
+ 	     request.  Reset `have_ptrace_getregs'.  */
+ 	  have_ptrace_getregs = 0;
+ 	  return;
+ 	}
+ 
+       perror_with_name ("Couldn't get registers");
+     }
+ 
+   supply_gregset (&regs);
+ }
+ 
+ /* Store all valid general-purpose registers in GDB's register array
+    into the process/thread specified by TID.  */
+ 
+ static void
+ store_regs (int tid, int regno)
+ {
+   elf_gregset_t regs;
+ 
+   if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+     perror_with_name ("Couldn't get registers");
+ 
+   fill_gregset (&regs, regno);
+ 
+   if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
+     perror_with_name ("Couldn't write registers");
+ }
+ 
+ #else
+ 
+ static void
+ fetch_regs (int tid)
+ {
+ }
+ static void
+ store_regs (int tid, int regno)
+ {
+ }
+ 
+ #endif
+ \f
+ 
+ /* Transfering floating-point registers between GDB, inferiors and cores.  */
+ 
+ /* Fill GDB's register array with the floating-point register values in
+    *FPREGSETP.  */
+ 
+ void
+ supply_fpregset (elf_fpregset_t * fpregsetp)
+ {
+   i387_supply_fxsave ((char *) fpregsetp);
+ }
+ 
+ /* Fill register REGNO (if it is a floating-point register) in
+    *FPREGSETP with the value in GDB's register array.  If REGNO is -1,
+    do this for all registers.  */
+ 
+ void
+ fill_fpregset (elf_fpregset_t * fpregsetp, int regno)
+ {
+   i387_fill_fxsave ((char *) fpregsetp, regno);
+ }
+ 
+ #ifdef HAVE_PTRACE_GETREGS
+ 
+ /* Fetch all floating-point registers from process/thread TID and store
+    thier values in GDB's register array.  */
+ 
+ static void
+ fetch_fpregs (int tid)
+ {
+   elf_fpregset_t fpregs;
+ 
+   if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+     perror_with_name ("Couldn't get floating point status");
+ 
+   supply_fpregset (&fpregs);
+ }
+ 
+ /* Store all valid floating-point registers in GDB's register array
+    into the process/thread specified by TID.  */
+ 
+ static void
+ store_fpregs (int tid, int regno)
+ {
+   elf_fpregset_t fpregs;
+ 
+   if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+     perror_with_name ("Couldn't get floating point status");
+ 
+   fill_fpregset (&fpregs, regno);
+ 
+   if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
+     perror_with_name ("Couldn't write floating point status");
+ }
+ 
+ #else
+ 
+ static void
+ fetch_fpregs (int tid)
+ {
+ }
+ static void
+ store_fpregs (int tid, int regno)
+ {
+ }
+ 
+ #endif
+ \f
+ 
+ /* Transferring arbitrary registers between GDB and inferior.  */
+ 
+ /* Check if register REGNO in the child process is accessible.
+    If we are accessing registers directly via the U area, only the
+    general-purpose registers are available.
+    All registers should be accessible if we have GETREGS support.  */
+ 
+ int
+ cannot_fetch_register (int regno)
+ {
+   if (!have_ptrace_getregs)
+     return OLD_CANNOT_FETCH_REGISTER (regno);
+   return 0;
+ }
+ 
+ int
+ cannot_store_register (int regno)
+ {
+   if (!have_ptrace_getregs)
+     return OLD_CANNOT_STORE_REGISTER (regno);
+   return 0;
+ }
+ 
+ /* Fetch register REGNO from the child process.  If REGNO is -1, do
+    this for all registers (including the floating point and SSE
+    registers).  */
+ 
+ void
+ fetch_inferior_registers (int regno)
+ {
+   int tid;
+ 
+   /* Use the old method of peeking around in `struct user' if the
+      GETREGS request isn't available.  */
+   if (!have_ptrace_getregs)
+     {
+       old_fetch_inferior_registers (regno);
+       return;
+     }
+ 
+   /* Linux LWP ID's are process ID's.  */
+   if ((tid = TIDGET (inferior_ptid)) == 0)
+     tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
+ 
+   if (regno == -1)
+     {
+       fetch_regs (tid);
+ 
+       /* The call above might reset `have_ptrace_getregs'.  */
+       if (!have_ptrace_getregs)
+ 	{
+ 	  old_fetch_inferior_registers (-1);
+ 	  return;
+ 	}
+ 
+       fetch_fpregs (tid);
+       return;
+     }
+ 
+   if (GETREGS_SUPPLIES (regno))
+     {
+       fetch_regs (tid);
+       return;
+     }
+ 
+   if (GETFPREGS_SUPPLIES (regno))
+     {
+       fetch_fpregs (tid);
+       return;
+     }
+ 
+   internal_error (__FILE__, __LINE__,
+ 		  "Got request for bad register number %d.", regno);
+ }
+ 
+ /* Store register REGNO back into the child process.  If REGNO is -1,
+    do this for all registers (including the floating point and SSE
+    registers).  */
+ void
+ store_inferior_registers (int regno)
+ {
+   int tid;
+ 
+   /* Use the old method of poking around in `struct user' if the
+      SETREGS request isn't available.  */
+   if (!have_ptrace_getregs)
+     {
+       old_store_inferior_registers (regno);
+       return;
+     }
+ 
+   /* Linux LWP ID's are process ID's.  */
+   if ((tid = TIDGET (inferior_ptid)) == 0)
+     tid = PIDGET (inferior_ptid);	/* Not a threaded program.  */
+ 
+   /* Use the PTRACE_SETFPXREGS requests whenever possible, since it
+      transfers more registers in one system call.  But remember that
+      store_fpxregs can fail, and return zero.  */
+   if (regno == -1)
+     {
+       store_regs (tid, regno);
+       store_fpregs (tid, regno);
+       return;
+     }
+ 
+   if (GETREGS_SUPPLIES (regno))
+     {
+       store_regs (tid, regno);
+       return;
+     }
+ 
+   if (GETFPREGS_SUPPLIES (regno))
+     {
+       store_fpregs (tid, regno);
+       return;
+     }
+ 
+   internal_error (__FILE__, __LINE__,
+ 		  "Got request to store bad register number %d.", regno);
+ }
+ \f
+ 
+ static const unsigned char linux_syscall[] = { 0x0f, 0x05 };
+ 
+ #define LINUX_SYSCALL_LEN (sizeof linux_syscall)
+ 
+ /* The system call number is stored in the %rax register.  */
+ #define LINUX_SYSCALL_REGNUM 0	/* %rax */
+ 
+ /* We are specifically interested in the sigreturn and rt_sigreturn
+    system calls.  */
+ 
+ #ifndef SYS_sigreturn
+ #define SYS_sigreturn		__NR_sigreturn
+ #endif
+ #ifndef SYS_rt_sigreturn
+ #define SYS_rt_sigreturn	__NR_rt_sigreturn
+ #endif
+ 
+ /* Offset to saved processor flags, from <asm/sigcontext.h>.  */
+ #define LINUX_SIGCONTEXT_EFLAGS_OFFSET (152)
+ /* Offset to saved processor registers from <asm/ucontext.h> */
+ #define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36)
+ 
+ /* Resume execution of the inferior process.
+    If STEP is nonzero, single-step it.
+    If SIGNAL is nonzero, give it that signal.  */
+ 
+ void
+ child_resume (ptid_t ptid, int step, enum target_signal signal)
+ {
+   int pid = PIDGET (ptid);
+   int request = PTRACE_CONT;
+ 
+   if (pid == -1)
+     /* Resume all threads.  */
+     /* I think this only gets used in the non-threaded case, where "resume
+        all threads" and "resume inferior_ptid" are the same.  */
+     pid = PIDGET (inferior_ptid);
+ 
+   if (step)
+     {
+       CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid));
+       unsigned char buf[LINUX_SYSCALL_LEN];
+ 
+       request = PTRACE_SINGLESTEP;
+ 
+       /* Returning from a signal trampoline is done by calling a
+          special system call (sigreturn or rt_sigreturn, see
+          i386-linux-tdep.c for more information).  This system call
+          restores the registers that were saved when the signal was
+          raised, including %eflags.  That means that single-stepping
+          won't work.  Instead, we'll have to modify the signal context
+          that's about to be restored, and set the trace flag there.  */
+ 
+       /* First check if PC is at a system call.  */
+       if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0
+ 	  && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
+ 	{
+ 	  int syscall =
+ 	    read_register_pid (LINUX_SYSCALL_REGNUM, pid_to_ptid (pid));
+ 
+ 	  /* Then check the system call number.  */
+ 	  if (syscall == SYS_rt_sigreturn)
+ 	    {
+ 	      CORE_ADDR sp = read_register (SP_REGNUM);
+ 	      CORE_ADDR addr = sp;
+ 	      unsigned long int eflags;
+ 
+ 	      addr +=
+ 		sizeof (struct siginfo) + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+ 
+ 	      /* Set the trace flag in the context that's about to be
+ 	         restored.  */
+ 	      addr += LINUX_SIGCONTEXT_EFLAGS_OFFSET;
+ 	      read_memory (addr, (char *) &eflags, 8);
+ 	      eflags |= 0x0100;
+ 	      write_memory (addr, (char *) &eflags, 8);
+ 	    }
+ 	}
+     }
+ 
+   if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1)
+     perror_with_name ("ptrace");
+ }
+ \f
+ 
+ /* Copy LEN bytes to or from inferior's memory starting at MEMADDR
+    to debugger memory starting at MYADDR.   Copy to inferior if
+    WRITE is nonzero.  TARGET is ignored.
+ 
+    Returns the length copied, which is either the LEN argument or zero.
+    This xfer function does not do partial moves, since child_ops
+    doesn't allow memory operations to cross below us in the target stack
+    anyway.  */
+ 
+ int
+ child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+ 		   struct mem_attrib *attrib ATTRIBUTE_UNUSED,
+ 		   struct target_ops *target)
+ {
+   register int i;
+   /* Round starting address down to longword boundary.  */
+   register CORE_ADDR addr = memaddr & -sizeof (PTRACE_XFER_TYPE);
+   /* Round ending address up; get number of longwords that makes.  */
+   register int count
+     = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+     / sizeof (PTRACE_XFER_TYPE);
+   /* Allocate buffer of that many longwords.  */
+   register PTRACE_XFER_TYPE *buffer
+     = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+ 
+   if (write)
+     {
+       /* Fill start and end extra bytes of buffer with existing memory data.  */
+       if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE))
+ 	{
+ 	  /* Need part of initial word -- fetch it.  */
+ 	  ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ 		  (PTRACE_ARG3_TYPE) addr, buffer);
+ 	}
+ 
+       if (count > 1)		/* FIXME, avoid if even boundary */
+ 	{
+ 	  ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ 		  ((PTRACE_ARG3_TYPE)
+ 		   (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))),
+ 		  buffer + count - 1);
+ 	}
+ 
+       /* Copy data to be written over corresponding part of buffer */
+ 
+       memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ 	      myaddr, len);
+ 
+       /* Write the entire buffer.  */
+ 
+       for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ 	{
+ 	  errno = 0;
+ 	  ptrace (PT_WRITE_D, PIDGET (inferior_ptid),
+ 		  (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ 	  if (errno)
+ 	    {
+ 	      /* Using the appropriate one (I or D) is necessary for
+ 	         Gould NP1, at least.  */
+ 	      errno = 0;
+ 	      ptrace (PT_WRITE_I, PIDGET (inferior_ptid),
+ 		      (PTRACE_ARG3_TYPE) addr, buffer[i]);
+ 	    }
+ 	  if (errno)
+ 	    return 0;
+ 	}
+ #ifdef CLEAR_INSN_CACHE
+       CLEAR_INSN_CACHE ();
+ #endif
+     }
+   else
+     {
+       /* Read all the longwords */
+       for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
+ 	{
+ 	  errno = 0;
+ 	  ptrace (PT_READ_I, PIDGET (inferior_ptid),
+ 		  (PTRACE_ARG3_TYPE) addr, buffer + i);
+ 	  if (errno)
+ 	    return 0;
+ 	}
+ 
+       /* Copy appropriate bytes out of the buffer.  */
+       memcpy (myaddr,
+ 	      (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)),
+ 	      len);
+     }
+   return len;
+ }
+ 
+ /* Interpreting register set info found in core files.  */
+ 
+ /* Provide registers to GDB from a core file.
+ 
+    CORE_REG_SECT points to an array of bytes, which are the contents
+    of a `note' from a core file which BFD thinks might contain
+    register contents.  CORE_REG_SIZE is its size.
+ 
+    WHICH says which register set corelow suspects this is:
+      0 --- the general-purpose register set, in elf_gregset_t format
+      2 --- the floating-point register set, in elf_fpregset_t format
+ 
+    REG_ADDR isn't used on Linux.  */
+ 
+ static void
+ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+ 		      int which, CORE_ADDR reg_addr)
+ {
+   elf_gregset_t gregset;
+   elf_fpregset_t fpregset;
+   switch (which)
+     {
+     case 0:
+       if (core_reg_size != sizeof (gregset))
+ 	warning ("Wrong size gregset in core file.");
+       else
+ 	{
+ 	  memcpy (&gregset, core_reg_sect, sizeof (gregset));
+ 	  supply_gregset (&gregset);
+ 	}
+       break;
+ 
+     case 2:
+       if (core_reg_size != sizeof (fpregset))
+ 	warning ("Wrong size fpregset in core file.");
+       else
+ 	{
+ 	  memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
+ 	  supply_fpregset (&fpregset);
+ 	}
+       break;
+ 
+     default:
+       /* We've covered all the kinds of registers we know about here,
+          so this must be something we wouldn't know what to do with
+          anyway.  Just ignore it.  */
+       break;
+     }
+ }
+ 
+ /* Register that we are able to handle Linux ELF core file formats.  */
+ 
+ static struct core_fns linux_elf_core_fns = {
+   bfd_target_elf_flavour,	/* core_flavour */
+   default_check_format,		/* check_format */
+   default_core_sniffer,		/* core_sniffer */
+   fetch_core_registers,		/* core_read_registers */
+   NULL				/* next */
+ };
+ 
+ #if !defined (offsetof)
+ #define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
+ #endif
+ 
+ /* Record the value of the debug control register.  */
+ static long debug_control_mirror;
+ 
+ /* Record which address associates with which register.  */
+ static CORE_ADDR address_lookup[DR_LASTADDR - DR_FIRSTADDR + 1];
+ 
+ static int
+ x86_64_insert_aligned_watchpoint (ptid_t, CORE_ADDR, CORE_ADDR, int, int);
+ 
+ static int
+ x86_64_insert_nonaligned_watchpoint (ptid_t, CORE_ADDR, CORE_ADDR, int, int);
+ 
+ /* Insert a watchpoint.  */
+ 
+ int
+ x86_64_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+ {
+   return x86_64_insert_aligned_watchpoint (ptid, addr, addr, len, rw);
+ }
+ 
+ static int
+ x86_64_insert_aligned_watchpoint (ptid_t ptid, CORE_ADDR waddr,
+ 				  CORE_ADDR addr, int len, int rw)
+ {
+   int i;
+   int read_write_bits, len_bits;
+   int free_debug_register;
+   int register_number;
+ 
+   /* Look for a free debug register.  */
+   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+     {
+       if (address_lookup[i - DR_FIRSTADDR] == 0)
+ 	break;
+     }
+ 
+   /* No more debug registers!  */
+   if (i > DR_LASTADDR)
+     return -1;
+ 
+   read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
+ 
+   if (len == 1)
+     len_bits = DR_LEN_1;
+   else if (len == 2)
+     {
+       if (addr % 2)
+ 	return x86_64_insert_nonaligned_watchpoint (ptid, waddr, addr, len,
+ 						    rw);
+       len_bits = DR_LEN_2;
+     }
+   else if (len == 4)
+     {
+       if (addr % 4)
+ 	return x86_64_insert_nonaligned_watchpoint (ptid, waddr, addr, len,
+ 						    rw);
+       len_bits = DR_LEN_4;
+     }
+   else if (len == 8)
+     {
+       if (addr % 8)
+ 	return x86_64_insert_nonaligned_watchpoint (ptid, waddr, addr, len,
+ 						    rw);
+       len_bits = DR_LEN_8;
+     }
+   else
+     return x86_64_insert_nonaligned_watchpoint (ptid, waddr, addr, len, rw);
+ 
+   free_debug_register = i;
+   register_number = free_debug_register - DR_FIRSTADDR;
+   debug_control_mirror |=
+     ((read_write_bits | len_bits)
+      << (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * register_number));
+   debug_control_mirror |=
+     (1 << (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
+   debug_control_mirror |= DR_LOCAL_SLOWDOWN;
+   debug_control_mirror &= ~DR_CONTROL_RESERVED;
+ 
+   ptrace (6, PIDGET (ptid), offsetof (struct user, u_debugreg[DR_CONTROL]),
+ 	  debug_control_mirror);
+   ptrace (6, PIDGET (ptid),
+ 	  offsetof (struct user, u_debugreg[free_debug_register]), addr);
+ 
+   /* Record where we came from.  */
+   address_lookup[register_number] = addr;
+   return 0;
+ }
+ 
+ static int
+ x86_64_insert_nonaligned_watchpoint (ptid_t ptid, CORE_ADDR waddr,
+ 				     CORE_ADDR addr, int len, int rw)
+ {
+   int align;
+   int size;
+   int rv;
+ 
+   static int size_try_array[8][8] = {
+     {1, 1, 1, 1, 1, 1, 1, 1},	/* trying size one */
+     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size two */
+     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size three */
+     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size four */
+     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size five */
+     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size six */
+     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size seven */
+     {8, 1, 2, 1, 4, 1, 2, 1},	/* trying size eight */
+   };
+ 
+   rv = 0;
+   while (len > 0)
+     {
+       align = addr % 8;
+       /* Eight is the maximum length for x86-64.  */
+       size = size_try_array[len > 8 ? 7 : len - 1][align];
+ 
+       rv = x86_64_insert_aligned_watchpoint (ptid, waddr, addr, size, rw);
+       if (rv)
+ 	{
+ 	  x86_64_remove_watchpoint (ptid, waddr, size);
+ 	  return rv;
+ 	}
+       addr += size;
+       len -= size;
+     }
+   return rv;
+ }
+ 
+ /* Remove a watchpoint.  */
+ 
+ int
+ x86_64_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+ {
+   int i;
+   int register_number;
+ 
+   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+     {
+       register_number = i - DR_FIRSTADDR;
+       if (address_lookup[register_number] == addr)
+ 	{
+ 	  debug_control_mirror &=
+ 	    ~(1 <<
+ 	      (DR_LOCAL_ENABLE_SHIFT + DR_ENABLE_SIZE * register_number));
+ 	  address_lookup[register_number] = 0;
+ 	}
+     }
+   ptrace (6, PIDGET (ptid), offsetof (struct user, u_debugreg[DR_CONTROL]),
+ 	  debug_control_mirror);
+   ptrace (6, PIDGET (ptid), offsetof (struct user, u_debugreg[DR_STATUS]), 0);
+ 
+   return 0;
+ }
+ 
+ /* Check if stopped by a watchpoint.  */
+ 
+ CORE_ADDR
+ x86_64_stopped_by_watchpoint (ptid_t ptid)
+ {
+   int i;
+   int status;
+ 
+   status =
+     ptrace (3, PIDGET (ptid), offsetof (struct user, u_debugreg[DR_STATUS]),
+ 	    0);
+   ptrace (6, PIDGET (ptid), offsetof (struct user, u_debugreg[DR_STATUS]), 0);
+ 
+   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+     {
+       if (status & (1 << (i - DR_FIRSTADDR)))
+ 	return address_lookup[i - DR_FIRSTADDR];
+     }
+   return 0;
+ }
+ 
+ void
+ _initialize_i386_linux_nat (void)
+ {
+   add_core_fns (&linux_elf_core_fns);
+ }
Index: x86_64-linux-tdep.c
===================================================================
RCS file: x86_64-linux-tdep.c
diff -N x86_64-linux-tdep.c
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64-linux-tdep.c	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,134 ----
+ /* Target-dependent code for Linux running on x86-64, for GDB.
+    Copyright 2001 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 "defs.h"
+ #include "inferior.h"
+ #include "gdbcore.h"
+ #include "regcache.h"
+ #include "x86_64-tdep.h"
+ #include "dwarf2cfi.h"
+ 
+ #define STRUCT_OFFSET(struct_type, member)    \
+     ((long) ((char*) &((struct_type*) 0)->member))
+ 
+ #define LINUX_SIGTRAMP_INSN0 (0x48)	/* mov $NNNNNNNN,%rax */
+ #define LINUX_SIGTRAMP_OFFSET0 (0)
+ #define LINUX_SIGTRAMP_INSN1 (0x0f)	/* syscall */
+ #define LINUX_SIGTRAMP_OFFSET1 (7)
+ 
+ static const unsigned char linux_sigtramp_code[] = {
+   LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x89, 0x00, 0x00, 0x00,	/*  mov $0x89,%rax */
+   LINUX_SIGTRAMP_INSN1, 0x05	/* syscall */
+ };
+ 
+ #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+ 
+ /* If PC is in a sigtramp routine, return the address of the start of
+    the routine.  Otherwise, return 0.  */
+ 
+ static CORE_ADDR
+ x86_64_linux_sigtramp_start (CORE_ADDR pc)
+ {
+   unsigned char buf[LINUX_SIGTRAMP_LEN];
+   if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+     return 0;
+ 
+   if (buf[0] != LINUX_SIGTRAMP_INSN0)
+     {
+       if (buf[0] != LINUX_SIGTRAMP_INSN1)
+ 	return 0;
+ 
+       pc -= LINUX_SIGTRAMP_OFFSET1;
+ 
+       if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ 	return 0;
+     }
+ 
+   if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+     return 0;
+ 
+   return pc;
+ }
+ 
+ /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
+ #define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36)
+ 
+ /* Assuming FRAME is for a Linux sigtramp routine, return the address
+    of the associated sigcontext structure.  */
+ CORE_ADDR
+ x86_64_linux_sigcontext_addr (struct frame_info * frame)
+ {
+   CORE_ADDR pc;
+ 
+   pc = x86_64_linux_sigtramp_start (frame->pc);
+   if (pc)
+     {
+       if (frame->next)
+ 	/* If this isn't the top frame, the next frame must be for the
+ 	   signal handler itself.  The sigcontext structure is part of
+ 	   the user context. */
+ 	return frame->next->frame + sizeof (struct siginfo) +
+ 	  LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+ 
+ 
+       /* This is the top frame. */
+       return read_register (SP_REGNUM) + sizeof (struct siginfo) +
+ 	LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+ 
+     }
+ 
+   error ("Couldn't recognize signal trampoline.");
+   return 0;
+ }
+ 
+ /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
+ #define LINUX_SIGCONTEXT_PC_OFFSET (136)
+ 
+ /* Assuming FRAME is for a Linux sigtramp routine, return the saved
+    program counter.  */
+ 
+ CORE_ADDR
+ x86_64_linux_sigtramp_saved_pc (struct frame_info * frame)
+ {
+   CORE_ADDR addr;
+ 
+   addr = x86_64_linux_sigcontext_addr (frame);
+   return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 8);
+ }
+ 
+ /* Immediately after a function call, return the saved pc.  */
+ 
+ CORE_ADDR
+ x86_64_linux_saved_pc_after_call (struct frame_info * frame)
+ {
+   if (frame->signal_handler_caller)
+     return x86_64_linux_sigtramp_saved_pc (frame);
+ 
+   return read_memory_integer (read_register (SP_REGNUM), 8);
+ }
+ 
+ /* Saved Pc.  Get it from sigcontext if within sigtramp.  */
+ CORE_ADDR
+ x86_64_linux_frame_saved_pc (struct frame_info * frame)
+ {
+   if (frame->signal_handler_caller)
+     return x86_64_linux_sigtramp_saved_pc (frame);
+   return cfi_get_ra (frame);
+ }
Index: x86_64-nat.c
===================================================================
RCS file: x86_64-nat.c
diff -N x86_64-nat.c
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64-nat.c	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,56 ----
+ /* AMD x86_64 native support.
+    Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
+    2000 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 "defs.h"
+ #include <sys/user.h>
+ #include "x86_64-tdep.h"
+ 
+ /* blockend is the value of u.u_ar0, and points to the
+    place where GS is stored.  */
+ 
+ CORE_ADDR
+ x86_64_register_u_addr (CORE_ADDR blockend, int regnum)
+ {
+   struct user u;
+   CORE_ADDR fpstate;
+   CORE_ADDR ubase;
+   ubase = blockend;
+   if (IS_FP_REGNUM (regnum))
+     {
+       fpstate = ubase + ((char *) &u.i387.st_space - (char *) &u);
+       return (fpstate + 16 * (regnum - FP0_REGNUM));
+     }
+   else if (IS_SSE_REGNUM (regnum))
+     {
+       fpstate = ubase + ((char *) &u.i387.xmm_space - (char *) &u);
+       return (fpstate + 16 * (regnum - XMM0_REGNUM));
+     }
+   else
+     return (ubase + 8 * x86_64_regmap[regnum]);
+ }
+ \f
+ 
+ int
+ kernel_u_size (void)
+ {
+   return (sizeof (struct user));
+ }
Index: x86_64-tdep.c
===================================================================
RCS file: x86_64-tdep.c
diff -N x86_64-tdep.c
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64-tdep.c	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,904 ----
+ /* Target-dependent code for the x86-64 for GDB, the GNU debugger.
+    Copyright 2001 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 "defs.h"
+ #include "inferior.h"
+ #include "gdbcore.h"
+ #include "gdbcmd.h"
+ #include "arch-utils.h"
+ #include "regcache.h"
+ #include "symfile.h"
+ #include "x86_64-tdep.h"
+ #include "dwarf2cfi.h"
+ 
+ /* x86_64_register_raw_size_table[i] is the number of bytes of storage in
+    GDB's register array occupied by register i.  */
+ int x86_64_register_raw_size_table[X86_64_NUM_REGS] = {
+   8, 8, 8, 8,
+   8, 8, 8, 8,
+   8, 8, 8, 8,
+   8, 8, 8, 8,
+   8, 4,
+   10, 10, 10, 10,
+   10, 10, 10, 10,
+   4, 4, 4, 4,
+   4, 4, 4, 4,
+   16, 16, 16, 16,
+   16, 16, 16, 16,
+   16, 16, 16, 16,
+   16, 16, 16, 16,
+   4
+ };
+ 
+ /* Number of bytes of storage in the actual machine representation for
+    register REGNO.  */
+ int
+ x86_64_register_raw_size (int regno)
+ {
+   return x86_64_register_raw_size_table[regno];
+ }
+ 
+ /* x86_64_register_byte_table[i] is the offset into the register file of the
+    start of register number i.  We initialize this from
+    x86_64_register_raw_size_table.  */
+ int x86_64_register_byte_table[X86_64_NUM_REGS];
+ 
+ /* Index within `registers' of the first byte of the space for register REGNO.  */
+ int
+ x86_64_register_byte (int regno)
+ {
+   return x86_64_register_byte_table[regno];
+ }
+ 
+ /* Return the GDB type object for the "standard" data type of data in
+    register N. */
+ static struct type *
+ x86_64_register_virtual_type (int regno)
+ {
+   if (regno == PC_REGNUM || regno == SP_REGNUM)
+     return lookup_pointer_type (builtin_type_void);
+   if (IS_FP_REGNUM (regno))
+     return builtin_type_long_double;
+   if (IS_SSE_REGNUM (regno))
+     return builtin_type_v4sf;
+   if (IS_FPU_CTRL_REGNUM (regno) || regno == MXCSR_REGNUM
+       || regno == x86_64_regmap[EFLAGS])
+     return builtin_type_int;
+   return builtin_type_long;
+ }
+ 
+ /* Number of bytes of storage in the program's representation
+    for register REGNO.  */
+ int
+ x86_64_register_virtual_size (int regno)
+ {
+   return (TYPE_LENGTH (x86_64_register_virtual_type (regno)));
+ }
+ 
+ /* x86_64_register_convertible is true if register N's virtual format is
+    different from its raw format.  Note that this definition assumes
+    that the host supports IEEE 32-bit floats, since it doesn't say
+    that SSE registers need conversion.  Even if we can't find a
+    counterexample, this is still sloppy.  */
+ int
+ x86_64_register_convertible (int regno)
+ {
+   return IS_FP_REGNUM (regno);
+ }
+ 
+ /* Convert data from raw format for register REGNUM in buffer FROM to
+    virtual format with type TYPE in buffer TO.  In principle both
+    formats are identical except that the virtual format has two extra
+    bytes appended that aren't used.  We set these to zero.  */
+ void
+ x86_64_register_convert_to_virtual (int regnum, struct type *type,
+ 				    char *from, char *to)
+ {
+ /* Copy straight over, but take care of the padding.  */
+   memcpy (to, from, FPU_REG_RAW_SIZE);
+   memset (to + FPU_REG_RAW_SIZE, 0, TYPE_LENGTH (type) - FPU_REG_RAW_SIZE);
+ }
+ 
+ /* Convert data from virtual format with type TYPE in buffer FROM to
+    raw format for register REGNUM in buffer TO.  Simply omit the two
+    unused bytes.  */
+ 
+ void
+ x86_64_register_convert_to_raw (struct type *type, int regnum,
+ 				char *from, char *to)
+ {
+   memcpy (to, from, FPU_REG_RAW_SIZE);
+ }
+ \f
+ 
+ /* This is the variable that is set with "set disassembly-flavour", and
+    its legitimate values.  */
+ static const char att_flavour[] = "att";
+ static const char intel_flavour[] = "intel";
+ static const char *valid_flavours[] = {
+   att_flavour,
+   intel_flavour,
+   NULL
+ };
+ static const char *disassembly_flavour = att_flavour;
+ \f
+ 
+ static CORE_ADDR
+ x86_64_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+ {
+   char buf[8];
+ 
+   store_unsigned_integer (buf, 8, CALL_DUMMY_ADDRESS ());
+ 
+   write_memory (sp - 8, buf, 8);
+   return sp - 8;
+ }
+ 
+ void
+ x86_64_pop_frame (void)
+ {
+   generic_pop_current_frame (cfi_pop_frame);
+ }
+ 
+ /* The returning of values is done according to the special algorithm.
+    Some types are returned in registers an some (big structures) in memory.
+    See ABI for details.
+  */
+ 
+ #define MAX_CLASSES 4
+ 
+ enum x86_64_reg_class
+ {
+   X86_64_NO_CLASS,
+   X86_64_INTEGER_CLASS,
+   X86_64_INTEGERSI_CLASS,
+   X86_64_SSE_CLASS,
+   X86_64_SSESF_CLASS,
+   X86_64_SSEDF_CLASS,
+   X86_64_SSEUP_CLASS,
+   X86_64_X87_CLASS,
+   X86_64_X87UP_CLASS,
+   X86_64_MEMORY_CLASS
+ };
+ 
+ /* Return the union class of CLASS1 and CLASS2.
+    See the x86-64 ABI for details.  */
+ 
+ static enum x86_64_reg_class
+ merge_classes (class1, class2)
+      enum x86_64_reg_class class1, class2;
+ {
+   /* Rule #1: If both classes are equal, this is the resulting class.  */
+   if (class1 == class2)
+     return class1;
+ 
+   /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+      the other class.  */
+   if (class1 == X86_64_NO_CLASS)
+     return class2;
+   if (class2 == X86_64_NO_CLASS)
+     return class1;
+ 
+   /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
+   if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+     return X86_64_MEMORY_CLASS;
+ 
+   /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
+   if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+       || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+     return X86_64_INTEGERSI_CLASS;
+   if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+       || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+     return X86_64_INTEGER_CLASS;
+ 
+   /* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used.  */
+   if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS
+       || class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS)
+     return X86_64_MEMORY_CLASS;
+ 
+   /* Rule #6: Otherwise class SSE is used.  */
+   return X86_64_SSE_CLASS;
+ }
+ 
+ 
+ /* Classify the argument type.
+    CLASSES will be filled by the register class used to pass each word
+    of the operand.  The number of words is returned.  In case the parameter
+    should be passed in memory, 0 is returned. As a special case for zero
+    sized containers, classes[0] will be NO_CLASS and 1 is returned.
+ 
+    See the x86-64 PS ABI for details.
+ */
+ 
+ static int
+ classify_argument (struct type *type,
+ 		   enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset)
+ {
+   int bytes = TYPE_LENGTH (type);
+   int words = (bytes + 8 - 1) / 8;
+ 
+   switch (TYPE_CODE (type))
+     {
+     case TYPE_CODE_ARRAY:
+     case TYPE_CODE_STRUCT:
+     case TYPE_CODE_UNION:
+       {
+ 	int i;
+ 	enum x86_64_reg_class subclasses[MAX_CLASSES];
+ 
+ 	/* On x86-64 we pass structures larger than 16 bytes on the stack.  */
+ 	if (bytes > 16)
+ 	  return 0;
+ 
+ 	for (i = 0; i < words; i++)
+ 	  classes[i] = X86_64_NO_CLASS;
+ 
+ 	/* Zero sized arrays or structures are NO_CLASS.  We return 0 to
+ 	   signalize memory class, so handle it as special case.  */
+ 	if (!words)
+ 	  {
+ 	    classes[0] = X86_64_NO_CLASS;
+ 	    return 1;
+ 	  }
+ 	switch (TYPE_CODE (type))
+ 	  {
+ 	  case TYPE_CODE_STRUCT:
+ 	    {
+ 	      int j;
+ 	      for (j = 0; j < type->nfields; ++j)
+ 		{
+ 		  int num = classify_argument (type->fields[j].type,
+ 					       subclasses,
+ 					       (type->fields[j].loc.bitpos
+ 						+ bit_offset) % 256);
+ 		  if (!num)
+ 		    return 0;
+ 		  for (i = 0; i < num; i++)
+ 		    {
+ 		      int pos =
+ 			(type->fields[j].loc.bitpos + bit_offset) / 8 / 8;
+ 		      classes[i + pos] =
+ 			merge_classes (subclasses[i], classes[i + pos]);
+ 		    }
+ 		}
+ 	    }
+ 	    break;
+ 	  case TYPE_CODE_ARRAY:
+ 	    {
+ 	      int num;
+ 
+ 	      num = classify_argument (type->target_type,
+ 				       subclasses, bit_offset);
+ 	      if (!num)
+ 		return 0;
+ 
+ 	      /* The partial classes are now full classes.  */
+ 	      if (subclasses[0] == X86_64_SSESF_CLASS && bytes != 4)
+ 		subclasses[0] = X86_64_SSE_CLASS;
+ 	      if (subclasses[0] == X86_64_INTEGERSI_CLASS && bytes != 4)
+ 		subclasses[0] = X86_64_INTEGER_CLASS;
+ 
+ 	      for (i = 0; i < words; i++)
+ 		classes[i] = subclasses[i % num];
+ 	    }
+ 	    break;
+ 	  case TYPE_CODE_UNION:
+ 	    {
+ 	      int j;
+ 	      {
+ 		for (j = 0; j < type->nfields; ++j)
+ 		  {
+ 		    int num;
+ 		    num = classify_argument (type->fields[j].type,
+ 					     subclasses, bit_offset);
+ 		    if (!num)
+ 		      return 0;
+ 		    for (i = 0; i < num; i++)
+ 		      classes[i] = merge_classes (subclasses[i], classes[i]);
+ 		  }
+ 	      }
+ 	    }
+ 	    break;
+ 	  }
+ 	/* Final merger cleanup.  */
+ 	for (i = 0; i < words; i++)
+ 	  {
+ 	    /* If one class is MEMORY, everything should be passed in
+ 	       memory.  */
+ 	    if (classes[i] == X86_64_MEMORY_CLASS)
+ 	      return 0;
+ 
+ 	    /* The X86_64_SSEUP_CLASS should be always preceeded by
+ 	       X86_64_SSE_CLASS.  */
+ 	    if (classes[i] == X86_64_SSEUP_CLASS
+ 		&& (i == 0 || classes[i - 1] != X86_64_SSE_CLASS))
+ 	      classes[i] = X86_64_SSE_CLASS;
+ 
+ 	    /*  X86_64_X87UP_CLASS should be preceeded by X86_64_X87_CLASS.  */
+ 	    if (classes[i] == X86_64_X87UP_CLASS
+ 		&& (i == 0 || classes[i - 1] != X86_64_X87_CLASS))
+ 	      classes[i] = X86_64_SSE_CLASS;
+ 	  }
+ 	return words;
+       }
+       break;
+     case TYPE_CODE_FLT:
+       switch (bytes)
+ 	{
+ 	case 4:
+ 	  if (!(bit_offset % 64))
+ 	    classes[0] = X86_64_SSESF_CLASS;
+ 	  else
+ 	    classes[0] = X86_64_SSE_CLASS;
+ 	  return 1;
+ 	case 8:
+ 	  classes[0] = X86_64_SSEDF_CLASS;
+ 	  return 1;
+ 	case 16:
+ 	  classes[0] = X86_64_X87_CLASS;
+ 	  classes[1] = X86_64_X87UP_CLASS;
+ 	  return 2;
+ 	}
+       break;
+     case TYPE_CODE_INT:
+     case TYPE_CODE_PTR:
+       switch (bytes)
+ 	{
+ 	case 1:
+ 	case 2:
+ 	case 4:
+ 	case 8:
+ 	  if (bytes * 8 + bit_offset <= 32)
+ 	    classes[0] = X86_64_INTEGERSI_CLASS;
+ 	  else
+ 	    classes[0] = X86_64_INTEGER_CLASS;
+ 	  return 1;
+ 	case 16:
+ 	  classes[0] = classes[1] = X86_64_INTEGER_CLASS;
+ 	  return 2;
+ 	default:
+ 	  break;
+ 	}
+     }
+   internal_error (__FILE__, __LINE__, "Unknown argument type");
+ }
+ 
+ /* Examine the argument and return set number of register required in each
+    class.  Return 0 ifif parameter should be passed in memory.  */
+ 
+ static int
+ examine_argument (enum x86_64_reg_class classes[MAX_CLASSES],
+ 		  int n, int *int_nregs, int *sse_nregs)
+ {
+   *int_nregs = 0;
+   *sse_nregs = 0;
+   if (!n)
+     return 0;
+   for (n--; n >= 0; n--)
+     switch (classes[n])
+       {
+       case X86_64_INTEGER_CLASS:
+       case X86_64_INTEGERSI_CLASS:
+ 	(*int_nregs)++;
+ 	break;
+       case X86_64_SSE_CLASS:
+       case X86_64_SSESF_CLASS:
+       case X86_64_SSEDF_CLASS:
+ 	(*sse_nregs)++;
+ 	break;
+       case X86_64_NO_CLASS:
+       case X86_64_SSEUP_CLASS:
+       case X86_64_X87_CLASS:
+       case X86_64_X87UP_CLASS:
+ 	break;
+       case X86_64_MEMORY_CLASS:
+ 	internal_error (__FILE__, __LINE__, "Unexpected memory class");
+       }
+   return 1;
+ }
+ 
+ #define RET_INT_REGS 2
+ #define RET_SSE_REGS 2
+ 
+ #define XMM1_REGNUM  35
+ 
+ /* Check if the structure in value_type is returned in registers or in
+    memory. If this function returns 1, gdb will call STORE_STRUCT_RETURN and
+    EXTRACT_STRUCT_VALUE_ADDRESS else STORE_RETURN_VALUE and EXTRACT_RETURN_VALUE
+    will be used.  */
+ int
+ x86_64_use_struct_convention (int gcc_p, struct type *value_type)
+ {
+   enum x86_64_reg_class class[MAX_CLASSES];
+   int n = classify_argument (value_type, class, 0);
+   int needed_intregs;
+   int needed_sseregs;
+ 
+   return (!n ||
+ 	  !examine_argument (class, n, &needed_intregs, &needed_sseregs) ||
+ 	  needed_intregs > RET_INT_REGS || needed_sseregs > RET_SSE_REGS);
+ }
+ 
+ 
+ /* Extract from an array REGBUF containing the (raw) register state, a
+    function return value of TYPE, and copy that, in virtual format,
+    into VALBUF.  */
+ 
+ void
+ x86_64_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+ {
+   enum x86_64_reg_class class[MAX_CLASSES];
+   int n = classify_argument (type, class, 0);
+   int needed_intregs;
+   int needed_sseregs;
+   int intreg = 0;
+   int ssereg = 0;
+   int offset = 0;
+   int ret_int_r[RET_INT_REGS] = { x86_64_regmap[RAX], x86_64_regmap[RDX] };
+   int ret_sse_r[RET_SSE_REGS] = { XMM0_REGNUM, XMM1_REGNUM };
+ 
+   if (!n ||
+       !examine_argument (class, n, &needed_intregs, &needed_sseregs) ||
+       needed_intregs > RET_INT_REGS || needed_sseregs > RET_SSE_REGS)
+     {				/* memory class */
+       CORE_ADDR addr;
+       memcpy (&addr, regbuf, REGISTER_RAW_SIZE (x86_64_regmap[RAX]));
+       read_memory (addr, valbuf, TYPE_LENGTH (type));
+       return;
+     }
+   else
+     {
+       int i;
+       for (i = 0; i < n; i++)
+ 	{
+ 	  switch (class[i])
+ 	    {
+ 	    case X86_64_NO_CLASS:
+ 	      break;
+ 	    case X86_64_INTEGER_CLASS:
+ 	      memcpy (valbuf + offset,
+ 		      regbuf + REGISTER_BYTE (ret_int_r[(intreg + 1) / 2]),
+ 		      8);
+ 	      offset += 8;
+ 	      intreg += 2;
+ 	      break;
+ 	    case X86_64_INTEGERSI_CLASS:
+ 	      memcpy (valbuf + offset,
+ 		      regbuf + REGISTER_BYTE (ret_int_r[intreg / 2]), 4);
+ 	      offset += 8;
+ 	      intreg++;
+ 	      break;
+ 	    case X86_64_SSEDF_CLASS:
+ 	    case X86_64_SSESF_CLASS:
+ 	    case X86_64_SSE_CLASS:
+ 	      memcpy (valbuf + offset,
+ 		      regbuf + REGISTER_BYTE (ret_sse_r[(ssereg + 1) / 2]),
+ 		      8);
+ 	      offset += 8;
+ 	      ssereg += 2;
+ 	      break;
+ 	    case X86_64_SSEUP_CLASS:
+ 	      memcpy (valbuf + offset + 8,
+ 		      regbuf + REGISTER_BYTE (ret_sse_r[ssereg / 2]), 8);
+ 	      offset += 8;
+ 	      ssereg++;
+ 	      break;
+ 	    case X86_64_X87_CLASS:
+ 	      memcpy (valbuf + offset, regbuf + REGISTER_BYTE (FP0_REGNUM),
+ 		      8);
+ 	      offset += 8;
+ 	      break;
+ 	    case X86_64_X87UP_CLASS:
+ 	      memcpy (valbuf + offset,
+ 		      regbuf + REGISTER_BYTE (FP0_REGNUM) + 8, 8);
+ 	      offset += 8;
+ 	      break;
+ 	    case X86_64_MEMORY_CLASS:
+ 	    default:
+ 	      internal_error (__FILE__, __LINE__,
+ 			      "Unexpected argument class");
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* Handled by unwind informations.  */
+ static void
+ x86_64_frame_init_saved_regs (struct frame_info *fi)
+ {
+ }
+ 
+ /* Write into the appropriate registers a function return value stored
+    in VALBUF of type TYPE, given in virtual format.  */
+ void
+ x86_64_store_return_value (struct type *type, char *valbuf)
+ {
+   int len = TYPE_LENGTH (type);
+ 
+   if (TYPE_CODE_FLT == TYPE_CODE (type))
+     {
+       /* Floating-point return values can be found in %st(0).  */
+       if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT
+ 	  && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext)
+ 	{
+ 	  /* Copy straight over.  */
+ 	  write_register_bytes (REGISTER_BYTE (FP0_REGNUM), valbuf,
+ 				FPU_REG_RAW_SIZE);
+ 	}
+       else
+ 	{
+ 	  char buf[FPU_REG_RAW_SIZE];
+ 	  DOUBLEST val;
+ 
+ 	  /* Convert the value found in VALBUF to the extended
+ 	     floating point format used by the FPU.  This is probably
+ 	     not exactly how it would happen on the target itself, but
+ 	     it is the best we can do.  */
+ 	  val = extract_floating (valbuf, TYPE_LENGTH (type));
+ 	  floatformat_from_doublest (&floatformat_i387_ext, &val, buf);
+ 	  write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf,
+ 				FPU_REG_RAW_SIZE);
+ 	}
+     }
+   else
+     {
+       int low_size = REGISTER_RAW_SIZE (0);
+       int high_size = REGISTER_RAW_SIZE (1);
+ 
+       if (len <= low_size)
+ 	write_register_bytes (REGISTER_BYTE (0), valbuf, len);
+       else if (len <= (low_size + high_size))
+ 	{
+ 	  write_register_bytes (REGISTER_BYTE (0), valbuf, low_size);
+ 	  write_register_bytes (REGISTER_BYTE (1),
+ 				valbuf + low_size, len - low_size);
+ 	}
+       else
+ 	internal_error (__FILE__, __LINE__,
+ 			"Cannot store return value of %d bytes long.", len);
+     }
+ }
+ 
+ static char *
+ x86_64_register_name (int reg_nr)
+ {
+   static char *register_names[] = {
+     "rax", "rdx", "rcx", "rbx",
+     "rsi", "rdi", "rbp", "rsp",
+     "r8", "r9", "r10", "r11",
+     "r12", "r13", "r14", "r15",
+     "rip", "eflags",
+     "st0", "st1", "st2", "st3",
+     "st4", "st5", "st6", "st7",
+     "fctrl", "fstat", "ftag", "fiseg",
+     "fioff", "foseg", "fooff", "fop",
+     "xmm0", "xmm1", "xmm2", "xmm3",
+     "xmm4", "xmm5", "xmm6", "xmm7",
+     "xmm8", "xmm9", "xmm10", "xmm11",
+     "xmm12", "xmm13", "xmm14", "xmm15",
+     "mxcsr"
+   };
+   if (reg_nr < 0)
+     return NULL;
+   if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
+     return NULL;
+   return register_names[reg_nr];
+ }
+ \f
+ 
+ 
+ /* We have two flavours of disassembly.  The machinery on this page
+    deals with switching between those.  */
+ 
+ static int
+ gdb_print_insn_x86_64 (bfd_vma memaddr, disassemble_info * info)
+ {
+   if (disassembly_flavour == att_flavour)
+     return print_insn_i386_att (memaddr, info);
+   else if (disassembly_flavour == intel_flavour)
+     return print_insn_i386_intel (memaddr, info);
+   /* Never reached -- disassembly_flavour is always either att_flavour
+      or intel_flavour.  */
+   internal_error (__FILE__, __LINE__, "failed internal consistency check");
+ }
+ \f
+ 
+ /* Store the address of the place in which to copy the structure the
+    subroutine will return.  This is called from call_function. */
+ void
+ x86_64_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+ {
+   write_register (x86_64_regmap[RDI], addr);
+ }
+ 
+ int
+ x86_64_frameless_function_invocation (struct frame_info *frame)
+ {
+   return 0;
+ }
+ 
+ /* On x86_64 there are no reasonable prologs.  */
+ CORE_ADDR
+ x86_64_skip_prologue (CORE_ADDR pc)
+ {
+   return pc;
+ }
+ 
+ /* Sequence of bytes for breakpoint instruction.  */
+ static unsigned char *
+ x86_64_breakpoint_from_pc (CORE_ADDR * pc, int *lenptr)
+ {
+   static unsigned char breakpoint[] = { 0xcc };
+   *lenptr = 1;
+   return breakpoint;
+ }
+ 
+ static struct gdbarch *
+ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+ {
+   struct gdbarch *gdbarch;
+   struct gdbarch_tdep *tdep;
+ 
+   /* Find a candidate among the list of pre-declared architectures. */
+   for (arches = gdbarch_list_lookup_by_info (arches, &info);
+        arches != NULL;
+        arches = gdbarch_list_lookup_by_info (arches->next, &info))
+     {
+       switch (info.bfd_arch_info->mach)
+ 	{
+ 	case bfd_mach_x86_64:
+ 	case bfd_mach_x86_64_intel_syntax:
+ 	  switch (gdbarch_bfd_arch_info (arches->gdbarch)->mach)
+ 	    {
+ 	    case bfd_mach_x86_64:
+ 	    case bfd_mach_x86_64_intel_syntax:
+ 	      return arches->gdbarch;
+ 	    case bfd_mach_i386_i386:
+ 	    case bfd_mach_i386_i8086:
+ 	    case bfd_mach_i386_i386_intel_syntax:
+ 	      break;
+ 	    default:
+ 	      internal_error (__FILE__, __LINE__,
+ 			      "i386_gdbarch_init: unknown machine type");
+ 	    }
+ 	  break;
+ 	case bfd_mach_i386_i386:
+ 	case bfd_mach_i386_i8086:
+ 	case bfd_mach_i386_i386_intel_syntax:
+ 	  switch (gdbarch_bfd_arch_info (arches->gdbarch)->mach)
+ 	    {
+ 	    case bfd_mach_x86_64:
+ 	    case bfd_mach_x86_64_intel_syntax:
+ 	      break;
+ 	    case bfd_mach_i386_i386:
+ 	    case bfd_mach_i386_i8086:
+ 	    case bfd_mach_i386_i386_intel_syntax:
+ 	      return arches->gdbarch;
+ 	    default:
+ 	      internal_error (__FILE__, __LINE__,
+ 			      "i386_gdbarch_init: unknown machine type");
+ 	    }
+ 	  break;
+ 	default:
+ 	  internal_error (__FILE__, __LINE__,
+ 			  "i386_gdbarch_init: unknown machine type");
+ 	}
+     }
+ 
+   tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+   gdbarch = gdbarch_alloc (&info, tdep);
+ 
+   switch (info.bfd_arch_info->mach)
+     {
+     case bfd_mach_x86_64:
+     case bfd_mach_x86_64_intel_syntax:
+       tdep->last_fpu_regnum = 25;
+       tdep->first_xmm_regnum = 34;
+       tdep->last_xmm_regnum = 34;
+       tdep->mxcsr_regnum = 50;
+       tdep->first_fpu_ctrl_regnum = 26;
+       tdep->last_fpu_ctrl_regnum = 33;
+       tdep->fctrl_regnum = 26;
+       tdep->fstat_regnum = 27;
+       tdep->ftag_regnum = 28;
+       tdep->fcs_regnum = 29;
+       tdep->fcoff_regnum = 30;
+       tdep->fds_regnum = 31;
+       tdep->fdoff_regnum = 32;
+       tdep->fop_regnum = 33;
+       break;
+     case bfd_mach_i386_i386:
+     case bfd_mach_i386_i8086:
+     case bfd_mach_i386_i386_intel_syntax:
+       /* This is place for definition of i386 target vector.  */
+       break;
+     default:
+       internal_error (__FILE__, __LINE__,
+ 		      "i386_gdbarch_init: unknown machine type");
+     }
+ 
+   set_gdbarch_long_bit (gdbarch, 64);
+   set_gdbarch_long_long_bit (gdbarch, 64);
+   set_gdbarch_ptr_bit (gdbarch, 64);
+ 
+   set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+   set_gdbarch_ieee_float (gdbarch, 1);
+ 
+ 
+   set_gdbarch_num_regs (gdbarch, X86_64_NUM_REGS);
+   set_gdbarch_register_name (gdbarch, x86_64_register_name);
+   set_gdbarch_register_size (gdbarch, 8);
+   set_gdbarch_register_raw_size (gdbarch, x86_64_register_raw_size);
+   set_gdbarch_max_register_raw_size (gdbarch, 16);
+   set_gdbarch_register_byte (gdbarch, x86_64_register_byte);
+   /* Total amount of space needed to store our copies of the machine's register
+      (SIZEOF_GREGS + SIZEOF_FPU_REGS + SIZEOF_FPU_CTRL_REGS + SIZEOF_SSE_REGS) */
+   set_gdbarch_register_bytes (gdbarch,
+ 			      (18 * 8) + (8 * 10) + (8 * 4) + (8 * 16 + 4));
+   set_gdbarch_register_virtual_size (gdbarch, x86_64_register_virtual_size);
+   set_gdbarch_max_register_virtual_size (gdbarch, 16);
+ 
+   set_gdbarch_register_virtual_type (gdbarch, x86_64_register_virtual_type);
+ 
+   set_gdbarch_register_convertible (gdbarch, x86_64_register_convertible);
+   set_gdbarch_register_convert_to_virtual (gdbarch,
+ 					   x86_64_register_convert_to_virtual);
+   set_gdbarch_register_convert_to_raw (gdbarch,
+ 				       x86_64_register_convert_to_raw);
+ 
+ /* Register numbers of various important registers.  */
+   set_gdbarch_sp_regnum (gdbarch, 7);	/* (rsp) Contains address of top of stack.  */
+   set_gdbarch_fp_regnum (gdbarch, 6);	/* (rbp) */
+   set_gdbarch_pc_regnum (gdbarch, 16);	/* (rip) Contains program counter.  */
+ 
+   set_gdbarch_fp0_regnum (gdbarch, 18);	/* First FPU floating-point register.  */
+ 
+   set_gdbarch_read_fp (gdbarch, cfi_read_fp);
+   set_gdbarch_write_fp (gdbarch, cfi_write_fp);
+ 
+ /* Discard from the stack the innermost frame, restoring all registers.  */
+   set_gdbarch_pop_frame (gdbarch, x86_64_pop_frame);
+ 
+   /* FRAME_CHAIN takes a frame's nominal address and produces the frame's
+      chain-pointer.  */
+   set_gdbarch_frame_chain (gdbarch, cfi_frame_chain);
+ 
+   set_gdbarch_frameless_function_invocation (gdbarch,
+ 					     x86_64_frameless_function_invocation);
+   set_gdbarch_frame_saved_pc (gdbarch, x86_64_linux_frame_saved_pc);
+ 
+   set_gdbarch_frame_args_address (gdbarch, default_frame_address);
+   set_gdbarch_frame_locals_address (gdbarch, default_frame_address);
+ 
+ /* Return number of bytes at start of arglist that are not really args.  */
+   set_gdbarch_frame_args_skip (gdbarch, 8);
+ 
+   set_gdbarch_frame_init_saved_regs (gdbarch, x86_64_frame_init_saved_regs);
+ 
+ /* Frame pc initialization is handled by unwind informations.  */
+   set_gdbarch_init_frame_pc (gdbarch, cfi_init_frame_pc);
+ 
+ /* Initialization of unwind informations.  */
+   set_gdbarch_init_extra_frame_info (gdbarch, cfi_init_extra_frame_info);
+ 
+ /* Getting saved registers is handled by unwind informations.  */
+   set_gdbarch_get_saved_register (gdbarch, cfi_get_saved_register);
+ 
+   set_gdbarch_frame_init_saved_regs (gdbarch, x86_64_frame_init_saved_regs);
+ 
+ /* Cons up virtual frame pointer for trace */
+   set_gdbarch_virtual_frame_pointer (gdbarch, cfi_virtual_frame_pointer);
+ 
+ 
+   set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid);
+ 
+   set_gdbarch_use_generic_dummy_frames (gdbarch, 1);
+   set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+   set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
+   set_gdbarch_call_dummy_length (gdbarch, 0);
+   set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
+   set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
+   set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+   set_gdbarch_call_dummy_words (gdbarch, 0);
+   set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
+   set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
+   set_gdbarch_call_dummy_p (gdbarch, 1);
+   set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+   set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
+   set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
+   set_gdbarch_push_return_address (gdbarch, x86_64_push_return_address);
+   set_gdbarch_push_arguments (gdbarch, default_push_arguments);
+ 
+ /* Return number of args passed to a frame, no way to tell.  */
+   set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+ /* Don't use default structure extract routine */
+   set_gdbarch_extract_struct_value_address (gdbarch, 0);
+ 
+ /* If USE_STRUCT_CONVENTION retruns 0, then gdb uses STORE_RETURN_VALUE
+    and EXTRACT_RETURN_VALUE to store/fetch the functions return value.  It is
+    the case when structure is returned in registers.  */
+   set_gdbarch_use_struct_convention (gdbarch, x86_64_use_struct_convention);
+ 
+ /* Store the address of the place in which to copy the structure the
+    subroutine will return.  This is called from call_function. */
+   set_gdbarch_store_struct_return (gdbarch, x86_64_store_struct_return);
+ 
+ /* Extract from an array REGBUF containing the (raw) register state
+    a function return value of type TYPE, and copy that, in virtual format,
+    into VALBUF.  */
+   set_gdbarch_extract_return_value (gdbarch, x86_64_extract_return_value);
+ 
+ 
+ /* Write into the appropriate registers a function return value stored
+    in VALBUF of type TYPE, given in virtual format.  */
+   set_gdbarch_store_return_value (gdbarch, x86_64_store_return_value);
+ \f
+ 
+ /* Offset from address of function to start of its code.  */
+   set_gdbarch_function_start_offset (gdbarch, 0);
+ 
+   set_gdbarch_skip_prologue (gdbarch, x86_64_skip_prologue);
+ 
+   set_gdbarch_saved_pc_after_call (gdbarch, x86_64_linux_saved_pc_after_call);
+ 
+   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ 
+   set_gdbarch_breakpoint_from_pc (gdbarch, x86_64_breakpoint_from_pc);
+ 
+ 
+ /* Amount PC must be decremented by after a breakpoint.  This is often the
+    number of bytes in BREAKPOINT but not always.  */
+   set_gdbarch_decr_pc_after_break (gdbarch, 1);
+ 
+   return gdbarch;
+ }
+ 
+ void
+ _initialize_x86_64_tdep (void)
+ {
+   register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
+ 
+   /* Initialize the table saying where each register starts in the
+      register file.  */
+   {
+     int i, offset;
+ 
+     offset = 0;
+     for (i = 0; i < X86_64_NUM_REGS; i++)
+       {
+ 	x86_64_register_byte_table[i] = offset;
+ 	offset += x86_64_register_raw_size_table[i];
+       }
+   }
+ 
+   tm_print_insn = gdb_print_insn_x86_64;
+   tm_print_insn_info.mach = bfd_lookup_arch (bfd_arch_i386, 3)->mach;
+ 
+   /* Add the variable that controls the disassembly flavour.  */
+   {
+     struct cmd_list_element *new_cmd;
+ 
+     new_cmd = add_set_enum_cmd ("disassembly-flavour", no_class,
+ 				valid_flavours, &disassembly_flavour, "\
+ Set the disassembly flavour, the valid values are \"att\" and \"intel\", \
+ and the default value is \"att\".", &setlist);
+     add_show_from_set (new_cmd, &showlist);
+   }
+ }
Index: x86_64-tdep.h
===================================================================
RCS file: x86_64-tdep.h
diff -N x86_64-tdep.h
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64-tdep.h	Wed Sep  5 05:06:20 2001
***************
*** 0 ****
--- 1,48 ----
+ /* Target-dependent code for GDB, the GNU debugger.
+    Copyright 2000
+    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 X86_64_TDEP_H
+ #define X86_64_TDEP_H
+ 
+ #include "i386-tdep.h"
+ #include <sys/reg.h>
+ 
+ /* Mapping between the general-purpose registers in `struct user'
+    format and GDB's register array layout.  */
+ 
+ static int x86_64_regmap[] = {
+   RAX, RDX, RCX, RBX,
+   RSI, RDI, RBP, RSP,
+   R8, R9, R10, R11,
+   R12, R13, R14, R15,
+   RIP, EFLAGS
+ };
+ 
+ /* Number of all registers */
+ #define X86_64_NUM_REGS (51)
+ 
+ /* Number of general registers.  */
+ #define X86_64_NUM_GREGS (18)
+ 
+ gdbarch_frame_saved_pc_ftype x86_64_linux_frame_saved_pc;
+ gdbarch_saved_pc_after_call_ftype x86_64_linux_saved_pc_after_call;
+ 
+ #endif
Index: config/djgpp/fnchange.lst
===================================================================
RCS file: /cvs/src/src/gdb/config/djgpp/fnchange.lst,v
retrieving revision 1.19
diff -c -3 -p -r1.19 fnchange.lst
*** fnchange.lst	2001/08/24 05:00:06	1.19
--- fnchange.lst	2001/09/05 12:06:21
***************
*** 202,207 ****
--- 202,209 ----
  @V@/gdb/testsuite/gdb.mi/mi0-var-display.exp @V@/gdb/testsuite/gdb.mi/mi0vardisplay.exp
  @V@/gdb/tui/tuiSourceWin.c @V@/gdb/tui/tuiWinSource.c
  @V@/gdb/tui/tuiSourceWin.h @V@/gdb/tui/tuiWinSource.h
+ @V@/gdb/x86_64-linux-tdep.c @V@/gdb/x8664-ltdep.c
+ @V@/gdb/x86_64-linux-nat.c @V@/gdb/x8664-lnat.c
  @V@/intl/intlh.inst.in @V@/intl/intlh_inst.in
  @V@/intl/po2tbl.sed.in @V@/intl/po2tblsed.in
  @V@/itcl/itcl/itclConfig.sh.in @V@/itcl/itcl/itclConfig.sh-in
Index: config/i386/nm-x86_64.h
===================================================================
RCS file: nm-x86_64.h
diff -N nm-x86_64.h
*** /dev/null	Tue May  5 13:32:27 1998
--- nm-x86_64.h	Wed Sep  5 05:06:21 2001
***************
*** 0 ****
--- 1,100 ----
+ /* Native support for Linux/x86-64.
+    Copyright 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+    1999, 2000, 2001
+    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 NM_X86_64_H
+ #define NM_X86_64_H
+ 
+ #include "nm-linux.h"
+ 
+ 
+ #define REGISTER_U_ADDR(addr, blockend, regno) \
+ 	(addr) = x86_64_register_u_addr ((blockend),(regno));
+ CORE_ADDR x86_64_register_u_addr (CORE_ADDR, int);
+ 
+ /* Return the size of the user struct.  */
+ #define KERNEL_U_SIZE kernel_u_size()
+ extern int kernel_u_size (void);
+ 
+ /* Offset of the registers within the user area.  */
+ #define U_REGS_OFFSET 0
+ 
+ /* This is the amount to subtract from u.u_ar0
+    to get the offset in the core file of the register values.  */
+ #define KERNEL_U_ADDR 0x0
+ 
+ #define CHILD_XFER_MEMORY
+ 
+ #define PTRACE_ARG3_TYPE void*
+ \f
+ /* GNU/Linux supports the x86_64 hardware debugging registers.  */
+ 
+ #define TARGET_HAS_HARDWARE_WATCHPOINTS
+ 
+ #define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
+ 
+ /* After a watchpoint trap, the PC points to the instruction after
+    the one that caused the trap.  Therefore we don't need to step over it.
+    But we do need to reset the status register to avoid another trap.  */
+ #define HAVE_CONTINUABLE_WATCHPOINT
+ 
+ #define STOPPED_BY_WATCHPOINT(W)  \
+   x86_64_stopped_by_watchpoint (inferior_ptid)
+ CORE_ADDR x86_64_stopped_by_watchpoint (ptid_t);
+ 
+ /* Use these macros for watchpoint insertion/removal.  */
+ 
+ #define target_insert_watchpoint(addr, len, type)  \
+   x86_64_insert_watchpoint (inferior_ptid, addr, len, type)
+ int x86_64_insert_watchpoint (ptid_t pid, CORE_ADDR addr, int len, int rw);
+ 
+ #define target_remove_watchpoint(addr, len, type)  \
+   x86_64_remove_watchpoint (inferior_ptid, addr, len)
+ int x86_64_remove_watchpoint (ptid_t pid, CORE_ADDR addr, int len);
+ \f
+ /* We define this if link.h is available, because with ELF we use SVR4 style
+    shared libraries. */
+ 
+ #ifdef HAVE_LINK_H
+ #define SVR4_SHARED_LIBS
+ #include "solib.h"		/* Support for shared libraries. */
+ #endif
+ 
+ /* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
+ #define FETCH_INFERIOR_REGISTERS
+ 
+ /* Override child_resume in `infptrace.c'.  */
+ #define CHILD_RESUME
+ 
+ // extern int lin_lwp_prepare_to_proceed (void);
+ #undef PREPARE_TO_PROCEED
+ // #define PREPARE_TO_PROCEED(select_it) lin_lwp_prepare_to_proceed ()
+ 
+ extern void lin_lwp_attach_lwp (ptid_t pid, int verbose);
+ #define ATTACH_LWP(pid, verbose) lin_lwp_attach_lwp ((pid), (verbose))
+ 
+ #include <signal.h>
+ 
+ extern void lin_thread_get_thread_signals (sigset_t * mask);
+ #define GET_THREAD_SIGNALS(mask) lin_thread_get_thread_signals (mask)
+ 
+ #endif /* NM_X86_64.h */
Index: config/i386/x86_64linux.mh
===================================================================
RCS file: x86_64linux.mh
diff -N x86_64linux.mh
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64linux.mh	Wed Sep  5 05:06:21 2001
***************
*** 0 ****
--- 1,11 ----
+ # Host: AMD x86-64 running GNU/Linux
+ 
+ XM_FILE= xm-i386.h
+ XDEPFILES=
+ 
+ NAT_FILE= nm-x86_64.h
+ NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
+ 	core-aout.o x86_64-nat.o x86_64-linux-nat.o i387-nat.o \
+ 	proc-service.o thread-db.o lin-lwp.o
+ 
+ LOADLIBES = -ldl -rdynamic
Index: config/i386/x86_64linux.mt
===================================================================
RCS file: x86_64linux.mt
diff -N x86_64linux.mt
*** /dev/null	Tue May  5 13:32:27 1998
--- x86_64linux.mt	Wed Sep  5 05:06:21 2001
***************
*** 0 ****
--- 1,6 ----
+ # Target: AMD x86-64 running GNU/Linux
+ TDEPFILES= x86_64-tdep.o x86_64-linux-tdep.o i387-tdep.o dwarf2cfi.o \
+ 	solib.o solib-svr4.o solib-legacy.o
+ TM_FILE= tm-x86_64.h
+ 
+ GDBSERVER_DEPFILES= low-linux.o

-- 
Jiri Smid

---------------------------------------------------------------------
SuSE CR, s.r.o.                                 e-mail: smid@suse.cz
Drahobejlova 27                                tel:+420 2 83095 373
190 00 Praha 9                                 fax:+420 2 83095 374
Ceska republika                                http://www.suse.cz


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-05  7:02 [RFA]: x86_64 target - multiarch Jiri Smid
@ 2001-09-05  7:38 ` Eli Zaretskii
  2001-09-05 15:31 ` Mark Kettenis
  2001-09-05 17:55 ` Andrew Cagney
  2 siblings, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2001-09-05  7:38 UTC (permalink / raw)
  To: Jiri Smid; +Cc: gdb-patches

On 5 Sep 2001, Jiri Smid wrote:

> 	* config/djgpp/fnchange.lst: Add entries for x86_64-linux-tdep.c
> 	and x86_64-linux-nat.c

These changes are approved.

> + int
> + x86_64_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
> + {
> +   return x86_64_insert_aligned_watchpoint (ptid, addr, addr, len, rw);
> + }
> + 
> + static int
> + x86_64_insert_aligned_watchpoint (ptid_t ptid, CORE_ADDR waddr,
> + 				  CORE_ADDR addr, int len, int rw)
> + {
> +   int i;
> +   int read_write_bits, len_bits;
> +   int free_debug_register;
> +   int register_number;
> + 
> +   /* Look for a free debug register.  */
> +   for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
> +     {
> +       if (address_lookup[i - DR_FIRSTADDR] == 0)
> + 	break;
> +     }
> + 
> +   /* No more debug registers!  */
> +   if (i > DR_LASTADDR)
> +     return -1;
> + 
> +   read_write_bits = (rw & 1) ? DR_RW_READ : DR_RW_WRITE;
> + 
> +   if (len == 1)
> +     len_bits = DR_LEN_1;
> +   else if (len == 2)
> +     {
> +       if (addr % 2)
> + 	return x86_64_insert_nonaligned_watchpoint (ptid, waddr, addr, len,
> + 						    rw);
> +       len_bits = DR_LEN_2;
> +     }

I think I already mentioned this in earlier discussions: why did you base 
the watchpoint support on the old SysV stuff instead of the newer code in 
i386-nat.c?  Don't you want the additional features supported by 
i386-nat.c, like debug register sharing between watchpoints?  Try this, 
for example:

	(gdb) watch a == 1
	(gdb) watch a == 2
	(gdb) watch a == 3
	(gdb) watch a == 4

In your implementation, this takes 4 debug registers, whereas i386-nat.c 
will only use one.  Also, with your implementation, even if you are ready 
to waste 3 debug registers, GDB might become confused if you decide to 
remove one of these watchpoints (since the remove_watchpoint code will 
zero out all the debug registers because they watch the same address).

Also, I think this implementation doesn't support watching regions larger 
than 8 bytes very well, because the code which removes watchpoints 
doesn't break the region into smaller regions the same way 
x86_64_insert_nonaligned_watchpoint does.

So I suggest to use the code in i386-nat.c as the starting point.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-05  7:02 [RFA]: x86_64 target - multiarch Jiri Smid
  2001-09-05  7:38 ` Eli Zaretskii
@ 2001-09-05 15:31 ` Mark Kettenis
  2001-09-05 18:05   ` Andrew Cagney
  2001-09-06  0:30   ` Eli Zaretskii
  2001-09-05 17:55 ` Andrew Cagney
  2 siblings, 2 replies; 9+ messages in thread
From: Mark Kettenis @ 2001-09-05 15:31 UTC (permalink / raw)
  To: Jiri Smid; +Cc: gdb-patches

Hi Jiri,

This starts looking good.  A few notes though.

* i386-tdep.h:

Is it really necessary to include all those FPU register numbers in
`struct gdbarch_tdep'?  At the moment you use at least the same order
for most things as the standard i386 register numbering scheme, so I
think you can remove a few variables from `struct gdbarch_tdep' and
define the register numbers relative to the remaining variables.  For
example you could remove fctrl_regnum, fstat_regnum, etc. and do

#define FCTRL_REGNUM FIRST_FPU_CTRL_REGNUM
#define FSTAT_REGNUM FIRST_FPU_CTRL_REGNUM + 1
etc.

* x86_64-linux-nat.c:

Including <asm/*.h> is considered bad practice.  You can probably use
<sys/debugreg.h> instead of <asm/debugreg.h> and <sys/syscall.h>
instead of <asm/unistd.h>.

There is a while load of backwards compatibility stuff in this file
that's probably unecessary on x86_64.  You probably copied it from
i386-linux-nat.c, where this stuff is necessary to be able to run GDB
on Linux 2.0, and with older versions of glibc.  I assume that all
Linux kernels that run on the x86_64 have the PTRACE_GETREGS,
PTRACE_GETFPREGS, PTRACE_GETFPXREGS, etc. requests, so you can
probably get rid of all the HAVE_PTRACE_XXX hackery.  The code to
fetch registers directly from the U area (fetch_register,
old_fetch_inferior_registers) can probably be removed too.

child_resume() and child_xfer_memory appear to have some formatting
problems.  Might be related to using tabs instead of spaces.

Eli already pointed out that the you should try to use the generic
hardware watchpoint support in i386-nat.c instead of rolling your own
here.  Check the current i386-linux-nat.c to see how you can use that
stuff.

* x86_64-nat.c:

If you get rid of the U area register reading code above, the stuff in
this file shouldn't be necessary anymore (at least in theory).

* x86_64-tdep.c:

The implementation of x86_64_register_convert_to_virtual() is almost
certainly wrong.  However, the floating-point stuff is a bit in flux
right now, and you might want to fix this later, when things have
settled a bit.

Please fix merge_classes() to use an ISO C function definition.
Again some formatting problems.

Mark


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-05  7:02 [RFA]: x86_64 target - multiarch Jiri Smid
  2001-09-05  7:38 ` Eli Zaretskii
  2001-09-05 15:31 ` Mark Kettenis
@ 2001-09-05 17:55 ` Andrew Cagney
  2 siblings, 0 replies; 9+ messages in thread
From: Andrew Cagney @ 2001-09-05 17:55 UTC (permalink / raw)
  To: Jiri Smid; +Cc: gdb-patches

jiri,

my only comment is on the file name.  are you sure you want to name 
every thing x86_64 and not x86-64?

you may want to mention you and/or suse as contributors in the relevent 
copyrights :-)

other than that just address the concerns already raised by mark and 
eli, and assume mark and eli's approval is final.

	andrew


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-05 15:31 ` Mark Kettenis
@ 2001-09-05 18:05   ` Andrew Cagney
  2001-09-06  0:30   ` Eli Zaretskii
  1 sibling, 0 replies; 9+ messages in thread
From: Andrew Cagney @ 2001-09-05 18:05 UTC (permalink / raw)
  To: Jiri Smid; +Cc: Mark Kettenis, gdb-patches

> Again some formatting problems.

jiri, the most efficient way of fixing formatting problems is to use the 
indent program.  the thing to remember is that you don't care how ugly 
the indentation is, just as long as it complies with gnu standards.

the attached script may help

	andrew


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-05 15:31 ` Mark Kettenis
  2001-09-05 18:05   ` Andrew Cagney
@ 2001-09-06  0:30   ` Eli Zaretskii
  2001-09-11  5:13     ` Jiri Smid
  1 sibling, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2001-09-06  0:30 UTC (permalink / raw)
  To: Mark Kettenis; +Cc: Jiri Smid, gdb-patches

On 6 Sep 2001, Mark Kettenis wrote:

> Eli already pointed out that the you should try to use the generic
> hardware watchpoint support in i386-nat.c instead of rolling your own
> here.

I don't think x86_64 can use i386-nat.c's implementation, unless
i386-nat.c is extended to handle debug registers that can watch regions 
wider than 4 bytes.  One thing that definitely needs to be changed is the 
size_try_array array, and some of the functions don't expect to see a 
region more than 4 bytes long.

But even if x86_64 does not use i386-nat.c, they could roll a similar
implementation, and thus support the same features.  FWIW, NEWS
already promises that all x86 targets support those features ;-)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-06  0:30   ` Eli Zaretskii
@ 2001-09-11  5:13     ` Jiri Smid
  2001-09-11  5:43       ` Eli Zaretskii
  0 siblings, 1 reply; 9+ messages in thread
From: Jiri Smid @ 2001-09-11  5:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: Mark Kettenis, Eli Zaretskii

Eli Zaretskii <eliz@is.elta.co.il> writes:

> On 6 Sep 2001, Mark Kettenis wrote:
> 
> > Eli already pointed out that the you should try to use the generic
> > hardware watchpoint support in i386-nat.c instead of rolling your own
> > here.
> 
> I don't think x86_64 can use i386-nat.c's implementation, unless
> i386-nat.c is extended to handle debug registers that can watch regions 
> wider than 4 bytes.  One thing that definitely needs to be changed is the 
> size_try_array array, and some of the functions don't expect to see a 
> region more than 4 bytes long.
> 
> But even if x86_64 does not use i386-nat.c, they could roll a similar
> implementation, and thus support the same features.  FWIW, NEWS
> already promises that all x86 targets support those features ;-)

  Support for 8-byte wide watchpoints doesn't need too many changes in
i386-nat.c. If this patch is be accepted the x86-64 target could use
the generic i386 hardware watchpoint support.

Index: gdb/ChangeLog
from  Jiri Smid   <smid@suse.cz>
	* i386-nat.c (TARGET_HAS_DR_LEN_8, DR_LEN_8): Declare.
	(i386_length_and_rw_bits, i386_handle_nonaligned_watchpoint,
	i386_insert_watchpoint, i386_remove_watchpoint):  Add support for
	8-byte wide watchpoints.
	(i386_show_dr): Debug message format string change.

Index: gdb/i386-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-nat.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 i386-nat.c
*** i386-nat.c	2001/04/18 00:37:49	1.3
--- i386-nat.c	2001/09/11 11:59:18
***************
*** 60,65 ****
--- 60,70 ----
  
  #ifdef I386_USE_GENERIC_WATCHPOINTS
  
+ /* Support for 8-byte wide hw watchpoints.  */
+ #ifndef TARGET_HAS_DR_LEN_8
+ #define TARGET_HAS_DR_LEN_8 0
+ #endif
+ 
  /* Debug registers' indices.  */
  #define DR_NADDR		4  /* the number of debug address registers */
  #define DR_STATUS		6  /* index of debug status register (DR6) */
***************
*** 89,94 ****
--- 94,100 ----
  #define DR_LEN_1		(0x0 << 2) /* 1-byte region watch or breakpt */
  #define DR_LEN_2		(0x1 << 2) /* 2-byte region watch */
  #define DR_LEN_4		(0x3 << 2) /* 4-byte region watch */
+ #define DR_LEN_8		(0x2 << 2) /* 8-byte region watch (x86-64) */
  
  /* Local and Global Enable flags in DR7.
  
*************** i386_show_dr (const char *func, CORE_ADD
*** 252,260 ****
  		     dr_control_mirror, dr_status_mirror);
    ALL_DEBUG_REGISTERS(i)
      {
!       printf_unfiltered ("\tDR%d: addr=%08lx, ref.count=%d  DR%d: addr=%08lx, ref.count=%d\n",
! 			 i, dr_mirror[i], dr_ref_count[i],
! 			 i+1, dr_mirror[i+1], dr_ref_count[i+1]);
        i++;
      }
  }
--- 258,266 ----
  		     dr_control_mirror, dr_status_mirror);
    ALL_DEBUG_REGISTERS(i)
      {
!       printf_unfiltered ("\tDR%d: addr=%p, ref.count=%d  DR%d: addr=%p, ref.count=%d\n",
! 			 i, (void *)dr_mirror[i], dr_ref_count[i],
! 			 i+1, (void*)dr_mirror[i+1], dr_ref_count[i+1]);
        i++;
      }
  }
*************** Invalid hw breakpoint type %d in i386_le
*** 291,302 ****
  
    switch (len)
      {
-       case 4:
- 	return (DR_LEN_4 | rw);
-       case 2:
- 	return (DR_LEN_2 | rw);
        case 1:
  	return (DR_LEN_1 | rw);
        default:
  	internal_error (__FILE__, __LINE__, "\
  Invalid hw breakpoint length %d in i386_length_and_rw_bits.\n", len);
--- 297,311 ----
  
    switch (len)
      {
        case 1:
  	return (DR_LEN_1 | rw);
+       case 2:
+ 	return (DR_LEN_2 | rw);
+       case 4:
+ 	return (DR_LEN_4 | rw);
+       case 8:
+         if (TARGET_HAS_DR_LEN_8)
+  	  return (DR_LEN_8 | rw);
        default:
  	internal_error (__FILE__, __LINE__, "\
  Invalid hw breakpoint length %d in i386_length_and_rw_bits.\n", len);
*************** i386_handle_nonaligned_watchpoint (i386_
*** 407,426 ****
    int align;
    int size;
    int rv = 0, status = 0;
  
!   static int size_try_array[4][4] =
    {
!     { 1, 1, 1, 1 },		/* trying size one */
!     { 2, 1, 2, 1 },		/* trying size two */
!     { 2, 1, 2, 1 },		/* trying size three */
!     { 4, 1, 2, 1 }		/* trying size four */
    };
  
    while (len > 0)
      {
!       align = addr % 4;
!       /* Four is the maximum length an x86 debug register can watch.  */
!       size = size_try_array[len > 4 ? 3 : len - 1][align];
        if (what == WP_COUNT)
  	/* size_try_array[] is defined so that each iteration through
  	   the loop is guaranteed to produce an address and a size
--- 416,441 ----
    int align;
    int size;
    int rv = 0, status = 0;
+   int max_wp_len = TARGET_HAS_DR_LEN_8 ? 8 : 4;
  
!   static int size_try_array[8][8] =
    {
!     {1, 1, 1, 1, 1, 1, 1, 1},	/* trying size one */
!     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size two */
!     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size three */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size four */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size five */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size six */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size seven */
!     {8, 1, 2, 1, 4, 1, 2, 1},	/* trying size eight */
    };
  
    while (len > 0)
      {
!       align = addr % max_wp_len;
!       /* Four(eigth on x86_64) is the maximum length an x86 debug register
! 	 can watch.  */
!       size = size_try_array[len > max_wp_len ? (max_wp_len - 1) : len - 1][align];
        if (what == WP_COUNT)
  	/* size_try_array[] is defined so that each iteration through
  	   the loop is guaranteed to produce an address and a size
*************** i386_insert_watchpoint (CORE_ADDR addr, 
*** 466,472 ****
  {
    int retval;
  
!   if (len == 3 || len > 4 || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
    else
      {
--- 481,488 ----
  {
    int retval;
  
!   if ((len != 1 && len !=2 && len !=4 && (TARGET_HAS_DR_LEN_8 && len !=8))
!       || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
    else
      {
*************** i386_remove_watchpoint (CORE_ADDR addr, 
*** 489,495 ****
  {
    int retval;
  
!   if (len == 3 || len > 4 || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type);
    else
      {
--- 505,512 ----
  {
    int retval;
  
!   if ((len != 1 && len !=2 && len !=4 && (TARGET_HAS_DR_LEN_8 && len !=8))
!       || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type);
    else
      {


-- 
Jiri Smid

---------------------------------------------------------------------
SuSE CR, s.r.o.                                 e-mail: smid@suse.cz
Drahobejlova 27                                tel:+420 2 83095 373
190 00 Praha 9                                 fax:+420 2 83095 374
Ceska republika                                http://www.suse.cz


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-11  5:13     ` Jiri Smid
@ 2001-09-11  5:43       ` Eli Zaretskii
  2001-09-12  2:31         ` Jiri Smid
  0 siblings, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2001-09-11  5:43 UTC (permalink / raw)
  To: Jiri Smid; +Cc: gdb-patches, Mark Kettenis

On 11 Sep 2001, Jiri Smid wrote:

> *** 466,472 ****
>   {
>     int retval;
>   
> !   if (len == 3 || len > 4 || addr % len != 0)
>       retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
>     else
>       {
> --- 481,488 ----
>   {
>     int retval;
>   
> !   if ((len != 1 && len !=2 && len !=4 && (TARGET_HAS_DR_LEN_8 && len !=8))
> !       || addr % len != 0)
>       retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
>     else
>       {

Unless I'm missing something, the new code loses if addr and len both 
equal to 3, for a target which does not define TARGET_HAS_DR_LEN_8.  I 
think this is better:

 if ((len != 1 && len !=2 && len !=4 && !(TARGET_HAS_DR_LEN_8 && len ==8))

(There's one more case like this.)

Other than that, I have no comments.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFA]: x86_64 target - multiarch
  2001-09-11  5:43       ` Eli Zaretskii
@ 2001-09-12  2:31         ` Jiri Smid
  0 siblings, 0 replies; 9+ messages in thread
From: Jiri Smid @ 2001-09-12  2:31 UTC (permalink / raw)
  To: gdb-patches; +Cc: Eli Zaretskii

Eli Zaretskii <eliz@is.elta.co.il> writes:

> On 11 Sep 2001, Jiri Smid wrote:
> 
> > *** 466,472 ****
> >   {
> >     int retval;
> >   
> > !   if (len == 3 || len > 4 || addr % len != 0)
> >       retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
> >     else
> >       {
> > --- 481,488 ----
> >   {
> >     int retval;
> >   
> > !   if ((len != 1 && len !=2 && len !=4 && (TARGET_HAS_DR_LEN_8 && len !=8))
> > !       || addr % len != 0)
> >       retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
> >     else
> >       {
> 
> Unless I'm missing something, the new code loses if addr and len both 
> equal to 3, for a target which does not define TARGET_HAS_DR_LEN_8.  I 
> think this is better:
> 
>  if ((len != 1 && len !=2 && len !=4 && !(TARGET_HAS_DR_LEN_8 && len ==8))
> 
> (There's one more case like this.)
> 
> Other than that, I have no comments.

You're right, I only add parentheses to avoid gcc warnings.
(also paddr is used instead of %p as recommended by Andrew Cagney)

OK to commit now?

Index: ChangeLog
from  Jiri Smid   <smid@suse.cz>
	* i386-nat.c (TARGET_HAS_DR_LEN_8, DR_LEN_8): Declare.
	(i386_length_and_rw_bits, i386_handle_nonaligned_watchpoint,
	i386_insert_watchpoint, i386_remove_watchpoint):  Add support for
	8-byte wide watchpoints.
	(i386_show_dr): Debug message format string change.

Index: i386-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-nat.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 i386-nat.c
*** i386-nat.c	2001/04/18 00:37:49	1.3
--- i386-nat.c	2001/09/12 08:01:19
***************
*** 60,65 ****
--- 60,70 ----
  
  #ifdef I386_USE_GENERIC_WATCHPOINTS
  
+ /* Support for 8-byte wide hw watchpoints.  */
+ #ifndef TARGET_HAS_DR_LEN_8
+ #define TARGET_HAS_DR_LEN_8 0
+ #endif
+ 
  /* Debug registers' indices.  */
  #define DR_NADDR		4  /* the number of debug address registers */
  #define DR_STATUS		6  /* index of debug status register (DR6) */
***************
*** 89,94 ****
--- 94,100 ----
  #define DR_LEN_1		(0x0 << 2) /* 1-byte region watch or breakpt */
  #define DR_LEN_2		(0x1 << 2) /* 2-byte region watch */
  #define DR_LEN_4		(0x3 << 2) /* 4-byte region watch */
+ #define DR_LEN_8		(0x2 << 2) /* 8-byte region watch (x86-64) */
  
  /* Local and Global Enable flags in DR7.
  
*************** i386_show_dr (const char *func, CORE_ADD
*** 252,260 ****
  		     dr_control_mirror, dr_status_mirror);
    ALL_DEBUG_REGISTERS(i)
      {
!       printf_unfiltered ("\tDR%d: addr=%08lx, ref.count=%d  DR%d: addr=%08lx, ref.count=%d\n",
! 			 i, dr_mirror[i], dr_ref_count[i],
! 			 i+1, dr_mirror[i+1], dr_ref_count[i+1]);
        i++;
      }
  }
--- 258,266 ----
  		     dr_control_mirror, dr_status_mirror);
    ALL_DEBUG_REGISTERS(i)
      {
!       printf_unfiltered ("\tDR%d: addr=0x%s, ref.count=%d  DR%d: addr=0x%s, ref.count=%d\n",
! 			 i, paddr(dr_mirror[i]), dr_ref_count[i],
! 			 i+1, paddr(dr_mirror[i+1]), dr_ref_count[i+1]);
        i++;
      }
  }
*************** Invalid hw breakpoint type %d in i386_le
*** 291,302 ****
  
    switch (len)
      {
-       case 4:
- 	return (DR_LEN_4 | rw);
-       case 2:
- 	return (DR_LEN_2 | rw);
        case 1:
  	return (DR_LEN_1 | rw);
        default:
  	internal_error (__FILE__, __LINE__, "\
  Invalid hw breakpoint length %d in i386_length_and_rw_bits.\n", len);
--- 297,311 ----
  
    switch (len)
      {
        case 1:
  	return (DR_LEN_1 | rw);
+       case 2:
+ 	return (DR_LEN_2 | rw);
+       case 4:
+ 	return (DR_LEN_4 | rw);
+       case 8:
+         if (TARGET_HAS_DR_LEN_8)
+  	  return (DR_LEN_8 | rw);
        default:
  	internal_error (__FILE__, __LINE__, "\
  Invalid hw breakpoint length %d in i386_length_and_rw_bits.\n", len);
*************** i386_handle_nonaligned_watchpoint (i386_
*** 407,426 ****
    int align;
    int size;
    int rv = 0, status = 0;
  
!   static int size_try_array[4][4] =
    {
!     { 1, 1, 1, 1 },		/* trying size one */
!     { 2, 1, 2, 1 },		/* trying size two */
!     { 2, 1, 2, 1 },		/* trying size three */
!     { 4, 1, 2, 1 }		/* trying size four */
    };
  
    while (len > 0)
      {
!       align = addr % 4;
!       /* Four is the maximum length an x86 debug register can watch.  */
!       size = size_try_array[len > 4 ? 3 : len - 1][align];
        if (what == WP_COUNT)
  	/* size_try_array[] is defined so that each iteration through
  	   the loop is guaranteed to produce an address and a size
--- 416,441 ----
    int align;
    int size;
    int rv = 0, status = 0;
+   int max_wp_len = TARGET_HAS_DR_LEN_8 ? 8 : 4;
  
!   static int size_try_array[8][8] =
    {
!     {1, 1, 1, 1, 1, 1, 1, 1},	/* trying size one */
!     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size two */
!     {2, 1, 2, 1, 2, 1, 2, 1},	/* trying size three */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size four */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size five */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size six */
!     {4, 1, 2, 1, 4, 1, 2, 1},	/* trying size seven */
!     {8, 1, 2, 1, 4, 1, 2, 1},	/* trying size eight */
    };
  
    while (len > 0)
      {
!       align = addr % max_wp_len;
!       /* Four(eigth on x86_64) is the maximum length an x86 debug register
! 	 can watch.  */
!       size = size_try_array[len > max_wp_len ? (max_wp_len - 1) : len - 1][align];
        if (what == WP_COUNT)
  	/* size_try_array[] is defined so that each iteration through
  	   the loop is guaranteed to produce an address and a size
*************** i386_insert_watchpoint (CORE_ADDR addr, 
*** 466,472 ****
  {
    int retval;
  
!   if (len == 3 || len > 4 || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
    else
      {
--- 481,488 ----
  {
    int retval;
  
!   if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8))
!       || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_INSERT, addr, len, type);
    else
      {
*************** i386_remove_watchpoint (CORE_ADDR addr, 
*** 489,495 ****
  {
    int retval;
  
!   if (len == 3 || len > 4 || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type);
    else
      {
--- 505,512 ----
  {
    int retval;
  
!   if (((len != 1 && len !=2 && len !=4) && !(TARGET_HAS_DR_LEN_8 && len == 8))
!       || addr % len != 0)
      retval = i386_handle_nonaligned_watchpoint (WP_REMOVE, addr, len, type);
    else
      {


-- 
Jiri Smid

---------------------------------------------------------------------
SuSE CR, s.r.o.                                 e-mail: smid@suse.cz
Drahobejlova 27                                tel:+420 2 83095 373
190 00 Praha 9                                 fax:+420 2 83095 374
Ceska republika                                http://www.suse.cz


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2001-09-12  2:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-09-05  7:02 [RFA]: x86_64 target - multiarch Jiri Smid
2001-09-05  7:38 ` Eli Zaretskii
2001-09-05 15:31 ` Mark Kettenis
2001-09-05 18:05   ` Andrew Cagney
2001-09-06  0:30   ` Eli Zaretskii
2001-09-11  5:13     ` Jiri Smid
2001-09-11  5:43       ` Eli Zaretskii
2001-09-12  2:31         ` Jiri Smid
2001-09-05 17:55 ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox