[2/9] Support fs_base and gs_base on FreeBSD/i386.

Message ID dd63aee602e301565ca6853c8c40d983bc39fb2c.1548180889.git.jhb@FreeBSD.org
State New, archived
Headers

Commit Message

John Baldwin Jan. 22, 2019, 6:42 p.m. UTC
  The i386 BSD native target uses the same ptrace operations
(PT_[GS]ET[FG]SBASE) as the amd64 BSD native target to fetch and store
the registers.

The amd64 BSD native now uses 'tdep->fsbase_regnum' instead of
hardcoding AMD64_FSBASE_REGNUM and AMD64_GSBASE_REGNUM to support
32-bit targets.  In addition, the store operations explicitly zero the
new register value before fetching it from the register cache to
ensure 32-bit values are zero-extended.

gdb/ChangeLog:

	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
	(amd64bsd_store_inferior_registers): Likewise.
	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
	Enable segment base registers.
	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
	PT_GETFSBASE and PT_GETGSBASE.
	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and PT_SETGSBASE.
	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
	segment base registers.
	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
---
 gdb/ChangeLog        | 14 ++++++++++++
 gdb/amd64-bsd-nat.c  | 26 ++++++++++++++-------
 gdb/amd64-fbsd-nat.c |  4 ++--
 gdb/i386-bsd-nat.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/i386-fbsd-nat.c  |  2 +-
 gdb/i386-fbsd-tdep.c |  2 +-
 6 files changed, 90 insertions(+), 12 deletions(-)
  

Comments

Simon Marchi Feb. 2, 2019, 3:26 p.m. UTC | #1
On 2019-01-22 13:42, John Baldwin wrote:
> The i386 BSD native target uses the same ptrace operations
> (PT_[GS]ET[FG]SBASE) as the amd64 BSD native target to fetch and store
> the registers.
> 
> The amd64 BSD native now uses 'tdep->fsbase_regnum' instead of
> hardcoding AMD64_FSBASE_REGNUM and AMD64_GSBASE_REGNUM to support
> 32-bit targets.  In addition, the store operations explicitly zero the
> new register value before fetching it from the register cache to
> ensure 32-bit values are zero-extended.

To be clear, this happens when debugging a 32-bits process on a 64-bits 
OS?  When debugging a 32-bits process on a 32-bits OS, the code in 
i386-bsd-nat.c would be used?

