2011-02-21 Hui Zhu <teawater@gmail.com>
[deliverable/binutils-gdb.git] / gdb / mips-linux-tdep.c
index d631a7b3c32d000234567da53a66086e2b823eed..c78d5d649f1d7be61258384accf961b81b7ef1f9 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux on MIPS processors.
 
-   Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #include "solist.h"
 #include "symtab.h"
 #include "target-descriptions.h"
+#include "regset.h"
 #include "mips-linux-tdep.h"
+#include "glibc-tdep.h"
+#include "linux-tdep.h"
+#include "xml-syscall.h"
 
 static struct target_so_ops mips_svr4_so_ops;
 
@@ -54,6 +58,7 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
   struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   char buf[gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT];
 
   jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
@@ -64,7 +69,8 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
     return 0;
 
   *pc = extract_unsigned_integer (buf,
-                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
+                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
+                                 byte_order);
 
   return 1;
 }
@@ -76,10 +82,11 @@ mips_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 static void
 supply_32bit_reg (struct regcache *regcache, int regnum, const void *addr)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[MAX_REGISTER_SIZE];
-  store_signed_integer (buf,
-                       register_size (get_regcache_arch (regcache), regnum),
-                        extract_signed_integer (addr, 4));
+  store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
+                        extract_signed_integer (addr, 4, byte_order));
   regcache_raw_supply (regcache, regnum, buf);
 }
 
@@ -122,6 +129,16 @@ mips_supply_gregset (struct regcache *regcache,
     regcache_raw_supply (regcache, regi, zerobuf);
 }
 
+static void
+mips_supply_gregset_wrapper (const struct regset *regset,
+                             struct regcache *regcache,
+                            int regnum, const void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips_elf_gregset_t));
+
+  mips_supply_gregset (regcache, (const mips_elf_gregset_t *)gregs);
+}
+
 /* Pack our registers (or one register) into an elf_gregset_t.  */
 
 void
@@ -180,6 +197,16 @@ mips_fill_gregset (const struct regcache *regcache,
     }
 }
 
+static void
+mips_fill_gregset_wrapper (const struct regset *regset,
+                          const struct regcache *regcache,
+                          int regnum, void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips_elf_gregset_t));
+
+  mips_fill_gregset (regcache, (mips_elf_gregset_t *)gregs, regnum);
+}
+
 /* Likewise, unpack an elf_fpregset_t.  */
 
 void
@@ -207,6 +234,16 @@ mips_supply_fpregset (struct regcache *regcache,
                       zerobuf);
 }
 
+static void
+mips_supply_fpregset_wrapper (const struct regset *regset,
+                              struct regcache *regcache,
+                             int regnum, const void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips_elf_fpregset_t));
+
+  mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *)gregs);
+}
+
 /* Likewise, pack one or all floating point registers into an
    elf_fpregset_t.  */
 
@@ -240,6 +277,16 @@ mips_fill_fpregset (const struct regcache *regcache,
     }
 }
 
+static void
+mips_fill_fpregset_wrapper (const struct regset *regset,
+                           const struct regcache *regcache,
+                           int regnum, void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips_elf_fpregset_t));
+
+  mips_fill_fpregset (regcache, (mips_elf_fpregset_t *)gregs, regnum);
+}
+
 /* Support for 64-bit ABIs.  */
 
 /* Figure out where the longjmp will land.
@@ -257,6 +304,7 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   CORE_ADDR jb_addr;
   struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   void *buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
   int element_size = gdbarch_ptr_bit (gdbarch) == 32 ? 4 : 8;
 
@@ -268,7 +316,8 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
     return 0;
 
   *pc = extract_unsigned_integer (buf,
-                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
+                                 gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT,
+                                 byte_order);
 
   return 1;
 }
@@ -279,7 +328,7 @@ mips64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 
 /* Supply a 64-bit register.  */
 
-void
+static void
 supply_64bit_reg (struct regcache *regcache, int regnum,
                  const gdb_byte *buf)
 {
@@ -335,6 +384,16 @@ mips64_supply_gregset (struct regcache *regcache,
     regcache_raw_supply (regcache, regi, zerobuf);
 }
 
+static void
+mips64_supply_gregset_wrapper (const struct regset *regset,
+                               struct regcache *regcache,
+                              int regnum, const void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips64_elf_gregset_t));
+
+  mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *)gregs);
+}
+
 /* Pack our registers (or one register) into a 64-bit elf_gregset_t.  */
 
 void
