This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH] Improve the fetch/store of general-purpose and floating-point PowerPC registers
- From: Sérgio Durigan Júnior <sergiodj at br dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Date: Tue, 06 Jan 2009 22:43:38 -0200
- Subject: Re: [PATCH] Improve the fetch/store of general-purpose and floating-point PowerPC registers
- References: <1223404355.7030.20.camel@miki> <1224184035.27672.64.camel@miki>
Hi guys,
Here's the new version of the patch. I've made some modifications in
order to "follow the pattern" already established in this portion of the
code. As a side effect, the code is cleaner now since it has less #ifdef
statements and uses control variables to decide if a ptrace flag is
present or not.
Thanks to Luis Machado for his valuable comments regarding this.
Best regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
2009-01-06 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* configure.ac: Checking the existence of PTRACE_GETREGS,
PTRACE_SETREGS, PTRACE_GETREGS64, PTRACE_SETREGS64,
PTRACE_GETFPREGS and PTRACE_SETFPREGS in <asm/ptrace.h>.
* ppc-linux-nat.c (have_ptrace_getsetregs): New variable.
(have_ptrace_getsetfpregs): Likewise.
(fetch_all_gp_regs): New function.
(fetch_gp_regs): New function.
(fetch_all_fp_regs): Likewise.
(fetch_fp_regs): New function.
(fetch_ppc_registers): Using the new methods to fetch general-
purpose and floating-pointer registers.
(store_all_gp_regs): New function.
(store_gp_regs): Likewise.
(store_all_fp_regs): New function.
(store_fp_regs): Likewise.
(store_ppc_registers): Using the new methods to store general-
purpose and floating-pointer registers.
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 <sys/ptrace.h> provides the PTRACE_GETREGS request.
AC_MSG_CHECKING(for PTRACE_GETREGS)
AC_CACHE_VAL(gdb_cv_have_ptrace_getregs,
-[AC_TRY_COMPILE([#include <sys/ptrace.h>],
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
[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 <sys/ptrace.h> provides the PTRACE_SETREGS request.
+AC_MSG_CHECKING(for PTRACE_SETREGS)
+AC_CACHE_VAL(gdb_cv_have_ptrace_setregs,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> provides the PTRACE_GETREGS64 request.
+AC_MSG_CHECKING(for PTRACE_GETREGS64)
+AC_CACHE_VAL(gdb_cv_have_ptrace_getregs64,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> provides the PTRACE_SETREGS64 request.
+AC_MSG_CHECKING(for PTRACE_SETREGS64)
+AC_CACHE_VAL(gdb_cv_have_ptrace_setregs64,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> provides the PTRACE_GETFPREGS request.
+AC_MSG_CHECKING(for PTRACE_GETFPREGS)
+AC_CACHE_VAL(gdb_cv_have_ptrace_getfpregs,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> provides the PTRACE_SETFPREGS request.
+AC_MSG_CHECKING(for PTRACE_SETFPREGS)
+AC_CACHE_VAL(gdb_cv_have_ptrace_setfpregs,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> provides the PTRACE_GETFPXREGS request.
AC_MSG_CHECKING(for PTRACE_GETFPXREGS)
AC_CACHE_VAL(gdb_cv_have_ptrace_getfpxregs,
-[AC_TRY_COMPILE([#include <sys/ptrace.h>],
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
[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 <sys/ptrace.h> provides the PTRACE_SETFPXREGS request.
+AC_MSG_CHECKING(for PTRACE_SETFPXREGS)
+AC_CACHE_VAL(gdb_cv_have_ptrace_setfpxregs,
+[AC_TRY_COMPILE([#include <sys/ptrace.h>
+ #include <asm/ptrace.h>],
+ [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 <sys/ptrace.h> 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);