*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / i386obsd-tdep.c
index 8cfaa2444070c76bfc7ff5b9dda0450c697fe2e2..4c9b88d6152b1247db9849ff92a712871930089e 100644 (file)
@@ -1,5 +1,7 @@
 /* Target-dependent code for OpenBSD/i386.
-   Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003
+
+   Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
+   2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "defs.h"
 #include "arch-utils.h"
+#include "frame.h"
 #include "gdbcore.h"
 #include "regcache.h"
+#include "regset.h"
+#include "symtab.h"
+#include "objfiles.h"
 #include "osabi.h"
+#include "target.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
 
 #include "i386-tdep.h"
 #include "i387-tdep.h"
+#include "solib-svr4.h"
 
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-void _initialize_i386obsd_tdep (void);
+/* Support for signal handlers.  */
 
-#define SIZEOF_STRUCT_REG      (16 * 4)
+/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
+   in virtual memory.  The randomness makes it somewhat tricky to
+   detect it, but fortunately we can rely on the fact that the start
+   of the sigtramp routine is page-aligned.  By the way, the mapping
+   is read-only, so you cannot place a breakpoint in the signal
+   trampoline.  */
 
-static void
-i386obsd_supply_reg (char *regs, int regno)
-{
-  int i;
+/* Default page size.  */
+static const int i386obsd_page_size = 4096;
 
-  for (i = 0; i <= 15; i++)
-    if (regno == i || regno == -1)
-      supply_register (i, regs + i * 4);
-}
+/* Return whether the frame preceding NEXT_FRAME corresponds to an
+   OpenBSD sigtramp routine.  */
 
-static void
-fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
-                      CORE_ADDR ignore)
+static int
+i386obsd_sigtramp_p (struct frame_info *next_frame)
 {
-  char *regs, *fsave;
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
+  const char sigreturn[] =
+  {
+    0xb8,
+    0x67, 0x00, 0x00, 0x00,    /* movl $SYS_sigreturn, %eax */
+    0xcd, 0x80                 /* int $0x80 */
+  };
+  size_t buflen = sizeof sigreturn;
+  char *name, *buf;
 
-  /* We get everything from one section.  */
-  if (which != 0)
-    return;
+  /* If the function has a valid symbol name, it isn't a
+     trampoline.  */
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (name != NULL)
+    return 0;
 
-  if (core_reg_size < (SIZEOF_STRUCT_REG + 108))
-    {
-      warning ("Wrong size register set in core file.");
-      return;
-    }
+  /* If the function lives in a valid section (even without a starting
+     point) it isn't a trampoline.  */
+  if (find_pc_section (pc) != NULL)
+    return 0;
+
+  /* Allocate buffer.  */
+  buf = alloca (buflen);
+
+  /* If we can't read the instructions at START_PC, return zero.  */
+  if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen))
+    return 0;
+
+  /* Check for sigreturn(2).  */
+  if (memcmp (buf, sigreturn, buflen) == 0)
+    return 1;
 
-  regs = core_reg_sect;
-  fsave = core_reg_sect + SIZEOF_STRUCT_REG;
+  /* If we can't read the instructions at START_PC, return zero.  */
+  if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen))
+    return 0;
 
-  /* Integer registers.  */
-  i386obsd_supply_reg (regs, -1);
+  /* Check for sigreturn(2) (again).  */
+  if (memcmp (buf, sigreturn, buflen) == 0)
+    return 1;
 
-  /* Floating point registers.  */
-  i387_supply_fsave (fsave, -1);
+  return 0;
 }
+\f
+/* Mapping between the general-purpose registers in `struct reg'
+   format and GDB's register cache layout.  */
 
