changelog: update changelog
[platform/upstream/binutils.git] / gdb / i386nbsd-tdep.c
index 737e273..e0719f4 100644 (file)
@@ -1,14 +1,12 @@
 /* Target-dependent code for NetBSD/i386.
 
-   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
-   2003, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1988-2014 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,
@@ -17,9 +15,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 "arch-utils.h"
@@ -29,9 +25,8 @@
 #include "regset.h"
 #include "osabi.h"
 #include "symtab.h"
-
-#include "gdb_assert.h"
-#include "gdb_string.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
 
 #include "i386-tdep.h"
 #include "i387-tdep.h"
@@ -59,164 +54,216 @@ static int i386nbsd_r_reg_offset[] =
   15 * 4                       /* %gs */
 };
 
-static void
-i386nbsd_aout_supply_regset (const struct regset *regset,
-                            struct regcache *regcache, int regnum,
-                            const void *regs, size_t len)
+/* From <machine/signal.h>.  */
+int i386nbsd_sc_reg_offset[] =
 {
-  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+  10 * 4,                      /* %eax */
+  9 * 4,                       /* %ecx */
+  8 * 4,                       /* %edx */
+  7 * 4,                       /* %ebx */
+  14 * 4,                      /* %esp */
+  6 * 4,                       /* %ebp */
+  5 * 4,                       /* %esi */
+  4 * 4,                       /* %edi */
+  11 * 4,                      /* %eip */
+  13 * 4,                      /* %eflags */
+  12 * 4,                      /* %cs */
+  15 * 4,                      /* %ss */
+  3 * 4,                       /* %ds */
+  2 * 4,                       /* %es */
+  1 * 4,                       /* %fs */
+  0 * 4                                /* %gs */
+};
 
-  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
+/* From <machine/mcontext.h>.  */
+int i386nbsd_mc_reg_offset[] =
+{
+  11 * 4,                      /* %eax */
+  10 * 4,                      /* %ecx */
+  9 * 4,                       /* %edx */
+  8 * 4,                       /* %ebx */
+  7 * 4,                       /* %esp */
+  6 * 4,                       /* %ebp */
+  5 * 4,                       /* %esi */
+  4 * 4,                       /* %edi */
+  14 * 4,                      /* %eip */
+  16 * 4,                      /* %eflags */
+  15 * 4,                      /* %cs */
+  18 * 4,                      /* %ss */
+  3 * 4,                       /* %ds */
+  2 * 4,                       /* %es */
+  1 * 4,                       /* %fs */
+  0 * 4                                /* %gs */
+};
 
-  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
-  i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
-}
+static void i386nbsd_sigtramp_cache_init (const struct tramp_frame *,
+                                         struct frame_info *,
+                                         struct trad_frame_cache *,
+                                         CORE_ADDR);
 
