* gdb.ada/taft_type/pck.ads, gdb.ada/taft_type/pck.adb,
[deliverable/binutils-gdb.git] / gdb / i386obsd-tdep.c
index f2b25efeb2dfa440d04223b706ae17917fe0d0bd..4bde914a5fb70c1116c0637b0d395c4659f62092 100644 (file)
@@ -1,14 +1,13 @@
 /* Target-dependent code for OpenBSD/i386.
 
-   Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
-   2003, 2004, 2005
-   Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, 2003,
+   2004, 2005, 2006, 2007, 2008 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 "arch-utils.h"
 #include "frame.h"
+#include "frame-unwind.h"
 #include "gdbcore.h"
 #include "regcache.h"
 #include "regset.h"
@@ -31,6 +29,7 @@
 #include "objfiles.h"
 #include "osabi.h"
 #include "target.h"
+#include "trad-frame.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -265,7 +264,6 @@ i386obsd_supply_uthread (struct regcache *regcache,
          regcache_raw_supply (regcache, i, buf);
        }
     }
-
 }
 
 static void
@@ -313,6 +311,134 @@ i386obsd_collect_uthread (const struct regcache *regcache,
        }
     }
 }
+\f
+/* Kernel debugging support.  */
+
+/* From <machine/frame.h>.  Note that %esp and %ess are only saved in
+   a trap frame when entering the kernel from user space.  */
+static int i386obsd_tf_reg_offset[] =
+{
+  10 * 4,                      /* %eax */
+  9 * 4,                       /* %ecx */
+  8 * 4,                       /* %edx */
+  7 * 4,                       /* %ebx */
+  -1,                          /* %esp */
+  6 * 4,                       /* %ebp */
+  5 * 4,                       /* %esi */
+  4 * 4,                       /* %edi */
+  13 * 4,                      /* %eip */
+  15 * 4,                      /* %eflags */
+  14 * 4,                      /* %cs */
+  -1,                          /* %ss */
+  3 * 4,                       /* %ds */
+  2 * 4,                       /* %es */
+  0 * 4,                       /* %fs */
+  1 * 4                                /* %gs */
+};
+
+static struct trad_frame_cache *
+i386obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
+{
+  struct trad_frame_cache *cache;
+  CORE_ADDR func, sp, addr;
+  ULONGEST cs;
+  char *name;
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = trad_frame_cache_zalloc (next_frame);
+  *this_cache = cache;
+
+  /* NORMAL_FRAME matches the type in i386obsd_trapframe_unwind, but
+     SIGTRAMP_FRAME might be more appropriate.  */
+  func = frame_func_unwind (next_frame, NORMAL_FRAME);
+  sp = frame_unwind_register_unsigned (next_frame, I386_ESP_REGNUM);
+
+  find_pc_partial_function (func, &name, NULL, NULL);
+  if (name && strncmp (name, "Xintr", 5) == 0)
+    addr = sp + 8;             /* It's an interrupt frame.  */
+  else
+    addr = sp;
+
+  for (i = 0; i < ARRAY_SIZE (i386obsd_tf_reg_offset); i++)
+    if (i386obsd_tf_reg_offset[i] != -1)
+      trad_frame_set_reg_addr (cache, i, addr + i386obsd_tf_reg_offset[i]);
+
+  /* Read %cs from trap frame.  */
+  addr += i386obsd_tf_reg_offset[I386_CS_REGNUM];
+  cs = read_memory_unsigned_integer (addr, 4); 
+  if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
+    {
+      /* Trap from user space; terminate backtrace.  */
+      trad_frame_set_id (cache, null_frame_id);
+    }
+  else
+    {
+      /* Construct the frame ID using the function start.  */
+      trad_frame_set_id (cache, frame_id_build (sp + 8, func));
+    }
+
+  return cache;
+}
+
+static void
+i386obsd_trapframe_this_id (struct frame_info *next_frame,
+                           void **this_cache, struct frame_id *this_id)
+{
+  struct trad_frame_cache *cache =
+    i386obsd_trapframe_cache (next_frame, this_cache);
+  
+  trad_frame_get_id (cache, this_id);
+}
+
+static void
+i386obsd_trapframe_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)
+{
+  struct trad_frame_cache *cache =
+    i386obsd_trapframe_cache (next_frame, this_cache);
+
+  trad_frame_get_register (cache, next_frame, regnum,
+                          optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static int
+i386obsd_trapframe_sniffer (const struct frame_unwind *self,
+                           struct frame_info *next_frame,
+                           void **this_prologue_cache)
+{
+  ULONGEST cs;
+  char *name;
+
+  /* Check Current Privilege Level and bail out if we're not executing
+     in kernel space.  */
+  cs = frame_unwind_register_unsigned (next_frame, I386_CS_REGNUM);
+  if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
+    return 0;
+
+  find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
+  return (name && (strcmp (name, "calltrap") == 0
+                  || strcmp (name, "syscall1") == 0
+                  || strncmp (name, "Xintr", 5) == 0
+                  || strncmp (name, "Xsoft", 5) == 0));
+}
+
+static const struct frame_unwind i386obsd_trapframe_unwind = {
+  /* FIXME: kettenis/20051219: This really is more like an interrupt
+     frame, but SIGTRAMP_FRAME would print <signal handler called>,
+     which really is not what we want here.  */
+  NORMAL_FRAME,
+  i386obsd_trapframe_this_id,
+  i386obsd_trapframe_prev_register,
+  NULL,
+  i386obsd_trapframe_sniffer
+};
+\f
 
 static void 
 i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -343,6 +469,9 @@ i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* OpenBSD provides a user-level threads implementation.  */
   bsd_uthread_set_supply_uthread (gdbarch, i386obsd_supply_uthread);
   bsd_uthread_set_collect_uthread (gdbarch, i386obsd_collect_uthread);
+
+  /* Unwind kernel trap frames correctly.  */
+  frame_unwind_prepend_unwinder (gdbarch, &i386obsd_trapframe_unwind);
 }
 
 /* OpenBSD a.out.  */
This page took 0.026789 seconds and 4 git commands to generate.