> gdb/ChangeLog:
> 
> 	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
> 	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
> 	(amd64bsd_store_inferior_registers): Likewise.
> 	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
> 	Enable segment base registers.
> 	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
> 	PT_GETFSBASE and PT_GETGSBASE.
> 	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and PT_SETGSBASE.
> 	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
> 	segment base registers.
> 	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
> ---
>  gdb/ChangeLog        | 14 ++++++++++++
>  gdb/amd64-bsd-nat.c  | 26 ++++++++++++++-------
>  gdb/amd64-fbsd-nat.c |  4 ++--
>  gdb/i386-bsd-nat.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++
>  gdb/i386-fbsd-nat.c  |  2 +-
>  gdb/i386-fbsd-tdep.c |  2 +-
>  6 files changed, 90 insertions(+), 12 deletions(-)
> 
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 4afd5b664e..056a60fa23 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,17 @@
> +2019-01-22  John Baldwin  <jhb@FreeBSD.org>
> +
> +	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
> +	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
> +	(amd64bsd_store_inferior_registers): Likewise.
> +	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
> +	Enable segment base registers.
> +	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
> +	PT_GETFSBASE and PT_GETGSBASE.
> +	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and 
> PT_SETGSBASE.
> +	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
> +	segment base registers.
> +	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
> +
>  2019-01-22  John Baldwin  <jhb@FreeBSD.org>
> 
>  	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
> diff --git a/gdb/amd64-bsd-nat.c b/gdb/amd64-bsd-nat.c
> index a2a91abb91..0f47ff6c61 100644
> --- a/gdb/amd64-bsd-nat.c
> +++ b/gdb/amd64-bsd-nat.c
> @@ -43,6 +43,9 @@ amd64bsd_fetch_inferior_registers (struct regcache
> *regcache, int regnum)
>  {
>    struct gdbarch *gdbarch = regcache->arch ();
>    pid_t pid = get_ptrace_pid (regcache->ptid ());
> +#ifdef PT_GETFSBASE
> +  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +#endif

TDEP is used in both #ifdef PT_GETFSBASE and #ifdef PT_GETGSBASE, but is 
only declared here in an #ifdef PT_GETFSBASE.  I suppose it's not 
actually an issue because they will always be present together.  But we 
might as well use "#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)" 
for the declaration.

> 
>    if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, 
> regnum))
>      {
> @@ -57,27 +60,27 @@ amd64bsd_fetch_inferior_registers (struct regcache
> *regcache, int regnum)
>      }
> 
>  #ifdef PT_GETFSBASE
> -  if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
> +  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 (AMD64_FSBASE_REGNUM, &base);
> +      regcache->raw_supply (tdep->fsbase_regnum, &base);
>        if (regnum != -1)
>  	return;
>      }
>  #endif
>  #ifdef PT_GETGSBASE
> -  if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM)
> +  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 (AMD64_GSBASE_REGNUM, &base);
> +      regcache->raw_supply (tdep->fsbase_regnum + 1, &base);
>        if (regnum != -1)
>  	return;
>      }
> @@ -116,6 +119,9 @@ amd64bsd_store_inferior_registers (struct regcache
> *regcache, int regnum)
>  {
>    struct gdbarch *gdbarch = regcache->arch ();
>    pid_t pid = get_ptrace_pid (regcache->ptid ());
> +#ifdef PT_GETFSBASE
> +  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +#endif

Same here.

> 
>    if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, 
> regnum))
>      {
> @@ -134,11 +140,13 @@ amd64bsd_store_inferior_registers (struct
> regcache *regcache, int regnum)
>      }
> 
>  #ifdef PT_SETFSBASE
> -  if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
> +  if (regnum == -1 || regnum == tdep->fsbase_regnum)
>      {
>        register_t base;
> 
> -      regcache->raw_collect (AMD64_FSBASE_REGNUM, &base);
> +      /* Clear the full base value to support 32-bit targets.  */
> +      base = 0;
> +      regcache->raw_collect (tdep->fsbase_regnum, &base);

It's probably safer to clear the value to 0 as you did, so that's fine.  
But I would have thought that when debugging 32-bits processes, the high 
bits would be ignored at some point.  The kernel would know that this is 
a 32 bits register, so it would just take the 32 low bits of what it 
receives, and it magically works whatever the original data type is 
because it's little endian.

Otherwise, this LGTM.

Simon
  
John Baldwin Feb. 4, 2019, 7:45 p.m. UTC | #2
On 2/2/19 7:26 AM, Simon Marchi wrote:
> On 2019-01-22 13:42, John Baldwin wrote:
>> The i386 BSD native target uses the same ptrace operations
>> (PT_[GS]ET[FG]SBASE) as the amd64 BSD native target to fetch and store
>> the registers.
>>
>> The amd64 BSD native now uses 'tdep->fsbase_regnum' instead of
>> hardcoding AMD64_FSBASE_REGNUM and AMD64_GSBASE_REGNUM to support
>> 32-bit targets.  In addition, the store operations explicitly zero the
>> new register value before fetching it from the register cache to
>> ensure 32-bit values are zero-extended.
> 
> To be clear, this happens when debugging a 32-bits process on a 64-bits 
> OS?  When debugging a 32-bits process on a 32-bits OS, the code in 
> i386-bsd-nat.c would be used?

Correct.

>> gdb/ChangeLog:
>>
>> 	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
>> 	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
>> 	(amd64bsd_store_inferior_registers): Likewise.
>> 	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
>> 	Enable segment base registers.
>> 	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
>> 	PT_GETFSBASE and PT_GETGSBASE.
>> 	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and PT_SETGSBASE.
>> 	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
>> 	segment base registers.
>> 	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
>> ---
>>  gdb/ChangeLog        | 14 ++++++++++++
>>  gdb/amd64-bsd-nat.c  | 26 ++++++++++++++-------
>>  gdb/amd64-fbsd-nat.c |  4 ++--
>>  gdb/i386-bsd-nat.c   | 54 ++++++++++++++++++++++++++++++++++++++++++++
>>  gdb/i386-fbsd-nat.c  |  2 +-
>>  gdb/i386-fbsd-tdep.c |  2 +-
>>  6 files changed, 90 insertions(+), 12 deletions(-)
>>
>> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
>> index 4afd5b664e..056a60fa23 100644
>> --- a/gdb/ChangeLog
>> +++ b/gdb/ChangeLog
>> @@ -1,3 +1,17 @@
>> +2019-01-22  John Baldwin  <jhb@FreeBSD.org>
>> +
>> +	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
>> +	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
>> +	(amd64bsd_store_inferior_registers): Likewise.
>> +	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
>> +	Enable segment base registers.
>> +	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
>> +	PT_GETFSBASE and PT_GETGSBASE.
>> +	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and 
>> PT_SETGSBASE.
>> +	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
>> +	segment base registers.
>> +	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
>> +
>>  2019-01-22  John Baldwin  <jhb@FreeBSD.org>
>>
>>  	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
>> diff --git a/gdb/amd64-bsd-nat.c b/gdb/amd64-bsd-nat.c
>> index a2a91abb91..0f47ff6c61 100644
>> --- a/gdb/amd64-bsd-nat.c
>> +++ b/gdb/amd64-bsd-nat.c
>> @@ -43,6 +43,9 @@ amd64bsd_fetch_inferior_registers (struct regcache
>> *regcache, int regnum)
>>  {
>>    struct gdbarch *gdbarch = regcache->arch ();
>>    pid_t pid = get_ptrace_pid (regcache->ptid ());
>> +#ifdef PT_GETFSBASE
>> +  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +#endif
> 
> TDEP is used in both #ifdef PT_GETFSBASE and #ifdef PT_GETGSBASE, but is 
> only declared here in an #ifdef PT_GETFSBASE.  I suppose it's not 
> actually an issue because they will always be present together.  But we 
> might as well use "#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)" 
> for the declaration.

Ok.  I could also just perhaps collapse the other two #ifdef's instead of
using separate ones.  FreeBSD always provides both if it provides one.  None
of the other BSD's provide these currently.  I suspect if they did they
would always provide both.

>> @@ -134,11 +140,13 @@ amd64bsd_store_inferior_registers (struct
>> regcache *regcache, int regnum)
>>      }
>>
>>  #ifdef PT_SETFSBASE
>> -  if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
>> +  if (regnum == -1 || regnum == tdep->fsbase_regnum)
>>      {
>>        register_t base;
>>
>> -      regcache->raw_collect (AMD64_FSBASE_REGNUM, &base);
>> +      /* Clear the full base value to support 32-bit targets.  */
>> +      base = 0;
>> +      regcache->raw_collect (tdep->fsbase_regnum, &base);
> 
> It's probably safer to clear the value to 0 as you did, so that's fine.  
> But I would have thought that when debugging 32-bits processes, the high 
> bits would be ignored at some point.  The kernel would know that this is 
> a 32 bits register, so it would just take the 32 low bits of what it 
> receives, and it magically works whatever the original data type is 
> because it's little endian.

I had originally just done this out of paranoia, but I checked and FreeBSD's
amd64 kernel will actually fail attempts to set the base address higher
than 4G with EINVAL rather than silently truncating.
  
Simon Marchi Feb. 5, 2019, 6:58 p.m. UTC | #3
On 2019-02-04 14:45, John Baldwin wrote:
> I had originally just done this out of paranoia, but I checked and 
> FreeBSD's
> amd64 kernel will actually fail attempts to set the base address higher
> than 4G with EINVAL rather than silently truncating.

That's even better!
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4afd5b664e..056a60fa23 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@ 
+2019-01-22  John Baldwin  <jhb@FreeBSD.org>
+
+	* amd64-bsd-nat.c (amd64bsd_fetch_inferior_registers): Use
+	tdep->fsbase_regnum instead of constants for fs_base and gs_base.
+	(amd64bsd_store_inferior_registers): Likewise.
+	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
+	Enable segment base registers.
+	* i386-bsd-nat.c (i386bsd_fetch_inferior_registers): Use
+	PT_GETFSBASE and PT_GETGSBASE.
+	(i386bsd_store_inferior_registers): Use PT_SETFSBASE and PT_SETGSBASE.
+	* i386-fbsd-nat.c (i386_fbsd_nat_target::read_description): Enable
+	segment base registers.
+	* i386-fbsd-tdep.c (i386fbsd_core_read_description): Likewise.
+
 2019-01-22  John Baldwin  <jhb@FreeBSD.org>
 
 	* amd64-fbsd-nat.c (amd64_fbsd_nat_target::read_description):
diff --git a/gdb/amd64-bsd-nat.c b/gdb/amd64-bsd-nat.c
index a2a91abb91..0f47ff6c61 100644
--- a/gdb/amd64-bsd-nat.c
+++ b/gdb/amd64-bsd-nat.c
@@ -43,6 +43,9 @@  amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   pid_t pid = get_ptrace_pid (regcache->ptid ());
+#ifdef PT_GETFSBASE
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+#endif
 
   if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
@@ -57,27 +60,27 @@  amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
     }
 
 #ifdef PT_GETFSBASE
-  if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
+  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 (AMD64_FSBASE_REGNUM, &base);
+      regcache->raw_supply (tdep->fsbase_regnum, &base);
       if (regnum != -1)
 	return;
     }
 #endif
 #ifdef PT_GETGSBASE
