summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2006-12-02 00:46:06 +0000
committerchristos <christos@NetBSD.org>2006-12-02 00:46:06 +0000
commit3254d721de3962280dfc08f106956165fdb7e02f (patch)
treeb0eaef747622d7f56bbe4e4aecd68e1eaeebb78d /gnu
parent437f8cc1490a91a08bb84a9ae158952e3b80f2c6 (diff)
- add kernel frame unwinding support (copied from i386obsd-tdep.c)
- add a nasty hack to recognize elf kernels which do not have a PT_NOTE as NetBSD binaries.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/dist/gdb6/gdb/i386nbsd-tdep.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/gnu/dist/gdb6/gdb/i386nbsd-tdep.c b/gnu/dist/gdb6/gdb/i386nbsd-tdep.c
index 737e27382b6..d2ca71136f1 100644
--- a/gnu/dist/gdb6/gdb/i386nbsd-tdep.c
+++ b/gnu/dist/gdb6/gdb/i386nbsd-tdep.c
@@ -37,6 +37,9 @@
#include "i387-tdep.h"
#include "nbsd-tdep.h"
#include "solib-svr4.h"
+#include "elf-bfd.h" /* for header hack */
+#include "trad-frame.h" /* kernel frame support */
+#include "frame-unwind.h" /* kernel frame support */
/* From <machine/reg.h>. */
static int i386nbsd_r_reg_offset[] =
@@ -218,6 +221,132 @@ int i386nbsd_sc_reg_offset[] =
0 * 4 /* %gs */
};
+/* 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 i386nbsd_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 */
+ 1 * 4, /* %fs */
+ 0 * 4 /* %gs */
+};
+
+static struct trad_frame_cache *
+i386nbsd_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;
+
+ func = frame_func_unwind (next_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 + 4;
+
+ for (i = 0; i < ARRAY_SIZE (i386nbsd_tf_reg_offset); i++)
+ if (i386nbsd_tf_reg_offset[i] != -1)
+ trad_frame_set_reg_addr (cache, i, addr + i386nbsd_tf_reg_offset[i]);
+
+ /* Read %cs from trap frame. */
+ addr += i386nbsd_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
+i386nbsd_trapframe_this_id (struct frame_info *next_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ struct trad_frame_cache *cache =
+ i386nbsd_trapframe_cache (next_frame, this_cache);
+
+ trad_frame_get_id (cache, this_id);
+}
+
+static void
+i386nbsd_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 =
+ i386nbsd_trapframe_cache (next_frame, this_cache);
+
+ trad_frame_get_register (cache, next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static int
+i386nbsd_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));
+}
+
+const struct frame_unwind i386nbsd_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,
+ i386nbsd_trapframe_this_id,
+ i386nbsd_trapframe_prev_register,
+ NULL,
+ i386nbsd_trapframe_sniffer
+};
+
static void
i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -243,6 +372,9 @@ i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
original 4.3 BSD. */
tdep->sc_reg_offset = i386nbsd_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
+
+ /* Unwind kernel trap frames correctly. */
+ frame_unwind_prepend_unwinder (gdbarch, &i386nbsd_trapframe_unwind);
}
/* NetBSD a.out. */
@@ -278,9 +410,24 @@ i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->struct_return = pcc_struct_return;
}
+static enum gdb_osabi
+i386nbsd_elf_osabi_sniffer (bfd *abfd)
+{
+ if (strcmp (bfd_get_target (abfd), "elf32-i386") != 0)
+ return GDB_OSABI_UNKNOWN;
+ /* disgusting hack since kernels don't have a PT_NOTE section */
+ if ((unsigned long)elf_elfheader (abfd)->e_entry != (unsigned long)0xc0100000)
+ return GDB_OSABI_UNKNOWN;
+
+ return GDB_OSABI_NETBSD_ELF;
+}
+
+
void
_initialize_i386nbsd_tdep (void)
{
+ gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
+ i386nbsd_elf_osabi_sniffer);
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,