target kvm support for amd64

This commit is contained in:
fvdl 2007-05-15 15:40:49 +00:00
parent c58471c2ca
commit cdfcd42972
3 changed files with 188 additions and 1 deletions

View File

@ -28,6 +28,9 @@
#include "amd64-tdep.h"
#include "amd64-nat.h"
#include <machine/frame.h>
#include <machine/pcb.h>
/* Mapping between the general-purpose registers in NetBSD/amd64
`struct reg' format and GDB's register cache layout for
NetBSD/i386.
@ -58,6 +61,68 @@ static int amd64nbsd32_r_reg_offset[] =
};
static int
amd64nbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
{
struct switchframe sf;
int regnum;
/* The following is true for NetBSD/amd64:
The pcb contains the stack pointer at the point of the context
switch in cpu_switch(). At that point we have a stack frame as
described by `struct switchframe', which for NetBSD/amd64 has the
following layout:
interrupt level
%r15
%r14
%r13
%r12
%rbp
%rbx
return address
Together with %rsp in the pcb, this accounts for all callee-saved
registers specified by the psABI. From this information we
reconstruct the register state as it would look when we just
returned from cpu_switch().
For kernel core dumps the pcb is saved by savectx(). In that case
the stack frame only contains the return address, and there is no way
to recover the other registers. */
/* The stack pointer shouldn't be zero. */
if (pcb->pcb_rsp == 0)
return 0;
/* Read the stack frame, and check its validity. */
read_memory (pcb->pcb_rsp, (gdb_byte *) &sf, sizeof sf);
if (sf.sf_rbp == pcb->pcb_rbp)
{
/* Yes, we have a frame that matches cpu_switch(). */
pcb->pcb_rsp += sizeof (struct switchframe);
regcache_raw_supply (regcache, 12, &sf.sf_r12);
regcache_raw_supply (regcache, 13, &sf.sf_r13);
regcache_raw_supply (regcache, 14, &sf.sf_r14);
regcache_raw_supply (regcache, 15, &sf.sf_r15);
regcache_raw_supply (regcache, AMD64_RBX_REGNUM, &sf.sf_rbx);
regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &sf.sf_rip);
}
else
{
/* No, the pcb must have been last updated by savectx(). */
pcb->pcb_rsp += 8;
regcache_raw_supply (regcache, AMD64_RIP_REGNUM, &sf);
}
regcache_raw_supply (regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp);
regcache_raw_supply (regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp);
regcache_raw_supply (regcache, AMD64_FS_REGNUM, &pcb->pcb_fs);
regcache_raw_supply (regcache, AMD64_GS_REGNUM, &pcb->pcb_gs);
return 1;
}
/* Provide a prototype to silence -Wmissing-prototypes. */
void _initialize_amd64nbsd_nat (void);
@ -74,4 +139,8 @@ _initialize_amd64nbsd_nat (void)
t = amd64bsd_target ();
t->to_pid_to_exec_file = nbsd_pid_to_exec_file;
add_target (t);
/* Support debugging kernel virtual memory images. */
bsd_kvm_add_target (amd64nbsd_supply_pcb);
}

View File

@ -31,6 +31,8 @@
#include "amd64-tdep.h"
#include "nbsd-tdep.h"
#include "solib-svr4.h"
#include "trad-frame.h"
#include "frame-unwind.h"
/* Support for signal handlers. */
@ -98,6 +100,119 @@ int amd64nbsd_r_reg_offset[] =
15 * 8 /* %gs */
};
/* Kernel debuging support */
#define amd64nbsd_tf_reg_offset amd64nbsd_r_reg_offset
static struct trad_frame_cache *
amd64nbsd_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, 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 (amd64nbsd_tf_reg_offset); i++)
if (amd64nbsd_tf_reg_offset[i] != -1)
trad_frame_set_reg_addr (cache, i, addr + amd64nbsd_tf_reg_offset[i]);
/* Read %cs from trap frame. */
addr += amd64nbsd_tf_reg_offset[AMD64_CS_REGNUM];
cs = read_memory_unsigned_integer (addr, 8);
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 + 16, func));
}
return cache;
}
static void
amd64nbsd_trapframe_this_id (struct frame_info *next_frame,
void **this_cache, struct frame_id *this_id)
{
struct trad_frame_cache *cache =
amd64nbsd_trapframe_cache (next_frame, this_cache);
trad_frame_get_id (cache, this_id);
}
static void
amd64nbsd_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 =
amd64nbsd_trapframe_cache (next_frame, this_cache);
trad_frame_get_register (cache, next_frame, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static int
amd64nbsd_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, AMD64_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, "alltraps") == 0)
|| (strcmp (name, "calltrap") == 0)
|| (strncmp (name, "Xtrap", 5) == 0)
|| (strcmp (name, "osyscall1") == 0)
|| (strcmp (name, "Xsyscall") == 0)
|| (strncmp (name, "Xintr", 5) == 0)
|| (strncmp (name, "Xresume", 7) == 0)
|| (strncmp (name, "Xstray", 6) == 0)
|| (strncmp (name, "Xrecurse", 8) == 0)
|| (strncmp (name, "Xsoft", 5) == 0)
|| (strcmp (name, "Xdoreti", 5) == 0)));
}
static const struct frame_unwind amd64nbsd_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,
amd64nbsd_trapframe_this_id,
amd64nbsd_trapframe_prev_register,
NULL,
amd64nbsd_trapframe_sniffer
};
static void
amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@ -121,6 +236,9 @@ amd64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* NetBSD 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, &amd64nbsd_trapframe_unwind);
}

View File

@ -1,3 +1,3 @@
# Host: NetBSD/amd64
NATDEPFILES= fork-child.o inf-ptrace.o \
amd64-nat.o amd64bsd-nat.o nbsd-nat.o amd64nbsd-nat.o
amd64-nat.o amd64bsd-nat.o nbsd-nat.o amd64nbsd-nat.o bsd-kvm.o