Split type_unit_group
[deliverable/binutils-gdb.git] / gdb / alpha-linux-tdep.c
index 4a52fe358c572c0b2d44348da9a34c9c3bb28052..589b89567053a47b49214f8adc9944fb67965f99 100644 (file)
@@ -1,5 +1,5 @@
 /* Target-dependent code for GNU/Linux on Alpha.
-   Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2002-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include "defs.h"
 #include "frame.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
 #include "osabi.h"
 #include "solib-svr4.h"
 #include "symtab.h"
 #include "regset.h"
 #include "regcache.h"
-
+#include "linux-tdep.h"
 #include "alpha-tdep.h"
+#include "gdbarch.h"
+
+/* This enum represents the signals' numbers on the Alpha
+   architecture.  It just contains the signal definitions which are
+   different from the generic implementation.
+
+   It is derived from the file <arch/alpha/include/uapi/asm/signal.h>,
+   from the Linux kernel tree.  */
+
+enum
+  {
+    /* SIGABRT is the same as in the generic implementation, but is
+       defined here because SIGIOT depends on it.  */
+    ALPHA_LINUX_SIGABRT = 6,
+    ALPHA_LINUX_SIGEMT = 7,
+    ALPHA_LINUX_SIGBUS = 10,
+    ALPHA_LINUX_SIGSYS = 12,
+    ALPHA_LINUX_SIGURG = 16,
+    ALPHA_LINUX_SIGSTOP = 17,
+    ALPHA_LINUX_SIGTSTP = 18,
+    ALPHA_LINUX_SIGCONT = 19,
+    ALPHA_LINUX_SIGCHLD = 20,
+    ALPHA_LINUX_SIGIO = 23,
+    ALPHA_LINUX_SIGINFO = 29,
+    ALPHA_LINUX_SIGUSR1 = 30,
+    ALPHA_LINUX_SIGUSR2 = 31,
+    ALPHA_LINUX_SIGPOLL = ALPHA_LINUX_SIGIO,
+    ALPHA_LINUX_SIGPWR = ALPHA_LINUX_SIGINFO,
+    ALPHA_LINUX_SIGIOT = ALPHA_LINUX_SIGABRT,
+  };
 
 /* Under GNU/Linux, signal handler invocations can be identified by
    the designated code sequence that is used to return from a signal
      (2) the kernel has changed from using "addq" to "lda" to load the
          syscall number,
      (3) there is a "normal" sigreturn and an "rt" sigreturn which
-         has a different stack layout.
-*/
+         has a different stack layout.  */
 
 static long
-alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
+alpha_linux_sigtramp_offset_1 (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
-  switch (alpha_read_insn (pc))
+  switch (alpha_read_insn (gdbarch, pc))
     {
     case 0x47de0410:           /* bis $30,$30,$16 */
     case 0x47fe0410:           /* bis $31,$30,$16 */
@@ -66,7 +93,7 @@ alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
 }
 
 static LONGEST
-alpha_linux_sigtramp_offset (CORE_ADDR pc)
+alpha_linux_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   long i, off;
 
@@ -74,7 +101,7 @@ alpha_linux_sigtramp_offset (CORE_ADDR pc)
     return -1;
 
   /* Guess where we might be in the sequence.  */
-  off = alpha_linux_sigtramp_offset_1 (pc);
+  off = alpha_linux_sigtramp_offset_1 (gdbarch, pc);
   if (off < 0)
     return -1;
 
@@ -84,7 +111,7 @@ alpha_linux_sigtramp_offset (CORE_ADDR pc)
     {
       if (i == off)
        continue;
-      if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
+      if (alpha_linux_sigtramp_offset_1 (gdbarch, pc + i) != i)
        return -1;
     }
 
@@ -92,22 +119,24 @@ alpha_linux_sigtramp_offset (CORE_ADDR pc)
 }
 
 static int
-alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+alpha_linux_pc_in_sigtramp (struct gdbarch *gdbarch,
+                           CORE_ADDR pc, const char *func_name)
 {
-  return alpha_linux_sigtramp_offset (pc) >= 0;
+  return alpha_linux_sigtramp_offset (gdbarch, pc) >= 0;
 }
 
 static CORE_ADDR
-alpha_linux_sigcontext_addr (struct frame_info *next_frame)
+alpha_linux_sigcontext_addr (struct frame_info *this_frame)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   CORE_ADDR pc;
   ULONGEST sp;
   long off;
 
-  pc = frame_pc_unwind (next_frame);
-  sp = frame_unwind_register_unsigned (next_frame, ALPHA_SP_REGNUM);
+  pc = get_frame_pc (this_frame);
+  sp = get_frame_register_unsigned (this_frame, ALPHA_SP_REGNUM);
 
