]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/sparcobsd-tdep.c
Update Copyright year range in all files maintained by GDB.
[thirdparty/binutils-gdb.git] / gdb / sparcobsd-tdep.c
index 66d15ec503b74a164039b65bd77081e641428299..10f91fe3688112962ddab5b7762217020d92a62a 100644 (file)
@@ -1,12 +1,12 @@
 /* Target-dependent code for OpenBSD/sparc.
 
-   Copyright 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004-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,
    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., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "floatformat.h"
 #include "frame.h"
 #include "frame-unwind.h"
+#include "gdbcore.h"
 #include "osabi.h"
-#include "solib-svr4.h"
+#include "regcache.h"
 #include "symtab.h"
 #include "trad-frame.h"
 
 #include "gdb_assert.h"
 
+#include "obsd-tdep.h"
 #include "sparc-tdep.h"
+#include "solib-svr4.h"
+#include "bsd-uthread.h"
 
 /* Signal trampolines.  */
 
    detecting it won't work.
 
    The signal trampoline will be mapped at an address that is page
-   aligned.  We recognize the signal trampoline by the looking for the
+   aligned.  We recognize the signal trampoline by looking for the
    sigreturn system call.  */
 
 static const int sparc32obsd_page_size = 4096;
 
 static int
-sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, const char *name)
 {
   CORE_ADDR start_pc = (pc & ~(sparc32obsd_page_size - 1));
   unsigned long insn;
@@ -67,7 +69,8 @@ sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
 }
 
 static struct sparc_frame_cache *
-sparc32obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
+sparc32obsd_sigtramp_frame_cache (struct frame_info *this_frame,
+                                 void **this_cache)
 {
   struct sparc_frame_cache *cache;
   CORE_ADDR addr;
@@ -75,70 +78,158 @@ sparc32obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
   if (*this_cache)
     return *this_cache;
 
-  cache = sparc_frame_cache (next_frame, this_cache);
+  cache = sparc_frame_cache (this_frame, this_cache);
   gdb_assert (cache == *this_cache);
 
   /* If we couldn't find the frame's function, we're probably dealing
      with an on-stack signal trampoline.  */
   if (cache->pc == 0)
     {
-      cache->pc = frame_pc_unwind (next_frame);
+      cache->pc = get_frame_pc (this_frame);
       cache->pc &= ~(sparc32obsd_page_size - 1);
 
       /* Since we couldn't find the frame's function, the cache was
          initialized under the assumption that we're frameless.  */
-      cache->frameless_p = 0;
-      addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
+      sparc_record_save_insn (cache);
+      addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
       cache->base = addr;
     }
 
-  cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (next_frame);
+  cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (this_frame);
 
   return cache;
 }
 
 static void
-sparc32obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
-                          struct frame_id *this_id)
+sparc32obsd_sigtramp_frame_this_id (struct frame_info *this_frame,
+                                   void **this_cache,
+                                   struct frame_id *this_id)
 {
   struct sparc_frame_cache *cache =
-    sparc32obsd_frame_cache (next_frame, this_cache);
+    sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
 
   (*this_id) = frame_id_build (cache->base, cache->pc);
 }
 
-static void
-sparc32obsd_frame_prev_register (struct frame_info *next_frame,
-                                void **this_cache,
-                                int regnum, int *optimizedp,
-                                enum lval_type *lvalp, CORE_ADDR *addrp,
-                                int *realnump, gdb_byte *valuep)
+static struct value *
+sparc32obsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
+                                         void **this_cache, int regnum)
 {
   struct sparc_frame_cache *cache =
-    sparc32obsd_frame_cache (next_frame, this_cache);
+    sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
 
-  trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
-                               optimizedp, lvalp, addrp, realnump, valuep);
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
 }
 
