gdb: change bug URL to https
[deliverable/binutils-gdb.git] / gdb / sparc-linux-tdep.c
index 858d0ce70914eca13726b5f03a5334ab1f177518..247fde21657c41fbde076256e106c5b207f131a1 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux SPARC.
 
-   Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2003-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -18,7 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "dwarf2-frame.h"
+#include "dwarf2/frame.h"
 #include "frame.h"
 #include "frame-unwind.h"
 #include "gdbtypes.h"
 #include "symtab.h"
 #include "trad-frame.h"
 #include "tramp-frame.h"
+#include "xml-syscall.h"
+#include "linux-tdep.h"
+
+/* The syscall's XML filename for sparc 32-bit.  */
+#define XML_SYSCALL_FILENAME_SPARC32 "syscalls/sparc-linux.xml"
 
 #include "sparc-tdep.h"
 
@@ -63,9 +68,9 @@ static const struct tramp_frame sparc32_linux_sigframe =
   SIGTRAMP_FRAME,
   4,
   {
-    { 0x821020d8, -1 },                /* mov __NR_sugreturn, %g1 */
-    { 0x91d02010, -1 },                /* ta  0x10 */
-    { TRAMP_SENTINEL_INSN, -1 }
+    { 0x821020d8, ULONGEST_MAX },              /* mov __NR_sigreturn, %g1 */
+    { 0x91d02010, ULONGEST_MAX },              /* ta  0x10 */
+    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
   },
   sparc32_linux_sigframe_init
 };
@@ -78,13 +83,38 @@ static const struct tramp_frame sparc32_linux_rt_sigframe =
   SIGTRAMP_FRAME,
   4,
   {
-    { 0x82102065, -1 },                /* mov __NR_rt_sigreturn, %g1 */
-    { 0x91d02010, -1 },                /* ta  0x10 */
-    { TRAMP_SENTINEL_INSN, -1 }
+    { 0x82102065, ULONGEST_MAX },              /* mov __NR_rt_sigreturn, %g1 */
+    { 0x91d02010, ULONGEST_MAX },              /* ta  0x10 */
+    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
   },
   sparc32_linux_sigframe_init
 };
 
+/* This enum represents the signals' numbers on the SPARC
+   architecture.  It just contains the signal definitions which are
+   different from the generic implementation.
+
+   It is derived from the file <arch/sparc/include/uapi/asm/signal.h>,
+   from the Linux kernel tree.  */
+
+enum
+  {
+    SPARC_LINUX_SIGEMT = 7,
+    SPARC_LINUX_SIGBUS = 10,
+    SPARC_LINUX_SIGSYS = 12,
+    SPARC_LINUX_SIGURG = 16,
+    SPARC_LINUX_SIGSTOP = 17,
+    SPARC_LINUX_SIGTSTP = 18,
+    SPARC_LINUX_SIGCONT = 19,
+    SPARC_LINUX_SIGCHLD = 20,
+    SPARC_LINUX_SIGIO = 23,
+    SPARC_LINUX_SIGPOLL = SPARC_LINUX_SIGIO,
+    SPARC_LINUX_SIGLOST = 29,
+    SPARC_LINUX_SIGPWR = SPARC_LINUX_SIGLOST,
+    SPARC_LINUX_SIGUSR1 = 30,
+    SPARC_LINUX_SIGUSR2 = 31,
+  };
+
 static void
 sparc32_linux_sigframe_init (const struct tramp_frame *self,
                             struct frame_info *this_frame,
@@ -135,9 +165,12 @@ sparc32_linux_step_trap (struct frame_info *frame, unsigned long insn)
     {
       ULONGEST sc_num = get_frame_register_unsigned (frame, SPARC_G1_REGNUM);
 
-      /* __NR_rt_sigreturn is 101 and __NR_sigreturn is 216  */
+      /* __NR_rt_sigreturn is 101 and __NR_sigreturn is 216.  */
       if (sc_num == 101 || sc_num == 216)
        {
+         struct gdbarch *gdbarch = get_frame_arch (frame);
+         enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
          ULONGEST sp, pc_offset;
 
          sp = get_frame_register_unsigned (frame, SPARC_SP_REGNUM);
@@ -157,7 +190,7 @@ sparc32_linux_step_trap (struct frame_info *frame, unsigned long insn)
          if (sc_num == 101)
            pc_offset += 128;
 
-         return read_memory_unsigned_integer (sp + pc_offset, 4);
+         return read_memory_unsigned_integer (sp + pc_offset, 4, byte_order);
        }
     }
 
@@ -165,7 +198,7 @@ sparc32_linux_step_trap (struct frame_info *frame, unsigned long insn)
 }
 \f
 
