[gdb/server] Don't overwrite fs/gs_base with -m32
authorTom de Vries <tdevries@suse.de>
Wed, 20 Jan 2021 15:29:30 +0000 (16:29 +0100)
committerTom de Vries <tdevries@suse.de>
Wed, 20 Jan 2021 15:29:30 +0000 (16:29 +0100)
commit037e8112b9794a633248e5aa5943f3be273e0a20
treed1a60fb8935822581e8413e5b401477bc56101fd
parent4bd7c90276a11ee2f43c6bbe62f2379f3a225234
[gdb/server] Don't overwrite fs/gs_base with -m32

Consider a minimal test-case test.c:
...
int main (void) { return 0; }
...
compiled with -m32:
...
$ gcc test.c -m32
...

When running the exec using gdbserver on openSUSE Factory (currently running a
linux kernel version 5.10.5):
...
$ gdbserver localhost:12345 a.out
...
to which we connect in a gdb session, we run into a segfault in the inferior:
...
$ gdb -batch -q -ex "target remote localhost:12345" -ex continue
Program received signal SIGSEGV, Segmentation fault.
0xf7dd8bd2 in init_cacheinfo () at ../sysdeps/x86/cacheinfo.c:761
...

The segfault is caused by gdbserver overwriting $gs_base with 0 using
PTRACE_SETREGS.  After it is overwritten, the next use of $gs in the inferior
will trigger the segfault.

Before linux kernel version 5.9, the value used by PTRACE_SETREGS for $gs_base
was ignored, but starting version 5.9, the linux kernel has support for
intel architecture extension FSGSBASE, which allows users to modify $gs_base,
and consequently PTRACE_SETREGS can no longer ignore the $gs_base value.

The overwrite of $gs_base with 0 is done by a memset in x86_fill_gregset,
which was added in commit 9e0aa64f551 "Fix gdbserver qGetTLSAddr for
x86_64 -m32".  The memset intends to zero-extend 32-bit registers that are
tracked in the regcache to 64-bit when writing them into the PTRACE_SETREGS
data argument.  But in addition, it overwrites other registers that are
not tracked in the regcache, such as $gs_base.

Fix the segfault by redoing the fix from commit 9e0aa64f551 in minimal form.

Tested on x86_64-linux:
- openSUSE Leap 15.2 (using kernel version 5.3.18):
  - native
  - gdbserver -m32
  - -m32
- openSUSE Factory (using kernel version 5.10.5):
  - native
  - m32

gdbserver/ChangeLog:

2021-01-20  Tom de Vries  <tdevries@suse.de>

* linux-x86-low.cc (collect_register_i386): New function.
(x86_fill_gregset):  Remove memset.  Use collect_register_i386.
gdbserver/ChangeLog
gdbserver/linux-x86-low.cc