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


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

[PATCH] Update Sparc/Linux support



Although this looks like a "jumbo" patch, %99 of it is Linux/Sparc
specific updates and improvements and they really do belong logically
together.  The changes outside of Linux/Sparc specific files are very
small and hopefully easy to understand.

I have a batch of Sparc target generic bug fixes, and those will be
forthcoming after this change set is reviewed/fixed/applied.  Those
bug fixes will include enough to get sparc64 targets passing the same
parts of the testsuite that 32-bit sparc currently does.  They will
not be submitted now because there are large areas of overlap with
these changes.

Brief overview of "why" of the changes:

1) We implement all of the getregs/setregs ptrace calls now in
   sparc-linux-nat.c so that we can handle GDB_MULTI_ARCH correctly
   on native Linux/Sparc.

   This doesn't handle debugging 64-bit native binaries from 32-bit
   GDB, that work will I will do soon.  But debugging 32-bit binaries
   from 64-bit gdb does work.

2) We also do core-file support in sparc-linux-nat.c too.

3) Sparc/Linux has fully working PTRACE_{READDATA,WRITEDATA} so
   implement our own child_xfer_memory() to avoid using the horribly
   inefficient thing found in infptrace.  Watching what happens in
   the infptrace.c version during gdb.base/huge.exp is amusing. :)

4) #1 and #2 makes sparc-nat.o no longer needed under Linux.  This
   file should really be renamed to sparc-bsd-nat.c since that is what
   it really is.  A lot of the __linux__ ifdefs may now be removed
   from sparc-nat.c

   After my upcoming sparc target fixes are installed, I'd be more
   than happy to show someone doing one of the BSD sparc/sparc64
   ports how to make sparc-nat.c handle multi-arch Sparc correctly.

5) Linux/Sparc signal support is added.

6) Linux/Sparc 32-bit has 8 byte long double.  Teach GDB about that.
   Allow this target setting to be computed at run-time.

7) Allow LONGJMP Sparc support vars to be multi-arch'd and all sizes
   determined at runtime.

8) Add ld.so resolve step-over support to Linux/Sparc.

9) Define Linux/Sparc SVR4_FETCH_LINK_MAP_OFFSETS in order to handle
   multi-arch correctly.

   As noted in my comments next to these defines, it would be super
   nice if there was some OS level gdbarch abstraction.  Ie. there
   would be a "target" gdbarch setup and an "os" one.  Currently there
   is only a target level one and this makes overriding things in the
   OS specific areas more difficult in multi-arch configurations than
   it needs to be.

If the person reviewing these changes has any questions, just let
ask away.  I do not have CVS access, so the person who approves this
needs to check it in as well.

Thanks.

2002-04-17  David S. Miller  <davem@redhat.com>

	* config/sparc/linux.mh (NATDEPFILES): Make the list more
	closely resemble how other Linux ports set this for ease
	of maintainence.  Add sparc-linux-nat.o, remove sparc-nat.o.
	* config/sparc/linux.mt (TDEPFILES): Add sparc-linux-tdep.o
	* config/sparc/sp64linux.mt (TDEPFILES): Likewise.
	* sparc-linux-tdep.c: New file.
	* Makefile.in (ALLDEPFILES): Add sparc-linux-tdep.c
	(sparc-linux-tdep.o): Add dependencies.
	(sparc-linux-nat.o): Update dependencies.
	* sparc-linux-nat.c (supply_gregset, fill_gregset,
	supply_fpregset, fill_fpregset): Handle GDB_TARGET_IS_SPARC64.
	(fetch_core_registers, fetch_inferior_registers,
	store_all_registers, store_inferior_registers,
	sparc_linux_core_fns, _initialize_core_sparc_linux,
	child_xfer_memory): New functions.
	* config/sparc/tm-sparc.h (SPARC_TARGET_LONG_DOUBLE_SZ): Defines
	size of long double, default to 16.  Target specific headers may
	override.
	* config/sparc/nm-linux.h (CHILD_PREPARE_TO_STORE,
	PTRACE_ARG3_TYPE, PTRACE_XFER_TYPE): Define.
	(KERNEL_U_SIZE, kernel_u_size): Remove, unreferenced.
	* config/sparc/tm-linux.h (GDB_MULTI_ARCH): Set to
	GDB_MULTI_ARCH_PARTIAL.
	(SPARC_TARGET_LONG_DOUBLE_SZ): Re-define to 8.
	(LONGJMP_TARGET_SIZE, JB_PC, JB_ELEMENT_SIZE, GET_LONGJMP_TARGET,
	IN_SIGTRAMP, FRAME_SAVED_PC, FRAME_CHAIN, SAVED_PC_AFTER_CALL,
	SKIP_SOLIB_RESOLVER, SKIP_PROLOGUE_FRAMELESS_P,
	SVR4_FETCH_LINK_MAP_OFFSETS): Define.
	(get_longjmp_target, sparc_linux_in_sigtramp,
	sparc_linux_frame_saved_pc, sparc_linux_frame_chain,
	sparc_linux_saved_pc_after_call, sparc_linux_skip_solib_resolver,
	sparc_linux_skip_prologue_frameless_p,
	sparc_linux_svr4_fetch_link_map_offsets): Declare.
	* config/sparc/tm-sp64linux.h (GDB_MULTI_ARCH): Don't define, let
	tm-sparc64.h do it.
	(tm-sysv4.h): Don't include.
	(tm-linux.h): Include this instead.
	(LONGJMP_TARGET_SIZE, JB_PC, JB_ELEMENT_SIZE, GET_LONGJMP_TARGET,
	IN_SIGTRAMP, FRAME_SAVED_PC, FRAME_CHAIN, SAVED_PC_AFTER_CALL,
	SKIP_SOLIB_RESOLVER, SKIP_PROLOGUE_FRAMELESS_P,
	SVR4_FETCH_LINK_MAP_OFFSETS): Define.
	(get_longjmp_target, sparc_linux_in_sigtramp,
	sparc_linux_frame_saved_pc, sparc_linux_frame_chain,
	sparc_linux_saved_pc_after_call, sparc_linux_skip_solib_resolver,
	sparc_linux_skip_prologue_frameless_p,
	sparc_linux_svr4_fetch_link_map_offsets): Declare.
	* sparc-tdep.c (get_longjmp_target): Alloc LONGJMP_TARGET_SIZE to
	be defined by target headers.  Allow it to be run-time computed
	by using alloca() for 'buf'.
	(sparc64_push_arguments): Verify SPARC_TARGET_LONG_DOUBLE_SIZE.
	(sparc_gdbarch_init): Use SPARC_TARGET_LONG_DOUBLE_SZ.  Don't
	call set_gdbarch_long_double_bit until GDB_TARGET_IS_SPARC64
	value is stabilized.
	
--- ./config/sparc/linux.mh.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/linux.mh	Tue Apr 16 10:58:53 2002
@@ -3,9 +3,9 @@
 XM_FILE= xm-linux.h
 
 NAT_FILE= nm-linux.h
-NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o sparc-nat.o \
-	proc-service.o thread-db.o lin-lwp.o sparc-linux-nat.o \
-	linux-proc.o gcore.o 
+NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o linux-proc.o \
+	sparc-linux-nat.o \
+	proc-service.o thread-db.o lin-lwp.o linux-proc.o gcore.o 
 
 # The dynamically loaded libthread_db needs access to symbols in the
 # gdb executable.
--- ./config/sparc/linux.mt.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/linux.mt	Tue Apr 16 10:58:53 2002
@@ -1,3 +1,3 @@
 # Target: Sparcstation, running Linux
-TDEPFILES= sparc-tdep.o solib.o solib-svr4.o solib-legacy.o
+TDEPFILES= sparc-tdep.o sparc-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
 TM_FILE= tm-linux.h
--- ./config/sparc/nm-linux.h.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/nm-linux.h	Tue Apr 16 10:58:53 2002
@@ -26,7 +26,20 @@
 
 #define FETCH_INFERIOR_REGISTERS
 
-/* Return sizeof user struct to callers in less machine dependent routines */
+/* Before storing, we need to read all the registers.
 
-#define KERNEL_U_SIZE kernel_u_size()
-extern int kernel_u_size (void);
+   This would be needed even if ptrace provided a way to read/write
+   one register at a time.  The reason is that if you change the value
+   of SP_REGNUM, you have to read in the local/in registers first.
+   These registers are saved in memory on the stack on Sparc, not in
+   the ptrace save area.  */
+
+#define CHILD_PREPARE_TO_STORE() read_register_bytes (0, NULL, REGISTER_BYTES)
+
+#define PTRACE_ARG3_TYPE long
+
+#ifdef __arch64__
+#define PTRACE_XFER_TYPE long
+#endif
+
+#define CHILD_XFER_MEMORY
--- ./config/sparc/sp64linux.mt.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/sp64linux.mt	Tue Apr 16 10:58:53 2002
@@ -1,3 +1,3 @@
 # Target: UltraSPARC, running Linux 64bit programs