-  if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM)
+  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 (AMD64_GSBASE_REGNUM, &base);
+      regcache->raw_supply (tdep->fsbase_regnum + 1, &base);
       if (regnum != -1)
 	return;
     }
@@ -116,6 +119,9 @@  amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   pid_t pid = get_ptrace_pid (regcache->ptid ());
+#ifdef PT_GETFSBASE
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+#endif
 
   if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
@@ -134,11 +140,13 @@  amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
     }
 
 #ifdef PT_SETFSBASE
-  if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
+  if (regnum == -1 || regnum == tdep->fsbase_regnum)
     {
       register_t base;
 
-      regcache->raw_collect (AMD64_FSBASE_REGNUM, &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"));
@@ -147,11 +155,13 @@  amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
     }
 #endif
 #ifdef PT_SETGSBASE
-  if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM)
+  if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
     {
       register_t base;
 
-      regcache->raw_collect (AMD64_GSBASE_REGNUM, &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"));
diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c
index 39ba69d9bf..e31232bd20 100644
--- a/gdb/amd64-fbsd-nat.c
+++ b/gdb/amd64-fbsd-nat.c
@@ -190,13 +190,13 @@  amd64_fbsd_nat_target::read_description ()
       if (is64)
 	return amd64_target_description (xcr0, true);
       else
-	return i386_target_description (xcr0, false);
+	return i386_target_description (xcr0, true);
     }
 #endif
   if (is64)
     return amd64_target_description (X86_XSTATE_SSE_MASK, true);
   else
-    return i386_target_description (X86_XSTATE_SSE_MASK, false);
+    return i386_target_description (X86_XSTATE_SSE_MASK, true);
 }
 
 #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO)