-static const struct frame_unwind sparc32obsd_frame_unwind =
+static int
+sparc32obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
+                                   struct frame_info *this_frame,
+                                   void **this_cache)
+{
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (sparc32obsd_pc_in_sigtramp (pc, name))
+    return 1;
+
+  return 0;
+}
+static const struct frame_unwind sparc32obsd_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
-  sparc32obsd_frame_this_id,
-  sparc32obsd_frame_prev_register
+  default_frame_unwind_stop_reason,
+  sparc32obsd_sigtramp_frame_this_id,
+  sparc32obsd_sigtramp_frame_prev_register,
+  NULL,
+  sparc32obsd_sigtramp_frame_sniffer
 };
 
-static const struct frame_unwind *
-sparc32obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
+\f
+
+/* Offset wthin the thread structure where we can find %fp and %i7.  */
+#define SPARC32OBSD_UTHREAD_FP_OFFSET  128
+#define SPARC32OBSD_UTHREAD_PC_OFFSET  132
+
+static void
+sparc32obsd_supply_uthread (struct regcache *regcache,
+                           int regnum, CORE_ADDR addr)
 {
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
-  char *name;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR fp, fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
+  gdb_byte buf[4];
 
-  find_pc_partial_function (pc, &name, NULL, NULL);
-  if (sparc32obsd_pc_in_sigtramp (pc, name))
-    return &sparc32obsd_frame_unwind;
+  gdb_assert (regnum >= -1);
+
+  fp = read_memory_unsigned_integer (fp_addr, 4, byte_order);
+  if (regnum == SPARC_SP_REGNUM || regnum == -1)
+    {
+      store_unsigned_integer (buf, 4, byte_order, fp);
+      regcache_raw_supply (regcache, SPARC_SP_REGNUM, buf);
+
+      if (regnum == SPARC_SP_REGNUM)
+       return;
+    }
 
-  return NULL;
+  if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM
+      || regnum == -1)
+    {
+      CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
+
+      i7 = read_memory_unsigned_integer (i7_addr, 4, byte_order);
+      if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+       {
+         store_unsigned_integer (buf, 4, byte_order, i7 + 8);
+         regcache_raw_supply (regcache, SPARC32_PC_REGNUM, buf);
+       }
+      if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
+       {
+         store_unsigned_integer (buf, 4, byte_order, i7 + 12);
+         regcache_raw_supply (regcache, SPARC32_NPC_REGNUM, buf);
+       }
+
+      if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
+       return;
+    }
+
+  sparc_supply_rwindow (regcache, fp, regnum);
+}
+
+static void
+sparc32obsd_collect_uthread(const struct regcache *regcache,
+                           int regnum, CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR sp;
+  gdb_byte buf[4];
+
+  gdb_assert (regnum >= -1);
+
+  if (regnum == SPARC_SP_REGNUM || regnum == -1)
+    {
+      CORE_ADDR fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
+
+      regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
+      write_memory (fp_addr,buf, 4);
+    }
+
+  if (regnum == SPARC32_PC_REGNUM || regnum == -1)
+    {
+      CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
+
+      regcache_raw_collect (regcache, SPARC32_PC_REGNUM, buf);
+      i7 = extract_unsigned_integer (buf, 4, byte_order) - 8;
+      write_memory_unsigned_integer (i7_addr, 4, byte_order, i7);
+
+      if (regnum == SPARC32_PC_REGNUM)
+       return;
+    }
+
+  regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
+  sp = extract_unsigned_integer (buf, 4, byte_order);
+  sparc_collect_rwindow (regcache, sp, regnum);
 }
 \f
 
@@ -150,7 +241,13 @@ sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* OpenBSD/sparc is very similar to NetBSD/sparc ELF.  */
   sparc32nbsd_elf_init_abi (info, gdbarch);
 
-  frame_unwind_append_sniffer (gdbarch, sparc32obsd_sigtramp_frame_sniffer);
+  set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
+
+  frame_unwind_append_unwinder (gdbarch, &sparc32obsd_sigtramp_frame_unwind);
+
+  /* OpenBSD provides a user-level threads implementation.  */
+  bsd_uthread_set_supply_uthread (gdbarch, sparc32obsd_supply_uthread);
+  bsd_uthread_set_collect_uthread (gdbarch, sparc32obsd_collect_uthread);
 }
 
 \f