-TDEPFILES= sparc-tdep.o solib.o solib-svr4.o solib-legacy.o
+TDEPFILES= sparc-tdep.o sparc-linux-tdep.o solib.o solib-svr4.o solib-legacy.o
 TM_FILE= tm-sp64linux.h
--- ./config/sparc/tm-linux.h.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/tm-linux.h	Tue Apr 16 10:58:53 2002
@@ -23,10 +23,58 @@
 #ifndef TM_SPARCLINUX_H
 #define TM_SPARCLINUX_H
 
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_PARTIAL
+
 #include "sparc/tm-sparc.h"
 
-#define SIGCONTEXT_PC_OFFSET 12
+#undef SPARC_TARGET_LONG_DOUBLE_SZ
+#define SPARC_TARGET_LONG_DOUBLE_SZ 8
 
 #include "tm-linux.h"
+
+#define LONGJMP_TARGET_SIZE 4
+#define JB_PC 2
+#define JB_ELEMENT_SIZE 4
+
+extern int get_longjmp_target (CORE_ADDR *);
+#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
+
+/* When the sparc Linux kernel calls a signal handler, the return
+   address points to a bit of code on the stack.  These definitions
+   are used to identify this bit of code as a signal trampoline in
+   order to support backtracing through calls to signal handlers.  */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(frame) sparc_linux_frame_saved_pc (frame)
+extern CORE_ADDR sparc_linux_frame_saved_pc (struct frame_info *frame);
+
+#define FRAME_CHAIN(THISFRAME) (sparc_linux_frame_chain (THISFRAME))
+extern CORE_ADDR sparc_linux_frame_chain (struct frame_info *);
+
+#undef SAVED_PC_AFTER_CALL
+#define SAVED_PC_AFTER_CALL(frame) sparc_linux_saved_pc_after_call (frame)
+extern CORE_ADDR sparc_linux_saved_pc_after_call (struct frame_info *);
+
+/* When we call a function in a shared library, and the PLT sends us
+   into the dynamic linker to find the function's real address, we
+   need to skip over the dynamic linker call.  This function decides
+   when to skip, and where to skip to.  See the comments for
+   SKIP_SOLIB_RESOLVER at the top of infrun.c.  */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
+
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
+
+/* ??? Should be doing this with gdbarch but that is not easy from
+   ??? ${cpu}-${os}-tdep.c files currently.  */
+
+extern struct link_map_offsets *sparc_linux_svr4_fetch_link_map_offsets (void);
+#define SVR4_FETCH_LINK_MAP_OFFSETS() \
+  sparc_linux_svr4_fetch_link_map_offsets ()
 
 #endif /* TM_SPARCLINUX_H */
--- ./config/sparc/tm-sp64linux.h.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/tm-sp64linux.h	Tue Apr 16 10:58:53 2002
@@ -21,11 +21,22 @@ Foundation, Inc., 59 Temple Place - Suit
 #ifndef TM_SPARC_LIN64_H
 #define TM_SPARC_LIN64_H
 
-#define GDB_MULTI_ARCH 0
-
 #include "sparc/tm-sp64.h"
 
-#define SIGCONTEXT_PC_OFFSET 16  /* See asm-sparc64/sigcontext.h */
+#undef LONGJMP_TARGE_TSIZE
+#define LONGJMP_TARGET_SIZE (GDB_TARGET_IS_SPARC64 ? 8 : 4)
+
+#undef JB_PC
+#define JB_PC (GDB_TARGET_IS_SPARC64 ? 24 : 2)
+
+#undef JB_ELEMENT_SIZE
+#define JB_ELEMENT_SIZE (GDB_TARGET_IS_SPARC64 ? 8 : 4)
+
+#undef GET_LONGJMP_TARGET
+#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
+extern int get_longjmp_target (CORE_ADDR *);
+
+#define SIGCONTEXT_PC_OFFSET (128 + (16 * 8) + 8)  /* See asm-sparc64/sigcontext.h */
 
 /* We always want full V9 + Ultra VIS stuff... */
 #undef TM_PRINT_INSN_MACH
@@ -33,6 +44,44 @@ Foundation, Inc., 59 Temple Place - Suit
 
 #define GDB_PTRACE_REGS64
 
-#include "tm-sysv4.h"
+#include "tm-linux.h"
+
+/* When the sparc Linux kernel calls a signal handler, the return
+   address points to a bit of code on the stack.  These definitions
+   are used to identify this bit of code as a signal trampoline in
+   order to support backtracing through calls to signal handlers.  */
+
+#define IN_SIGTRAMP(pc, name) sparc_linux_in_sigtramp (pc, name)
+extern int sparc_linux_in_sigtramp (CORE_ADDR, char *);
+
+#undef FRAME_SAVED_PC
+#define FRAME_SAVED_PC(frame) sparc_linux_frame_saved_pc (frame)
+extern CORE_ADDR sparc_linux_frame_saved_pc (struct frame_info *frame);
+
+#define FRAME_CHAIN(THISFRAME) (sparc_linux_frame_chain (THISFRAME))
+extern CORE_ADDR sparc_linux_frame_chain (struct frame_info *);
+
+#undef SAVED_PC_AFTER_CALL
+#define SAVED_PC_AFTER_CALL(frame) sparc_linux_saved_pc_after_call (frame)
+extern CORE_ADDR sparc_linux_saved_pc_after_call (struct frame_info *);
+
+/* When we call a function in a shared library, and the PLT sends us
+   into the dynamic linker to find the function's real address, we
+   need to skip over the dynamic linker call.  This function decides
+   when to skip, and where to skip to.  See the comments for
+   SKIP_SOLIB_RESOLVER at the top of infrun.c.  */
+#define SKIP_SOLIB_RESOLVER sparc_linux_skip_solib_resolver
+extern CORE_ADDR sparc_linux_skip_solib_resolver (CORE_ADDR pc);
+
+#undef SKIP_PROLOGUE_FRAMELESS_P
+#define SKIP_PROLOGUE_FRAMELESS_P(PC) sparc_linux_skip_prologue_frameless_p (PC)
+extern CORE_ADDR sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc);
+
+/* ??? Should be doing this with gdbarch but that is not easy from
+   ??? ${cpu}-${os}-tdep.c files currently.  */
+
+extern struct link_map_offsets *sparc_linux_svr4_fetch_link_map_offsets (void);
+#define SVR4_FETCH_LINK_MAP_OFFSETS() \
+  sparc_linux_svr4_fetch_link_map_offsets ()
 
-#endif TM_SPARC_LIN64_H
+#endif /* TM_SPARC_LIN64_H */
--- ./config/sparc/tm-sparc.h.~1~	Tue Apr 16 10:56:47 2002
+++ ./config/sparc/tm-sparc.h	Tue Apr 16 10:58:53 2002
@@ -325,6 +325,11 @@ extern int sparc_npc_regnum (void);
 extern int sparc_y_regnum (void);
 
 #endif /* GDB_MULTI_ARCH */
