[00/11] GDB-internal TLS support for Linux targets

Message ID 20241010022552.47637-1-kevinb@redhat.com
Headers
Series GDB-internal TLS support for Linux targets |

Message

Kevin Buettner Oct. 10, 2024, 2:16 a.m. UTC
  This series of commits adds internal TLS lookup support to GDB for the
following Linux target architectures: x86_64, aarch64, ppc64, s390x,
and riscv.

It does this by providing knowledge about how to translate link map
addresses to module ids and how to traverse various TLS data
structures.

Translating link map addresses to module ids is tricky.  In theory,
this value is available in the link map data structure, but it's
not part of the ABI.  I ended up implementing two mechanisms for
doing this mapping, one for MUSL, and one for GLIBC.  For both of
these, I think the method that I used is less fragile than attempting
to use an offset to the module id field for a current versions of
these libraries.

Traversing TLS data structures starts with obtaining the
value of the thread register (or registers for S390X), then finding
the field containing the DTV (dynamic thread vector) address within
the TCB (thread control block), then using the module id as an index
into the DTV in order to obtain the TLS block.  For some C libraries
(MUSL, but only on certain architectures), a final adjustment may be
needed to obtain the actual address of the TLS block.

This patch set also shows how internal TLS support might be added for
i386, however, due to problems with accessing the gsbase register, it
doesn't work, so the commit which adds this potential support is then
immediately deleted in the next commit.  The point of doing this is so
that it's available to anyone who wishes to work on i386 support.  IMO,
it's not worth doing without also doing corresponding ptrace work in
the kernel.  I think this would have been worth doing back in the i386
heyday, but is not worth doing now.

The details for traversing the TLS data structures differ not only
between architectures, but also depends upon the C library with which
the executable being debugged has been linked.  The internal TLS
support in this series is known to work with GLIBC versions 2.27 thru
2.40.9000 and MUSL versions 1.1.24, 1.2.3 and 1.2.5.  For MUSL, the
support provided by this series provides new debugging functionality
that didn't exist before - it will now be possible to examine TLS
variables in programs linked against MUSL.  (It didn't work before
due to MUSL not implementing the libthread_db library.)

I've done regression testing using recent Fedora versions for all five
architectures.  Bugs were found and fixed during that testing.

Once that was done, I did even more testing, using a limited number of
tests.  These are the new tests that I've added, plus those tests with
which regression testing identified some problems.  The list is:

TESTS="gdb.base/tls-dlobj.exp gdb.base/tls-nothreads.exp \
       gdb.base/tls-multiobj.exp gdb.threads/tls.exp \
       gdb.server/no-thread-db.exp"

I tested using targets:

  unix, native-gdbserver, native-extended-gdbserver,

and, for x86_64 targets:
  unix/-m32, native-gdbserver/-m32, and native-extended-gdbserver/-m32

I also tested with no CC_FOR_TARGET (which defaults to gcc),
CC_FOR_TARGET=musl-gcc, and CC_FOR_TARGET=clang.  On Fedora, using
CC_FOR_TARGET=musl-gcc causes the program and libraries to be compiled
with gcc, but linked against the MUSL C library.  I didn't use this
option on non-Fedora machines, though my Void linux testing tested
using the MUSL library since that's what's installed in that test
environment.

I also ran additional tests using check-read1 for combos with no
CC_FOR_TARGET.

Using all sensible combinations of the above, I tested on 13 machines / 5
architectures:

  x86_64 / Fedora 28 / glibc-2.27
  x86_64 / Fedora 34 / glibc-2.33 / musl-libc-1.2.3
  x86_64 / Fedora 35 / glibc-2.34 / musl-libc-1.2.3
  x86_64 / Fedora 40 / glibc-2.39 / musl-libc-1.2.5
  x86_64 / Fedora 41 / glibc-2.40 / musl-libc-1.2.5
  x86_64 / rawhide (fc42) / glibc-2.40.9000 / musl-libc-1.2.5
  x86_64 / OpenSuse Leap 15.5 / glibc-2.31 / no musl
  x86_64 / Ubuntu 22.04 / glibc-2.35 / no musl
  x86_64 / void - 2024-03-14 / no glibc / musl 1.1.24

  aarch64 / Fedora 40 / glibc-2.39 / musl-libc-1.2.5
  riscv / Fedora 40 / glibc-2.39 / musl-libc-1.2.5
  ppc64le / Fedora 41 / glibc-2.40 / musl-libc-1.2.5
  s390x / Fedora 40 / glibc-2.39 / musl-libc-1.2.5