-  off = alpha_linux_sigtramp_offset (pc);
+  off = alpha_linux_sigtramp_offset (gdbarch, pc);
   gdb_assert (off >= 0);
 
   /* __NR_rt_sigreturn has a couple of structures on the stack.  This is:
@@ -117,9 +146,9 @@ alpha_linux_sigcontext_addr (struct frame_info *next_frame)
          struct ucontext uc;
         };
 
-       offsetof (struct rt_sigframe, uc.uc_mcontext);
-  */
-  if (alpha_read_insn (pc - off + 4) == 0x201f015f)
+       offsetof (struct rt_sigframe, uc.uc_mcontext);  */
+
+  if (alpha_read_insn (gdbarch, pc - off + 4) == 0x201f015f)
     return sp + 176;
 
   /* __NR_sigreturn has the sigcontext structure at the top of the stack.  */
@@ -135,22 +164,28 @@ alpha_linux_supply_gregset (const struct regset *regset,
                            struct regcache *regcache,
                            int regnum, const void *gregs, size_t len)
 {
-  const gdb_byte *regs = gregs;
-  int i;
+  const gdb_byte *regs = (const gdb_byte *) gregs;
+
   gdb_assert (len >= 32 * 8);
+  alpha_supply_int_regs (regcache, regnum, regs, regs + 31 * 8,
+                        len >= 33 * 8 ? regs + 32 * 8 : NULL);
+}
 
-  for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
-    {
-      if (regnum == i || regnum == -1)
-       regcache_raw_supply (regcache, i, regs + i * 8);
-    }
+/* Collect register REGNUM from the register cache REGCACHE and store
+   it in the buffer specified by GREGS and LEN as described by the
+   general-purpose register set REGSET.  If REGNUM is -1, do this for
+   all registers in REGSET.  */
 
-  if (regnum == ALPHA_PC_REGNUM || regnum == -1)
-    regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
+static void
+alpha_linux_collect_gregset (const struct regset *regset,
+                            const struct regcache *regcache,
+                            int regnum, void *gregs, size_t len)
+{
+  gdb_byte *regs = (gdb_byte *) gregs;
 
-  if (regnum == ALPHA_UNIQUE_REGNUM || regnum == -1)
-    regcache_raw_supply (regcache, ALPHA_UNIQUE_REGNUM,
-                        len >= 33 * 8 ? regs + 32 * 8 : NULL);
+  gdb_assert (len >= 32 * 8);
+  alpha_fill_int_regs (regcache, regnum, regs, regs + 31 * 8,
+                      len >= 33 * 8 ? regs + 32 * 8 : NULL);
 }
 
 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
@@ -162,46 +197,158 @@ alpha_linux_supply_fpregset (const struct regset *regset,
                             struct regcache *regcache,
                             int regnum, const void *fpregs, size_t len)
 {
-  const gdb_byte *regs = fpregs;
-  int i;
+  const gdb_byte *regs = (const gdb_byte *) fpregs;
+
   gdb_assert (len >= 32 * 8);
+  alpha_supply_fp_regs (regcache, regnum, regs, regs + 31 * 8);
+}
 
-  for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
-    {
-      if (regnum == i || regnum == -1)
-       regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
-    }
+/* Collect register REGNUM from the register cache REGCACHE and store
+   it in the buffer specified by FPREGS and LEN as described by the
+   general-purpose register set REGSET.  If REGNUM is -1, do this for
+   all registers in REGSET.  */
 
-  if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
-    regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 31 * 8);
+static void
+alpha_linux_collect_fpregset (const struct regset *regset,
+                             const struct regcache *regcache,
+                             int regnum, void *fpregs, size_t len)
+{
+  gdb_byte *regs = (gdb_byte *) fpregs;
+
+  gdb_assert (len >= 32 * 8);
+  alpha_fill_fp_regs (regcache, regnum, regs, regs + 31 * 8);
 }
 
-static struct regset alpha_linux_gregset =
+static const struct regset alpha_linux_gregset =
 {
   NULL,
-  alpha_linux_supply_gregset
+  alpha_linux_supply_gregset, alpha_linux_collect_gregset
 };
 
-static struct regset alpha_linux_fpregset =
+static const struct regset alpha_linux_fpregset =
 {
   NULL,
-  alpha_linux_supply_fpregset
+  alpha_linux_supply_fpregset, alpha_linux_collect_fpregset
 };
 
-/* Return the appropriate register set for the core section identified
-   by SECT_NAME and SECT_SIZE.  */
+/* Iterate over core file register note sections.  */
 
