This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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) &regs) == -1)
+	{
+	  if (errno == EIO)
+	    {
+	      have_ptrace_regsets = 0;
+	      return;
+	    }
+	  perror_with_name (_("Couldn't get registers"));
+	}
+
+      mips64_supply_gregset (&regs);
+    }
+
+  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) &regs) == -1)
+	perror_with_name (_("Couldn't get registers"));
+
+      mips64_fill_gregset (&regs, regno);
+
+      if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]