-const struct sparc_gregset sparc32_linux_core_gregset =
+const struct sparc_gregmap sparc32_linux_core_gregmap =
 {
   32 * 4,                      /* %psr */
   33 * 4,                      /* %pc */
@@ -184,7 +217,8 @@ sparc32_linux_supply_core_gregset (const struct regset *regset,
                                   struct regcache *regcache,
                                   int regnum, const void *gregs, size_t len)
 {
-  sparc32_supply_gregset (&sparc32_linux_core_gregset, regcache, regnum, gregs);
+  sparc32_supply_gregset (&sparc32_linux_core_gregmap,
+                         regcache, regnum, gregs);
 }
 
 static void
@@ -192,7 +226,8 @@ sparc32_linux_collect_core_gregset (const struct regset *regset,
                                    const struct regcache *regcache,
                                    int regnum, void *gregs, size_t len)
 {
-  sparc32_collect_gregset (&sparc32_linux_core_gregset, regcache, regnum, gregs);
+  sparc32_collect_gregset (&sparc32_linux_core_gregmap,
+                          regcache, regnum, gregs);
 }
 
 static void
@@ -200,7 +235,7 @@ sparc32_linux_supply_core_fpregset (const struct regset *regset,
                                    struct regcache *regcache,
                                    int regnum, const void *fpregs, size_t len)
 {
-  sparc32_supply_fpregset (regcache, regnum, fpregs);
+  sparc32_supply_fpregset (&sparc32_bsd_fpregmap, regcache, regnum, fpregs);
 }
 
 static void
@@ -208,22 +243,191 @@ sparc32_linux_collect_core_fpregset (const struct regset *regset,
                                     const struct regcache *regcache,
                                     int regnum, void *fpregs, size_t len)
 {
-  sparc32_collect_fpregset (regcache, regnum, fpregs);
+  sparc32_collect_fpregset (&sparc32_bsd_fpregmap, regcache, regnum, fpregs);
+}
+
+/* Set the program counter for process PTID to PC.  */
+
+#define PSR_SYSCALL    0x00004000
+
+static void
+sparc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ());
+  ULONGEST psr;
+
+  regcache_cooked_write_unsigned (regcache, tdep->pc_regnum, pc);
+  regcache_cooked_write_unsigned (regcache, tdep->npc_regnum, pc + 4);
+
+  /* Clear the "in syscall" bit to prevent the kernel from
+     messing with the PCs we just installed, if we happen to be
+     within an interrupted system call that the kernel wants to
+     restart.
+
+     Note that after we return from the dummy call, the PSR et al.
+     registers will be automatically restored, and the kernel
+     continues to restart the system call at this point.  */
+  regcache_cooked_read_unsigned (regcache, SPARC32_PSR_REGNUM, &psr);
+  psr &= ~PSR_SYSCALL;
+  regcache_cooked_write_unsigned (regcache, SPARC32_PSR_REGNUM, psr);
+}
+
+static LONGEST
+sparc32_linux_get_syscall_number (struct gdbarch *gdbarch,
+                                 thread_info *thread)
+{
+  struct regcache *regcache = get_thread_regcache (thread);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  /* The content of a register.  */
+  gdb_byte buf[4];
+  /* The result.  */
+  LONGEST ret;
+
+  /* Getting the system call number from the register.
+     When dealing with the sparc architecture, this information
+     is stored at the %g1 register.  */
+  regcache->cooked_read (SPARC_G1_REGNUM, buf);
+
+  ret = extract_signed_integer (buf, 4, byte_order);
+
+  return ret;
+}
+
+/* Implementation of `gdbarch_gdb_signal_from_target', as defined in
+   gdbarch.h.  */
+
+static enum gdb_signal
+sparc32_linux_gdb_signal_from_target (struct gdbarch *gdbarch,
+                                     int signal)
+{
+  switch (signal)
+    {
+    case SPARC_LINUX_SIGEMT:
+      return GDB_SIGNAL_EMT;
+
+    case SPARC_LINUX_SIGBUS:
+      return GDB_SIGNAL_BUS;
+
+    case SPARC_LINUX_SIGSYS:
+      return GDB_SIGNAL_SYS;
+
+    case SPARC_LINUX_SIGURG:
+      return GDB_SIGNAL_URG;
+
+    case SPARC_LINUX_SIGSTOP:
+      return GDB_SIGNAL_STOP;
+
+    case SPARC_LINUX_SIGTSTP:
+      return GDB_SIGNAL_TSTP;
+
+    case SPARC_LINUX_SIGCONT:
+      return GDB_SIGNAL_CONT;
+
+    case SPARC_LINUX_SIGCHLD:
+      return GDB_SIGNAL_CHLD;
+
+    /* No way to differentiate between SIGIO and SIGPOLL.
+       Therefore, we just handle the first one.  */
+    case SPARC_LINUX_SIGIO:
+      return GDB_SIGNAL_IO;
+
+    /* No way to differentiate between SIGLOST and SIGPWR.
+       Therefore, we just handle the first one.  */
+    case SPARC_LINUX_SIGLOST:
+      return GDB_SIGNAL_LOST;
+
+    case SPARC_LINUX_SIGUSR1:
+      return GDB_SIGNAL_USR1;
+
+    case SPARC_LINUX_SIGUSR2:
+      return GDB_SIGNAL_USR2;
+    }
+
+  return linux_gdb_signal_from_target (gdbarch, signal);
+}
+
+/* Implementation of `gdbarch_gdb_signal_to_target', as defined in
+   gdbarch.h.  */
+
+static int
+sparc32_linux_gdb_signal_to_target (struct gdbarch *gdbarch,
+                                   enum gdb_signal signal)
+{
+  switch (signal)
+    {
+    case GDB_SIGNAL_EMT:
+      return SPARC_LINUX_SIGEMT;
+
+    case GDB_SIGNAL_BUS:
+      return SPARC_LINUX_SIGBUS;
+
+    case GDB_SIGNAL_SYS:
+      return SPARC_LINUX_SIGSYS;
+
+    case GDB_SIGNAL_URG:
+      return SPARC_LINUX_SIGURG;
+
+    case GDB_SIGNAL_STOP:
+      return SPARC_LINUX_SIGSTOP;
+
+    case GDB_SIGNAL_TSTP:
+      return SPARC_LINUX_SIGTSTP;
+
+    case GDB_SIGNAL_CONT:
+      return SPARC_LINUX_SIGCONT;
+
+    case GDB_SIGNAL_CHLD:
+      return SPARC_LINUX_SIGCHLD;
+
+    case GDB_SIGNAL_IO:
+      return SPARC_LINUX_SIGIO;
+
+    case GDB_SIGNAL_POLL:
+      return SPARC_LINUX_SIGPOLL;
+
+    case GDB_SIGNAL_LOST:
+      return SPARC_LINUX_SIGLOST;
+
+    case GDB_SIGNAL_PWR:
+      return SPARC_LINUX_SIGPWR;
+
+    case GDB_SIGNAL_USR1:
+      return SPARC_LINUX_SIGUSR1;
+
+    case GDB_SIGNAL_USR2:
+      return SPARC_LINUX_SIGUSR2;
+    }
+
+  return linux_gdb_signal_to_target (gdbarch, signal);
 }
 
 \f
 
