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 @@ -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 . */ 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 . */ + +#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 */