* i386-linux-tdep.c (I386_LINUX_RECORD_SIZE_*,
[deliverable/binutils-gdb.git] / gdb / mips-linux-tdep.c
index 1c612464b82188ff1d70e1008dad9ef8bb6f09c3..242196ac790b4ddec2db307d7c9fc44401b8cfb6 100644 (file)
@@ -1,13 +1,13 @@
 /* Target-dependent code for GNU/Linux on MIPS processors.
 
-   Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007
+   Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
    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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdbcore.h"
@@ -37,7 +35,9 @@
 #include "solib-svr4.h"
 #include "solist.h"
 #include "symtab.h"
+#include "target-descriptions.h"
 #include "mips-linux-tdep.h"
+#include "glibc-tdep.h"
 
 static struct target_so_ops mips_svr4_so_ops;
 
@@ -51,19 +51,21 @@ static struct target_so_ops mips_svr4_so_ops;
 #define MIPS_LINUX_JB_PC 0
 
 static int
-mips_linux_get_longjmp_target (CORE_ADDR *pc)
+mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
-  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  char buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT];
 
-  jb_addr = read_register (MIPS_A0_REGNUM);
+  jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
 
   if (target_read_memory (jb_addr
-                         + MIPS_LINUX_JB_PC * MIPS_LINUX_JB_ELEMENT_SIZE,
-                         buf, TARGET_PTR_BIT / TARGET_CHAR_BIT))
+                           + MIPS_LINUX_JB_PC * MIPS_LINUX_JB_ELEMENT_SIZE,
+                         buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
     return 0;
 
-  *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  *pc = extract_unsigned_integer (buf,
+                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
 
   return 1;
 }
@@ -76,7 +78,8 @@ static void
 supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
 {
   gdb_byte buf[MAX_REGISTER_SIZE];
-  store_signed_integer (buf, register_size (current_gdbarch, regnum),
+  store_signed_integer (buf,
+                       register_size (get_regcache_arch (regcache), regnum),
                         extract_signed_integer (addr, 4));
   regcache_raw_supply (regcache, regnum, buf);
 }
@@ -90,29 +93,32 @@ mips_supply_gregset (struct regcache *regcache,
   int regi;
   const mips_elf_greg_t *regp = *gregsetp;
   char zerobuf[MAX_REGISTER_SIZE];
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
   memset (zerobuf, 0, MAX_REGISTER_SIZE);
 
-  for (regi = EF_REG0; regi <= EF_REG31; regi++)
+  for (regi = EF_REG0 + 1; regi <= EF_REG31; regi++)
     supply_32bit_reg (regcache, regi - EF_REG0, regp + regi);
 
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
-                   regp + EF_LO);
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
-                   regp + EF_HI);
+  if (mips_linux_restart_reg_p (gdbarch))
+    supply_32bit_reg (regcache, MIPS_RESTART_REGNUM, regp + EF_REG0);
 
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->pc,
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->lo, regp + EF_LO);
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->hi, regp + EF_HI);
+
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->pc,
                    regp + EF_CP0_EPC);
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->badvaddr,
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
                    regp + EF_CP0_BADVADDR);
   supply_32bit_reg (regcache, MIPS_PS_REGNUM, regp + EF_CP0_STATUS);
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->cause,
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->cause,
                    regp + EF_CP0_CAUSE);
 
   /* Fill inaccessible registers with zero.  */
+  regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf);
   regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf);
   for (regi = MIPS_FIRST_EMBED_REGNUM;
-       regi < MIPS_LAST_EMBED_REGNUM;
+       regi <= MIPS_LAST_EMBED_REGNUM;
        regi++)
     regcache_raw_supply (regcache, regi, zerobuf);
 }
@@ -123,6 +129,7 @@ void
 mips_fill_gregset (const struct regcache *regcache,
                   mips_elf_gregset_t *gregsetp, int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int regaddr, regi;
   mips_elf_greg_t *regp = *gregsetp;
   void *dst;
@@ -130,41 +137,40 @@ mips_fill_gregset (const struct regcache *regcache,
   if (regno == -1)
     {
       memset (regp, 0, sizeof (mips_elf_gregset_t));
-      for (regi = 0; regi < 32; regi++)
+      for (regi = 1; regi < 32; regi++)
        mips_fill_gregset (regcache, gregsetp, regi);
-      mips_fill_gregset (regcache, gregsetp,
-                        mips_regnum (current_gdbarch)->lo);
-      mips_fill_gregset (regcache, gregsetp,
-                        mips_regnum (current_gdbarch)->hi);
-      mips_fill_gregset (regcache, gregsetp,
-                        mips_regnum (current_gdbarch)->pc);
-      mips_fill_gregset (regcache, gregsetp,
-                        mips_regnum (current_gdbarch)->badvaddr);
+      mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo);
+      mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi);
+      mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc);
+      mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->badvaddr);
       mips_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