@@ -342,6 +401,7 @@ mips64_fill_gregset (const struct regcache *regcache,
                     mips64_elf_gregset_t *gregsetp, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int regaddr, regi;
   mips64_elf_greg_t *regp = *gregsetp;
   void *dst;
@@ -354,7 +414,8 @@ mips64_fill_gregset (const struct regcache *regcache,
       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_regnum (gdbarch)->badvaddr);
       mips64_fill_gregset (regcache, gregsetp, MIPS_PS_REGNUM);
       mips64_fill_gregset (regcache, gregsetp,  mips_regnum (gdbarch)->cause);
       mips64_fill_gregset (regcache, gregsetp, MIPS_RESTART_REGNUM);
@@ -387,12 +448,23 @@ mips64_fill_gregset (const struct regcache *regcache,
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno),
+                                   byte_order);
       dst = regp + regaddr;
-      store_signed_integer (dst, 8, val);
+      store_signed_integer (dst, 8, byte_order, val);
     }
 }
 
+static void
+mips64_fill_gregset_wrapper (const struct regset *regset,
+                            const struct regcache *regcache,
+                            int regnum, void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips64_elf_gregset_t));
+
+  mips64_fill_gregset (regcache, (mips64_elf_gregset_t *)gregs, regnum);
+}
+
 /* Likewise, unpack an elf_fpregset_t.  */
 
 void
@@ -431,6 +503,16 @@ mips64_supply_fpregset (struct regcache *regcache,
                    (const gdb_byte *)(*fpregsetp + 32) + 4);
 }
 
+static void
+mips64_supply_fpregset_wrapper (const struct regset *regset,
+                                struct regcache *regcache,
+                               int regnum, const void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips64_elf_fpregset_t));
+
+  mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *)gregs);
+}
+
 /* Likewise, pack one or all floating point registers into an
    elf_fpregset_t.  */
 
@@ -439,6 +521,7 @@ mips64_fill_fpregset (const struct regcache *regcache,
                      mips64_elf_fpregset_t *fpregsetp, int regno)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte *to;
 
   if ((regno >= gdbarch_fp0_regnum (gdbarch))
@@ -457,7 +540,8 @@ mips64_fill_fpregset (const struct regcache *regcache,
        }
       else
        {
-         to = (gdb_byte *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch));
+         to = (gdb_byte *) (*fpregsetp + regno
+                            - gdbarch_fp0_regnum (gdbarch));
          regcache_raw_collect (regcache, regno, to);
        }
     }
@@ -467,9 +551,10 @@ mips64_fill_fpregset (const struct regcache *regcache,
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno),
+                                   byte_order);
       to = (gdb_byte *) (*fpregsetp + 32);
-      store_signed_integer (to, 4, val);
+      store_signed_integer (to, 4, byte_order, val);
     }
   else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
     {
@@ -477,9 +562,10 @@ mips64_fill_fpregset (const struct regcache *regcache,
       LONGEST val;
 
       regcache_raw_collect (regcache, regno, buf);
-      val = extract_signed_integer (buf, register_size (gdbarch, regno));
+      val = extract_signed_integer (buf, register_size (gdbarch, regno),
+                                   byte_order);
       to = (gdb_byte *) (*fpregsetp + 32) + 4;
-      store_signed_integer (to, 4, val);
+      store_signed_integer (to, 4, byte_order, val);
     }
   else if (regno == -1)
     {
@@ -496,72 +582,75 @@ mips64_fill_fpregset (const struct regcache *regcache,
     }
 }
 
+static void
+mips64_fill_fpregset_wrapper (const struct regset *regset,
+                             const struct regcache *regcache,
+                             int regnum, void *gregs, size_t len)
+{
+  gdb_assert (len == sizeof (mips64_elf_fpregset_t));
 
-/*  Use a local version of this function to get the correct types for
-    regsets, until multi-arch core support is ready.  */
+  mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *)gregs, regnum);
+}
 
-static void
-fetch_core_registers (struct regcache *regcache,
-                     char *core_reg_sect, unsigned core_reg_size,
-                     int which, CORE_ADDR reg_addr)
+const struct regset *
+mips_linux_regset_from_core_section (struct gdbarch *gdbarch,
+                                    const char *sect_name, size_t sect_size)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   mips_elf_gregset_t gregset;
   mips_elf_fpregset_t fpregset;
   mips64_elf_gregset_t gregset64;
   mips64_elf_fpregset_t fpregset64;
 
