This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[PATCH] Update Sparc/Linux support
- From: "David S. Miller" <davem at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Wed, 17 Apr 2002 14:06:29 -0700
- Subject: [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 *) ®s->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 *) ®s->pr_fprs);
+ supply_register (FSR_REGNUM, (char *) ®s->pr_fsr);
+ }
+ else
+ {
+ elf32_fpregset_t *regs = (elf32_fpregset_t *) __fpregsetp;
+
+ for (i = FP0_REGNUM; i < FP0_REGNUM + 32; i++)
+ supply_register (i, (char *) ®s->pr_regs[i - FP0_REGNUM]);
+ supply_register (FPS_REGNUM, (char *) ®s->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 *) ®s->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, ®s->pr_fprs);
+ if (regno == -1 || regno == FSR_REGNUM)
+ regcache_collect (FSR_REGNUM, ®s->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, ®s->pr_regs[i - FP0_REGNUM]);
+
+ if (regno == -1 || regno == FPS_REGNUM)
+ regcache_collect (FPS_REGNUM, ®s->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,
+ ®isters[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),
+ ®isters[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)