-      mips_fill_gregset (regcache, gregsetp,
-                        mips_regnum (current_gdbarch)->cause);
+      mips_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->cause);
+      mips_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
       return;
    }
 
-  if (regno < 32)
+  if (regno > 0 && regno < 32)
     {
       dst = regp + regno + EF_REG0;
       regcache_raw_collect (regcache, regno, dst);
       return;
     }
 
-  if (regno == mips_regnum (current_gdbarch)->lo)
-    regaddr = EF_LO;
-  else if (regno == mips_regnum (current_gdbarch)->hi)
+  if (regno == mips_regnum (gdbarch)->lo)
+     regaddr = EF_LO;
+  else if (regno == mips_regnum (gdbarch)->hi)
     regaddr = EF_HI;
-  else if (regno == mips_regnum (current_gdbarch)->pc)
+  else if (regno == mips_regnum (gdbarch)->pc)
     regaddr = EF_CP0_EPC;
-  else if (regno == mips_regnum (current_gdbarch)->badvaddr)
+  else if (regno == mips_regnum (gdbarch)->badvaddr)
     regaddr = EF_CP0_BADVADDR;
   else if (regno == MIPS_PS_REGNUM)
     regaddr = EF_CP0_STATUS;
-  else if (regno == mips_regnum (current_gdbarch)->cause)
+  else if (regno == mips_regnum (gdbarch)->cause)
     regaddr = EF_CP0_CAUSE;
+  else if (mips_linux_restart_reg_p (gdbarch)
+          && regno == MIPS_RESTART_REGNUM)
+    regaddr = EF_REG0;
   else
     regaddr = -1;
 
@@ -181,21 +187,24 @@ void
 mips_supply_fpregset (struct regcache *regcache,
                      const mips_elf_fpregset_t *fpregsetp)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int regi;
   char zerobuf[MAX_REGISTER_SIZE];
 
   memset (zerobuf, 0, MAX_REGISTER_SIZE);
 
   for (regi = 0; regi < 32; regi++)
-    regcache_raw_supply (regcache, FP0_REGNUM + regi, *fpregsetp + regi);
+    regcache_raw_supply (regcache,
+                        gdbarch_fp0_regnum (gdbarch) + regi,
+                        *fpregsetp + regi);
 
   regcache_raw_supply (regcache,
-                      mips_regnum (current_gdbarch)->fp_control_status,
+                      mips_regnum (gdbarch)->fp_control_status,
                       *fpregsetp + 32);
 
   /* FIXME: how can we supply FCRIR?  The ABI doesn't tell us.  */
   regcache_raw_supply (regcache,
-                      mips_regnum (current_gdbarch)->fp_implementation_revision,
+                      mips_regnum (gdbarch)->fp_implementation_revision,
                       zerobuf);
 }
 
@@ -206,14 +215,16 @@ void
 mips_fill_fpregset (const struct regcache *regcache,
                    mips_elf_fpregset_t *fpregsetp, int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   char *from, *to;
 
-  if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32))
+  if ((regno >= gdbarch_fp0_regnum (gdbarch))
+      && (regno < gdbarch_fp0_regnum (gdbarch) + 32))
     {
-      to = (char *) (*fpregsetp + regno - FP0_REGNUM);
+      to = (char *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
       regcache_raw_collect (regcache, regno, to);
     }
-  else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+  else if (regno == mips_regnum (gdbarch)->fp_control_status)
     {
       to = (char *) (*fpregsetp + 32);
       regcache_raw_collect (regcache, regno, to);
@@ -223,9 +234,10 @@ mips_fill_fpregset (const struct regcache *regcache,
       int regi;
 
       for (regi = 0; regi < 32; regi++)
-       mips_fill_fpregset (regcache, fpregsetp, FP0_REGNUM + regi);
+       mips_fill_fpregset (regcache, fpregsetp,
+                           gdbarch_fp0_regnum (gdbarch) + regi);
       mips_fill_fpregset (regcache, fpregsetp,
-                         mips_regnum (current_gdbarch)->fp_control_status);
+                         mips_regnum (gdbarch)->fp_control_status);
     }
 }
 
