PT_GETXSTATE_INFO and XSTATE core dump sections. - Use kern.proc.sigtramp on i386 to fix unwinding across signal frames. - Change the amd64 FreeBSD ABI to return an i386 target description when debugging a 32-bit process. This allows XSAVE debugging to work for an i386 binary on amd64. - Rework thread patches to pull all threads-related patches out of the main port patches and into a single optional patch. - Adjust the thread patches so that fbsd-threads.c passes register requests for LWPs down to the native target instead of calling ptrace directly. This allows XSAVE to work with threads without any other changes. The x86 nat.c files now pass LWP IDs to ptrace register operations (other platforms already did this). The supply/collect regset stubs are now only needed to support userland threads for libkse. PR: 197501 Approved by: maintainer, bdrewery
606 lines
17 KiB
Text
606 lines
17 KiB
Text
diff --git a/bfd/elf.c b/bfd/elf.c
|
||
index 3f377d1..9481435 100644
|
||
--- bfd/elf.c
|
||
+++ bfd/elf.c
|
||
@@ -8609,6 +8609,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
|
||
if (note->namesz == 6
|
||
&& strcmp (note->namedata, "LINUX") == 0)
|
||
return elfcore_grok_xstatereg (abfd, note);
|
||
+ else if (note->namesz == 8
|
||
+ && strcmp (note->namedata, "FreeBSD") == 0)
|
||
+ return elfcore_grok_xstatereg (abfd, note);
|
||
else
|
||
return TRUE;
|
||
|
||
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
|
||
index f1b039e..7a4c1dc 100644
|
||
--- gdb/amd64-tdep.h
|
||
+++ gdb/amd64-tdep.h
|
||
@@ -84,6 +84,11 @@ enum amd64_regnum
|
||
|
||
#define AMD64_NUM_REGS (AMD64_ZMM31H_REGNUM + 1)
|
||
|
||
+extern struct target_desc *tdesc_amd64;
|
||
+extern struct target_desc *tdesc_amd64_avx;
|
||
+extern struct target_desc *tdesc_amd64_mpx;
|
||
+extern struct target_desc *tdesc_amd64_avx512;
|
||
+
|
||
extern struct displaced_step_closure *amd64_displaced_step_copy_insn
|
||
(struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to,
|
||
struct regcache *regs);
|
||
diff --git a/gdb/amd64bsd-nat.c b/gdb/amd64bsd-nat.c
|
||
index 4b0a231..9e6a0df 100644
|
||
--- gdb/amd64bsd-nat.c
|
||
+++ gdb/amd64bsd-nat.c
|
||
@@ -37,6 +37,10 @@
|
||
#include "inf-ptrace.h"
|
||
|
||
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+size_t x86_xsave_len;
|
||
+#endif
|
||
+
|
||
/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
|
||
for all registers (including the floating-point registers). */
|
||
|
||
@@ -62,6 +66,20 @@ amd64bsd_fetch_inferior_registers (struct target_ops *ops,
|
||
if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
|
||
{
|
||
struct fpreg fpregs;
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ char *xstateregs;
|
||
+
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ xstateregs = alloca(x86_xsave_len);
|
||
+ if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
|
||
+ perror_with_name (_("Couldn't get extended state status"));
|
||
+
|
||
+ amd64_supply_xsave (regcache, -1, xstateregs);
|
||
+ return;
|
||
+ }
|
||
+#endif
|
||
|
||
if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||
@@ -111,6 +129,24 @@ amd64bsd_store_inferior_registers (struct target_ops *ops,
|
||
if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
|
||
{
|
||
struct fpreg fpregs;
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ char *xstateregs;
|
||
+
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ xstateregs = alloca(x86_xsave_len);
|
||
+ if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
|
||
+ (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, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) xstateregs, x86_xsave_len) == -1)
|
||
+ perror_with_name (_("Couldn't write extended state status"));
|
||
+ return;
|
||
+ }
|
||
+#endif
|
||
|
||
if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||
diff --git a/gdb/amd64bsd-nat.h b/gdb/amd64bsd-nat.h
|
||
index 7ff95f3..9d85a1f 100644
|
||
--- gdb/amd64bsd-nat.h
|
||
+++ gdb/amd64bsd-nat.h
|
||
@@ -20,6 +20,9 @@
|
||
#ifndef AMD64BSD_NAT_H
|
||
#define AMD64BSD_NAT_H
|
||
|
||
+/* Low level amd64 XSAVE info. */
|
||
+extern size_t x86_xsave_len;
|
||
+
|
||
/* Low level amd64 debug register functions. */
|
||
|
||
extern void amd64bsd_dr_set_control (unsigned long control);
|
||
diff --git a/gdb/amd64fbsd-nat.c b/gdb/amd64fbsd-nat.c
|
||
index 08de9a1..eea2472 100644
|
||
--- gdb/amd64fbsd-nat.c
|
||
+++ gdb/amd64fbsd-nat.c
|
||
@@ -36,6 +36,7 @@
|
||
#include "amd64-nat.h"
|
||
#include "amd64bsd-nat.h"
|
||
#include "i386-nat.h"
|
||
+#include "i386-xstate.h"
|
||
|
||
|
||
/* Offset in `struct reg' where MEMBER is stored. */
|
||
@@ -153,6 +154,68 @@ amd64fbsd_mourn_inferior (struct target_ops *ops)
|
||
super_mourn_inferior (ops);
|
||
}
|
||
|
||
+static const struct target_desc *
|
||
+amd64fbsd_read_description (struct target_ops *ops)
|
||
+{
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ static int xsave_probed;
|
||
+ static uint64_t xcr0;
|
||
+#endif
|
||
+ struct reg regs;
|
||
+ int is64;
|
||
+
|
||
+ if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||
+ perror_with_name (_("Couldn't get registers"));
|
||
+ is64 = (regs.r_cs == GSEL(GUCODE_SEL, SEL_UPL));
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ if (!xsave_probed)
|
||
+ {
|
||
+ struct ptrace_xstate_info info;
|
||
+
|
||
+ if (ptrace (PT_GETXSTATE_INFO, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) &info, sizeof(info)) == 0)
|
||
+ {
|
||
+ x86_xsave_len = info.xsave_len;
|
||
+ xcr0 = info.xsave_mask;
|
||
+ }
|
||
+ xsave_probed = 1;
|
||
+ }
|
||
+
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ switch (xcr0 & I386_XSTATE_ALL_MASK)
|
||
+ {
|
||
+ case I386_XSTATE_MPX_AVX512_MASK:
|
||
+ case I386_XSTATE_AVX512_MASK:
|
||
+ if (is64)
|
||
+ return tdesc_amd64_avx512;
|
||
+ else
|
||
+ return tdesc_i386_avx512;
|
||
+ case I386_XSTATE_MPX_MASK:
|
||
+ if (is64)
|
||
+ return tdesc_amd64_mpx;
|
||
+ else
|
||
+ return tdesc_i386_mpx;
|
||
+ case I386_XSTATE_AVX_MASK:
|
||
+ if (is64)
|
||
+ return tdesc_amd64_avx;
|
||
+ else
|
||
+ return tdesc_i386_avx;
|
||
+ default:
|
||
+ if (is64)
|
||
+ return tdesc_amd64;
|
||
+ else
|
||
+ return tdesc_i386;
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
+ if (is64)
|
||
+ return tdesc_amd64;
|
||
+ else
|
||
+ return tdesc_i386;
|
||
+}
|
||
+
|
||
/* Provide a prototype to silence -Wmissing-prototypes. */
|
||
void _initialize_amd64fbsd_nat (void);
|
||
|
||
@@ -183,6 +246,7 @@ _initialize_amd64fbsd_nat (void)
|
||
|
||
super_mourn_inferior = t->to_mourn_inferior;
|
||
t->to_mourn_inferior = amd64fbsd_mourn_inferior;
|
||
+ t->to_read_description = amd64fbsd_read_description;
|
||
|
||
t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
|
||
t->to_find_memory_regions = fbsd_find_memory_regions;
|
||
diff --git a/gdb/amd64fbsd-tdep.c b/gdb/amd64fbsd-tdep.c
|
||
index 884fbc4..582ae50 100644
|
||
--- gdb/amd64fbsd-tdep.c
|
||
+++ gdb/amd64fbsd-tdep.c
|
||
@@ -23,6 +23,9 @@
|
||
#include "gdbcore.h"
|
||
#include "regcache.h"
|
||
#include "osabi.h"
|
||
+#include "regset.h"
|
||
+#include "i386fbsd-tdep.h"
|
||
+#include "i386-xstate.h"
|
||
|
||
#include "gdb_assert.h"
|
||
#include <string.h>
|
||
@@ -31,6 +34,15 @@
|
||
#include "bsd-uthread.h"
|
||
#include "solib-svr4.h"
|
||
|
||
+/* Supported register note sections. */
|
||
+static struct core_regset_section amd64fbsd_regset_sections[] =
|
||
+{
|
||
+ { ".reg", 22 * 8, "general-purpose" },
|
||
+ { ".reg2", 512, "floating-point" },
|
||
+ { ".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state" },
|
||
+ { NULL, 0 }
|
||
+};
|
||
+
|
||
/* Support for signal handlers. */
|
||
|
||
/* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
|
||
@@ -144,6 +156,27 @@ static int amd64fbsd_jmp_buf_reg_offset[] =
|
||
0 * 8 /* %rip */
|
||
};
|
||
|
||
+static const struct target_desc *
|
||
+amd64fbsd_core_read_description (struct gdbarch *gdbarch,
|
||
+ struct target_ops *target,
|
||
+ bfd *abfd)
|
||
+{
|
||
+ uint64_t xcr0 = i386fbsd_core_read_xcr0 (abfd);
|
||
+
|
||
+ switch (xcr0 & I386_XSTATE_ALL_MASK)
|
||
+ {
|
||
+ case I386_XSTATE_MPX_AVX512_MASK:
|
||
+ case I386_XSTATE_AVX512_MASK:
|
||
+ return tdesc_amd64_avx512;
|
||
+ case I386_XSTATE_MPX_MASK:
|
||
+ return tdesc_amd64_mpx;
|
||
+ case I386_XSTATE_AVX_MASK:
|
||
+ return tdesc_amd64_avx;
|
||
+ default:
|
||
+ return tdesc_amd64;
|
||
+ }
|
||
+}
|
||
+
|
||
static void
|
||
amd64fbsd_supply_uthread (struct regcache *regcache,
|
||
int regnum, CORE_ADDR addr)
|
||
@@ -204,6 +237,14 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||
tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
|
||
tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
|
||
|
||
+ tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
|
||
+
|
||
+ /* Install supported register note sections. */
|
||
+ set_gdbarch_core_regset_sections (gdbarch, amd64fbsd_regset_sections);
|
||
+
|
||
+ set_gdbarch_core_read_description (gdbarch,
|
||
+ amd64fbsd_core_read_description);
|
||
+
|
||
/* FreeBSD provides a user-level threads implementation. */
|
||
bsd_uthread_set_supply_uthread (gdbarch, amd64fbsd_supply_uthread);
|
||
bsd_uthread_set_collect_uthread (gdbarch, amd64fbsd_collect_uthread);
|
||
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
|
||
index e0950a3..0498445 100644
|
||
--- gdb/i386-tdep.h
|
||
+++ gdb/i386-tdep.h
|
||
@@ -325,6 +325,11 @@ enum record_i386_regnum
|
||
/* Size of the largest register. */
|
||
#define I386_MAX_REGISTER_SIZE 64
|
||
|
||
+extern struct target_desc *tdesc_i386;
|
||
+extern struct target_desc *tdesc_i386_avx;
|
||
+extern struct target_desc *tdesc_i386_mpx;
|
||
+extern struct target_desc *tdesc_i386_avx512;
|
||
+
|
||
/* Types for i386-specific registers. */
|
||
extern struct type *i387_ext_type (struct gdbarch *gdbarch);
|
||
|
||
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
|
||
index acae6cb..c26e830 100644
|
||
--- gdb/i386bsd-nat.c
|
||
+++ gdb/i386bsd-nat.c
|
||
@@ -83,6 +83,10 @@ static int i386bsd_r_reg_offset[] =
|
||
so that we try PT_GETXMMREGS the first time around. */
|
||
static int have_ptrace_xmmregs = -1;
|
||
#endif
|
||
+
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+size_t x86_xsave_len;
|
||
+#endif
|
||
|
||
|
||
/* Supply the general-purpose registers in GREGS, to REGCACHE. */
|
||
@@ -150,7 +154,25 @@ i386bsd_fetch_inferior_registers (struct target_ops *ops,
|
||
struct fpreg fpregs;
|
||
#ifdef HAVE_PT_GETXMMREGS
|
||
char xmmregs[512];
|
||
+#endif
|
||
+
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ char *xstateregs;
|
||
+
|
||
+ xstateregs = alloca(x86_xsave_len);
|
||
+ if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
|
||
+ perror_with_name (_("Couldn't get extended state status"));
|
||
|
||
+ i387_supply_xsave (regcache, -1, xstateregs);
|
||
+ return;
|
||
+ }
|
||
+ else
|
||
+#endif
|
||
+
|
||
+#ifdef HAVE_PT_GETXMMREGS
|
||
if (have_ptrace_xmmregs != 0
|
||
&& ptrace(PT_GETXMMREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
|
||
@@ -160,18 +182,15 @@ i386bsd_fetch_inferior_registers (struct target_ops *ops,
|
||
}
|
||
else
|
||
{
|
||
+ have_ptrace_xmmregs = 0;
|
||
+#endif
|
||
if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||
perror_with_name (_("Couldn't get floating point status"));
|
||
|
||
i387_supply_fsave (regcache, -1, &fpregs);
|
||
+#ifdef HAVE_PT_GETXMMREGS
|
||
}
|
||
-#else
|
||
- if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
|
||
- (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||
- perror_with_name (_("Couldn't get floating point status"));
|
||
-
|
||
- i387_supply_fsave (regcache, -1, &fpregs);
|
||
#endif
|
||
}
|
||
}
|
||
@@ -206,7 +225,27 @@ i386bsd_store_inferior_registers (struct target_ops *ops,
|
||
struct fpreg fpregs;
|
||
#ifdef HAVE_PT_GETXMMREGS
|
||
char xmmregs[512];
|
||
+#endif
|
||
+
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ char *xstateregs;
|
||
|
||
+ xstateregs = alloca(x86_xsave_len);
|
||
+ if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
|
||
+ perror_with_name (_("Couldn't get extended state status"));
|
||
+
|
||
+ i387_collect_xsave (regcache, -1, xstateregs, 0);
|
||
+
|
||
+ if (ptrace (PT_SETXSTATE, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) xstateregs, x86_xsave_len) == -1)
|
||
+ perror_with_name (_("Couldn't write extended state status"));
|
||
+ }
|
||
+#endif
|
||
+
|
||
+#ifdef HAVE_PT_GETXMMREGS
|
||
if (have_ptrace_xmmregs != 0
|
||
&& ptrace(PT_GETXMMREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
|
||
diff --git a/gdb/i386bsd-nat.h b/gdb/i386bsd-nat.h
|
||
index a92fa56..044f530 100644
|
||
--- gdb/i386bsd-nat.h
|
||
+++ gdb/i386bsd-nat.h
|
||
@@ -25,6 +25,9 @@
|
||
|
||
extern struct target_ops *i386bsd_target (void);
|
||
|
||
+/* Low level i386 XSAVE info. */
|
||
+extern size_t x86_xsave_len;
|
||
+
|
||
/* low level i386 debug register functions used in i386fbsd-nat.c. */
|
||
|
||
extern void i386bsd_dr_set_control (unsigned long control);
|
||
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
|
||
index fb80991..b9620e1 100644
|
||
--- gdb/i386fbsd-nat.c
|
||
+++ gdb/i386fbsd-nat.c
|
||
@@ -31,6 +31,7 @@
|
||
#include "i386-tdep.h"
|
||
#include "i386-nat.h"
|
||
#include "i386bsd-nat.h"
|
||
+#include "i386-xstate.h"
|
||
|
||
/* Resume execution of the inferior process. If STEP is nonzero,
|
||
single-step it. If SIGNAL is nonzero, give it that signal. */
|
||
@@ -116,6 +117,46 @@ i386fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
|
||
}
|
||
|
||
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+static const struct target_desc *
|
||
+i386fbsd_read_description (struct target_ops *ops)
|
||
+{
|
||
+ static int xsave_probed;
|
||
+ static uint64_t xcr0;
|
||
+
|
||
+ if (!xsave_probed)
|
||
+ {
|
||
+ struct ptrace_xstate_info info;
|
||
+
|
||
+ if (ptrace (PT_GETXSTATE_INFO, ptid_get_pid (inferior_ptid),
|
||
+ (PTRACE_TYPE_ARG3) &info, sizeof(info)) == 0)
|
||
+ {
|
||
+ x86_xsave_len = info.xsave_len;
|
||
+ xcr0 = info.xsave_mask;
|
||
+ }
|
||
+ xsave_probed = 1;
|
||
+ }
|
||
+
|
||
+ if (x86_xsave_len != 0)
|
||
+ {
|
||
+ switch (xcr0 & I386_XSTATE_ALL_MASK)
|
||
+ {
|
||
+ case I386_XSTATE_MPX_AVX512_MASK:
|
||
+ case I386_XSTATE_AVX512_MASK:
|
||
+ return tdesc_i386_avx512;
|
||
+ case I386_XSTATE_MPX_MASK:
|
||
+ return tdesc_i386_mpx;
|
||
+ case I386_XSTATE_AVX_MASK:
|
||
+ return tdesc_i386_avx;
|
||
+ default:
|
||
+ return tdesc_i386;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ return tdesc_i386;
|
||
+}
|
||
+#endif
|
||
+
|
||
/* Prevent warning from -Wmissing-prototypes. */
|
||
void _initialize_i386fbsd_nat (void);
|
||
|
||
@@ -140,6 +181,9 @@ _initialize_i386fbsd_nat (void)
|
||
|
||
#endif /* HAVE_PT_GETDBREGS */
|
||
|
||
+#ifdef PT_GETXSTATE_INFO
|
||
+ t->to_read_description = i386fbsd_read_description;
|
||
+#endif
|
||
|
||
t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
|
||
t->to_find_memory_regions = fbsd_find_memory_regions;
|
||
diff --git a/gdb/i386fbsd-tdep.c b/gdb/i386fbsd-tdep.c
|
||
index ed6df6b..8f7109f 100644
|
||
--- gdb/i386fbsd-tdep.c
|
||
+++ gdb/i386fbsd-tdep.c
|
||
@@ -22,6 +22,9 @@
|
||
#include "gdbcore.h"
|
||
#include "osabi.h"
|
||
#include "regcache.h"
|
||
+#include "regset.h"
|
||
+#include "i386fbsd-tdep.h"
|
||
+#include "i386-xstate.h"
|
||
|
||
#include "gdb_assert.h"
|
||
|
||
@@ -32,6 +35,15 @@
|
||
|
||
/* FreeBSD 3.0-RELEASE or later. */
|
||
|
||
+/* Supported register note sections. */
|
||
+static struct core_regset_section i386fbsd_regset_sections[] =
|
||
+{
|
||
+ { ".reg", 19 * 4, "general-purpose" },
|
||
+ { ".reg2", 512, "floating-point" },
|
||
+ { ".reg-xstate", I386_XSTATE_MAX_SIZE, "XSAVE extended state" },
|
||
+ { NULL, 0 }
|
||
+};
|
||
+
|
||
/* From <machine/reg.h>. */
|
||
static int i386fbsd_r_reg_offset[] =
|
||
{
|
||
@@ -82,6 +94,64 @@ static int i386fbsd_jmp_buf_reg_offset[] =
|
||
0 * 4 /* %eip */
|
||
};
|
||
|
||
+/* Get XSAVE extended state xcr0 from core dump. */
|
||
+
|
||
+uint64_t
|
||
+i386fbsd_core_read_xcr0 (bfd *abfd)
|
||
+{
|
||
+ asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
|
||
+ uint64_t xcr0;
|
||
+
|
||
+ if (xstate)
|
||
+ {
|
||
+ size_t size = bfd_section_size (abfd, xstate);
|
||
+
|
||
+ /* Check extended state size. */
|
||
+ if (size < I386_XSTATE_AVX_SIZE)
|
||
+ xcr0 = I386_XSTATE_SSE_MASK;
|
||
+ else
|
||
+ {
|
||
+ char contents[8];
|
||
+
|
||
+ if (! bfd_get_section_contents (abfd, xstate, contents,
|
||
+ I386_FBSD_XSAVE_XCR0_OFFSET,
|
||
+ 8))
|
||
+ {
|
||
+ warning (_("Couldn't read `xcr0' bytes from "
|
||
+ "`.reg-xstate' section in core file."));
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ xcr0 = bfd_get_64 (abfd, contents);
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ xcr0 = 0;
|
||
+
|
||
+ return xcr0;
|
||
+}
|
||
+
|
||
+static const struct target_desc *
|
||
+i386fbsd_core_read_description (struct gdbarch *gdbarch,
|
||
+ struct target_ops *target,
|
||
+ bfd *abfd)
|
||
+{
|
||
+ uint64_t xcr0 = i386fbsd_core_read_xcr0 (abfd);
|
||
+
|
||
+ switch (xcr0 & I386_XSTATE_ALL_MASK)
|
||
+ {
|
||
+ case I386_XSTATE_MPX_AVX512_MASK:
|
||
+ case I386_XSTATE_AVX512_MASK:
|
||
+ return tdesc_i386_avx512;
|
||
+ case I386_XSTATE_MPX_MASK:
|
||
+ return tdesc_i386_mpx;
|
||
+ case I386_XSTATE_AVX_MASK:
|
||
+ return tdesc_i386_avx;
|
||
+ default:
|
||
+ return tdesc_i386;
|
||
+ }
|
||
+}
|
||
+
|
||
static void
|
||
i386fbsd_supply_uthread (struct regcache *regcache,
|
||
int regnum, CORE_ADDR addr)
|
||
@@ -218,6 +288,14 @@ i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
||
/* FreeBSD 4.0 introduced a new `struct sigcontext'. */
|
||
tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
|
||
tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
|
||
+
|
||
+ tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
|
||
+
|
||
+ /* Install supported register note sections. */
|
||
+ set_gdbarch_core_regset_sections (gdbarch, i386fbsd_regset_sections);
|
||
+
|
||
+ set_gdbarch_core_read_description (gdbarch,
|
||
+ i386fbsd_core_read_description);
|
||
}
|
||
|
||
|
||
diff --git a/gdb/i386fbsd-tdep.h b/gdb/i386fbsd-tdep.h
|
||
new file mode 100644
|
||
index 0000000..8935255
|
||
--- /dev/null
|
||
+++ gdb/i386fbsd-tdep.h
|
||
@@ -0,0 +1,33 @@
|
||
+/* Target-dependent code for FreeBSD x86.
|
||
+
|
||
+ Copyright (C) 2014 Free Software Foundation, Inc.
|
||
+
|
||
+ This file is part of GDB.
|
||
+
|
||
+ This program is free software; you can redistribute it and/or modify
|
||
+ it under the terms of the GNU General Public License as published by
|
||
+ the Free Software Foundation; either version 3 of the License, or
|
||
+ (at your option) any later version.
|
||
+
|
||
+ This program is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ GNU General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU General Public License
|
||
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#ifndef I386FBSD_TDEP_H
|
||
+#define I386FBSD_TDEP_H
|
||
+
|
||
+/* Get XSAVE extended state xcr0 from core dump. */
|
||
+extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd);
|
||
+
|
||
+/*
|
||
+ * The format of the XSAVE extended area is determined by hardware.
|
||
+ * Cores store the XSAVE extended area in a NT_X86_XSTATE note that
|
||
+ * matches the layout on Linux.
|
||
+ */
|
||
+#define I386_FBSD_XSAVE_XCR0_OFFSET 464
|
||
+
|
||
+#endif /* i386fbsd-tdep.h */
|