aboutsummaryrefslogtreecommitdiff
path: root/gdb/amd64-fbsd-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/amd64-fbsd-nat.c')
-rw-r--r--gdb/amd64-fbsd-nat.c260
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. */