-  if (which == 0)
+  if (strcmp (sect_name, ".reg") == 0)
     {
-      if (core_reg_size == sizeof (gregset))
+      if (sect_size == sizeof (gregset))
        {
-         memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
-         mips_supply_gregset (regcache,
-                              (const mips_elf_gregset_t *) &gregset);
+         if (tdep->gregset == NULL)
+           tdep->gregset = regset_alloc (gdbarch,
+                                          mips_supply_gregset_wrapper,
+                                         mips_fill_gregset_wrapper);
+         return tdep->gregset;
        }
-      else if (core_reg_size == sizeof (gregset64))
+      else if (sect_size == sizeof (gregset64))
        {
-         memcpy ((char *) &gregset64, core_reg_sect, sizeof (gregset64));
-         mips64_supply_gregset (regcache,
-                                (const mips64_elf_gregset_t *) &gregset64);
+         if (tdep->gregset64 == NULL)
+           tdep->gregset64 = regset_alloc (gdbarch,
+                                            mips64_supply_gregset_wrapper,
+                                           mips64_fill_gregset_wrapper);
+         return tdep->gregset64;
        }
       else
        {
          warning (_("wrong size gregset struct in core file"));
        }
     }
-  else if (which == 2)
+  else if (strcmp (sect_name, ".reg2") == 0)
     {
-      if (core_reg_size == sizeof (fpregset))
+      if (sect_size == sizeof (fpregset))
        {
-         memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
-         mips_supply_fpregset (regcache,
-                               (const mips_elf_fpregset_t *) &fpregset);
+         if (tdep->fpregset == NULL)
+           tdep->fpregset = regset_alloc (gdbarch,
+                                           mips_supply_fpregset_wrapper,
+                                          mips_fill_fpregset_wrapper);
+         return tdep->fpregset;
        }
-      else if (core_reg_size == sizeof (fpregset64))
+      else if (sect_size == sizeof (fpregset64))
        {
-         memcpy ((char *) &fpregset64, core_reg_sect,
-                 sizeof (fpregset64));
-         mips64_supply_fpregset (regcache,
-                                 (const mips64_elf_fpregset_t *) &fpregset64);
+         if (tdep->fpregset64 == NULL)
+           tdep->fpregset64 = regset_alloc (gdbarch,
+                                             mips64_supply_fpregset_wrapper,
+                                            mips64_fill_fpregset_wrapper);
+         return tdep->fpregset64;
        }
       else
        {
          warning (_("wrong size fpregset struct in core file"));
        }
     }
-}
-
-/* Register that we are able to handle ELF file formats using standard
-   procfs "regset" structures.  */
 
-static struct core_fns regset_core_fns =
-{
-  bfd_target_elf_flavour,              /* core_flavour */
-  default_check_format,                        /* check_format */
-  default_core_sniffer,                        /* core_sniffer */
-  fetch_core_registers,                        /* core_read_registers */
-  NULL                                 /* next */
-};
+  return NULL;
+}
 
 static const struct target_desc *
 mips_linux_core_read_description (struct gdbarch *gdbarch,
@@ -603,7 +692,8 @@ 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);
+  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
 
   read_memory (pc - 12, buf, 28);
 
@@ -621,7 +711,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name)
   p = buf + 12;
   while (p >= buf)
     {
-      insn = extract_unsigned_integer (p, 4);
+      insn = extract_unsigned_integer (p, 4, byte_order);
       if (insn == insn1)
        break;
       p -= 4;
@@ -629,7 +719,7 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name)
   if (p < buf)
     return 0;
 
-  insn = extract_unsigned_integer (p + 4, 4);
+  insn = extract_unsigned_integer (p + 4, 4, byte_order);
   if (n64)
     {
       /* daddu t7,ra */
@@ -643,12 +733,12 @@ mips_linux_in_dynsym_stub (CORE_ADDR pc, char *name)
        return 0;
     }
 
-  insn = extract_unsigned_integer (p + 8, 4);
+  insn = extract_unsigned_integer (p + 8, 4, byte_order);
   /* jalr t9,ra */
   if (insn != 0x0320f809)
     return 0;
 