+
+/* Long-double's are 16-bytes on most platforms, but this can be
+   overridden.  */
+
+#define SPARC_TARGET_LONG_DOUBLE_SZ 16
 
 /* On the Sun 4 under SunOS, the compile will leave a fake insn which
    encodes the structure size being returned.  If we detect such
--- ./sparc-linux-nat.c.~1~	Tue Apr 16 10:56:47 2002
+++ ./sparc-linux-nat.c	Tue Apr 16 10:58:53 2002
@@ -21,80 +21,914 @@
 
 #include "defs.h"
 #include "regcache.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "inferior.h"
+#include "target.h"
    
 #include <sys/procfs.h>
+#include <sys/ptrace.h>
+
+#include <asm/unistd.h>
 
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
+typedef unsigned long long elf64_greg_t;
+typedef elf64_greg_t elf64_gregset_t[36];
+typedef unsigned int elf32_greg_t;
+typedef elf32_greg_t elf32_gregset_t[38];
+
+static elf64_greg_t
+tstate_to_ccr(elf64_greg_t tstate)
+{
+	return (tstate >> 32) & 0xff;
+}
+
+static elf64_greg_t
+ccr_to_tstate(elf64_greg_t ccr)
+{
+	return (ccr & 0xffULL) << 32;
+}
+
 void
-supply_gregset (elf_gregset_t *gregsetp)
+supply_gregset (gdb_gregset_t *__gregsetp)
 {
-  elf_greg_t *regp = (elf_greg_t *) gregsetp;
-  int i;
+  if (GDB_TARGET_IS_SPARC64)
+    {
+      elf64_greg_t *regp = (elf64_greg_t *) __gregsetp;
+      elf64_greg_t ccr;
+      int i;
+
+      for (i = G0_REGNUM; i <= I7_REGNUM; i++)
+	supply_register (i, (char *) (regp + (i - G0_REGNUM)));
+
+      ccr = tstate_to_ccr(regp[32]);
+      supply_register (CCR_REGNUM, (char *) &ccr);
+      supply_register (PC_REGNUM, (char *) (regp + 33));
+      supply_register (NPC_REGNUM, (char *) (regp + 34));
+      supply_register (Y_REGNUM, (char *) (regp + 35));
+
+      /* ??? We could be clever and derive these from other sources
+	 ??? such as tstate, but that causes testsuite failures
+	 ??? because things like sparc_pop_frame would need to do such
+	 ??? derivations too.  */
+      for (i = FPRS_REGNUM; i <= FCC3_REGNUM; i++)
+	supply_register (i, NULL);
+    }
+  else
+    {
+      elf32_greg_t *regp = (elf32_greg_t *) __gregsetp;
+      int i;
+
+      for (i = G0_REGNUM; i <= I7_REGNUM; i++)
+	supply_register (i, (char *) (regp + (i - G0_REGNUM)));
+
+      supply_register (PS_REGNUM, (char *) (regp + 32));
+
+      supply_register (PC_REGNUM, (char *) (regp + 33));
+      supply_register (NPC_REGNUM, (char *) (regp + 34));
+      supply_register (Y_REGNUM, (char *) (regp + 35));
+
+      /* Fill inaccessible registers with zero.  */
+      supply_register (WIM_REGNUM, NULL);
+      supply_register (TBR_REGNUM, NULL);
+      supply_register (CPS_REGNUM, NULL);
+    }
+}
 
-  for (i = G0_REGNUM; i <= I7_REGNUM; i++)
-    supply_register (i, (char *) (regp + (i - G0_REGNUM)));
+void
+fill_gregset (gdb_gregset_t *__gregsetp, int regno)
+{
+  int i;
 
-  supply_register (PS_REGNUM, (char *) (regp + 32));
+  if (GDB_TARGET_IS_SPARC64)
+    {
+      elf64_greg_t *regp = (elf64_greg_t *) __gregsetp;
+      elf64_greg_t ccr;
+
+      for (i = G0_REGNUM; i <= I7_REGNUM; i++)
+	if (regno == -1 || regno == i)
+	  regcache_collect (i, regp + (i - G0_REGNUM));
+
+      if (regno == -1 || regno == CCR_REGNUM)
+	{
+	  regcache_collect (CCR_REGNUM, &ccr);
+	  regp[32] = ccr_to_tstate(ccr);
+	}
+
+      if (regno == -1 || regno == PC_REGNUM)
+	regcache_collect (PC_REGNUM, regp + 33);
+      if (regno == -1 || regno == NPC_REGNUM)
+	regcache_collect (NPC_REGNUM, regp + 34);
+      if (regno == -1 || regno == Y_REGNUM)
+	regcache_collect (Y_REGNUM, regp + 35);
+    }
+  else
+    {
+      elf32_greg_t *regp = (elf32_greg_t *) __gregsetp;
+
+      for (i = G0_REGNUM; i <= I7_REGNUM; i++)
+	if (regno == -1 || regno == i)
+	  regcache_collect (i, regp + (i - G0_REGNUM));
+
+      if (regno == -1 || regno == PS_REGNUM)
+	regcache_collect (PS_REGNUM, regp + 32);
+
+      if (regno == -1 || regno == PC_REGNUM)
+	regcache_collect (PC_REGNUM, regp + 33);
+      if (regno == -1 || regno == NPC_REGNUM)
+	regcache_collect (NPC_REGNUM, regp + 34);
+      if (regno == -1 || regno == Y_REGNUM)
+	regcache_collect (Y_REGNUM, regp + 35);
+    }
+}
 
-  supply_register (PC_REGNUM, (char *) (regp + 33));
-  supply_register (NPC_REGNUM, (char *) (regp + 34));
-  supply_register (Y_REGNUM, (char *) (regp + 35));
+typedef struct {
+  unsigned long long pr_regs[32];
+  unsigned long long pr_fsr;
+  unsigned long long pr_gsr;
+  unsigned long long pr_fprs;
+} elf64_fpregset_t;
+
+typedef struct {
+  unsigned int pr_regs[32];
+  unsigned int __unused;
+  unsigned int pr_fsr;
+  unsigned int pr_qcnt;
+  unsigned int pr_q_entrysize;
+  unsigned int pr_en;
+  unsigned int pr_q[64];
+} elf32_fpregset_t;
 
-  supply_register (WIM_REGNUM, (char *) (regp + 36));
-  supply_register (TBR_REGNUM, (char *) (regp + 37));
+void
+supply_fpregset (gdb_fpregset_t *__fpregsetp)
+{
+  int i;
 
-  /* Fill inaccessible registers with zero.  */
-  supply_register (CPS_REGNUM, NULL);
+  if (GDB_TARGET_IS_SPARC64)
+    {
+      elf64_fpregset_t *regs = (elf64_fpregset_t *) __fpregsetp;
+      unsigned int *fp_single = (unsigned int *) &regs->pr_regs[0];
+      unsigned long long *fp_double = (unsigned long long *) &fp_single[32];
+
+      for (i = 0; i < 32; i++)
+	supply_register (i + FP0_REGNUM, (char *) &fp_single[i]);
+      for (i = 0; i < 16; i++)
+	supply_register (i + FP0_REGNUM + 32, (char *) &fp_double[i]);
+
+      /* XXX No GSR_REGNUM */
+      supply_register (FPRS_REGNUM, (char *) &regs->pr_fprs);
+      supply_register (FSR_REGNUM, (char *) &regs->pr_fsr);
+    }
+  else
+    {
+      elf32_fpregset_t *regs = (elf32_fpregset_t *) __fpregsetp;
+
+      for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
+	supply_register (i, (char *) &regs->pr_regs[i - FP0_REGNUM]);
+      supply_register (FPS_REGNUM, (char *) &regs->pr_fsr);
+    }
 }
 
 void
-fill_gregset (elf_gregset_t *gregsetp, int regno)
+fill_fpregset (gdb_fpregset_t *__fpregsetp, int regno)
 {
-  elf_greg_t *regp = (elf_greg_t *) gregsetp;
   int i;
 
-  for (i = G0_REGNUM; i <= I7_REGNUM; i++)
-    if (regno == -1 || regno == i)
-      regcache_collect (i, regp + (i - G0_REGNUM));
+  if (GDB_TARGET_IS_SPARC64)
+    {
+      elf64_fpregset_t *regs = (elf64_fpregset_t *) __fpregsetp;
+      unsigned int *fp_single = (unsigned int *) &regs->pr_regs[0];
+      unsigned long long *fp_double = (unsigned long long *) &fp_single[32];
+
+      for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
+	if (regno == -1 || regno == i)
+	  regcache_collect (i, (char *) &fp_single[i - FP0_REGNUM]);
+      for (i = FP0_REGNUM + 32; i < FP0_REGNUM + 32 + 16; i++)
+	if (regno == -1 || regno == i)
+	  regcache_collect (i, (char *) &fp_double[i - (FP0_REGNUM + 32)]);
+
+      /* XXX No GSR_REGNUM */
+
+      if (regno == -1 || regno == FPRS_REGNUM)
+	regcache_collect (FPRS_REGNUM, &regs->pr_fprs);
+      if (regno == -1 || regno == FSR_REGNUM)
+	regcache_collect (FSR_REGNUM, &regs->pr_fsr);
+    }
+  else
+    {
+      elf32_fpregset_t *regs = (elf32_fpregset_t *) __fpregsetp;
+
+      for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
+	if (regno == -1 || regno == i)
+	  regcache_collect (i, &regs->pr_regs[i - FP0_REGNUM]);
+
+      if (regno == -1 || regno == FPS_REGNUM)
+	regcache_collect (FPS_REGNUM, &regs->pr_fsr);
+    }
+}
+
+/*  Use a local version of this function to get the correct types for
+    regsets, until multi-arch core support is ready.  */
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
+		      int which, CORE_ADDR reg_addr)
+{
+
+  if (which == 0)
+    {
+      if (GDB_TARGET_IS_SPARC64)
+	{
+	  elf64_gregset_t gregset;
+
+	  memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
+	  supply_gregset ((gdb_gregset_t *) &gregset);
+	}
+      else
+	{
+	  elf32_gregset_t gregset;
+
+	  memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
+	  supply_gregset ((gdb_gregset_t *) &gregset);
+	}
+    }
+  else if (which == 2)
+    {
+      if (GDB_TARGET_IS_SPARC64)
+	{
+	  elf64_fpregset_t fpregset;
+
+	  memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
+	  supply_fpregset ((gdb_fpregset_t *) &fpregset);
+	}
+      else
+	{
+	  elf32_fpregset_t fpregset;
+
+	  memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
+	  supply_fpregset ((gdb_fpregset_t *) &fpregset);
+	}
+    }
+}
+
+/* Size of a general (integer) register: */
+extern int sparc_intreg_size (void);
+#define SPARC_INTREG_SIZE (sparc_intreg_size ())
+
+static elf32_greg_t
+tstate_to_psr(elf64_greg_t tstate)
+{
+  return ((tstate & 0x1f) |
+	  0x80 |
+	  ((tstate & (elf64_greg_t)0x0f00000000) >> 12) |
+	  ((tstate & (elf64_greg_t)0xf000000000) >> 20) |
+	  0xff000000);
+}
 