diff --git a/gdb/i386-bsd-nat.c b/gdb/i386-bsd-nat.c
index 009a8dc1b2..a10b496096 100644
--- a/gdb/i386-bsd-nat.c
+++ b/gdb/i386-bsd-nat.c
@@ -144,6 +144,33 @@  i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
 	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
+
   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
     {
       struct fpreg fpregs;
@@ -211,6 +238,33 @@  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 (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
+
   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
     {
       struct fpreg fpregs;
diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c
index 8ff104cf72..f2703a3c75 100644
--- a/gdb/i386-fbsd-nat.c
+++ b/gdb/i386-fbsd-nat.c
@@ -160,7 +160,7 @@  i386_fbsd_nat_target::read_description ()
   if (x86bsd_xsave_len == 0)
     xcr0 = X86_XSTATE_SSE_MASK;
 
-  return i386_target_description (xcr0, false);
+  return i386_target_description (xcr0, true);
 }
 #endif
 
diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c
index 43b15167ae..239ca91abe 100644
--- a/gdb/i386-fbsd-tdep.c
+++ b/gdb/i386-fbsd-tdep.c
@@ -267,7 +267,7 @@  i386fbsd_core_read_description (struct gdbarch *gdbarch,
 				struct target_ops *target,
 				bfd *abfd)
 {
-  return i386_target_description (i386fbsd_core_read_xcr0 (abfd), false);
+  return i386_target_description (i386fbsd_core_read_xcr0 (abfd), true);
 }
 
 /* Similar to i386_supply_fpregset, but use XSAVE extended state.  */