-static const struct regset *
-i386nbsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
-                                       const char *sect_name,
-                                       size_t sect_size)
+static const struct tramp_frame i386nbsd_sigtramp_sc16 =
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  SIGTRAMP_FRAME,
+  1,
+  {
+    { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x10, -1 },
+                       /* leal  0x10(%esp), %eax */
+    { 0x50, -1 },      /* pushl %eax */
+    { 0x50, -1 },      /* pushl %eax */
+    { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x127, %eax           # __sigreturn14 */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x1, %eax             # exit */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  i386nbsd_sigtramp_cache_init
+};
 
-  /* NetBSD a.out core dumps don't use seperate register sets for the
-     general-purpose and floating-point registers.  */
+static const struct tramp_frame i386nbsd_sigtramp_sc2 =
+{
+  SIGTRAMP_FRAME,
+  1,
+  {
+    { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x0c, -1 },
+                       /* leal  0x0c(%esp), %eax */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x127, %eax           # __sigreturn14 */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x1, %eax */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  i386nbsd_sigtramp_cache_init
+};
 
-  if (strcmp (sect_name, ".reg") == 0
-      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
-    {
-      if (tdep->gregset == NULL)
-        tdep->gregset =
-         regset_alloc (gdbarch, i386nbsd_aout_supply_regset, NULL);
-      return tdep->gregset;
-    }
+static const struct tramp_frame i386nbsd_sigtramp_si2 =
+{
+  SIGTRAMP_FRAME,
+  1,
+  {
+    { 0x8b, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x08, -1 },
+                       /* movl  8(%esp),%eax */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* movl  $0x134, %eax            # setcontext */
+    { 0xcd, -1 }, { 0x80, -1 },
+                       /* int   $0x80 */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* movl  $0x1, %eax */
+    { 0xcd, -1 }, { 0x80, -1 },
+                       /* int   $0x80 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  i386nbsd_sigtramp_cache_init
+};
 
-  return NULL;
-}
+static const struct tramp_frame i386nbsd_sigtramp_si31 =
+{
+  SIGTRAMP_FRAME,
+  1,
+  {
+    { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 },
+        { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* leal  0x8c(%esp), %eax */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* movl  $0x134, %eax            # setcontext */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x1, %eax */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  i386nbsd_sigtramp_cache_init
+};
 
-/* Under NetBSD/i386, signal handler invocations can be identified by the
-   designated code sequence that is used to return from a signal handler.
-   In particular, the return address of a signal handler points to the
-   following code sequence:
-
-       leal    0x10(%esp), %eax
-       pushl   %eax
-       pushl   %eax
-       movl    $0x127, %eax            # __sigreturn14
-       int     $0x80
-
-   Each instruction has a unique encoding, so we simply attempt to match
-   the instruction the PC is pointing to with any of the above instructions.
-   If there is a hit, we know the offset to the start of the designated
-   sequence and can then check whether we really are executing in the
-   signal trampoline.  If not, -1 is returned, otherwise the offset from the
-   start of the return sequence is returned.  */
-#define RETCODE_INSN1          0x8d
-#define RETCODE_INSN2          0x50
-#define RETCODE_INSN3          0x50
-#define RETCODE_INSN4          0xb8
-#define RETCODE_INSN5          0xcd
-
-#define RETCODE_INSN2_OFF      4
-#define RETCODE_INSN3_OFF      5
-#define RETCODE_INSN4_OFF      6
-#define RETCODE_INSN5_OFF      11
-
-static const unsigned char sigtramp_retcode[] =
+static const struct tramp_frame i386nbsd_sigtramp_si4 =
 {
-  RETCODE_INSN1, 0x44, 0x24, 0x10,
-  RETCODE_INSN2,
-  RETCODE_INSN3,
-  RETCODE_INSN4, 0x27, 0x01, 0x00, 0x00,
-  RETCODE_INSN5, 0x80,
+  SIGTRAMP_FRAME,
+  1,
+  {
+    { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 },
+        { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* leal  0x8c(%esp), %eax */
+    { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+                       /* movl  %eax, 0x4(%esp) */
+    { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 },
+                       /* movl  $0x134, %eax            # setcontext */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { 0xc7, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 },
+        { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 },
+                       /* movl   $0xffffffff,0x4(%esp) */
+    { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 },
+                       /* movl  $0x1, %eax */
+    { 0xcd, -1 }, { 0x80, -1},
+                       /* int   $0x80 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  i386nbsd_sigtramp_cache_init
 };
 
-static LONGEST
-i386nbsd_sigtramp_offset (struct frame_info *next_frame)
+static void
+i386nbsd_sigtramp_cache_init (const struct tramp_frame *self,
+                             struct frame_info *this_frame,
+                             struct trad_frame_cache *this_cache,
+                             CORE_ADDR func)
 {
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
-  unsigned char ret[sizeof(sigtramp_retcode)], insn;
-  LONGEST off;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+  CORE_ADDR base;
+  int *reg_offset;
+  int num_regs;
   int i;
 
-  if (!safe_frame_unwind_memory (next_frame, pc, &insn, 1))
-    return -1;
-
-  switch (insn)
+  if (self == &i386nbsd_sigtramp_sc16 || self == &i386nbsd_sigtramp_sc2)
     {
-    case RETCODE_INSN1:
-      off = 0;
-      break;
-
-    case RETCODE_INSN2:
-      /* INSN2 and INSN3 are the same.  Read at the location of PC+1
-        to determine if we're actually looking at INSN2 or INSN3.  */
-      if (!safe_frame_unwind_memory (next_frame, pc + 1, &insn, 1))
-       return -1;
-
-      if (insn == RETCODE_INSN3)
-       off = RETCODE_INSN2_OFF;
-      else
-       off = RETCODE_INSN3_OFF;
-      break;
-
-    case RETCODE_INSN4:
-      off = RETCODE_INSN4_OFF;
-      break;
-
-    case RETCODE_INSN5:
-      off = RETCODE_INSN5_OFF;
-      break;
-
-    default:
-      return -1;
-    }
-
-  pc -= off;
+      reg_offset = i386nbsd_sc_reg_offset;
+      num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
 
-  if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret)))
-    return -1;
-
-  if (memcmp (ret, sigtramp_retcode, sizeof (ret)) == 0)
-    return off;
-
-  return -1;
-}
+      /* Read in the sigcontext address.  */
+      base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
+    }
+  else
+    {
+      reg_offset = i386nbsd_mc_reg_offset;
+      num_regs = ARRAY_SIZE (i386nbsd_mc_reg_offset);
 
-/* Return whether the frame preceding NEXT_FRAME corresponds to a
-   NetBSD sigtramp routine.  */
+      /* Read in the ucontext address.  */
+      base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
+      /* offsetof(ucontext_t, uc_mcontext) == 36 */
+      base += 36;
+    }
 
-static int
-i386nbsd_sigtramp_p (struct frame_info *next_frame)
-{
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
-  char *name;
+  for (i = 0; i < num_regs; i++)
+    if (reg_offset[i] != -1)
+      trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]);
 
-  find_pc_partial_function (pc, &name, NULL, NULL);
-  return (nbsd_pc_in_sigtramp (pc, name)
-         || i386nbsd_sigtramp_offset (next_frame) >= 0);
+  /* Construct the frame ID using the function start.  */
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
 }