@@ -242,19 +254,22 @@ mips_fill_fpregset (const struct regcache *regcache,
 #define MIPS64_LINUX_JB_PC 0
 
 static int
-mips64_linux_get_longjmp_target (CORE_ADDR *pc)
+mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
-  void *buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
-  int element_size = TARGET_PTR_BIT == 32 ? 4 : 8;
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  void *buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
+  int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8;
 
-  jb_addr = read_register (MIPS_A0_REGNUM);
+  jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
 
   if (target_read_memory (jb_addr + MIPS64_LINUX_JB_PC * element_size,
-                         buf, TARGET_PTR_BIT / TARGET_CHAR_BIT))
+                         buf,
+                         gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
     return 0;
 
-  *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  *pc = extract_unsigned_integer (buf,
+                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
 
   return 1;
 }
@@ -265,12 +280,13 @@ mips64_linux_get_longjmp_target (CORE_ADDR *pc)
 
 /* Supply a 64-bit register.  */
 
-void
+static void
 supply_64bit_reg (struct regcache *regcache, int regnum,
                  const gdb_byte *buf)
 {
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
-      && register_size (current_gdbarch, regnum) == 4)
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
+      && register_size (gdbarch, regnum) == 4)
     regcache_raw_supply (regcache, regnum, buf + 4);
   else
     regcache_raw_supply (regcache, regnum, buf);
@@ -285,31 +301,37 @@ mips64_supply_gregset (struct regcache *regcache,
   int regi;
   const mips64_elf_greg_t *regp = *gregsetp;
   gdb_byte zerobuf[MAX_REGISTER_SIZE];
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
   memset (zerobuf, 0, MAX_REGISTER_SIZE);
 
-  for (regi = MIPS64_EF_REG0; regi <= MIPS64_EF_REG31; regi++)
+  for (regi = MIPS64_EF_REG0 + 1; regi <= MIPS64_EF_REG31; regi++)
     supply_64bit_reg (regcache, regi - MIPS64_EF_REG0,
                      (const gdb_byte *)(regp + regi));
 
-  supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->lo,
+  if (mips_linux_restart_reg_p (gdbarch))
+    supply_64bit_reg (regcache, MIPS_RESTART_REGNUM,
+                     (const gdb_byte *)(regp + MIPS64_EF_REG0));
+
+  supply_64bit_reg (regcache, mips_regnum (gdbarch)->lo,
                    (const gdb_byte *) (regp + MIPS64_EF_LO));
-  supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->hi,
+  supply_64bit_reg (regcache, mips_regnum (gdbarch)->hi,
                    (const gdb_byte *) (regp + MIPS64_EF_HI));
 
-  supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->pc,
+  supply_64bit_reg (regcache, mips_regnum (gdbarch)->pc,
                    (const gdb_byte *) (regp + MIPS64_EF_CP0_EPC));
-  supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->badvaddr,
+  supply_64bit_reg (regcache, mips_regnum (gdbarch)->badvaddr,
                    (const gdb_byte *) (regp + MIPS64_EF_CP0_BADVADDR));
   supply_64bit_reg (regcache, MIPS_PS_REGNUM,
                    (const gdb_byte *) (regp + MIPS64_EF_CP0_STATUS));
-  supply_64bit_reg (regcache, mips_regnum (current_gdbarch)->cause,
+  supply_64bit_reg (regcache, mips_regnum (gdbarch)->cause,
                    (const gdb_byte *) (regp + MIPS64_EF_CP0_CAUSE));
 
   /* Fill inaccessible registers with zero.  */
+  regcache_raw_supply (regcache, MIPS_ZERO_REGNUM, zerobuf);
   regcache_raw_supply (regcache, MIPS_UNUSED_REGNUM, zerobuf);
   for (regi = MIPS_FIRST_EMBED_REGNUM;
-       regi < MIPS_LAST_EMBED_REGNUM;
+       regi <= MIPS_LAST_EMBED_REGNUM;
        regi++)
     regcache_raw_supply (regcache, regi, zerobuf);
 }
@@ -320,43 +342,43 @@ void
 mips64_fill_gregset (const struct regcache *regcache,
                     mips64_elf_gregset_t *gregsetp, int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int regaddr, regi;
   mips64_elf_greg_t *regp = *gregsetp;
-  void *src, *dst;
+  void *dst;
 
   if (regno == -1)
     {
       memset (regp, 0, sizeof (mips64_elf_gregset_t));
-      for (regi = 0; regi < 32; regi++)
+      for (regi = 1; regi < 32; regi++)
         mips64_fill_gregset (regcache, gregsetp, regi);
-      mips64_fill_gregset (regcache, gregsetp,
-                          mips_regnum (current_gdbarch)->lo);
-      mips64_fill_gregset (regcache, gregsetp,
-                          mips_regnum (current_gdbarch)->hi);
-      mips64_fill_gregset (regcache, gregsetp,
-                          mips_regnum (current_gdbarch)->pc);
-      mips64_fill_gregset (regcache, gregsetp,
-                          mips_regnum (current_gdbarch)->badvaddr);
+      mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->lo);
+      mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->hi);
+      mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->pc);
+      mips64_fill_gregset (regcache, gregsetp, mips_regnum (gdbarch)->badvaddr);
       mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