-  if (regno == -1 || regno == PS_REGNUM)
-    regcache_collect (PS_REGNUM, regp + 32);
+static elf64_greg_t
+psr_to_tstate_icc(elf32_greg_t psr)
+{
+  elf64_greg_t tstate = ((elf64_greg_t)(psr & 0x00f00000)) << 12;
 
-  if (regno == -1 || regno == PC_REGNUM)
-    regcache_collect (PC_REGNUM, regp + 33);
-  if (regno == -1 || regno == NPC_REGNUM)
-    regcache_collect (NPC_REGNUM, regp + 34);
-  if (regno == -1 || regno == Y_REGNUM)
-    regcache_collect (Y_REGNUM, regp + 35);
+  if ((psr & (0xffffffff)) == 0xff000000)
+    tstate |= ((elf64_greg_t)(psr & 0x000f0000)) << 20;
 
-  if (regno == -1 || regno == WIM_REGNUM)
-    regcache_collect (WIM_REGNUM, regp + 36);
-  if (regno == -1 || regno == TBR_REGNUM)
-    regcache_collect (TBR_REGNUM, regp + 37);
+  return tstate;
 }
 
+struct pt64_regs
+{
+  elf64_greg_t	u_regs[16];
+  elf64_greg_t	tstate;
+  elf64_greg_t	tpc;
+  elf64_greg_t	tnpc;
+  elf32_greg_t	y;
+  elf32_greg_t	fprs;
+};
+
+struct pt32_regs
+{
+  elf32_greg_t	psr;
+  elf32_greg_t	pc;
+  elf32_greg_t	npc;
+  elf32_greg_t	y;
+  elf32_greg_t	u_regs[16];
+};
+
+#define UREG_G1        0
+#define UREG_G2        1
+#define UREG_G3        2
+#define UREG_G4        3
+#define UREG_G5        4
+#define UREG_G6        5
+#define UREG_G7        6
+#define UREG_O0        7
+#define UREG_O1        8
+#define UREG_O2        9
+#define UREG_O3        10
+#define UREG_O4        11
+#define UREG_O5        12
+#define UREG_O6        13
+#define UREG_O7        14
+
+struct pt64_fpregs
+{
+  elf32_greg_t	regs[64];
+  elf64_greg_t	fsr;
+};
+
+struct pt32_fpregs
+{
+  elf32_greg_t	regs[32];
+  elf32_greg_t	fsr;
+  elf32_greg_t	flags;
+  elf32_greg_t	extra;
+  elf32_greg_t	fpqd;
+  struct fpu_fq {
+    elf32_greg_t	insnaddr;
+    elf32_greg_t	insn;
+  } fpq[16];
+};
+
 void