-const struct regset *
-alpha_linux_regset_from_core_section (struct gdbarch *gdbarch,
-                                     const char *sect_name, size_t sect_size)
+static void
+alpha_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                         iterate_over_regset_sections_cb *cb,
+                                         void *cb_data,
+                                         const struct regcache *regcache)
 {
-  if (strcmp (sect_name, ".reg") == 0 && sect_size >= 32 * 8)
-    return &alpha_linux_gregset;
+  cb (".reg", 32 * 8, 32 * 8, &alpha_linux_gregset, NULL, cb_data);
+  cb (".reg2", 32 * 8, 32 * 8, &alpha_linux_fpregset, NULL, cb_data);
+}
+
+/* Implementation of `gdbarch_gdb_signal_from_target', as defined in
+   gdbarch.h.  */
+
+static enum gdb_signal
+alpha_linux_gdb_signal_from_target (struct gdbarch *gdbarch,
+                                   int signal)
+{
+  switch (signal)
+    {
+    case ALPHA_LINUX_SIGEMT:
+      return GDB_SIGNAL_EMT;
+
+    case ALPHA_LINUX_SIGBUS:
+      return GDB_SIGNAL_BUS;
+
+    case ALPHA_LINUX_SIGSYS:
+      return GDB_SIGNAL_SYS;
+
+    case ALPHA_LINUX_SIGURG:
+      return GDB_SIGNAL_URG;
+
+    case ALPHA_LINUX_SIGSTOP:
+      return GDB_SIGNAL_STOP;
+
+    case ALPHA_LINUX_SIGTSTP:
+      return GDB_SIGNAL_TSTP;
 
-  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 32 * 8)
-    return &alpha_linux_fpregset;
+    case ALPHA_LINUX_SIGCONT:
+      return GDB_SIGNAL_CONT;
 
-  return NULL;
+    case ALPHA_LINUX_SIGCHLD:
+      return GDB_SIGNAL_CHLD;
+
+    /* No way to differentiate between SIGIO and SIGPOLL.
+       Therefore, we just handle the first one.  */
+    case ALPHA_LINUX_SIGIO:
+      return GDB_SIGNAL_IO;
+
+    /* No way to differentiate between SIGINFO and SIGPWR.
+       Therefore, we just handle the first one.  */
+    case ALPHA_LINUX_SIGINFO:
+      return GDB_SIGNAL_INFO;
+
+    case ALPHA_LINUX_SIGUSR1:
+      return GDB_SIGNAL_USR1;
+
+    case ALPHA_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
+alpha_linux_gdb_signal_to_target (struct gdbarch *gdbarch,
+                                 enum gdb_signal signal)
+{
+  switch (signal)
+    {
+    case GDB_SIGNAL_EMT:
+      return ALPHA_LINUX_SIGEMT;
+
+    case GDB_SIGNAL_BUS:
+      return ALPHA_LINUX_SIGBUS;
+
+    case GDB_SIGNAL_SYS:
+      return ALPHA_LINUX_SIGSYS;
+
+    case GDB_SIGNAL_URG:
+      return ALPHA_LINUX_SIGURG;
+
+    case GDB_SIGNAL_STOP:
+      return ALPHA_LINUX_SIGSTOP;
+
+    case GDB_SIGNAL_TSTP:
+      return ALPHA_LINUX_SIGTSTP;
+
+    case GDB_SIGNAL_CONT:
+      return ALPHA_LINUX_SIGCONT;
+
+    case GDB_SIGNAL_CHLD:
+      return ALPHA_LINUX_SIGCHLD;
+
+    case GDB_SIGNAL_IO:
+      return ALPHA_LINUX_SIGIO;
+
+    case GDB_SIGNAL_INFO:
+      return ALPHA_LINUX_SIGINFO;
+
+    case GDB_SIGNAL_USR1:
+      return ALPHA_LINUX_SIGUSR1;
+
+    case GDB_SIGNAL_USR2:
+      return ALPHA_LINUX_SIGUSR2;
+
+    case GDB_SIGNAL_POLL:
+      return ALPHA_LINUX_SIGPOLL;
+
+    case GDB_SIGNAL_PWR:
+      return ALPHA_LINUX_SIGPWR;
+    }
+
+  return linux_gdb_signal_to_target (gdbarch, signal);
 }
 
 static void
@@ -209,6 +356,8 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep;
 
+  linux_init_abi (info, gdbarch);
+
   /* Hook into the DWARF CFI frame unwinder.  */
   alpha_dwarf2_init_abi (info, gdbarch);
 
@@ -231,12 +380,18 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_fetch_tls_load_module_address (gdbarch,
                                              svr4_fetch_objfile_link_map);
 
-  set_gdbarch_regset_from_core_section
-    (gdbarch, alpha_linux_regset_from_core_section);
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, alpha_linux_iterate_over_regset_sections);
+
+  set_gdbarch_gdb_signal_from_target (gdbarch,
+                                     alpha_linux_gdb_signal_from_target);
+  set_gdbarch_gdb_signal_to_target (gdbarch,
+                                   alpha_linux_gdb_signal_to_target);
 }
 
+void _initialize_alpha_linux_tdep ();
 void
-_initialize_alpha_linux_tdep (void)
+_initialize_alpha_linux_tdep ()
 {
   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
                           alpha_linux_init_abi);
This page took 0.033128 seconds and 4 git commands to generate.