-      mips64_fill_gregset (regcache, gregsetp,
-                          mips_regnum (current_gdbarch)->cause);
+      mips64_fill_gregset (regcache, gregsetp,  mips_regnum (gdbarch)->cause);
+      mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
       return;
    }
 
-  if (regno < 32)
+  if (regno > 0 && regno < 32)
     regaddr = regno + MIPS64_EF_REG0;
-  else if (regno == mips_regnum (current_gdbarch)->lo)
+  else if (regno == mips_regnum (gdbarch)->lo)
     regaddr = MIPS64_EF_LO;
-  else if (regno == mips_regnum (current_gdbarch)->hi)
+  else if (regno == mips_regnum (gdbarch)->hi)
     regaddr = MIPS64_EF_HI;
-  else if (regno == mips_regnum (current_gdbarch)->pc)
+  else if (regno == mips_regnum (gdbarch)->pc)
     regaddr = MIPS64_EF_CP0_EPC;
-  else if (regno == mips_regnum (current_gdbarch)->badvaddr)
+  else if (regno == mips_regnum (gdbarch)->badvaddr)
     regaddr = MIPS64_EF_CP0_BADVADDR;
   else if (regno == MIPS_PS_REGNUM)
     regaddr = MIPS64_EF_CP0_STATUS;
-  else if (regno == mips_regnum (current_gdbarch)->cause)
+  else if (regno == mips_regnum (gdbarch)->cause)
     regaddr = MIPS64_EF_CP0_CAUSE;
+  else if (mips_linux_restart_reg_p (gdbarch)
+          && regno == MIPS_RESTART_REGNUM)
+    regaddr = MIPS64_EF_REG0;
   else
     regaddr = -1;
 
@@ -366,8 +388,7 @@ mips64_fill_gregset (const struct regcache *regcache,
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf,
-                                   register_size (current_gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno));
       dst = regp + regaddr;
       store_signed_integer (dst, 8, val);
     }
@@ -379,32 +400,35 @@ void
 mips64_supply_fpregset (struct regcache *regcache,
                        const mips64_elf_fpregset_t *fpregsetp)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int regi;
 
   /* See mips_linux_o32_sigframe_init for a description of the
      peculiar FP register layout.  */
-  if (register_size (current_gdbarch, FP0_REGNUM) == 4)
+  if (register_size (gdbarch, gdbarch_fp0_regnum (gdbarch)) == 4)
     for (regi = 0; regi < 32; regi++)
       {
        const gdb_byte *reg_ptr = (const gdb_byte *)(*fpregsetp + (regi & ~1));
-       if ((gdbarch_byte_order (current_gdbarch)
-           == BFD_ENDIAN_BIG) != (regi & 1))
+       if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
          reg_ptr += 4;
-       regcache_raw_supply (regcache, FP0_REGNUM + regi, reg_ptr);
+       regcache_raw_supply (regcache,
+                            gdbarch_fp0_regnum (gdbarch) + regi,
+                            reg_ptr);
       }
   else
     for (regi = 0; regi < 32; regi++)
-      regcache_raw_supply (regcache, FP0_REGNUM + regi,
+      regcache_raw_supply (regcache,
+                          gdbarch_fp0_regnum (gdbarch) + regi,
                           (const char *)(*fpregsetp + regi));
 
-  supply_32bit_reg (regcache, mips_regnum (current_gdbarch)->fp_control_status,
+  supply_32bit_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
                    (const 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 (regcache,
-                   mips_regnum (current_gdbarch)->fp_implementation_revision,
+                   mips_regnum (gdbarch)->fp_implementation_revision,
                    (const gdb_byte *)(*fpregsetp + 32) + 4);
 }
 
@@ -415,47 +439,46 @@ void
 mips64_fill_fpregset (const struct regcache *regcache,
                      mips64_elf_fpregset_t *fpregsetp, int regno)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   gdb_byte *to;
 
-  if ((regno >= FP0_REGNUM) && (regno < FP0_REGNUM + 32))
+  if ((regno >= gdbarch_fp0_regnum (gdbarch))
+      && (regno < gdbarch_fp0_regnum (gdbarch) + 32))
     {
       /* See mips_linux_o32_sigframe_init for a description of the
         peculiar FP register layout.  */
-      if (register_size (current_gdbarch, regno) == 4)
+      if (register_size (gdbarch, regno) == 4)
        {
-         int regi = regno - FP0_REGNUM;
+         int regi = regno - gdbarch_fp0_regnum (gdbarch);
 
          to = (gdb_byte *) (*fpregsetp + (regi & ~1));
-         if ((gdbarch_byte_order (current_gdbarch)
-             == BFD_ENDIAN_BIG) != (regi & 1))
+         if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (regi & 1))
            to += 4;
          regcache_raw_collect (regcache, regno, to);
        }
       else
        {
-         to = (gdb_byte *) (*fpregsetp + regno - FP0_REGNUM);
+         to = (gdb_byte *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
          regcache_raw_collect (regcache, regno, to);
        }
     }
-  else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
+  else if (regno == mips_regnum (gdbarch)->fp_control_status)
     {
       gdb_byte buf[MAX_REGISTER_SIZE];
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf,
-                                   register_size (current_gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno));
       to = (gdb_byte *) (*fpregsetp + 32);
       store_signed_integer (to, 4, val);
     }
-  else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
+  else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     {
       gdb_byte buf[MAX_REGISTER_SIZE];
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf,
-                                   register_size (current_gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno));
       to = (gdb_byte *) (*fpregsetp + 32) + 4;
       store_signed_integer (to, 4, val);
     }
