diff options
-rw-r--r-- | gdb/ChangeLog | 36 | ||||
-rw-r--r-- | gdb/sparc-linux-tdep.c | 34 | ||||
-rw-r--r-- | gdb/sparc-nat.c | 122 | ||||
-rw-r--r-- | gdb/sparc-nat.h | 40 | ||||
-rw-r--r-- | gdb/sparc-sol2-nat.c | 10 | ||||
-rw-r--r-- | gdb/sparc-tdep.c | 22 | ||||
-rw-r--r-- | gdb/sparc-tdep.h | 23 |
7 files changed, 236 insertions, 51 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 56ea4484497..a0b79e692dd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,41 @@ 2003-11-02 Mark Kettenis <kettenis@gnu.org> + * sparc-tdep.h (struct sparc_gregset): Add r_y_size member. + (sparc32_supply_gregset): Renamed from sparc_supply_gregset. + (sparc32_collect_gregset): Renamed from sparc_collect_gregset. + (sparc32_supply_fpregset): Renamed from sparc_supply_fpregset. + (sparc32_collect_fpregset): Renamed from sparc_collect_fpregset. + * sparc-tdep.c (sparc32_supply_gregset): Renamed from + sparc_supply_gregset. + (sparc32_collect_gregset): Renamed from sparc_collect_gregset. + (sparc32_supply_fpregset): Renamed from sparc_supply_fpregset. + (sparc32_collect_fpregset): Renamed from sparc_collect_fpregset. + * sparc-linux-tdep.c: Include "solib-svr4.h". + (sparc32_linux_svr4_fetch_link_map_offsets): New function. + (sparc32_linux_init_abi): Set solib_svr4_fetch_link_map_offsets. + * sparc-nat.h: New file. + * sparc-nat.c: Add some more comments. Include "sparc-nat.h". + (PTRACE_GETREGS): Define to PT_GETREGS if not already defined. + (PTRACE_SETREGS, PTRACE_GETFPREGS, PTRACE_SETFPREGS): Likewise. + (sparc_supply_gregset, sparc_collect_gregset, + sparc_supply_fpregset, sparc_collect_fpregset, + sparc_gregset_supplies_p, sparc_fpregset_supplies_p): New function + variables. + (sparc32_gregset_supplies_p): Rename from + sparc_gregset_supplies_p. + (sparc32_fpregset_supplies_p): Rename from + sparc_fpregset_supplies_p. + (fetch_inferior_registers): Deal with GNU/Linux LWPs. + (store_inferior_registers): Likewise. Work around peculiarity in + NetBSD when writing the floating-point registers. + (_initialize_sparc_nat): Initialize sparc_supply_gregset, + sparc_collect_gregset, sparc_supply_fpregset, + sparc_collect_fpregset, sparc_gregset_supplies_p and + sparc_fpregset_supplies_p if necessary. + * sparc-sol2-nat.c (supply_gregset): Call sparc32_supply_gregset + instead of sparc_supply_gregset. + (supply_fpregset, fill_gregset, fill_fpregset): Likewise. + * config/sparc/nm-linux.h (PTRACE_ARG3_TYPE, PTRACE_XFER_TYPE): Define. diff --git a/gdb/sparc-linux-tdep.c b/gdb/sparc-linux-tdep.c index 3ba72f68908..e3643f82a91 100644 --- a/gdb/sparc-linux-tdep.c +++ b/gdb/sparc-linux-tdep.c @@ -22,9 +22,40 @@ #include "defs.h" #include "gdbarch.h" #include "osabi.h" +#include "solib-svr4.h" #include "sparc-tdep.h" +static struct link_map_offsets * +sparc32_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; + + /* Everything we need is in the first 8 bytes. */ + lmo.r_debug_size = 8; + lmo.r_map_offset = 4; + lmo.r_map_size = 4; + + /* Everything we need is in the first 20 bytes. */ + 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; + } + + return lmp; +} + static void sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -33,6 +64,9 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* ... but doesn't have kernel-assisted single-stepping support. */ set_gdbarch_software_single_step (gdbarch, sparc_software_single_step); + + set_solib_svr4_fetch_link_map_offsets + (gdbarch, sparc32_linux_svr4_fetch_link_map_offsets); } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/sparc-nat.c b/gdb/sparc-nat.c index bbf2b4e5b07..09ee7c6471b 100644 --- a/gdb/sparc-nat.c +++ b/gdb/sparc-nat.c @@ -23,7 +23,22 @@ #include "inferior.h" #include "regcache.h" -/* We need a data structure for use with ptrace(2). SunOS 4 has +#include <signal.h> +#include "gdb_string.h" +#include <sys/ptrace.h> +#include "gdb_wait.h" +#ifdef HAVE_MACHINE_REG_H +#include <machine/reg.h> +#endif + +#include "sparc-tdep.h" +#include "sparc-nat.h" + +/* With some trickery we can use the code in this file for most (if + not all) ptrace(2) based SPARC systems, which includes SunOS 4, + Linux and the various SPARC BSD's. + + First, we need a data structure for use with ptrace(2). SunOS has `struct regs' and `struct fp_status' in <machine/reg.h>. BSD's have `struct reg' and `struct fpreg' in <machine/reg.h>. GNU/Linux has the same structures as SunOS 4, but they're in <asm/reg.h>, @@ -35,11 +50,7 @@ typedefs, providing them for the other systems, therefore solves the puzzle. */ -#include <signal.h> -#include <sys/ptrace.h> -#include "gdb_wait.h" #ifdef HAVE_MACHINE_REG_H -#include <machine/reg.h> #ifdef HAVE_STRUCT_REG typedef struct reg gregset_t; typedef struct fpreg fpregset_t; @@ -49,15 +60,40 @@ typedef struct fp_status fpregset_t; #endif #endif -#include "sparc-tdep.h" +/* Second, we need to remap the BSD ptrace(2) requests to their SunOS + equivalents. GNU/Linux already follows SunOS here. */ + +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS PT_GETREGS +#endif + +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS PT_SETREGS +#endif + +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS PT_GETFPREGS +#endif + +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS PT_SETFPREGS +#endif /* Register set description. */ const struct sparc_gregset *sparc_gregset; +void (*sparc_supply_gregset) (const struct sparc_gregset *, + struct regcache *, int , const void *); +void (*sparc_collect_gregset) (const struct sparc_gregset *, + const struct regcache *, int, void *); +void (*sparc_supply_fpregset) (struct regcache *, int , const void *); +void (*sparc_collect_fpregset) (const struct regcache *, int , void *); +int (*sparc_gregset_supplies_p) (int); +int (*sparc_fpregset_supplies_p) (int); /* Determine whether `gregset_t' contains register REGNUM. */ int -sparc_gregset_supplies_p (int regnum) +sparc32_gregset_supplies_p (int regnum) { /* Integer registers. */ if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM) @@ -78,8 +114,8 @@ sparc_gregset_supplies_p (int regnum) /* Determine whether `fpregset_t' contains register REGNUM. */ -static int -sparc_fpregset_supplies_p (int regnum) +int +sparc32_fpregset_supplies_p (int regnum) { /* Floating-point registers. */ if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM) @@ -99,6 +135,24 @@ void fetch_inferior_registers (int regnum) { struct regcache *regcache = current_regcache; + int pid; + + /* NOTE: cagney/2002-12-03: This code assumes that the currently + selected light weight processes' registers can be written + directly into the selected thread's register cache. This works + fine when given an 1:1 LWP:thread model (such as found on + GNU/Linux) but will, likely, have problems when used on an N:1 + (userland threads) or N:M (userland multiple LWP) model. In the + case of the latter two, the LWP's registers do not necessarily + belong to the selected thread (the LWP could be in the middle of + executing the thread switch code). + + These functions should instead be paramaterized with an explicit + object (struct regcache, struct thread_info?) into which the LWPs + registers can be written. */ + pid = TIDGET (inferior_ptid); + if (pid == 0) + pid = PIDGET (inferior_ptid); if (regnum == SPARC_G0_REGNUM) { @@ -110,8 +164,7 @@ fetch_inferior_registers (int regnum) { gregset_t regs; - if (ptrace (PTRACE_GETREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) ®s, 0) == -1) + if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) ®s, 0) == -1) perror_with_name ("Couldn't get registers"); sparc_supply_gregset (sparc_gregset, regcache, -1, ®s); @@ -123,8 +176,7 @@ fetch_inferior_registers (int regnum) { fpregset_t fpregs; - if (ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) + if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) perror_with_name ("Couldn't get floating point status"); sparc_supply_fpregset (regcache, -1, &fpregs); @@ -135,19 +187,24 @@ void store_inferior_registers (int regnum) { struct regcache *regcache = current_regcache; + int pid; + + /* NOTE: cagney/2002-12-02: See comment in fetch_inferior_registers + about threaded assumptions. */ + pid = TIDGET (inferior_ptid); + if (pid == 0) + pid = PIDGET (inferior_ptid); if (regnum == -1 || sparc_gregset_supplies_p (regnum)) { gregset_t regs; - if (ptrace (PTRACE_GETREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) ®s, 0) == -1) + if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) ®s, 0) == -1) perror_with_name ("Couldn't get registers"); sparc_collect_gregset (sparc_gregset, regcache, regnum, ®s); - if (ptrace (PTRACE_SETREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) ®s, 0) == -1) + if (ptrace (PTRACE_SETREGS, pid, (PTRACE_ARG3_TYPE) ®s, 0) == -1) perror_with_name ("Couldn't write registers"); /* Deal with the stack regs. */ @@ -166,17 +223,24 @@ store_inferior_registers (int regnum) if (regnum == -1 || sparc_fpregset_supplies_p (regnum)) { - fpregset_t fpregs; + fpregset_t fpregs, saved_fpregs; - if (ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) + if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) perror_with_name ("Couldn't get floating-point registers"); + memcpy (&saved_fpregs, &fpregs, sizeof (fpregs)); sparc_collect_fpregset (regcache, regnum, &fpregs); - if (ptrace (PTRACE_SETFPREGS, PIDGET (inferior_ptid), - (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) - perror_with_name ("Couldn't write floating-point registers"); + /* Writing the floating-point registers will fail on NetBSD with + EINVAL if the inferior process doesn't have an FPU state + (i.e. if it didn't use the FPU yet). Therefore we don't try + to write the registers if nothing changed. */ + if (memcmp (&saved_fpregs, &fpregs, sizeof (fpregs)) != 0) + { + if (ptrace (PTRACE_SETFPREGS, pid, + (PTRACE_ARG3_TYPE) &fpregs, 0) == -1) + perror_with_name ("Couldn't write floating-point registers"); + } if (regnum != -1) return; @@ -193,4 +257,16 @@ _initialize_sparc_nat (void) /* Deafult to using SunOS 4 register sets. */ if (sparc_gregset == NULL) sparc_gregset = &sparc32_sunos4_gregset; + if (sparc_supply_gregset == NULL) + sparc_supply_gregset = sparc32_supply_gregset; + if (sparc_collect_gregset == NULL) + sparc_collect_gregset = sparc32_collect_gregset; + if (sparc_supply_fpregset == NULL) + sparc_supply_fpregset = sparc32_supply_fpregset; + if (sparc_collect_fpregset == NULL) + sparc_collect_fpregset = sparc32_collect_fpregset; + if (sparc_gregset_supplies_p == NULL) + sparc_gregset_supplies_p = sparc32_gregset_supplies_p; + if (sparc_fpregset_supplies_p == NULL) + sparc_fpregset_supplies_p = sparc32_fpregset_supplies_p; } diff --git a/gdb/sparc-nat.h b/gdb/sparc-nat.h new file mode 100644 index 00000000000..8f99b1eea11 --- /dev/null +++ b/gdb/sparc-nat.h @@ -0,0 +1,40 @@ +/* Native-dependent code for SPARC. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef SPARC_NAT_H +#define SPARC_NAT_H 1 + +struct sparc_gregset; + +extern const struct sparc_gregset *sparc_gregset; +extern void (*sparc_supply_gregset) (const struct sparc_gregset *, + struct regcache *, int , const void *); +extern void (*sparc_collect_gregset) (const struct sparc_gregset *, + const struct regcache *, int, void *); +extern void (*sparc_supply_fpregset) (struct regcache *, int , const void *); +extern void (*sparc_collect_fpregset) (const struct regcache *, int , void *); +extern int (*sparc_gregset_supplies_p) (int); +extern int (*sparc_fpregset_supplies_p) (int); + +extern int sparc32_gregset_supplies_p (int regnum); +extern int sparc32_fpregset_supplies_p (int regnum); + +#endif /* sparc-nat.h */ diff --git a/gdb/sparc-sol2-nat.c b/gdb/sparc-sol2-nat.c index 5b3113a372c..e42e3c84b18 100644 --- a/gdb/sparc-sol2-nat.c +++ b/gdb/sparc-sol2-nat.c @@ -34,24 +34,24 @@ void supply_gregset (prgregset_t *gregs) { - sparc_supply_gregset (&sparc32_sol2_gregset, current_regcache, -1, gregs); + sparc32_supply_gregset (&sparc32_sol2_gregset, current_regcache, -1, gregs); } void supply_fpregset (prfpregset_t *fpregs) { - sparc_supply_fpregset (current_regcache, -1, fpregs); + sparc32_supply_fpregset (current_regcache, -1, fpregs); } void fill_gregset (prgregset_t *gregs, int regnum) { - sparc_collect_gregset (&sparc32_sol2_gregset, - current_regcache, regnum, gregs); + sparc32_collect_gregset (&sparc32_sol2_gregset, + current_regcache, regnum, gregs); } void fill_fpregset (prfpregset_t *fpregs, int regnum) { - sparc_collect_fpregset (current_regcache, regnum, fpregs); + sparc32_collect_fpregset (current_regcache, regnum, fpregs); } diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c index ecefb8fb295..d7f24baed08 100644 --- a/gdb/sparc-tdep.c +++ b/gdb/sparc-tdep.c @@ -1079,12 +1079,10 @@ sparc_collect_rwindow (const struct regcache *regcache, /* Helper functions for dealing with register sets. */ -/* FIXME: kettenis/20031125: Make these handle 64-bit register sets. */ - void -sparc_supply_gregset (const struct sparc_gregset *gregset, - struct regcache *regcache, - int regnum, const void *gregs) +sparc32_supply_gregset (const struct sparc_gregset *gregset, + struct regcache *regcache, + int regnum, const void *gregs) { const char *regs = gregs; int i; @@ -1146,9 +1144,9 @@ sparc_supply_gregset (const struct sparc_gregset *gregset, } void -sparc_collect_gregset (const struct sparc_gregset *gregset, - const struct regcache *regcache, - int regnum, void *gregs) +sparc32_collect_gregset (const struct sparc_gregset *gregset, + const struct regcache *regcache, + int regnum, void *gregs) { char *regs = gregs; int i; @@ -1201,8 +1199,8 @@ sparc_collect_gregset (const struct sparc_gregset *gregset, } void -sparc_supply_fpregset (struct regcache *regcache, - int regnum, const void *fpregs) +sparc32_supply_fpregset (struct regcache *regcache, + int regnum, const void *fpregs) { const char *regs = fpregs; int i; @@ -1218,8 +1216,8 @@ sparc_supply_fpregset (struct regcache *regcache, } void -sparc_collect_fpregset (const struct regcache *regcache, - int regnum, void *fpregs) +sparc32_collect_fpregset (const struct regcache *regcache, + int regnum, void *fpregs) { char *regs = fpregs; int i; diff --git a/gdb/sparc-tdep.h b/gdb/sparc-tdep.h index bf081a01cc5..a683092f113 100644 --- a/gdb/sparc-tdep.h +++ b/gdb/sparc-tdep.h @@ -38,6 +38,7 @@ struct sparc_gregset int r_tbr_offset; int r_g1_offset; int r_l0_offset; + int r_y_size; }; /* SPARC architecture-specific information. */ @@ -146,16 +147,16 @@ extern void sparc_collect_rwindow (const struct regcache *regcache, /* Register offsets for SunOS 4. */ extern const struct sparc_gregset sparc32_sunos4_gregset; -extern void sparc_supply_gregset (const struct sparc_gregset *gregset, - struct regcache *regcache, - int regnum, const void *gregs); -extern void sparc_collect_gregset (const struct sparc_gregset *gregset, - const struct regcache *regcache, - int regnum, void *gregs); -extern void sparc_supply_fpregset (struct regcache *regcache, - int regnum, const void *fpregs); -extern void sparc_collect_fpregset (const struct regcache *regcache, - int regnum, void *fpregs); +extern void sparc32_supply_gregset (const struct sparc_gregset *gregset, + struct regcache *regcache, + int regnum, const void *gregs); +extern void sparc32_collect_gregset (const struct sparc_gregset *gregset, + const struct regcache *regcache, + int regnum, void *gregs); +extern void sparc32_supply_fpregset (struct regcache *regcache, + int regnum, const void *fpregs); +extern void sparc32_collect_fpregset (const struct regcache *regcache, + int regnum, void *fpregs); /* Functions and variables exported from sparc-sol2-tdep.c. */ @@ -163,6 +164,6 @@ extern void sparc_collect_fpregset (const struct regcache *regcache, extern const struct sparc_gregset sparc32_sol2_gregset; extern void sparc32_sol2_init_abi (struct gdbarch_info info, - struct gdbarch *gdbarch); + struct gdbarch *gdbarch); #endif /* sparc-tdep.h */ |