-
-/* From <machine/signal.h>.  */
-int i386nbsd_sc_reg_offset[] =
-{
-  10 * 4,                      /* %eax */
-  9 * 4,                       /* %ecx */
-  8 * 4,                       /* %edx */
-  7 * 4,                       /* %ebx */
-  14 * 4,                      /* %esp */
-  6 * 4,                       /* %ebp */
-  5 * 4,                       /* %esi */
-  4 * 4,                       /* %edi */
-  11 * 4,                      /* %eip */
-  13 * 4,                      /* %eflags */
-  12 * 4,                      /* %cs */
-  15 * 4,                      /* %ss */
-  3 * 4,                       /* %ds */
-  2 * 4,                       /* %es */
-  1 * 4,                       /* %fs */
-  0 * 4                                /* %gs */
-};
+\f
 
 static void 
 i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -231,30 +278,22 @@ i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset);
   tdep->sizeof_gregset = 16 * 4;
 
-  /* NetBSD has different signal trampoline conventions.  */
-  tdep->sigtramp_start = 0;
-  tdep->sigtramp_end = 0;
-  tdep->sigtramp_p = i386nbsd_sigtramp_p;
-
   /* NetBSD uses -freg-struct-return by default.  */
   tdep->struct_return = reg_struct_return;
 
-  /* NetBSD has a `struct sigcontext' that's different from the
-     original 4.3 BSD.  */
-  tdep->sc_reg_offset = i386nbsd_sc_reg_offset;
-  tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
-}
-
-/* NetBSD a.out.  */
-
-static void
-i386nbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
-{
-  i386nbsd_init_abi (info, gdbarch);
-
-  /* NetBSD a.out has a single register set.  */
-  set_gdbarch_regset_from_core_section
-    (gdbarch, i386nbsd_aout_regset_from_core_section);
+  /* NetBSD uses tramp_frame sniffers for signal trampolines.  */
+  tdep->sigcontext_addr= 0;
+  tdep->sigtramp_start = 0;
+  tdep->sigtramp_end = 0;
+  tdep->sigtramp_p = 0;
+  tdep->sc_reg_offset = 0;
+  tdep->sc_num_regs = 0;
+
+  tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc16);
+  tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc2);
+  tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si2);
+  tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si31);
+  tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si4);
 }
 
 /* NetBSD ELF.  */
@@ -278,11 +317,12 @@ i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->struct_return = pcc_struct_return;
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_i386nbsd_tdep;
+
 void
 _initialize_i386nbsd_tdep (void)
 {
-  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_AOUT,
-                         i386nbsdaout_init_abi);
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD_ELF,
                          i386nbsdelf_init_abi);
 }