@@ -464,12 +487,13 @@ mips64_fill_fpregset (const struct regcache *regcache,
       int regi;
 
       for (regi = 0; regi < 32; regi++)
-       mips64_fill_fpregset (regcache, fpregsetp, FP0_REGNUM + regi);
+       mips64_fill_fpregset (regcache, fpregsetp,
+                             gdbarch_fp0_regnum (gdbarch) + regi);
       mips64_fill_fpregset (regcache, fpregsetp,
-                           mips_regnum (current_gdbarch)->fp_control_status);
+                           mips_regnum (gdbarch)->fp_control_status);
       mips64_fill_fpregset (regcache, fpregsetp,
-                           (mips_regnum (current_gdbarch)
-                            ->fp_implementation_revision));
+                           (mips_regnum (gdbarch)
+                             ->fp_implementation_revision));
     }
 }
 
@@ -540,6 +564,28 @@ static struct core_fns regset_core_fns =
   NULL                                 /* next */
 };
 
+static const struct target_desc *
+mips_linux_core_read_description (struct gdbarch *gdbarch,
+                                 struct target_ops *target,
+                                 bfd *abfd)
+{
+  asection *section = bfd_get_section_by_name (abfd, ".reg");
+  if (! section)
+    return NULL;
+
+  switch (bfd_section_size (abfd, section))
+    {
+    case sizeof (mips_elf_gregset_t):
+      return mips_tdesc_gp32;
+
+    case sizeof (mips64_elf_gregset_t):
+      return mips_tdesc_gp64;
+
+    default:
+      return NULL;
+    }
+}
+
 
 /* Check the code at PC for a dynamic linker lazy resolution stub.
    Because they aren't in the .plt section, we pattern-match on the
@@ -558,7 +604,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name)
 {
   unsigned char buf[28], *p;
   ULONGEST insn, insn1;
-  int n64 = (mips_abi (current_gdbarch) == MIPS_ABI_N64);
+  int n64 = (mips_abi (target_gdbarch) == MIPS_ABI_N64);
 
   read_memory (pc - 12, buf, 28);
 
@@ -621,13 +667,13 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name)
 }
 
 /* Return non-zero iff PC belongs to the dynamic linker resolution
-   code or to a stub.  */
+   code, a PLT entry, or a lazy binding stub.  */
 
 static int
 mips_linux_in_dynsym_resolve_code (CORE_ADDR pc)
 {
   /* Check whether PC is in the dynamic linker.  This also checks
-     whether it is in the .plt section, which MIPS does not use.  */
+     whether it is in the .plt section, used by non-PIC executables.  */
   if (svr4_in_dynsym_resolve_code (pc))
     return 1;
 
@@ -643,8 +689,8 @@ mips_linux_in_dynsym_resolve_code (CORE_ADDR pc)
    and glibc_skip_solib_resolver in glibc-tdep.c.  The normal glibc
    implementation of this triggers at "fixup" from the same objfile as
    "_dl_runtime_resolve"; MIPS GNU/Linux can trigger at
-   "__dl_runtime_resolve" directly.  An unresolved PLT entry will
-   point to _dl_runtime_resolve, which will first call
+   "__dl_runtime_resolve" directly.  An unresolved lazy binding
+   stub will point to _dl_runtime_resolve, which will first call
    __dl_runtime_resolve, and then pass control to the resolved
    function.  */
 
@@ -658,7 +704,7 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
   if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc)
     return frame_pc_unwind (get_current_frame ());
 
-  return 0;
+  return glibc_skip_solib_resolver (gdbarch, pc);
 }
 
 /* Signal trampoline support.  There are four supported layouts for a
@@ -667,12 +713,12 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
    efficient way, but simplest.  First, declare all the unwinders.  */
 
 static void mips_linux_o32_sigframe_init (const struct tramp_frame *self,
-                                         struct frame_info *next_frame,
+                                         struct frame_info *this_frame,
                                          struct trad_frame_cache *this_cache,
                                          CORE_ADDR func);
 
 static void mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
