X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Famd64obsd-tdep.c;h=ed57cb8c4758b34153f6266535cdeba534454ec5;hb=4ee62156d969867d3d3ffedf656a74643f77279e;hp=34a48ca8eaa03fc793f2ebba34831b92964201a7;hpb=197e01b6dcd118b70ed3621b62b2ff3fa929d50f;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/amd64obsd-tdep.c b/gdb/amd64obsd-tdep.c
index 34a48ca8ea..ed57cb8c47 100644
--- a/gdb/amd64obsd-tdep.c
+++ b/gdb/amd64obsd-tdep.c
@@ -1,12 +1,13 @@
/* Target-dependent code for OpenBSD/amd64.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
+ 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,
@@ -15,12 +16,11 @@
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 . */
#include "defs.h"
#include "frame.h"
+#include "frame-unwind.h"
#include "gdbcore.h"
#include "symtab.h"
#include "objfiles.h"
@@ -28,6 +28,7 @@
#include "regcache.h"
#include "regset.h"
#include "target.h"
+#include "trad-frame.h"
#include "gdb_assert.h"
#include "gdb_string.h"
@@ -79,13 +80,13 @@ amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
/* Default page size. */
static const int amd64obsd_page_size = 4096;
-/* Return whether the frame preceding NEXT_FRAME corresponds to an
- OpenBSD sigtramp routine. */
+/* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp
+ routine. */
static int
-amd64obsd_sigtramp_p (struct frame_info *next_frame)
+amd64obsd_sigtramp_p (struct frame_info *this_frame)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
const gdb_byte sigreturn[] =
{
@@ -110,7 +111,7 @@ amd64obsd_sigtramp_p (struct frame_info *next_frame)
/* If we can't read the instructions at START_PC, return zero. */
buf = alloca ((sizeof sigreturn) + 1);
- if (!safe_frame_unwind_memory (next_frame, start_pc + 6, buf, buflen))
+ if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen))
return 0;
/* Check for sigreturn(2). Depending on how the assembler encoded
@@ -123,13 +124,13 @@ amd64obsd_sigtramp_p (struct frame_info *next_frame)
return 1;
}
-/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
- routine, return the address of the associated sigcontext structure. */
+/* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
+ address of the associated sigcontext structure. */
static CORE_ADDR
-amd64obsd_sigcontext_addr (struct frame_info *next_frame)
+amd64obsd_sigcontext_addr (struct frame_info *this_frame)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
ULONGEST offset = (pc & (amd64obsd_page_size - 1));
/* The %rsp register points at `struct sigcontext' upon entry of a
@@ -145,9 +146,9 @@ amd64obsd_sigcontext_addr (struct frame_info *next_frame)
instruction clobbers %rsp, but its value is saved in `%rdi'. */
if (offset > 5)
- return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM);
+ return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
else
- return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
+ return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
}
/* OpenBSD 3.5 or later. */
@@ -250,6 +251,8 @@ static void
amd64obsd_supply_uthread (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_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
CORE_ADDR sp = 0;
gdb_byte buf[8];
@@ -262,12 +265,12 @@ amd64obsd_supply_uthread (struct regcache *regcache,
int offset;
/* Fetch stack pointer from thread structure. */
- sp = read_memory_unsigned_integer (sp_addr, 8);
+ sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
/* Adjust the stack pointer such that it looks as if we just
returned from _thread_machdep_switch. */
offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
- store_unsigned_integer (buf, 8, sp + offset);
+ store_unsigned_integer (buf, 8, byte_order, sp + offset);
regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
}
@@ -279,7 +282,7 @@ amd64obsd_supply_uthread (struct regcache *regcache,
/* Fetch stack pointer from thread structure (if we didn't
do so already). */
if (sp == 0)
- sp = read_memory_unsigned_integer (sp_addr, 8);
+ sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
/* Read the saved register from the stack frame. */
read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
@@ -292,6 +295,8 @@ static void
amd64obsd_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_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
CORE_ADDR sp = 0;
gdb_byte buf[8];
@@ -307,10 +312,10 @@ amd64obsd_collect_uthread (const struct regcache *regcache,
stored into the thread structure. */
offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
- sp = extract_unsigned_integer (buf, 8) - offset;
+ sp = extract_unsigned_integer (buf, 8, byte_order) - offset;
/* Store the stack pointer. */
- write_memory_unsigned_integer (sp_addr, 8, sp);
+ write_memory_unsigned_integer (sp_addr, 8, byte_order, sp);
/* The stack pointer was (potentially) modified. Make sure we
build a proper stack frame. */
@@ -325,7 +330,7 @@ amd64obsd_collect_uthread (const struct regcache *regcache,
/* Fetch stack pointer from thread structure (if we didn't
calculate it already). */
if (sp == 0)
- sp = read_memory_unsigned_integer (sp_addr, 8);
+ sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
/* Write the register into the stack frame. */
regcache_raw_collect (regcache, i, buf);
@@ -333,6 +338,111 @@ amd64obsd_collect_uthread (const struct regcache *regcache,
}
}
}
+/* Kernel debugging support. */
+
+/* From . Easy since `struct trapframe' matches
+ `struct sigcontext'. */
+#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
+
+static struct trad_frame_cache *
+amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ 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 (this_frame);
+ *this_cache = cache;
+
+ func = get_frame_func (this_frame);
+ sp = get_frame_register_unsigned (this_frame, AMD64_RSP_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 (amd64obsd_tf_reg_offset); i++)
+ if (amd64obsd_tf_reg_offset[i] != -1)
+ trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
+
+ /* Read %cs from trap frame. */
+ addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
+ cs = read_memory_unsigned_integer (addr, 8, byte_order);
+ if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
+ {
+ /* Trap from user space; terminate backtrace. */
+ trad_frame_set_id (cache, outer_frame_id);
+ }
+ else
+ {
+ /* Construct the frame ID using the function start. */
+ trad_frame_set_id (cache, frame_id_build (sp + 16, func));
+ }
+
+ return cache;
+}
+
+static void
+amd64obsd_trapframe_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ amd64obsd_trapframe_cache (this_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ struct trad_frame_cache *cache =
+ amd64obsd_trapframe_cache (this_frame, this_cache);
+
+ return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static int
+amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_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 = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
+ if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
+ return 0;
+
+ find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
+ return (name && ((strcmp (name, "calltrap") == 0)
+ || (strcmp (name, "osyscall1") == 0)
+ || (strcmp (name, "Xsyscall") == 0)
+ || (strncmp (name, "Xintr", 5) == 0)));
+}
+
+static const struct frame_unwind amd64obsd_trapframe_unwind = {
+ /* FIXME: kettenis/20051219: This really is more like an interrupt
+ frame, but SIGTRAMP_FRAME would print ,
+ which really is not what we want here. */
+ NORMAL_FRAME,
+ amd64obsd_trapframe_this_id,
+ amd64obsd_trapframe_prev_register,
+ NULL,
+ amd64obsd_trapframe_sniffer
+};
+
static void
amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -363,6 +473,9 @@ amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* OpenBSD uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
+
+ /* Unwind kernel trap frames correctly. */
+ frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
}