Bug 24548 - gdb: TLS variables inaccessible when not linking with libpthread.
Summary: gdb: TLS variables inaccessible when not linking with libpthread.
Status: NEW
Alias: None
Product: gdb
Classification: Unclassified
Component: threads (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 26917 (view as bug list)
Depends on:
Blocks:
 
Reported: 2019-05-13 13:36 UTC by Carlos O'Donell
Modified: 2022-08-23 00:23 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Carlos O'Donell 2019-05-13 13:36:23 UTC
There has been a serious regression in the ability to debug TLS variables in applications.

Take this test for example:

cat >> tls-test.c <<EOF
#include <stdio.h>
#include <stdlib.h>

__thread int count;

int
main (void)
{
  count = 42;
  printf ("%d\n", count);
  return count;
}
EOF

[carlos@athas ~]$ gcc -O0 -g3 -o tls-test tls-test.c
[carlos@athas ~]$ ./tls-test
42

[carlos@athas ~]$ gdb ./tls-test
GNU gdb (GDB) Fedora 8.2.91.20190424-24.fc30
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./tls-test...
(gdb) break main
Breakpoint 1 at 0x40112a: file tls-test.c, line 9.
(gdb) r
Starting program: /home/carlos/tls-test 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.29-9.fc30.x86_64

Breakpoint 1, main () at tls-test.c:9
9	  count = 42;
(gdb) p count
Cannot find thread-local storage for process 18173, executable file /home/carlos/tls-test:
Cannot find thread-local variables on this target
(gdb) 

This is a serious regression.

gdb *must not* expect libpthread to be present in the process to access or debug count. It was never a requirement before, is not a requirement of the core specficiation, and should not be a requirement of any new specification.

Thread local storage at the C-level is designed to be independent of the threading library, but may require nptl_db to access some members of the main thread.

Let met explain in detail why this is important:

Users develop libraries without knowing if their library will be used in a multi-threaded or single-threaded enviroment. In order to support both, the library uses __thread variables to create per-thread data.

gdb now makes it impossible to debug such applications, forcing them to choose between:

(a) Forcing libpthread to be used such that they can be debugged (a bad choice).

(b) Creating two library builds, one for debugging (with libpthread) and one with out (a bad choice again, since you don't test what you ship).

There is no technical restriction that I know of that limits gdb's ability to access the thread local storage variables.

This change has been present in gdb for a while, but as a core GNU Toolchain developer I've worked around it, but I feel the need is serious and we need to discuss this issue sincce it impacts a lot of workflow debugging.

We must be able to access TLS variables in single threaded programs because libraries are free to use TLS variables for the eventuality that they get used with threads. Similarly libc.so.6 is *full* of TLS variable usage for exactly this reason.

On the gdb side what is preventing us from fixing this?

How can I help?
Comment 1 Carlos O'Donell 2019-05-13 17:37:02 UTC
I'm not sure if this is a regression anymore. I can't reproduce what I thought was a working configuration.
Comment 2 Gary Benson 2019-05-14 09:25:00 UTC
I'd planned to ask you for a working configuration, the code to access TLS variables lives in libthread_db (mainly the function td_thr_tlsbase), but libthread_db won't initialize unless the inferior contains a symbol (nptl_version) which would normally come from libpthread.so.

Note that either upstream GDB or Fedora GDB has a hack to allow printing of errno without libpthread.so, might that have been the working configuration you recalled?
Comment 3 Pedro Alves 2019-05-14 12:38:40 UTC
Right, this isn't a regression -- it never worked.

For the record, this was discussed a couple years ago on the glibc/gdb lists, here:

 https://www.sourceware.org/ml/libc-alpha/2017-09/msg00580.html

That's a proof of concept prototype that tweaks glibc and gdb to make it possible to load libthread_db into gdb for non-threaded programs.

> Note that either upstream GDB or Fedora GDB has a hack to allow printing of 
> errno without libpthread.so, might that have been the working configuration you 
> recalled?

Right, the hack in fedora gdb is just a check inside the print command -- gdb transforms a print of "errno" to "*__errno_location()":

@@ -1184,6 +1184,10 @@ print_command_1 (const char *exp, int voidprint)
 
   if (exp && *exp)
     {
+      /* '*((int *(*) (void)) __errno_location) ()' is incompatible with
+        function descriptors.  */
+      if (target_has_execution && strcmp (exp, "errno") == 0)
+       exp = "*(*(int *(*)(void)) __errno_location) ()";
       expression_up expr = parse_expression (exp);
       val = evaluate_expression (expr.get ());
     }
Comment 4 Tom de Vries 2020-11-18 21:06:16 UTC
*** Bug 26917 has been marked as a duplicate of this bug. ***
Comment 5 Kevin Buettner 2022-01-13 17:15:27 UTC
For environments using glibc-2.34 and beyond, this bug is fixed; in those environments GDB is able to access TLS variables due to the fact that the thread/TLS machinery has now been moved into libc.

I'm reluctant to close this bug, however, since it's still a problem in other environments (i.e. glibc versions prior to 2.34 and possibly other C / pthread library implementations as well.)
Comment 6 Disconnect3d 2022-08-23 00:23:12 UTC
(In reply to Kevin Buettner from comment #5)
> For environments using glibc-2.34 and beyond, this bug is fixed; in those
> environments GDB is able to access TLS variables due to the fact that the
> thread/TLS machinery has now been moved into libc.
> 
> I'm reluctant to close this bug, however, since it's still a problem in
> other environments (i.e. glibc versions prior to 2.34 and possibly other C /
> pthread library implementations as well.)

Hi, I just hit this issue by myself. Do you know if there is a working workaround for it for old glibc versions? Or: how do I force linker to link to libpthreads?

The [0] suggests using something like:
```
g++ -x c++ - -o my_program -Wl,--no-as-needed -lpthread -Wl,--as-needed
```

but it does not seem to work for me.

[0] https://stackoverflow.com/questions/37556673/force-linking-to-pthread-with-g