-                                            struct frame_info *next_frame,
+                                            struct frame_info *this_frame,
                                             struct trad_frame_cache *this_cache,
                                             CORE_ADDR func);
 
@@ -808,13 +854,14 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = {
 
 static void
 mips_linux_o32_sigframe_init (const struct tramp_frame *self,
-                             struct frame_info *next_frame,
+                             struct frame_info *this_frame,
                              struct trad_frame_cache *this_cache,
                              CORE_ADDR func)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int ireg, reg_position;
   CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
-  const struct mips_regnum *regs = mips_regnum (current_gdbarch);
+  const struct mips_regnum *regs = mips_regnum (gdbarch);
   CORE_ADDR regs_base;
 
   if (self == &mips_linux_o32_sigframe)
@@ -827,21 +874,21 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
      per-frame basis, but right now we don't; the kernel saves eight
      bytes but we only want four.  Use regs_base to access any
      64-bit fields.  */
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     regs_base = sigcontext_base + 4;
   else
     regs_base = sigcontext_base;
 
-#if 0
-  trad_frame_set_reg_addr (this_cache, ORIG_ZERO_REGNUM
-                                      + gdbarch_num_regs (current_gdbarch),
-                          regs_base + SIGCONTEXT_REGS);
-#endif
+  if (mips_linux_restart_reg_p (gdbarch))
+    trad_frame_set_reg_addr (this_cache,
+                            (MIPS_RESTART_REGNUM
+                             + gdbarch_num_regs (gdbarch)),
+                            regs_base + SIGCONTEXT_REGS);
 
   for (ireg = 1; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
                             ireg + MIPS_ZERO_REGNUM
-                              + gdbarch_num_regs (current_gdbarch),
+                              + gdbarch_num_regs (gdbarch),
                             regs_base + SIGCONTEXT_REGS
                             + ireg * SIGCONTEXT_REG_SIZE);
 
@@ -854,38 +901,38 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
      layout, since we can't tell, and it's much more common.  Which bits are
      the "high" bits depends on endianness.  */
   for (ireg = 0; ireg < 32; ireg++)
-    if ((gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1))
+    if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1))
       trad_frame_set_reg_addr (this_cache,
                               ireg + regs->fp0 +
-                                gdbarch_num_regs (current_gdbarch),
+                                gdbarch_num_regs (gdbarch),
                               sigcontext_base + SIGCONTEXT_FPREGS + 4
                               + (ireg & ~1) * SIGCONTEXT_REG_SIZE);
     else
       trad_frame_set_reg_addr (this_cache,
                               ireg + regs->fp0
-                                + gdbarch_num_regs (current_gdbarch),
+                                + gdbarch_num_regs (gdbarch),
                               sigcontext_base + SIGCONTEXT_FPREGS
                               + (ireg & ~1) * SIGCONTEXT_REG_SIZE);
 
   trad_frame_set_reg_addr (this_cache,
-                          regs->pc + gdbarch_num_regs (current_gdbarch),
+                          regs->pc + gdbarch_num_regs (gdbarch),
                           regs_base + SIGCONTEXT_PC);
 
   trad_frame_set_reg_addr (this_cache,
                           regs->fp_control_status
-                          + gdbarch_num_regs (current_gdbarch),
+                          + gdbarch_num_regs (gdbarch),
                           sigcontext_base + SIGCONTEXT_FPCSR);
   trad_frame_set_reg_addr (this_cache,
-                          regs->hi + gdbarch_num_regs (current_gdbarch),
+                          regs->hi + gdbarch_num_regs (gdbarch),
                           regs_base + SIGCONTEXT_HI);
   trad_frame_set_reg_addr (this_cache,
-                          regs->lo + gdbarch_num_regs (current_gdbarch),
+                          regs->lo + gdbarch_num_regs (gdbarch),
                           regs_base + SIGCONTEXT_LO);
   trad_frame_set_reg_addr (this_cache,
-                          regs->cause + gdbarch_num_regs (current_gdbarch),
+                          regs->cause + gdbarch_num_regs (gdbarch),
                           sigcontext_base + SIGCONTEXT_CAUSE);
   trad_frame_set_reg_addr (this_cache,
-                          regs->badvaddr + gdbarch_num_regs (current_gdbarch),
+                          regs->badvaddr + gdbarch_num_regs (gdbarch),
                           sigcontext_base + SIGCONTEXT_BADVADDR);
 
   /* Choice of the bottom of the sigframe is somewhat arbitrary.  */
@@ -912,7 +959,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
     sigset_t            uc_sigmask;   [ mask last for extensibility ]
   };
 
