diff options
Diffstat (limited to 'gdb/amd64-fbsd-nat.c')
-rw-r--r-- | gdb/amd64-fbsd-nat.c | 260 |
1 files changed, 203 insertions, 57 deletions
diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c index f9bd45d..98a1af0 100644 --- a/gdb/amd64-fbsd-nat.c +++ b/gdb/amd64-fbsd-nat.c @@ -31,17 +31,19 @@ #include "fbsd-nat.h" #include "amd64-tdep.h" +#include "amd64-fbsd-tdep.h" #include "amd64-nat.h" -#include "amd64-bsd-nat.h" #include "x86-nat.h" #include "gdbsupport/x86-xstate.h" - +#include "x86-bsd-nat.h" class amd64_fbsd_nat_target final - : public amd64_bsd_nat_target<fbsd_nat_target> + : public x86bsd_nat_target<fbsd_nat_target> { public: - /* Add some extra features to the common *BSD/amd64 target. */ + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; + const struct target_desc *read_description () override; #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) @@ -51,61 +53,208 @@ public: static amd64_fbsd_nat_target the_amd64_fbsd_nat_target; -/* Offset in `struct reg' where MEMBER is stored. */ -#define REG_OFFSET(member) offsetof (struct reg, member) +#ifdef PT_GETXSTATE_INFO +static size_t xsave_len; +#endif + +/* This is a layout of the amd64 'struct reg' but with i386 + registers. */ -/* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in - `struct reg' location where the GDB register REGNUM is stored. - Unsupported registers are marked with `-1'. */ -static int amd64fbsd64_r_reg_offset[] = +static const struct regcache_map_entry amd64_fbsd32_gregmap[] = { - REG_OFFSET (r_rax), - REG_OFFSET (r_rbx), - REG_OFFSET (r_rcx), - REG_OFFSET (r_rdx), - REG_OFFSET (r_rsi), - REG_OFFSET (r_rdi), - REG_OFFSET (r_rbp), - REG_OFFSET (r_rsp), - REG_OFFSET (r_r8), - REG_OFFSET (r_r9), - REG_OFFSET (r_r10), - REG_OFFSET (r_r11), - REG_OFFSET (r_r12), - REG_OFFSET (r_r13), - REG_OFFSET (r_r14), - REG_OFFSET (r_r15), - REG_OFFSET (r_rip), - REG_OFFSET (r_rflags), - REG_OFFSET (r_cs), - REG_OFFSET (r_ss), - -1, - -1, - -1, - -1 + { 8, REGCACHE_MAP_SKIP, 8 }, + { 1, I386_EDI_REGNUM, 8 }, + { 1, I386_ESI_REGNUM, 8 }, + { 1, I386_EBP_REGNUM, 8 }, + { 1, I386_EBX_REGNUM, 8 }, + { 1, I386_EDX_REGNUM, 8 }, + { 1, I386_ECX_REGNUM, 8 }, + { 1, I386_EAX_REGNUM, 8 }, + { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */ + { 1, I386_FS_REGNUM, 2 }, + { 1, I386_GS_REGNUM, 2 }, + { 1, REGCACHE_MAP_SKIP, 4 }, /* err */ + { 1, I386_ES_REGNUM, 2 }, + { 1, I386_DS_REGNUM, 2 }, + { 1, I386_EIP_REGNUM, 8 }, + { 1, I386_CS_REGNUM, 8 }, + { 1, I386_EFLAGS_REGNUM, 8 }, + { 1, I386_ESP_REGNUM, 0 }, + { 1, I386_SS_REGNUM, 8 }, + { 0 } }; - -/* Mapping between the general-purpose registers in FreeBSD/amd64 - `struct reg' format and GDB's register cache layout for - FreeBSD/i386. +static const struct regset amd64_fbsd32_gregset = +{ + amd64_fbsd32_gregmap, regcache_supply_regset, regcache_collect_regset +}; - Note that most FreeBSD/amd64 registers are 64-bit, while the - FreeBSD/i386 registers are all 32-bit, but since we're - little-endian we get away with that. */ +/* Return the regset to use for 'struct reg' for the GDBARCH. */ -/* From <machine/reg.h>. */ -static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] = +static const struct regset * +find_gregset (struct gdbarch *gdbarch) { - 14 * 8, 13 * 8, /* %eax, %ecx */ - 12 * 8, 11 * 8, /* %edx, %ebx */ - 20 * 8, 10 * 8, /* %esp, %ebp */ - 9 * 8, 8 * 8, /* %esi, %edi */ - 17 * 8, 19 * 8, /* %eip, %eflags */ - 18 * 8, 21 * 8, /* %cs, %ss */ - -1, -1, -1, -1 /* %ds, %es, %fs, %gs */ -}; - + if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) + return &amd64_fbsd32_gregset; + else + return &amd64_fbsd_gregset; +} + +/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this + for all registers. */ + +void +amd64_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = regcache->arch (); +#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) + const i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); +#endif + pid_t pid = get_ptrace_pid (regcache->ptid ()); + const struct regset *gregset = find_gregset (gdbarch); + + if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, gregset)) + { + if (regnum != -1) + return; + } + +#ifdef PT_GETFSBASE + if (regnum == -1 || regnum == tdep->fsbase_regnum) + { + register_t base; + + if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't get segment register fs_base")); + + regcache->raw_supply (tdep->fsbase_regnum, &base); + if (regnum != -1) + return; + } +#endif +#ifdef PT_GETGSBASE + if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) + { + register_t base; + + if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't get segment register gs_base")); + + regcache->raw_supply (tdep->fsbase_regnum + 1, &base); + if (regnum != -1) + return; + } +#endif + + /* There is no amd64_fxsave_supplies or amd64_xsave_supplies. + Instead, the earlier register sets return early if the request + was for a specific register that was already satisified to avoid + fetching the FPU/XSAVE state unnecessarily. */ + +#ifdef PT_GETXSTATE_INFO + if (xsave_len != 0) + { + void *xstateregs = alloca (xsave_len); + + if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) + perror_with_name (_("Couldn't get extended state status")); + + amd64_supply_xsave (regcache, regnum, xstateregs); + return; + } +#endif + + struct fpreg fpregs; + + if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) + perror_with_name (_("Couldn't get floating point status")); + + amd64_supply_fxsave (regcache, regnum, &fpregs); +} + +/* Store register REGNUM back into the inferior. If REGNUM is -1, do + this for all registers. */ + +void +amd64_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = regcache->arch (); +#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) + const i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); +#endif + pid_t pid = get_ptrace_pid (regcache->ptid ()); + const struct regset *gregset = find_gregset (gdbarch); + + if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS, + gregset)) + { + if (regnum != -1) + return; + } + +#ifdef PT_SETFSBASE + if (regnum == -1 || regnum == tdep->fsbase_regnum) + { + register_t base; + + /* Clear the full base value to support 32-bit targets. */ + base = 0; + regcache->raw_collect (tdep->fsbase_regnum, &base); + + if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't write segment register fs_base")); + if (regnum != -1) + return; + } +#endif +#ifdef PT_SETGSBASE + if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) + { + register_t base; + + /* Clear the full base value to support 32-bit targets. */ + base = 0; + regcache->raw_collect (tdep->fsbase_regnum + 1, &base); + + if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) + perror_with_name (_("Couldn't write segment register gs_base")); + if (regnum != -1) + return; + } +#endif + + /* There is no amd64_fxsave_supplies or amd64_xsave_supplies. + Instead, the earlier register sets return early if the request + was for a specific register that was already satisified to avoid + fetching the FPU/XSAVE state unnecessarily. */ + +#ifdef PT_GETXSTATE_INFO + if (xsave_len != 0) + { + void *xstateregs = alloca (xsave_len); + + if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) + perror_with_name (_("Couldn't get extended state status")); + + amd64_collect_xsave (regcache, regnum, xstateregs, 0); + + if (ptrace (PT_SETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, + xsave_len) == -1) + perror_with_name (_("Couldn't write extended state status")); + return; + } +#endif + + struct fpreg fpregs; + + if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) + perror_with_name (_("Couldn't get floating point status")); + + amd64_collect_fxsave (regcache, regnum, &fpregs); + + if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) + perror_with_name (_("Couldn't write floating point status")); +} /* Support for debugging kernel virtual memory images. */ @@ -179,13 +328,13 @@ amd64_fbsd_nat_target::read_description () if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (), (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0) { - x86bsd_xsave_len = info.xsave_len; + xsave_len = info.xsave_len; xcr0 = info.xsave_mask; } xsave_probed = 1; } - if (x86bsd_xsave_len != 0) + if (xsave_len != 0) { if (is64) return amd64_target_description (xcr0, true); @@ -213,9 +362,6 @@ void _initialize_amd64fbsd_nat (); void _initialize_amd64fbsd_nat () { - amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset; - amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset; - add_inf_child_target (&the_amd64_fbsd_nat_target); /* Support debugging kernel virtual memory images. */ |