The point of testing old Fedora releases is to be able to test
older glibc versions.  In particular glibc-2.33 and earlier
had pthread functionality split into libpthread.so while glibc-2.34
and later place it into libc proper.

All of the testing went well except on riscv and s390x with
CC_FOR_TARGET=clang.  That's six test runs total, and they each show
799 FAILs.  The log files shows that riscv mostly prints the wrong
answer and that s390x shows output like "Cannot access memory at
address 0x3fff8d494e8".  But this happens regardless of whether
internal TLS support is used or libthread_db support.  I think it's
likely that it's a clang bug which I can do nothing about (aside from
filing a bug report).

Kevin Buettner (11):
  Don't attempt to find TLS address when target has no registers
  Allow TLS access to work in gdb.server/no-thread-db.exp
  Track and fetch TLS module ids for MUSL and GLIBC
  Implement internal TLS address lookup for Linux targets
  Internal TLS support for aarch64, x86_64, riscv, ppc64, and s390x
  Internal, but disabled, TLS support for i386
  Delete disabled i386 internal TLS support
  New test - gdb.base/tls-nothreads.exp
  New test - gdb.base/tls-multiobj.exp
  New test - gdb.base/tls-dlobj.exp
  Add TLS NEWS entry and document 'set
    force-internal-tls-address-lookup' command

 gdb/NEWS                                  |  20 ++
 gdb/aarch64-linux-tdep.c                  |  53 +++
 gdb/amd64-linux-tdep.c                    |  37 +++
 gdb/doc/gdb.texinfo                       |  17 +
 gdb/findvar.c                             |   7 +-
 gdb/linux-tdep.c                          | 209 ++++++++++++
 gdb/linux-tdep.h                          |  36 +++
 gdb/minsyms.c                             |   8 +-
 gdb/ppc-linux-tdep.c                      |  62 ++++
 gdb/riscv-linux-tdep.c                    |  78 +++++
 gdb/s390-linux-tdep.c                     |  43 +++
 gdb/solib-svr4.c                          | 203 +++++++++++-
 gdb/solib-svr4.h                          |  12 +
 gdb/testsuite/gdb.base/tls-common.exp.tcl |  50 +++
 gdb/testsuite/gdb.base/tls-dlobj-lib.c    |  87 +++++
 gdb/testsuite/gdb.base/tls-dlobj.c        | 310 ++++++++++++++++++
 gdb/testsuite/gdb.base/tls-dlobj.exp      | 378 ++++++++++++++++++++++
 gdb/testsuite/gdb.base/tls-multiobj.c     |  89 +++++
 gdb/testsuite/gdb.base/tls-multiobj.exp   | 231 +++++++++++++
 gdb/testsuite/gdb.base/tls-multiobj1.c    |  26 ++
 gdb/testsuite/gdb.base/tls-multiobj2.c    |  26 ++
 gdb/testsuite/gdb.base/tls-multiobj3.c    |  26 ++
 gdb/testsuite/gdb.base/tls-nothreads.c    |  57 ++++
 gdb/testsuite/gdb.base/tls-nothreads.exp  | 249 ++++++++++++++
 gdb/testsuite/gdb.server/no-thread-db.exp |   4 +-
 25 files changed, 2311 insertions(+), 7 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/tls-common.exp.tcl
 create mode 100644 gdb/testsuite/gdb.base/tls-dlobj-lib.c
 create mode 100644 gdb/testsuite/gdb.base/tls-dlobj.c
 create mode 100644 gdb/testsuite/gdb.base/tls-dlobj.exp
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj.exp
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj1.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj2.c
 create mode 100644 gdb/testsuite/gdb.base/tls-multiobj3.c
 create mode 100644 gdb/testsuite/gdb.base/tls-nothreads.c
 create mode 100644 gdb/testsuite/gdb.base/tls-nothreads.exp