-  struct rt_sigframe_n32 {
+  struct rt_sigframe {
     u32 rs_ass[4];                  [ argument save space for o32 ]
     u32 rs_code[2];                 [ signal trampoline ]
     struct siginfo rs_info;
@@ -933,15 +980,23 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
     unsigned long long sc_regs[32];
     unsigned long long sc_fpregs[32];
     unsigned long long sc_mdhi;
+    unsigned long long sc_hi1;
+    unsigned long long sc_hi2;
+    unsigned long long sc_hi3;
     unsigned long long sc_mdlo;
+    unsigned long long sc_lo1;
+    unsigned long long sc_lo2;
+    unsigned long long sc_lo3;
     unsigned long long sc_pc;
-    unsigned int       sc_status;
     unsigned int       sc_fpc_csr;
-    unsigned int       sc_fpc_eir;
     unsigned int       sc_used_math;
-    unsigned int       sc_cause;
-    unsigned int       sc_badvaddr;
-  };  */
+    unsigned int       sc_dsp;
+    unsigned int       sc_reserved;
+  };
+
+  That is the post-2.6.12 definition of the 64-bit sigcontext; before
+  then, there were no hi1-hi3 or lo1-lo3.  Cause and badvaddr were
+  included too.  */
 /* *INDENT-ON* */
 
 #define N32_STACK_T_SIZE               STACK_T_SIZE
@@ -958,71 +1013,62 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
 #define N64_SIGCONTEXT_REGS     (0 * 8)
 #define N64_SIGCONTEXT_FPREGS   (32 * 8)
 #define N64_SIGCONTEXT_HI       (64 * 8)
-#define N64_SIGCONTEXT_LO       (65 * 8)
-#define N64_SIGCONTEXT_PC       (66 * 8)
-#define N64_SIGCONTEXT_FPCSR    (67 * 8 + 1 * 4)
-#define N64_SIGCONTEXT_FIR      (67 * 8 + 2 * 4)
-#define N64_SIGCONTEXT_CAUSE    (67 * 8 + 4 * 4)
-#define N64_SIGCONTEXT_BADVADDR (67 * 8 + 5 * 4)
+#define N64_SIGCONTEXT_LO       (68 * 8)
+#define N64_SIGCONTEXT_PC       (72 * 8)
+#define N64_SIGCONTEXT_FPCSR    (73 * 8)
 
 #define N64_SIGCONTEXT_REG_SIZE 8
 
 static void
 mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
-                                struct frame_info *next_frame,
+                                struct frame_info *this_frame,
                                 struct trad_frame_cache *this_cache,
                                 CORE_ADDR func)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int ireg, reg_position;
   CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
-  const struct mips_regnum *regs = mips_regnum (current_gdbarch);
+  const struct mips_regnum *regs = mips_regnum (gdbarch);
 
   if (self == &mips_linux_n32_rt_sigframe)
     sigcontext_base += N32_SIGFRAME_SIGCONTEXT_OFFSET;
   else
     sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET;
 
-#if 0
-  trad_frame_set_reg_addr (this_cache, 
-                          ORIG_ZERO_REGNUM
-                            + gdbarch_num_regs (current_gdbarch),
-                          sigcontext_base + N64_SIGCONTEXT_REGS);
-#endif
+  if (mips_linux_restart_reg_p (gdbarch))
+    trad_frame_set_reg_addr (this_cache,
+                            (MIPS_RESTART_REGNUM
+                             + gdbarch_num_regs (gdbarch)),
+                            sigcontext_base + N64_SIGCONTEXT_REGS);
 
   for (ireg = 1; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
                             ireg + MIPS_ZERO_REGNUM
-                            + gdbarch_num_regs (current_gdbarch),
+                            + gdbarch_num_regs (gdbarch),
                             sigcontext_base + N64_SIGCONTEXT_REGS
                             + ireg * N64_SIGCONTEXT_REG_SIZE);
 
   for (ireg = 0; ireg < 32; ireg++)
     trad_frame_set_reg_addr (this_cache,
                             ireg + regs->fp0
-                            + gdbarch_num_regs (current_gdbarch),
+                            + gdbarch_num_regs (gdbarch),
                             sigcontext_base + N64_SIGCONTEXT_FPREGS
                             + ireg * N64_SIGCONTEXT_REG_SIZE);
 
   trad_frame_set_reg_addr (this_cache,
-                          regs->pc + gdbarch_num_regs (current_gdbarch),
+                          regs->pc + gdbarch_num_regs (gdbarch),
                           sigcontext_base + N64_SIGCONTEXT_PC);
 
   trad_frame_set_reg_addr (this_cache,
                           regs->fp_control_status
-                          + gdbarch_num_regs (current_gdbarch),
+                          + gdbarch_num_regs (gdbarch),
                           sigcontext_base + N64_SIGCONTEXT_FPCSR);
   trad_frame_set_reg_addr (this_cache,
-                          regs->hi + gdbarch_num_regs (current_gdbarch),
+                          regs->hi + gdbarch_num_regs (gdbarch),
                           sigcontext_base + N64_SIGCONTEXT_HI);
   trad_frame_set_reg_addr (this_cache,
-                          regs->lo + gdbarch_num_regs (current_gdbarch),
+                          regs->lo + gdbarch_num_regs (gdbarch),
                           sigcontext_base + N64_SIGCONTEXT_LO);
