diff options
author | Simon Marchi <simon.marchi@efficios.com> | 2020-04-27 10:46:51 -0400 |
---|---|---|
committer | Simon Marchi <simon.marchi@efficios.com> | 2020-04-27 10:47:50 -0400 |
commit | 1eb399142793d31d1b7a358baad5fded996e02eb (patch) | |
tree | fd64c7f70ebbfc23e2624f5d2f6fa6b7bb850f76 /gdbserver | |
parent | 45fc7c9968485f5ee0532a14fad211372e12f837 (diff) | |
download | fsf-binutils-gdb-1eb399142793d31d1b7a358baad5fded996e02eb.zip fsf-binutils-gdb-1eb399142793d31d1b7a358baad5fded996e02eb.tar.gz fsf-binutils-gdb-1eb399142793d31d1b7a358baad5fded996e02eb.tar.bz2 |
gdb, gdbserver: remove configure check for fs_base/gs_base in user_regs_struct
I recently stumbled on this code mentioning Linux kernel 2.6.25, and
thought it could be time for some spring cleaning (newer GDBs probably
don't need to supports 12-year old kernels). I then found that the
"legacy" case is probably broken anyway, which gives an even better
motivation for its removal.
In short, this patch removes the configure checks that check if
user_regs_struct contains the fs_base/gs_base fields and adjusts all
uses of the HAVE_STRUCT_USER_REGS_STRUCT_{FS,GS}_BASE macros. The
longer explanation/rationale follows.
Apparently, Linux kernels since 2.6.25 (that's from 2008) have been
reliably providing fs_base and gs_base as part of user_regs_struct.
Commit df5d438e33d7 in the Linux kernel [1] seems related. This means
that we can get these values by reading registers with PTRACE_GETREGS.
Previously, these values were obtained using a separate
PTRACE_ARCH_PRCTL ptrace call.
First, I'm not even sure the configure check was really right in the
first place.
The user_regs_struct used by GDB comes from
/usr/include/x86_64-linux-gnu/sys/user.h (or equivalent on other
distros) and is provided by glibc. glibc has had the fs_base/gs_base
fields in there for a very long time, at least since this commit from
2001 [2]. The Linux kernel also has its version of user_regs_struct,
which I think was exported to user-space at some point. It included the
fs_base/gs_base fields since at least this 2002 commit [3]. In any
case, my conclusion is that the fields were there long before the
aforementioned Linux kernel commit. The kernel commit didn't add these
fields, it only made sure that they have reliable values when obtained
with PTRACE_GETREGS.
So, checking for the presence of the fs_base/gs_base fields in struct
user_regs_struct doesn't sound like a good way of knowing if we can
reliably get the fs_base/gs_base values from PTRACE_GETREGS. My guess
is that if we were using that strategy on a < 2.6.25 kernel, things
would not work correctly:
- configure would find that the user_regs_struct has the fs_base/gs_base
fields (which are probided by glibc anyway)
- we would be reading the fs_base/gs_base values using PTRACE_GETREGS,
for which the kernel would provide unreliable values
Second, I have tried to see how things worked by forcing GDB to not use
fs_base/gs_base from PTRACE_GETREGS (forcing it to use the "legacy"
code, by configuring with
ac_cv_member_struct_user_regs_struct_gs_base=no ac_cv_member_struct_user_regs_struct_fs_base=no
Doing so breaks writing registers back to the inferior. For example,
calling an inferior functions gives an internal error:
(gdb) p malloc(10)
/home/smarchi/src/binutils-gdb/gdb/i387-tdep.c:1408: internal-error: invalid i387 regnum 152
The relevant last frames where this error happens are:
#8 0x0000563123d262fc in internal_error (file=0x563123e93fd8 "/home/smarchi/src/binutils-gdb/gdb/i387-tdep.c", line=1408, fmt=0x563123e94482 "invalid i387 regnum %d") at /home/smarchi/src/binutils-gdb/gdbsupport/errors.cc:55
#9 0x0000563123047d0d in i387_collect_xsave (regcache=0x5631269453f0, regnum=152, xsave=0x7ffd38402a20, gcore=0) at /home/smarchi/src/binutils-gdb/gdb/i387-tdep.c:1408
#10 0x0000563122c69e8a in amd64_collect_xsave (regcache=0x5631269453f0, regnum=152, xsave=0x7ffd38402a20, gcore=0) at /home/smarchi/src/binutils-gdb/gdb/amd64-tdep.c:3448
#11 0x0000563122c5e94c in amd64_linux_nat_target::store_registers (this=0x56312515fd10 <the_amd64_linux_nat_target>, regcache=0x5631269453f0, regnum=152) at /home/smarchi/src/binutils-gdb/gdb/amd64-linux-nat.c:335
#12 0x00005631234c8c80 in target_store_registers (regcache=0x5631269453f0, regno=152) at /home/smarchi/src/binutils-gdb/gdb/target.c:3485
#13 0x00005631232e8df7 in regcache::raw_write (this=0x5631269453f0, regnum=152, buf=0x56312759e468 "@\225\372\367\377\177") at /home/smarchi/src/binutils-gdb/gdb/regcache.c:765
#14 0x00005631232e8f0c in regcache::cooked_write (this=0x5631269453f0, regnum=152, buf=0x56312759e468 "@\225\372\367\377\177") at /home/smarchi/src/binutils-gdb/gdb/regcache.c:778
#15 0x00005631232e75ec in regcache::restore (this=0x5631269453f0, src=0x5631275eb130) at /home/smarchi/src/binutils-gdb/gdb/regcache.c:283
#16 0x0000563123083fc4 in infcall_suspend_state::restore (this=0x5631273ed930, gdbarch=0x56312718cf20, tp=0x5631270bca90, regcache=0x5631269453f0) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:9103
#17 0x0000563123081eed in restore_infcall_suspend_state (inf_state=0x5631273ed930) at /home/smarchi/src/binutils-gdb/gdb/infrun.c:9151
The problem seems to be that amd64_linux_nat_target::store_registers
calls amd64_native_gregset_supplies_p to know whether gregset provides
fs_base. When !HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE,
amd64_native_gregset_supplies_p returns false. store_registers
therefore assumes that it must be an "xstate" register. This is of
course wrong, and that leads to the failed assertion when
i387_collect_xsave doesn't recognize the register.
amd64_linux_nat_target::store_registers could probably be fixed to
handle this case, but I don't think it's worth it, given that it would
only be to support very old kernels.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=df5d438e33d7fc914ba9b6e0d6b019a8966c5fcc
[2] https://sourceware.org/git/?p=glibc.git;a=commit;h=c9cf6ddeebb7bb
[3] https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/?id=88e4bc32686ebd0b1111a94f93eba2d334241f68
gdb/ChangeLog:
* configure.ac: Remove check for fs_base/gs_base in
user_regs_struct.
* configure: Re-generate.
* config.in: Re-generate.
* amd64-nat.c (amd64_native_gregset_reg_offset): Adjust.
* amd64-linux-nat.c (amd64_linux_nat_target::fetch_registers,
amd64_linux_nat_target::store_registers, ps_get_thread_area, ): Adjust.
gdbserver/ChangeLog:
* configure.ac: Remove check for fs_base/gs_base in
user_regs_struct.
* configure: Re-generate.
* config.in: Re-generate.
* linux-x86-low.cc (x86_64_regmap, x86_fill_gregset,
x86_store_gregset): Adjust.
Diffstat (limited to 'gdbserver')
-rw-r--r-- | gdbserver/ChangeLog | 9 | ||||
-rw-r--r-- | gdbserver/config.in | 6 | ||||
-rwxr-xr-x | gdbserver/configure | 28 | ||||
-rw-r--r-- | gdbserver/configure.ac | 8 | ||||
-rw-r--r-- | gdbserver/linux-x86-low.cc | 29 |
5 files changed, 9 insertions, 71 deletions
diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index f017922..3b5fd99 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,3 +1,12 @@ +2020-04-27 Simon Marchi <simon.marchi@efficios.com> + + * configure.ac: Remove check for fs_base/gs_base in + user_regs_struct. + * configure: Re-generate. + * config.in: Re-generate. + * linux-x86-low.cc (x86_64_regmap, x86_fill_gregset, + x86_store_gregset): Adjust. + 2020-04-22 Hannes Domani <ssbssa@yahoo.de> * server.cc (handle_search_memory_1): Fix gdb_read_memory return value diff --git a/gdbserver/config.in b/gdbserver/config.in index 8683ce6..07213aa 100644 --- a/gdbserver/config.in +++ b/gdbserver/config.in @@ -303,12 +303,6 @@ /* Define to 1 if `st_blocks' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLOCKS -/* Define to 1 if `fs_base' is a member of `struct user_regs_struct'. */ -#undef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - -/* Define to 1 if `gs_base' is a member of `struct user_regs_struct'. */ -#undef HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE - /* Define to 1 if the target supports __sync_*_compare_and_swap */ #undef HAVE_SYNC_BUILTINS diff --git a/gdbserver/configure b/gdbserver/configure index 06edb45..5479823 100755 --- a/gdbserver/configure +++ b/gdbserver/configure @@ -10043,34 +10043,6 @@ cat >>confdefs.h <<_ACEOF _ACEOF -# See if <sys/user.h> supports the %fs_base and %gs_bas amd64 segment registers. -# Older amd64 Linux's don't have the fs_base and gs_base members of -# `struct user_regs_struct'. -ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "fs_base" "ac_cv_member_struct_user_regs_struct_fs_base" "#include <sys/types.h> -#include <sys/user.h> -" -if test "x$ac_cv_member_struct_user_regs_struct_fs_base" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE 1 -_ACEOF - - -fi -ac_fn_c_check_member "$LINENO" "struct user_regs_struct" "gs_base" "ac_cv_member_struct_user_regs_struct_gs_base" "#include <sys/types.h> -#include <sys/user.h> -" -if test "x$ac_cv_member_struct_user_regs_struct_gs_base" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE 1 -_ACEOF - - -fi - - - ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" "#include <sys/types.h> #include <sys/socket.h> diff --git a/gdbserver/configure.ac b/gdbserver/configure.ac index 755cc28..090a6dc 100644 --- a/gdbserver/configure.ac +++ b/gdbserver/configure.ac @@ -145,14 +145,6 @@ libiberty_INIT AC_CHECK_DECLS([perror, vasprintf, vsnprintf]) -# See if <sys/user.h> supports the %fs_base and %gs_bas amd64 segment registers. -# Older amd64 Linux's don't have the fs_base and gs_base members of -# `struct user_regs_struct'. -AC_CHECK_MEMBERS([struct user_regs_struct.fs_base, struct user_regs_struct.gs_base], - [], [], [#include <sys/types.h> -#include <sys/user.h>]) - - AC_CHECK_TYPES(socklen_t, [], [], [#include <sys/types.h> #include <sys/socket.h> diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index f6a399e..7a65c1d 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -233,11 +233,7 @@ static const int x86_64_regmap[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, ORIG_RAX * 8, -#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE 21 * 8, 22 * 8, -#else - -1, -1, -#endif -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */ -1, -1, /* MPX registers BNDCFGU, BNDSTATUS. */ -1, -1, -1, -1, -1, -1, -1, -1, /* xmm16 ... xmm31 (AVX512) */ @@ -413,19 +409,6 @@ x86_fill_gregset (struct regcache *regcache, void *buf) if (x86_64_regmap[i] != -1) collect_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); -#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - { - unsigned long base; - int lwpid = lwpid_of (current_thread); - - collect_register_by_name (regcache, "fs_base", &base); - ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_FS); - - collect_register_by_name (regcache, "gs_base", &base); - ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_SET_GS); - } -#endif - return; } @@ -468,18 +451,6 @@ x86_store_gregset (struct regcache *regcache, const void *buf) if (x86_64_regmap[i] != -1) supply_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); -#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE - { - unsigned long base; - int lwpid = lwpid_of (current_thread); - - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_FS) == 0) - supply_register_by_name (regcache, "fs_base", &base); - - if (ptrace (PTRACE_ARCH_PRCTL, lwpid, &base, ARCH_GET_GS) == 0) - supply_register_by_name (regcache, "gs_base", &base); - } -#endif return; } #endif |