-  insn = extract_unsigned_integer (p + 12, 4);
+  insn = extract_unsigned_integer (p + 12, 4, byte_order);
   if (n64)
     {
       /* daddiu t8,zero,0 */
@@ -666,13 +756,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;
 
@@ -688,8 +778,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.  */
 
@@ -701,9 +791,9 @@ mips_linux_skip_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
   resolver = lookup_minimal_symbol ("__dl_runtime_resolve", NULL, NULL);
 
   if (resolver && SYMBOL_VALUE_ADDRESS (resolver) == pc)
-    return frame_pc_unwind (get_current_frame ());
+    return frame_unwind_caller_pc (get_current_frame ());
 
-  return 0;
+  return glibc_skip_solib_resolver (gdbarch, pc);
 }
 
 /* Signal trampoline support.  There are four supported layouts for a
@@ -785,7 +875,7 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = {
 
    struct sigframe {
      u32 sf_ass[4];            [argument save space for o32]
-     u32 sf_code[2];           [signal trampoline]
+     u32 sf_code[2];           [signal trampoline or fill]
      struct sigcontext sf_sc;
      sigset_t sf_mask;
    };
@@ -815,7 +905,7 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = {
 
    struct rt_sigframe {
      u32 rs_ass[4];            [argument save space for o32]
-     u32 rs_code[2]            [signal trampoline]
+     u32 rs_code[2]            [signal trampoline or fill]
      struct siginfo rs_info;
      struct ucontext rs_uc;
    };
@@ -830,7 +920,6 @@ static const struct tramp_frame mips_linux_n64_rt_sigframe = {
    };  */
 /* *INDENT-ON* */
 
-#define SIGFRAME_CODE_OFFSET         (4 * 4)
 #define SIGFRAME_SIGCONTEXT_OFFSET   (6 * 4)
 
 #define RTSIGFRAME_SIGINFO_SIZE      128
@@ -859,14 +948,15 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int ireg, reg_position;
-  CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
+  CORE_ADDR frame_sp = get_frame_sp (this_frame);
+  CORE_ADDR sigcontext_base;
   const struct mips_regnum *regs = mips_regnum (gdbarch);
   CORE_ADDR regs_base;
 
   if (self == &mips_linux_o32_sigframe)
-    sigcontext_base += SIGFRAME_SIGCONTEXT_OFFSET;
+    sigcontext_base = frame_sp + SIGFRAME_SIGCONTEXT_OFFSET;
   else
-    sigcontext_base += RTSIGFRAME_SIGCONTEXT_OFFSET;
+    sigcontext_base = frame_sp + RTSIGFRAME_SIGCONTEXT_OFFSET;
 
   /* I'm not proud of this hack.  Eventually we will have the
      infrastructure to indicate the size of saved registers on a
@@ -935,9 +1025,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
                           sigcontext_base + SIGCONTEXT_BADVADDR);
 
   /* Choice of the bottom of the sigframe is somewhat arbitrary.  */
-  trad_frame_set_id (this_cache,
-                    frame_id_build (func - SIGFRAME_CODE_OFFSET,
-                                    func));
+  trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
 }
 
 /* *INDENT-OFF* */
@@ -945,7 +1033,7 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self,
 
   struct rt_sigframe_n32 {
     u32 rs_ass[4];                  [ argument save space for o32 ]
-    u32 rs_code[2];                 [ signal trampoline ]
+    u32 rs_code[2];                 [ signal trampoline or fill ]
     struct siginfo rs_info;
     struct ucontextn32 rs_uc;
   };
@@ -1026,13 +1114,14 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int ireg, reg_position;
-  CORE_ADDR sigcontext_base = func - SIGFRAME_CODE_OFFSET;
+  CORE_ADDR frame_sp = get_frame_sp (this_frame);
+  CORE_ADDR sigcontext_base;
   const struct mips_regnum *regs = mips_regnum (gdbarch);
 
   if (self == &mips_linux_n32_rt_sigframe)
-    sigcontext_base += N32_SIGFRAME_SIGCONTEXT_OFFSET;
+    sigcontext_base = frame_sp + N32_SIGFRAME_SIGCONTEXT_OFFSET;
   else
-    sigcontext_base += N64_SIGFRAME_SIGCONTEXT_OFFSET;
+    sigcontext_base = frame_sp + N64_SIGFRAME_SIGCONTEXT_OFFSET;
 
   if (mips_linux_restart_reg_p (gdbarch))
     trad_frame_set_reg_addr (this_cache,
@@ -1070,9 +1159,7 @@ mips_linux_n32n64_sigframe_init (const struct tramp_frame *self,
                           sigcontext_base + N64_SIGCONTEXT_LO);
 
   /* Choice of the bottom of the sigframe is somewhat arbitrary.  */
-  trad_frame_set_id (this_cache,
-                    frame_id_build (func - SIGFRAME_CODE_OFFSET,
-                                    func));
+  trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
 }
 
 static void