-supply_fpregset (elf_fpregset_t *fpregsetp)
+fetch_inferior_registers (int regno)
+{
+  int intreg_size = SPARC_INTREG_SIZE;
+  int proc_id, i;
+  char *buf;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  if ((proc_id = TIDGET (inferior_ptid)) == 0)
+    proc_id = PIDGET (inferior_ptid);		/* Not a threaded program.  */
+
+  if (sizeof (void *) == 8)
+    {
+      union {
+	struct pt64_regs regs;
+	struct pt64_fpregs fpregs;
+      } u;
+      int offset = (intreg_size == 4) ? 4 : 0;
+
+      if (regno <= O7_REGNUM
+	  || (regno >= Y_REGNUM && regno != FSR_REGNUM)
+	  || (!register_cached (SP_REGNUM) && regno <= I7_REGNUM))
+	{
+	  if (0 != ptrace (PTRACE_GETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_getregs");
+
+	  supply_register (G0_REGNUM, NULL);
+	  if (regno == -1)
+	    {
+	      for (i = G1_REGNUM; i < G1_REGNUM + 15; i++)
+		{
+		  char *regptr = (char *)&u.regs.u_regs[i - G1_REGNUM + UREG_G1];
+
+		  regptr += offset;
+		  supply_register (i, regptr);
+		}
+	    }
+	  else if (regno >= G1_REGNUM && regno < G1_REGNUM + 15)
+	    {
+	      char *regptr = (char *)&u.regs.u_regs[regno - G1_REGNUM + UREG_G1];
+
+	      regptr += offset;
+	      supply_register (regno, regptr);
+	    }
+	  else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+	    {
+	      char *regptr = (char *)&u.regs.u_regs[SP_REGNUM - G1_REGNUM + UREG_G1];
+
+	      regptr += offset;
+	      supply_register (SP_REGNUM, regptr);
+	    }
+
+	  if (regno == -1 ||
+	      (! GDB_TARGET_IS_SPARC64 && regno == PS_REGNUM) ||
+	      (GDB_TARGET_IS_SPARC64 && regno == CCR_REGNUM))
+	    {
+	      if (! GDB_TARGET_IS_SPARC64)
+		{
+		  elf32_greg_t psr_convert = tstate_to_psr(u.regs.tstate);
+		  supply_register (PS_REGNUM, (char *) &psr_convert);
+		}
+	      else
+		{
+		  elf64_greg_t ccr_convert = tstate_to_ccr(u.regs.tstate);
+		  supply_register (CCR_REGNUM, (char *) &ccr_convert);
+		}
+	    }
+	  if (regno == -1 || regno == PC_REGNUM)
+	    supply_register (PC_REGNUM, ((char *) &u.regs.tpc) + offset);
+	  if (regno == -1 || regno == NPC_REGNUM)
+	    supply_register (NPC_REGNUM, ((char *) &u.regs.tnpc) + offset);
+	  if (regno == -1 || regno == Y_REGNUM)
+	    supply_register (Y_REGNUM, ((char *) &u.regs.y) + offset);
+
+	  if (regno == -1)
+	    {
+	      if (! GDB_TARGET_IS_SPARC64)
+		{
+		  supply_register (WIM_REGNUM, NULL);
+		  supply_register (TBR_REGNUM, NULL);
+		  supply_register (CPS_REGNUM, NULL);
+		}
+	      else
+		{
+		  for (i = FPRS_REGNUM; i <= FCC3_REGNUM; i++)
+		    supply_register (i, NULL);
+		}
+	    }
+	}
+
+      if (regno == -1 ||
+	  (! GDB_TARGET_IS_SPARC64 && regno == FPS_REGNUM) ||
+	  (GDB_TARGET_IS_SPARC64   && regno == FSR_REGNUM) ||
+	  (regno >= FP0_REGNUM
+	   && regno < FP0_REGNUM + ((GDB_TARGET_IS_SPARC64) ? 48 : 32)))
+	{
+	  elf64_greg_t *fp_double = (elf64_greg_t *)&u.fpregs.regs[32];
+
+	  if (0 != ptrace (PTRACE_GETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_getfpregs");
+
+	  if (regno == -1)
+	    {
+	      if (GDB_TARGET_IS_SPARC64)
+		{
+		  for (i = 0; i < 32; i++)
+		    supply_register (FP0_REGNUM + i, (char *) &u.fpregs.regs[i]);
+		  for (i = 0; i < 16; i++)
+		    supply_register (FP0_REGNUM + i + 32, (char *) &fp_double[i]);
+		  supply_register (FSR_REGNUM, (char *) &u.fpregs.fsr);
+		}
+	      else
+		{
+		  for (i = 0; i < 32; i++)
+		    supply_register (FP0_REGNUM + i, (char *)&u.fpregs.regs[i]);
+		  supply_register (FPS_REGNUM, ((char *) &u.fpregs.fsr) + offset);
+		}
+	    }
+	  else
+	    {
+	      if (regno >= FP0_REGNUM && regno < (FP0_REGNUM + 32))
+		supply_register (regno, (char *) &u.fpregs.regs[regno - FP0_REGNUM]);
+	      else if (regno >= FP0_REGNUM + 32
+		       && regno < FP0_REGNUM + 48)
+		supply_register (regno, (char *) &fp_double[regno - 32 - FP0_REGNUM]);
+	      else if (GDB_TARGET_IS_SPARC64)
+		supply_register (FSR_REGNUM, (char *) &u.fpregs.fsr);
+	      else
+		supply_register (FPS_REGNUM, ((char *) &u.fpregs.fsr) + offset);
+	    }
+	}
+    }
+  else
+    {
+      union {
+	struct pt32_regs regs;
+	struct pt32_fpregs fpregs;
+      } u;
+
+      if (regno <= O7_REGNUM
+	  || regno >= Y_REGNUM
+	  || (!register_cached (SP_REGNUM) && regno <= I7_REGNUM))
+	{
+	  if (0 != ptrace (PTRACE_GETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_getregs");
+
+	  supply_register (G0_REGNUM, NULL);
+	  if (regno == -1)
+	    {
+	      for (i = G1_REGNUM; i < G1_REGNUM + 15; i++)
+		{
+		  char *regptr = (char *)&u.regs,u_regs[i - G1_REGNUM + UREG_G1];
+
+		  supply_register (i, regptr);
+		}
+	    }
+	  else if (regno >= G1_REGNUM && regno < G1_REGNUM + 15)
+	    {
+	      char *regptr = (char *)&u.regs.u_regs[regno - G1_REGNUM + UREG_G1];
+
+	      supply_register (regno, regptr);
+	    }
+	  else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+	    {
+	      char *regptr = (char *)&u.regs.u_regs[SP_REGNUM - G1_REGNUM + UREG_G1];
+
+	      supply_register (SP_REGNUM, regptr);
+	    }
+
+	  if (regno == -1 || regno == PS_REGNUM)
+	    supply_register (PS_REGNUM, (char *) &u.regs.psr);
+	  if (regno == -1 || regno == PC_REGNUM)
+	    supply_register (PC_REGNUM, (char *) &u.regs.pc);
+	  if (regno == -1 || regno == NPC_REGNUM)
+	    supply_register (NPC_REGNUM, (char *) &u.regs.npc);
+	  if (regno == -1 || regno == Y_REGNUM)
+	    supply_register (Y_REGNUM, (char *) &u.regs.y);
+
+	  if (regno == -1)
+	    {
+	      supply_register (WIM_REGNUM, NULL);
+	      supply_register (TBR_REGNUM, NULL);
+	      supply_register (CPS_REGNUM, NULL);
+	    }
+	}
+
+      if (regno == -1 ||
+	  regno == FPS_REGNUM ||
+	  (regno >= FP0_REGNUM
+	   && regno < FP0_REGNUM + 32))
+	{
+	  if (0 != ptrace (PTRACE_GETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_getfpregs");
+
+	  if (regno == -1)
+	    {
+	      for (i = 0; i < 32; i++)
+		supply_register (FP0_REGNUM + i, (char *)&u.fpregs.regs[i]);
+	      supply_register (FPS_REGNUM, (char *) &u.fpregs.fsr);
+	    }
+	  else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+	    {
+	      supply_register (regno, (char *)&u.fpregs.regs[regno - FP0_REGNUM]);
+	    }
+	  else
+	    supply_register (FPS_REGNUM, (char *) &u.fpregs.fsr);
+	}
+    }
+
+  if (regno == -1)
+    {
+      buf = alloca (16 * intreg_size);
+      target_read_memory (read_sp (), buf, 16 * intreg_size);
+      for (i = 0; i <= (I7_REGNUM - L0_REGNUM); i++)
+	supply_register (i + L0_REGNUM,
+			 buf + (i * intreg_size));
+    }
+  else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+    {
+      buf = alloca (intreg_size);
+      target_read_memory (read_sp () + REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM),
+			  buf, intreg_size);
+      supply_register (regno, buf);
+    }
+}
+
+static void
+store_all_registers (int proc_id)
 {
   int i;
 
-  for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
-    supply_register (i, (char *) &fpregsetp->pr_fr.pr_regs[i - FP0_REGNUM]);
+  if (sizeof (void *) == 8)
+    {
+      union {
+	struct pt64_regs regs;
+	struct pt64_fpregs fpregs;
+      } u;
+      int offset = (SPARC_INTREG_SIZE == 4) ? 4 : 0;
+
+      for (i = G1_REGNUM; i < G0_REGNUM + 16; i++)
+	{
+	  char *regptr = ((char *)&u.regs.u_regs[i - G1_REGNUM + UREG_G1]);
+
+	  if (offset != 0)
+	    memset (regptr, 0, sizeof(elf64_greg_t));
+	  regptr += offset;
+	  read_register_gen (i, regptr);
+	}
+      if (! GDB_TARGET_IS_SPARC64)
+	{
+	  elf32_greg_t tmp32;
+
+	  read_register_gen (PS_REGNUM, (char *) &tmp32);
+	  u.regs.tstate = psr_to_tstate_icc(tmp32);
+
+	  read_register_gen (PC_REGNUM, (char *) &tmp32);
+	  u.regs.tpc = tmp32;
+
+	  read_register_gen (NPC_REGNUM, (char *) &tmp32);
+	  u.regs.tnpc = tmp32;
+
+	  read_register_gen (Y_REGNUM, (char *) &tmp32);
+	  u.regs.y = tmp32;
+	}
+      else
+	{
+	  elf64_greg_t ccr;
+
+	  read_register_gen(CCR_REGNUM, (char *) &ccr);
+	  u.regs.tstate = ccr_to_tstate(ccr);
+
+	  read_register_gen(PC_REGNUM, (char *) &u.regs.tpc);
+	  read_register_gen(NPC_REGNUM, (char *) &u.regs.tnpc);
+	  read_register_gen(Y_REGNUM, (char *) &u.regs.y);
+	}
+
+      if (0 != ptrace (PTRACE_SETREGS, proc_id,
+		       (PTRACE_ARG3_TYPE) &u.regs, 0))
+	perror ("ptrace_setregs");
+
+      for (i = 0; i < 32; i++)
+	read_register_gen (FP0_REGNUM + i, (char *) &u.fpregs.regs[i]);
+      if (GDB_TARGET_IS_SPARC64)
+	{
+	  elf64_greg_t *fp_double = (elf64_greg_t *) &u.fpregs.regs[32];
+	  for (i = 0; i < 16; i++)
+	    read_register_gen (FP0_REGNUM + 32 + i, (char *) &fp_double[i]);
+	  read_register_gen (FSR_REGNUM, (char *) &u.fpregs.fsr);
+	}
+      else
+	read_register_gen (FPS_REGNUM, ((char *) &u.fpregs.fsr) + offset);
+
+      if (0 != ptrace (PTRACE_SETFPREGS, proc_id,
+		       (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	perror ("ptrace_setfpregs");
+    }
+  else
+    {
+      union {
+	struct pt32_regs regs;
+	struct pt32_fpregs fpregs;
+      } u;
+
+      for (i = G1_REGNUM; i < G0_REGNUM + 16; i++)
+	{
+	  char *regptr = ((char *)&u.regs.u_regs[i - G1_REGNUM + UREG_G1]);
+
+	  read_register_gen (i, regptr);
+	}
+      read_register_gen(PS_REGNUM, (char *) &u.regs.psr);
+      read_register_gen(PC_REGNUM, (char *) &u.regs.pc);
+      read_register_gen(NPC_REGNUM, (char *) &u.regs.npc);
+      read_register_gen(Y_REGNUM, (char *) &u.regs.y);
+
+      if (0 != ptrace (PTRACE_SETREGS, proc_id,
+		       (PTRACE_ARG3_TYPE) &u.regs, 0))
+	perror ("ptrace_setregs");
+
+      for (i = 0; i < 32; i++)
+	read_register_gen (FP0_REGNUM + i, (char *) &u.fpregs.regs[i]);
+      read_register_gen (FPS_REGNUM, (char *) &u.fpregs.fsr);
+
+      if (0 != ptrace (PTRACE_SETFPREGS, proc_id,
+		       (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	perror ("ptrace_setfpregs");
+    }
+}
 
-  supply_register (FPS_REGNUM, (char *) &fpregsetp->pr_fsr);
+void
+store_inferior_registers (int regno)
+{
+  int intreg_size = SPARC_INTREG_SIZE;
+  int proc_id, i, store_mask;
+  char *buf;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  if ((proc_id = TIDGET (inferior_ptid)) == 0)
+    proc_id = PIDGET (inferior_ptid);		/* Not a threaded program.  */
+
+  if (regno == G1_REGNUM)
+    return;
+
+  if (regno < 0 || regno == SP_REGNUM)
+    {
+      CORE_ADDR sp = read_sp ();
+
+      if (!register_cached(L0_REGNUM + 5))
+	internal_error (__FILE__, __LINE__, "failed internal consistency check");
+      target_write_memory (sp,
+			   &registers[REGISTER_BYTE (L0_REGNUM)],
+			   16 * intreg_size);
+    }
+  else if (regno >= L0_REGNUM && regno <= I7_REGNUM)
+    {
+      CORE_ADDR sp = read_sp ();
+
+      if (!register_cached(regno))
+	internal_error (__FILE__, __LINE__, "failed internal consistency check");
+      target_write_memory (sp + REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM),
+			   &registers[REGISTER_BYTE (regno)],
+			   intreg_size);
+      return;
+    }
+
+  if (regno < 0)
+    {
+      store_all_registers (proc_id);
+      return;
+    }
+
+  if (sizeof (void *) == 8)
+    {
+      union {
+	struct pt64_regs regs;
+	struct pt64_fpregs fpregs;
+      } u;
+      int offset = (intreg_size == 4) ? 4 : 0;
+
+      if (regno <= O7_REGNUM
+	  || (regno >= Y_REGNUM && regno != FSR_REGNUM))
+	{
+	  if (0 != ptrace (PTRACE_GETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_getregs");
+
+	  if (regno >= G1_REGNUM && regno <= O7_REGNUM)
+	    {
+	      char *regptr = (char *) &u.regs.u_regs[regno - G1_REGNUM + UREG_G1];
+
+	      if (offset != 0)
+		memset (regptr, 0, sizeof(elf64_greg_t));
+	      regptr += offset;
+	      read_register_gen(regno, regptr);
+	    }
+	  if (! GDB_TARGET_IS_SPARC64)
+	    {
+	      elf32_greg_t tmp32;
+
+	      if (regno == PS_REGNUM)
+		{
+		  read_register_gen (PS_REGNUM, (char *) &tmp32);
+		  u.regs.tstate = psr_to_tstate_icc(tmp32);
+		}
+	      if (regno == PC_REGNUM)
+		{
+		  read_register_gen (PC_REGNUM, (char *) &tmp32);
+		  u.regs.tpc = tmp32;
+		}
+	      if (regno == NPC_REGNUM)
+		{
+		  read_register_gen (NPC_REGNUM, (char *) &tmp32);
+		  u.regs.tnpc = tmp32;
+		}
+	      if (regno == Y_REGNUM)
+		{
+		  read_register_gen (Y_REGNUM, (char *) &tmp32);
+		  u.regs.y = tmp32;
+		}
+	    }
+	  else
+	    {
+	      if (regno == CCR_REGNUM)
+		{
+		  elf64_greg_t ccr;
+
+		  read_register_gen (CCR_REGNUM, (char *) &ccr);
+		  u.regs.tstate = ccr_to_tstate(ccr);
+		}
+	      if (regno == PC_REGNUM)
+		read_register_gen (PC_REGNUM, (char *) &u.regs.tpc);
+	      if (regno == NPC_REGNUM)
+		read_register_gen (NPC_REGNUM, (char *) &u.regs.tnpc);
+	      if (regno == Y_REGNUM)
+		read_register_gen (Y_REGNUM, (char *) &u.regs.y);
+	    }
+
+	  if (0 != ptrace (PTRACE_SETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_setregs");
+	}
+      else
+	{
+	  if (0 != ptrace (PTRACE_GETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_getfpregs");
+
+	  if (GDB_TARGET_IS_SPARC64)
+	    {
+	      if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+		read_register_gen (regno, (char *) &u.fpregs.regs[regno - FP0_REGNUM]);
+	      else if (regno >= FP0_REGNUM + 32 && regno < FP0_REGNUM + 48)
+		{
+		  elf64_greg_t *fp_double = (elf64_greg_t *) &u.fpregs.regs[32];
+		  read_register_gen (regno,
+				     (char *) &fp_double[regno - (FP0_REGNUM + 32)]);
+		}
+	      else if (regno == FSR_REGNUM)
+		read_register_gen (FSR_REGNUM, (char *) &u.fpregs.fsr);
+	    }
+	  else
+	    {
+	      if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+		read_register_gen (regno, (char *) &u.fpregs.regs[regno - FP0_REGNUM]);
+	      else if (regno == FPS_REGNUM)
+		read_register_gen (FPS_REGNUM, ((char *) &u.fpregs.fsr) + offset);
+	    }
+
+	  if (0 != ptrace (PTRACE_SETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_setfpregs");
+	}
+    }
+  else
+    {
+      union {
+	struct pt32_regs regs;
+	struct pt32_fpregs fpregs;
+      } u;
+
+      if (regno <= O7_REGNUM
+	  || (regno >= Y_REGNUM && regno != FPS_REGNUM))
+	{
+	  if (0 != ptrace (PTRACE_GETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_getregs");
+
+	  if (regno >= G1_REGNUM && regno <= O7_REGNUM)
+	    {
+	      char *regptr = (char *) &u.regs.u_regs[regno - G1_REGNUM + UREG_G1];
+
+	      read_register_gen(regno, regptr);
+	    }
+	  if (regno == PS_REGNUM)
+	    read_register_gen (PS_REGNUM, (char *) &u.regs.psr);
+	  if (regno == PC_REGNUM)
+	    read_register_gen (PC_REGNUM, (char *) &u.regs.pc);
+	  if (regno == NPC_REGNUM)
+	    read_register_gen (NPC_REGNUM, (char *) &u.regs.npc);
+	  if (regno == Y_REGNUM)
+	    read_register_gen (Y_REGNUM, (char *) &u.regs.y);
+
+	  if (0 != ptrace (PTRACE_SETREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.regs, 0))
+	    perror ("ptrace_setregs");
+	}
+      else
+	{
+	  if (0 != ptrace (PTRACE_GETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_getfpregs");
+
+	  if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32)
+	    read_register_gen (regno, (char *) &u.fpregs.regs[regno - FP0_REGNUM]);
+	  else if (regno == FPS_REGNUM)
+	    read_register_gen (FPS_REGNUM, (char *) &u.fpregs.fsr);
+
+	  if (0 != ptrace (PTRACE_SETFPREGS, proc_id,
+			   (PTRACE_ARG3_TYPE) &u.fpregs, 0))
+	    perror ("ptrace_setfpregs");
+	}
+    }
 }
 
+/* Register that we are able to handle ELF file formats using standard
+   procfs "regset" structures.  */
+
+static struct core_fns sparc_linux_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 */
+};
+
 void
-fill_fpregset (elf_fpregset_t *fpregsetp, int regno)
+_initialize_core_sparc_linux (void)
 {
-  int i;
+  add_core_fns (&sparc_linux_core_fns);
+}
+
+/* Oh well, glibc's Linux ptrace() implementation does not understand
+   the 5-arg calls that we need here.  */
+#define __NR_ptrace_syscall __NR_ptrace
+_syscall5(int,ptrace_syscall,int,req,int,pid,unsigned long,memaddr,int,len,char *,myaddr)
+
+/* PTRACE_{READ,WRITE}DATA works under Sparc GNU/Linux and it is sooooo much
+   faster than what infptrace.c does.  For example, using infptrace.c
+   the test gdb.base/huge.exp can take forever, with this code it is nearly
+   instantaneous.  */
+
+int
+child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
+		   struct mem_attrib *attrib, struct target_ops *target)
+{
+  int proc_id, err;
+
+  if ((proc_id = TIDGET (inferior_ptid)) == 0)
+    proc_id = PIDGET (inferior_ptid);		/* Not a threaded program.  */
+
+  errno = 0;
+
+  if (write)
+    {
+      ptrace_syscall (PTRACE_WRITEDATA, proc_id, memaddr, len, myaddr);
+    }
+  else
+    {
+      ptrace_syscall (PTRACE_READDATA, proc_id, memaddr, len, myaddr);
+    }
 
-  for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
-    if (regno == -1 || regno == i)
-      regcache_collect (i, &fpregsetp->pr_fr.pr_regs[i - FP0_REGNUM]);
+  if (errno)
+    return 0;
 
-  if (regno == -1 || regno == FPS_REGNUM)
-    regcache_collect (FPS_REGNUM, &fpregsetp->pr_fsr);
+  return len;
 }
--- ./sparc-tdep.c.~1~	Tue Apr 16 10:56:47 2002
+++ ./sparc-tdep.c	Tue Apr 16 10:58:53 2002
@@ -1720,8 +1720,12 @@
 get_longjmp_target (CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
+#ifndef LONGJMP_TARGET_SIZE
 #define LONGJMP_TARGET_SIZE 4
-  char buf[LONGJMP_TARGET_SIZE];
+#endif
+  char *buf;
+
+  buf = alloca(LONGJMP_TARGET_SIZE);
 
   jb_addr = read_register (O0_REGNUM);
 
@@ -2382,9 +2386,12 @@
 		register_counter += 1;
 		break;
 	      case 16:	/* Quad-precision (long double) */
-		fpreg = FP0_REGNUM + 2 * register_counter;
-		register_counter += 2;
-		break;
+		if (SPARC_TARGET_LONG_DOUBLE_SZ == 16)
+		  {
+		    fpreg = FP0_REGNUM + 2 * register_counter;
+		    register_counter += 2;
+		    break;
+		  }
 	      default:
 		internal_error (__FILE__, __LINE__, "bad switch");
 	      }
@@ -2970,7 +2977,6 @@
   set_gdbarch_init_extra_frame_info (gdbarch, sparc_init_extra_frame_info);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
-  set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
   set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
   set_gdbarch_max_register_raw_size (gdbarch, 8);
   set_gdbarch_max_register_virtual_size (gdbarch, 8);
@@ -3114,6 +3120,9 @@
       tdep->call_dummy_call_offset = 148 + 4 * 5;
       break;
     }
+
+  set_gdbarch_long_double_bit (gdbarch,
+			       SPARC_TARGET_LONG_DOUBLE_SZ * TARGET_CHAR_BIT);
 
   /* 
    * Settings that vary per-architecture:
--- ./sparc-linux-tdep.c.~1~	Tue Apr 16 10:59:01 2002
+++ ./sparc-linux-tdep.c	Tue Apr 16 10:58:53 2002
@@ -0,0 +1,474 @@
+/* Target-dependent code for GNU/Linux running on Sparc's, for GDB.
+
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "inferior.h"
+#include "obstack.h"
+#include "target.h"
+#include "value.h"
+#include "bfd.h"
+#include "gdb_string.h"
+#include "regcache.h"
+
+#include "gdbcore.h"
+
+/* For sparc_linux_skip_solib_resolver.  */
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+
+#include "solib-svr4.h"		/* For struct link_map_offsets.  */
+
+/* Recognizing signal handler frames.  */
+
+/* GNU/Linux has two flavors of signals.  Normal signal handlers, and
+   "realtime" (RT) signals.  The RT signals can provide additional
+   information to the signal handler if the SA_SIGINFO flag is set
+   when establishing a signal handler using `sigaction'.  It is not
+   unlikely that future versions of GNU/Linux will support SA_SIGINFO
+   for normal signals too.  */
+
+/* When the sparc Linux kernel calls a signal handler and the
+   SA_RESTORER flag isn't set, the return address points to a bit of
+   code on the stack.  This function returns whether the PC appears to
+   be within this bit of code.
+
+   The instruction sequence for normal signals is
+	mov __NR_sigreturn, %g1		! hex: 0x821020d8
+	ta  0x10			! hex: 0x91d02010
+
+   Checking for the code sequence should be somewhat reliable, because
+   the effect is to call the system call sigreturn.  This is unlikely
+   to occur anywhere other than a signal trampoline.
+
+   It kind of sucks that we have to read memory from the process in
+   order to identify a signal trampoline, but there doesn't seem to be
+   any other way.  The IN_SIGTRAMP macro in tm-linux.h arranges to
+   only call us if no function name could be identified, which should
+   be the case since the code is on the stack.  */
+
+#define LINUX_SIGTRAMP_WORD0	(0x821020d8)	/* mov __NR_sigreturn, %g1 */
+#define LINUX_SIGTRAMP_WORD1	(0x91d02010)	/* ta  0x10 */
+
+#define LINUX_SIGTRAMP_LEN	(0x8)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+   the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sparc_linux_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned int buf[LINUX_SIGTRAMP_LEN / sizeof(unsigned int)];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the three instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_SIGTRAMP_WORD0)
+    {
+      if (buf[0] != LINUX_SIGTRAMP_WORD1)
+	return 0;
+
+      pc -= 4;
+
+      if (read_memory_nobpt(pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+	return 0;
+    }
+
+  if (buf[0] != LINUX_SIGTRAMP_WORD0
+      || buf[1] != LINUX_SIGTRAMP_WORD1)
+    return 0;
+
+  return pc;
+}
+
+/* This function does the same for RT signals.  Here the instruction
+   sequence is
+       mov __NR_rt_sigreturn, %g1	! hex: 0x82102065
+       ta  {0x10,0x6d}			! hex: 0x91d02010 or 0x91d0206d
+
+   The effect is to call the system call rt_sigreturn.  The trap number
+   is variable based upon whether this is a 32-bit or 64-bit sparc binary.
+   Note that 64-bit binaries only use this RT signal return method.  */
+
+#define LINUX_RT_SIGTRAMP_WORD0		(0x82102065)
+#define LINUX_RT_SIGTRAMP_WORD1_32	(0x91d02010)
+#define LINUX_RT_SIGTRAMP_WORD1_64	(0x91d0206d)
+
+#define LINUX_RT_SIGTRAMP_LEN		8
+
+/* If PC is in a RT sigtramp routine, return the address of the start
+   of the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+sparc_linux_rt_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned int buf[LINUX_RT_SIGTRAMP_LEN / sizeof(unsigned int)];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the two instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_WORD0)
+    {
+      if (buf[0] != LINUX_RT_SIGTRAMP_WORD1_32
+	  && buf[0] != LINUX_RT_SIGTRAMP_WORD1_64)
+	return 0;
+
+      pc -= 4;
+
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+	return 0;
+    }
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_WORD0
+      || (buf[1] != LINUX_RT_SIGTRAMP_WORD1_32
+	  && buf[1] != LINUX_RT_SIGTRAMP_WORD1_64))
+    return 0;
+
+  return pc;
+}
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.  */
+
+int
+sparc_linux_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  int ret;
+
+  if (name)
+    ret = (STREQ ("__sigreturn_stub", name) || STREQ ("__rt_sigreturn_stub", name));
+  else
+    ret = (sparc_linux_sigtramp_start (pc) != 0
+	   || sparc_linux_rt_sigtramp_start (pc) != 0);
+
+  return ret;
+}
+
+/* Size of a general (integer) register: */
+extern int sparc_intreg_size (void);
+#define SPARC_INTREG_SIZE  sparc_intreg_size ()
+
+/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
+   PC/SP of the associated sigcontext structure.  */
+
+static CORE_ADDR
+sparc_linux_sigtramp_saved_pc (struct frame_info *frame)
+{
+  CORE_ADDR ret;
+  char *buf;
+
+  if (!frame->next)
+    return 0;
+
+  buf = alloca(SPARC_INTREG_SIZE);
+
+  if (sparc_linux_sigtramp_start (frame->pc) != 0)
+    {
+      /* Stack frame is:
+           standard 32-bit register window + slack	96 bytes
+           siginfo_t					PC at offset 4  */
+
+      read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+
+      ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+      return ret;
+    }
+
+  if (sparc_linux_rt_sigtramp_start (frame->pc) != 0)
+    {
+      /* For 32-bit task, same as non-rt frame.  For 64-bit task
+	 the layout is:
+	      standard 64-bit register window + slack	192 bytes
+	      siginfo_t					128 bytes
+	      pt_regs					PC at offset 136  */
+      if (! GDB_TARGET_IS_SPARC64)
+	{
+	  read_memory(frame->next->frame + (96 + 4), buf, SPARC_INTREG_SIZE);
+	}
+      else
+	{
+	  read_memory(frame->next->frame + (192 + 128 + 136), buf, SPARC_INTREG_SIZE);
+	}
+
+      ret = PC_ADJUST (extract_address (buf, SPARC_INTREG_SIZE));
+
+      return ret;
+    }
+
+  error ("Couldn't recognize signal trampoline.");
+  return 0;
+}
+
+extern CORE_ADDR sparc_frame_chain (struct frame_info *);
+
+CORE_ADDR
+sparc_linux_frame_chain (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return frame->frame;
+
+  return sparc_frame_chain (frame);
+}
+
+extern CORE_ADDR sparc_frame_saved_pc (struct frame_info *);
+
+/* Return the saved program counter for FRAME.  */
+
+CORE_ADDR
+sparc_linux_frame_saved_pc (struct frame_info *frame)
+{
+  CORE_ADDR ret;
+
+  if (frame->signal_handler_caller)
+    ret = sparc_linux_sigtramp_saved_pc (frame);
+  else
+    ret = sparc_frame_saved_pc (frame);
+
+  return ret;
+}
+
+CORE_ADDR
+sparc_linux_saved_pc_after_call (struct frame_info *frame)
+{
+  CORE_ADDR ret;
+
+  if (frame->signal_handler_caller)
+    ret = sparc_linux_sigtramp_saved_pc (frame);
+  else
+    ret = sparc_pc_adjust (read_register (RP_REGNUM));
+
+  return ret;
+}
+
+/* Calling functions in shared libraries.  */
+
+/* Find the minimal symbol named NAME, and return both the minsym
+   struct and its objfile.  This probably ought to be in minsym.c, but
+   everything there is trying to deal with things like C++ and
+   SOFUN_ADDRESS_MAYBE_TURQUOISE, ...  Since this is so simple, it may
+   be considered too special-purpose for general consumption.  */
+
+static struct minimal_symbol *
+find_minsym_and_objfile (char *name, struct objfile **objfile_p)
+{
+  struct objfile *objfile;
+
+  ALL_OBJFILES (objfile)
+    {
+      struct minimal_symbol *msym;
+
+      ALL_OBJFILE_MSYMBOLS (objfile, msym)
+	{
+	  if (SYMBOL_NAME (msym)
+	      && STREQ (SYMBOL_NAME (msym), name))
+	    {
+	      *objfile_p = objfile;
+	      return msym;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+static CORE_ADDR
+skip_hurd_resolver (CORE_ADDR pc)
+{
+  /* The HURD dynamic linker is part of the GNU C library, so many
+     GNU/Linux distributions use it.  (All ELF versions, as far as I
+     know.)  An unresolved PLT entry points to "_dl_runtime_resolve",
+     which calls "fixup" to patch the PLT, and then passes control to
+     the function.
+
+     We look for the symbol `_dl_runtime_resolve', and find `fixup' in
+     the same objfile.  If we are at the entry point of `fixup', then
+     we set a breakpoint at the return address (at the top of the
+     stack), and continue.
+  
+     It's kind of gross to do all these checks every time we're
+     called, since they don't change once the executable has gotten
+     started.  But this is only a temporary hack --- upcoming versions
+     of GNU/Linux will provide a portable, efficient interface for
+     debugging programs that use shared libraries.  */
+
+  struct objfile *objfile;
+  struct minimal_symbol *resolver 
+    = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
+
+  if (resolver)
+    {
+      struct minimal_symbol *fixup
+	= lookup_minimal_symbol ("fixup", NULL, objfile);
+
+      if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+	return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+
+      fixup = lookup_minimal_symbol("profile_fixup", NULL, objfile);
+      if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
+	return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+    }
+
+  return 0;
+}      
+
+/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
+   This function:
+   1) decides whether a PLT has sent us into the linker to resolve
+      a function reference, and 
+   2) if so, tells us where to set a temporary breakpoint that will
+      trigger when the dynamic linker is done.  */
+
+CORE_ADDR
+sparc_linux_skip_solib_resolver (CORE_ADDR pc)
+{
+  CORE_ADDR result;
+
+  /* Plug in functions for other kinds of resolvers here.  */
+  result = skip_hurd_resolver (pc);
+  if (result)
+    return result;
+
+  return 0;
+}
+
+/* We need special processing here because 'fixup' in the dynamic linker
+   looks like it is frameless, but it really does get a frame from its
+   caller in the PLT (which does save).
+
+   Actually, any piece of code which has the same pettern, ie.:
+
+	place1:		save
+			call place2
+			 nop
+
+	place2:		call place3
+			 nop
+			jmp  %reg
+			restore
+
+	place3:		save
+			...
+			ret
+			 restore
+
+   is going to confuse SKIP_PROLOGUE_FRAMELESS_P.  It is hard to
+   formulate a generic fix for this that would not break on sibcalls.  */
+
+CORE_ADDR
+sparc_linux_skip_prologue_frameless_p (CORE_ADDR pc)
+{
+  struct objfile *objfile;
+  struct minimal_symbol *resolver 
+    = find_minsym_and_objfile ((GDB_TARGET_IS_SPARC64 ?
+				"_dl_runtime_resolve_0" :
+				"_dl_runtime_resolve"), &objfile);
+
+  if (resolver)
+    {
+      CORE_ADDR rpc = SYMBOL_VALUE_ADDRESS (resolver);
+      int resolver_size = 0x60;
+
+      /* This size includes all of the resolver instances present.
+	 For example on sparc32 it includes _dl_runtime_resolve
+	 and _dl_profile_resolve, and on sparc64 it includes
+	 _dl_runtime_resolve_0 _dl_runtime_resolve_1 and
+	 _dl_profile_resolve.  It works because they are present
+	 one right after another in the dynamic linker.  */
+      if (GDB_TARGET_IS_SPARC64)
+	resolver_size = 0x100;
+
+      if (pc >= rpc && pc < (rpc + resolver_size))
+	return pc + 4;
+    }
+  return sparc_skip_prologue (pc, 1);
+}
+
+/* Fetch (and possibly build) an appropriate link_map_offsets
+   structure for native GNU/Linux Sparc targets using the struct offsets
+   defined in link.h (but without actual reference to that file).
+
+   This makes it possible to access GNU/Linux Sparc shared libraries from a
+   GDB that was built on a different host platform (for cross debugging).
+
+   It also is needed to handle GDB multi-arch properly.  */
+
+struct link_map_offsets *
+sparc_linux_svr4_fetch_link_map_offsets (void)
+{ 
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    { 
+      lmp = &lmo;
+
+      if (! GDB_TARGET_IS_SPARC64)
+	{
+	  lmo.r_debug_size = 8;	/* The actual size is 20 bytes, but
+				   this is all we need.  */
+	  lmo.r_map_offset = 4;
+	  lmo.r_map_size   = 4;
+	  lmo.link_map_size = 20;
+	  lmo.l_addr_offset = 0;
+	  lmo.l_addr_size   = 4;
+	  lmo.l_name_offset = 4;
+	  lmo.l_name_size   = 4;
+	  lmo.l_next_offset = 12;
+	  lmo.l_next_size   = 4;
+	  lmo.l_prev_offset = 16;
+	  lmo.l_prev_size   = 4;
+	}
+      else
+	{
+	  lmo.r_debug_size = 16; /* The actual size is 40 bytes, but
+				    this is all we need.  */
+	  lmo.r_map_offset = 8;
+	  lmo.r_map_size   = 8;
+	  lmo.link_map_size = 40;
+	  lmo.l_addr_offset = 0;
+	  lmo.l_addr_size   = 8;
+	  lmo.l_name_offset = 8;
+	  lmo.l_name_size   = 8;
+	  lmo.l_next_offset = 24;
+	  lmo.l_next_size   = 8;
+	  lmo.l_prev_offset = 32;
+	  lmo.l_prev_size   = 8;
+	}
+    }
+
+  return lmp;
+}
--- ./Makefile.in.~1~	Tue Apr 16 10:58:53 2002
+++ ./Makefile.in	Tue Apr 16 11:03:02 2002
@@ -1213,7 +1213,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 2
 	ser-go32.c ser-pipe.c ser-tcp.c \
 	sh-tdep.c solib.c solib-svr4.c solib-sunos.c sparc-linux-nat.c \
 	sparc-nat.c \
-	sparc-tdep.c sparcl-tdep.c sun3-nat.c \
+	sparc-tdep.c sparcl-tdep.c sparc-linux-tdep.c sun3-nat.c \
 	symm-tdep.c symm-nat.c \
 	vax-tdep.c \
 	vx-share/xdr_ld.c vx-share/xdr_ptrace.c vx-share/xdr_rdb.c \
@@ -2046,7 +2046,13 @@
 	$(symtab_h) $(gdb_string_h) $(source_h) $(completer_h) $(linespec_h) \
 	$(ui_out_h)
 
-sparc-linux-nat.o: sparc-linux-nat.c $(defs_h) $(regcache_h)
+sparc-linux-nat.o: sparc-linux-nat.c $(defs_h) $(regcache_h) $(gdbcore_h) \
+	$(gdb_string_h) $(inferior_h) $(target_h) gregset.h
+
+sparc-linux-tdep.o: sparc-linux-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) \
+	$(inferior_h) $(obstack_h) $(target_h) $(value_h) $(bfd_h) \
+	$(gdb_string_h) $(regcache_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \
+	$(objdiles_h) $(solib_svr4_h)
 
 sparc-nat.o: sparc-nat.c $(bfd_h) $(defs_h) $(inferior_h) $(gdbcore_h) \
 	$(target_h) $(regcache_h)


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