-  trad_frame_set_reg_addr (this_cache,
-                          regs->cause + gdbarch_num_regs (current_gdbarch),
-                          sigcontext_base + N64_SIGCONTEXT_CAUSE);
-  trad_frame_set_reg_addr (this_cache,
-                          regs->badvaddr + gdbarch_num_regs (current_gdbarch),
-                          sigcontext_base + N64_SIGCONTEXT_BADVADDR);
 
   /* Choice of the bottom of the sigframe is somewhat arbitrary.  */
   trad_frame_set_id (this_cache,
@@ -1030,6 +1076,51 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
                                     func));
 }
 
+static void
+mips_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch), pc);
+
+  /* Clear the syscall restart flag.  */
+  if (mips_linux_restart_reg_p (gdbarch))
+    regcache_cooked_write_unsigned (regcache, MIPS_RESTART_REGNUM, 0);
+}
+
+/* Return 1 if MIPS_RESTART_REGNUM is usable.  */
+
+int
+mips_linux_restart_reg_p (struct gdbarch *gdbarch)
+{
+  /* If we do not have a target description with registers, then
+     MIPS_RESTART_REGNUM will not be included in the register set.  */
+  if (!tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return 0;
+
+  /* If we do, then MIPS_RESTART_REGNUM is safe to check; it will
+     either be GPR-sized or missing.  */
+  return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0;
+}
+
+/* When FRAME is at a syscall instruction, return the PC of the next
+   instruction to be executed.  */
+
+static CORE_ADDR
+mips_linux_syscall_next_pc (struct frame_info *frame)
+{
+  CORE_ADDR pc = get_frame_pc (frame);
+  ULONGEST v0 = get_frame_register_unsigned (frame, MIPS_V0_REGNUM);
+
+  /* If we are about to make a sigreturn syscall, use the unwinder to
+     decode the signal frame.  */
+  if (v0 == MIPS_NR_sigreturn
+      || v0 == MIPS_NR_rt_sigreturn
+      || v0 == MIPS_NR_N64_rt_sigreturn
+      || v0 == MIPS_NR_N32_rt_sigreturn)
+    return frame_pc_unwind (get_current_frame ());
+
+  return pc + 4;
+}
 
 /* Initialize one of the GNU/Linux OS ABIs.  */
 
@@ -1039,6 +1130,7 @@ mips_linux_init_abi (struct gdbarch_info info,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum mips_abi abi = mips_abi (gdbarch);
+  struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
 
   switch (abi)
     {
@@ -1077,11 +1169,9 @@ mips_linux_init_abi (struct gdbarch_info info,
        tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
        break;
       default:
-       internal_error (__FILE__, __LINE__, _("can't handle ABI"));
        break;
     }
 
-  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
   set_gdbarch_skip_solib_resolver (gdbarch, mips_linux_skip_resolver);
 
   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
@@ -1099,8 +1189,36 @@ mips_linux_init_abi (struct gdbarch_info info,
        = mips_linux_in_dynsym_resolve_code;
     }
   set_solib_ops (gdbarch, &mips_svr4_so_ops);
+
+  set_gdbarch_write_pc (gdbarch, mips_linux_write_pc);
+
+  set_gdbarch_core_read_description (gdbarch,
+                                    mips_linux_core_read_description);
+
+  tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+
+  if (tdesc_data)
+    {
+      const struct tdesc_feature *feature;
+
+      /* If we have target-described registers, then we can safely
+        reserve a number for MIPS_RESTART_REGNUM (whether it is
+        described or not).  */
+      gdb_assert (gdbarch_num_regs (gdbarch) <= MIPS_RESTART_REGNUM);
+      set_gdbarch_num_regs (gdbarch, MIPS_RESTART_REGNUM + 1);
+
+      /* If it's present, then assign it to the reserved number.  */
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.mips.linux");
+      if (feature != NULL)
+       tdesc_numbered_register (feature, tdesc_data, MIPS_RESTART_REGNUM,
+                                "restart");
+    }
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_mips_linux_tdep;
+
 void
 _initialize_mips_linux_tdep (void)
 {
This page took 0.038873 seconds and 4 git commands to generate.