From 00d7af046f12f18759b5b2c909d0b4527ac1857e Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 28 Jan 2022 11:14:37 -0800 Subject: [PATCH] FreeBSD x86 nat: Use register maps for GP register sets. Rather than using the x86-specific register offset tables, use register maps to describe the layout of the general purpose registers fetched via PT_GETREGS. The sole user-visible difference is that FreeBSD/amd64 will now report additional segment registers ($ds, $es, $fs, and $gs) for both 32-bit and 64-bit processes. As part of these changes, the FreeBSD x86 native targets no longer use amd64-bsd-nat.c or i386-bsd-nat.c. Remove FreeBSD-specific register handling (for $fs_base, $gs_base, and XSAVE state) from these files. Similarly, remove the global x86bsd_xsave_len from x86-bsd-nat.c. The FreeBSD x86 native targets use a static xsave_len instead. While here, rework the probing of PT_GETXMMREGS on FreeBSD/i386. Probe the ptrace op once in the target read_description method and cache the result for the future similar to the way the status of XSAVE support is probed in the read_description method. In addition, return the proper xcr0 mask (X87-only) for old kernels or systems without either XSAVE or XMM support. --- gdb/amd64-bsd-nat.c | 96 ---------------- gdb/amd64-fbsd-nat.c | 260 +++++++++++++++++++++++++++++++++--------- gdb/amd64-fbsd-tdep.c | 1 + gdb/amd64-fbsd-tdep.h | 27 +++++ gdb/configure.nat | 4 +- gdb/i386-bsd-nat.c | 92 --------------- gdb/i386-fbsd-nat.c | 229 +++++++++++++++++++++++++++++++++++-- gdb/i386-fbsd-tdep.h | 4 + gdb/x86-bsd-nat.c | 4 - gdb/x86-bsd-nat.h | 3 - 10 files changed, 457 insertions(+), 263 deletions(-) create mode 100644 gdb/amd64-fbsd-tdep.h diff --git a/gdb/amd64-bsd-nat.c b/gdb/amd64-bsd-nat.c index 52730ba276e..77dc4c935ca 100644 --- a/gdb/amd64-bsd-nat.c +++ b/gdb/amd64-bsd-nat.c @@ -59,9 +59,6 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = regcache->arch (); ptid_t ptid = regcache->ptid (); -#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) - i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); -#endif if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) { @@ -75,50 +72,9 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) return; } -#ifdef PT_GETFSBASE - if (regnum == -1 || regnum == tdep->fsbase_regnum) - { - register_t base; - - if (gdb_ptrace (PT_GETFSBASE, ptid, (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 (gdb_ptrace (PT_GETGSBASE, ptid, (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 - if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum)) { struct fpreg fpregs; -#ifdef PT_GETXSTATE_INFO - void *xstateregs; - - if (x86bsd_xsave_len != 0) - { - xstateregs = alloca (x86bsd_xsave_len); - if (gdb_ptrace (PT_GETXSTATE, 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 (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) perror_with_name (_("Couldn't get floating point status")); @@ -135,9 +91,6 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = regcache->arch (); ptid_t ptid = regcache->ptid (); -#if defined(PT_SETFSBASE) || defined(PT_SETGSBASE) - i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch); -#endif if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum)) { @@ -155,58 +108,9 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum) 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 (gdb_ptrace (PT_SETFSBASE, ptid, (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 (gdb_ptrace (PT_SETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1) - perror_with_name (_("Couldn't write segment register gs_base")); - if (regnum != -1) - return; - } -#endif - if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum)) { struct fpreg fpregs; -#ifdef PT_GETXSTATE_INFO - void *xstateregs; - - if (x86bsd_xsave_len != 0) - { - xstateregs = alloca (x86bsd_xsave_len); - if (gdb_ptrace (PT_GETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs, 0) - == -1) - perror_with_name (_("Couldn't get extended state status")); - - amd64_collect_xsave (regcache, regnum, xstateregs, 0); - - if (gdb_ptrace (PT_SETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs, - x86bsd_xsave_len) == -1) - perror_with_name (_("Couldn't write extended state status")); - return; - } -#endif if (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) perror_with_name (_("Couldn't get floating point status")); diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c index f9bd45de455..98a1af03a66 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 + : public x86bsd_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 . */ -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 (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 (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. */ diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c index fa363776fc0..f87c976dd61 100644 --- a/gdb/amd64-fbsd-tdep.c +++ b/gdb/amd64-fbsd-tdep.c @@ -27,6 +27,7 @@ #include "gdbsupport/x86-xstate.h" #include "amd64-tdep.h" +#include "amd64-fbsd-tdep.h" #include "fbsd-tdep.h" #include "solib-svr4.h" #include "inferior.h" diff --git a/gdb/amd64-fbsd-tdep.h b/gdb/amd64-fbsd-tdep.h new file mode 100644 index 00000000000..0a18dbcbfd7 --- /dev/null +++ b/gdb/amd64-fbsd-tdep.h @@ -0,0 +1,27 @@ +/* FreeBSD/amd64 target support, prototypes. + + Copyright (C) 2021 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 AMD64_FBSD_TDEP_H +#define AMD64_FBSD_TDEP_H + +#include "regset.h" + +extern const struct regset amd64_fbsd_gregset; + +#endif /* AMD64_FBSD_TDEP_H */ diff --git a/gdb/configure.nat b/gdb/configure.nat index 6fc3978a77e..20ce8050a96 100644 --- a/gdb/configure.nat +++ b/gdb/configure.nat @@ -165,7 +165,7 @@ case ${gdb_host} in i386) # Host: FreeBSD/i386 NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \ - x86-bsd-nat.o i386-bsd-nat.o i386-fbsd-nat.o bsd-kvm.o" + x86-bsd-nat.o i386-fbsd-nat.o bsd-kvm.o" ;; mips) # Host: FreeBSD/mips @@ -192,7 +192,7 @@ case ${gdb_host} in case ${gdb_host_cpu} in i386) # Host: FreeBSD/amd64 - NATDEPFILES="${NATDEPFILES} amd64-nat.o amd64-bsd-nat.o \ + NATDEPFILES="${NATDEPFILES} amd64-nat.o \ amd64-fbsd-nat.o bsd-kvm.o x86-nat.o nat/x86-dregs.o \ x86-bsd-nat.o" ;; diff --git a/gdb/i386-bsd-nat.c b/gdb/i386-bsd-nat.c index c112b02c2e1..bd9655c9ef9 100644 --- a/gdb/i386-bsd-nat.c +++ b/gdb/i386-bsd-nat.c @@ -159,56 +159,12 @@ i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) return; } -#ifdef PT_GETFSBASE - if (regnum == -1 || regnum == I386_FSBASE_REGNUM) - { - register_t base; - - if (gdb_ptrace (PT_GETFSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1) - perror_with_name (_("Couldn't get segment register fs_base")); - - regcache->raw_supply (I386_FSBASE_REGNUM, &base); - if (regnum != -1) - return; - } -#endif -#ifdef PT_GETGSBASE - if (regnum == -1 || regnum == I386_GSBASE_REGNUM) - { - register_t base; - - if (gdb_ptrace (PT_GETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1) - perror_with_name (_("Couldn't get segment register gs_base")); - - regcache->raw_supply (I386_GSBASE_REGNUM, &base); - if (regnum != -1) - return; - } -#endif - if (regnum == -1 || regnum >= I386_ST0_REGNUM) { struct fpreg fpregs; #ifdef HAVE_PT_GETXMMREGS char xmmregs[512]; -#endif - -#ifdef PT_GETXSTATE_INFO - if (x86bsd_xsave_len != 0) - { - void *xstateregs; - xstateregs = alloca (x86bsd_xsave_len); - if (gdb_ptrace (PT_GETXSTATE, ptid, - (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) - perror_with_name (_("Couldn't get extended state status")); - - i387_supply_xsave (regcache, -1, xstateregs); - return; - } -#endif - -#ifdef HAVE_PT_GETXMMREGS if (have_ptrace_xmmregs != 0 && gdb_ptrace(PT_GETXMMREGS, ptid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) @@ -255,60 +211,12 @@ i386bsd_store_inferior_registers (struct regcache *regcache, int regnum) return; } -#ifdef PT_SETFSBASE - if (regnum == -1 || regnum == I386_FSBASE_REGNUM) - { - register_t base; - - regcache->raw_collect (I386_FSBASE_REGNUM, &base); - - if (gdb_ptrace (PT_SETFSBASE, ptid, (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 == I386_GSBASE_REGNUM) - { - register_t base; - - regcache->raw_collect (I386_GSBASE_REGNUM, &base); - - if (gdb_ptrace (PT_SETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1) - perror_with_name (_("Couldn't write segment register gs_base")); - if (regnum != -1) - return; - } -#endif - if (regnum == -1 || regnum >= I386_ST0_REGNUM) { struct fpreg fpregs; #ifdef HAVE_PT_GETXMMREGS char xmmregs[512]; -#endif - -#ifdef PT_GETXSTATE_INFO - if (x86bsd_xsave_len != 0) - { - void *xstateregs; - - xstateregs = alloca (x86bsd_xsave_len); - if (gdb_ptrace (PT_GETXSTATE, ptid, - (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) - perror_with_name (_("Couldn't get extended state status")); - i387_collect_xsave (regcache, -1, xstateregs, 0); - - if (gdb_ptrace (PT_SETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs, - x86bsd_xsave_len) == -1) - perror_with_name (_("Couldn't write extended state status")); - return; - } -#endif - -#ifdef HAVE_PT_GETXMMREGS if (have_ptrace_xmmregs != 0 && gdb_ptrace(PT_GETXMMREGS, ptid, (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c index 75fe5e78f20..6fb67434a2d 100644 --- a/gdb/i386-fbsd-nat.c +++ b/gdb/i386-fbsd-nat.c @@ -29,17 +29,20 @@ #include "fbsd-nat.h" #include "i386-tdep.h" +#include "i386-fbsd-tdep.h" +#include "i387-tdep.h" #include "x86-nat.h" #include "gdbsupport/x86-xstate.h" #include "x86-bsd-nat.h" -#include "i386-bsd-nat.h" class i386_fbsd_nat_target final - : public i386_bsd_nat_target + : public x86bsd_nat_target { public: - /* Add some extra features to the common *BSD/i386 target. */ -#ifdef PT_GETXSTATE_INFO + void fetch_registers (struct regcache *, int) override; + void store_registers (struct regcache *, int) override; + +#if defined(PT_GETXMMREGS) || defined(PT_GETXSTATE_INFO) const struct target_desc *read_description () override; #endif @@ -52,6 +55,192 @@ public: static i386_fbsd_nat_target the_i386_fbsd_nat_target; +#ifdef PT_GETXSTATE_INFO +static size_t xsave_len; +#endif + +#ifdef HAVE_PT_GETXMMREGS +static int have_ptrace_xmmregs; +#endif + +/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this + for all registers. */ + +void +i386_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = regcache->arch (); +#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) + const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +#endif + pid_t pid = get_ptrace_pid (regcache->ptid ()); + + if (fetch_register_set (regcache, regnum, PT_GETREGS, + &i386_fbsd_gregset)) + { + if (regnum != -1) + return; + } + +#ifdef PT_GETFSBASE + if (regnum == -1 || regnum == I386_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 (I386_FSBASE_REGNUM, &base); + if (regnum != -1) + return; + } +#endif +#ifdef PT_GETGSBASE + if (regnum == -1 || regnum == I386_GSBASE_REGNUM) + { + 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 (I386_GSBASE_REGNUM, &base); + if (regnum != -1) + return; + } +#endif + + /* There is no i386_fxsave_supplies or i386_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")); + + i387_supply_xsave (regcache, regnum, xstateregs); + return; + } +#endif +#ifdef HAVE_PT_GETXMMREGS + if (have_ptrace_xmmregs != 0) + { + char xmmregs[I387_SIZEOF_FXSAVE]; + + if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) + perror_with_name (_("Couldn't get XMM registers")); + + i387_supply_fxsave (regcache, regnum, xmmregs); + 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")); + + i387_supply_fsave (regcache, regnum, &fpregs); +} + +/* Store register REGNUM back into the inferior. If REGNUM is -1, do + this for all registers. */ + +void +i386_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum) +{ + struct gdbarch *gdbarch = regcache->arch (); +#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) + const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +#endif + pid_t pid = get_ptrace_pid (regcache->ptid ()); + + if (store_register_set (regcache, regnum, PT_GETREGS, PT_SETREGS, + &i386_fbsd_gregset)) + { + if (regnum != -1) + return; + } + +#ifdef PT_SETFSBASE + if (regnum == -1 || regnum == I386_FSBASE_REGNUM) + { + register_t base; + + regcache->raw_collect (I386_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 == I386_GSBASE_REGNUM) + { + register_t base; + + regcache->raw_collect (I386_GSBASE_REGNUM, &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 i386_fxsave_supplies or i386_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")); + + i387_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 +#ifdef HAVE_PT_GETXMMREGS + if (have_ptrace_xmmregs != 0) + { + char xmmregs[I387_SIZEOF_FXSAVE]; + + if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) + perror_with_name (_("Couldn't get XMM registers")); + + i387_collect_fxsave (regcache, regnum, xmmregs); + + if (ptrace (PT_SETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) + perror_with_name (_("Couldn't write XMM registers")); + 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")); + + i387_collect_fsave (regcache, regnum, &fpregs); + + if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) + perror_with_name (_("Couldn't write floating point status")); +} + /* Resume execution of the inferior process. If STEP is nonzero, single-step it. If SIGNAL is nonzero, give it that signal. */ @@ -135,15 +324,21 @@ i386fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) } -#ifdef PT_GETXSTATE_INFO +#if defined(PT_GETXMMREGS) || defined(PT_GETXSTATE_INFO) /* Implement the read_description method. */ const struct target_desc * i386_fbsd_nat_target::read_description () { +#ifdef PT_GETXSTATE_INFO static int xsave_probed; static uint64_t xcr0; +#endif +#ifdef PT_GETXMMREGS + static int xmm_probed; +#endif +#ifdef PT_GETXSTATE_INFO if (!xsave_probed) { struct ptrace_xstate_info info; @@ -151,16 +346,32 @@ i386_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) - xcr0 = X86_XSTATE_SSE_MASK; + if (xsave_len != 0) + return i386_target_description (xcr0, true); +#endif + +#ifdef PT_GETXMMREGS + if (!xmm_probed) + { + char xmmregs[I387_SIZEOF_FXSAVE]; + + if (ptrace (PT_GETXMMREGS, inferior_ptid.pid (), + (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) + have_ptrace_xmmregs = 1; + xmm_probed = 1; + } + + if (have_ptrace_xmmregs) + return i386_target_description (X86_XSTATE_SSE_MASK, true); +#endif - return i386_target_description (xcr0, true); + return i386_target_description (X86_XSTATE_X87_MASK, true); } #endif diff --git a/gdb/i386-fbsd-tdep.h b/gdb/i386-fbsd-tdep.h index 583f49f84f2..76f4c20f657 100644 --- a/gdb/i386-fbsd-tdep.h +++ b/gdb/i386-fbsd-tdep.h @@ -20,6 +20,8 @@ #ifndef I386_FBSD_TDEP_H #define I386_FBSD_TDEP_H +#include "regset.h" + /* Get XSAVE extended state xcr0 from core dump. */ extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd); @@ -28,4 +30,6 @@ extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd); matches the layout on Linux. */ #define I386_FBSD_XSAVE_XCR0_OFFSET 464 +extern const struct regset i386_fbsd_gregset; + #endif /* i386-fbsd-tdep.h */ diff --git a/gdb/x86-bsd-nat.c b/gdb/x86-bsd-nat.c index 06da979f83b..099059a5e0b 100644 --- a/gdb/x86-bsd-nat.c +++ b/gdb/x86-bsd-nat.c @@ -33,10 +33,6 @@ #include "inf-ptrace.h" -#ifdef PT_GETXSTATE_INFO -size_t x86bsd_xsave_len; -#endif - /* Support for debug registers. */ #ifdef HAVE_PT_GETDBREGS diff --git a/gdb/x86-bsd-nat.h b/gdb/x86-bsd-nat.h index a545ee33306..8b6760e7169 100644 --- a/gdb/x86-bsd-nat.h +++ b/gdb/x86-bsd-nat.h @@ -22,9 +22,6 @@ #include "x86-nat.h" -/* Low level x86 XSAVE info. */ -extern size_t x86bsd_xsave_len; - /* A prototype *BSD/x86 target. */ #ifdef HAVE_PT_GETDBREGS -- 2.30.2