This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[commit] 64-bit ptrace fixes for MIPS64
- From: Daniel Jacobowitz <drow at false dot org>
- To: gdb-patches at sourceware dot org
- Date: Wed, 15 Mar 2006 12:19:35 -0500
- Subject: [commit] 64-bit ptrace fixes for MIPS64
There have historically been two problems for N32 GDB:
- There was considerable confusion about the types of the arguments
to ptrace. Mark Kettenis's suggestion made me go back to look
at the entire issue again, and we ended up changing the N32
glibc and 64-bit kernel to use "long" for the ptrace arguments,
like other platforms do. That matched GDB. Previously, the
third argument was a long and the fourth was a long long.
- Meanwhile, the best way to get ahold of registers is by using
PTRACE_GETREGS and avoiding any trouble with how to read multiple
word registers. So the kernel now supports PTRACE_GETREGS with
a pleasantly unambiguous format - no ABI quirks.
This patch adds PTRACE_GETREGS support for mips-linux, falling back
to PEEKUSER if it doesn't work. Works like a charm if your kernel
is new enough!
If you want to use an N32 GDB, be sure to get the recent glibc patch
to remove the MIPS-specific ptrace.h and ptrace.c.
Tested on mips64-linux and committed.
--
Daniel Jacobowitz
CodeSourcery
2006-03-15 Daniel Jacobowitz <dan@codesourcery.com>
* Makefile.in (mips_linux_tdep_h): New.
(mpis-linux-nat.o, mips-linux-tdep.o): Update.
* mips-linux-nat.c: Include "inferior.h", "mips-linux-tdep.h", and
<sys/ptrace.h>.
(have_ptrace_regsets, super_fetch_registers, super_store_registers)
(mips64_linux_regsets_fetch_registers)
(mips64_linux_regsets_store_registers, mips64_linux_fetch_registers)
(mips64_linux_store_registers): New.
(_initialize_mips_linux_nat): Override to_fetch_registers and
to_store_registers.
* mips-linux-tdep.h: New file.
* mips-linux-tdep.c: Include "mips-linux-tdep.c".
(ELF_NGREG, ELF_NFPREG, elf_greg_t, elf_gregset_t, elf_fpreg_t)
(elf_fpregset_t, FPR_BASE, PC, CAUSE, BADVADDR, MMHI, MMLO)
(FPC_CSR, FPC_EIR, EF_REG0, EF_REG31, EF_LO, EF_HI, EF_CP0_EPC)
(EF_CP0_BADVADDR, EF_CP0_STATUS, EF_CP0_CAUSE, EF_SIZE)
(MIPS64_ELF_NGREG, MIPS64_ELF_NFPREG, mips64_elf_greg_t)
(mips64_elf_gregset_t, mips64_elf_fpreg_t, mips64_elf_fpregset_t)
(MIPS64_FPR_BASE, MIPS64_PC, MIPS64_CAUSE, MIPS64_BADVADDR)
(MIPS64_MMHI, MIPS64_MMLO, MIPS64_FPC_CSR, MIPS64_FPC_EIR)
(MIPS64_EF_REG0, MIPS64_EF_REG31, MIPS64_EF_LO, MIPS64_EF_HI)
(MIPS64_EF_CP0_EPC, MIPS64_EF_CP0_BADVADDR, MIPS64_EF_CP0_STATUS)
(MIPS64_EF_CP0_CAUSE, MIPS64_EF_SIZE): Delete.
(supply_32bit_reg): Use gdb_byte.
(supply_64bit_reg): New.
(mips_supply_gregset, mips_fill_gregset, mips_supply_fpregset)
(mips_fill_fpregset, fetch_core_registers, supply_gregset)
(fill_gregset, supply_fpregset): Update for renamed types.
(mips64_supply_gregset): Use gdb_byte and supply_64bit_reg.
(mips64_fill_gregset): Make global. Handle 32-bit register
sizes.
(mips64_fill_fpregset): Make global. Use gdb_byte. Handle
FP regsets properly.
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2006-03-15 09:51:56.000000000 -0500
+++ src/gdb/Makefile.in 2006-03-15 09:51:56.000000000 -0500
@@ -737,6 +737,7 @@ macrotab_h = macrotab.h
main_h = main.h
mdebugread_h = mdebugread.h $(coff_sym_h) $(coff_symconst_h)
memattr_h = memattr.h
+mips_linux_tdep_h = mips-linux-tdep.h
mips_mdebug_tdep_h = mips-mdebug-tdep.h
mipsnbsd_tdep_h = mipsnbsd-tdep.h
mips_tdep_h = mips-tdep.h
@@ -2295,11 +2296,12 @@ mips64obsd-tdep.o: mips64obsd-tdep.c $(d
$(gdb_string_h) $(mips_tdep_h) $(solib_svr4_h)
mips-irix-tdep.o: mips-irix-tdep.c $(defs_h) $(osabi_h) $(elf_bfd_h)
mips-linux-nat.o: mips-linux-nat.c $(defs_h) $(mips_tdep_h) $(target_h) \
- $(linux_nat_h) $(gdb_proc_service_h)
+ $(linux_nat_h) $(gdb_proc_service_h) $(mips_linux_tdep_h) \
+ $(inferior_h)
mips-linux-tdep.o: mips-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \
$(solib_svr4_h) $(osabi_h) $(mips_tdep_h) $(gdb_string_h) \
$(gdb_assert_h) $(frame_h) $(regcache_h) $(trad_frame_h) \
- $(tramp_frame_h) $(floatformat_h)
+ $(tramp_frame_h) $(floatformat_h) $(mips_linux_tdep_h)
mips-mdebug-tdep.o: mips-mdebug-tdep.c $(defs_h) $(frame_h) $(mips_tdep_h) \
$(trad_frame_h) $(block_h) $(symtab_h) $(objfiles_h) $(elf_mips_h) \
$(elf_bfd_h) $(gdb_assert_h) $(frame_unwind_h) $(frame_base_h) \
Index: src/gdb/mips-linux-nat.c
===================================================================
--- src.orig/gdb/mips-linux-nat.c 2006-03-15 09:51:51.000000000 -0500
+++ src/gdb/mips-linux-nat.c 2006-03-15 09:51:56.000000000 -0500
@@ -21,16 +21,30 @@
Boston, MA 02110-1301, USA. */
#include "defs.h"
+#include "inferior.h"
#include "mips-tdep.h"
#include "target.h"
#include "linux-nat.h"
+#include "mips-linux-tdep.h"
#include "gdb_proc_service.h"
+#include <sys/ptrace.h>
+
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
#endif
+/* Assume that we have PTRACE_GETREGS et al. support. If we do not,
+ we'll clear this and use PTRACE_PEEKUSER instead. */
+static int have_ptrace_regsets = 1;
+
+/* Saved function pointers to fetch and store a single register using
+ PTRACE_PEEKUSER and PTRACE_POKEUSER. */
+
+void (*super_fetch_registers) (int);
+void (*super_store_registers) (int);
+
/* Pseudo registers can not be read. ptrace does not provide a way to
read (or set) MIPS_PS_REGNUM, and there's no point in reading or
setting MIPS_ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or
@@ -89,10 +103,161 @@ ps_get_thread_area (const struct ps_proc
return PS_OK;
}
+/* Fetch REGNO (or all registers if REGNO == -1) from the target
+ using PTRACE_GETREGS et al. */
+
+static void
+mips64_linux_regsets_fetch_registers (int regno)
+{
+ int is_fp;
+ int tid;
+
+ if (regno >= mips_regnum (current_gdbarch)->fp0
+ && regno <= mips_regnum (current_gdbarch)->fp0 + 32)
+ is_fp = 1;
+ else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ is_fp = 1;
+ else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ is_fp = 1;
+ else
+ is_fp = 0;
+
+ tid = ptid_get_lwp (inferior_ptid);
+ if (tid == 0)
+ tid = ptid_get_pid (inferior_ptid);
+
+ if (regno == -1 || !is_fp)
+ {
+ mips64_elf_gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_regsets = 0;
+ return;
+ }
+ perror_with_name (_("Couldn't get registers"));
+ }
+
+ mips64_supply_gregset (®s);
+ }
+
+ if (regno == -1 || is_fp)
+ {
+ mips64_elf_fpregset_t fp_regs;
+
+ if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_regsets = 0;
+ return;
+ }
+ perror_with_name (_("Couldn't get FP registers"));
+ }
+
+ mips64_supply_fpregset (&fp_regs);
+ }
+}
+
+/* Store REGNO (or all registers if REGNO == -1) to the target
+ using PTRACE_SETREGS et al. */
+
+static void
+mips64_linux_regsets_store_registers (int regno)
+{
+ int is_fp;
+ int tid;
+
+ if (regno >= mips_regnum (current_gdbarch)->fp0
+ && regno <= mips_regnum (current_gdbarch)->fp0 + 32)
+ is_fp = 1;
+ else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+ is_fp = 1;
+ else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ is_fp = 1;
+ else
+ is_fp = 0;
+
+ tid = ptid_get_lwp (inferior_ptid);
+ if (tid == 0)
+ tid = ptid_get_pid (inferior_ptid);
+
+ if (regno == -1 || !is_fp)
+ {
+ mips64_elf_gregset_t regs;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ perror_with_name (_("Couldn't get registers"));
+
+ mips64_fill_gregset (®s, regno);
+
+ if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) ®s) == -1)
+ perror_with_name (_("Couldn't set registers"));
+ }
+
+ if (regno == -1 || is_fp)
+ {
+ mips64_elf_fpregset_t fp_regs;
+
+ if (ptrace (PTRACE_GETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ perror_with_name (_("Couldn't get FP registers"));
+
+ mips64_fill_fpregset (&fp_regs, regno);
+
+ if (ptrace (PTRACE_SETFPREGS, tid, 0L,
+ (PTRACE_TYPE_ARG3) &fp_regs) == -1)
+ perror_with_name (_("Couldn't set FP registers"));
+ }
+}
+
+/* Fetch REGNO (or all registers if REGNO == -1) from the target
+ using any working method. */
+
+static void
+mips64_linux_fetch_registers (int regnum)
+{
+ /* Unless we already know that PTRACE_GETREGS does not work, try it. */
+ if (have_ptrace_regsets)
+ mips64_linux_regsets_fetch_registers (regnum);
+
+ /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
+ back to PTRACE_PEEKUSER. */
+ if (!have_ptrace_regsets)
+ super_fetch_registers (regnum);
+}
+
+/* Store REGNO (or all registers if REGNO == -1) to the target
+ using any working method. */
+
+static void
+mips64_linux_store_registers (int regnum)
+{
+ /* Unless we already know that PTRACE_GETREGS does not work, try it. */
+ if (have_ptrace_regsets)
+ mips64_linux_regsets_store_registers (regnum);
+
+ /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
+ back to PTRACE_PEEKUSER. */
+ if (!have_ptrace_regsets)
+ super_store_registers (regnum);
+}
+
void _initialize_mips_linux_nat (void);
void
_initialize_mips_linux_nat (void)
{
- add_target (linux_target ());
+ struct target_ops *t = linux_target ();
+
+ super_fetch_registers = t->to_fetch_registers;
+ super_store_registers = t->to_store_registers;
+
+ t->to_fetch_registers = mips64_linux_fetch_registers;
+ t->to_store_registers = mips64_linux_store_registers;
+
+ add_target (t);
}
Index: src/gdb/mips-linux-tdep.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/mips-linux-tdep.h 2006-03-15 09:56:00.000000000 -0500
@@ -0,0 +1,94 @@
+/* Target-dependent code for GNU/Linux on MIPS processors.
+
+ Copyright 2006 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. */
+
+/* Copied from <asm/elf.h>. */
+#define ELF_NGREG 45
+#define ELF_NFPREG 33
+
+typedef unsigned char mips_elf_greg_t[4];
+typedef mips_elf_greg_t mips_elf_gregset_t[ELF_NGREG];
+
+typedef unsigned char mips_elf_fpreg_t[8];
+typedef mips_elf_fpreg_t mips_elf_fpregset_t[ELF_NFPREG];
+
+/* 0 - 31 are integer registers, 32 - 63 are fp registers. */
+#define FPR_BASE 32
+#define PC 64
+#define CAUSE 65
+#define BADVADDR 66
+#define MMHI 67
+#define MMLO 68
+#define FPC_CSR 69
+#define FPC_EIR 70
+
+#define EF_REG0 6
+#define EF_REG31 37
+#define EF_LO 38
+#define EF_HI 39
+#define EF_CP0_EPC 40
+#define EF_CP0_BADVADDR 41
+#define EF_CP0_STATUS 42
+#define EF_CP0_CAUSE 43
+
+#define EF_SIZE 180
+
+void mips_supply_gregset (mips_elf_gregset_t *);
+void mips_fill_gregset (mips_elf_gregset_t *, int);
+void mips_supply_fpregset (mips_elf_fpregset_t *);
+void mips_fill_fpregset (mips_elf_fpregset_t *, int);
+
+/* 64-bit support. */
+
+/* Copied from <asm/elf.h>. */
+#define MIPS64_ELF_NGREG 45
+#define MIPS64_ELF_NFPREG 33
+
+typedef unsigned char mips64_elf_greg_t[8];
+typedef mips64_elf_greg_t mips64_elf_gregset_t[MIPS64_ELF_NGREG];
+
+typedef unsigned char mips64_elf_fpreg_t[8];
+typedef mips64_elf_fpreg_t mips64_elf_fpregset_t[MIPS64_ELF_NFPREG];
+
+/* 0 - 31 are integer registers, 32 - 63 are fp registers. */
+#define MIPS64_FPR_BASE 32
+#define MIPS64_PC 64
+#define MIPS64_CAUSE 65
+#define MIPS64_BADVADDR 66
+#define MIPS64_MMHI 67
+#define MIPS64_MMLO 68
+#define MIPS64_FPC_CSR 69
+#define MIPS64_FPC_EIR 70
+
+#define MIPS64_EF_REG0 0
+#define MIPS64_EF_REG31 31
+#define MIPS64_EF_LO 32
+#define MIPS64_EF_HI 33
+#define MIPS64_EF_CP0_EPC 34
+#define MIPS64_EF_CP0_BADVADDR 35
+#define MIPS64_EF_CP0_STATUS 36
+#define MIPS64_EF_CP0_CAUSE 37
+
+#define MIPS64_EF_SIZE 304
+
+void mips64_supply_gregset (mips64_elf_gregset_t *);
+void mips64_fill_gregset (mips64_elf_gregset_t *, int);
+void mips64_supply_fpregset (mips64_elf_fpregset_t *);
+void mips64_fill_fpregset (mips64_elf_fpregset_t *, int);
Index: src/gdb/mips-linux-tdep.c
===================================================================
--- src.orig/gdb/mips-linux-tdep.c 2006-03-15 09:51:56.000000000 -0500
+++ src/gdb/mips-linux-tdep.c 2006-03-15 09:51:56.000000000 -0500
@@ -33,37 +33,7 @@
#include "trad-frame.h"
#include "tramp-frame.h"
#include "floatformat.h"
-
-/* Copied from <asm/elf.h>. */
-#define ELF_NGREG 45
-#define ELF_NFPREG 33
-
-typedef unsigned char elf_greg_t[4];
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef unsigned char elf_fpreg_t[8];
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-
-/* 0 - 31 are integer registers, 32 - 63 are fp registers. */
-#define FPR_BASE 32
-#define PC 64
-#define CAUSE 65
-#define BADVADDR 66
-#define MMHI 67
-#define MMLO 68
-#define FPC_CSR 69
-#define FPC_EIR 70
-
-#define EF_REG0 6
-#define EF_REG31 37
-#define EF_LO 38
-#define EF_HI 39
-#define EF_CP0_EPC 40
-#define EF_CP0_BADVADDR 41
-#define EF_CP0_STATUS 42
-#define EF_CP0_CAUSE 43
-
-#define EF_SIZE 180
+#include "mips-linux-tdep.h"
/* Figure out where the longjmp will land.
We expect the first arg to be a pointer to the jmp_buf structure
@@ -99,7 +69,7 @@ mips_linux_get_longjmp_target (CORE_ADDR
static void
supply_32bit_reg (int regnum, const void *addr)
{
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
store_signed_integer (buf, register_size (current_gdbarch, regnum),
extract_signed_integer (addr, 4));
regcache_raw_supply (current_regcache, regnum, buf);
@@ -107,11 +77,11 @@ supply_32bit_reg (int regnum, const void
/* Unpack an elf_gregset_t into GDB's register cache. */
-static void
-mips_supply_gregset (elf_gregset_t *gregsetp)
+void
+mips_supply_gregset (mips_elf_gregset_t *gregsetp)
{
int regi;
- elf_greg_t *regp = *gregsetp;
+ mips_elf_greg_t *regp = *gregsetp;
char zerobuf[MAX_REGISTER_SIZE];
memset (zerobuf, 0, MAX_REGISTER_SIZE);
@@ -142,16 +112,16 @@ mips_supply_gregset (elf_gregset_t *greg
/* Pack our registers (or one register) into an elf_gregset_t. */
-static void
-mips_fill_gregset (elf_gregset_t *gregsetp, int regno)
+void
+mips_fill_gregset (mips_elf_gregset_t *gregsetp, int regno)
{
int regaddr, regi;
- elf_greg_t *regp = *gregsetp;
+ mips_elf_greg_t *regp = *gregsetp;
void *dst;
if (regno == -1)
{
- memset (regp, 0, sizeof (elf_gregset_t));
+ memset (regp, 0, sizeof (mips_elf_gregset_t));
for (regi = 0; regi < 32; regi++)
mips_fill_gregset (gregsetp, regi);
mips_fill_gregset (gregsetp, mips_regnum (current_gdbarch)->lo);
@@ -195,8 +165,8 @@ mips_fill_gregset (elf_gregset_t *gregse
/* Likewise, unpack an elf_fpregset_t. */
-static void
-mips_supply_fpregset (elf_fpregset_t *fpregsetp)
+void
+mips_supply_fpregset (mips_elf_fpregset_t *fpregsetp)
{
int regi;
char zerobuf[MAX_REGISTER_SIZE];
@@ -220,8 +190,8 @@ mips_supply_fpregset (elf_fpregset_t *fp
/* Likewise, pack one or all floating point registers into an
elf_fpregset_t. */
-static void
-mips_fill_fpregset (elf_fpregset_t *fpregsetp, int regno)
+void
+mips_fill_fpregset (mips_elf_fpregset_t *fpregsetp, int regno)
{
char *from, *to;
@@ -284,37 +254,6 @@ mips_linux_register_addr (int regno, COR
/* Support for 64-bit ABIs. */
-/* Copied from <asm/elf.h>. */
-#define MIPS64_ELF_NGREG 45
-#define MIPS64_ELF_NFPREG 33
-
-typedef unsigned char mips64_elf_greg_t[8];
-typedef mips64_elf_greg_t mips64_elf_gregset_t[MIPS64_ELF_NGREG];
-
-typedef unsigned char mips64_elf_fpreg_t[8];
-typedef mips64_elf_fpreg_t mips64_elf_fpregset_t[MIPS64_ELF_NFPREG];
-
-/* 0 - 31 are integer registers, 32 - 63 are fp registers. */
-#define MIPS64_FPR_BASE 32
-#define MIPS64_PC 64
-#define MIPS64_CAUSE 65
-#define MIPS64_BADVADDR 66
-#define MIPS64_MMHI 67
-#define MIPS64_MMLO 68
-#define MIPS64_FPC_CSR 69
-#define MIPS64_FPC_EIR 70
-
-#define MIPS64_EF_REG0 0
-#define MIPS64_EF_REG31 31
-#define MIPS64_EF_LO 32
-#define MIPS64_EF_HI 33
-#define MIPS64_EF_CP0_EPC 34
-#define MIPS64_EF_CP0_BADVADDR 35
-#define MIPS64_EF_CP0_STATUS 36
-#define MIPS64_EF_CP0_CAUSE 37
-
-#define MIPS64_EF_SIZE 304
-
/* Figure out where the longjmp will land.
We expect the first arg to be a pointer to the jmp_buf structure
from which we extract the pc (MIPS_LINUX_JB_PC) that we will land
@@ -343,39 +282,49 @@ mips64_linux_get_longjmp_target (CORE_AD
return 1;
}
-/* Unpack an elf_gregset_t into GDB's register cache. */
+/* Register set support functions. These operate on standard 64-bit
+ regsets, but work whether the target is 32-bit or 64-bit. A 32-bit
+ target will still use the 64-bit format for PTRACE_GETREGS. */
+
+/* Supply a 64-bit register. */
+
+void
+supply_64bit_reg (int regnum, const gdb_byte *buf)
+{
+ if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
+ && register_size (current_gdbarch, regnum) == 4)
+ regcache_raw_supply (current_regcache, regnum, buf + 4);
+ else
+ regcache_raw_supply (current_regcache, regnum, buf);
+}
-static void
+/* Unpack a 64-bit elf_gregset_t into GDB's register cache. */
+
+void
mips64_supply_gregset (mips64_elf_gregset_t *gregsetp)
{
int regi;
mips64_elf_greg_t *regp = *gregsetp;
- char zerobuf[MAX_REGISTER_SIZE];
+ gdb_byte zerobuf[MAX_REGISTER_SIZE];
memset (zerobuf, 0, MAX_REGISTER_SIZE);
for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++)
- regcache_raw_supply (current_regcache, (regi - MIPS64_EF_REG0),
- (char *)(regp + regi));
-
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->lo,
- (char *) (regp + MIPS64_EF_LO));
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->hi,
- (char *) (regp + MIPS64_EF_HI));
+ supply_64bit_reg (regi - MIPS64_EF_REG0, (gdb_byte *)(regp + regi));
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->pc,
- (char *) (regp + MIPS64_EF_CP0_EPC));
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->badvaddr,
- (char *) (regp + MIPS64_EF_CP0_BADVADDR));
- regcache_raw_supply (current_regcache, MIPS_PS_REGNUM,
- (char *) (regp + MIPS64_EF_CP0_STATUS));
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->cause,
- (char *) (regp + MIPS64_EF_CP0_CAUSE));
+ supply_64bit_reg (mips_regnum (current_gdbarch)->lo,
+ (gdb_byte *) (regp + MIPS64_EF_LO));
+ supply_64bit_reg (mips_regnum (current_gdbarch)->hi,
+ (gdb_byte *) (regp + MIPS64_EF_HI));
+
+ supply_64bit_reg (mips_regnum (current_gdbarch)->pc,
+ (gdb_byte *) (regp + MIPS64_EF_CP0_EPC));
+ supply_64bit_reg (mips_regnum (current_gdbarch)->badvaddr,
+ (gdb_byte *) (regp + MIPS64_EF_CP0_BADVADDR));
+ supply_64bit_reg (MIPS_PS_REGNUM,
+ (gdb_byte *) (regp + MIPS64_EF_CP0_STATUS));
+ supply_64bit_reg (mips_regnum (current_gdbarch)->cause,
+ (gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE));
/* Fill inaccessible registers with zero. */
regcache_raw_supply (current_regcache, MIPS_UNUSED_REGNUM, zerobuf);
@@ -385,9 +334,9 @@ mips64_supply_gregset (mips64_elf_gregse
regcache_raw_supply (current_regcache, regi, zerobuf);
}
-/* Pack our registers (or one register) into an elf_gregset_t. */
+/* Pack our registers (or one register) into a 64-bit elf_gregset_t. */
-static void
+void
mips64_fill_gregset (mips64_elf_gregset_t *gregsetp, int regno)
{
int regaddr, regi;
@@ -412,13 +361,8 @@ mips64_fill_gregset (mips64_elf_gregset_
}
if (regno < 32)
- {
- dst = regp + regno + MIPS64_EF_REG0;
- regcache_raw_collect (current_regcache, regno, dst);
- return;
- }
-
- if (regno == mips_regnum (current_gdbarch)->lo)
+ regaddr = regno + MIPS64_EF_REG0;
+ else if (regno == mips_regnum (current_gdbarch)->lo)
regaddr = MIPS64_EF_LO;
else if (regno == mips_regnum (current_gdbarch)->hi)
regaddr = MIPS64_EF_HI;
@@ -435,52 +379,97 @@ mips64_fill_gregset (mips64_elf_gregset_
if (regaddr != -1)
{
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ LONGEST val;
+
+ regcache_raw_collect (current_regcache, regno, buf);
+ val = extract_signed_integer (buf,
+ register_size (current_gdbarch, regno));
dst = regp + regaddr;
- regcache_raw_collect (current_regcache, regno, dst);
+ store_signed_integer (dst, 8, val);
}
}
/* Likewise, unpack an elf_fpregset_t. */
-static void
+void
mips64_supply_fpregset (mips64_elf_fpregset_t *fpregsetp)
{
int regi;
- char zerobuf[MAX_REGISTER_SIZE];
- memset (zerobuf, 0, MAX_REGISTER_SIZE);
-
- for (regi = 0; regi < 32; regi++)
- regcache_raw_supply (current_regcache, FP0_REGNUM + regi,
- (char *)(*fpregsetp + regi));
-
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->fp_control_status,
- (char *)(*fpregsetp + 32));
-
- /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */
- regcache_raw_supply (current_regcache,
- mips_regnum (current_gdbarch)->fp_implementation_revision,
- zerobuf);
+ /* See mips_linux_o32_sigframe_init for a description of the
+ peculiar FP register layout. */
+ if (register_size (current_gdbarch, FP0_REGNUM) == 4)
+ for (regi = 0; regi < 32; regi++)
+ {
+ gdb_byte *reg_ptr = (gdb_byte *) (*fpregsetp + (regi & ~1));
+ if ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) != (regi & 1))
+ reg_ptr += 4;
+ regcache_raw_supply (current_regcache, FP0_REGNUM + regi, reg_ptr);
+ }
+ else
+ for (regi = 0; regi < 32; regi++)
+ regcache_raw_supply (current_regcache, FP0_REGNUM + regi,
+ (char *)(*fpregsetp + regi));
+
+ supply_32bit_reg (mips_regnum (current_gdbarch)->fp_control_status,
+ (gdb_byte *)(*fpregsetp + 32));
+
+ /* The ABI doesn't tell us how to supply FCRIR, and core dumps don't
+ include it - but the result of PTRACE_GETFPREGS does. The best we
+ can do is to assume that its value is present. */
+ supply_32bit_reg (mips_regnum (current_gdbarch)->fp_implementation_revision,
+ (gdb_byte *)(*fpregsetp + 32) + 4);
}
/* Likewise, pack one or all floating point registers into an
elf_fpregset_t. */
-static void
+void
mips64_fill_fpregset (mips64_elf_fpregset_t *fpregsetp, int regno)
{
- char *from, *to;
+ gdb_byte *to;
if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32))
{
- to = (char *) (*fpregsetp + regno - FP0_REGNUM);
- regcache_raw_collect (current_regcache, regno, to);
+ /* See mips_linux_o32_sigframe_init for a description of the
+ peculiar FP register layout. */
+ if (register_size (current_gdbarch, regno) == 4)
+ {
+ int regi = regno - FP0_REGNUM;
+
+ to = (gdb_byte *) (*fpregsetp + (regi & ~1));
+ if ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) != (regi & 1))
+ to += 4;
+ regcache_raw_collect (current_regcache, regno, to);
+ }
+ else
+ {
+ to = (gdb_byte *) (*fpregsetp + regno - FP0_REGNUM);
+ regcache_raw_collect (current_regcache, regno, to);
+ }
}
else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
{
- to = (char *) (*fpregsetp + 32);
- regcache_raw_collect (current_regcache, regno, to);
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ LONGEST val;
+
+ regcache_raw_collect (current_regcache, regno, buf);
+ val = extract_signed_integer (buf,
+ register_size (current_gdbarch, regno));
+ to = (gdb_byte *) (*fpregsetp + 32);
+ store_signed_integer (to, 4, val);
+ }
+ else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+ {
+ gdb_byte buf[MAX_REGISTER_SIZE];
+ LONGEST val;
+
+ regcache_raw_collect (current_regcache, regno, buf);
+ val = extract_signed_integer (buf,
+ register_size (current_gdbarch, regno));
+ to = (gdb_byte *) (*fpregsetp + 32) + 4;
+ store_signed_integer (to, 4, val);
}
else if (regno == -1)
{
@@ -488,8 +477,10 @@ mips64_fill_fpregset (mips64_elf_fpregse
for (regi = 0; regi < 32; regi++)
mips64_fill_fpregset (fpregsetp, FP0_REGNUM + regi);
- mips64_fill_fpregset(fpregsetp,
- mips_regnum (current_gdbarch)->fp_control_status);
+ mips64_fill_fpregset (fpregsetp,
+ mips_regnum (current_gdbarch)->fp_control_status);
+ mips64_fill_fpregset (fpregsetp, (mips_regnum (current_gdbarch)
+ ->fp_implementation_revision));
}
}
@@ -537,8 +528,8 @@ static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
int which, CORE_ADDR reg_addr)
{
- elf_gregset_t gregset;
- elf_fpregset_t fpregset;
+ mips_elf_gregset_t gregset;
+ mips_elf_fpregset_t fpregset;
mips64_elf_gregset_t gregset64;
mips64_elf_fpregset_t fpregset64;
@@ -1088,7 +1079,7 @@ mips_linux_n32n64_sigframe_init (const s
/* Wrapper functions. These are only used by libthread_db. */
void
-supply_gregset (elf_gregset_t *gregsetp)
+supply_gregset (mips_elf_gregset_t *gregsetp)
{
if (mips_isa_regsize (current_gdbarch) == 4)
mips_supply_gregset (gregsetp);
@@ -1097,7 +1088,7 @@ supply_gregset (elf_gregset_t *gregsetp)
}
void
-fill_gregset (elf_gregset_t *gregsetp, int regno)
+fill_gregset (mips_elf_gregset_t *gregsetp, int regno)
{
if (mips_isa_regsize (current_gdbarch) == 4)
mips_fill_gregset (gregsetp, regno);
@@ -1108,7 +1099,7 @@ fill_gregset (elf_gregset_t *gregsetp, i
/* Likewise, unpack an elf_fpregset_t. */
void
-supply_fpregset (elf_fpregset_t *fpregsetp)
+supply_fpregset (mips_elf_fpregset_t *fpregsetp)
{
if (mips_isa_regsize (current_gdbarch) == 4)
mips_supply_fpregset (fpregsetp);
@@ -1120,7 +1111,7 @@ supply_fpregset (elf_fpregset_t *fpregse
elf_fpregset_t. */
void
-fill_fpregset (elf_fpregset_t *fpregsetp, int regno)
+fill_fpregset (mips_elf_fpregset_t *fpregsetp, int regno)
{
if (mips_isa_regsize (current_gdbarch) == 4)
mips_fill_fpregset (fpregsetp, regno);