diff --git a/gdb/configure.ac b/gdb/configure.ac index 4e0cf7d..ff50f40 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -943,7 +943,8 @@ AC_CHECK_MEMBERS([struct reg.r_fs, struct reg.r_gs], [], [], # See if provides the PTRACE_GETREGS request. AC_MSG_CHECKING(for PTRACE_GETREGS) AC_CACHE_VAL(gdb_cv_have_ptrace_getregs, -[AC_TRY_COMPILE([#include ], +[AC_TRY_COMPILE([#include + #include ], [PTRACE_GETREGS;], [gdb_cv_have_ptrace_getregs=yes], [gdb_cv_have_ptrace_getregs=no])]) @@ -953,10 +954,81 @@ if test $gdb_cv_have_ptrace_getregs = yes; then [Define if sys/ptrace.h defines the PTRACE_GETREGS request.]) fi +# See if provides the PTRACE_SETREGS request. +AC_MSG_CHECKING(for PTRACE_SETREGS) +AC_CACHE_VAL(gdb_cv_have_ptrace_setregs, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_SETREGS;], + [gdb_cv_have_ptrace_setregs=yes], + [gdb_cv_have_ptrace_setregs=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_setregs) +if test $gdb_cv_have_ptrace_setregs = yes; then + AC_DEFINE(HAVE_PTRACE_SETREGS, 1, + [Define if sys/ptrace.h defines the PTRACE_SETREGS request.]) +fi + +# See if provides the PTRACE_GETREGS64 request. +AC_MSG_CHECKING(for PTRACE_GETREGS64) +AC_CACHE_VAL(gdb_cv_have_ptrace_getregs64, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_GETREGS64;], + [gdb_cv_have_ptrace_getregs64=yes], + [gdb_cv_have_ptrace_getregs64=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_getregs64) +if test $gdb_cv_have_ptrace_getregs64 = yes; then + AC_DEFINE(HAVE_PTRACE_GETREGS64, 1, + [Define if sys/ptrace.h defines the PTRACE_GETREGS64 request.]) +fi + +# See if provides the PTRACE_SETREGS64 request. +AC_MSG_CHECKING(for PTRACE_SETREGS64) +AC_CACHE_VAL(gdb_cv_have_ptrace_setregs64, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_SETREGS64;], + [gdb_cv_have_ptrace_setregs64=yes], + [gdb_cv_have_ptrace_setregs64=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_setregs64) +if test $gdb_cv_have_ptrace_setregs64 = yes; then + AC_DEFINE(HAVE_PTRACE_SETREGS64, 1, + [Define if sys/ptrace.h defines the PTRACE_SETREGS64 request.]) +fi + +# See if provides the PTRACE_GETFPREGS request. +AC_MSG_CHECKING(for PTRACE_GETFPREGS) +AC_CACHE_VAL(gdb_cv_have_ptrace_getfpregs, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_GETFPREGS;], + [gdb_cv_have_ptrace_getfpregs=yes], + [gdb_cv_have_ptrace_getfpregs=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_getfpregs) +if test $gdb_cv_have_ptrace_getfpregs = yes; then + AC_DEFINE(HAVE_PTRACE_GETFPREGS, 1, + [Define if sys/ptrace.h defines the PTRACE_GETFPREGS request.]) +fi + +# See if provides the PTRACE_SETFPREGS request. +AC_MSG_CHECKING(for PTRACE_SETFPREGS) +AC_CACHE_VAL(gdb_cv_have_ptrace_setfpregs, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_SETFPREGS;], + [gdb_cv_have_ptrace_setfpregs=yes], + [gdb_cv_have_ptrace_setfpregs=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_setfpregs) +if test $gdb_cv_have_ptrace_setfpregs = yes; then + AC_DEFINE(HAVE_PTRACE_SETFPREGS, 1, + [Define if sys/ptrace.h defines the PTRACE_SETFPREGS request.]) +fi + # See if provides the PTRACE_GETFPXREGS request. AC_MSG_CHECKING(for PTRACE_GETFPXREGS) AC_CACHE_VAL(gdb_cv_have_ptrace_getfpxregs, -[AC_TRY_COMPILE([#include ], +[AC_TRY_COMPILE([#include + #include ], [PTRACE_GETFPXREGS;], [gdb_cv_have_ptrace_getfpxregs=yes], [gdb_cv_have_ptrace_getfpxregs=no])]) @@ -966,6 +1038,20 @@ if test $gdb_cv_have_ptrace_getfpxregs = yes; then [Define if sys/ptrace.h defines the PTRACE_GETFPXREGS request.]) fi +# See if provides the PTRACE_SETFPXREGS request. +AC_MSG_CHECKING(for PTRACE_SETFPXREGS) +AC_CACHE_VAL(gdb_cv_have_ptrace_setfpxregs, +[AC_TRY_COMPILE([#include + #include ], + [PTRACE_SETFPXREGS;], + [gdb_cv_have_ptrace_setfpxregs=yes], + [gdb_cv_have_ptrace_setfpxregs=no])]) +AC_MSG_RESULT($gdb_cv_have_ptrace_setfpxregs) +if test $gdb_cv_have_ptrace_setfpxregs = yes; then + AC_DEFINE(HAVE_PTRACE_SETFPXREGS, 1, + [Define if sys/ptrace.h defines the PTRACE_SETFPXREGS request.]) +fi + # See if provides the PT_GETDBREGS request. AC_MSG_CHECKING(for PT_GETDBREGS) AC_CACHE_VAL(gdb_cv_have_pt_getdbregs, diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c index b946093..f2ecf7c 100644 --- a/gdb/ppc-linux-nat.c +++ b/gdb/ppc-linux-nat.c @@ -108,6 +108,27 @@ #define PTRACE_GETSIGINFO 0x4202 #endif +/* Similarly for the general-purpose (gp0 -- gp31) + and floating-point registers (fp0 -- fp31). */ +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS 12 +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS 13 +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS 14 +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS 15 +#endif +#ifndef PTRACE_GETREGS64 +#define PTRACE_GETREGS64 22 +#endif +#ifndef PTRACE_SETREGS64 +#define PTRACE_SETREGS64 23 +#endif + /* This oddity is because the Linux kernel defines elf_vrregset_t as an array of 33 16 bytes long elements. I.e. it leaves out vrsave. However the PTRACE_GETVRREGS and PTRACE_SETVRREGS requests return @@ -218,6 +239,18 @@ int have_ptrace_getvrregs = 1; error. */ int have_ptrace_getsetevrregs = 1; +/* Non-zero if our kernel may support the PTRACE_GETREGS and + PTRACE_SETREGS (for both 32- and 64-bit) requests, for + reading and writing the general-purpose registers. Zero if + we've tried one of them and gotten an error. */ +int have_ptrace_getsetregs = 1; + +/* Non-zero if our kernel may support the PTRACE_GETFPREGS and + PTRACE_SETFPREGS requests, for reading and writing the + floating-pointers registers. Zero if we've tried one of + them and gotten an error. */ +int have_ptrace_getsetfpregs = 1; + /* *INDENT-OFF* */ /* registers layout, as presented by the ptrace interface: PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, @@ -601,6 +634,89 @@ fetch_altivec_registers (struct regcache *regcache, int tid) supply_vrregset (regcache, ®s); } +static int +fetch_all_gp_regs (struct regcache *regcache, int tid) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int get_req; + gdb_gregset_t gregset; + + gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8); + + get_req = (tdep->wordsize == 4) ? PTRACE_GETREGS : PTRACE_GETREGS64; + + if (ptrace (get_req, tid, 0, (void *) &gregset) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetregs = 0; + return 0; + } + perror_with_name (_("Couldn't get general-purpose registers.")); + } + + supply_gregset (regcache, (const gdb_gregset_t *) &gregset); + + return 1; +} + +static void +fetch_gp_regs (struct regcache *regcache, int tid) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int i; + + if (have_ptrace_getsetregs) + if (fetch_all_gp_regs (regcache, tid)) + return; + + /* If we've hit this point, it doesn't really matter which + architecture we are using. We just need to read the + registers in the "old-fashioned way". */ + for (i = 0; i < ppc_num_gprs; i++) + fetch_register (regcache, tid, tdep->ppc_gp0_regnum + i); +} + +static int +fetch_all_fp_regs (struct regcache *regcache, int tid) +{ + gdb_fpregset_t fpregs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0, (void *) &fpregs) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetfpregs = 0; + return 0; + } + perror_with_name (_("Couldn't get floating point status")); + } + + supply_fpregset (regcache, (const gdb_fpregset_t *) &fpregs); + + return 1; +} + +static void +fetch_fp_regs (struct regcache *regcache, int tid) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int i; + + if (have_ptrace_getsetfpregs) + if (fetch_all_fp_regs (regcache, tid)) + return; + + /* If we've hit this point, it doesn't really matter which + architecture we are using. We just need to read the + registers in the "old-fashioned way". */ + for (i = 0; i < ppc_num_fprs; i++) + fetch_register (regcache, tid, tdep->ppc_fp0_regnum + i); +} + static void fetch_ppc_registers (struct regcache *regcache, int tid) { @@ -608,11 +724,9 @@ fetch_ppc_registers (struct regcache *regcache, int tid) struct gdbarch *gdbarch = get_regcache_arch (regcache); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - for (i = 0; i < ppc_num_gprs; i++) - fetch_register (regcache, tid, tdep->ppc_gp0_regnum + i); + fetch_gp_regs (regcache, tid); if (tdep->ppc_fp0_regnum >= 0) - for (i = 0; i < ppc_num_fprs; i++) - fetch_register (regcache, tid, tdep->ppc_fp0_regnum + i); + fetch_fp_regs (regcache, tid); fetch_register (regcache, tid, gdbarch_pc_regnum (gdbarch)); if (tdep->ppc_ps_regnum != -1) fetch_register (regcache, tid, tdep->ppc_ps_regnum); @@ -969,18 +1083,121 @@ store_altivec_registers (const struct regcache *regcache, int tid) perror_with_name (_("Couldn't write AltiVec registers")); } +static int +store_all_gp_regs (const struct regcache *regcache, int tid, int regno) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + /* Get/set requisitions depending on the arch. */ + int get_req, set_req; + gdb_gregset_t gregset; + + gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8); + + get_req = (tdep->wordsize == 4) ? PTRACE_GETREGS : PTRACE_GETREGS64; + set_req = (tdep->wordsize == 4) ? PTRACE_SETREGS : PTRACE_SETREGS64; + + if (ptrace (get_req, tid, 0, (void *) &gregset) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetregs = 0; + return 0; + } + perror_with_name (_("Couldn't get general-purpose registers.")); + } + + fill_gregset (regcache, &gregset, regno); + + if (ptrace (set_req, tid, 0, (void *) &gregset) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetregs = 0; + return 0; + } + perror_with_name (_("Couldn't write general-purpose registers.")); + } + + return 1; +} + static void -store_ppc_registers (const struct regcache *regcache, int tid) +store_gp_regs (const struct regcache *regcache, int tid, int regno) { - int i; struct gdbarch *gdbarch = get_regcache_arch (regcache); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - + int i; + + if (have_ptrace_getsetregs) + if (store_all_gp_regs (regcache, tid, regno)) + return; + + /* If we hit this point, it doesn't really matter which + architecture we are using. We just need to store the + registers in the "old-fashioned way". */ for (i = 0; i < ppc_num_gprs; i++) store_register (regcache, tid, tdep->ppc_gp0_regnum + i); +} + +static int +store_all_fp_regs (const struct regcache *regcache, int tid, int regno) +{ + gdb_fpregset_t fpregs; + + if (ptrace (PTRACE_GETFPREGS, tid, 0, (void *) &fpregs) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetfpregs = 0; + return 0; + } + perror_with_name (_("Couldn't get floating point status")); + } + + fill_fpregset (regcache, &fpregs, regno); + + if (ptrace (PTRACE_SETFPREGS, tid, 0, (void *) &fpregs) < 0) + { + if (errno == EIO) + { + have_ptrace_getsetfpregs = 0; + return 0; + } + perror_with_name (_("Couldn't write floating point status")); + } + + return 1; +} + +static void +store_fp_regs (const struct regcache *regcache, int tid, int regno) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int i; + + if (have_ptrace_getsetfpregs) + if (store_all_fp_regs (regcache, tid, regno)) + return; + + /* If we hit this point, it doesn't really matter which + architecture we are using. We just need to store the + registers in the "old-fashioned way". */ + for (i = 0; i < ppc_num_fprs; i++) + store_register (regcache, tid, tdep->ppc_fp0_regnum + i); +} + +static void +store_ppc_registers (const struct regcache *regcache, int tid) +{ + int i; + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + store_gp_regs (regcache, tid, -1); if (tdep->ppc_fp0_regnum >= 0) - for (i = 0; i < ppc_num_fprs; i++) - store_register (regcache, tid, tdep->ppc_fp0_regnum + i); + store_fp_regs (regcache, tid, -1); store_register (regcache, tid, gdbarch_pc_regnum (gdbarch)); if (tdep->ppc_ps_regnum != -1) store_register (regcache, tid, tdep->ppc_ps_regnum);