@@ -1101,6 +1188,58 @@ mips_linux_restart_reg_p (struct gdbarch *gdbarch)
   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_unwind_caller_pc (get_current_frame ());
+
+  return pc + 4;
+}
+
+/* Return the current system call's number present in the
+   v0 register.  When the function fails, it returns -1.  */
+
+static LONGEST
+mips_linux_get_syscall_number (struct gdbarch *gdbarch,
+                              ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regsize = register_size (gdbarch, MIPS_V0_REGNUM);
+  /* The content of a register */
+  gdb_byte buf[8];
+  /* The result */
+  LONGEST ret;
+
+  /* Make sure we're in a known ABI */
+  gdb_assert (tdep->mips_abi == MIPS_ABI_O32
+             || tdep->mips_abi == MIPS_ABI_N32
+             || tdep->mips_abi == MIPS_ABI_N64);
+
+  gdb_assert (regsize <= sizeof (buf));
+
+  /* Getting the system call number from the register.
+     syscall number is in v0 or $2.  */
+  regcache_cooked_read (regcache, MIPS_V0_REGNUM, buf);
+
+  ret = extract_signed_integer (buf, regsize, byte_order);
+
+  return ret;
+}
+
 /* Initialize one of the GNU/Linux OS ABIs.  */
 
 static void
@@ -1111,6 +1250,11 @@ mips_linux_init_abi (struct gdbarch_info info,
   enum mips_abi abi = mips_abi (gdbarch);
   struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
 
+  linux_init_abi (info, gdbarch);
+
+  /* Get the syscall number from the arch's register.  */
+  set_gdbarch_get_syscall_number (gdbarch, mips_linux_get_syscall_number);
+
   switch (abi)
     {
       case MIPS_ABI_O32:
@@ -1120,6 +1264,7 @@ mips_linux_init_abi (struct gdbarch_info info,
          (gdbarch, svr4_ilp32_fetch_link_map_offsets);
        tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_sigframe);
        tramp_frame_prepend_unwinder (gdbarch, &mips_linux_o32_rt_sigframe);
+       set_xml_syscall_file_name ("syscalls/mips-o32-linux.xml");
        break;
       case MIPS_ABI_N32:
        set_gdbarch_get_longjmp_target (gdbarch,
@@ -1133,6 +1278,7 @@ mips_linux_init_abi (struct gdbarch_info info,
           does not distinguish between quiet and signalling NaNs).  */
        set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
        tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n32_rt_sigframe);
+       set_xml_syscall_file_name ("syscalls/mips-n32-linux.xml");
        break;
       case MIPS_ABI_N64:
        set_gdbarch_get_longjmp_target (gdbarch,
@@ -1146,12 +1292,12 @@ mips_linux_init_abi (struct gdbarch_info info,
           does not distinguish between quiet and signalling NaNs).  */
        set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
        tramp_frame_prepend_unwinder (gdbarch, &mips_linux_n64_rt_sigframe);
+       set_xml_syscall_file_name ("syscalls/mips-n64-linux.xml");
        break;
       default:
        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);
@@ -1175,6 +1321,11 @@ mips_linux_init_abi (struct gdbarch_info info,
   set_gdbarch_core_read_description (gdbarch,
                                     mips_linux_core_read_description);
 
+  set_gdbarch_regset_from_core_section (gdbarch,
+                                       mips_linux_regset_from_core_section);
+
+  tdep->syscall_next_pc = mips_linux_syscall_next_pc;
+
   if (tdesc_data)
     {
       const struct tdesc_feature *feature;
@@ -1194,6 +1345,9 @@ mips_linux_init_abi (struct gdbarch_info info,
     }
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_mips_linux_tdep;
+
 void
 _initialize_mips_linux_tdep (void)
 {
@@ -1207,6 +1361,4 @@ _initialize_mips_linux_tdep (void)
                              GDB_OSABI_LINUX,
                              mips_linux_init_abi);
     }
-
-  deprecated_add_core_fns (&regset_core_fns);
 }
This page took 0.045922 seconds and 4 git commands to generate.