-static struct core_fns i386obsd_core_fns =
+/* From <machine/reg.h>.  */
+static int i386obsd_r_reg_offset[] =
 {
-  bfd_target_unknown_flavour,          /* core_flavour */
-  default_check_format,                        /* check_format */
-  default_core_sniffer,                        /* core_sniffer */
-  fetch_core_registers,                        /* core_read_registers */
-  NULL                                 /* next */
+  0 * 4,                       /* %eax */
+  1 * 4,                       /* %ecx */
+  2 * 4,                       /* %edx */
+  3 * 4,                       /* %ebx */
+  4 * 4,                       /* %esp */
+  5 * 4,                       /* %ebp */
+  6 * 4,                       /* %esi */
+  7 * 4,                       /* %edi */
+  8 * 4,                       /* %eip */
+  9 * 4,                       /* %eflags */
+  10 * 4,                      /* %cs */
+  11 * 4,                      /* %ss */
+  12 * 4,                      /* %ds */
+  13 * 4,                      /* %es */
+  14 * 4,                      /* %fs */
+  15 * 4                       /* %gs */
 };
+
+static void
+i386obsd_aout_supply_regset (const struct regset *regset,
+                            struct regcache *regcache, int regnum,
+                            const void *regs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+
+  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
+
+  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
+  i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
+}
+
+static const struct regset *
+i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
+                                       const char *sect_name,
+                                       size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* OpenBSD a.out core dumps don't use seperate register sets for the
+     general-purpose and floating-point registers.  */
+
+  if (strcmp (sect_name, ".reg") == 0
+      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
+    {
+      if (tdep->gregset == NULL)
+        tdep->gregset =
+         regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
+      return tdep->gregset;
+    }
+
+  return NULL;
+}
 \f
 
-CORE_ADDR i386obsd_sigtramp_start = 0xbfbfdf20;
-CORE_ADDR i386obsd_sigtramp_end = 0xbfbfdff0;
+/* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
+CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
+CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
 
 /* From <machine/signal.h>.  */
 int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
@@ -111,24 +194,62 @@ i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* Obviously OpenBSD is BSD-based.  */
   i386bsd_init_abi (info, gdbarch);
 
+  /* OpenBSD has a different `struct reg'.  */
+  tdep->gregset_reg_offset = i386obsd_r_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
+  tdep->sizeof_gregset = 16 * 4;
+
   /* OpenBSD uses -freg-struct-return by default.  */
   tdep->struct_return = reg_struct_return;
 
   /* OpenBSD uses a different memory layout.  */
-  tdep->sigtramp_start = i386obsd_sigtramp_start;
-  tdep->sigtramp_end = i386obsd_sigtramp_end;
+  tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
+  tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
+  tdep->sigtramp_p = i386obsd_sigtramp_p;
 
   /* OpenBSD has a `struct sigcontext' that's different from the
-     origional 4.3 BSD.  */
+     original 4.3 BSD.  */
   tdep->sc_reg_offset = i386obsd_sc_reg_offset;
-  tdep->sc_num_regs = I386_NUM_GREGS;
+  tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
 }
 
+/* OpenBSD a.out.  */
+
+static void
+i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  i386obsd_init_abi (info, gdbarch);
+
+  /* OpenBSD a.out has a single register set.  */
+  set_gdbarch_regset_from_core_section
+    (gdbarch, i386obsd_aout_regset_from_core_section);
+}
+
+/* OpenBSD ELF.  */
+
+static void
+i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* It's still OpenBSD.  */
+  i386obsd_init_abi (info, gdbarch);
+
+  /* But ELF-based.  */
+  i386_elf_init_abi (info, gdbarch);
+
+  /* OpenBSD ELF uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_i386obsd_tdep (void);
+
 void
 _initialize_i386obsd_tdep (void)
 {
-  add_core_fns (&i386obsd_core_fns);
-
   /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
      indistingushable from NetBSD/i386 a.out binaries, building a GDB
      that should support both these targets will probably not work as
@@ -136,5 +257,7 @@ _initialize_i386obsd_tdep (void)
 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
 
   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
-                         i386obsd_init_abi);
+                         i386obsd_aout_init_abi);
+  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
+                         i386obsd_elf_init_abi);
 }
This page took 0.02596 seconds and 4 git commands to generate.