- 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.
This commit is contained in:
christos 2006-12-02 00:46:06 +00:00
parent 437f8cc149
commit 3254d721de

View File

@ -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,