+static const struct regset sparc32_linux_gregset =
+  {
+    NULL,
+    sparc32_linux_supply_core_gregset,
+    sparc32_linux_collect_core_gregset
+  };
+
+static const struct regset sparc32_linux_fpregset =
+  {
+    NULL,
+    sparc32_linux_supply_core_fpregset,
+    sparc32_linux_collect_core_fpregset
+  };
+
 static void
 sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  tdep->gregset = regset_alloc (gdbarch, sparc32_linux_supply_core_gregset,
-                               sparc32_linux_collect_core_gregset);
+  linux_init_abi (info, gdbarch);
+
+  tdep->gregset = &sparc32_linux_gregset;
   tdep->sizeof_gregset = 152;
 
-  tdep->fpregset = regset_alloc (gdbarch, sparc32_linux_supply_core_fpregset,
-                                sparc32_linux_collect_core_fpregset);
+  tdep->fpregset = &sparc32_linux_fpregset;
   tdep->sizeof_fpregset = 396;
 
   tramp_frame_prepend_unwinder (gdbarch, &sparc32_linux_sigframe);
@@ -238,10 +442,6 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
      prologue analysis.  */
   tdep->plt_entry_size = 12;
 
-  /* GNU/Linux doesn't support the 128-bit `long double' from the psABI.  */
-  set_gdbarch_long_double_bit (gdbarch, 64);
-  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
-
   /* Enable TLS support.  */
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
@@ -250,14 +450,24 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->step_trap = sparc32_linux_step_trap;
 
   /* Hook in the DWARF CFI frame unwinder.  */
-  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
-}
+  dwarf2_append_unwinders (gdbarch);
+
+  set_gdbarch_write_pc (gdbarch, sparc_linux_write_pc);
 
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-extern void _initialize_sparc_linux_tdep (void);
+  /* Functions for 'catch syscall'.  */
+  set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_SPARC32);
+  set_gdbarch_get_syscall_number (gdbarch,
+                                  sparc32_linux_get_syscall_number);
+
+  set_gdbarch_gdb_signal_from_target (gdbarch,
+                                     sparc32_linux_gdb_signal_from_target);
+  set_gdbarch_gdb_signal_to_target (gdbarch,
+                                   sparc32_linux_gdb_signal_to_target);
+}
 
+void _initialize_sparc_linux_tdep ();
 void
-_initialize_sparc_linux_tdep (void)
+_initialize_sparc_linux_tdep ()
 {
   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_LINUX,
                          sparc32_linux_init_abi);
This page took 0.027857 seconds and 4 git commands to generate.